Listing

AskTom Home
ViewForPrinting
Home
Recent Archives Advanced Search FAQ by Category Most Popular Hot Articles Your Questions [ Listing ]
Subject | Article | Last Updated (East coast time)
Refreshing Materialized Views | article only | Jan 01, 2001 11:52 am
Function argument assignment between types "const char*" and "unsigned char*" is not allowed. | article only | Jan 01, 2001 12:03 pm
Constraint | article only | Jan 01, 2001 12:06 pm
Can I run 2 versions of Oracle on NT | article only | Jan 02, 2001 06:15 am
Underlying mechanism of Exchanging the partitions | article only | Jan 02, 2001 07:04 am
How to build extended proceudre on HP-UNIX (64 bit) 11.0 | article only | Jan 02, 2001 08:32 am
Dropping Datafiles | article only | Jan 02, 2001 09:18 am
Populating a table with dates | article only | Jan 02, 2001 09:20 am
How to use UTL_SMTP | article only | Jan 02, 2001 10:05 am
reporting | article only | Jan 02, 2001 11:27 am
L | article only | Jan 02, 2001 01:51 pm
Archiving Transactions | article only | Jan 02, 2001 02:21 pm
DBCS (Double Byte Character Set) | article only | Jan 02, 2001 02:56 pm
getting out put of a java stored procedure in a HTML page | article only | Jan 02, 2001 03:19 pm
Partitioning | article only | Jan 02, 2001 03:48 pm
Selecting Index | article only | Jan 03, 2001 09:22 am
size of log_buffer and online redo log file | article only | Jan 03, 2001 09:29 am
commit or not | article only | Jan 03, 2001 09:39 am
Identifying New line charecters in a String | article only | Jan 03, 2001 09:54 am
RBS question | article only | Jan 03, 2001 12:44 pm
how much size of database | article only | Jan 03, 2001 01:58 pm
Variable table names | article only | Jan 03, 2001 02:19 pm
Reporting issues | article only | Jan 03, 2001 02:29 pm
Obejects and Execute Immediate | article only | Jan 03, 2001 04:12 pm
issys_modifiable | article only | Jan 03, 2001 04:30 pm
use hints ? | article only | Jan 04, 2001 08:53 am
Long RAW | article only | Jan 04, 2001 09:25 am
Security | article only | Jan 04, 2001 09:26 am
Designer 6i | article only | Jan 04, 2001 09:34 am
Limit of export file on solaris 2.6 and oracle 815 | article only | Jan 04, 2001 10:10 am
Oracle Product & Reports | article only | Jan 04, 2001 02:08 pm
PL/SQL Procedure | article only | Jan 04, 2001 03:20 pm
Temporary Table | article only | Jan 04, 2001 04:03 pm
Convert minutes into HH:MM:SS format | article only | Jan 04, 2001 04:25 pm
Long DataType Concat with VarChar? | article only | Jan 04, 2001 04:32 pm
Saving Server Module Diagram as a PDF file | article only | Jan 04, 2001 07:05 pm
Oracle on a Raw Partition (on NT) | article only | Jan 04, 2001 07:11 pm
Dynamic SQL | article only | Jan 04, 2001 07:14 pm
Does Oracle Intermedia support Word 2000 ? | article only | Jan 04, 2001 07:15 pm
Wanting to know what is a good book for an beginner. | article only | Jan 05, 2001 09:12 am
What value is optimal for PCTINCREASE in Temporary Tablespace ! | article only | Jan 05, 2001 09:31 am
Difference between SYS and SYSTEM User Account ! | article only | Jan 05, 2001 09:35 am
Dynamic SQL | article only | Jan 05, 2001 09:40 am
stop user from connecting to the db from more than 1 machine/location at the same time | article only | Jan 05, 2001 09:56 am
Tablespace and Tables sizing | article only | Jan 05, 2001 10:07 am
Select Statement | article only | Jan 05, 2001 10:19 am
Returning Result Sets from Stored Procedure | article only | Jan 05, 2001 10:28 am
Creating Views | article only | Jan 05, 2001 11:37 am
date issue | article only | Jan 05, 2001 12:18 pm
Storing & Retrieving Excel Spreadsheet in DB | article only | Jan 05, 2001 03:17 pm
System.out.println | article only | Jan 05, 2001 04:52 pm
What bits of encryption does PL/SQL packages use ? | article only | Jan 05, 2001 06:53 pm
SQL Query tuning | article only | Jan 05, 2001 07:22 pm
preparedstatement | article only | Jan 05, 2001 07:28 pm
LOCKS | article only | Jan 05, 2001 09:19 pm
Round In Java and Oracle. | article only | Jan 06, 2001 09:21 am
database Administration | article only | Jan 06, 2001 09:23 am
Data Dict. vs Local tablespaces | article only | Jan 06, 2001 12:59 pm
rebuilding indexes | article only | Jan 06, 2001 01:18 pm
Execute_Query - Query on Detail Block | article only | Jan 07, 2001 10:18 am
script | article only | Jan 07, 2001 10:44 am
Database tunning & controlling. | article only | Jan 07, 2001 11:18 am
Trigger for multiple Tables - Reg. | article only | Jan 07, 2001 11:22 am
Forms 6 | article only | Jan 07, 2001 11:32 am
Limiting rows returned from query in web app | article only | Jan 07, 2001 11:35 am
V$OPEN_CURSOR | article only | Jan 07, 2001 01:58 pm
row(s) 1 - 66 of 66
January 01, 2001 Andre -- Thanks for the question regarding "Refreshing Materialized Views", version 8.1.6
You Asked
Hi Tom, and Happy New Year !

I need to setup a policy to refresh a materialized view. Some
points were not clear to me.

Questions:

1) Since I plan to have summaries from tables which are loaded
at uncertain times -- and I need to have them updated. So I
cannot use START WITH. It seems to me there are 2 options:
a) ON DEMAND (default) by scheduling a manual refresh using
DBMS_MVIEW after the load.
b) ON COMMIT, since SQL*LOADER itself will commit the data.
Apparently, ON COMMIT is better because I don't have to schedule
a manual refersh, which involves more work. Am I correct, or are
there other implications ?

2) If I create a MV with a COMPLETE, FAST, FORCE or NEVER
method, will the manual refresh use the respective method to
refresh the MV ? Or will it, for example, always refresh the MV
entirely (something like the COMPLETE method) ?

3) I understand the COMPLETE and FAST methods. But -- according
to Oracle -- FORCE would "apply fast refresh if possible;
otherwise, apply complete refresh". What does he mean by "if
possible" ? Would you please comment on the FORCE method ?

4) The NEVER method is said to never refresh the MV in any way.
Does that also apply to the refresh procedures of DBMS_MVIEW ?

5) Is it mandatory that I create a materialized view log
whenever I use the fast refresh method ?

Thanks !
and we said...
1) you can use start with and next if you like to schedule a
refresh to occur on some scheduled time (eg: start right now and
refresh every night at midnight).  You can still do an on demand
based refresh as well -- by using the supplied refresh routines
in the plsql packages.

On commit will add a certain amount of overhead to the load
process so, if the load is "large", you might be best off doing
the load and then a complete refresh of the materialized views
(rather then applying all of the changes, it may be faster just
to rebuild the entire mv).

So, on commit might mean a little less administrative overhead
but a little more runtime processing horsepower.  If you are
loading large amounts of data, the overhead might be enough to
convince you to schedule a complete refresh "post" load.

2) the refresh will use by default whatever the MV was created
with (complete/fast).  you can force it to use one or the other
at runtime as well using the dbms_mview.refresh procedure with
method set to one of C, F, or ?

3) if we can do a fast (the snapshot log exists, it has not been
purged, the mv is a candidate for a fast refresh, and so on) we
do a fast.  If we cannot, we do a complete.  A force just
ensures that one way or the other, the MV is refreshed.

4) NEVER REFRESH prevents the materialized view from being
refreshed with any Oracle refresh mechanism or procedure. If you
issue a REFRESH statement on the materialized view, Oracle
returns an error.

5) For a fast refresh, yes we need a snapshot log as this is the
list of all changes to the base table(s) made since the last
fast refresh.
January 01, 2001 Ramakrishna -- Thanks for the question regarding "Function argument assignment between types "const char*" and "unsigned char*" is not allowed.", version version 7.3.4
You Asked
Hi

I am using a variable, say "empname" of type "varchar" in a
Pro*C file. I am passing "empname.arr",pointer to the variable
as argument to a function written in "C". When this Pro*C file
is compiled I am getting the warning/error as
--->
Function argument assignment between types "const char*" and
"unsigned char*" is not allowed.

But,the result of compilation an executable file when executed
is working fine.

How can I avoid the above problem?

Wish You Happy New Year
Thanks
Ramakrishna
and we said...
You are probably on AIX.  Their default C compiler warns of all
types of things.  A varchar type in Oracle is an unsigned char *
type.  Most of the C functions take a "char *" (by default
"signed").  Your options are:

o don't use varchar, use char's instead.
o cast the empname.arr as a char *,    f( (char *)empname.arr)
o find the appropriate switch to send to your C compiler to turn

  off this specific warning.
o ignore it.
January 01, 2001 Nikunj -- Thanks for the question regarding "Constraint", version 8.0.5
You Asked
hello tom,

i whould like to know that in which table in which column and
with which constraint name i had used my reference key.

i.e. in custmast table custcode is p.k.
in cust_det custcode is my f.k.
in ord_mast custcode is my f.k.

so i need my custcode as r.k. declare in cust_det table with xxx
constaint name & in
ord_mast table with xxx constaint name.

thanks.
and we said...
user_constraints and user_cons_columns has all of this.  Here is
a sql query for example that given a PARENT table will print out
all of the ALTER child_table ADD constraint <fk name> references
PARENT_TABLE commands.

column fkey format a80 word_wrapped
select
'alter table "' || child_tname || '"' || chr(10) ||
'add constraint "' || child_cons_name || '"' || chr(10) ||
'foreign key ( ' || child_columns || ' ) ' || chr(10) ||
'references "' || parent_tname || '" ( ' || parent_columns ||
');' fkey
from
( select a.table_name child_tname, a.constraint_name
child_cons_name,
         b.r_constraint_name parent_cons_name,
         max(decode(position, 1,     '"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 2,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 3,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 4,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 5,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 6,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 7,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 8,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 9,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,10,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,11,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,12,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,13,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,14,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,15,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,16,', '||'"'||
                substr(column_name,1,30)||'"',NULL))
            child_columns
    from user_cons_columns a, user_constraints b
   where a.constraint_name = b.constraint_name
     and b.constraint_type = 'R'
   group by a.table_name, a.constraint_name, b.r_constraint_name
) child,
( select a.constraint_name parent_cons_name, a.table_name
parent_tname,
         max(decode(position, 1,     '"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 2,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 3,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 4,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 5,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 6,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 7,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 8,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 9,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,10,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,11,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,12,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,13,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,14,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,15,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,16,', '||'"'||
                substr(column_name,1,30)||'"',NULL))
            parent_columns
    from user_cons_columns a, user_constraints b
   where a.constraint_name = b.constraint_name
     and b.constraint_type in ( 'P', 'U' )
   group by a.table_name, a.constraint_name ) parent
where child.parent_cons_name = parent.parent_cons_name
  and parent.parent_tname = upper('&1')
/
January 02, 2001 Aliosn -- Thanks for the question regarding "Can I run 2 versions of Oracle on NT", version 8.0.4 & 8.1.6
You Asked
I need to upgrade an 8.0.4. database on NT to 8.1.6 but also
have other databases on this machine that I do not want to
upgrade (yet).

Can I run both 8.1.6 for the upgraded database and 8.0.4 for the
others on the same NT machine at the same time?
and we said...
Yes, you will simply use "multiple oracle homes" and have each
version of Oracle installed in a different Oracle home.

Oracle software from version 8.0.4 on up supports multiple
oracle homes on NT.
January 02, 2001 Ravi -- Thanks for the question regarding "Underlying mechanism of Exchanging the partitions", version 815
You Asked
Dear Tom,

I have a partitioned table with 9 partitions.  Each partition is
about 10Gig in size. Now, I also have set of 9 conversion
tables(non partitioned tables ) for each partitions in the
partitioned tables. The non-partitioned tables and the
partitoned table are indentical except that the
non-partitioned(conversion) tables have extra columns.

Each table also has 4 indexes defined on them and the indexes in
the partitioned table are local and donot have any
non-partitioned/global indexes defined. Now, I am tasked with
exchanging the partitions with the non-partitioned tables along
with the indexes.

I have tested the same with small sizes. But I have not worked
with such huge sizes. However, I would like to understand the
underlying mechanism of exchanging the partitions.

When an object is renamed in oracle, it would not take time.
Similarly, when I exchange partitions with non-partitioned
table, will it result fast as is in renaming of objects. Or
oracle has to rebuild all the segments and will take time.

If it is going to work just like renaming, then what is the
difference between

if the partition and the corrsponding non-partitioned table are
in different tablespaces or

if the partition and the corrsponding non-partitioned table are
in same tablespace.

Could you please give an idea of how much time, it might take
for one partition.

Each partition is 10G in size and has 4 indexes of 1G each in
size.

Could you please suggest me any other method. Your suggestions
are always highly valuable.

Thanks
Ravi
and we said...
If you are planning on exchanging the table with the extra
columns with a partition, be prepared for:

           *
ERROR at line 3:
ORA-14096: tables in ALTER TABLE EXCHANGE PARTITION must have
the same number of columns

You cannot do that.  You'll have to add the columns to the
partitioned table first.

A partition exchange is simply an exchange of segments -- no
movement of data takes place.  It is a data dictionary update.
For example:

tkyte@TKYTE816> CREATE TABLE new_table2000
  2  ( x int,
  3    y int,
  4    z DATE
  5  )
  6  PARTITION BY RANGE (z)
  7  (
  8  PARTITION newtab_1999_h1 VALUES LESS
  9  THAN(to_date('30-jun-1999','dd-mon-yyyy')),
 10  PARTITION newtab_1999_h2 VALUES LESS
 11  THAN(to_date('31-dec-1999','dd-mon-yyyy'))
 12  )
 13  /

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> insert into NEW_table2000  values ( -1, -1,
'15-jun-1999' );

1 row created.

tkyte@TKYTE816> insert into NEW_table2000  values ( -2, -2,
'15-dec-1999' );

1 row created.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> create table temp ( x int, y int, z date )
tablespace tools;

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> select segment_name, partition_name,
  2         tablespace_name, extent_id
  3    from user_extents
  4   where segment_name in ( 'NEW_TABLE2000', 'TEMP' );

SEGMENT_NAME    PARTITION_NAME  TABLE  EXTENT_ID
--------------- --------------- ----- ----------
TEMP                            TOOLS          0
NEW_TABLE2000   NEWTAB_1999_H2  USERS          0
NEW_TABLE2000   NEWTAB_1999_H1  USERS          0

tkyte@TKYTE816>
tkyte@TKYTE816> alter table new_table2000
  2  exchange partition newtab_1999_h1
  3  with table temp;

Table altered.

tkyte@TKYTE816>
tkyte@TKYTE816> select segment_name, partition_name,
  2         tablespace_name, extent_id
  3    from user_extents
  4   where segment_name in ( 'NEW_TABLE2000', 'TEMP' );

SEGMENT_NAME    PARTITION_NAME  TABLE  EXTENT_ID
--------------- --------------- ----- ----------
TEMP                            USERS          0
NEW_TABLE2000   NEWTAB_1999_H2  USERS          0
NEW_TABLE2000   NEWTAB_1999_H1  TOOLS          0

shows that the extents from TEMP and NEW_TABLE2000 (in different
tablespaces) were simply "swapped".

The time to do 1 partition will be a function of the number of
extents...  You will need to do it when no one is performing DML
or queries on the table (cursors must be invalidated and such)
January 02, 2001 H -- Thanks for the question regarding "How to build extended proceudre on HP-UNIX (64 bit) 11.0", version 8.1.6 on HP-UNIX
You Asked
I build a extended procedure in a libary on HP-UNIX,
but when I call the extended function, oracle tell me can't
found the function in libary.

I use the same C source code to build DLL on WINDOWS2000, and
use the same call mode , Oracle run correct.

Would you please tell me how to do. A simple example is the
best.
Tanks in advance.
and we said...
in $ORACLE_HOME/plsql/demo there is a sample external procedure.
 If you go there and issue:

$ make -f demo_plsql.mk

it should build this sample and show you the necessary linking
options you need to supply on HP/UX to build a .sl file and
export functions from it.
January 02, 2001 Andre -- Thanks for the question regarding "Dropping Datafiles", version 8.1.6
You Asked
Hi Tom,

I read your notes on dropping datafiles at:
http://osi.oracle.com/wa/ask/owa/ask_tom_pkg.display?p_dispid=515222144417&p_search_str=%7BDROP%7D%20and%20%7BDATAFILE%7D
However, I think it is intended for versions prior to Oracle8i
since it does not mention the possibility of using the MOVE
clause to move tables between tablespaces in this process, which
could be very handy, I suppose.

And I also read about moving tables at:
http://osi.oracle.com/wa/ask/owa/ask_tom_pkg.display?p_dispid=47812348053&p_search_str=%7BMOVE%7D%20and%20%7BTABLE%7D
My scenario is: I have a tablespace (APP_DATA) with 5 small
datafiles, and for simplicity of management I would like to put
all its objects into a bit smaller one than the sum of all
datafiles -- especially because many of its segments may be
reorganized (they will considerably be reduced in size). All
segments in APP_DATA are regular tables (non-patitioned and
non-IOT) and some have indexes in the APP_INDEX tablespace. None
of the tables has LONG or LONG RAW columns. Besides I have
plenty of disk space.

This is a non-critical database, so I can stop users to do this
maintenance. However I know DML on tables is not permitted
during the move, only queries. And in the case of indexes
rebuilds and IOT moves, I can specify the ONLINE clause to allow
DML.

My plan is:

a) backup the database;

b) create a WORK tablespace big enough to hold all segments in
the APP_DATA tablespace;

c) ALTER TABLE MOVE all tables from APP_DATA to WORK using
dynamic SQL -- or your script moveall.sql;

d) drop APP_DATA (it is empty now);

e) re-create APP_DATA with one datafile;

f) ALTER TABLE MOVE all tables from WORK to APP_DATA;

g) drop WORK;

h) backup de database again.

Questions:

1) I found very little reference as to moving tables in 8.1.6´s
Administrator´s Guide and SQL Reference. But, from what I read
elsewhere, I will have no problem with indexes, since they will
be retained in APP_INDEX. Correct ?

2) Since I´ll be dropping the tablespace -- although recreating
it later with the same name -- I might have problems with
"pending references to it", like quotas and default tablespace
caluses. How should I deal with this ?

3) As far as I´m aware, I will not have problems with grants,
constraints, triggers, etc, since these are data dictionary
objects. Am I right ?

4) Do you see any other implications ?

Thanks again !
and we said...
I would suggest an abbreviated set of steps:

1) backup
2) create APP_DATA_NEW big enough
3) alter table move to app_data_new
4) alter index rebuild
5) drop app_data
6) backup

Don't bother with a double move when one would do.

q1) you need to REBUILD all indexes immediately after a move
since the rowids (our internal pointers) have all changed.  All
of the indexes will be there but they will be unusable.  My
moveall script generates the needed rebuild statements as well.

q2) alter the users with quotas to reference the NEW tablespace.
 Or, if you do the double move, do nothing special here.

q3) correct, as long as you MOVE, not drop and recreate, you do
not need to be concerned about any of the above.

q4) nope.
Review & Followup
Rating: 5
August 25, 2001
Reviewer: Karen from Denver
I have spent my Saturday reading your forum and I have learned a lot.  You have
saved me a ton of time, since, I too, made the mistake of trying to drop a
datafile from a tablespace.  Of course, what was I thinking...  I can MOVE my
objects...  Life is looking up!

I appreciate all of your examples too.

January 02, 2001 Sahed -- Thanks for the question regarding "Populating a table with dates ", version oracle 816 (8i)
You Asked
I wish to create a table by populating it with date
i.e from jan 2000 for next four years.

I have tried a few things around the sysdate functionality
without any sucess

Please help me

I thank you in advance for your help

S.A.S
and we said...
create table t ( x date );

begin
   for i in 0 .. 10000
   loop
      exit when
        to_date('01012000','ddmmyyyy') +i
              >= to_date( '01012005', 'ddmmyyyy');
      insert into t values ( to_date('01012000',ddmmyyyy')+i )
   end loop;
end;
/

is one method.
Review & Followup
Rating: 3
You can try this sql to.. September 05, 2001
Reviewer: Saurav
insert into testdate (select trunc(sysdate - 365,'yyyy') + r
  from ( select rownum-1 r from all_objects where rownum <= 1461
))
/

January 02, 2001 Iceymole -- Thanks for the question regarding "How to use UTL_SMTP", version Oracle 8i
You Asked
Hi Tom,
I would like to know the use of UTL_SMTP in sending mails. I
checked in the Oracle 8i books available but is not explained
except that it is used to send mails.

My requirement is send bulk emails to number of users.

Please reply.

cheers
Iceymole.
and we said...
It is document in the supplied packages guide, along with an
example:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/utl_smtp.htm#1000695
....
Review & Followup
Rating: 3
April 17, 2001
Reviewer: A reader from India

January 02, 2001 Servet -- Thanks for the question regarding "reporting", version 3.3
You Asked
hi tom
i need to an sql query whic will return a resultset as the one
below.
col0       col1   col2

001         10    20
001         15    10
001         10    25
subtotal    35    55

002         2      3
002         5      7
002         8      9
subtotal    15    19

grandtotal  50    74

if this is doable with SQLplus and if you tell me how id be
pleased.
Thanks for your help
and we said...
Sure, it will look something like this:

scott@ORA8I.WORLD> compute sum of sal on deptno
scott@ORA8I.WORLD> break on deptno
scott@ORA8I.WORLD> select deptno, sal from emp order by deptno;

    DEPTNO        SAL
---------- ----------
        10       2450
                 5000
                    5
                 1300
********** ----------
sum              8755
        20        800
                 1100
                 3000
                 3000
                 2975
********** ----------
sum             10875
        30       1600
                 2850
                 1250
                  950
                 1500
                 1250
********** ----------
sum              9400

15 rows selected.

scott@ORA8I.WORLD>

see
http://technet.oracle.com/doc/oracle8i_816/sqlplus.816/index.htm
for all of the options available with BREAK, COMPUTE and so on.
January 02, 2001 Lindsay -- Thanks for the question regarding "L", version 8.1.7
You Asked
Hi,

I have just read an article which talks about how long SQL statements which are
nearly identical can have the same hash value.  The result is higher statement
overhead and poor performance.

When I query the v$sql table there are records in there that have duplicate hash
values, yet there are no records in the v$sqlarea table with duplicate hash
values.  I am wondering what the difference is between the two tables (v$sql and
v$sqlarea)?

The article I read also stated that the hash values are calculated on the first
200 characters in the sql statement.  I am wondering if this is correct because
I have sql statements which are the same for the first 200 characters and beyond
yet they have different hash values?

Thanks for your help,

Lindsay
and we said...
V$SQL:
This view lists statistics on shared SQL area without the GROUP BY clause and
contains one row for each child of the original SQL text entered.

V$SQLAREA:
This view lists statistics on shared SQL area and contains one row per SQL
string. It provides statistics on SQL statements that are in memory, parsed, and
ready for execution.

So, v$sql is the "base" table for v$sqlarea.  v$sqlarea is an aggregation of
v$sql.  If you query v$sql and sum up the counts of "duplicate" hashes and goto
v$sqlarea and sum the version_counts -- you should see similar if not the same
exact numbers:

ops$tkyte@ORA8I.WORLD> select sum(cnt)
  2    from ( select hash_value, count(*) cnt
  3                     from v$sql
  4                    group by hash_value
  5                   having count(*) > 1 )
  6  /

  SUM(CNT)
----------
      1818

ops$tkyte@ORA8I.WORLD> select sum(version_count)
  2    from v$sqlarea
  3   where version_count > 1
  4  /

SUM(VERSION_COUNT)
------------------
              1818

ops$tkyte@ORA8I.WORLD>

the hash algorithm varies from release to release over time and gets better over
time.  Currently it is a function of not just the front but bits from other
places in the query as well.
January 02, 2001 vinnie -- Thanks for the question regarding "Archiving Transactions", version 8.1.5
You Asked
Tom,

Does ORACLE provide a means to archive all transactions that
take place on a specific table or does a user have to create a
means of his/her own to accomplish this?

Thanks Again
and we said...
We provide an archive of transactions via the archive redo log.
We do it at the database level.  If you have more persistent
auditing needs (eg: need to keep the before and after images
online and queryable), you will need to implement it yourself
using a trigger and an "audit" table of sorts.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:59412348055
for an example.
January 02, 2001 Jack -- Thanks for the question regarding "DBCS (Double Byte Character Set)", version 8.1.6,8.1.7
You Asked
We are going to implement an Oracle database and need DBCS set
up with the database for an Asia Pacific application although
the application will run in the US.  It is my understanding that
we can just create a separate Oracle instance/database for this
application and specify the appropriate DBCS character set.
UTF-8 is a multi-byte format with variable width and Oracle 8
supports this.  Is this the one we should use?  Are there others
we 'could' use?
and we said...
You'll want to read through
http://technet.oracle.com/doc/oracle8i_816/server.816/a76966/toc.htm
completely if you want to fully understand all of the issues
with regards to this.  This document also has a list of the
character sets:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76966/appa.htm#967600
there are lots there to choose from (and yes, there are
alternatives to utf-8 you may consider)
January 02, 2001 Muhtashim -- Thanks for the question regarding "getting out put of a java stored procedure in a HTML page", version 8.1.5
You Asked
I am using Java stored procedure that will check some foreign
key and generates message if error occurs( e.g. foreign key is
not there.). This java stored procedure is wrapped in a before
update/add trigger; means when any one tries to update/add Data
java procedure will be fired and give error message only if
there is any error. This is  web-based. So at client's end there
is only HTML page. We are using servlet for server side program.
Servlet is taking request from HTML and calling EJB for data
updating/Adding/deleting/creating.To whom java stored procedure
from the trigger should send the message. To EJB? then how EJB
will send the message to servlet so that I can print it as
dynamic HTML page. Or is there any direct way? I think java
stored procedure should not be wrapped in trigger ; should be in
a function which will return the string "true" if a record is
found or string "Foreign key not found/e.g. Salesman is not
existing in Salesman Table" if zero row is selected. Servlet
will call the function before any add/update.. command and get
the returning string in a variable. Then comparing the string
value it will call EJB to ADD/update... if it is "true"; or else
print the message .
and we said...
The java stored procedure cannot return a formal parameter or
return value to anyone except to code in the body of the trigger
itself as it is being called by the database as the result of a
trigger firing.  It can only return a value to the trigger.  The
trigger can then issue a raise_application_error() which will
notify the EJB that an error occured.  The EJB will be
responsible for catching that error and dealing with it.  The
EJB can return to the servlet a nicely formated formal
parameter.

So, you should code the trigger as such:

...
begin
   java_stored_procedure( ....,
                          some_output_indicating_success,
                          some_output_error_message );

   if some_output_indicating_success <> 'Y' )
   then
     raise_application_error(-20001, some_output_error_message);
   end if;
end;
/

Note that if this is a simple FOREIGN KEY relationship, there
are INFINITELY better and more appropriate ways to implement
this.  Foreign keys should not be done via a trigger, rather
they should be done declaratively:

   alter table t add constraint t_fk_to_t2
   foreign key(a,b,c) references t2(d,e,f);
January 02, 2001 Arthur -- Thanks for the question regarding "Partitioning", version 8.1.5
You Asked
Tom,

I've often debated on whether or not to partition some of our
larger tables.  The tables are about 2 or 3GB.  I'd rather not
partition the tables if I do not have to.  What is a good
measure to decide if a table needs to be partitioned into
different files?   Size perhaps?

Arthur
and we said...
Size is one consideration.  Others (many of which are dependent
on size) could be:

o do you need to do parallel DML (mass updates) to this data?

o do you believe you would benefit from paralle index range
scans on this data?

o do you full scan this data frequently and might you therefore
be able to benefit from partition elimination.  For example, if
you have 4 "regions" in this table, having an index on region
would not make sense typically.  So, a simple select count(*)
from T where region = 1 must full scan.  If you partitioned by
region, you could cut down the amount of data you have to scan
by a factor of 4

o is this "rolling window" type of data.  Do you load up lots of
new rows and delete lots of old rows?  Partition by date and do
simple "exchange partitions" to remove old data and add new
instantly.

and so on.  Most of the above is related to size -- 2-3gig is
about where you might consider it.  If you do simple indexed
reads into this table and performance and manageability is just
fine -- then it is just fine.
January 03, 2001 Venkata -- Thanks for the question regarding "Selecting Index ", version 8.0.5.0
You Asked
Hi Tom,

I have 3 (A,B,C,) tables.

table_name  column_name distinct_values Total_No_of_Rows
A           a_col       7               7.5 millions
B           b_col       9               3.5  ,,
C           c_col       242             2    ,,

Now my ? are

1. Because of low cordiality in A and B table
   can i create bit map index on the columns in the above
   mentioned is it OK?

2. what about C table, which one B-tree or Bit map index?

thanks lot,
Venkat
and we said...
1) yes, if you need one.  If you do not need one -- then no.
Only you can answer the question "do you need one".  Do you
frequently ask questions like "how many rows in A have a_col =
X"?  If not, a bitmap index won't help.  Another consideration
is -- does table A get updated?  In particular, does the column
a_col get modified frequently?  If so -- a bitmap index will not
be nearly as concurrent as a btree would be (but you cannot use
a btree on this either) so it will be a trade off in that
respect.

2) Each value points to about 8,300 entries.  8,300 is about
1/2% of the table.  A conventional index could work on this
column -- as could a bitmap -- especially if you aggregate alot
(how many rows in C have a c_col = X or Y for example).

Same considerations apply as above.
January 03, 2001 wallacel -- Thanks for the question regarding "size of log_buffer and online redo log file", version 8.1.6
You Asked
Tom:

is there any relationship between the size of log_buffer
and online redo log files?

Regards,
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:55812348055
for some background on this.

There really isn't a relationship between log buffer and the
size of the online redo log files.  There is a relationship
between log buffer and the size+speed of your transactions.
January 03, 2001 wallacel -- Thanks for the question regarding "commit or not", version 8.1.6
You Asked
Tom:

which one run fast? why?
A.
for i in 1..1000 loop
insert into test values(i);
end loop;

B.
for i in 1..1000 loop
insert into test values(i);
commit;
end loop;
and we said...
Almost certainly the one that does not commit in the loop:

ops$tkyte@DEV816> drop table t;
Table dropped.

ops$tkyte@DEV816> create table t ( x int );
Table created.

ops$tkyte@DEV816> begin
  2  for i in 1..1000 loop
  3  insert into t values(i);
  4  end loop;
  5  end;
  6  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.08

ops$tkyte@DEV816> drop table t;
Table dropped.

ops$tkyte@DEV816> create table t ( x int );
Table created.

ops$tkyte@DEV816> begin
  2  for i in 1..1000 loop
  3  insert into t values(i);
  4  commit;
  5  end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.79
ops$tkyte@DEV816>

A commit forces a synchronous write to the online redo log files
that we must wait for.  Doing this every iteration imposes LOTS
of waits.  Also, you are executing more code.

the golden rule of committing is very simple:

Commit as often as you must and as infrequently as you have to.

or

Your tranasaction should be as small as it can be but as large
as it has to be

Both are saying that your TRANSACTION should dictate the
frequency of the commit.  You commit on transactional
boundaries, you do not commit for performance reasons.
January 03, 2001 Rajesh -- Thanks for the question regarding "Identifying New line charecters in a String", version 6
You Asked
Hi ,
   I am very new to Oracle 3 months.We were having Sybase-Power
builder combination. Recently we have moved to Oracle8 with
Developer6.I have transferred the data from sybase to my local
oracle database using the data pipe line option of Power
builder.
     What i am doing is collate data from two tables and insert
into a empty table.I then check if there is an 'Enter or new
line charecter'  inside the string.I used the function
instr(<variable holding the value> ,chr(10)) , but it always
return the value 0.How am i going to get around the problem. I
am using a server side stored procedure to do the above process.

      Is it a pronlem with the data or is there any other
fuction or methord to find out.
       Hope to hear form u soon.
Thanking you
Rajesh
and we said...
Perhaps you don't have line feeds (chr(10)) but carriage returns
in the data?  try chr(13) which is a carriage return.

If you have a string that has a chr(10) in it, instr would find
it.  You can use the DUMP() function to see exactly what data is
in the string.  For example:

ops$tkyte@ORA8I.WORLD> create table t ( x varchar2(11) );
Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into t values
                       ( 'Hello' || chr(10) || 'World' );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values
                       ( 'Hello' || chr(13) || 'World' );

1 row created.

ops$tkyte@ORA8I.WORLD> column dump format a15 word_wrapped
ops$tkyte@ORA8I.WORLD> select x, instr(x,chr(10)), dump(x)  dump
  2    from t
  3  /

X           INSTR(X,CHR(10)) DUMP
----------- ---------------- ---------------
Hello                      6 Typ=1 Len=11:
World                        72,101,108,108,
                             111,10,87,111,1
                             14,108,100

Hello
World                      0 Typ=1 Len=11:
                             72,101,108,108,
                             111,13,87,111,1
                             14,108,100
Review & Followup
Rating: 3
How are the uses of dump func tion October 09, 2001
Reviewer: A reader
Tom

Can you tell us how and where we can make use of the dump function, in our day
to day programming.

Thank you

January 03, 2001 ted -- Thanks for the question regarding "RBS question", version 8.1.6
You Asked
thomas,

I have 4 rbs tablespaces(400 mb per tablespace, total 1600mb)
rbs segment size is 2m miniextent 20 optimal size 40m(2mx20)
20 rbs segment each with 40 mb. total space 800m(20x40m)

rbs1-5 in ts 1   (40mx5=200mb this leave 200mb free to extend)
   6-10 in ts 2
   11-15 in ts 3
   16-20 in ts 4

==============
my rollstats have following info:

shriks, and extends are all zeros
a lot wrap.

q: why extends did not take place.

NAME                              RSSIZE   OPTSIZE   SHRINKS
AVESHRINK     WRAPS   EXTENDS
------------------------------ --------- --------- ---------
--------- --------- ---------
SYSTEM                            401408                   0
    0         0         0
RBS01                           42590208  41943040         0
    0        17         0
RBS02                           42590208  41943040         0
    0        89         0
RBS03                           42590208  41943040         0
    0       103         0
RBS04                           42590208  41943040         0
    0        97         0
RBS05                           42590208  41943040         0
    0        24         0
RBS06                           42590208  41943040         0
    0        95         0
RBS07                           42590208  41943040         0
    0        83         0
RBS08                           42590208  41943040         0
    0        94         0
RBS09                           42590208  41943040         0
    0        96         0
RBS10                           42590208  41943040         0
    0        92         0
RBS11                           42590208  41943040         0
    0        87         0
RBS12                           42590208  41943040         0
    0        75         0
RBS13                           42590208  41943040         0
    0        86         0
RBS14                           42590208  41943040         0
    0        99         0
RBS15                           42590208  41943040         0
    0        96         0
RBS16                           42590208  41943040         0
    0        61         0
RBS17                           42590208  41943040         0
    0        96         0
RBS18                           42590208  41943040         0
    0         6         0
RBS19                           42590208  41943040         0
    0        22         0
RBS20                           42590208  41943040         0
    0        98         0

q:
and we said...
extends will ONLY take place if we would need to wrap but cannot
wrap (since an active transaction is still using the "head" of
the rollback segment we would like to wrap into).

If we would like to wrap and we can wrap -- we do.  We will not
extend just because there is space.  We only extend when forced
to (and return an error if we cannot).

If you have lots of short transactions -- you'll never extend --
you'll wrap alot.
January 03, 2001 Nikunj -- Thanks for the question regarding "how much size of database", version 8.1.6
You Asked
hi tom,

i have below q.

1. how can i get the size of database ?
2. how can i get the how much database ocupy by different user ?
3. each user used how much space in each tables space ?

thanks.
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:285415955510
for overall tablespace/databse space usage.

To get stats by user, you will use the DBA_SEGMENTS view .  A
simple

select owner, sum(bytes) from dba_segments group by owner;

or

select owner, tablespace_name, sum(bytes) from dba_segments
group by owner, tablespace_name;

will give you the result you are looking for.
January 03, 2001 Sandy -- Thanks for the question regarding "Variable table names", version 2000 R2.1
You Asked
Hi Tom,

How can I access a table (delete, create, insert)  when the
table name is a variable?

Thanks

Sandy
and we said...
You need to use dynamic sql.  In forms, you can use forms_ddl()
or the EXEC_SQL package.  In the database you can use the
package dbms_sql.

If you search for any of
http://asktom.oracle.com/pls/ask/f?p=4950:7:::::F4950_P7_SEARCH_CRITERIA:exec_sql
http://asktom.oracle.com/pls/ask/f?p=4950:7:::::F4950_P7_SEARCH_CRITERIA:forms_ddl
http://asktom.oracle.com/pls/ask/f?p=4950:7:::::F4950_P7_SEARCH_CRITERIA:dbms_sql
on my site, you'll get various examples.

January 03, 2001 Asher -- Thanks for the question regarding
      "Reporting issues", version 816

      You Asked
Hi,

we have a web site for e-commerce purposes, it runs with
a weblogic application server,an oracle 8.1.6 database and
we are using java and jdbc to work with the oracle db, as a part
of the site we give our users reports about their
operations in our site.
Currently we do not use any report generator tool, and we do not
plan
to do so in the near future, I have several questions in general

regarding reporting in a web environment, if the questions are
not in your expertise area or are at a newbie level, maybe you
can point me to
a web site or any other reference regarding these issues.
1. When performing reports is it common to build a special view
per report ?, is it
"an expensive" operation for oracle to keep the views' data up
to date?
2. Is there a way to obtain the number of rows returned in a
select statement
(without exuting a select count statement), this is more a jdbc
question.
3. We have a report of 100 rows, can we start a select that will
bring 10
rows and show them to the user, and at the next http request
bring the next 10
(can we have something like an open cursor to be reused at the
second time
or something of that sort).
4. where is a good place to look for information of this kind,
which is basicly I presume application development

thanks in advance for taking the time to answer this huge
question.

Asher bitton

      and we said...
1) views are stored queries.  there is no cost associated with
"keeping data up to date" with views.  The entire Oracle data
dictionary (all_*, dba_*, user_* tables) are views.  This data
is not redundantly stored.

There is a feature called a materialized view (see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76994/mv.htm#721
for details).  For that there is extra storage and some overhead
associated with maintaining the currency of data.

2) You cannot get what we do not know.

Lets say you open a cursor like:

  select * from a_one_billion_row_table;

At the point in time you open that query -- we have absolutely
NO IDEA how many rows it will retrieve.  We do not prebuild the
answer somewhere and then start handing them out.  In most
cases, we've just come up with a PLAN to get the rows -- we
haven't gotten them.

3) see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:127412348064
4) the server concepts manual:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/toc.htm
is an excellent resource, as well the application developers
guides:

http://technet.oracle.com/doc/oracle8i_816/appdev.816/index.htm
Some of your questions are hard to get answered by a book
though.  The questions that have no answers for example

- how to get rowcount of a query without executing it.  That you
won't find in any book since its just not possible.

And the others that are sort of "tricks" (getting rows N through
M for example) you might not find easily.  For those, you can
search here or use the newsgroups (an excellent resource).

http://technet.oracle.com/
is another excellent resource.

January 03, 2001 Angelo -- Thanks for the question regarding
      "Obejects and Execute Immediate", version 8.1.5

      You Asked
Tom,

Thanks for the help the other day with the remote pl/sql.

The question I have now, still trying to get this other thing to work, is does
Execute Immediate support object types?  If not
does dbms.sql support pl/sql tables.

I'm trying to return a collection of elements from a remote host to a local host
but my dblink is created dynamically.  Any Ideas?

Thanks

Angelo

      and we said...
execute immediate supports objects HOWEVER, objects do not support distributed!
catch 22.  dbms_sql cannot bind to plsql tables, only to scalars or arrays of
scalars (for bulk inserts/updates and deletes, not for arguments to procedures).

So, how can you return a set.  You can return a set via a query over the db
link.  You would run the packaged procedure to get all in/out scalar variables.
You could then run a query to get the "result set".  Here is a full example.  On
the "remote" site I'll create a "record" type at the SQL level (must be at the
SQL level, not in PLSQL).  I'll create a nested table type of that record type.
Then, I'll create a package that accepts and returns any and all scalar
variables and fills in an array of this table type.  I have a function that
simply returns this global package variable and a view that turns it into a
result set.

Here is the code:

create or replace type myRecordType
as object
( x int,
  y date,
  z varchar2(25)
)
/

create or replace type myTableType
as table of myRecordType;
/

The above represents what I want to return as a result set.

create or replace package demo_pkg
as
    procedure prime_it( arg1 in out number );

    function return_it return myTableType;

end;
/

Prime It is the procedure I call to get all of the input/output scalar
arguments AND to fill in the result set table...

create or replace package body demo_pkg
as

some_data myTableType := myTabletype();

procedure prime_it( arg1 in out number )
as
begin
    for i in 1 .. arg1 loop
        some_data.extend;
        some_data(i) :=
            myRecordType( i, sysdate+i, 'record ' || i );
    end loop;
end;

function return_it return myTableType
as
begin
    return some_data;
end;

end;
/

Here my function just makes up some data.  Lastly, I create a view at this
remote site to "hide" the object type since I need to do this over a db link:

create or replace view
demo_pkg_view
as
select * from
TABLE ( cast( demo_pkg.return_it() as mytableType ) )
/

Now, on the other site, I need to run an anonymous block that factors in the
db link dynamically and then OPEN a cursor on that site.  It would look like
this:

declare
    type rc is ref cursor;

    l_db_link varchar2(255) default 'ora816dev.us.oracle.com';
    l_n       number := 5;
    l_result  rc;
    l_x       int;
    l_y       date;
    l_z       varchar2(25);
begin
    execute immediate
      'begin demo_pkg.prime_it@'||l_db_link || '(:x); end;'
    using in out l_n;

    open l_result for
         'select * from demo_pkg_view@' || l_db_link;

    loop
        fetch l_result into l_x, l_y, l_z;
        exit when l_result%notfound;

        dbms_output.put_line(l_x || ',' || l_y || ',' || l_z);
    end loop;
    close l_result;
end;
/

The above was executed in an 8.1.6.2 database to an 8.1.6.2 database...
January 03, 2001 wallacel -- Thanks for the question regarding
      "issys_modifiable", version 8.1.6

      You Asked
Tom:

what does issys_modifiable in v$parameter means?
for sort_area_size , it is deferred,
but i can't use alter system set sort_area_size=value to modify
it.
deferred means the parameter cannot be changed until the next
session.
I don't understand what does  "until the next session" means

      and we said...
You have to set it "deferred".  That means the setting cannot be
changed for EXISTING sessions but it can be changed for all
FUTURE sessions:

sys@DEV816> alter system set sort_area_size=100000 DEFERRED;
System altered.

until I exit and re-enter sqlplus, the old setting of
sort_area_size will be in effect.
January 04, 2001 ken -- Thanks for the question regarding "use
      hints ?", version 8.1.5

      You Asked
Tom,

Happy new year !!!

What is the best way for me to update all rows in table e.g

I have to update 2 columns in table with the values from 2 other
columns in the same table.  I can do this:

update table_a
set col_a = col_c,
    col_b = col_d;

but this will be very slow if there 's alot of rows.

Thanks

      and we said...
You have to update every row.  You will visit every row.
Regardless of whether you do this in 1 statement as above or
1000 statements -- it'll generate a simiar amount of redo and
rollback.

It won't be any slower to do with 1 statement then 1000
statements (in fact, a single statement will typically
outperform procedural logic every time).

However, you might be able to "update in parallel".  If you are
doing this to a partitioned table, you can use parallel DML on
it.  You could also start up N sessions and partition the table
yourself in some fashion.  For example, if this table has a
primary key X with values 1..100000, you could fire off 10
sessions that each did:

  update table_a set col_a = colc, col_b = cold
    where x between &low_bound and &high_bound;

to update all of the rows "in parallel"
January 04, 2001 Srinivas -- Thanks for the question regarding
      "Long RAW", version 8.0.5

      You Asked
I know that Long RAW columns are for backward compatibility. But
if I have columns that are Long RAW and they store text files
how will I retrieve these files from the database and view them?
Can I use PL/SQL or do I have to go for OCI, C, Java?

      and we said...
With 8.0, your options are somewhat limited.  OCI, Pro*C, Java,
VB would all work.  if the long raw is always 32k or less, PLSQL
can do it as well.

In 8.1, you can "insert into t2 select to_lob(lr_column) from t1
where ..." to convert a long raw into a blob and then use plsql
to process it totally.
January 04,
      2001 Bala -- Thanks for the question
      regarding "Security", version 8.1.6

      You Asked
Hi Tom

Company Wanted to implement Security features in their
application.  The application is non oracle based application
(PERL, may be they may use JAVA later stage). How can this be
achieved from oracle side.  Do we have any materials online.

Thanks

`

      and we said...
See

http://osi.oracle.com/~tkyte/article2/index.html
sounds like a perfect application of fine grained access
control.  This feature allows you to implement security policies
in the database regardless of the client.  The data is protected
at the source.
January 04, 2001
      Vladimir -- Thanks for the question
      regarding "Designer 6i", version 8i

      You Asked
Hi Tom, Can I install Desginer 6i (For windows 2000/98/95) with
Oracle 8i Personal Edition Version 8.1.6 (for Windows
2000/98/95) on one PC with Windows 98?, I read that Oracle
Designer 6i is certified for use against a Repository installed
onto Oracle 8.1.6 Enterprise Edition, that means I need to
instal Oracle 8.1.6 Enterprise Edition on the PC or exist some
personal edition to use on Windows 98 where will be the
repository and where I can download because on
technet.oracle.com offer just Oracle 8 version 8.0?

Thanks Tom

      and we said...
The personal edition of 8.1.6 is supported with designer 6i
RELEASE 2 only  (not release 1).  With release 1 (you don't
specify) you would need 8.1.6 EE.

I do not believe 8.0 is posted anywhere for download anymore.
We typically stage only the latest versions of software on
technet.
January 04, 2001 Ravi -- Thanks for the question regarding "Limit
      of export file on solaris 2.6 and oracle 815", version 815

      You Asked
Dear Tom,

My solaris version is 2.6 and oracle is 815

I am exporting to a veritas logical volume. It was built with
largefile system option.

However, when I am exporting and when the dump size reaches 2G,
the following error occurs

EXP-00002: error in writing to export file
EXP-00222:
System error message 27
EXP-00002: error in writing to export file
EXP-00000: Export terminated unsuccessfully

Some where I read that this restriction exists only in solaris
2.5 /solaris 2.6 and above which cannot support large file
systems/ oracle version 7 and below.

However, in the same logical volume I could create a file with
mkfile of 3G.

Could you please give your comment on why the error occurs.
However, I am planning with filesize option of exp tool.

Thanks
Ravi

      and we said...
The support for large files has to be built into the
applications.  The database itself supports large files but,
like many OS tools, exp and imp only support "normally" sized
files.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1216036222364
for the 2 solutions (one you already mentioned, the other is the
one I like to use -- exp to a named pipe, compress it and split
it.  takes less space and you don't have to figure out the max
number of files you might ever want to export to)
January 04, 2001 Vladimir -- Thanks for the question regarding
      "Oracle Product & Reports", version 8i

      You Asked
Hi Tom,
Can you explain me please more about the release product of
Oracle, I means when somebody talk about personal edition of
8.1.6 that means Personal Oracle 8i release 8.1.6, what was the
release for Personal Oracle 8? just 8? not 8i?,
Other question that I have is about to generate report on the
browser!!, it will be better to write the SQL procedure inside
Java Servlet or JSP like:
executeQuery ("Select ....from...where...")
or
it will be better to create inside to Database and then used
CallableStatment cstmt = conn.prepareCall("{call
procedure_name(?,?)}")
and why is better?
thanks Tom

      and we said...
In the 8i family we had:

Oracle8i release 1, version 8.1.5
Oracle8i release 2, version 8.1.6
Oracle8i release 3, version 8.1.7

In the Oracle8 family we had:

Oracle8, version 8.0.3
Oracle8, version 8.0.4
Oracle8, version 8.0.5
Oracle8, version 8.0.6

In the Oracle7 family we had

Oracle7 version 7.0 - 7.3  (with each having at least one more
digit behind it, 7.0.13, 7.1.6, 7.2.3, 7.3.4 for example).

For number 2, neither is "better" then the other.  If you do it
in the database, you probably wouldn't introduce Java into the
mix at all -- you would just use the PLSQL cartridge which is a
piece of software to convert a URL into a stored procedure call
at the webserver level.  If you used java, you would use a
mixture of SQL and stored procedures typically to get the job
done.
January 04, 2001 Wendy -- Thanks for the question regarding
      "PL/SQL Procedure ", version Oracle 7.3.4 on NT Server

      You Asked
Dear Tom:
Two questions:
1. How to identify fragmented tablespace and how to fix them?
2. I tried to delete a lot of row( about 1 millions) from a
table (I can't use truncate, because I need to keep some data ),
but it came back a message saying that max# of extents reached
for RB1, I heard that a PL/SQL procedure would help accomplish
this, can you help me?

Thanks

      and we said...
1) a fragmented tablespace occurs when you have lots of "weird"
sized free extents in a tablespace that cannot be used by any of
the objects in that tablespace.  This typically happens only if
you truncate or drop objects frequently in a tablespace (it is
not possible to have a fragmented tablespace if you never drop,
truncate, or rebuild objects).

You can detect this by looking at DBA_FREE_SPACE.  This will
list all of the free extents in your tablespace.  You can then
look at the next extents for the objects in your tablespace.  If
any of the sizes of the free extents in DBA_FREE_SPACE are
smaller then the smallest NEXT extent, you have some fragmented
chunks of space that will never be used.

Many people like to use PCTINCREASE=0 (i do) and next extent
sizes that are either EQUAL to eachother (eg: all objects in
this tablespace will use a 5meg next extent) or multiples of
eachother (eg: 5/10/20 meg extents).  In this fashion, the odds
of having an orphan chunk of space is very small.

In Oracle8i, we introduced the concept of locally managed
tablespaces (you can search my site for locally managed to read
about them).  I like them alot, especially with the UNIFORM
sizing strategy.  Using this, the database will ignore NEXT
extent sizes and PCTINCREASES.  All extents are always the same
size.  It is impossible to have a fragmented tablespace in this
case.

To "fix" it, if you have a problem, involves exporting the
objects in the affected tablespace, dropping them and importing
them back in.

2) one approach would be to increase the size of your rollback
segments so your transaction can fit properly into the rollback
segment.  If you cannot do this, you can use a statement such
as:

loop
  delete from T where <some predicate> AND rownum < 10000;
  exit when sql%rowcount = 0;
  commit;
end loop;
commit;

That'll delete 10k rows at a time and commit each "batch".  what
also works (and usually works better) is if you can "partition"
the table somehow.  Lets say the rows you wanted to delete had a
nice indexed column that had the number 1..1000000 in it.  You
could fire off 10 concurrent sessions each of which does:

  delete form T where id between 1 and 100000;

to delete chunks of the data in parallel.

January 04, 2001 Amitava -- Thanks for the question regarding
      "Temporary Table", version 8..1.5

      You Asked
I am using temporary table concept to create temporary selecting
data from a tables. Presently I am trying to creste temporary
table selecting data from union of two queries but I am geting
an error. The procedure and error are given below:
Procedure:

 create or replace procedure test497 as
se_id VARCHAR2(30);
 Begin
se_id := userenv('sessionid');
execute immediate 'create global temporary table temp_497a_' ||
se_id ||'
on preserve commit rows as select
h.icn,tot_prc,to_char(d_rqsdt,''yyyymmdd'') d_rqsdt,
to_char(d_plsdt,''yyyymmdd'')
d_plsdt,to_char(d_shpdt,''yyyymmdd'') d_shpdt,
cust_name,bill_flag,full_cycle_flag,0 met,0 days_late,0
met_2wk,0 non_bill,0 bill,
0 full,0 short,0 full_met,0 short_met from
beam.orddtl@beam97 d, beam.ordhdr@beam97 h where h.icn = d.icn
and h.business in
(''STM'', ''GAS'') and ((h.div=''L'' or
h.div=''S'' or h.div=''G'') and (h.gen_flag!=''Y'' or h.gen_flag
is null)) and
cust_num = ''1839M'' and
h.order_type = ''CUS'' and to_char(d_shpdt,''yyyymmdd'')
between ''19951101'' and ''19960201''
union
select h.icn,tot_prc,
to_char(d_rqsdt,''yyyymmdd'') d_rqsdt,
to_char(d_plsdt,''yyyymmdd'')
d_plsdt,to_char(d_shpdt,''yyyymmdd'')
d_shpdt,cust_name,bill_flag,full_cycle_flag,0 met,
0 days_late,0 met_2wk,0 non_bill,0 bill,0 full,0 short,0
full_met,0 short_met from
beam.orddtlh d, beam.ordhdrh h where h.icn = d.icn and
h.business in
(''STM'', ''GAS'') and ((h.div=''L'' or h.div=''S'' or
h.div=''G'') and
(h.gen_flag!=''Y'' or h.gen_flag is null)) and
cust_num = ''1839M'' and h.order_type = ''CUS'' and
to_char(d_shpdt,''yyyymmdd'')
between ''19951101'' and ''19960201'''  ;
End;

Error:
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "BHOWMIAM.TEST497", line 8
ORA-06512: at line 1

Please suggest me how can I create a temporary table which fetch
data from union of two queries, each query fetching data from
two different source?

      and we said...
see
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for why you are getting the "table or view does not
exist".  Roles are not active in a stored procedures and you
must have access to these tables via a role.  In Oracle8i, there
is invokers rights, see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:961430030094
for an example.  Invokers rights do allow for some use of
roles in stored procedures.

btw: this is not the proper way to use temporary tables in
Oracle.  You should create the global temporary table ONCE
(outside of a procedure).  Each session will only see its data,
all users should use the SAME temporary table.  Doing DDL like
that is extremely expensive and makes it so you have to access
the temporary table using dynamic SQL only.

Your procedure should be:

create or replace procedure test497
as
  se_id VARCHAR2(30);
begin
  se_id := userenv('sessionid');
  insert into temp_497a
  select  h.icn,tot_prc,
           to_char(d_rqsdt,'yyyymmdd') d_rqsdt,
  .....
end;
/

January 04, 2001 Marc -- Thanks for the question regarding
      "Convert minutes into HH:MM:SS format", version version 8.0.5.0.0

      You Asked
Hi Tom,

I am creating a report in Developer and I am pulling a minutes
field from the database. Is there a way to convert the minutes
to HH:MM format(e.g. 93 minutes to 01:33)?

      and we said...
I hope you are using HH:MI -- not HH:MM which would be Hours and
MONTHS!

If you have minutes stored in a number field, so that you have
the number 93, the following will do it:

to_char( trunc(sysdate) + 93/24/60, 'hh:mi' )
                          ^^ replace that with your number...

That just adds 93 minutes to midnight today and then formats it
in hours and minutes.

Review &
      Followup

      Rating:
      5
  April 19, 2003
Reviewer:
      A reader

January 04, 2001 Scott -- Thanks for the question regarding "Long
      DataType Concat with VarChar?", version 805

      You Asked
I have the two description fields in a table as follows:
SQL> desc exav.work_history_sv
 Name                            Null?    Type
 ------------------------------- -------- ----
 WORK_ID                         NOT NULL NUMBER(38)
 PROBLEM_ID                      NOT NULL VARCHAR2(15)
 USER_ID                         NOT NULL VARCHAR2(15)
 WORK_BEGIN_DATE                 NOT NULL DATE
 WORK_BEGIN_TIME                 NOT NULL VARCHAR2(10)
 WORK_END_DATE                   NOT NULL DATE
 WORK_END_TIME                   NOT NULL VARCHAR2(10)
 DESCRIPTION                              VARCHAR2(254)
 DESC_OVRFLW                              LONG
 MODIFY_DATETIME                 NOT NULL NUMBER(38)

Tivoli puts whatever doesn't fit into description into
desc_ovrflw.  I don't know why they didn't use a longer
description field but I need to report on the entire
description.  How do I write an SQL query that will return the
text from description and desc_ovrflw as one column?
SELECT DESCRIPTION || DESC_OVRFLW ...
Does Not Work because of inconsistent datatypes.

Regards,
Scott

      and we said...
we can get the first 4000 bytes in SQL only (the first 4000
bytes of DESCRIPTION || DESC_OVRFLW ).  As long as the
desc_ovrflw does not exceed 32k -- this will work fine:

ops$tkyte@ORA8I.WORLD> create table work_history_sv
  2  ( description varchar2(254),
  3    desc_ovrflw long
  4  )
  5  /
Table created.

ops$tkyte@ORA8I.WORLD> create or replace
  2  function description4000( p_rowid in rowid ) return
varchar2
  3  as
  4          l_c1 varchar2(254);
  5          l_c2 long;
  6  begin
  7          select description, desc_ovrflw
  8            into l_c1, l_c2
  9            from work_history_sv
 10           where rowid = p_rowid;
 11
 12          return substr( l_c1||l_c2, 1, 4000 );
 13  end;
 14  /
Function created.

ops$tkyte@ORA8I.WORLD> create or replace view
work_history_sv_view
  2  as
  3  select a.*, description4000(rowid) desc_4000
  4    from work_history_sv a
  5  /

View created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into work_history_sv values(
'hello world', ' this is the overflow' );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select * from work_history_sv_view
  2  /

DESCRIPTION
-----------------------------------------------------------------
-----------------------------------
DESC_OVRFLW
-----------------------------------------------------------------
---------------
DESC_4000
-----------------------------------------------------------------
-----------------------------------
hello world
 this is the overflow
hello world this is the overflow

January 04, 2001 David -- Thanks for the question regarding
      "Saving Server Module Diagram as a PDF file", version 8.1.5/Designer 6.0

      You Asked
Tom,

When I save my server module diagram on my PC, it puts it in a
format that I'm unfamiliar with.  I'd like to save it as a PDF
file so I can e-mail it out to others as an attachment.  Is
there any way to do this?

Thanks,

/Dave

      and we said...
I do not work with designer much myself so I asked someone for
help on this one and they say:

...
You're right: easy question. Unfortuantely not an easy answer.
See http;//invincible.uk.oracle.com/faq/web_diagrams.html for
the best alternative. Designer is an OLE server/container (can't
remember which is which), so another option is to copy the
document and paste it into MS Word.
....

Now, you won't be able to "see" invincible, its behind the
Oracle firewall but what they say there is:

....
Previously we would have suggested using software from Solutron
to publish diagrams to the web. This software is no longer being
developed by Solutron and should therefore not be suggested as
the answer. The current alternative is to install Adobe Acrobat
4.0 (approx $250). This software comes with an Acrobat PDF
Writer that effectively acts as a Printer Driver. From any of
the Designer Diagrammers choose the Print command from the file
menu and change the name of the printer to the Adobe Acrobat
PDFWriter. Check the fit to a single page checkbox, you can zoom
in using the Adobe Acrobat Reader, and print to file. You will
be asked for a file name. Place the file in a directory that a
Web Server can access, construct a page with some appropriate
HTML links and your diagrams will appear on the web. Ensure that
the diagram is documented by including the Summary Information.
(Option under the Diagram File Menu option)
.....

Thanks to Tim Taylor for help on this one....

January 04, 2001 Bharath Kumar -- Thanks for the question
      regarding "Oracle on a Raw Partition (on NT)", version 8.1.6

      You Asked
Hi Tom,

   In fact this is not a pure Oracle question. I want to try
running Oracle on a Raw Partition. But I have NT/2000 machines
with me. Can I immplement a raw partition in NT and run Oracle
on it ? If so, what are the special config changes I have to
make ? Please explain...

Regards

Bharath

      and we said...
See

http://technet.oracle.com/doc/oracle8i_816/nt.816/a73008/apd.htm#620714
for all of the gory details....
January 04, 2001 Bharath Kumar -- Thanks for the question
      regarding "Dynamic SQL", version 8.1.6

      You Asked
Hi Tom,

   I am developing a pl/sql block for online database backups. I
wanted to execute statements thru the 'Execute Immediate'
statement. The regular statements go through normally... But
when I have a statement like 'host copy <filename>
<destination>', it throws up an error saying 'Invalid SQL
Statement'. Can you please explain the error ?

Regards

Bharath

      and we said...
PLSQL is running in the server.  HOST is a SQLPlus command and a
forms command.  HOST is not a PLSQL or SQL command and cannot be
used in PLSQL.

some of your options are:

o use RMAN.  This is a tool designed to automate and manage your
backups for you.

o use Java.  Java running in the database (or outside of the
database) has the ability to do things in the operating system.
PLSQL is somewhat confined to the "database".

o write a file copy routine in C and link that in as an external
procedure that is callable from PLSQL.  In that fashion, PLSQL
will be able to "copy" a file.

It should be noted that for something as important as a backup,
even if HOST worked -- it would be a very bad idea.  The HOST
command would give you no opportunity to check the success or
failure of the copy.  You need something a little more low level
for backing up with.
January 04,
      2001 Sam -- Thanks for the question
      regarding "Does Oracle Intermedia support Word 2000 ?", version 8.1.6

      You Asked
Hi Tom,

I have currently trying something out on Oracle Intermedia
but got a problem that need your help.

I have a document created using Word 2000.
(i have a table with a BFILE as the column type)

When I run a query like:
SELECT ID from EMP where contains(thefile, 'Oracle') > 0

it does not return the result even though the file has that
keyword.

I tried to save the file as Word 6.0/95 and then reinsert
a record in that table.
This time, it's able to return the ID.

Is there a new INSO filter for this ?

Thanks a lot.

      and we said...
The office 2000 family of file formats is supported with version
8.1.7 of intermedia.

Review &
      Followup

      Rating: 4
ms office
      word  October 06, 2003
Reviewer:  alzaghier
       from az
can i display my letter in word which send data from report dev

January 05, 2001 Paul -- Thanks for the question regarding
      "Wanting to know what is a good book for an beginner.", version Not Sure

      You Asked
Hello Tom,

I have advance knowledge about Microsoft Windows operating
systems and networks. I would like to get to know about Oracle
server's. I really know nothing about Oracle. I know that Oracle
is taking over and is the way to go when it come to the
internet. So I would like to increase my knowledge to stay with
the game. So if you can please advise a good book to read to
some one with advanced knowledgement of computers and networks
that would be appreciated.

Thanks alot...

      and we said...
Strong recommend the Oracle8i Concepts manual as a starting
place.  See

http://technet.oracle.com/doc/oracle8i_816/server.816/index.htm
...
January 05, 2001 OP -- Thanks for the question regarding "What
      value is optimal for PCTINCREASE in Temporary Tablespace !", version
      8.1.6.0

      You Asked
Dear Tom,
Hi !

WISH YOU A VERY HAPPY,WONDERFUL AND PROSEPROUS NEW YEAR !

Ques) What value of should be given to PCTINCREASE in a
TEMPORARY TABLESPACE ?

Ques) Can I access internal structure like Library Cache
from the memory.Is there any special previlege or
permission is required to access this ?

DOES ORACLE SUPPORT LOW LEVEL ACCESS TO MEMORY ?

Thanks & Regards
OP

      and we said...
pctincrease = 0 is the best.  You should make the extents an
integer multiple of the sort_area_size for your database and
have initial=next with pctincrease=0.

as for accessing the library cache, you can use the v$ views to
see whats in there.  Refer to the Oracle8i reference manual for
a description of these views.

You cannot access our memory directly, the v$ views expose our
data structures as tables.
January
      05, 2001 OP -- Thanks for the question
      regarding "Difference between SYS and SYSTEM User Account !", version
      8.1.6.0

      You Asked
Dear Tom,
Hi again !

When we Install Orcale,by Default we get SYS and SYSTEM
as an account.

If I do not create my DBA account on this system,can
I administrate ORACLE compeletely through either of
these accounts ,If Yes,through which account I can
take a full control over the database.Is it SYSTEM
or SYS Account.

What is the difference between SYS,SYSTEM and Internal
Login's ?

Kindly answer.

Thanks & Regards
OP

      and we said...
I would not use either of SYS or SYSTEM except when I was
directed to by a specific installation procedure.  You should
create your own DBA accounts and grant them the sysdba or
sysoper privelege to startup/shutdown the database.

SYS is special.  But sys is not good enough.  You need INTERNAL
or SYSDBA to do certain operations.  I would recommend strongly
against using SYS to do things.  SYS cannot create triggers, SYS
cannot have read only transactions, and so on.  SYS should not
be used.

System is just an account, nothing special about it.  We use it
to store various things.

Internal is a super special account.  It is a SYSDBA/SYSOPER.
It can startup/shutdown the database.  You should avoid using it
as it will be going away at some point in the future.  The
correct approach is to "connect user/password AS sysdba" to
perform these operations.

January 05, 2001 Puneet -- Thanks for the question regarding
      "Dynamic SQL", version 8.1.5.0.0

      You Asked
Hello Tom,
A very Good Morning.
I wish to know how can I using EXECUTE IMMEDIATE populate value
in more than 1 variable with a SELECT query using INTO.

For eg. SELECT COUNT(1), field_name1, field_name2
FROM table_name
INTO var1, var2, var3;

Regards
Puneet Mathur

      and we said...
Just like you have it.  You are missing a group by in your
query:

ops$tkyte@ORA8I.WORLD> declare
  2      x  varchar2(25);
  3      y  varchar2(25);
  4      z  varchar2(25);
  5  begin
  6      execute immediate
  7         'select sysdate, count(*), rownum
  8                    from dual
  9                   group by sysdate, rownum'
 10       into x, y, z;
 11  end;
 12  /

PL/SQL procedure successfully completed.
January 05, 2001 Meng Keong -- Thanks for the question regarding
      "stop user from connecting to the db from more than 1 machine/location at
      the same time", version version 7.3.4

      You Asked
Q1:
i have some html files and some orcale forms in a winNT server.
from these html files, there is a link to launch an oracle
form. so users can launch the oracle form from anywhere as long
as they have access to my html files.
my question is: can we limit the number of users from launching
the oracle form?

Q2:
i know about the profile in database, but even if i limit the
session per user, the user can still connect to the db from more
than one location/machine at the same time.
Is there a way to stop the user from connecting to the db from
more than 1 machine/location. I want to give the user unlimited
sessions but i want to limit the user to only 1 connection to
the db from one location/machine.

Thank you in advance.

ps: Happy New Year! Cheers!

      and we said...
You could use resource profiles (see the admin guide) to limit
people to 1 session.

If you want it to be that they can run your form only once but
have as many other sessions as they want, you can use
dbms_application_info and some startup logic in your form.  Your
application would do something like:

  begin
    dbms_application_info.set_client_info( 'my form name' );
  end;

upon startup.  It would also query (or perhaps someone with
access to v$session would code a stored procedure to return this
data):

    select count(*)
      from v$session
     where username = USER
       and client_info = 'my form name';

If the count came back as 2 or more, you would simply exit the
form immediately.

For q2 -- I do not understand that.  If you limit them to 1
session per user, they can only have one session in the database
-- period.  If they goto another location/machine, and they have
a session opened elsewhere, they cannot log in.
January 05, 2001 Randy -- Thanks for the question regarding
      "Tablespace and Tables sizing", version Oracle 8i (8.1.5)

      You Asked
1. I'm trying to insert a 500,000 record to my historical table
   from my temporary table, when suddenly I encounter the error
   ORA - 01653  Unable to extend tablename from tablespace .....

   What is the problem basically ?  My tablespace is still have
enough space. I normally encounter this problem if I try to
insert large number of records like 200,000 and above.

    What steps should I do to eliminate this problem?

Thank you very much !!!

      and we said...
Your tablespace might be big enough but it sounds like it is
"fragmented".  When a table attempts to extend, it will look for
a set of contigous blocks that is equal or greater to its next
extent size.  Lets say your table wants a 1meg next extent.
Further, your tablespace has 2meg free.  The attempt to "grow"
the table might very well fail even though you want 1meg and
there is 2meg free.  If the free 2meg of data is scattered in 4
chucks, each of 512k and they are not contigous -- we cannot
allocate that 1meg extent.

You can use my script free.sql to print out how much free space
is in a tablespace AND the largest contigous set of free space
(see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:285415955510
for a copy).  If your next extent is larger then this
"largest" chunk, it will not be able to extend.  You either need
to alter the table to have its next extent be smaller then the
largest contigous chunk of space or add more space to the
tablespace itself.

January 05, 2001 bhalchandra -- Thanks for the question regarding
      "Select Statement ", version Report Builder 6.0.5.28.0

      You Asked
Hi TOM,

I am Working on Developer 6 Report Builder 6.0.5.28.0

I have table structure as below

DSG_CNTSCH
Name                            Null?    Type
------------------------------- -------- ----
ACTIVITY_NO                     NOT NULL VARCHAR2(2)
ASSGN_EMPCODE                            VARCHAR2(5)
WRK_DATE                                 DATE
TOT_HRS                                  NUMBER(3)

and fill Data like this;

AC ASSGN WRK_DATE     TOT_HRS
-- ----- --------- ----------
12 001   25-DEC-00          9
12 002   18-DEC-00          9
12 003   18-DEC-00          9
12 001   19-DEC-00          9
12 002   19-DEC-00          7
12 003   20-DEC-00          3
12 003   20-DEC-00          5
12 001   23-DEC-00          9
12 002   23-DEC-00          6
12 003   23-DEC-00          3
12 001   24-DEC-00          8
12 002   24-DEC-00          9
12 001   26-DEC-00          8
12 002   26-DEC-00          9
12 003   26-DEC-00          9
12 001   28-DEC-00          9
12 002   28-DEC-00          8
12 003   28-DEC-00          9
12 001   29-DEC-00          4
12 002   29-DEC-00          9
12 003   29-DEC-00          9
12 001   30-DEC-00          5
12 002   30-DEC-00          9
12 003   30-DEC-00          9

I want data shown like below when select statement run.
There are no data of date '27-DEC-00' in table.

AC ASSGN WRK_DATE     TOT_HRS
-- ----- --------- ----------
12 001   27-DEC-00          0
12 002   27-DEC-00          0
12 003   27-DEC-00          0

I wright query like this :

select  A.ACTIVITY_NO,  A.ASSGN_EMPCODE,
to_date('27/12/2000','dd/mm/yyyy') WRKDT,
sum(nvl(A.TOT_HRS,0))  TOT_HRS
from  ASB.DSG_CNTSCH A
where  A.WRK_DATE = to_date('27/12/2000','dd/mm/yyyy')
group by A.ACTIVITY_NO, A.ASSGN_EMPCODE,
to_date('27/12/2000','dd/mm/yyyy')
/

Result is

'no rows selected'

please tell how to get that data.

Thanking you in anticipation

      and we said...
What we have to do is generate a set of data that is "complete".
 Looking at your example, you want for a given activity_no (12
in your case) the three assgn_empcode's for every day in a given
range.  In order to generate that data, we can use this query:

ops$tkyte@ORA8I.WORLD> select * from
  2  (select '12' activity_no, '001' assgn_empcode from dual
       union all
  3   select '12', '002' from dual union all
  4   select '12', '003' from dual) ,
  5  (select to_date( '18-dec-00' )+rownum-1 wrk_date
  6     from all_objects
  7    where rownum     < 14 )
  8  /

AC ASS WRK_DATE
-- --- ---------
12 001 18-DEC-00
12 002 18-DEC-00
12 003 18-DEC-00
12 001 19-DEC-00
12 002 19-DEC-00
12 003 19-DEC-00
12 001 20-DEC-00
12 002 20-DEC-00
12 003 20-DEC-00
12 001 21-DEC-00
12 002 21-DEC-00
12 003 21-DEC-00
12 001 22-DEC-00
12 002 22-DEC-00
12 003 22-DEC-00
12 001 23-DEC-00
12 002 23-DEC-00
12 003 23-DEC-00
12 001 24-DEC-00
12 002 24-DEC-00
12 003 24-DEC-00
12 001 25-DEC-00
12 002 25-DEC-00
12 003 25-DEC-00
12 001 26-DEC-00
12 002 26-DEC-00
12 003 26-DEC-00
12 001 27-DEC-00
12 002 27-DEC-00
12 003 27-DEC-00
12 001 28-DEC-00
12 002 28-DEC-00
12 003 28-DEC-00
12 001 29-DEC-00
12 002 29-DEC-00
12 003 29-DEC-00
12 001 30-DEC-00
12 002 30-DEC-00
12 003 30-DEC-00

39 rows selected.

that just "makes up" the data in the range we want.  You would
use different constants of course to generate different ranges.
We can now OUTER JOIN that to our original data:

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select a.activity_no, a.assgn_empcode,
a.wrk_date, nvl( b.tot_hrs, 0 )
  2    from (select * from
  3    (select '12' activity_no, '001' assgn_empcode from dual
union all
  4     select '12', '002' from dual union all
  5      select '12', '003' from dual) ,
  6      (select to_date( '18-dec-00' )+rownum-1 wrk_date
  7         from all_objects
  8           where rownum  < 14 ) ) A,
  9    dsg_cntsch B
 10  where a.activity_no = b.activity_no(+)
 11    and a.assgn_empcode = b.assgn_empcode(+)
 12    and a.wrk_date = b.wrk_date(+)
 13  order by a.wrk_date
 14  /

AC ASS WRK_DATE  NVL(B.TOT_HRS,0)
-- --- --------- ----------------
12 001 18-DEC-00                0
12 002 18-DEC-00                9
12 003 18-DEC-00                9
12 001 19-DEC-00                9
12 002 19-DEC-00                7
12 003 19-DEC-00                0
12 001 20-DEC-00                0
12 003 20-DEC-00                5
12 003 20-DEC-00                3
12 002 20-DEC-00                0
12 001 21-DEC-00                0
12 002 21-DEC-00                0
12 003 21-DEC-00                0
12 001 22-DEC-00                0
12 003 22-DEC-00                0
12 002 22-DEC-00                0
12 001 23-DEC-00                9
12 003 23-DEC-00                3
12 002 23-DEC-00                6
12 001 24-DEC-00                8
12 002 24-DEC-00                9
12 003 24-DEC-00                0
12 001 25-DEC-00                9
12 002 25-DEC-00                0
12 003 25-DEC-00                0
12 001 26-DEC-00                8
12 002 26-DEC-00                9
12 003 26-DEC-00                9
12 001 27-DEC-00                0
12 003 27-DEC-00                0
12 002 27-DEC-00                0
12 001 28-DEC-00                9
12 002 28-DEC-00                8
12 003 28-DEC-00                9
12 001 29-DEC-00                4
12 002 29-DEC-00                9
12 003 29-DEC-00                9
12 001 30-DEC-00                5
12 002 30-DEC-00                9
12 003 30-DEC-00                9

40 rows selected.

filling in the gaps....
January 05, 2001 Stefan -- Thanks for the question regarding
      "Returning Result Sets from Stored Procedure", version 8.04

      You Asked
Hi,

in all examples i've read until now, stored procs
only return data via parameters.

Is it possible to get one or more result sets back from a sp
like in DB2?

DB2-Example:

within SP:
  DECLARE CURSOR xyz WITH RETURN AS
    select blah from blah

      and we said...
see

http://osi.oracle.com/~tkyte/ResultSets/index.html
....
January 05, 2001 Prem -- Thanks for the question regarding
      "Creating Views", version Oracle 8

      You Asked
I have created a package that contains a Type as follows

package PKG_TEST as
Type shifts_ty is RECORD(
    comp_code    varchar2(10),
    SHIFT_CODE    varchar2(10),
    sft_flg        varchar2(10),
    beg_tm        number,
    end_tm        number,
    skills        varchar2(10)
    );
Type shifts is Table of shifts_ty index by binary_integer;
end;

Create package body PKG_TEST_BODY
as
AS

 FUNCTION test_proc(test varchar2)

return shifts is
shiftspkg SHIFTS;

cursor q1 is select
shifts.comp_code,shifts.shift_code,shifts.WRK_BEG_TM,shifts.WRK_e
nd_TM,
shifts.skills from str_shifts shifts where comp_code ='TSI';
qty q1%rowtype;
begin

    open q1;
    loop
        fetch q1 into qty;
        exit when q1%notfound;

        for iCount in 1.. qty.skills.count
        loop
            shiftspkg(icount).comp_code:= qty.comp_code;
            shiftspkg(icount).SHIFT_CODE:= qty.shift_code;
            shiftspkg(icount).sft_flg:= 'SLOTS';
            shiftspkg(icount).beg_tm:= qty.wrk_beg_tm;
            shiftspkg(icount).end_tm:= qty.wrk_end_tm;
            shiftspkg(icount).skills:= qty.skills(icount);

        end loop;

    end loop;
    return    shiftspkg;
end;

end;
/

The function return a the shifts as defined in the package.
Can I now create view using this function like this

create view vt_test as select * from
TABLE(Cast(pkg_test.test_proc('dd') as shifts))
/

I tried this out but not successful. Could you please tell me
where I have gone wrong and if this is not possible suggest an
alternative.

Thank You!!!

      and we said...
You need to use SQL types -- not plsql types.  SQL has no idea
what pkg_test.test_proc returns or what the type "shifts" is all
about.

Here is your example in Oracle8 release 8.0:

tkyte@ORA806.WORLD> create or replace type myScalarType as
object
  2  ( comp_code varchar2(10),
  3    shift_code varchar2(10),
  4    sft_flg        varchar2(10),
  5    beg_tm        number,
  6    end_tm        number,
  7    skills        varchar2(10)
  8  )
  9  /

Type created.

tkyte@ORA806.WORLD>
tkyte@ORA806.WORLD> create or replace type myArrayType as table
of myScalarType
  2  /

Type created.

tkyte@ORA806.WORLD>
tkyte@ORA806.WORLD> create or replace package pkg_test
  2  as
  3      function test_proc( test varchar2 ) return myArrayType;
  4      pragma restrict_references(test_proc,wnds,wnps);
  5  end;
  6  /

Package created.

tkyte@ORA806.WORLD>
tkyte@ORA806.WORLD> create or replace package body pkg_test
  2  as
  3
  4  FUNCTION test_proc(test varchar2) return myArrayType
  5  is
  6      l_data  myArrayType := myArrayType();
  7  begin
  8      for i in 1 .. 5
  9      loop
 10          l_data.extend;
 11          l_data( l_data.count ) := myScalarType( 'cc-'||i,
 12                                                  'sc-'||i,
 13                                                  'flg-'||i,
 14                                                  i,
 15                                                  i,
 16                                                  test||i );
 17      end loop;
 18
 19      return l_data;
 20  end;
 21
 22  end;
 23  /

Package body created.

tkyte@ORA806.WORLD>
tkyte@ORA806.WORLD>
tkyte@ORA806.WORLD> create or replace view X
  2  as
  3  select *
  4    from THE ( select cast( pkg_test.test_proc('hello') as
myArrayType )
  5                 from dual ) a
  6  /

View created.

tkyte@ORA806.WORLD> select * from x;

COMP_CODE  SHIFT_CODE SFT_FLG        BEG_TM     END_TM SKILLS
---------- ---------- ---------- ---------- ----------
----------
cc-1       sc-1       flg-1               1          1 hello1
cc-2       sc-2       flg-2               2          2 hello2
cc-3       sc-3       flg-3               3          3 hello3
cc-4       sc-4       flg-4               4          4 hello4
cc-5       sc-5       flg-5               5          5 hello5

tkyte@ORA806.WORLD>

January 05, 2001 David -- Thanks for the question regarding "date
      issue", version 7.3.4

      You Asked
Dear Tom,

Oracle default date format is DD-MON-YY, when I select one date
datatype column in my table using add_months function,

select cda_trans_dts from call_detail where
cda_trans_dts > add_months(sysdate, -1)
SQL> /

I got the following date data which is the same as Oracle date
default format

CDA_TRANS
---------

05-DEC-00
05-DEC-00
05-DEC-00
05-DEC-00
05-DEC-00
......
......

However, when I select it in another way, I got no date data
displayed as the following

SQL> select count(*) from call_detail
  2  where trans_dts in ('05-JAN-01');

  COUNT(*)
----------
         0

I am trying to count the row numbers of the trans_dts dated
05-JAN-01.

Here is my questions

1. Is the WHERE...IN clause not used correctly? How can I get
the trans_dts records number in 05-JAN-01?
2. Where can I find out my database date format?

Your help is always appreciated.

      and we said...
A

select * from nls_session_parameters;

will show you your date format for your session.  The date:

  '05-jan-01'

will be treated as january 5'th, 2001 using the format
dd-mon-yy.  Now, if someone inserted 05-JAN-01 in the year 1999
using that format, the date they inserted in January 5'th 1901
-- not 2001.

You need to query out that data and see if you have 1901 or 2001
data in that column.  I'll bet you have 1901 data and you need
to update your invalid dates.

January 05, 2001 Peter -- Thanks for the question regarding
      "Storing & Retrieving Excel Spreadsheet in DB", version 8.1.5 &
      8.1.6

      You Asked
The requirement is to store and Excel spreadsheet from a users
local or network drive into the database. Front end is written
in ColdFusion.

Can you provide me with advice and sample code that describes
how to store and retrieve this data? Should I use a Blob or Clob
datatype to store the spreadsheet?

Related to this, do you know how/if Excel could be automatically
launced in order to update a spreadsheet that is stored in the
database?

Thanks...

      and we said...
You will defintely want to use a BLOB since a spreadsheet is
binary data.

I would refer you to:

http://technet.oracle.com/doc/oracle8i_816/appdev.816/index.htm
for documentation on LOBS in Oracle.  As for how cold fusion
works with them -- I'll have to refer you to the makes of cold
fusion, I do not know what support they may (or may not) have
for them.

You can also search on my site for LOB, blob, clob.  I have
quite a few examples there in Java, C, and PLSQL.

If you use something like iFS

http://www.oracle.com/ip/deploy/database/features/index.html?ifs.html
excel can read/write the spreadsheet from/to the database
naturally.

January 05, 2001 Gregg -- Thanks for the question regarding
      "System.out.println", version 1.0.2

      You Asked
Hi Tom,

When using Oracle 9iAS (Solaris), how does one get to see the
System.out.println debug messages? Where do they go?

Thanks,
Gregg

      and we said...
Well, as there are various environments under which java might
be running in iAS (servlet, jsp, in the database, as a bean,
etc) and each could go to a different place -- I'll offer up a
different solution to the problem.

Rather then trying to find where system.out.println is going --
we can redirect it to where you want it to go.  The following
snippet of code is thanks to Mark Piermarini who works with me.
Using this, you can have System.out.println go to whatever named
file you want (just make sure the OS account you are running the
iAS as has the ability to write to that location!).

import java.io.*;
import java.util.*;

public class Redirect {

   static PrintStream originalOut = null;
   static PrintStream fileOut = null;
   static boolean redirectOut = false;

   public static boolean redirectOut(String fileName) {
      boolean flag = true;

      try {
         // If this is null then save it so we
         // can restore it later.
         if (originalOut == null) {
            originalOut = System.out;
         }

         // Open file in append mode. Create if not found.
         // PrintStream auto-flushes.
         fileOut =  new PrintStream
                   (new FileOutputStream(fileName, true), true);
         System.setOut(fileOut);
      } catch (FileNotFoundException e) {
         flag = false;
      } finally {
         return flag;
      }
   }

   // Attempt to restore the original output.
   // Close file as well.
   public static void restoreOut() {

      if (originalOut != null) {
         System.setOut(originalOut);
      }

      if (fileOut != null) {
         fileOut.close();
         fileOut = null;
      }
   }

   public static void main(String[] args) {
      if (redirectOut("/tmp/blah")) {
         System.out.println("HELLO");
         restoreOut();
      } else {
         System.out.println
         ("Unable to redirect the output stream.");
      }
   }
}
January 05, 2001 Bala -- Thanks for the question regarding "What
      bits of encryption does PL/SQL packages use ?", version 8.1.6

      You Asked
Tom

Would like to know how much bits of encryption does
DESEncrypt and DESDecrypt Procedures uses.

Thanks

      and we said...
The DES Key length is fixed at 56bits.

In Oracle8i release 3 (8.1.7) there is also a DES3Encrypt
routine.  The DES key length for encryption is fixed at 128 bits
(for 2-key DES) or 192 bits (for 3-key DES); you cannot alter
these key lengths.

January 05, 2001 seshu -- Thanks for the question regarding "SQL
      Query tuning", version 8.0.5.2.1

      You Asked
Hi,
We've one application(Front-end Dev2000) which is using the
following query :

SELECT COMM_DATE_OPEN,COMM_COMMENT,COMM_TYPE_ID,COMM_AGR_ID,
COMM_ID,EMP_USERID,COMM_CHANGED_BY,ROWID
FROM VW_COMMENT_HISTORY_VIEW
WHERE COMM_AGR_ID=:1
order by comm_type_id asc, comm_date_open desc

VIEW : "VW_COMMENT_HISTORY_VIEW " in the above query :

select comm_id, comm_agr_id, comm_type_id, comm_comment,
comm_changed_by, comm_date_open, emp_userid
from comments, users
where emp_employee_no(+) = comm_changed_by
(COMMENTS : a partitioned table of size 5.6 GB)
(Part key : COMM_AGR_ID)
(Indexes: LOCAL:COMM_AGR_ID GLOBAL: COMM_CHANGED_BY)
The above refered query will be used by end-users(more than 300
users online 24x7).
I guess, somewhere in the query,there is a scope for tuning.I
feel,whenever you use the above query calling a view in-turn,it
may casue increased over-head.
I request your suggestion. Thanks & Regards

      and we said...
The use of a view here is not relevant.  It is not affecting
performance at all -- there is no overhead.

The query:

select comm_id, comm_agr_id, comm_type_id, comm_comment,
       comm_changed_by, comm_date_open, emp_userid
  from comments, users
 where emp_employee_no(+) = comm_changed_by
   and comm_agr_id = :1
 order by comm_type_id asc, comm_date_open desc

and

SELECT COMM_DATE_OPEN,COMM_COMMENT,COMM_TYPE_ID,COMM_AGR_ID,
       COMM_ID,EMP_USERID,COMM_CHANGED_BY,ROWID
  FROM VW_COMMENT_HISTORY_VIEW
 WHERE COMM_AGR_ID=:1
 order by comm_type_id asc, comm_date_open desc

should get the same exact plan as long as COMM_CHANGED_BY is in
COMMENTS and EMP_EMPLOYEE_NO is in USERS.

One enhancement that will permit this to run faster in
Oracle8i release 8.1 will be the addition of a true desc
index.  If you had an index on

(comm_agr_id, comm_type_id, comm_date_open DESC)

We would be able to get you the first rows (something thats very
good for forms) very rapidly as we would goto this index to read
the data sorted and pick up the USERS information via an index
on users(emp_employee_no).  We will totally avoid the sort.

Prior to 8.1, desc indexes did not exist.  We could read an
index "backwards" but that will not help you here since only one
of the columns is descending and the rest are ascending.

January 05, 2001 wallacel -- Thanks for the question regarding
      "preparedstatement", version 8.1.6

      You Asked
Tom:

jdbc document says that "To write changes to the database,such
as for INSERT or UPDATE, you will typically create a
PrepareStatement objects"

my question is when querying, should i use preparestatment
or just statement?
say i have query like
select * from emp where empno=1
and
select * from emp where empno=2;

I think by using preparestatment, they can share sql area.

am i right?

      and we said...
Hopefully you have a statement like:

select * from emp where empno = ?

not = 1 or = 2!  Yes, you would use bind variables with a
prepared statement like this:

      PreparedStatement ps =
         conn.prepareStatement("select answers_desc " +
                            "from answers_table " +
                           "where answers_qid = :bv1 " +
                             "and answers_uid = :bv2" );
      ps.setString( 1, qid );
      ps.setString( 2, uid );
      ResultSet rset = ps.executeQuery();

January 05, 2001 Anil -- Thanks for the question regarding
      "LOCKS", version 8.1

      You Asked
Hi Tom,
      I created a snapshot for a table called Customer.
      will oracle locks the snapshot when even there is a
      update or insert into the master table.

Thanks in Advance
Kumar

      and we said...
The snapshot will be locked briefly during the REFRESH of the
snapshot (and this only matters if you have an UPDATEABLE
snapshot, with a read only snapshot, no one will even notice
that it is locked).

The snapshot will not be locked during modifications to the
parent object -- in most cases, the parent object is on a wholly
different machine.
January 06,
      2001 Ganesh -- Thanks for the question
      regarding "Round In Java and Oracle.", version 8.1.x

      You Asked
Hi Tom,

When i do a Round of -5.5 in oracle it is giving me -6 and when
i do a round(-5.5) in java it is giving me -5.

So why this difference???

Can u pls give me a reason for this discrepancy as this may
affect applications.

Regards,
Ganesh R

      and we said...
There are two ways to do a round, one rounds negative numbers
towards zero, the other rounds negative numbers towards negative
infinity.

Both are "equally" valid.  I suppose the discrepency comes in in
that Java picked one way to do it -- we had choosen another.  We
cannot change the definition of Java nor can Java change our
definitions.

Most IEEE math packages I've seen follow the "sql" way.  that
is, round is defined as:

    function ROUND (X : real ) return real;
        -- returns integer FLOOR(X + 0.5) if X > 0;
        -- return integer CEIL(X - 0.5) if X < 0

If this poses an issue for you, you would pick one over the
other depending on your needs and use it consistently.  For
example, suppose you choose the "java" method which rounds
towards zero for negative numbers, you can simply:

ops$tkyte@ORA8I.WORLD> create or replace
  2  function jround( p_real in number ) return number
  3  as language java
  4  name 'java.lang.Math.round( long ) return double';
  5  /

Function created.

And now the function jround is a "peer" of round -- you can call
it from SQL or PLSQL just as naturally as round:

ops$tkyte@ORA8I.WORLD> select round(-5.5),
  2             ceil(-5.5 - 0.5),
  3             jround(-5.5)
  4    from dual
  5  /

ROUND(-5.5) CEIL(-5.5-0.5) JROUND(-5.5)
----------- -------------- ------------
         -6             -6           -5

January 06, 2001 sanchit -- Thanks for the question regarding
      "database Administration", version oracle8i

      You Asked
a) What do you mean by size of the database and how you
calculate it.

      and we said...
Typically people mean the cumulative size of the datafiles
included in the database.  This can be seen using many scripts.
My personal favorite is something I call "free.sql" -- it shows
the total space allocated to the database and how much is used.
You can get it from:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:285415955510\
...

January 06, 2001 Omar -- Thanks for the question regarding "Data
      Dict. vs Local tablespaces", version 8.1.6

      You Asked
Hi Tom,
   Is it right that when are create your tablespaces as local ,
you no
longer bother with the Pctused, pctincrease when creating
objects in
those tablespace, and if is not in what cases you should bother
whith
them.

with best regards

      and we said...
pctincrease is ignored in locally managed tablespaces.  PCTUSED
has to do with space utilization on a block and freelists and is
not affected by locally managed tablespaces (that is, pctused is
the same as it always was, pctincrease is ignored).

In a locally managed tablespace you either:

o have every extent be the same size.  This is UNIFORM
allocation.  Each and every extent will be the same.

o allow us to size the extents according to our algorithm.
pctincrease does not apply in this case.

January 06, 2001 navdeep -- Thanks for the question regarding
      "rebuilding indexes", version 8.0.4.2.0

      You Asked
hi tom
       i have made an query for analysing the index and
subsequently putting the data of index_stats into a temp table.
after studying the data i have found some indexes
with BLKS_GETS_PER_ACCESS >5.
e.g
-----------------------------------------------------------------
-------------------------------------------------------
NAME                           MOST_REPEATED_KEY   DISTINCT_KEYS
    DEL_LF_ROWS          HEIGHT BLKS_GETS_PER_ACCESS
------------------------------ ----------------- ---------------
--------------- --------------- --------------------
DOC_TYPE                                   20123               3
              0               3      4723.1666666667
IDX_COL_TAB                                   59             505
              0               3      10.034653465347
IDX_CONS_TAB                                  59             505
              0               3      9.0148514851485
IND_GRD_PACK                                7363              72
              0               3                  200
OFFCDPXEXINVDTL                            28296               1
              0               3              14151.5
OTHER_CD_IND                               28180              49
              0               3      494.09183673469
SALE_TYPE                                  20776               5
              0               3               3031.9
-----------------------------------------------------------------
--------------------------------------------------------
Now even after rebuilding these indexes i am again getting the
same BLKS_GETS_PER_ACCESS.
Is there any other option which i can specify with index rebuild
to reduce BLKS_GETS_PER_ACCESS.

thanx
navdeep

      and we said...
I'll have to guess here because you left out a vital column --
LF_ROWS.

I see indexes up there with 3, 1, 5 distinct values.  Unless
there are 3, 1, and 5 rows in those indexes -- those indexes
should not exist unless they are bitmapped indexes.  The
blks_gets_per_access returns a metric that said if I executed a
query "select count(*) from T where indexed_column = VALUE" --
how many blocks would I access.  For the table with 3 distinct
values in the index (doc_type) -- we would access 4,723 blocks.

Here is an example.  I'll load up a table with 3 values.  We'll
fill this table up.  We'll look at the blocks gets per access --
we'll rebuild that index just to make sure.  Nothing will make
this metric "better" since an index on a column with 3 values is
not sensible.  Then, I'll fill the table with unique values and
we'll see the metric behave as expected:

ops$tkyte@ORA8I.WORLD> create table t ( x int );
Table created.

ops$tkyte@ORA8I.WORLD> create index t_idx  on t( x );
Index created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1 );
ops$tkyte@ORA8I.WORLD> insert into t values ( 2 );
ops$tkyte@ORA8I.WORLD> insert into t values ( 3 );

ops$tkyte@ORA8I.WORLD> analyze index t_idx validate structure;
Index analyzed.

ops$tkyte@ORA8I.WORLD> select lf_rows, lf_blks, distinct_keys,
blks_gets_per_access
  2    from index_stats;

   LF_ROWS    LF_BLKS DISTINCT_KEYS BLKS_GETS_PER_ACCESS
---------- ---------- ------------- --------------------
         3          1             3                    2

ops$tkyte@ORA8I.WORLD> insert into t select * from t;
3 rows created.

ops$tkyte@ORA8I.WORLD> analyze index t_idx validate structure;
Index analyzed.

ops$tkyte@ORA8I.WORLD> select lf_rows, lf_blks, distinct_keys,
blks_gets_per_access
  2    from index_stats;

   LF_ROWS    LF_BLKS DISTINCT_KEYS BLKS_GETS_PER_ACCESS
---------- ---------- ------------- --------------------
         6          1             3                  2.5

ops$tkyte@ORA8I.WORLD> begin
  2          for i in 1 .. 10 loop
  3                  insert into t select * from t;
  4                  commit;
  5          end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> analyze index t_idx validate structure;
Index analyzed.

ops$tkyte@ORA8I.WORLD> select lf_rows, lf_blks, distinct_keys,
blks_gets_per_access
  2    from index_stats;

   LF_ROWS    LF_BLKS DISTINCT_KEYS BLKS_GETS_PER_ACCESS
---------- ---------- ------------- --------------------
      6144         17             3               1026.5

ops$tkyte@ORA8I.WORLD> alter index t_idx rebuild;
Index altered.

ops$tkyte@ORA8I.WORLD> analyze index t_idx validate structure;
Index analyzed.

ops$tkyte@ORA8I.WORLD> select lf_rows, lf_blks, distinct_keys,
blks_gets_per_access
  2    from index_stats;

   LF_ROWS    LF_BLKS DISTINCT_KEYS BLKS_GETS_PER_ACCESS
---------- ---------- ------------- --------------------
      6144         12             3               1026.5

ops$tkyte@ORA8I.WORLD> truncate table t;
Table truncated.

ops$tkyte@ORA8I.WORLD> begin
  2          for i in 1 .. 7000 loop
  3                  insert into t values ( i );
  4          end loop;
  5  end;
  6  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> analyze index t_idx validate structure;
Index analyzed.

ops$tkyte@ORA8I.WORLD> select lf_rows, lf_blks, distinct_keys,
blks_gets_per_access
  2    from index_stats;

   LF_ROWS    LF_BLKS DISTINCT_KEYS BLKS_GETS_PER_ACCESS
---------- ---------- ------------- --------------------
      7000         14          7000                    3

ops$tkyte@ORA8I.WORLD>

Basically -- what this should mean to you is that the indexes
above (especially the ones with 3, 72, 1, 49 and 5 distinct
keys) are not good candidates for indexed columns!  They others,
with 505, are borderline, its hard to say if they are good or
not.

Now, if you used a bitmapped index on my example with the values
1, 2, and 3 you would find:

ops$tkyte@ORA8I.WORLD> create bitmap index t_idx on t(x);

Index created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> analyze index t_idx validate structure;

Index analyzed.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select lf_rows, lf_blks, distinct_keys,
blks_gets_per_access
  2    from index_stats;

   LF_ROWS    LF_BLKS DISTINCT_KEYS BLKS_GETS_PER_ACCESS
---------- ---------- ------------- --------------------
         3          1             3                    2

which is pretty good.  Bear in mind however that bitmap indexes
are not very good for concurrent modifications so they may not
apply in your case.  See the data warehousing and
designing/tuning for performance guides for more info.
January 07, 2001 Rama Subramanian -- Thanks for the question
      regarding "Execute_Query - Query on Detail Block", version 6.0.5.0.2

      You Asked
Hi,

I'm using Forms 6.0.5.0.2, database is Oracle 8.1.5 on Sco
UnixWare 7.1.0.

I use the Enter_Query, Execute_Query combination in my form
modules for query options.  I know that Forms builds a query
based on the values entered by the user, when Execute_Query is
fired.

Suppose I have a Master block, and 2 or 3 detail blocks.
Querying based on values of the master block is no issue,
through the method mentioned earlier.  But, suppose I need to
query the Master_Detail values based on values of a detail
block.

[Sale particulars (master block), Customer details (Child
Block), query all sale particulars of a particular customer].

How should I approach this scenario?

Thank you in advance.

Rama Subramanian G

      and we said...
You just need to build another master detail with the master and
detail base tables reversed.

If you normally had

TABLE A (master)

TABLE B (child1)
TABLE C (child2)

and you want to drive the query off of Table B now, you would
have:

TABLE B (master of table A)
TABLE A (child of b, master of C)
TABLE C (child of table a)

Either that, or you would build a control block (non-database
block) where the end user could enter constraining parameters
and YOU would build a where clause for forms to use (eg: you
would detect the :control_block.name was not null, hence they
put some criteria in there and you would build a predicate

where :mast_block.primary_key in
  ( select :child_block.fkey
      from child_table
     where child_table.name = :control_block.name )

and use set_block_property to change the default where clause
for master block (remember to set it off after you are done with
it)
January 07, 2001 alex -- Thanks for the question regarding
      "script", version 8.1.6

      You Asked
Hello, Tom!

Could you help me to build script to spool all triggers in file
from data dictionary.

thanks!

Alex.

      and we said...
I don't have a perfected one but it won't be too difficult. You
can start with this:

set feedback off
set termout off
set heading off
set pagesize 0
spool temp
prompt select to_char(sysdate,'dd-mon-yyyy hh24:mi:ss') from
dual

select
chr(10) || '/' || chr(10) ||
'create or replace trigger "' || owner || '"."' ||
         trigger_name || '"' || chr(10)||
 decode( substr( trigger_type, 1, 1 ),
         'A', 'AFTER', 'B', 'BEFORE', 'I', 'INSTEAD OF' ) ||
              chr(10) ||
 triggering_event || chr(10) ||
 'ON "' || table_owner || '"."' ||
       table_name || '"' || chr(10) ||
 decode( instr( trigger_type, 'EACH ROW' ), 0, null,
            'FOR EACH ROW' ) || chr(10) ,
 trigger_body
from dba_triggers
where owner = 'SCOTT'
/
prompt /

spool off

It'll generate a lst file with most of the triggers. It does not
yet deal with referencing old as and new as and other such
syntax but with a decode here and there -- it'll get you going.

January 07, 2001 Hanan -- Thanks for the question regarding
      "Database tunning & controlling.", version Oracle ver-8.1.6

      You Asked
Hi Tom,

I'd b most obliged if u can possibly help me with the following  questions: (&
even if u cann't).
Pls try 2 b patient, 4 my questions may seem trivial 2 u.

First, let me inform u that we're running an Oracle database - ver/8.1.6 on a
Windows2000 platform.

1)PROBLEM: Controling the # of users currently logged on to the
  -------- database.
  ELABORATION: Frequently I engage the problem of users being
  blocked from connecting to the database due 2 reaching the
  maximum # of possible users.
  Trying 2 solve this, I incremented the 'PROCESSES' value, (of
  the 'init.ora' - initiation file), up to 200.
  Should I increment this parameter more? (what r the limits?),
  or r there any other parameters which must b considered...
  (i.e. the 'SESSIONS' parameter: is it relevant 2 the subject?)

  When I view the 'sessions' tab of the 'instance' folder - in
  the 'DBA studio' component, I c many sessions which r under the
  'inactive' - status.
  I assume this happens after a certain idling time.
  If that is correct, is there any way of automizing a 'kill'
  for these particular sessions ? (by this maintaining a low #
  of processes).

  - Processes/Sessions: I'm afraid I'm mixing up these 2...

2)PROBLEM: Locating users which r locking tables.
  --------
  ELABORATION: occasionally we r tackled with a user locking some
  table in the database, due 2 some loop (=bug) in his/her JAVA
  application which is running on the database, thru a 'JDBC'
  (Java Data Base Connector).
  Since there r many processes/sessions logged on thru a certain
  user at the time, I do not know (yet) of any way in which I
  can determine which process/session of this user - is locking
  this table, which forces me 2 kill all the processes/sessions
  logged on thru this user.

 & at last, I'd wish 2 thank u once again 4 your patience...

 Sincerely
       Hanan.

      and we said...
The inactive status simply means the user is logged in but not currently
executing any SQL. If you open a window with sqlplus and just let it sit there
-- you'll be logged in but inactive.

Modifying processes will reset many other derived parameters such as sessions.
Setting processes is one method to "up" your connection count.

another method, if many sessions are continualy idle, is to configure
multi-threaded server.

see

http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/toc.htm
and specifically

http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/mts.htm#450520
for more info on MTS.

You can use resource profiles to "kick people out" after a certain amount of
idle time, hence releasing any locks they might have.  Their session status will
go into a KILLED state (vs inactive) and they will still consume a process until
their client contacts the database (to be informed their session was killed).
This won't fix your max processes issue however, only sizing processes= in the
init.ora or using something like MTS to allow more connections (sessions) then
processes will do that.

There are many utilities to find blockers/waiters.  The simpliest is found in
$ORACLE_HOME/rdbms/admin.  If you run (as SYS or INTERNAL using SVRMGRL) the
script catblock.sql, you'll be able to then run utllockt.sql at anytime to print
a graph of what session is blocking what other sessions.  You'll get the sid if
the session doing the blocking.  For example, i just opened 2 sqlplus sessions
and in both issued:

  select * from dept for update;

now one it blocked.  In a 3rd session I ran utllockt and I get:

WAITING_SESS   LOCK_TYPE    MODE_REQ MODE_HELD LOCK_ID1 LOCK_ID2
-------------- ------------ -------- --------- -------- --------
8              None
7              Transaction  Exclusiv Exclusiv  262198   123

Using another script I wrote (showsql.sql) I can see then:

tkyte@TKYTE816> @showsql

USERNAME        SID        SERIAL#    PROCESS   STATUS
--------------- ---------- ---------- --------- ----------
SCOTT                    7          7 812:1108  ACTIVE
SCOTT                    8         14 948:1112  INACTIVE
TKYTE                    9         30 516:960   ACTIVE
--------------------
SCOTT(7,7) ospid = 812:1108 program = SQLPLUS.EXE
Sunday    11:15  Sunday    11:18
select * from dept for update

So, session 8 is blocking 7.  7 is trying to run select * from dept for update
(i can see the sql they are running).  Session 8 is just sitting there inactive.
 A simple:

alter system kill session '8,14';

would clear this up.  I don't have to kill both scott's.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:767025833873
for showsql.sql

January 07, 2001 Patibandla -- Thanks for the question regarding
      "Trigger for multiple Tables - Reg.", version 8.1.6.0

      You Asked
I have three Address Tables.
1. EmpAddress Table (Employee Address)
2. SiteAddress Table (Customer Address)
3. CustAddress Table (Customer Address )

The Structure of the these tables are the same.
I am doing same  validations before/after insert/updaate
4 triggers on each of these tables.

So altogether there are 12 Triggers. Is there anyway to
reducing it to 4.

Whenever I change code in one trigger i have to change
the code in the rest of two.

Yr reply would be appreciated

Regards

Koshal

Is there
Can we define
group
tables

      and we said...
Move the common code in the trigger to a package.  Have the
triggers call the package.  I can get this down to 6 triggers:

create or replace trigger emp_trigger1
before insert or update on emp
begin
   if ( inserting ) then
      your_pkg.before_inserting_logic( :new. .... );
   else
      your_pkg.before_updating_logic( :new. , :old., ... );
   end if;
end;
/

create or replace trigger emp_trigger2
after insert or update on emp
begin
   if ( inserting ) then
      your_pkg.before_inserting_logic( :new. .... );
   else
      your_pkg.before_updating_logic( :new. , :old., ... );
   end if;
end;
/

and then do the same for the other 2 tables.  Also consider if
you can just do you AFTER logic in the BEFORE trigger.  Unless
there are other BEFORE triggers that I do not see -- you can
always put your AFTER logic in the BEFORE trigger.  Then you can
get down to 3 triggers.
January 07,
      2001 Pete -- Thanks for the question
      regarding "Forms 6", version Forms 6.0

      You Asked
Hi Tom,

we have a problem with blocks and columns in a
master-detail-form.

The table of the detail-block considers the columns

ID number,
Typ number,
Name1 number,
Name2 varchar2,
Name3 varchar2,
Name4 number,
Name5 date,
Name6 number.

In Forms looks the block like

ID Typ Name1 Name2 Name3 Name4 Name5 Name6
ID Typ Name1 Name2 Name3 Name4 Name5 Name6
ID Typ Name1 Name2 Name3 Name4 Name5 Name6.

We need a dynamic block of columns at runtime that display
the columns such like:

If Typ = 1 then display columns

ID Typ Name1 Name2 Name5 Name6
ID Typ Name1 Name2 Name5 Name6
ID Typ Name1 Name2 Name5 Name6.

If Typ = 2 then display columns

ID Typ Name1 Name2 Name3.
ID Typ Name1 Name2 Name3.
ID Typ Name1 Name2 Name3.

If TYP = 3 then display columns
ID Typ Name1 Name2 Name3 Name4 Name5 Name6
ID Typ Name1 Name2 Name3 Name4 Name5 Name6
ID Typ Name1 Name2 Name3 Name4 Name5 Name6.

Can you help?

      and we said...
First -- the type will have to be "consistent" or "constant".
So, at any point in time, i would be viewing typ=1 only or typ=2
only.  So, you could consider removing or factoring out the typ
column from the display since it will always have the same value
for all rows at any point in time.

You will have to use the builtin

SET_ITEM_PROPERTY

with the arguments POSTITION and VISIBLE.  Visible allows you to
hide/show a given column and positition will let you "slide" the
visible items to be next to each other.
January 07, 2001 Jim -- Thanks for the question regarding
      "Limiting rows returned from query in web app", version 8.1.[5,6,7]

      You Asked
Tom,

Is there a better way to limit the rows returned from the select
statement than the way I've shown below. The purpose of this
technique is to limit the numbers of rows returned to the client
in a web application by page or in this case by client profile
(letting the client determine the number by selecting a count to
display per query - the default is 24 rows). The between values
below are variables in the code. I couldn't figure out another
way for the inner selects to filter just the rows we want to
display (like 25 - 50 and 51 - 75, etc). It seems to me that
this would be straight forward if there was only one table to
select from and a key value to filter.  The reason I'm asking is
that the query uses alot of resources to have to get all the
data first and this is what I'm trying to avoid.

Thanks - Jim

select * from
(select f13, f14, f15, f16, rownum as rn from
( SELECT
NVL(trans.trans_ref, ' ') as f1,
NVL(trans.trans_descr, ' ') as f2,
NVL(trans.propaddr, ' ') as f3,
NVL(trans.propcitystatezip, ' ') as f4,
NVL(trans.start_date, '01-JAN-01') as f5,
NVL(trans.end_date, '01-JAN-01') as f6,
NVL(trans.model_schedule_type_id, 1) as f7,
NVL(trans.trans_status_id, 0) as f8,
NVL(useller.user_id, -1) as f9,
NVL(useller.fname, ' ') as f10,
NVL(useller.lname, ' ') as f11,
NVL(lseller.phone_home, ' ') as f12,
NVL(ubuyer.user_id, -1) as f13,
NVL(ubuyer.fname, ' ') as f14,
NVL(ubuyer.lname, ' ') as f15,
NVL(lbuyer.phone_home, ' ') as f16
FROM
trans, trans_user, trans_user tuseller, users useller, location
lseller,
trans_user tubuyer, users ubuyer, location lbuyer, users
WHERE
trans.trans_status_id = 0
AND trans_user.user_role_id = 1
AND trans_user.user_id = 1001
AND trans_user.trans_id = trans.trans_id
AND trans_user.trans_id = tuseller.trans_id
AND trans_user.trans_id = tubuyer.trans_id
AND trans_user.user_id = users.user_id
AND tuseller.user_id = useller.user_id
AND tuseller.user_id =
    (select useller.user_id from trans_user a where a.trans_id =
tuseller.trans_id and a.user_role_id = 5)
AND useller.location_id = lseller.location_id
AND tubuyer.user_id = ubuyer.user_id
AND ubuyer.location_id = lbuyer.location_id
ORDER by f1))
where rn between 1 and 50
/

      and we said...
In a stateless environment, where the cursor cannot be
maintained "opened" -- paging through queries that take a long
time to get the first row is painful.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:76812348057
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:138012348065
for ideas in this area.

Review &
      Followup

      Rating: 2
Limiting rows
      returned from query in web app", version 8.1.[5,6,7]  May
      07, 2001
Reviewer:  shiva  from INDIA
I calnt use a rowid for complex queries, where all my queries are dependent on
group by clauses. Sometimes i have to go about retrieving data using views.

      Rating: 2
Limiting rows
      returned from query in web app", version 8.1.[5,6,7]  May
      07, 2001
Reviewer:  shiva  from INDIA
I calnt use a rowid for complex queries, where all my queries are dependent on
group by clauses. Sometimes i have to go about retrieving data using views.
please help me out of this situation. my email id is shivkrish27@yahoo.com

      Rating: 3
Alternate
      approach to consider  July 16, 2001
Reviewer:
      Andrew  from San Jose, CA
See this URL.

http://www.jlcomp.demon.co.uk/plsql_a.html

January 07, 2001 Avi -- Thanks for the question regarding
      "V$OPEN_CURSOR", version 8.1.6

      You Asked
Hi Tom,
I am making a lot of "select" queries in the DB.
I can see all the select queries in the V$OPEN_CURSOR view.
Since my init.ora OPEN_CURSORS parameter equals 200
i can make no more selects - I get an error saying that to many
cursors are open.

My question is : What should I do in order not to exceed 200
open cursors, and when those entries are deleted from the view?

I am using java programs to query the database.
There are no declaration of explicit cursor.

the parameter session_cached_cursors is not initialized.

      and we said...
See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:553222846752
It'll show you how to monitor how many cursors your application
truely has open.  You must remember to CLOSE ever prepared stmt,
callable stmt, and resultset else the cursors they implicitly
define will remain open for the duration of your program.

See also

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1275600573808
for how to ensure you close all of these correctly.  Since
Java classes do not have "destructors", there is no clean up
code invoked for them when they go out of scope.  Hence
resources they allocate may remain in use long after you are
done with them unless you clean them up yourself.

    Copyright © 2003 Oracle Corporation, All rights reserved.


Recent Archives Advanced Search FAQ by Category Most Popular Hot Articles Your Questions [ Listing ]
Subject | Article | Last Updated (East coast time)
sqloader data insertion | article only | Jan 17, 2001 01:16 pm
Triggers | article only | Jan 17, 2001 01:28 pm
Architecture | article only | Jan 17, 2001 01:53 pm
about the strategy to consolidate data | article only | Jan 18, 2001 11:07 am
Locally Managed T/S - any differences in backup procedures? | article only | Jan 18, 2001 11:13 am
Bit Mapped Indexes and Foreign Keys | article only | Jan 18, 2001 11:18 am
Insert Cost | article only | Jan 18, 2001 11:37 am
v$type_size | article only | Jan 18, 2001 01:03 pm
DBA | article only | Jan 18, 2001 01:15 pm
Missing Indexes during Import | article only | Jan 18, 2001 03:37 pm
How to find tablespace fragmentation if not use tool | article only | Jan 18, 2001 04:45 pm
duplicate rows | article only | Jan 19, 2001 07:55 am
Index Organized Tables and DBA_SEGMENTS | article only | Jan 19, 2001 07:58 am
Where to I begin | article only | Jan 19, 2001 08:19 am
Design of Large Databases /Multiple Small Databases | article only | Jan 19, 2001 08:27 am
To get Name of Table's Column Forms6.0 | article only | Jan 19, 2001 08:31 am
JDBC query vs. Stored procedure | article only | Jan 19, 2001 10:17 am
HOW TO IMPLEMENT A LOGICAL BACKUP SET IN CONSISTENT MODE | article only | Jan 19, 2001 10:26 am
Copy data from one schema to another | article only | Jan 19, 2001 11:29 am
snapshot | article only | Jan 19, 2001 12:43 pm
Datafile changes & backup | article only | Jan 19, 2001 01:55 pm
Documentation for Oracle functions and packages | article only | Jan 19, 2001 01:56 pm
Database block checking | article only | Jan 19, 2001 02:00 pm
Cross Matrix Report | article only | Jan 19, 2001 04:16 pm
oracle 8i partition | article only | Jan 20, 2001 02:29 pm
backup of transaction log | article only | Jan 20, 2001 03:10 pm
Oracle 8i Personal Installation | article only | Jan 20, 2001 03:38 pm
row(s) 1 - 27 of 27
January 17, 2001 konstantina -- Thanks for the question regarding "sqloader data insertion", version ***
You Asked
I use sqlloader(8.1.6.1.0) in order to insert data in an oracle
database.I have a table with fields project_id,language,sector.A
data file example is listed below:
1113||EN||LAR THES ATH||
1112||FR||LAR||
1114||EN||ATH LAR||

'||' As delimiter.

How can i have separate rows for every sector for one
project_id ?I want to fill the table like this
1113 EN LAR
1113 EN THES
1113 EN ATH etc

Thanks for your help...
and we said...
You cannot do this directly from SQLLDR -- you can do this with
a "load table" and a trigger on that table.  For example
consider using these two tables:

create table temp_loader_tbl
( project_id int,
  language   varchar2(2),
  sector     varchar2(255)
)
/

create table real_table
( project_id int,
  language   varchar2(2),
  sector     varchar2(10)
)
/

We will load into temp_loader_tbl.  A trigger on that table,
such as:

create or replace trigger temp_loader_tbl_AIFER
after insert on temp_loader_tbl for each row
declare
    l_str       varchar(255) := :new.sector || ' ';
    l_piece     varchar2(10);
    n           number;
begin
    loop
        exit when l_str is null;
        n := instr( l_str, ' ' );
        l_piece := substr( l_str, 1, n-1 );
        l_str := substr( l_str, n+1 );

        insert into real_table
        values
        ( :new.project_id, :new.language, l_piece );
    end loop;
end;
/
show err

create or replace trigger temp_loader_tbl_AI
after insert on temp_loader_tbl
begin
    delete from temp_loader_tbl;
end;
/

will load the real table.  Now I can use a CTL file like this:

load data
infile *
replace
into table temp_loader_tbl
fields terminated by '|'
( project_id,
  f1 filler,
  language,
  f2 filler,
  sector
)
begindata
1113||EN||LAR THES ATH||
1112||FR||LAR||
1114||EN||ATH LAR||

and when I run it, I will get results such as:

ops$tkyte@ORA8I.WORLD> select * from temp_loader_tbl;

no rows selected

ops$tkyte@ORA8I.WORLD> select * from real_table;

PROJECT_ID LA SECTOR
---------- -- ----------
      1113 EN LAR
      1113 EN THES
      1113 EN ATH
      1112 FR LAR
      1114 EN ATH
      1114 EN LAR

6 rows selected.

ops$tkyte@ORA8I.WORLD>

the temp_loader_tbl will always appear empty (the after trigger
ensures that) and the other table will have our data.

this will work for a moderate amount of data - if I had
thousands of rows to load, this will be fine.  If I have
millions or more -- I might start looking for another method if
this turns out to be too slow.
January 17, 2001 Younes -- Thanks for the question regarding "Triggers", version 8.1.6
You Asked
Hi Tom,

i created this trigger:

create or replace trigger bef
  before insert on test
  referencing new as new old as old
  for each row
declare
  -- local variables here
  rTest test%rowtype;
begin
  rTest:= :new;
end bef;
 But i receive an error:
 PLS-000049: Bad bind variable new.

Is there any way to affect the rowtype to the new and old
values?

Thanks
and we said...
No, there is no way to atomically move a :new or :old "record"
into another record since :new and :old are not really records
at all.  Each column in a table may be referenced in a row
trigger by prefixing it with :new or :old -- :new and :old are
not really records.

When doing things like this, I typically use SQL to write SQL.
Since each element would need be moved one by one -- it is
easiest to have a little script lying around to help us do it.
For example:

set serveroutput on
set feedback off
set verify off
set embedded on
set heading off
spool tmp.sql

prompt declare
prompt     new_rec  &1..%rowtype;
prompt begin
select '    new_rec.' || column_name || ' := :new.' ||
column_name || ';'
  from user_tab_columns where table_name = upper('&1')
/

spool off
set feedback on
set embedded off
set heading on
set verify on

If you run:

ops$tkyte@ORA8I.WORLD> @test emp
declare
new_rec  emp.%rowtype
begin
    new_rec.EMPNO := :new.EMPNO;
    new_rec.ENAME := :new.ENAME;
    new_rec.JOB := :new.JOB;
    new_rec.MGR := :new.MGR;
    new_rec.HIREDATE := :new.HIREDATE;
    new_rec.SAL := :new.SAL;
    new_rec.COMM := :new.COMM;
    new_rec.DEPTNO := :new.DEPTNO;
ops$tkyte@ORA8I.WORLD>

it prints out the "beginning" of a trigger that does have the
modified values in a record for you.

Another example of this can be found at:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:59412348055
...
Review & Followup
Rating: 4
September 13, 2001
Reviewer: rupa from USA

Rating: 5
Oh, darn. September 10, 2003
Reviewer: Catherine Devlin from Dayton, OH USA
I'd been wondering if there was any way to do this.  I've been advised to remove
the guts of my triggers and put them into procedures, then call the procedures
from the triggers, so that I can use unit testing (utPLSQL!) on the procedures.
Of course, that involves a LOT of tedious and bulky parameter passing that would
be so much easier if we could do this.  A script to write the tedious
assignments is better than nothing, but it still makes for bulky code.

I'm glad to know that the answer, even if I'm disappointed that it's "no".  I
guess I should go file an enhancement request somewhere if I'm so upset...

January 17, 2001 Rajesh -- Thanks for the question regarding "Architecture", version 8.0.5
You Asked
What is the best Architecture to Implement 24x7 system? Is it
must to implement parallel server option for this or the
availability issue can be sorted with just using a stand by
database. Basically we don't want to have any manual
intervention. If the Database fails the user's should be
automatically redirected to a standby database (In effect the
user will not have any wait period in case of a database crash
not even the time required to switch manually to standby
database). What is the Oracle recommended solution?
and we said...
See
http://www.oracle.com/oramag/oracle/00-May/o30tom.html
for an overview.

There is no ONE answer.  You really need to balance cost against
needs against your environment.  Offhand, if you don't want any
manual intervention, I'd say Parallel Server might be the answer
-- however, an OPS database needs a little more care and feeding
then a standby database so if the "intervention" issue above is
an offshoot of "i don't have staff to manage the database" --
OPS won't help you too much.

After you read through that quick overview of some of the
options, feel free to come back with more pointed questions.
For better or worse -- there is no "one size fits all" when it
comes to "24x7".
January 18, 2001 Yujun -- Thanks for the question regarding "about the strategy to consolidate data", version Version 8
You Asked
Dear Sir/Madam,

We have several Oracle servers. Each has the databases of the
same scheme but different data. They can be connected with 64K
modems. We want to consolidate data to one server. So what kind
of technology does Oracle supply to support this? Should we
write the communication programs ourselves?

Thanks.

Yujun
and we said...
You can use snapshots to implement this.  A snapshot will do a
one time copy of the data to the centralized location and then
pull changes only after that (reducing the amount of traffic
generated).  Depending on the amount of changes -- a 64k line
might be sufficient.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76959/toc.htm
for information on replication available in Oracle and how
snapshots (also known as materialized views) function.
January 18, 2001 Satish -- Thanks for the question regarding "Locally Managed T/S - any differences in backup procedures?", version 8.1.5
You Asked
How are backups of Locally Managed T/s different than the
Dictionary managed ones.
Are there any special requirements.
Also please explain in terms of backing up through RMAN.
Thanks
and we said...
there are no differences internally or externally as far as
locally managed tablespaces go.
January 18, 2001 kris -- Thanks for the question regarding "Bit Mapped Indexes and Foreign Keys", version 816
You Asked
 Heres is some info I have gathered from index_stats.
 IDX_FK_1 [622 lf_rows] [158 BLKS_GETS_PER_ACCESS] [2 Distinct
Values]
 IDX_FK_2 [94500 lf_rows] [156 BLKS_GETS_PER_ACCESS] [307
DistinctValues]

Question 1
On both of the above examples the distinctiveness is 99%
which   means its a good candidate for bit mapped indexes.
Should I convert them?

I ask that question for 2 reason. If the table is small want the
CBO ignore he index and use FTS anyway?

Even if CBO uses FTS, would it benefit me converting them to bit
mapped  indexes just to save disk space?

I have several hundred indexes that have a distinctiveness above
95%. Thats why I am concerned about this.
Also do you have to have an index on a field if it referances a
FK? Because most of these indexes are FK's.

 Thanks again for your time.
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:292016138754
for when/why you would want to index a foreign key.  If you
NEVER update the "parent" key and you NEVER delete a parent row
-- the need for an index on a foreign key is very limited (and
outlined in the above link).  If you do update the parent key
and/or delete rows in the parent table -- you must be aware that
a FULL TABLE lock will be taken on the child table at that time
(EG: those operations will SERIALIZE in your database.

A bitmapped index cannot be used to alleviate this issue, it
would have to be a b*tree index.

In your above cases, if you do not update/delete the parent
table frequently -- using a bitmapped index or perhaps no index
at all would be the correct approach.
January 18, 2001 Anil -- Thanks for the question regarding "Insert Cost", version 8.1
You Asked
HI,
   Imagin a table called Emp(Empid Number,E_Name Varchar2(10),
                             Dept Number);
  EMpid is Primary Key, Dept is a Foreign Key.

  My Question is when i set the auto trace on and issue a
statement
 Like Insert into emo(Empid,E_Name,Dept) Values (:b1,:b2,:b3);
 Why the cost is high.?

 Is there any thing which i need to look into

  The plan Show like this

Execution Plan
----------------------------------------------------------
   0      INSERT STATEMENT Optimizer=CHOOSE (Cost=1375
Card=3815547 By
          tes=106835316)

Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
          1  consistent gets
          0  physical reads
       1056  redo size
        465  bytes sent via SQL*Net to client
        429  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed

Thanks In advance
Kumar
and we said...
the cost of a query (which I really wish they never exposed) is
totally 100% meaningless to us.  It means nothing.  It is not an
estimate of anything.  Please totally ignore it.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:313416745628
for a little more info on the "cost" of a query.
January 18, 2001 Anil -- Thanks for the question regarding "v$type_size", version 8.1.5
You Asked
Hi Tom,
  What v$type_size table is For.When i say
select type,type_size from v$type_size..i Get as follows

type   type_size
===============
eword    4
eb1      1
eb2      2
eb4      4
like this...we have many value...i don't think it is possible
for you to explain me every value,but certainly i would like to
know the following.

ub1,ub2,ub4,sb1,sb2,sb4,kcbh,ktbit,kdbh,kdbt,ktbbh.
please let me know what for above one is...what it means.

Regards
 Anil
and we said...
v$type_size shows you on your platform how big things are in
bytes.  Some are easy to figure out what they mean:

ub1 = Unsigned Byte 1 (1 byte)  = unsigned char in C
ub2 = Unsigned Byte 2 (2 bytes) = unsigned short in C
ub4 = Unsigned Byte 4           = unsigned long in C

sb1 = Signed Byte 1 (1 byte) = char in C
and so on....

Each of these is actually described right in the view itself:

ops$tkyte@ORA8I.WORLD> select type, description from
v$type_size;

TYPE     DESCRIPTION
-------- --------------------------------
EWORD    EITHER WORD
EB1      EITHER BYTE 1
EB2      EITHER BYTE 2
EB4      EITHER BYTE 4
UWORD    UNSIGNED WORD
UB1      UNSIGNED BYTE 1
UB2      UNSIGNED BYTE 2
UB4      UNSIGNED BYTE 4
SWORD    SIGNED WORD
SB1      SIGNED BYTE 1
SB2      SIGNED BYTE 2
SB4      SIGNED BYTE 4
BOOLEAN  BOOLEAN
FLOAT    FLOAT
DOUBLE   DOUBLE
SIZE_T   SIZE_T
PTR_T    PTR_T
KDBA     DATABASE BLOCK ADDRESS
KTNO     TABLE NUMBER IN CLUSTER
KSCN     SYSTEM COMMIT NUMBER
KXID     TRANSACTION ID
KUBA     UNDO ADDRESS
KCBH     BLOCK COMMON HEADER
KTBIT    TRANSACTION VARIABLE HEADER
KTBBH    TRANSACTION FIXED HEADER
KDBH     DATA HEADER
KDBT     TABLE DIRECTORY ENTRY
KTECT    EXTENT CONTROL
KTECH    EXTENT CONTROL
KTETB    EXTENT TABLE
KTSHC    SEGMENT HEADER
KTSFS    SEGMENT FREE SPACE LIST
KTUBH    UNDO HEADER
KTUXE    UNDO TRANSACTION ENTRY
KTUXC    UNDO TRANSACTION CONTROL
KDXCO    INDEX HEADER
KDXLE    INDEX LEAF HEADER
KDXBR    INDEX BRANCH HEADER
January 18, 2001 Prasad -- Thanks for the question regarding "DBA", version 7.1
You Asked
If there are two indexes on a table, how do you know that which
index is used when you fire a select statement on that table
which includes some of the columns from both the indexes ?
and we said...
By looking at the explain plan.  See
http://osi.oracle.com/~tkyte/article1/autotrace.html
or read about using the explain plan command in the SQL
reference manual.
January 18, 2001 Howie -- Thanks for the question regarding "Missing Indexes during Import", version 8.0.4
You Asked
Hi Tom

My problem is somewhat like follow :

I have a table say MASTER, it has one column EMPID of number
type. This column is the Primary Key for this Table and also
this is being referred by other tables for referential integrity
( Foreign Key ). This coloumn is also part of some other
composit indexes.

Now My problem is that when I export the Schema ( Under which
this table is lying) and import it in new database, then the
index which defines "Primary Key Constraint" is missing where as
I am able to see the there is Primary Key constraint is there on
this table ( From Dba_constraints). All other composit indexes
including this field are present there. Due to this missing
index there is huge degradation in performance.

My question is why this index is missing , Is "Primary Key is
Really Enabled when this index is missing", and what is the
solution to get rid of this problem?

Please explain in detail with example ?

Thanks In advance !

Howie
and we said...
This is the expected behaviour and I'm surprised there is a
"drop in performance" due to it.

A primary key constraint MAY (or may not) create a index on the
primary key.  This index MAY (or may not) be a UNIQUE index.  If
an index already exists that contains the primary key in its
entirety in the "leading" edge of the index -- that index will
suffice for the primary key enforcement.  So -- the existence
(or lack thereof) of a specific index to enforce your primary
key is a side effect of the order you happened to create things
in.  IMP created the objects in a different order, resulting in
an equivalent -- but different -- set of physical indexes.

Here is an example.  I'll create a table and then add a primary
key and then add an index on the primary key + some other
column.  The result will be 2 indexes.  Then, I'll drop the
table and do the SAME DDL in a different order.  By creating the
index first and then adding the primary key constraint -- I'll
end up with the same end result just minus 1 index that is not
necessary.

It would be interesting to turn on sql_trace and use tkprof
http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/ch14_str.htm#1018
to find out WHY it impacted performance so much.  The only
difference should be that instead of an INDEX UNIQUE, we should
get an INDEX RANGE SCAN on this index (since the "primary key"
index isn't there) but since the primary key is unique -- the
range scan should always find only 1 row anyway for a given
primary key value so it should be pretty much just as fast.  I
can imagine the index might be larger physically then an index
just on the primary key columns but it should not be
significantly larger.

tkyte@ORA806.WORLD> create table emp as select * from scott.emp;
Table created.

tkyte@ORA806.WORLD> alter table emp add constraint emp_pk
  2  primary key(empno);
Table altered.

tkyte@ORA806.WORLD> create index emp_idx on emp(empno,ename);
Index created.

tkyte@ORA806.WORLD> select object_name, object_type
  2  from user_objects;

OBJECT_NAME                    OBJECT_TYPE
------------------------------ ---------------
EMP                            TABLE
EMP_IDX                        INDEX
EMP_PK                         INDEX

tkyte@ORA806.WORLD> select constraint_name, constraint_type,
table_name
  2  from user_constraints;

CONSTRAINT_NAME                C TABLE_NAME
------------------------------ - ------------------------------
SYS_C00642                     C EMP
EMP_PK                         P EMP

The end result of the above was 2 indexes -- since I did the
primary key first and it needed some index -- and none existed
-- it created one....

tkyte@ORA806.WORLD> drop table emp;
Table dropped.

tkyte@ORA806.WORLD> create table emp as select * from scott.emp;
Table created.

tkyte@ORA806.WORLD> create index emp_idx on emp(empno,ename);
Index created.

tkyte@ORA806.WORLD> alter table emp add constraint emp_pk
  2  primary key(empno);
Table altered.

tkyte@ORA806.WORLD> select object_name, object_type
  2  from user_objects;

OBJECT_NAME                    OBJECT_TYPE
------------------------------ ---------------
EMP                            TABLE
EMP_IDX                        INDEX

tkyte@ORA806.WORLD> select constraint_name, constraint_type,
table_name
  2  from user_constraints;

CONSTRAINT_NAME                C TABLE_NAME
------------------------------ - ------------------------------
SYS_C00644                     C EMP
EMP_PK                         P EMP

tkyte@ORA806.WORLD>

Same exact ddl -- different order.  The index with the primary
key in the leading edge was used.
January 18, 2001 Pauline -- Thanks for the question regarding "How to find tablespace fragmentation if not use tool", version 8.1.5
You Asked
Hi Tom,
Could you tell how to find tablespace fragmentation (what is the
sql statement) if not use tool.

Thanks.
and we said...
Well, it depends on how you define "fragmentation".  In my
opinion, in version 8.1.5 (Oracle8i and up), fragmentation is an
impossible situation to be in.

My defininition of fragmentation is that you have many "small"
holes (regions of contigous free space) that are too small to be
the NEXT extent of any object.  These holes of free space
resulted from dropping some objects (or truncating them) and the
resulting free extents cannot be used by any other object in
that tablespace.  This is a direct result of using a pctincrease
that is not zero and having many wierd sized extents (every
extent is a unique size and shape).

In Oracle8i, we would all use locally managed tablespaces.
These would use either UNIFORM sizing (my favorite) or our
automatic allocation scheme.  In either case -- it is pretty
much impossible to get into a situation where you have unusable
free space.

To see if you suffer from "fragmentation", you can query
DBA_FREE_SPACE (best to do an alter tablespace coalesce first to
ensure all contigous free regions are made into 1 big free
region).  DBA_FREE_SPACE will report the size of all free
extents.  You would look for ANY free extent that is smaller
then the smallest NEXT extent size for any object in that
tablespace.

Below I artifically introduce this issue by using a dictionary
managed tablespace and objects with pctincrease=50.  I create
two tables and then allocate extents to them one after the other
so that they are "interleaved".  Then I drop one of the tables
and find all of the free extents that are too small to hold the
next extent for the smallest next extent in that tablespace.

tkyte@TKYTE816> drop tablespace t including contents;
Tablespace dropped.

tkyte@TKYTE816> create tablespace t
  2  datafile 'c:\temp\t.dbf' size 10m
  3  reuse
  4  /
Tablespace created.

tkyte@TKYTE816> create table t_t1 ( x int )
  2  storage ( initial 1k next 1k pctincrease 50 )
  3  tablespace t
  4  /
Table created.

tkyte@TKYTE816> create table t_t2 ( x int )
  2  storage ( initial 1k next 1k pctincrease 50 )
  3  tablespace t
  4  /

Table created.

tkyte@TKYTE816> alter table t_t1 allocate extent;
Table altered.

tkyte@TKYTE816> alter table t_t2 allocate extent;
Table altered.

... (above 2 commands executed in order over and over) ....

tkyte@TKYTE816> drop table t_t1;
Table dropped.

tkyte@TKYTE816> select *
  2    from dba_free_space
  3   where tablespace_name = 'T'
  4     and bytes <= ( select min(next_extent)
  5              from dba_segments
  6             where tablespace_name = 'T')
  7   order by block_id
  8  /

TABLESPACE_NAME                   FILE_ID   BLOCK_ID      BYTES
   BLOCKS RELATIVE_FNO
------------------------------ ---------- ---------- ----------
---------- ------------
T                                       9          2      16384
        2            9
T                                       9          6       8192
        1            9
T                                       9          8      16384
        2            9
T                                       9         12      24576
        3            9
T                                       9         18      40960
        5            9
T                                       9         28      81920
       10            9
T                                       9         48     122880
       15            9
T                                       9         78     163840
       20            9
T                                       9        118     245760
       30            9
T                                       9        178     368640
       45            9

10 rows selected.

tkyte@TKYTE816> spool off
January 19, 2001 Prasad -- Thanks for the question regarding "duplicate rows", version Oracle 8.0.5
You Asked
How to find duplicate rows in a table ?
and we said...
select c1, c2, c3, ..., cn, count(*)
  from T
 group by c1, c2, c3, ...., cn
HAVING count(*) > 1
/

will do it.  c1, c2, .. cn represents the set of columns that
should be "unique" in T.
Review & Followup
Rating: 5
duplicate rows September 05, 2001
Reviewer: Merle R. Vermuele from Omaha, NE USA
The answer was exactly what I was looking for to solve a problem I was having.

Rating: 5
May 02, 2003
Reviewer: A reader

January 19, 2001 William -- Thanks for the question regarding "Index Organized Tables and DBA_SEGMENTS", version 8i
You Asked
Hi Tom,

Can you tell me why there isn't any entries on the dba_segments
and dba_extents view for index organized tables?

Where would I be able to find extent information for an index
organized table?

Cheers

William
and we said...
They are there -- for the INDEX extents.  You have to convert
the IOT table name into its system generated index name.  For
example:

tkyte@TKYTE816> create table iot ( x int primary key, y date )
                organization index
                storage ( minextents 5 );

tkyte@TKYTE816> select index_name, index_type
  2  from user_indexes where table_name = 'IOT';

INDEX_NAME                     INDEX_TYPE
------------------------------ ---------------------------
SYS_IOT_TOP_22076              IOT - TOP

tkyte@TKYTE816> select bytes, blocks, extents
  2  from dba_segments where owner = USER
  3  and segment_name = 'SYS_IOT_TOP_22076';

     BYTES     BLOCKS    EXTENTS
---------- ---------- ----------
    655360         80          5
January 19, 2001 Steven -- Thanks for the question regarding "Where to I begin", version 8
You Asked
Dear Tom:

I'm in my second year of college as a CS major. I have mastered
HTML and JavaScript. But I want to learn something deeper,
something that today's Companies look and rely on. I have come
to the conclusion, that Oracle is it!

I would like to know, where I begin? What Internet guides or
books would you recommend for a novice developer?
and we said...
To get a good understanding of Oracle, what it is and how it
works -- I would highly recommend reading the Concepts guide
from cover to cover.  It is neither to high level or too deep to
get a good understanding of what it is about.  You do not need
to know SQL already to read it or how to write C or anything
like that.

You can get a copy of this at:
http://technet.oracle.com/doc/oracle8i_816/server.816/index.htm
I myself read this one document with every release of Oracle as
a refresher and to see whats "new".
January 19, 2001 Valar -- Thanks for the question regarding "Design of Large Databases /Multiple Small Databases", version 8.1.6
You Asked
Hi Tom,

Our requirement is to design a database which would contain
about 40 Million Records. The records would contain blob
(portait and signatures details of a customer) data. Given the
details of the data to be stored, we are anticipating that the
database size would work around 500 GB - 600 GB.

I would like to know whether if it is good to create multiple
databases of each 200 GB / some limtation like all data related
to year 1990 - 1993 in 1 database ; in the 2nd database have all
records related to 1993 - 1996 and so forth...

Or is it better to have all in one huge database ? How would
backup and recovery procedures affect,if we had a large database
? The proposed method is to use Legato Software. With the
previous experience, we are estimating to backup a 600 gb
database, it would take a day or so. is it advisable to have all
data in 1 one main database or should we scale the sizes od the
databases to facilitate easy maintenance and recovery ?

Also, how well can I take advantage of the partioning
techniques, even if I go for multiple small or large databases ?
Any pointers or suggestions would be really helpful.

The OS is Windows 2000 Server.

Thanks,
Valar
and we said...
No questions about it.  1 database -- period.

500/600 gig is not that large, especially if lots of the data is
"blob" data.

Partitioning would be a must for this database since it sounds
like 1 really huge table.  Where you would have used "multiple
databases" you will use partitions.  The methods you would have
employed to put the data into more then 1 database is what you
would use to put the data into partitions.

It should not take a day to backup a 500/600 gig database if you
have many devices.  Tablespaces can be backed up in parallel and
using RMAN (recovery manager) you can do incremental backups as
well.  Over time, as data becomes old, you may very well be able
to turn some partitions into "read only" partitions meaning you
never need to back them up again (unless you make them read
write once more).  Having the data in many databases would not
make backing up any faster (if you have the multiple devices to
backup many small databases you can throw them all at the single
instance as well).  In fact, it would take longer since the sum
of the sizes of the "small" databases would be much larger then
the size of the single instance would be.

500/600 gig is not huge.  It is large but very managable.
January 19, 2001 Mansur -- Thanks for the question regarding "To get Name of Table's Column Forms6.0", version none
You Asked
it is not working properly

declare
  colname varchar2(200);

begin
  colname := name_in('system.cursor_item');
  colname := null; --(it is not working)
end;

I am using in PopUp Menu. I want to reset any value of item
where i open the PopUp Menu. but colname variable is not
working.
and we said...
It is working -- it is doing exactly what you asked -- the
variable COLNAME after the assignment of NULL is in fact NULL.

If you are trying to set the item value whose NAME is in colname
to NULL, you need to use the copy builtin:

  copy( :system.cursor_item, NULL );

will take the NAME of the item in :system.cursor_item and copy a
NULL to that item.
Review & Followup
Rating: 4
use popup menu to navigate to a different form May 09, 2002
Reviewer: A reader
Tom, lets assume I have an emp form with deptno displayed

I want the functionality where I right click on the deptno item and a popup menu
appears and if I select an option go DEPT  in that menu I should be able to open
the dept form with read only access with the details of the respective deptno I
clicked in emp form.

Can you tell me how I should achieve this functionality.

January 19, 2001 Leah -- Thanks for the question regarding "JDBC query vs. Stored procedure", version 8.1.5
You Asked
Can you please explain why a stored procedure would run faster
than a JDBC query?
and we said...
I cannot -- it may, it may not.

If I had a stored procedure such as:

create or replace procedure foo
as
    type myVcArray is table of varchar2(30)
             index by binary_integer;

    l_enames    myVcArray;
begin
    select ename bulk collect into l_enames
      from emp;

    -- process.....
end;
/

That may very well execute faster then the corresponding java to
create the result set and fetch the rows.  There is no network
traffic involved here.  I am array fetching the data so there is
little context switching happening between the plsql runtime and
the database kernel.

Then again, if whatever -- process.... is runs faster in Java
then PLSQL, maybe - java will run the "process" faster.

Neither is inheritly FASTER then then other.  I can write slow
(or fast) plsql.  I can write slow (or fast) java.

I myself find that for data intensive things, things that do
lots of queries, I am 1,000 times more efficient using PLSQL
(coding efficiencies -- I can code the PLSQL to do something
many times faster and with many less errors then the
corresponding java code) then with java.
January 19, 2001 Jamie -- Thanks for the question regarding "HOW TO IMPLEMENT A LOGICAL BACKUP SET IN CONSISTENT MODE", version v8.1.6 and v7.3.4
You Asked
Hi Tom,

Here is my question:
According to the Oracle documentation, the incremental Exports
can not be specified as read_consistent (i.e.  CONSISTENT=y can
not be together with INCTYPE option).  Is the logical backup set
(monthly complete, weekly cummulative and daily incremental
exports) useful if it is taken while the database is open and
not being restricted.  If it is not useful because it is not
read-consistent, what would you do to have a consistent logical
backup set?

And here are my other questions:
1. Is it safe to remove the archive online logfiles after a hot
backup?
2. Should you still do a cold backup even though you do a hot
backup?  If so, then how often you should do a cold backup if
you do a hot backup nightly?

Thank you very much.
and we said...
Export should not be used for backup.  You should BACKUP in
order to backup.  EXP is not a good backup tool.

I would not ever even consider using export as a backup.  As an
extra copy to save myself in the event someone drops a table or
drops some code - yes.  As a backup for my database -- never in
a million years.

The cumulative exports are still useful yes.  You can use them
to restore A table in the event someone drops it.  You can use
them to get the DDL if someone has erased the scripts.  You can
use them to get the code for a procedure someone dropped.

You should never consider EXP a "backup" tool -- you should
consider a copy of some tables and DDL at some points in time.
You can never roll forward with it -- it is no good for doing a
database recovery from a failed disk.

As for "is it safe to remove the archive logfiles after a hot
backup".  I cannot really answer that -- not knowing how exactly
you do backups.  In general I would say the answer is "no".  You
need any archive that might have been generated DURING the
backup -- if you remove all archive logs after the backup, you
could be removing an archive you need.

Hopefully you keep AT LEAST 2 backups and you are constantly
copying archive redo log OFF of the machine onto some other
storage device.

You want to keep at least 2 backups for the following reason.
I've seen this happen -- someone is keeping 1 backup.  They just
overwrite the last backup with this new backup.  Halfway through
the backup -- a disk fails.  The database is now in need of
media recovery.  Unfortunately we were in the middle of copying
the file from the failed disk. Hence we do not have a copy of
this file at ALL -- anywhere.  We overwrote the last backup of
it with this new, failed copy.  We have lost data.  We need 2
backups at least in the event our last backup didn't work for
some reason.  You need to keep the archive logs needed to make
that backup consistent.

You need to constantly be getting archive redo log OFF of your
machine in the event the entire machine fails (gets burned up in
a fire for example).  Your hot backup is totally useless without
these archive redo logs to catch it back up.  You want a couple
of copies of these things around -- physically separate from the
machine that generated them -- in order to minimize data loss in
the event of a catastrophe.
January 19, 2001 Prem -- Thanks for the question regarding "Copy data from one schema to another", version Oracle 8
You Asked
Hi Tom,

I am now facing with a problem of copying data from one schema
to another. The requirement is that when a user switch to a mode
called the training mode all the data from the production
database has to be copied to another schema. I am not able to do
that through the database link and also the nested tables are
not supported over the link. So can you suggest a method to do
that as also a sample code. I can ofcource do this by using a
PL/SQl table and pass it over to another function at the target.
But this is a tedious task as there are more than 200 tables and
writing a function for each of them is not feasible. So what I
am looking is some kind of a say a dynamic way of doing it. Say
by passing the table name as the argument.

Please reply at the earliest

Regards
Prem
and we said...
exp userid=scott/tiger owner=scott file=scotts_data.dmp

followed by

imp userid=newuser/newps fromuser=scott touser=newuser
file=scotts_data.emp

will do that for you.  Just use EXP and IMP.
Review & Followup
Rating: 4
"Copy data from one schema to another", version Oracle 8 August 20, 2001
Reviewer: Rizwan Qazi from San Jose, CA
It was very helpful.

January 19, 2001 Anil -- Thanks for the question regarding "snapshot", version 8.1.5
You Asked
Hi tom,
  In 8.0.5 when we create snapshots, oracle creates mlog$ table
also.But In 8.1.5(8i) along with mlog$ table i see  rup$ table
also...what does it mean...and this is for what .

Thanx,

Regards
 Anil
and we said...
This is a temporary updatable snapshot log created for Java
RepAPI. When the user creates a PK snapshot log on a master
table, or does an 'alter snapshot log add primary key',  in
addition to  MLOG$_<tablename>, a temporary table by name
RUPD$_<tablename> is also automatically created.   When the user
gives 'Drop snapshot log on tablename', the snapshot log as well
as the temporary snapshot log are dropped.

For information on Java RepAPI, see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76959/repapi.htm#5445
...
Review & Followup
Rating: 4
snapshot October 17, 2003
Reviewer: sanchit jindal from Delhi, India

January 19, 2001 Amit -- Thanks for the question regarding "Datafile changes & backup", version 8.1.6
You Asked
Welcome back Tom !!

Assume a tablespace TS1 with datafiles DF1, DF2 .
The datafiles are backed up.

A few hours later, due to lack of space in TS1
one of the following happens:
  1) a new datafile DF3 is added.
  2) DF2 is manually resized to be larger.
  3) DF2 is autoextended.

A few hours after that one of the following
happens:
  1) the new DF3 is physically damaged and
     needs media recovery.
  2) the resized DF2 is physically damaged
     and needs media recovery.

Problems-
1. In the case of the DF3 recovery, we dont have a
   backup of the file from which to recover.
2. In the case of DF2 recovery- the backed up
   datafile size is smaller, and Oracle won't
   accept it for recovery.

Operational implications-
Please comment;
1. Every new / resized datafile must be backed up
   immediately after the change.
2. Should such a datafile be damaged before it
   is backed up, the tablespace needs to be
   recovered till point-in-time before the change.
   All data after that point-in-time in the tablespace
   will be lost.

Questions-
1. There is no "create datafile ... offline" syntax.
   If there were, a new datafile could be created
   offline, so that new data would not be put into it
   until we physically backup the datafile and then
   place it online for use.
   Is there any way to simulate the "create datafile ...
offline"
   effect ?
2. Theoretically, Oracle has all the information it needs
   about changes to datafiles in the online+archived logs.
   All the DDL commands of datafile resizing exist there.
   Is there any way to make Oracle accept an old copy
   of a datafile before resize, and apply all the events
   that happened to that datafile from it's old SCN till
   present time including the resize action) ?
3. Having tablespaces in autoextend mode; In this case
   datafiles will be extended, without the immediate
   knowledge of the dba. Is this risky ?
4. Is there any way of automating hot-backing up of
   new/resized datafiles with RMAN / OS backup ?

Thanks,
Amit.
and we said...
backup and recovery is much more robust then you think...

problem 1: "In the case of the DF3 recovery, we dont have a
   backup of the file from which to recover."

that's OK because everything we need to recover that datafile
with is in the online and archived redo logs.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/recoscen.htm#14480
for the exact steps.  See below for a specific exmaple.  We
don't NEED the datafile.

problem 2: "the backed up
   datafile size is smaller, and Oracle won't
   accept it for recovery."

isn't a problem because we most certainly will accept that file.
 As a test you can do this (i just did)

o create a small 1m tablespace with a datafile.
o alter it and begin backup.
o copy the datafile
o alter it and end backup.
o alter the datafile and "autoextend on next 1m" it.
o create a table with initial 2m initial extent. This will
  grow the datafile.
o offline the tablespace
o copy the 1m original file back.
o try to online it -- it'll tell you the file that needs
  recovery (its already accepted the smaller file at this
  point)
o alter database recover datafile 'that file';
o alter the tablespace online again -- all is well.

As for the questions:

1) There is such a command -- "alter database create datafile".
Here is an example I just ran through:

tkyte@TKYTE816> alter tablespace t begin backup;
Tablespace altered.

I copied the single datafile that is in T at this point

tkyte@TKYTE816> alter tablespace t end backup;
Tablespace altered.

tkyte@TKYTE816> alter tablespace t add datafile 'c:\temp\t2.dbf'
size 1m;
Tablespace altered.

So, I added a datafile AFTER the backup...

tkyte@TKYTE816> alter tablespace t offline;
Tablespace altered.

At this point, I went out and erased the two datafiles
associated with T.  I moved the copy of the one datafile in
place...

tkyte@TKYTE816> alter tablespace t online;
alter tablespace t online
*
ERROR at line 1:
ORA-01113: file 9 needs media recovery
ORA-01110: data file 9: 'C:\TEMP\T.DBF'

So, it sees the copy is out of sync...

tkyte@TKYTE816> recover tablespace t;
ORA-00283: recovery session canceled due to errors
ORA-01157: cannot identify/lock data file 10 - see DBWR trace
file
ORA-01110: data file 10: 'C:\TEMP\T2.DBF'

and now it tells of the missing datafile -- all we need do at
this point is:

tkyte@TKYTE816> alter database create datafile 'c:\temp\t2.dbf';
Database altered.

tkyte@TKYTE816> recover tablespace t;
Media recovery complete.
tkyte@TKYTE816> alter tablespace t online;
Tablespace altered.

and we are back in business....

2) It does and it will.

3) no.

4) it does much of this for you already -- this is part of what
they do.  You might want to read through some of the scenarios
in the backup and recovery guide -- they go through alot of this
and RMAN will automate most of it as it keeps lots of extra
information about the database.  However -- things it does NOT
know about -- it cannot help you with (so things you do AFTER it
(rman) runs might need some help from you but EVERY THING can be
recovered through).

The things you really need to worry about are unrecoverable
operations -- backups should occur after these or you need to be
preprared to "redo" them your self (that bulk data load, that
index build, that create table as select and so on that were
done in unrecoverable mode)
January 19, 2001 -- Thanks for the question regarding "Documentation for Oracle functions and packages", version 8.1.5
You Asked
Hi, Tom

where can i find a documentation/description of all Oracle
functions and packages (dbms_utility and other). I have not
found this in Server8i and Utility documentation.

Thanks, Oleg
and we said...
see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/toc.htm
which is the
"Oracle8i Supplied PL/SQL Packages Reference"
January 19, 2001 Oleg -- Thanks for the question regarding "Database block checking", version 8.1.6
You Asked
Hi, Tom!

There's an initialization parameter DB_BLOCK_CHECKSUM that turns
on/off calculating a checksum. The checksum is written to a
block only when block is written to datafile. The problem is
that some blocks are being written very rarely and some
(reference tables) are practically never being written down.

Is there any command or utility to force checksum calculating
and writing to all data blocks at once?

Thank you in advance,
and we said...
No and it wouldn't really make sense.  If the block is NEVER
written to disk -- it cannot become corrupt.  If the image on
disk is OK and we never write it to disk -- it is OK.
DB_BLOCK_CHECKING might be what you are looking for.

You can validate objects using various tools:

o analyze table T validate structure <cascade>;

o dbv -- the offline datafile verifier.

o dbms_repair

o db_block_CHECKING -- see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1094433279412
for some info.
January 19, 2001 Amin -- Thanks for the question regarding "Cross Matrix Report", version Reports 2.5
You Asked
Here is a real eg. a portion of SQL from report designer
***********************************
select
distinct
m.segment1||'.'||m.segment2||'.'||m.segment3||'.'||m.segment4,
m.description,
'00 - 07',
count(s.oe_trx_schedule_id) c
from can_cust_oe_trx_schedules s,
mtl_system_items m
where s.inventory_item_id = m.inventory_item_id
and m.description like  '%TACOMA%'
and m.segment4 = '0'
and shipping_date is not null
and s.created_by <> -1
and oe_tracking_date between :p_creation_date_low and
:p_creation_date_high
and trunc(shipping_date) - trunc(oe_tracking_date) <= 7
group by
m.segment1||'.'||m.segment2||'.'||m.segment3||'.'||m.segment4,m.d
escription

union all

select distinct
m.segment1||'.'||m.segment2||'.'||m.segment3||'.'||m.segment4,
m.description,
'08 - 14',
count(s.oe_trx_schedule_id) c
from can_cust_oe_trx_schedules s,
mtl_system_items m
where s.inventory_item_id = m.inventory_item_id
and m.description like  '%TACOMA%'
and m.segment4 = '0'
and shipping_date is not null
and s.created_by <> -1
and oe_tracking_date between :p_creation_date_low and
:p_creation_date_high
and (trunc(shipping_date) - trunc(oe_tracking_date) > 7 and
trunc(shipping_date) - trunc(oe_tracking_date) <= 14)
group by
m.segment1||'.'||m.segment2||'.'||m.segment3||'.'||m.segment4,m.d
escriptio
***************

The what i have done is made three groups
Group 1 have two fields. In default layout repeat is down
1. Segement1....
2. Description

Group 2 has my bucket field, Across in default layout

Group 3 has count c field, Down in default layout

Group 1 and 2 are cross product and group 3 is child of cross
product.

Resultant of this sql and cross matrix format is

                          00-07          08 - 14

Segment 1 & Description       99            55
Segment 2 & Description       44            22
and so on

so if have 7 buckets i write the same query 7 times with union
all, only differnce is third field which is my bucket.

*******
I wanted to create a Age Trial balance report. I used Cross
Matrix type report and was able to do it, but its very slow.
What i have done is for each bucket i used union all clause
for e.g.
Select
xxxx,
yyyy,
'First Bucket'
from
xxx
where
xxxxx

union all Select
xxxx,
yyyy,
'Second Bucket'
from
xxx
where
xxxxx

and so on. Is there a better approach using Cross Matrix method.
and we said...
Decode can let us do this transposition with 1 pass on the data.
 You basically have 3 columns
"segment,description,column-to-be-transposed".  I set up a small
example as thus:

tkyte@TKYTE816> create table t
  2  ( segment        varchar2(10),
  3    description       varchar2(10),
  4    schedule_id       int,
  5    shipping_date  date
  6  )
  7  /

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> declare
  2     r1 number;
  3     r2 number;
  4  begin
  5     for i in 1 .. 5
  6     loop
  7        for j in 1 .. 3
  8        loop
  9           for k in 1 .. random.rand_max(20)+1
 10           loop
 11              r1 := random.rand_max( 45 ) + 1;
 12              r2 := random.rand_max( 20 ) + 1;
 13
 14              insert into t values
 15              ( 'seg ' || i, 'desc ' || j, r2, trunc
                                               (sysdate+r1) );
 16           end loop;
 17        end loop;
 18     end loop;
 19  end;
 20  /

PL/SQL procedure successfully completed.

random.rand_max is something i wrote, see
http://osi.oracle.com/~tkyte/Misc/Random.html
for it if you would like.  That just generates some "dummy" data
for me.

Now, I'll dump out some of it for segment = 'seg 1'.  I'll pull
the days difference from "oe_tracking_date" (i'm using TODAY as
my oe_tracking_date -- where you have trunc(oe_tracking_date) i
have to_date( '19-JAN-2001')).  I'll also pull out the "week"
offset from that as well -- the ceil( difference/7 ).  That'll
return a number 1 if we are within 1..7 days, 2 if 8..14 and so
on.

tkyte@TKYTE816> select description,
  2         shipping_date-to_date('19-JAN-2001') days_diff,
  3     ceil( (shipping_date-to_date('19-JAN-2001'))/7 ) week_no
  4    from t
  5   where segment = 'seg 1'
  6   order by 3
  7  /

DESCRIPTIO  DAYS_DIFF    WEEK_NO
---------- ---------- ----------
desc 2              5          1
desc 2              6          1    <<== expect 2 for desc 2 in
desc 3              3          1         the 0-7 column
desc 3              2          1    <<== expect 2 for desc 3 in
desc 1             10          2         the 0-7 column
desc 2             11          2
desc 2             13          2
desc 3              8          2    <<== expect 3 for desc 3 in

desc 3              8          2         the 8-14 column
desc 3             14          2
desc 2             21          3
desc 2             21          3    and so on...
desc 3             16          3
desc 2             17          3
desc 2             22          4
desc 2             22          4
desc 2             23          4
desc 2             33          5
desc 2             31          5
desc 2             30          5
desc 3             32          5
desc 2             38          6
desc 2             42          6
desc 3             39          6
desc 3             37          6
desc 1             43          7

26 rows selected.

tkyte@TKYTE816> select segment, description,
  2         count( decode(
               ceil( (shipping_date-to_date('19-JAN-2001'))/7 ),
  3                       1, schedule_id, null ) ) "0-7",
  4         count( decode(
               ceil( (shipping_date-to_date('19-JAN-2001'))/7 ),
  5                       2, schedule_id, null ) ) "8-14",
  6         count( decode(
               ceil( (shipping_date-to_date('19-JAN-2001'))/7 ),
  7                       3, schedule_id, null ) ) "15-21",
  8         count( decode(
               ceil( (shipping_date-to_date('19-JAN-2001'))/7 ),
  9                       4, schedule_id, null ) ) "22-28"
 10    from t
 11   group by segment, description
 12  /

SEGMENT    DESCRIPTIO      0-7       8-14      15-21      22-28
---------- ---------- -------- ---------- ---------- ----------
seg 1      desc 1            0          1          0          0
seg 1      desc 2            2          2          3          3
seg 1      desc 3            2          3          1          0
seg 2      desc 1            3          2          3          2
seg 2      desc 2            2          0          1          2
seg 2      desc 3            1          1          1          4
seg 3      desc 1            3          2          0          1
seg 3      desc 2            0          4          3          8
seg 3      desc 3            1          4          1          3
seg 4      desc 1            1          1          5          1
seg 4      desc 2            3          1          4          3
seg 4      desc 3            1          2          2          1
seg 5      desc 1            3          1          1          3
seg 5      desc 2            2          0          0          1
seg 5      desc 3            0          0          2          1

Looking at this a little more closely:

tkyte@TKYTE816> select segment, description,
  2         count( decode(
               ceil( (shipping_date-to_date('19-JAN-2001'))/7 ),
  3                       1, schedule_id, null ) ) "0-7",

We are counting the DECODE of the "week number".  That "week
number" is a function that turns the difference in days between
our two dates into a number like 1, 2, 3, ... and so on.  If the
days are 1..7 days apart, we get 1.  8-14, we get two and so on.

We want COLUMN "0-7" to be a count of the schedule_id when the
difference between shipping_date and oe_tracking_date is less
then or equal to 7 -- hence when the decode of our function is
1, we return schedule_id else we return NULL.

We do the same thing for the column 8-14 only we look for the
ceil function to return 2.  And so on.

A simple group by and we get our counts.  In one pass we can not
only collect all of the data we need but we can transpose it as
well (reports won't need to do this for us)....
Review & Followup
Rating: 4
Is very useful May 10, 2001
Reviewer: Juan Carlos from Colombia
This query solve a lot of my problems

January 20, 2001 ahmad -- Thanks for the question regarding "oracle 8i partition", version 8.0.5
You Asked
hi;
tanx alot for ur previous help.
1.why is it useful to partion on multiple columns if multiple
columns make up table's primary key?
2.what is dynamic sql ?
3.what is character set and national characterset(the diffrence)
and what does this mean:
single byte 7 bit encoding scheme can define upto 128
(CHARACTERS.
single byte 8 bit encoding schem can define upto 256 characters
4.why we cant use bitmap indexes and unique indexes with index
clusters.
5 can we change minextents for a table or partition.
6.it is not possible to skip index maintenance on unusable
unique indexes but why?
7.what is the differece between local and global indexes except
that local index are automatically equpartitioned.
and we said...
1) I can't say that it is (or isn't) useful.  You partition by
what makes sense to partition by.  Did you read somewhere that
it is useful?  If so, a reference to that so I could read it in
context would help.

2) Dynamic SQL is SQL that is not static.  For example, in PLSQL
if I code:

  begin
      for x in ( select * from emp ) loop
         null;
      end loop;
  end;

that select is "static".  It is known at compile time and will
never change at runtime.  On the other hand:

create or replace
function get_row_cnts( p_tname in varchar2 ) return number
as
    l_theCursor     integer default dbms_sql.open_cursor;
    l_columnValue   number  default NULL;
    l_status        integer;
begin
    dbms_sql.parse(  l_theCursor,
                    'select count(*) from ' || p_tname,
                     dbms_sql.native );

    dbms_sql.define_column( l_theCursor, 1, l_columnValue );
    l_status := dbms_sql.execute(l_theCursor);
    if ( dbms_sql.fetch_rows(l_theCursor) > 0 )
    then
        dbms_sql.column_value( l_theCursor, 1, l_columnValue );
    end if;
    dbms_sql.close_cursor( l_theCursor );
    return l_columnValue;
end;
/

begin
   dbms_output.put_line('Emp has this many rows ' ||
                         get_row_cnts('emp'));
end;
/

shows how to do dynamic sql.  The SQL is in a string and we
dynamically execute it at runtime.

3) the character set is what "normal" data is stored as.  If you
insert into a varchar field -- it'll be in the character set of
the database.  the National character set allows you to have
fields of type nvarchar2 or nclob and data in these fields is
stored using the national character set.  It is a way to allow
you to store data from two different character sets in the
database simultaneously.

As for a 7 bit encoding schema (US7ASCII for example) can store
upto 128 different characters since 2^7 = 128.  If you have
7bits in which to store data, you have 128 unique characters.
An 8bit character set can store 256 characters.

4) Because there is a special index just for clusters -- the
cluster index.  It is what makes a cluster a cluster.  It is not
a b*tree (although it is very similar).  You cannot use ANY kind
of index for a cluster index except a CLUSTER INDEX.  Since each
cluster key value is stored only once each in the cluster and
the cluster index, no matter how many rows of different tables
contain the value it would be impossible for this to be
"unique".  A unique cluster key would sort of defeat the purpose
of clusters anyway -- the point of a cluster is to store all
rows with the same cluster key value on the same block and if
the cluster key were unique -- well then there wouldn't be
multiple rows with the same cluster key value!

5) No but you can alter the table and ALLOCATE extents for it
which has the same effect.

6) because they still exist.  If you want to skip maintenance,
you need to drop them.

7) thats the basic difference.  A local index has a one to one
mapping with the underlying partitions of the table upon which
it is built.  All of the rows in partition 1 of the table will
have index entries in partition 1 of the index and so on.

A global index can have its own partitioning scheme (or not)
that is wholly indepenedent of the table itself.  In partition 1
of the index, rows from ANY partition of the table may be
represented.
January 20, 2001 sangeetha -- Thanks for the question regarding "backup of transaction log", version version 8
You Asked
hai Tom,
can  you please guide me regarding the backup of transaction
log? iam in a conversion project from sqlserver to oracle.
the sql statement is
dump transaction with no commit
friends suggested me that it could be done with backup, but i
could not proceed. waiting for your reply
thanx
sangeetha
and we said...
We call it archive log mode.

SQLServer does transaction logging in a "heap".  We do it in a
circular buffer.  We are so different from them in this area
that you must unlearn everything you know about them and start
over.  The comparisions in this area are few and far between.
For example they manage REDO (replay that transaction) and UNDO
( rollback that transaction ) in the logs.  We manage REDO in
the logs and UNDO in the rollback segments in the database.

So, to get the continous chain of redo you need to make backups
consistent and to do hot backups, the database must be running
in "archivelog mode".  As we fill a log file, ARCH (a process)
will copy the filled redo log file to another destination(s).
After ARCH has copied it -- it is available for reuse.  This is
typically automated (the system does it) and you don't "dump
transaction" -- we just do it.

You want to give the concepts guide a good read through.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/toc.htm
it covers our structures, architecture and details such as
archivelog mode.  For example:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c28recov.htm#1850
is all about archivelog mode.
January 20, 2001 Harsh -- Thanks for the question regarding "Oracle 8i Personal Installation", version Oracle 8.1.6
You Asked
I have Windows Millineum Operating system. I have couple of
questions.
1. Can I install any version of Oracle Server i.e. Database (
not client ) on this O/s.
2. On which Windows O/s I can Install Oracle 8i version 8.1.6
Database ( It is downloaded from OTN). This Zip is same for NT
and 2000.

Pl. be specific also about the version of O/s.

Waiting for UR earliest response.
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1110233549326
...

Without knowing WHAT you exactly downloaded from technet, I
cannot say what OS specifically you can install on.

Oracle8i EE/SE from technet can only be installed on Win NT/2k.

Oracle8i PERSONAL edition can be downloaded to be installed on
Win NT/2k OR Win 98.


Subject | Article | Last Updated (East coast time)
Dropping an Index can improve the perfromance ! | article only | Jan 22, 2001 06:27 am
How to update a table upon startup. | article only | Jan 22, 2001 06:41 am
Question on Cluster Index ! | article only | Jan 22, 2001 06:51 am
Question related with character Set ! | article only | Jan 22, 2001 07:07 am
How to start and shutdown the database properly ! | article only | Jan 22, 2001 07:12 am
Indexes | article only | Jan 22, 2001 07:15 am
Question on Coalesced Space | article only | Jan 22, 2001 07:31 am
Asks Username/Password in SSL | article only | Jan 22, 2001 08:01 am
Speed of CLOB vs LONG | article only | Jan 22, 2001 04:52 pm
Space needed for anlalyzing of a table. | article only | Jan 23, 2001 08:22 am
Oracle University | article only | Jan 23, 2001 04:43 pm
dbms_job for more than one schema | article only | Jan 23, 2001 04:50 pm
Question on an answer | article only | Jan 23, 2001 05:02 pm
How to use ' From clasue query ' for a data block as a datasource. | article only | Jan 23, 2001 05:11 pm
Mutating Error | article only | Jan 23, 2001 05:17 pm
SELECT in the select-list | article only | Jan 23, 2001 05:19 pm
database backups | article only | Jan 23, 2001 05:23 pm
SQL UNLOADER | article only | Jan 23, 2001 06:36 pm
User Peivileges | article only | Jan 23, 2001 06:50 pm
idle session | article only | Jan 23, 2001 07:22 pm
fine grained user access control | article only | Jan 23, 2001 07:23 pm
pl/sql table | article only | Jan 23, 2001 08:32 pm
Making a URL call in PL/SQL | article only | Jan 24, 2001 10:11 am
Several Doubts | article only | Jan 24, 2001 10:19 am
Export utility -- what is its name on a PC | article only | Jan 24, 2001 10:29 am
To execute operating system command | article only | Jan 24, 2001 10:48 am
using sql loader | article only | Jan 24, 2001 02:00 pm
Package DBMS_SYS_SQL | article only | Jan 24, 2001 02:15 pm
import/export PROBLEM | article only | Jan 24, 2001 02:27 pm
Enabling SSL client server connection with Oracle 8.0.5 | article only | Jan 24, 2001 02:36 pm
size of tables,tablespaces | article only | Jan 24, 2001 03:19 pm
READING DATA from file | article only | Jan 24, 2001 03:49 pm
Roles during Export/Import | article only | Jan 25, 2001 05:52 pm
The "Query" option in the export command | article only | Jan 25, 2001 05:58 pm
Question on Direct path ! | article only | Jan 25, 2001 06:08 pm
suspending and resuming queries? | article only | Jan 26, 2001 08:09 am
Standby Database | article only | Jan 26, 2001 08:54 am
SQLPLUS | article only | Jan 26, 2001 09:24 am
dictionnary construction for log miner | article only | Jan 26, 2001 09:46 am
Question on Dynamic Extents ! | article only | Jan 26, 2001 09:57 am
XML Parser and V$ Files | article only | Jan 26, 2001 10:02 am
Date Manipulation When Testing Home Grown Applications | article only | Jan 26, 2001 10:10 am
Migration from DB2 to Oracle | article only | Jan 26, 2001 07:14 pm
Log miner again... | article only | Jan 26, 2001 07:17 pm
Invokers Rights Example | article only | Jan 26, 2001 07:18 pm
concurrent user | article only | Jan 26, 2001 07:55 pm
Date and char | article only | Jan 27, 2001 08:27 am
Problems with insert and cursor | article only | Jan 27, 2001 08:48 am
oracle sequences | article only | Jan 27, 2001 09:16 am
Fine Grained Security error ORA-00439 | article only | Jan 27, 2001 09:17 am
Truncate | article only | Jan 27, 2001 09:23 am
NT vs Unix | article only | Jan 27, 2001 09:35 am
OCP certifications | article only | Jan 27, 2001 09:48 am
Replacing primary key with non unique index | article only | Jan 27, 2001 10:06 am
How to find out which version of solaries is compatible | article only | Jan 27, 2001 10:10 am
selecting max value with all columns for distinct values | article only | Jan 27, 2001 10:19 am
Running Multiple databases on Server | article only | Jan 27, 2001 10:27 am
Script | article only | Jan 27, 2001 10:48 am
stored procedure | article only | Jan 27, 2001 10:50 am
java thin driver | article only | Jan 27, 2001 10:52 am
How to find system up and down time | article only | Jan 27, 2001 11:04 am
Displaying records in a control block(MULTI) and linking it to graph. | article only | Jan 27, 2001 11:31 am
Running Multiple Databases on the Server | article only | Jan 27, 2001 11:47 am
MTS and Parallel Server | article only | Jan 27, 2001 02:28 pm
Trusted Oracle | article only | Jan 28, 2001 09:23 am
Communicating b/w 2 sessions | article only | Jan 28, 2001 09:36 am
Help Regarding Executing OS command from PL/SQL | article only | Jan 28, 2001 09:57 am
oracle? | article only | Jan 28, 2001 02:48 pm
ifile | article only | Jan 28, 2001 07:28 pm
row(s) 1 - 69 of 69
January 22, 2001 OP -- Thanks for the question regarding "Dropping an Index can improve the perfromance !", version 8.1.6.0
You Asked
Dear Tom,
Hi !

How are you Doing !

Thanks for the previous suggestions.

Today,my Quest is as follows :-

Q) Is there any case where dropping an Index sometimes
improves the performnace of a Query or the overall
performnace of the server ? If Yes,kindly give me the
details.

Thanks and Regards
OP Lalwani
and we said...
Sure, anything can happen.

Lets say you are using the rule based optimizer.

You have a table T ( x int primary key, z date );

and you issue:

select count(*) from t where x > 0 and z < sysdate;

The RBO will use the index on the primary key typically, in a
plan like this:

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   SORT (AGGREGATE)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'T'
   3    2       INDEX (RANGE SCAN) OF 'SYS_C0014379' (UNIQUE)

Now, if ALL of the values of x are greated then zero -- this is
a very inefficient plan.  It would be much better to FULL SCAN
the table.  Get rid of or otherwise preclude the use of an index
and it'll go faster (this query will).   Note however that other
queries may get slower now as well.
January 22, 2001 praveen -- Thanks for the question regarding "How to update a table upon startup.", version 8.1.6
You Asked
I want to update a table whenever database started.Where should
I write the code?
and we said...
You can use an AFTER STARTUP trigger to accomplish this.  For a
quick example, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:263215360334
...
January 22, 2001 OP -- Thanks for the question regarding "Question on Cluster Index !", version 8.1.6.0
You Asked
Dear Tom,

Hi !

Q) Is clustrering and Cluster Index are same things ?
How a cluseter index can improve the storage space.
Kindly expalin the scenarios where creating a cluster
index will benefit in the database.

Kindly give the syntax for the creation of CLUSTER
and HASH INDEX ?

Thanks and Regards
OP Lalwani
and we said...
A cluster index is needed in support of a cluster.  One is used
to allow the other to exist.  Much like we need an index in
support of a primary key.  They are not the same things.

Clusters are useful in the database to store related pieces of
information from more then 1 table in the same physical database
block.  It in effect stores data "prejoined".  I can use this
technique to store all of the data from the DEPT and EMP table
for a given DEPTNO on the same block so that all employees of
department 10 as well as the department 10 master record are all
physically stored on the same exact block.  When I go to "join"
this data -- it is already done for me -- in a very few IOs I
can get all of the data I need.  Using conventional tables, this
data could be scattered onto many dozens of blocks.

Clusters are useful when you want data with the same cluster key
values to be physically stored near eachother.

Hash clusters are useful when you always access the data by
primary key.  For example, say you have some data in a table T
and you ALWAYS query:

  select * from T where id = :x;

That might be a good candidate for a hash cluster since there
will be no index needed.  Oracle will hash the value of :x into
a physical address and go right to the data.  No index range
scan, just a table access by the hash value.

The cluster syntax can be viewed at:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/ch4e6.htm#13140
it gives examples of creating a cluster, the cluster key index,
and the tables in the cluster.

Also, with a hash cluster there is no index by definition so no
syntax to inspect.  We hash the cluster key to determine where
the data goes -- we do not index it.  the data is the index.
Review & Followup
Rating: 5
November 16, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

January 22, 2001 OP -- Thanks for the question regarding "Question related with character Set !", version 8.1.6.0
You Asked
Dear Tom,

Hi !

Scenario
========

At my site we are developing a project for NTT
a Japanese company.

The database should support Japanese character.Now I
have Nt 4.0 Installed and the OS supports Japanese
character.I have installed ORACLE ENTERPRISE EDITION
for Oracle 8i.It was a TYPICAL INSTALLATION.

This database support English Character set.

Ques 1) Is there any command through which now the character
set can be changed to Japanese.

The driver to be used is "JA16SJIS ".

Ques 2) Is it compulsory that the OS in this case should
also support Japanese character set.

Thanks and Regards
OP Lalwani
and we said...
1) there are some cases where the character set can be converted
if the new character set is a strict superset of the existing
one.  You'll want to read through the NLS documenation:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76966/toc.htm
specically:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76966/ch3.htm#47136
which is "Changing the Character Set After Database Creation"

2) No it is not required.
January 22, 2001 OP -- Thanks for the question regarding "How to start and shutdown the database properly !", version 8.1.6.0
You Asked
Dear Tom,

Hi !

How are you Doing !

At our site I have ORACLE 8i Installed on WINDOWS NT 4.0.
It's now compulsory at this stage to make the database
available for 24 Hours.It has to be shutdown properly
while the office timmings are over.

Ques 1) What is the proper method to shutdown the database
through Orcale command ?

Ques 2) Where Exactly the change can be made in OS so that
the DATABASE should start when the computer boots with
NT and the instance shutdown properly when the computer
is switched off ?

Ques 3) Can I schedule the DATABASE STARTUP and SHUTDOWN
event so that it automatically starts at 9 a.m. and
shutdown sharp at 6 p.m .

Thanks and Regards
OP Lalwani
and we said...
1) you can use commands such as:

C:\>svrmgrl

Oracle Server Manager Release 3.1.6.0.0 - Production
Copyright (c) 1997, 1999, Oracle Corporation.  All Rights
Reserved.
Oracle8i Enterprise Edition Release 8.1.6.0.0 - Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production
SVRMGR> connect sys/manager as sysdba;
Connected.
SVRMGR> shutdown

You could also use the NET command:

C:\> net stop oracleservice<ORACLE_SID>

where oracleservice<ORACLE_SID> is the name of your database
service.

You could also use the control panel to stop/start the service.

You could also use OEM (enterprise manager) to control the
status of the database.

2) this should be done for you already.  We register services to
start/stop the database with the OS.  Go into control panel and
you should see the services there.  You can set the method for
starting the database to "automatic", "manual", or "disabled".
Its default setting is "automatic".

3) Well, while this seems to conflict with your original
statement that "the database available for 24 hours" -- the way
to do this would be to use a tool such as Oracle Enterprise
Manager which has job scheduling services.  You can setup jobs
to start and stop the database.

It is HIGHLY irregular and affects performance in a negative
fashion to frequently stop and restart the database.  You should
reconsider your desire to shutdown the database every night.
January 22, 2001 Siva -- Thanks for the question regarding "Indexes", version 7.3.4
You Asked
Can you give me a comprehensive set of considerations while
creating indexes as well as tips on when indexes work and when
they are actually counter productive - I'd specifically like to
know if indexes on string fields are not good enough and how to
tell the threshold number of records whereafter indexes actually
improve performance - I know most of this depends on the kind of
application one has but what I am looking for is a list of
guidelines and tips garnered from experience

Thanks
Siva Gabbita
and we said...
See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/ch6_acce.htm#427
for the rules of thumb.

Indexes on string fields (remember that NUMBERS in Oracle are in
fact "strings" of upto 22 bytes in length) are very effective.
If you have an ENAME field for example and run queries like:

   select * from emp where ename = 'KING';

an index on ename may very well be called for.
January 22, 2001 Bhavesh -- Thanks for the question regarding "Question on Coalesced Space", version 8.1.5
You Asked
Dear Tom,
Thanks for all the help so far.
We are on Solaris/Oracle8i 8.1.5.
I have PCTINCREASE 10.
In our TEST system, the query and o/p is given below.
Can you explain me following in view of the o/p please?
1. What is difference between per_coa_free_bytes AND
   percent_extents_coalesced ?
2. Above two columns is 100% for my interest tablespaces (
   FMSMMS ,IMS, MRPPIM, TEMP, TS1 ). This seems good. Is it
   because the SMON  processes is awaking and doing its job
   at GOOD ENOUGH frequency ?
3. If above two column is not showing good picture, how
   can I forcefully make SMON awake and force her to do her
   job ?

-- Here is the query:
set numformat 999,990.99
column pct_free heading "PCT_FREE|SPACE"
column largest_free_chunk_mb heading "LARGEST|CHUNK|FREE_MB" format 999,990.99
column tot_exts heading "NO_OF|CHUNKS|FREE"
column pct_free heading "PCT_FREE|SPACE"
column per_coa_free_bytes heading "PER|COA|FREE|BYTES"
column per_coa_free_exts heading "PER|COA|FREE|EXTS"
break on report

select substr(a.tablespace_name,1,15) tablespace_name,
substr(round(a.total_bytes*100/tot_size,2) || ' %', 1, 8) pct_free,
max(b.bytes/(1024*1024)) largest_free_chunk_mb,
a.total_extents tot_exts,
round(a.bytes_coalesced/a.total_bytes*100, 0) per_coa_free_bytes,
percent_extents_coalesced per_coa_free_exts
from  (
  select tablespace_name, sum(bytes) tot_size
  from dba_data_files
  group by tablespace_name
 ) a1,
  dba_free_space_coalesced a, dba_free_space b
where a.tablespace_name = b.tablespace_name
and   a1.tablespace_name = b.tablespace_name
group by a.tablespace_name,
substr(round(a.total_bytes*100/tot_size,2) || ' %', 1, 8) ,
a.total_extents,
round(a.bytes_coalesced/a.total_bytes*100, 0),
percent_extents_coalesced
;

-- Output of above query:
                                                   PER      PER
                           LARGEST     NO_OF       COA      COA
                PCT_FREE     CHUNK    CHUNKS      FREE     FREE
TABLESPACE_NAME SPACE      FREE_MB      FREE     BYTES     EXTS
--------------- --------- -------- --------- --------- --------
FMSMMS          18.56 %     309.35     12.00    100.00   100.00
IMS             37.24 %     488.44     21.00    100.00   100.00
MRPPIM          22.43 %     290.48     24.00    100.00   100.00
OEM_REPOSITORY  99.92 %       5.00      1.00    100.00   100.00
RBS             86.81 %      33.59    350.00     12.00    18.00
SYSTEM          34.69 %      57.98     31.00    100.00   100.00
TEMP            100 %         2.01    169.00      0.00     0.59
TS1             39.91 %      35.98      9.00    100.00   100.00

8 rows Selected.

tia,
Bhavesh Patel.
and we said...
In Oracle8i -- you should use locally managed tablespaces.  Then this hole
discussion is moot.  You never need to coalesce, things run faster (less
recursive sql) and it is virtually impossible to fragment (leave holes) in a
tablespace.  I no longer use dictionary managed tablespaces for anything other
then SYSTEM (which must currently be dictionary managed).

pctincrease is DEADLY.  I would recommend pctincrease = 0 for all objects in all
cases.  If you use equi sized extents or extents that are nice multiples of
eachother, fragmentation cannot occurr and the need to coalesce is not there.
If everyone uses the same sized extents (eg: we all use 5meg extents in
tablespace IMS for example) and you have 2 contigous free 5meg extents -- who
cares if they are coalesced into 1 10meg extent (which would have to be split
later to be used) or left as 2 5meg extents???  I would leave them at 2 5meg
extents (pctincrease = 0 will do that for us).

1) well, you wrote the query -- I would hope you might know ;)

it looks like one is reporting the pct of free bytes coalesced (total SPACE)
whereas the other is reporting on the number of extents (1 extent might have
50meg, another 1meg).  The two measure two totally different things.

2) unless you DROP and/or TRUNCATE objects -- SMON has nothing to do here.  We
can only coalesce free extents and unless you drop or truncate objects
frequently we have nothing to coalesce!  TEMP space is managed totally different
from other types of space so there is nothing for us to do here either.

3) you can issue alter tablespace TABLESPACE coalesce.  Again, it can ONLY have
an effect after a drop or truncate.  If you use locally managed tablespaces --
it is a moot point.
January 22, 2001 Ashish -- Thanks for the question regarding "Asks Username/Password in SSL", version 8.1.5
You Asked
HI TOM,

We are using Oracle 8.1.5 and OAS 4.0.81 for web site. Just
recently we have configured the SSL on our web server. We are
using basic oracle authenticatoin. Most of the pages are
dynamic. When the user first logs in he is served a insecured
page. After that if the user clicks on one of the links than it
goes to a secured page. This time the browser warns about it,
which is fine. But the problem is it asks for username/password
again. This isn't the same with IE 5.0 where it didn't ask for
usr/pwd again. But in IE 5.5 it asks. Is it the Browser problem
or is it we are missing on something. Also advise if there are
certain things to be taken care of to configure SSL.

Thanks a lot,

ashish
and we said...
It was a browser problem with IE 5.0.  They should have been
asking all along.

The browser is to cache the username and password by:

o protocol (http, https)
o hostname
o port on the host
o realm (as defined by the appliation itself)

if ANY of the above changes -- you must be reprompted for the
password.  Changing from http to https should prompt you.  If
you find the host names:

   foobar
   foobar.your.domain

are the same to you (eg: your.domain is your default domain)
they should be different to the browser so that:
http://foobar/
and
http://foobar.your.domain/
would both ask you for your password again.

This is the way in which basic authentication is specified to
function.  That IE didn't do it in 5.0 was a bug.  Since this is
part of the HTTP protocol, there is nothing you can do to change
the behaviour other then consistently use the same protocol (or
not use basic authentication).
January 22, 2001 Christian -- Thanks for the question regarding "Speed of CLOB vs LONG", version 8.1.5 and 8.1.6 (Linux)
You Asked
Hello Tom!

I have a performance problem concerning character data of length >4000
characters, which I can't store in a VARCHAR2 field.

I insert and then read back a set of data entries of ca 100kb length. When I do
this using a test table consisting of the attributes (id INTEGER, data CLOB),
the operation takes approximately 10 times longer than when I use a table
consisting of (id INTEGER, data LONG). This effect can be shown with Java using
JDBC (classes12.zip) and Perl using DBI (DBI: 1.13; DBD: 1.06), so I suppose
this is not the problem of the application, but of the (configuration of the?)
Oracle server.

SQL code for creating the tables T1 and T2:

create table t1 (id integer, data clob);
create table t2 (id integer, data long);

The Java code for inserting a CLOB is:

      PreparedStatement pstat1 =
          conn.prepareStatement
          ("insert into T1 values (?, empty_clob())");
      PreparedStatement pstat2 =
          conn.prepareStatement
          ("select DATA from T1 where id=? for update");
      for (int id=1; id<=ENTRIES; id++) {
          System.out.println(" Inserting ID " + id + "...");
          pstat1.setInt(1, id);
          pstat1.executeUpdate();
          pstat2.setInt(1, id);
          ResultSet res = pstat2.executeQuery();
          if (res.next()) {
              CLOB clob = (CLOB)res.getClob(1);
              clob.putString(1, outString);
          }
          res.close();
          conn.commit();
      }

Java code for reading a CLOB:

    PreparedStatement pstat =
        conn.prepareStatement("select DATA from T1 where id=?");
    for (int id=1; id<=ENTRIES; id++) {
        pstat.setInt(1, id);
        ResultSet res = pstat.executeQuery();
        while (res.next()) {
            Clob dataClob = res.getClob(1);
            String data =
                dataClob.getSubString(1, (int)dataClob.length());
            //System.out.println(data + ": " + data.length());
            System.out.println(" " + id + ": length: " +
                               data.length() + "; data: " +
                               data.charAt(0) +
                               data.charAt(1) + "..." +
                               data.charAt(data.length()-1));
        }
        res.close();
    }

Now the LONG stuff:
Inserting:

    PreparedStatement pstat =
        conn.prepareStatement("insert into T2 values (?, ?)");
    for (int id=1; id<=ENTRIES; id++) {
        System.out.println(" Inserting ID " + id + "...");
        pstat.setInt(1, id);
        pstat.setCharacterStream
            (2, new StringReader(outString.toString()), LENGTH);
        pstat.executeUpdate();
        conn.commit();
    }
    pstat.close();

Reading:

    pstat = conn.prepareStatement
                ("select DATA from T2 where id=?");
    for (int id=1; id<=ENTRIES; id++) {
        pstat.setInt(1, id);
        ResultSet res = pstat.executeQuery();
        while (res.next()) {
            String data = res.getString(1);
            //System.out.println(data + ": " + data.length());
            System.out.println(" " + id + ": length: " +
                               data.length() + "; data: " +
                               data.charAt(0) +
                               data.charAt(1) + "..." +
                               data.charAt(data.length()-1));
        }
        res.close();
    }

I would like to use CLOB instead of LONG because of some advantages, but the
performance disadvantages I ran into make me doubt.

Can you help me speeding up CLOBs?

Greetings

Christian
and we said...
Here are my findings

- the jdbc thin driver WRITES the clob 4,000 bytes at a time.  It reads it 32k
at a time.

- the jdbc THICK (oci8) driver uses internal API calls and is not limited to
4,000 bytes during the write.  It is many times faster.

- the long interface appears to work at about the same speed using either thick
or thin.

- using the OCI8 jdbc driver, we can write clobs at about the same speed and
read them as fast.

In any case, using DBMS_LOB.READ and WRITE instead of the helper functions will
allow you to contol the "chunksize" explicitly.  You can chunk the data upto 32k
in size.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:110812348061
for an example using Java.  It shows writing a BLOB using 32,000 bytes as
the chunksize.

I used the tables:

create table t1 ( id int, data clob );
create table t2 ( id int, data long );

in this test.  My outcome was:

clob.jdbc.thick
JDBC driver version is 8.1.6.2.0
2001-01-22 09:45:18.378:Going to write
2001-01-22 09:45:24.626:Going to read       ~6.3 seconds
2001-01-22 09:45:24.959:done                ~.3 seconds

clob.jdbc.thin
JDBC driver version is 8.1.6.2.0
2001-01-22 09:43:38.04:Going to write
2001-01-22 09:44:17.577:Going to read      ~39.5 seconds
2001-01-22 09:44:18.257:done               ~.8 seconds

long.jdbc.thick
JDBC driver version is 8.1.6.2.0
2001-01-22 09:52:41.086:Going to write
2001-01-22 09:52:46.519:Going to read      ~5.5 seconds
2001-01-22 09:52:47.257:done               ~.7 seconds

long.jdbc.thin
JDBC driver version is 8.1.6.2.0
2001-01-22 09:53:53.426:Going to write
2001-01-22 09:53:58.906:Going to read      ~5.5 seconds
2001-01-22 09:53:59.28:done                ~.3 seconds

This was using a 1.4meg clob as a test.

I used this code:

import java.sql.*;
import oracle.jdbc.driver.*;
import oracle.sql.*;

class JDBCVersion
{

public static void showTimeStamp( String msg )
{
    System.out.println( (new
       Timestamp(System.currentTimeMillis())).toString() +
                  ":" + msg );
}

public static void test_write(Connection conn) throws Exception
{
      PreparedStatement pstat1 =
          conn.prepareStatement
          ("insert into T1 values (?, empty_clob())");

      PreparedStatement pstat2 =
          conn.prepareStatement
          ("select DATA from T1 where id=? for update");

      showTimeStamp( "Generating data" );
      String outString = "Hello World";
      for( int i = 1; i < 18; i++ )
        outString = outString + outString;
      showTimeStamp( "Generated " + outString.length() +
                     " bytes of data" );

      showTimeStamp(" Inserting" );
      pstat1.setInt(1, 1);
      pstat1.executeUpdate();
      showTimeStamp( "Inserted data...." );

      pstat2.setInt(1, 1);
      ResultSet res = pstat2.executeQuery();
      showTimeStamp( "Executed Select" );

      if (res.next())
      {
          showTimeStamp( "Fetched Row" );
          CLOB clob = (CLOB)res.getClob(1);
          showTimeStamp( "Got Clob" );
          clob.putString(1, outString);
          showTimeStamp( "put string" );
      }
      res.close();
      conn.commit();
}

public static void test_read(Connection conn ) throws Exception
{
    PreparedStatement pstat =
        conn.prepareStatement("select DATA from T1 where id=?");

    showTimeStamp( "Executing Query" );
    pstat.setInt(1, 1);
    ResultSet res = pstat.executeQuery();
    while (res.next())
    {
        showTimeStamp( "Fetched row" );
        Clob dataClob = res.getClob(1);
        showTimeStamp( "got clob" );
        String data =
            dataClob.getSubString(1, (int)dataClob.length());
        showTimeStamp(" got string " + ": length: " +
           data.length() + "; data: " +
           data.charAt(0) + data.charAt(1) + "..." +
           data.charAt(data.length()-1));
    }
    res.close();
}

public static void main(String args[])throws Exception
{
    DriverManager.registerDriver
     (new oracle.jdbc.driver.OracleDriver());

    Connection conn=DriverManager.getConnection
      //("jdbc:oracle:thin:@aria-dev:1521:ora816dev"
      ("jdbc:oracle:oci8:@ora816dev.us.oracle.com"
          ,"scott","tiger");

    DatabaseMetaData meta=conn.getMetaData();
    System.out.println
    ("JDBC driver version is "+meta.getDriverVersion());

    conn.setAutoCommit(false);

    Statement stmt = conn.createStatement ();

    stmt.execute( "alter session set sql_trace=true" );
    stmt.execute( "delete from t1" );

    showTimeStamp( "Going to write" );
    test_write(conn);
    showTimeStamp( "Going to read" );
    test_read(conn);
    showTimeStamp( "done" );
}
}

import java.io.*;
import java.lang.*;
import java.sql.*;
import java.util.*;
import oracle.jdbc.driver.*;
import oracle.sql.*;

class JDBCVersion2
{

public static void showTimeStamp( String msg )
{
    System.out.println( (new
       Timestamp(System.currentTimeMillis())).toString() +
                   ":" + msg );
}

public static void test_write(Connection conn) throws Exception
{
    PreparedStatement pstat =
        conn.prepareStatement("insert into T2 values (?, ?)");
    showTimeStamp( "Generating data" );
    String outString = "Hello World";
    for( int i = 1; i < 18; i++ )
        outString = outString + outString;
    showTimeStamp( "Generated " + outString.length() +
                    " bytes of data" );
    int LENGTH = outString.length();

    System.out.println(" Inserting " );
    pstat.setInt(1, 1);
    pstat.setCharacterStream
          (2, new StringReader(outString.toString()), LENGTH);
    showTimeStamp(" Inserting" );
    pstat.executeUpdate();
    showTimeStamp( "Inserted data...." );
    conn.commit();

    pstat.close();
}

public static void test_read(Connection conn ) throws Exception
{

    PreparedStatement pstat = conn.prepareStatement
                ("select DATA from T2 where id=?");
    pstat.setInt(1, 1);
    showTimeStamp( "Executing Query" );
    ResultSet res = pstat.executeQuery();
    while (res.next()) {
        showTimeStamp( "Fetched row" );
        String data = res.getString(1);
        showTimeStamp( "got long" );
        //System.out.println(data + ": " + data.length());
        showTimeStamp(" " + 1 + ": length: " +
                           data.length() + "; data: " +
                           data.charAt(0) +
                            data.charAt(1) + "..." +
                            data.charAt(data.length()-1));
    }
    res.close();
}

public static void main(String args[])throws Exception
{
    DriverManager.registerDriver
       (new oracle.jdbc.driver.OracleDriver());

    Connection conn=DriverManager.getConnection
        ("jdbc:oracle:thin:@aria-dev:1521:ora816dev"
        //("jdbc:oracle:oci8:@ora816dev.us.oracle.com"
        ,"scott","tiger");

    DatabaseMetaData meta=conn.getMetaData();
    System.out.println("JDBC driver version is "+
                        meta.getDriverVersion());

    conn.setAutoCommit(false);

    Statement stmt = conn.createStatement ();

    stmt.execute( "alter session set sql_trace=true" );
    stmt.execute( "delete from t2" );

    showTimeStamp( "Going to write" );
    test_write(conn);
    showTimeStamp( "Going to read" );
    test_read(conn);
    showTimeStamp( "done" );
}
}
Review & Followup
Rating: 4
Speed of CLOB vs LONG January 05, 2002
Reviewer: netroamer from Beijing, China
I test the java programs. It works at my Win2000. But it doesn't work in 8.1.5
at Solaris 7. I've got error like this:

E:\trsbean\work>java JDBCVersion
JDBC driver version is 8.1.6.0.0
2002-01-06 11:55:35.647:Going to write
2002-01-06 11:55:35.728:Generating data
2002-01-06 11:55:35.728:Generated 10240 bytes of data
2002-01-06 11:55:35.728: Inserting
2002-01-06 11:55:35.758:Inserted data....
2002-01-06 11:55:35.768:Executed Select
2002-01-06 11:55:35.768:Fetched Row
2002-01-06 11:55:35.788:Got Clob
2002-01-06 11:55:35.868:put string
Exception in thread "main" java.sql.SQLException: ORA-03113: end-of-file on
communication channel

        at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:114)
        at oracle.jdbc.oci8.OCIDBAccess.check_error(OCIDBAccess.java:1503)
        at oracle.jdbc.oci8.OCIDBAccess.commit(OCIDBAccess.java:397)
        at oracle.jdbc.driver.OracleConnection.commit(OracleConnection.java:479)

        at JDBCVersion.test_write(JDBCVersion.java:51)
        at JDBCVersion.main(JDBCVersion.java:101)

What does it mean?

January 23, 2001 Ravi -- Thanks for the question regarding "Space needed for anlalyzing of a table.", version 805
You Asked
Tom,

I have table with allotted space more than 30G and also, the
used space is surely greater than 20G( accounting the rest 10G
for pctfree, unused block, etc.)

I am analyzing this table with compute statistics. Oracle says
that

"For COMPUTE STATISTICS, enough temporary space to hold and sort
the entire table plus a small overhead for each row is required"

But I have a temp. tablespace of only 4G. Though, the table size
is 30G (and used is >20G) but temp. tablespace <4G, how my
analyze command succeeds. I expected to fail thining, I may
required a temp. tablespace of size between 20 and 30G.

Could you please explain.

Thanks
Ravi

Tom,

Following are the details you have requested.

I am using the oracle provided procedure for analzing. It is

execute sys.dbms_utility.analyze_schema('FC_ADMIN','COMPUTE');

select blocks, empty_blocks from dba_tables where
table_name='FC_TEXT';

   BLOCKS EMPTY_BLOCKS
--------- ------------
  9273268        23365

The size of  db block is 8192 Bytes(ie 8k)

The table creation script is REM  CREATE TABLE
"FC_ADMIN"."KC_TEXT" ("MESSAGEID" NUMBER(*,0) NOT
REM  NULL ENABLE, "TYPE" NUMBER(*,0) NOT NULL ENABLE, "VALUE"
LONG,
REM  "COMPRESSLEVEL" NUMBER(*,0)) PCTFREE 10 PCTUSED 40 INITRANS
1
REM  MAXTRANS 255 LOGGING STORAGE(INITIAL 2147483646 NEXT
262144000
REM  MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS
1 FREELIST
REM  GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "FC_MESSAGE" ;

It does not have any indexes created explicitly. However, there
is a primay key defined on the table. Folloing depicts the same.

select * from dba_indexes where table_name='FC_TEXT';

OWNER                          INDEX_NAME
INDEX_TYPE
------------------------------ ------------------------------
------------
TABLE_OWNER                    TABLE_NAME
TABLE_TYPE  UNIQUENES
------------------------------ ------------------------------
----------- ---------
TABLESPACE_NAME                INI_TRANS MAX_TRANS
INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS
------------------------------ --------- ---------
-------------- ----------- -----------
MAX_EXTENTS PCT_INCREASE PCT_THRESHOLD INCLUDE_COLUMN FREELISTS
FREELIST_GROUPS  PCT_FREE LOG
----------- ------------ ------------- -------------- ---------
--------------- --------- ---
   BLEVEL LEAF_BLOCKS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY
AVG_DATA_BLOCKS_PER_KEY
--------- ----------- ------------- -----------------------
-----------------------
CLUSTERING_FACTOR STATUS    NUM_ROWS SAMPLE_SIZE LAST_ANAL
DEGREE
----------------- -------- --------- ----------- ---------
----------------------------------------
INSTANCES                                PAR T G BUFFER_
---------------------------------------- --- - - -------
FC_ADMIN                     FC_TEXT_PK                  NORMAL
FC_ADMIN                     FC_TEXT                     TABLE
    UNIQUE
FC_INDEX                             2       255        1048576
  52428800           1
  2.147E+09            0                                      1
             1        10 YES
        2       78697      28792745                       1
                 1
         12509559 VALID     28792745           0 21-JAN-01 3
DEFAULT                                  NO  N N DEFAULT

I also, have couple of other tables, that have size(the allotted
extents) > than the size of the temp. tablespace of the user who
is analyzing it. Still my query does not fail.

I am curiously waiting for your answers.

Thanks
Ravi
and we said...
Looking at your table -- I'm going to make some assumptions:

o messageid is unique
o type is of low cardinality (select count(distinct type) would
return a small number)
o value is of relatively small cardinality
o compress is of low cardinality

The amount of space required by the analyze will be a function
of the amount of "distinctness" in the table overall.  In a very
"distinct" table -- we will need more space then if the same
values are repeated over and over.

In the following examples -- I'm using an autoextend temporary
tablespace.  I start this tablespace out very small and let it
grow.  I'm the ONLY one using it so I get judge how much temp
space exactly I've been using by looking at the final file size.
 I created this temporary tablespace as such:

ops$tkyte@DEV816> alter user ops$tkyte temporary tablespace
temp;
User altered.

ops$tkyte@DEV816> drop tablespace tkyte_temp
  2  /
Tablespace dropped.

ops$tkyte@DEV816> create temporary tablespace tkyte_temp
  2  tempfile '/tmp/tkyte_temp.dbf'
  3  size 564k reuse
  4  autoextend on next 100k
  5  extent management local UNIFORM size 100k;
Tablespace created.

ops$tkyte@DEV816> alter user ops$tkyte temporary tablespace
tkyte_temp;
User altered.

I did this (dropped and recreated tkyte_temp) before each of the
"test" runs below.

For the first run, I created some sample data via:

ops$tkyte@DEV816> insert into kc_text
  2  ( messageid, type, value, compresslevel )
  3  select rownum,
  4             mod(rownum,10),
  5             mod(rownum,10000),
  6             mod(rownum,100)
  7    from sys.source$
  8  /

901445 rows created.

Then I checked the size of temp, ran the analyze and checked
temp again.  The results where:

ops$tkyte@DEV816> !ls -l /tmp/tkyte_temp.dbf
-rw-r-----   1 ora816     589824 Jan 23 07:06
/tmp/tkyte_temp.dbf

ops$tkyte@DEV816> analyze table kc_text compute statistics;

Table analyzed.

ops$tkyte@DEV816> !ls -l /tmp/tkyte_temp.dbf
-rw-r-----   1 ora816   13795328 Jan 23 07:37
/tmp/tkyte_temp.dbf

ops$tkyte@DEV816> l
  1  select round(blocks*8/1024) meg_used,
  2                      round(empty_blocks*8/1024) meg_free
  3                 from user_tables
  4*               where table_name = 'KC_TEXT'
ops$tkyte@DEV816> /

  MEG_USED   MEG_FREE
---------- ----------
        20          0

ops$tkyte@DEV816> select round(13795328/1024/1024) from dual;

ROUND(13795328/1024/1024)
-------------------------
                       13

So, in this particular case it took 13meg of TEMP to analyze 20
meg of data.  Different distributions of data would result in
different values.  Now, I dropped and recreated KC_TEXT and
populated it with very unique data:

ops$tkyte@DEV816> insert into kc_text
  2  ( messageid, type, value, compresslevel )
  3  select rownum,rownum,rownum,rownum
  4    from sys.source$
  5  /

901445 rows created.

Doing the same exact steps I find this time that:

ops$tkyte@DEV816> !ls -l /tmp/tkyte_temp.dbf
-rw-r-----   1 ora816     589824 Jan 23 07:43
/tmp/tkyte_temp.dbf

ops$tkyte@DEV816> analyze table kc_text compute statistics;

Table analyzed.

ops$tkyte@DEV816> !ls -l /tmp/tkyte_temp.dbf
-rw-r-----   1 ora816   51601408 Jan 23 08:08
/tmp/tkyte_temp.dbf

ops$tkyte@DEV816> select round(blocks*8/1024) meg_used,
  2                      round(empty_blocks*8/1024) meg_free
  3                 from user_tables
  4                where table_name = 'KC_TEXT'
  5  /

  MEG_USED   MEG_FREE
---------- ----------
        26          0

ops$tkyte@DEV816> select round(51601408/1024/1024) from dual;

ROUND(51601408/1024/1024)
-------------------------
                       49

It took 49 meg of temp space to analyze 26 meg of data.  The
needs of analyze are "about the size of the table" but will vary
dramatically depending on the distribution of data in the table
and the options used to analyze the table (computing histograms
might require more space then not and so on).

So, in your case, I would have to surmise that your data is not
extremely unique by column -- some of your columns contain low
cardinality data and that will result in reduced space needs
during the analyze.  The more data you have -- the less space
(proportionally) you will need.  I would expect the 20meg -
13meg ratio I had above to be even greater if I had 40meg of
data but retained the same cardinality on those three columns
(we need no additional space in the analysis of those columns,
we've already hit all of the values we are going to hit for
them).
Review & Followup
Rating: 5
TOM u r the man !!! April 25, 2001
Reviewer: KRISHNA DONNIPAD from Coudersport, PA,USA
It is beautifully explained.

Rating: 5
Excellent explanation!! May 07, 2001
Reviewer: Ashish from NJ USA

Rating: 5
July 31, 2001
Reviewer: Amit Joshi from CA USA
The information is way too Good !!!

Rating: 5
Space needed for analyze October 26, 2001
Reviewer: A Reader
It is an accurate and useful explanation

Rating: 4
March 21, 2002
Reviewer: VK from Singapore

January 23, 2001 Stefano -- Thanks for the question regarding "Oracle University", version 8.0.5
You Asked
Hi, the only thing I wanna know is which (or which one), of all
the Oracle Educational, are the most full of contents to become
nearly an expert on logical DB design.

Thank You.
Stefano.
and we said...
You would get that the most via the The Designer Systems
Engineer Professional Development Path
http://education.oracle.com/jobrole/designer.html
...
January 23, 2001 Jayaraman -- Thanks for the question regarding "dbms_job for more than one schema", version 8.1.6.0.0
You Asked
Hi Tom,
 We plan to split our existing single schema application into
multiple schemas. There is job process which is running which
calls a procedure that takes data from a temporary table and
then inserts into other tables every 5 seconds. As of now the
job owner,the tables and the procedure belong to the same
schema.Now if we split the schema is it still possible to run
the application with only one job with the job executing
individual procedures of each schema or should we have multiple
jobs running with each job executing the procedure for that
particular schema. Please guide us in this.
Thanks in advance,
Ashok
and we said...
You can have 1 job run the procedures owned by the other
schemas.  You will GRANT EXECUTE on the "subordinate" jobs to
the owner of the job directly (not via a role) so they can
create a procedure that can call these procedures.

You can also have 5 jobs scheduled, one in each schema.

Both are totally viable and sensible.  Which one works best for
you will ultimately be upto you.  Having one job call the other
five will make it such that they are all "dependent" on one
another (the stored procedure either runs or parts of it fail
causing the job to fail).  Having each as an independent job
would let each succeed or fail on its own terms.
January 23, 2001 konstantina -- Thanks for the question regarding "Question on an answer", version Sqlloader8.1.6.1.0
You Asked
Dear Tom ,
I sent you a question on January 17 and you answered to me in
this link:
http://osi.oracle.com/wa/ask/owa/ask_tom_pkg.display?p_dispid=1284201741376
Although it helped me very much I don't understand why  in CTL
file you wrote:
            fields terminated by '|'

when the delimiter is '||'

When the data file has a delimiter '|' the whole thing doesn't
work right

Thanks for your help again..
and we said...
Delimiters are 1 character long.  In this control file:

load data
infile *
replace
into table temp_loader_tbl
fields terminated by '|'
( project_id,
  f1 filler,      <<<-------------
  language,
  f2 filler,      <<<-------------
  sector
)
begindata
1113||EN||LAR THES ATH||
1112||FR||LAR||
1114||EN||ATH LAR||

I put in fillers to map the "empty" fields.  It is as if your
data was really:

1113|IGNORE ME|EN|IGNORE ME|LAR THES ATH|IGNORE ME|

and the IGNORE ME fields were just mapped away.

If you just have a SINGLE pipe, get rid of the fillers:

load data
infile *
replace
into table temp_loader_tbl
fields terminated by '|'
( project_id,
  language,
  sector
)
begindata
1113|EN|LAR THES ATH|
1112|FR|LAR|
1114|EN|ATH LAR|
January 23, 2001 dileep -- Thanks for the question regarding "How to use ' From clasue query ' for a data block as a datasource. ", version forms (6.0)
You Asked
I want to use 'From Clause Query' as a datasource for a data
block.
Please illustrate with code.
and we said...
Here is a support note on this subject:

PURPOSE
-------

The purpose of this note is to demonstrate the use of dynamic
From Clause Query with Forms variables.

SCOPE & APPLICATION
-------------------

This article is intended for all Developers using Oracle Forms
6.0.

Using From Clause Query dynamically with Forms variables.
---------------------------------------------------------

In Forms Builder build a block manually.  In this example we use
a block that contains 4 items.  Name the items EMPNO, ENAME, JOB
and DEPTNO.  We can call the items whatever we want, but
remember to use alias in the select statement with the same name
as the items in the block.  We will come back to this later in
the article.

Let us call BLOCK1 the block we have just created.  In the
Property Palette of BLOCK1 the following properties must be set:

   Database Data Block        =         YES
   Query Allowed              =         YES
   Query Data Source Type     =         FROM clause query
   Query Data Source Name     =         SELECT '1','2','3','4'
FROM DUAL

The select statement in Query Data Source Name is necessary,
otherwise we get a FRM-41380 error message.  It looks like Forms
is expecting to having something different from null in the
Query Data Source Name-property.  The number of items
in BLOCK1 should match the number of columns in the select
statement, i.e. if we had a block with 10 items then the select
statement should look like this:

SELECT '1',.....'10' FROM DUAL.

Next we check that the items in BLOCK1 match the properties of
the columns in the select statement we are interested in
executing.  This means that the items in the block should have
the same type and length of the data from the database.

Now we build another block.  This time a control block to
provide a dynamical variable.  We call this block BLOCK3.  In
BLOCK3 we create an item: x_deptno.

We create a When-New-Block-Instance trigger in BLOCK1.  The code
is as follows:

DECLARE
 q varchar2(1000);
BEGIN
 q := '(SELECT empno, ename, job, deptno FROM emp WHERE deptno =
'
      ||:BLOCK3.x_deptno||')';
 CLEAR_BLOCK;
 SET_BLOCK_PROPERTY('BLOCK1', QUERY_DATA_SOURCE_NAME, q);
 EXECUTE_QUERY;
END;

Note the select statement is in parenthesis.
The value of BLOCK3.x_deptno is assigned dynamically and
compared to deptno in the select statement.  Note that the
select statement in the code above could have been:
'(SELECT empno AS e_num, ename AS e_name, job AS e_pos, deptno
AS e_dno FROM emp
...........
Then the items in BLOCK1 should be named like this:
E_NUM, E_NAME, E_POS and E_DNO.
Review & Followup
Rating: 3
I have a little different case, you may have the ideal to fix it. March 23, 2002
Reviewer: A reader from Atlanta
Form6.0.8, oracle8.1.6

I am relatively new to the forms.
The automatic query refresh is not working for my application, tested on
client/server and the
Web.

In order to refreshing, I have to disconnect the form application from the
database and
reconnect it to.
I used the SQLPLUS to verify the user does not need reconnect inorder to view
the data
updated.

Settings in LOVs

automatic refresh =yes
filter before display = no
automatic display=no
automatic select =no
automatic skip =no
automatic position =no

settings in the record groups

record group fetch size =20
record group type =query
record group query =SELECT distinct(GL_CODE_COMBINATIONS.SEGMENT18) FROM
GL.GL_CODE_COMBINATIONS order by 1

I have created a small form for just test the auto-refresh, and it works by the
same settings. The problem for me is I could not find out what else other than
the settings of LOVs and the Record Groups .

January 23, 2001 Guru -- Thanks for the question regarding "Mutating Error", version 7.3
You Asked
Sir,

   If we get a Mutating Error.  How to come out of the problem
by doing some coding in the trigger.

Guru Prasad M.R.
and we said...
see
http://osi.oracle.com/~tkyte/Mutate/index.html
...
January 23, 2001 Balazs -- Thanks for the question regarding "SELECT in the select-list", version 8.1.6.1.0
You Asked
Hello Tom,

Please explain me the following:

SQL*Plus:

DEV8I:tricksyn>  select 1,(select sysdate from dual) sys_date
from dual;

        1 SYS_DATE
--------- -------------------
        1 2001.01.23 13:41:19

It's correct.

But when I want to use this one in a cursor than comes an error
message:

DEV8I:tricksyn> begin
  2  for c in (select 1,(select sysdate from dual) from dual)
loop
  3    null;
  4  end loop;
  5  end;
  6  /
for c in (select 1,(select sysdate from dual) from dual) loop
                    *

 ORA-06550: line 2, column 21: PLS-00103: Encountered the symbol
"SELECT" when expecting one of the following:     ( - + mod not
null others <an identifier>    <a double-quoted
delimited-identifier> <a bind variable> avg    count current
exists max min prior sql stddev sum variance    execute forall
time timestamp interval date    <a string literal with character
set specification>    <a number> <a single-quoted SQL string>
ORA-06550: line 2, column 47: PLS-00103: Encountered the symbol
"FROM" when expecting one of the following:     ; return
returning and or

Why doesn't work? Is this syntax wrong in PL/SQL?

Thanx for help!

Ambruzs
and we said...
It is the same issue as with the ROLLUP function.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:186812348071
for an explaination and a workaround.
January 23, 2001 john -- Thanks for the question regarding "database backups", version version 7.3.4.0.0
You Asked
i have on database system running one application and i am
currently using arcserve 6.5 to carry out a complete system
backup. the backup is carried out at 2am when there are no users
on the system.

what the process does not do is shutdown the database during the
backup process. archive logging has been set to false due to
performance issues.

are there basic scripts for carrying out scheduled stops and
starts of the database.

regards

john mcgillivary
and we said...
I've never seen performance issues with archiving -- If you have
some, put them up here and we'll try to address them.  Archiving
is critical unless you are willing to lose data at some point
in the future.  All production systems need to run in this
mode.  Archiving is a matter of having sufficient disks
available to reduce contention.  Archiving consumes virtually no
CPU.  There are no issues we cannot solve with regards to
archiving.

That aside -- You do need to shutdown that database before
backing up.  The scripts to automate startup's and shutdowns are
pretty straightforward.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:387218751430
for an example of one.
January 23, 2001 Alan -- Thanks for the question regarding "SQL UNLOADER", version Oracle 8.1.6 Enterprise Edition
You Asked
  Hi, Tom

  Thank you for your last answer to me. But I have another, what
can I do to print in a file the rows of a table like the example
below.
  Here there is some rows of the table scott.emp.

SQL> SELECT EMPNO, ENAME FROM EMP;

     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7566 JONES
      7654 MARTIN
      7698 BLAKE

    I'd like to print these rows in a 'txt' file like this

    7369SMITH
    7499ALLEN
    7521WARD
    7566JONES
    7654MARTIN
    7698BLAKE

   How can I do this ? It's an inverse process of Oracle SQL
Loader

                                          Thanks,

                                              Alan
and we said...
see
http://osi.oracle.com/~tkyte/flat/index.html
...
January 23, 2001 V Siva -- Thanks for the question regarding "User Peivileges", version 8.1.6.0.0
You Asked
Hi Tom,

I've a doubt in the user privileges related tables- What is
difference  and any relation between USER_SYS_PRIVS and
USER_ROLE_PRIVS;

In one of our database, 2 users are created. pmn15, pmn15_odc
When connected using pmn15,

SQL> select * from user_sys_privs;
USERNAME                       PRIVILEGE
       ADM
------------------------------
---------------------------------------- ---
PMN15                          ALTER SESSION
       NO
PMN15                          CREATE ANY SYNONYM
       NO
PMN15                          CREATE DATABASE LINK
       NO
PMN15                          CREATE PROCEDURE
       NO
PMN15                          CREATE PUBLIC SYNONYM
       NO
PMN15                          CREATE SEQUENCE
       NO
PMN15                          CREATE SESSION
       NO
PMN15                          CREATE TABLE
       NO
PMN15                          CREATE TRIGGER
       NO
PMN15                          CREATE VIEW
       NO

10 rows selected.

SQL>select * from user_role_privs;
no rows selected

When connect with userid pmn15_odc
SQL>select * from user_sys_privs;
USERNAME                       PRIVILEGE
       ADM
------------------------------
---------------------------------------- ---
PMN15_ODC                      UNLIMITED TABLESPACE
       NO

SQL>select * from user_role_privs;
USERNAME                       GRANTED_ROLE
ADM DEF OS_
------------------------------ ------------------------------
--- --- ---
PMN15_ODC                      CONNECT                        NO
 YES NO
PMN15_ODC                      RESOURCE                       NO
 YES NO

1. Why no rows selected from user_role_privs in the schema pmn15

But CREATE TAABLE privilege is there in USER_SYS_PRIVS table,
and I can create tables. And Why CONNECT and RESOURCE are not
shon in user_role_privs. As per my knowledge, these to are
required for connecting and creating any table?

2. In the schema(user) pmn15_odc, there is no privilege CREATE
TABLE in user_sys_privs, but still I can able to create tables.
How?
and we said...
1) there are no rows in the user_role_privs table becuase that
user has no roles assigned to them and neither does "PUBLIC".

That user was granted CREATE TABLE directly, not view a role.
That user was created using commands like:

create user pmn15 identified by password;
grant create session to pmn15;
grant create table to pmn15;
....

If you create a user and grant them CREATE SESSION -- they can
log in.  CONNECT is simply a role that, among other privileges,
has CREATE SESSION granted to it.  If you grant that user CREATE
TABLE and give them some quotas on tablespaces -- they can
create a table.  RESOURCE is simply a role that, among many
other privileges, has CREATE TABLE granted to it.

You never need use connect, resource, or dba.  They are just
"predefined" roles.  PMN15 was created with the concept of
"least privileges" in mind.  This is very typical in security
minded systems where you want to keep control over who has
access to what.  In a security minded system, one would not use
connect, resource and dba.  They would either create their own
custom roles with the bare minimal set of privileges needed OR
they would use direct grants of the bare essentials (as in the
case of PMN15).

2) pmn15_odc has the CREATE TABLE privilege from the CONNECT
role.  From SQL.BSQ (the bootstrap to create the data
dictionary) for 8.1.6:

create role connect
/
grant create session,alter session,create synonym,create view,
  create database link,create table,create cluster,create
sequence to connect
/
create role resource
/
grant create table,create cluster,create sequence,create
trigger,
 create procedure, create type, create indextype, create
operator
 to resource
/

thats why some people hesitate to use connect and resource --
the convey some pretty powerful privs.  Much better to grant
JUST exactly the privs you need.
January 23, 2001 sam -- Thanks for the question regarding "idle session", version 8.1.6
You Asked
Hi Tom:
    When user process died unexpectly, chances are there will be an idle session
on the server side left.
    If no resource limit or DCD is being enable on server side, how long will
this idle session last on server side?
    Which background process is responsible for cleaning it? What is the time
interval for this process to wake up and do its job?
    Is this configurable in the initSID.ora?

Thanks

Sam Hou
and we said...
If you are not using DCD (dead client detection) and this process is waiting for
the client to write to IT (eg: this process will not attempt to write to the
client, its waiting for the client to tell it to do something) -- this process
could stay there forever.

TCP/IP, when a socket shutsdown on one end, does not always tell the guy on the
other end that the person they were talking to no longer exists.

There is nothing for us to "cleanup" -- we are not aware there is a problem.  It
just looks like the client is taking their time in telling us to do something.
There is no way for us to tell the connection is dead (tcp won't tell us) short
of trying to WRITE on that connection.  Thats where DCD comes into play.

DCD attempts to write on the socket every now and again to see if the client is
still there.  Sort of like a "ping".  DCD is the way to solve this issue.  That
is the "init.ora" setting you need to make (although it'll be in the networking
config files, not the database).
January 23, 2001 murali -- Thanks for the question regarding "fine grained user access control", version 8.1.6
You Asked
hi,
i am planning to implement security on the database using fine
grained user access control.
i want to know if creating a context is required...or can we
implement this with security policies alone.
i have 5 users(roles) and each role will have many users.
the roles are ....guest(select on all
tables),customer,developer,superuser(write on all table),manager

can you please send me some examples which i can use in this
sort of senarios.
and we said...
See
http://osi.oracle.com/~tkyte/article2/index.html
you do not need to us application contexts.  They are tools that
might make it easier in many cases.  They are by no means a
requirement.
January 23, 2001 Gladiola -- Thanks for the question regarding "pl/sql table", version 6
You Asked
Hi Tom!
I was looking to find some details for pl/sql table.
I will use a block based on a procedure.
my question is:
Is the pl/sql private between session?
What happend with the table after I close the session?
thanks
and we said...
PL/SQL tables are private to a session as all data variables
are.

PL/SQL is run in the database in much the same was code is run
on unix.  The "text" (object code) is shared - just one copy is
out there.  The "data" is private.  Each process (session) has
its own data segement.  One process (session) cannot see the
data of another.

After you close a session, the contents of the plsql table is
gone.
January 24, 2001 John -- Thanks for the question regarding "Making a URL call in PL/SQL", version 8.1.7
You Asked
Tom,

Is it possible to construct a PL/SQL stored procedure that makes
a URL call.  Then have the resulting HTML displayed.

Something like...
procedure helloworld is

begin
htp.htmlOpen;
htp.BodyOpen;

htp.p('This would be cool, if it worked...');

owa_util.redirect_url('helloworld.html');

htp.BodyClose;
htp.htmlClose;
end;

Thanks,

John Perkins
and we said...
Yes, there is a builtin UTL_HTTP package for doing this.

Lets say the text of the page you are calling is going to be
"small".  You can:

...
begin
htp.htmlOpen;
htp.BodyOpen;

htp.p('This would be cool, if it worked...');

htp.p(
utl_http.request('http;//host:port/path/helloworld.html')
     );

htp.BodyClose;
htp.htmlClose;
end;

If the page is large, you'll need to use
utl_http.request_pieces.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/utl_http.htm#998100
for details on utl_http.
January 24, 2001 Guru -- Thanks for the question regarding "Several Doubts", version 7.3
You Asked
Dear Tom,

*  I am displaying a file by using dbms_output.  The file is
being read by using utl_file.  After displaying some characters
it will tell buffer overflow.  I know that i can give the buffer
size for dbms_output by using dbms_output.enable.  But i want to
know whether any way we can clear buffer programatically to get
rid of the problem.

*  Can i invoke SQL Loader from forms.

*  Actually what happens when we issue a POST command in forms.

Thanking You,
Guru Prasad M.R.
and we said...
You cannot flush the dbms_output buffer without losing the
entire contents (that is, all of the work you did would be gone,
never displayed).

When you call PLSQL, the routine runs from start to finish.  The
PLSQL cannot do any screen IO (it is running on the server).
SQLPlus is what does the screen IO.  SQLPlus must wait until the
PLSQL routine completes before requesting the contents of the
dbms_output buffer and printing it.  This buffer has a 1,000,000
character limit

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1011431134399
for an explaination of how dbms_output physically buffers
your data (e.g. you get somewhat less then 1000000 bytes of your
data buffered and depending on how big your lines are -- maybe
much less).  It also has a link to a page that shows ways to
implement your OWN dbms_output that does not have this limit.

You can invoke SQLLDR from forms via the HOST() built in.  You
can run any program you can start from the command line in this
fashion.

When you POST, forms takes all of the changes you have made in
the client and does them in the database -- it does not yet
commit them.  So, if you updated a record, deleted a record, and
inserted a record via the form into table T and did not POST
them data -- and then ran a stored procedure from your form that
queried T, that stored procedure would not see these changes
(forms is caching them).  If you POST before running the
procedure -- your procedure running in that session will see the
changes HOWEVER no other session will (because you posted them
but did not yet commit them).
January 24, 2001 Sue -- Thanks for the question regarding "Export utility -- what is its name on a PC", version 7.3.4 Client & Server for Windows Nt & 95
You Asked
I am trying to use the Oracle export utility. After reading the
Oracle DBA Handbook I thought I knew how to do so, however, in
Oracle entering exp at the SQL prompt results in an error, it
does not recognise the command. I then checked further and
thought that this utility should be run from the DOS prompt.
However, again the command exp was not recognised. I am working
on a client PC and have not got direct access to the server the
database runs on. Could this be part of the problem? I can gain
access to the Server if required.

Thanks

Sue Cornick
and we said...
Under windows -- until version 8.1, the utilities have the
version appended onto them.

In 7.3, it is most likely:

C:\> exp73  ......

goto your $ORACLE_HOME\bin directory and do a "dir exp*.exe" --
that should show you the correct name.  Note: some client
installs do not install tools like exp, imp, sqlldr and so on.
There is a chance export does not exist on your machine.

EXP is a command line program and will not work from SQLPlus (as
you have discovered)
January 24, 2001 suresh -- Thanks for the question regarding "To execute operating system command", version oracle 8.1.6
You Asked
Hai Tom
 How to  execute UNIX operating system command
from PL/SQL using Java Stored Procedure in PL/SQL.

Thanks in Advance
Suresh
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:952229840241
..
January 24, 2001 ashutosh -- Thanks for the question regarding "using sql loader ", version 8.0.4
You Asked
hi tom
   can we insert data simultaneously into two tables based on a
condition using sql loader. if yes then how

thanx
and we said...
Yes, you have to use POSTITIONAL data and have multiple into
statements.  For example:

LOAD DATA
INFILE *

INTO TABLE T1
replace
(
  a     position(1:1),
  b     position(2:2)
)

INTO TABLE T2
replace
(
  c    position(2:5),
  d    position(1:10)
)

BEGINDATA
abcdefghijklmnopqrstuvwxyz

If you need to do delimited data and you are using the
conventional path loader, you can use the delimited package (or
some variation thereof) I have at
http://osi.oracle.com/~tkyte/SkipCols/index.html
it gives you delimited access when using POSTIONed data.
January 24, 2001 Mike -- Thanks for the question regarding "Package DBMS_SYS_SQL", version 8.0.5
You Asked
Dear Tom,

pls tell me where can I read about DBMS_SYS_SQL package. It's
pkg body and specification are wrapped and no any mention about
it in documentation shipped with installation.

Thank you.
and we said...
It is an undocumented package used internally by Oracle
services.  It is called by DBMS_SQL.  It is specifically used by
replication and other products such as WebDB.  It is not
intended for use outside of Oracle.

It works the same as DBMS_SQL would however it has an additional
entry point "parse as user" that allows you to parse a sql
statement as any other user in the database.  That statement
will be executed with their privileges.  That makes this package
an EXTREMELY powerful package.  Execute on this package should
be strictly controlled as the accounts that can execute this can
do virtually anything they want.
January 24, 2001 yajuvendra -- Thanks for the question regarding "import/export PROBLEM ", version oracle 8.1.7
You Asked
 i have installed oracle 8.1.7. and i have exported a table
having object data type and i am tring to import it in different
schema but it is giving me error ->
"IMP - 00017:following statement failed with oracle error 2304:
"CREATE TYPE TEMP_TYPE TIMESTEMP '2001-01-24:12:54:38' OID
'C07F6E6CF1E' "511D488B80050BA897E09" AS OBJECT (TP1
VARCHAR2(30),TP2 VARCHAR2(30))"
IMP 00003:ORACLE ERROR 2304 ENCOUNTERED
ORA-02304:INVALID OBJECT IDENTIFIER LITERAL
IMP 00063:WARNING: SKIPPING TABLE "TEMPUSER"."FIRST_TABLE"
BECAUSE OBJECT TYPE "TEMPUSER"."TEMP_TYPE" CAN NOT BE CREATED OR
HAS DIFFERENT IDENTIFIER
and we said...
That will not work -- the OID already exists in that database.
In order to import that data, we need to use the SAME exact type
-- not a "similar" type, the same type.

You should not install the same type more then once in a
database for this and OTHER reasons.  It would be a good
practice to create a schema, say called TYPES, and install all
types into that schema.  This ensures a type is installed ONCE
per database instance -- never once per schema.

In this fashion, all schemas will use the same consistent type.
They will be able to do things like:

insert into myobjectTable select * from
someone_elses.objectTable;

if we used "similar" types -- each in our own schema -- that
would not be possible.

Think about what would happen if everyone had their own "NUMBER"
type -- it would be a mess.  The same thing is true for user
defined types.

If you had a user TYPES with the type in it and you had a user
"A" with a table "T" of that type and a user "B" with a table
(or not -- the table doesn't have to exist) you will be able to:

1) exp owner=a
2) imp fromuser=a touser=b ignore=y

that'll create (or not) the table based on the common type and
fill it up.

the same would be true of CROSS DATABASE issues.  You would
install the types into 1 database and then export them and
import them into the other databases.  In this fashion, they all
get created with the same OID and you can import/export back and
forth between the instances.
Review & Followup
Rating: 5
Very good and detailed review October 10, 2003
Reviewer: onsh76 from Canada
Tom,
It would be also great if Oracle include your suggestion in the Oracle
documentation.

January 24, 2001 Massimo -- Thanks for the question regarding "Enabling SSL client server connection with Oracle 8.0.5", version 8.0.5
You Asked
Dear sir, I'd like to connect a client and an Oracle 8.05 server
with SSL and NET8. What I need to install and configure to goal
that ? I read something on Oracle document but I can't
understand if I need third-party vendor software or all stuff is
included in Oracle Advenced Networking Option or in Oracle
Secure Service.

Coult'd you send me some samples ?

Thank you a lot.

P.S. I apologize for my bad English writing !!!
and we said...
SSL was added to ASO (Advanced Security Option) in Oracle8i.  It
was not available in Oracle8.0.

You would need to be using Net8 version 8.1 in order to get SSL
support.
January 24, 2001 Punit -- Thanks for the question regarding "size of tables,tablespaces", version 8.0.5
You Asked
How can we calculate the accurate size (in bytes) of
tables,tablespaces
and we said...
For tables and such, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
it'll show you allocated blocks, blocks with free space on them,
blocks that have never been used and so on for a segment.

for space used by tablespace, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:285415955510
it'll give you a report of that.
January 24, 2001 Manmohan -- Thanks for the question regarding "READING DATA from file", version oracle8.1.5.0.0
You Asked
Hi Tom,

 For reading data from a file we have 3 ways.first we can use
pro*C.or second we can use sqlloader to upload the data to the
corresponding table. and third we can use oracle provided
package UTL_FILE.
Please clarify when to use which one.Is there any restriction on
using the UTL_FILE.And if not then pl tell can we specify more
than one path in the pkg. as the target of the file
Thanks and regards
Manmohan Singh
and we said...
UTL_FILE, in Oracle8.0.5 and up, has a limit of 32k / line of
text that may be read or written and restricts you to using TEXT
files only (no binary data).

Neither pro*c nor sqlldr have these limits.

You will find that SQLLDR, if it can load the data (if the data
is in a format it can understand) will be the path of least
resistance.  You will write the least amount of code and get
excellent performance from it.  If you can use SQLLDR, use it.

Pro*C will generally be faster then PL/SQL and depending on how
well written it it -- may be faster or slower then SQLLDR.

UTL_FILE is appropriate for small to medium sized files.
January 25, 2001 Subhakar -- Thanks for the question regarding "Roles during Export/Import", version 8.1.7
You Asked
Hi Tom,

1. How to find out who has assigned a privilege to a particular
user?
Like for instance, I exported a user "X" from database1(As
SYSTEM) and imported him into database2.
I found that not all roles were imported (say, 'SELECT ANY
TABLE'). User X has this privilege in database1.
So, how do I find out who has given him this privilege in
database 1? and if this privilege was given by 'SYS'
to this user and if I do an export/import as 'SYSTEM' will this
privilege be exported/imported?

2)  I have read the following quote on a web site
(
http://sso.mont.disa.mil/Product%20Support/Oracle/Helpful_Tips/helpful_tips.htm
B.  Resizing and autoextending datafiles

Information:
We always need to add space to tablespaces over time, and we
usually do it by resizing the datafile, or by setting
the datafile to auotoextend on its own. If we resize a datafile
or set it to Autoextend itself, we may run into problems if
the instance has multiple database writers(DBWRs). So, before
you advise someone to just resize a datafile, make
sure they aren't running multiple DBWRs. If they are, then they
need to add a separate datafile in order to increase the
tablespace size.

Can U explain me why this is true?

Thankx,
Subhakar
and we said...
1) privileges are not tracked by WHO gave them to you.

When you export using OWNER=, that gets the objects owned by
that user.  It does ntt export the "definition" of that user.
It only exports things "owned" by that user.

If you want to "clone" the privileges of user X from one db to
another you can:

tkyte@DEV2.THINK.COM> select 'grant ' || privilege || ' to ' ||
grantee ||
  2  decode( admin_option, 'YES', ' with admin option;', ';' )
  3  from dba_sys_privs
  4  where grantee = 'TKYTE';

'GRANT'||PRIVILEGE||'TO'||GRANTEE||DECODE(ADMIN_OPTION,'YES','WIT
HADMINOPTION;',';')
-----------------------------------------------------------------
----------------------------------
grant UNLIMITED TABLESPACE to TKYTE;

  1  select 'grant ' || granted_role || ' to ' || grantee ||
  2  decode( admin_option, 'YES', ' with admin option;', ';' )
  3  from dba_role_privs
  4* where grantee = 'TKYTE'
tkyte@DEV2.THINK.COM> /

'GRANT'||GRANTED_ROLE||'TO'||GRANTEE||DECODE(ADMIN_OPTION,'YES','
WITHADMINOPTION;',';')
-----------------------------------------------------------------
------------------------
grant DBA to TKYTE;

tkyte@DEV2.THINK.COM> select 'grant ' || privilege || ' on ' ||
owner || '.' || table_name
  2  || ' to ' || grantee || decode( grantable, 'YES', ' with
grant option;', ';' )
  3  from dba_tab_privs where grantee = 'TKYTE';

'GRANT'||PRIVILEGE||'ON'||OWNER||'.'||TABLE_NAME||'TO'||GRANTEE||
DECODE(GRANTABLE,'YES','WITHGRANTOP
-----------------------------------------------------------------
-----------------------------------
grant READ on SYS.MY_FILES to TKYTE with grant option;

and spool the output of those three queries to a file.  That'll
carry the grants for that user over to the other instance.

2) there was a bug in an earlier release of Oracle.  It was
fixed in 7.3.3.5 and is no longer an issue.
Review & Followup
Rating: 5
exp/imp October 16, 2003
Reviewer: kukuluku from dallas, texas
Great!

So for importing a database excluding sys/system (data dictionary), if I just
run these scripts (for grant) and then import all schemas who own objects
(dba_objects) in the original database to target database, does this cover all
(grant should create new user too, right)?

January 25, 2001 orna -- Thanks for the question regarding "The "Query" option in the export command", version 8.1.6
You Asked
Hi Tom,

My question is :

What exactly happens when exporting certain rows from a table
using the "Query" option ?

Does the export directly export only part of the table ? or does
it create a replica of the whole table first ?

Can this option replace partitioning where periodic exports are
done on a certain partiotion as backup prir to dropping ?

e.g - if the "Calls" table is partitioned by "call date" (
partition for each month ) where every once in a while we export
, let's say the "December" partition , and then drop it -
can the partial export be as efficient ?

Thanks for your time
Orna
and we said...
It does it by modifying the query it uses to select the data.
It does not copy the data and then export, it just exports that
data by adding your where clause to a "select * from T". (where
T is your table).

It could be used to export a slice of a table prior to deleting
that data from the table.  However, if you had the data
partitioned by call_date and december was in a single partition,
it would be more efficient to export the PARTITION (via a full
scan) rather then exporting via a predicate (unless partition
elimination could be used with your where clause).

if the table was partitioned, i would probably still export by
partition.
January 25, 2001 OP -- Thanks for the question regarding "Question on Direct path !", version 8.1.6
You Asked
Hi Tom,

I have 1 more Quest.Kindly answer this also.

one week ago I had gone for the Interview,there
was a question in the written test as follows

When DBA performs a DIRECT PATH option and the
Database is in Nonarchive Mode in that case
what happens ?

1)Redo log is generated for the rollback segment
2) Redo generates for data dictionary
3) is generated for data loaded
4) is generated but not archived.
5) None

Thanks and Regards
OP Lalwani
and we said...
2 is PROBABLY the correct answer.

I could argue that 1, 2 and 4 are true.

If 2 is true -- that implies that some redo is generated and
since the database is not in archivelog mode it by definition
will not be archived so if 2 is true, 4 is true by association.

And if 2 is true -- then rollback for the data dictionary
changes are made and hence there will be redo log entries made
for the rollback.  Hence 1 is also true by association with 2.

They probably wanted you to say 2.  changes to the data
dictionary are always protected by redo and rollback in the
event of an instance failure.
January 26, 2001 Jonathan -- Thanks for the question regarding "suspending and resuming queries?", version 8.1.5
You Asked
I'd like to know if it is possible to suspend and then resume a
query without losing the work that've been done.

As I'm trying to do that within a soft, i'd like to know how I
can identify the target query? I mean : is there something like
a query ID?

I've read your answer concerning my log miner problem ( i wanted
to know if a query've been commited or not)

The problem is that your solution would be good if i wanted to
read the log that happened the day before but my goal is to get
the queries that've just been executed so they may not have been
commited or rollbacked.
In fact there are three states:
 * commited
 * rollbacked
 * not commited or rollbacked again

So if you got any idea...
and we said...
Oracle uses CURSORS for queries.  The CURSOR is the handle to
the result set.  You OPEN a cursor and then fetch from it.  The
query is easy to "suspend" and "resume" since you control when
and how many rows you get from it.  Cursors are naturally
"suspendable" by design.

Log miner is designed to analyze archived and inactive online
redo logs.  It is not really designed to analyze what is
happening right now, this second.  In fact, you will run into
strange issues occasionally analyzing current, online redo logs.

If a query has neither been committed nor rolled back, you can
still see the "rollback" of the failed statements.  Consider
this:

tkyte@TKYTE816> alter system switch logfile;
System altered.

tkyte@TKYTE816> insert into emp(empno) values ( 1111 );
1 row created.

tkyte@TKYTE816> insert into emp(empno) values ( 2222 );
1 row created.

tkyte@TKYTE816> insert into emp(empno) values ( 1111 );
insert into emp(empno) values ( 1111 )
*
ERROR at line 1:
ORA-00001: unique constraint (TKYTE.EMP_PK) violated

tkyte@TKYTE816> alter system switch logfile;

Now, lets see what that archived redo log I just created has in
it (i'm the only user on this system so the contents of that log
will be my session only for ease of seeing whats there).  After
loading that log up, I see:

tkyte@TKYTE816> select scn, sql_redo, sql_undo, rollback
  2    from v$logmnr_contents
  3  /

       SCN SQL_REDO             SQL_UNDO               ROLLBACK
---------- -------------------- -------------------- ----------
    885926 set transaction read                               0
           write;

    885926 insert into          delete from                   0
           TKYTE.EMP(EMPNO)     TKYTE.EMP where
           values (1111);       EMPNO = 1111 and
                                ROWID =
                                'AAAFahAADAAAAHzAAP'
                                ;

    885926                                                    0
    885926                                                    0
    885926 insert into          delete from                   0
           TKYTE.EMP(EMPNO)     TKYTE.EMP where
           values (2222);       EMPNO = 2222 and
                                ROWID =
                                'AAAFahAADAAAAHzAAO'
                                ;

    885926                                                    0
    885926 insert into          delete from                   0
           TKYTE.EMP(EMPNO)     TKYTE.EMP where
           values (1111);       EMPNO = 1111 and
                                ROWID =
                                'AAAFahAADAAAAHzAAQ'
                                ;

    885926 delete from                                        1
           TKYTE.EMP where
           ROWID =
           'AAAFahAADAAAAHzAAQ'

So, we know the second insert of 1111 failed.  We see in
logminer the attempt to insert it and then RIGHT AFTER it we see
the undoing of that (the rollback) and the ROLLBACK column is
once again flagged showing it rolled back that statement.

So, even when the query is rolled back internally due to a
constraint violation as the above is -- we can "see it" in log
miner.  This was of a query that was just run and not yet
committed which I think satisfies your situation.
January 26, 2001 Betty -- Thanks for the question regarding "Standby Database", version 8.1.6
You Asked
Is Standby Database available in both 8.1.6 Standard and
Enterprise Editions?  Will this be the same for 8.1.7?  My
company, which sell Clinical Software, is thinking of using this
as a Backup/Recovery Strategy and wants to make sure that this
will be compatiable on different Oracle editions and versions.

Thanks,
Betty
and we said...
In the "getting to know Oracle8i" guide, there is a chapter on
features and functions available by release( EE, SE and PE
versions -- enterprise, standard, personal).

If you look at:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76962/ch4.htm#74667
you'll see that automated standby and the ability to open a
standby in readonly mode is a feature of ENTERPRISE and PERSONAL
but not STANDARD edition.

That does not mean you cannot do a standby on standard edition
-- it means that the AUTOMATED standby capabilities are not
enabled and you will not be able to open the standby database in
read only mode for reporting.  You would have to use the steps
one one have used in 7.3 for performing a standby database
(before automated standby).  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:199412348073
for a discussion of what this entails.
January 26, 2001 B -- Thanks for the question regarding "SQLPLUS", version 3.3
You Asked
I would like to retrieve table_names from all_tables where table
name like 'ADD_'. I tried using the following but my query is
returning ADDRESS and ADD_CODES.
 select distinct table_name from all_tables
 where table_name like 'ADD_%'

I also tried using the escape sequence

select distinct table_name from all_tables
where table_name like 'ADD\_%'
and we said...
select distinct table_name
  from all_tables
 where table_name like 'ADD\_%' ESCAPE '\'
/

You have to tell us what character you would like to use as an
escape. \ is commonly used but any character would actually
work.
Review & Followup
Rating: 2
May 18, 2001
Reviewer: Daniel Faensen from Germany

Rating: 4
January 23, 2003
Reviewer: Kunjan Mehta from Mumbai, India
This is very useful, esp. while dealing with massive applications while
developing as well as maintaining; where u usually divide it in many modules,
and most likely going to prefix yr tables with a short module name with an
underscore or going to suffix yr object name based on any criteria.

January 26, 2001 john -- Thanks for the question regarding "dictionnary construction for log miner", version 8.1.5
You Asked
Is it possible to build the dictionnary from only one schema of
the database?
I've got a database with many schemas and I like to examine one
particulary.
and we said...
No, you export the entire data dictionary (or not).  There is no
option to extract just "a schema".

On a typical system, I find the exported data dictionary to be
about 4.5-10 meg in size and takes a couple of seconds (say 30
seconds on my laptop with 22k objects in all objects).
January 26, 2001 OP -- Thanks for the question regarding "Question on Dynamic Extents !", version 8.1.6
You Asked
Hi Tom,

How are you doing !

My Ques is

which of the follwing statements will cause the
dynamic extents to be allocated

create,insert,update,delete,truncate and commit.

Thanks and Regards
OP Lalwani
and we said...
by dynamic extents - I assume you mean "extent allocation"?  I
am not familar with the term dynamic extents.

create, insert, update can cause extents to be allocated in your
data segment (eg: your table could extend to add more space, an
index on your table could extend to add more space).

create, insert, update, delete could cause extents to be
allocated to some rollback segment and/or temporary segment.

truncate typically gives BACK extents.

commit doesn't touch extents.
January 26, 2001 -- Thanks for the question regarding "XML Parser and V$ Files", version 8.1.6
You Asked
Hi Tom

1.
We are planning to use xml to send and receive documents.  Do I
need to install something on Oracle side for the xml parser to
work or the Typical installation of Enterprise Edition will be
suffice.

2.

Is the sharable_mem column in v$sqlarea is stored in bytes or
kb.
Would also like to know if all the V$ tables store the memory or
buffer information in Bytes or KB, does oracle follow any
standard way or representing this.

Thanks
and we said...
1) you need to download the parser you would like from
http://technet.oracle.com/tech/xml/
and load it into the database (or use on a middle tier).

2) the memory is in bytes unless otherwise noted in the name of
the column (eg: _blocks would indicate it is the number of
blocks).
January 26, 2001 Greg -- Thanks for the question regarding "Date Manipulation When Testing Home Grown Applications", version 8.1.6
You Asked
Assuming my applications are getting their 'current date' from
sysdate, then doing internal processing, I have a testing
question.  I work for a financial institution that requires us
to test ahead a quarter or a year, several times a year (similar
to Y2K testing).  I am looking for an easy way to change the
date for my applications without affecting other applications
that are residing on the same app. server.  I amy also have
several instances of Oracle, and do not want to change the dates
of those instances. Setting the date at the server is out of the
question, bucause of too many other dependencies.

We have thought about using an external date driver to read into
the application, but that means more overhead.  With the
mainframe testing, we use a tool by Viasoft that overrides the
'current_date' for each CICS region or at the batch job level.
We are looking for such a solution at the client/server level.
Any suggestions?
and we said...
Short of using a function

create or replace function my_sysdate return date
as
begin
   return sysdate;
end;

instead of SYSDATE, I do not see any alternative other then at
the instance level (eg: you can set a fixed_date init.ora
parameter/alter system for the INSTANCE so that sysdate will be
fixed at some point in time for that instance) or at the OS
level (which would affect all instances on that machine).

So, if you have your own INSTANCE to test in, using FIXED_DATE
might be a viable alternative.

sys@TKYTE816> select sysdate from dual;

SYSDATE
---------
26-JAN-01

sys@TKYTE816> alter system set fixed_date = '26-jan-02';

System altered.

sys@TKYTE816> select sysdate from dual;

SYSDATE
---------
26-JAN-02
Review & Followup
Rating: 5
Thanks a ton to TOM November 19, 2001
Reviewer: Sankar from India
Now a days, instead of searching the ORACLE docs, first i am looking at this
site for re-solution of any issues/clarifications.

In worst case, i am getting the solution for any problem in not more than 5
minutes

Kudos to Tom,

January 26, 2001 -- Thanks for the question regarding "Migration from DB2 to Oracle", version 8.1.5
You Asked
Hi, Tom.

Can you recommend an Oracle tool to migrate from DB2 to Oracle
8i
I know that Oracle Migration Workbench cannot do it, but I am
sure, that it is not a first time, when someone should migrate
from DB2 to Oracle.

Can you help me?

Oleg
and we said...
Check out
http://technet.oracle.com/tech/migration/toolkits/

and click on DB2
....
January 26, 2001 Jonathan -- Thanks for the question regarding "Log miner again...", version 8.1.5
You Asked
I still need some complementary informations.

* If I got different schems in my database for example
  user1 and user2.
  In each schems I've got a table called 'product'

  Is there a way to know which one has been modified?

* When I query the field timestamp from v$logmnr_contents,I've
  got athis format dd/mm/yy is there a way to get it in this
  format: dd/mm/yy hh/mm/ss?
and we said...
1) yes, in V$LOGMNR_CONTENTS there is:

 SEG_OWNER
 SEG_NAME
 SEG_TYPE

that'll be the owner, name, and type of object modified.

2) either:

alter session set nls_date_format = 'dd/mm/yy hh/mi/ss'

(mi not MM!!) or

select to_char(timestamp,'dd/mmy/yy hh/mi/ss'), ....
  from v$logmnr_contents

timestamp is just an oracle date -- your date format dictates
how it is displayed.
January 26, 2001 Kathy -- Thanks for the question regarding "Invokers Rights Example", version 8.1.6
You Asked
Hi

I was at the NATCAP Jan meeting.  Really Enjoyed the session.
You mentioned that you have a procedure using Invokers Rights to
display the results of a query going down the page, Was
wondering if you were willing to share the code.

Thanks
Enjoyed putting a face to the Name, Etc
and we said...
Thanks for the feedback -- it was sort of fun to do it.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1035431863958
I have the Oracle8i specific one there (authid current_user) as
well as an Oracle8.0 sqlplus script that works... Nothing for
7.x however since dbms_sql did not have a describe API call back
then...
January 26, 2001 wallacel -- Thanks for the question regarding "concurrent user", version 8.1.6
You Asked
Tom:

our manager asking me how many concurrent transaction our
server can handle. i run a typical transaction 1000 times, it
takes around 40 seconds, does that mean our server can
handle roughly 25 concurrent transaction/second?
if it is not true, how should i estimate it?
and we said...
Well, it depends.

did you do something like:

for i in 1 .. 1000 loop
  do transaction
end loop

That is sort of "perfect world".  You have no contention for
resources -- no concurrency.

It would be infinitely more interesting to fire off 50 sessions
that each do

for i in 1 .. 20 loop
  do transaction
end loop

and see how long the min/max and avg response time is.  There
will be a HUGE difference.  Concurrency and its side effects
(contention for limited resources) will choke the system back
somewhat.  If only we could do 1 thing at a time ;)

What you should really do is test

o 1 user at a time
o 2 users at a time
o 10 users at a time
o x users at a time using some multiple until you get to your
  desired concurrent user count.

You'll find out how many concurrent users you can support before
performance starts to degrade.

You cannot estimate these things (well you can but it takes as
long to do the math as it would to run it and measure it)
accurately.  Benchmarking is the only true way to know for sure.
 Single user testing shows nothing.... (if that is what you did).
January 27, 2001 wallacel -- Thanks for the question regarding "Date and char", version 8.1.6
You Asked
Tom:

when i use preparestatement, i have problem regarding
Date and char.

1.
when i
pstmt.getDate(1), and then set it back,
time is lost, and date is still there.

2.
one of table's column is sex char(1), which have value 'm'
or 'f', i don't know which method should i use when query or
update. what i did is  change the type to varchar2(1)
and then use setString() and getString.
but i don't like it that way, is there any better way to do
that?

************************************************
************************************************
for sex column of user table , it is char(1);
if the parameter passed is "F" or "M", everything is ok,
but if the parameter passed is 'F' or 'M'
then i can't use
pstmt.setString(1,'F');
it will complain that
method setString(int,char) not found in interfact
java.sql.PreparedStatement.
and we said...
getDate just gets the date. Time is not part of a date.

Anyway -- here is what *I* do.  There are other ways, this is
just the way *I* do it.

I have methods:

  static public java.util.Date strToDate(String s)
  {
    java.util.Date   d   = null;
    if (s != null && s.length() == 19 )
    {
      d = new java.util.Date
                  (Integer.parseInt(s.substring(0,4)) - 1900,
                   Integer.parseInt(s.substring(5,7)) - 1,
                   Integer.parseInt(s.substring(8,10)),
                   Integer.parseInt(s.substring(11,13)),
                   Integer.parseInt(s.substring(14,16)),
                   Integer.parseInt(s.substring(17,19)));
    }
    return d;
  }

  static public String dateStr( java.util.Date x )
  {
    if ( x != null )
      return (x.getYear()+1900) + "/" + (x.getMonth()+1) +
              "/" + x.getDate() + " " +
             x.getHours() + ":" + x.getMinutes() + ":" +
             x.getSeconds();
    else
      return null;
  }

When I select a date, I always

to_char( Date_field,'YYYY/MM/DD HH24:MI:SS')

and on insert I always:

to_date(:5,'yyyy/mm/dd hh24:mi:ss')

I use strDate to convert to java date and dateStr to go back in.
 No ambiguity, no confusion.  It just works.

2) You need to conver the char into a String.  JDBC does not
support the char java datatype.  The path of least resistance
might be to add the char to an empty string -- that'll "cast" it
for you.  for example:

    ps.setString( 2, ""+'x' );
January 27, 2001 Marcel -- Thanks for the question regarding "Problems with insert and cursor", version 8i
You Asked
Hi, Tom...

I've created a stored procedure and declared a cursor. This
cursor has a select query (using the CONNECT BY clause) assigned
to.
Inside the BEGIN I fetch each line of the cursor and insert it
into another table. The problem is that when I get the lines of
that new table ("SELECT * FROM..."), they aren't in the same
order as they were in the cursor. Why does it happen?
I'm using dynamic SQL because in run-time I don't have the new
table's name (it's a parameter of the stored procedure).

The stored procedure looks like that:
CREATE OR REPLACE PROCEDURE SP_EVB_INS_ORDERED_PERSON (P_CD_CPY
NUMBER, P_NM_TAB IN VARCHAR2) IS

    /* P_NA_TAB IS THE TABLE'S NAME */

    DEL_STMT VARCHAR(200);
    INS_STMT VARCHAR(200);

    CURSOR C1 IS
    SELECT  /*+ INDEX(PERSON PERSON_NAME_IDX ) */
          CD_PER, LPAD(' ',2*(LEVEL-1))||NM_ACC AS NM_ACC,
ID_ACC_TYP, CD_OWN_ACC
    FROM ACCOUNT
    WHERE CD_CPY+0 = P_CD_CPY
        AND ID_ACC_TYP = 'CUS'
    CONNECT BY PRIOR CD_ACC = CD_OWN_ACC
        AND CD_CPY+0 = P_CD_CPY

BEGIN
    /* HERE I DELETE ALL THE LINES OF THE TABLE */
    DEL_STMT := 'DELETE ' || P_NM_TAB;
    EXECUTE IMMEDIATE DEL_STMT;

    /* HERE I INSERT THE LINES OF THE CURSOR INTO THE TABLE */
    FOR X IN C1 LOOP
        IF X.CD_OWN_ACC IS NULL THEN
           INS_STMT :=    'INSERT INTO ' || P_NM_TAB || ' VALUES
( ' || X.CD_ACC || ', ''' || X.NM_ACC || ''', ''' ||
X.ID_ACC_TYP || ''', NULL)';
    ELSE
            INS_STMT :=    'INSERT INTO ' || P_NM_TAB || '
VALUES ( ' || X.CD_ACC || ', ''' || X.NM_ACC || ''', ''' ||
X.ID_ACC_TYP || ''', ' || X.CD_OWN_ACC || ')';
    END IF;
    EXECUTE IMMEDIATE INS_STMT;
    END LOOP;
END;

The table ACCOUNT (that appears in the SELECT query of the
cursor) has the following description:
Name                            Null?    Type
------------------------------- -------- ----
CD_CPY                          NOT NULL NUMBER(8)
CD_ACC                          NOT NULL NUMBER(5)
CD_OWN_ACC                               NUMBER(5)
NM_ACC                          NOT NULL VARCHAR2(128)
ID_ACC_TYP                      NOT NULL CHAR(3)
VL_BAL                                   NUMBER(18,2)
ID_ACC_NAT                               CHAR(1)
ID_ACC_NUM                               VARCHAR2(30)
CD_CUR                          NOT NULL NUMBER(5)
DS_MEM                                   VARCHAR2(512)
IS_ACC_ACT                               CHAR(1)
ID_ACC_SUB_TYP                           CHAR(3)
CD_FRM                                   NUMBER(5)

and the new table has the following: Name
    Null?    Type
 ------------------------------- -------- ----
 CD_ACC                          NOT NULL NUMBER(5)
 NM_ACC                          NOT NULL VARCHAR2(128)
 ID_ACC_TYP                      NOT NULL CHAR(3)
 ID_ACC_SUB_TYP                           CHAR(3)
 CD_OWN_ACC                               NUMBER(5)

Thank you so much.

Marcel.
and we said...
You are assuming data in tables have some "physical order" when
in fact they do not.  We managed space for tables in a HEAP - we
find the best place for a given row and put it there.  This may
result in the first row you insert going into block 1, the
second into block 2, and the their (because it is small but the
second row was "big") going onto block 1.  When we full scan
this table -- we will see the first row you inserted followed by
the third then the second.

There is no "order" to data in a table -- data does not come out
in the order it was inserted.

In order to get the data out in some order you MUST use an order
by.  As you are inserting the data, you must assign a "sequence"
of some sort so you can order the data on the way out.

I suggest you write the routine more simply as follows:

CREATE OR REPLACE
PROCEDURE SP_EVB_INS_ORDERED_PERSON (P_CD_CPY NUMBER,
                                     P_NM_TAB IN VARCHAR2)
IS
BEGIN
    EXECUTE IMMEDIATE  'delete from ' || p_nm_tab;

    execute immediate
    'insert into ' || p_nm_tab || '
     select ROWNUM, cd_acc, nm_acc, id_acc_type, cd_own_acc
       from ( SELECT  /*+ INDEX(PERSON PERSON_NAME_IDX ) */
                      CD_PER,
                      LPAD(' ',2*(LEVEL-1))||NM_ACC AS NM_ACC,
                      ID_ACC_TYP, CD_OWN_ACC
                 FROM ACCOUNT
                WHERE CD_CPY+0 = :P_CD_CPY
                  AND ID_ACC_TYP = ''CUS''
              CONNECT BY PRIOR CD_ACC = CD_OWN_ACC
                  AND CD_CPY+0 = :P_CD_CPY' )
    using P_cd_cpy, P_p_cd_cpy;
END;

First and foremost -- this routine USES BIND VARIABLES.  It does
not make the horrible mistake of putting character string and
numeric literals into a statement.  This is the worst thing in
the world you can do in your case.  For every row you are
fetching right now -- you are building a unique, never before
seen insert statement that must be parsed, security checked,
optimized and so on.  I can promise you that in your routine
upwards of 90% of the execution time will be spent parsing
queries (inserts).  Using bind variables will reduce that to 10%
or less.  Removing the need to do individual inserts for each
row (you do not need to) will speed this up as well.  Never do
procedurally what you can do in a single SQL statement!

Now, the person who retrieves the data from 'p_nm_tab' must add

  order by SEQUENCE_COLUMN

where sequence column is a new column you will add that they can
sort by.

Perhaps an EVEN BETTER IDEA -- if this is a "temporary result
set" you are building would be to do this:

create or replace context my_ctx using sp_evb_ins_ordered_person
/

create or replace view Orderd_Person_View
as
SELECT  /*+ INDEX(PERSON PERSON_NAME_IDX ) */
        CD_PER, LPAD(' ',2*(LEVEL-1))||NM_ACC AS NM_ACC,
        ID_ACC_TYP, CD_OWN_ACC
   FROM ACCOUNT
  WHERE CD_CPY+0 = sys_context( 'my_ctx', 'CD_CPY' )
    AND ID_ACC_TYP = ''CUS''
CONNECT BY PRIOR CD_ACC = CD_OWN_ACC
    AND CD_CPY+0 = sys_context( 'my_ctx', 'CD_CPY' )
/

create or replace procedure
sp_evb_ins_ordered_person( p_cd_cpy in number )
as
begin
   dbms_session.set_context( 'my_ctx', 'cd_cpy', p_cd_cpy );
end;
/

In this fashion, you have just constructed a parameterized view.
 You call the stored procedure to set the bind variable in the
application context.  Now, if you open "select * from
ordered_person_view", the data you are currently putting into a
table and fetching back out will just come straight out of the
query in the first place.  To the developer/end user -- it will
not appear any different, it will be as if they have their own
little temporary table but

o you are using bind varaibles
o you avoid the overhead of the delete+insert
o you do only the work needed to get the rows
o they come back in the order you anticipate
o you have lots less "little temporary tables" littering your
  database

I would suggest this course of action in Oracle8i which supports
application contexts.  In version 8.0 and before I would use

  dbms_application_info.set_client_info( p_cd_cpy )

in place of dbms_session, remove the create context call and use

  userenv( 'client_info'

in place of

  sys_context( 'my_ctx', 'cd_cpy' )

to achieve the exact same result.
January 27, 2001 alvaro -- Thanks for the question regarding "oracle sequences", version oracle 7 Server Enterprise Edition 7.3.4.0.0
You Asked
I have some auditing tables where I record information about
transactions that changes data in other tables.
Each audited table has a trigger that record the information in
this table:

table trans_aud
Name                            Null?    Type
------------------------------- -------- ----
CONS                            NOT NULL NUMBER(16)
USUARIO                         NOT NULL VARCHAR2(30)
OSUSER                          NOT NULL VARCHAR2(15)
TERMINAL                        NOT NULL VARCHAR2(10)
MAQUINA                         NOT NULL VARCHAR2(64)
FECHA                           NOT NULL VARCHAR2(10)
HORA                            NOT NULL VARCHAR2(10)
OPERACION                       NOT NULL VARCHAR2(30)
TABLA                           NOT NULL VARCHAR2(30)
OWNER                           NOT NULL VARCHAR2(30)
LLAVE                           NOT NULL VARCHAR2(2000)
PROGRAMA                        NOT NULL VARCHAR2(48)
TARJETA                         NOT NULL VARCHAR2(50)
DIR_IP                          NOT NULL VARCHAR2(2000)

The field CONS is a consecutive that identifies each transaction
made to the table.
I have other table where I get this consecutive:

trans_cons
 Name                            Null?    Type
 ------------------------------- -------- ----
 CONS                            NOT NULL NUMBER(16)

I get the consecutive of the transaction with
  SELECT NVL(CONS,0) + 1  INTO CONSECUTIVO
  FROM   TRANS_CONS
  FOR UPDATE OF CONS;
  UPDATE TRANS_CONS SET CONS=CONS+1;

This is a design mistake because not commited transactions could
lock the whole database.
If a user lock the table TRANS_CONS for getting a consecutive
and the user doesn´t confirm the transaction, then other user
will be waiting for getting its consecutive.

for this reason I've decided to use a sequence for this purpose,
so when a transaction needs to get a consecutive I call the
sequence in the respective trigger:

select trae_cons.nextval into consecutivo from dual;

I want to know if this was a right way to solve the lock
problem, or if there are another ways to do it without the
database performance go down considerably.

thanks  for your help

acueto.
and we said...
Sequences are the right way definitely -- 100%.  Any other way
imposes serialization (even if that transaction commits, you are
permitting 1 transaction to take place at a time.  You might as
well be using a flat file and grep, sed and awk as your
database!)

You will not get consecutive numbers with a sequence however.
You will get increasing numbers but there will be GAPS.  A
transaction that rollsback will have selected some sequence
values that will be "gone".  I have never found this to be a
serious issue -- the need for consecutive numbers is always
found to be a totally artificial need and when reviewed in light
of the performance implications of using a serial, blocking
method to get consecutive numbers -- is always dropped as a
"requirement".

In Oracle you use a sequence.
In Sybase you use an identity type.
In Informix you use a serial number.

and so on.  They all exhibit much the same properties -- they
are highly concurrent methods of generating surrogate keys that
are increasing numbers.
January 27, 2001 Les -- Thanks for the question regarding "Fine Grained Security error ORA-00439", version 8.1.5.0.0
You Asked
I have created a security policy, and have been able to get it
to work (thanks to other answers you provided) ion our 8.1.5.0.0
database.

I want to use this policy in an 8.1.6.0.0 database, and what I
did is as follows:

1. Created the security function and installed it in the
8.1.6.0.0 database.
2. I ran the following to add the policy:
exec
dbms_rls.add_policy('SDDBDBA','student','student_access_policy','
SDDBDBA','student_security.STUDENT_SEC','select,insert,update,del
ete',TRUE);

and I always get the following error message:

ERROR at line 1:
ORA-00439: feature not enabled: Fine-grained access control
ORA-06512: at "SYS.DBMS_RLS", line 0
ORA-06512: at line 1

So I looked up ORA-00439 on technet and it says:

ORA-00439 feature not enabled: string

     Cause: The specified feature is not enabled.

     Action: Do not attempt to use this feature.

Not exactly the answer I was looking for.

My question, what is it I need to look for and/or do in order to
get the fine grained access control enabled in this 8.1.6.0.0
database?

Many thanks in advance Tom for any assistance you may offer.

Les Davidner
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1319602341091
...
January 27, 2001 Subhakar -- Thanks for the question regarding "Truncate", version 8.1.7
You Asked
Hi Tom,

I have a table with 1,000,000 rows in it. I did a "truncate"
table, waited for 20 seconds and killed that session. When I
queried that table, there were 1,000,000 rows in it. So, my
question is:
1) How were the rows restored without the redo? and,
2)What was the system doing in the 20 seconds when the truncate
command was actually executing?

Thankx,
Subhakar
and we said...
1) updates to the data dictionary are always protected by
rollback and redo.

2) the system was modifying the data dictionary, freeing the
extents, invalidating things, making sure foreign keys weren't
pointing to this object -- etc.  It does alot of checking and
work to free up the space.  I'll have to assume you were using a
DICTIONARY MANAGED tablespace, not a LOCALLY managed one.  There
in order to free the extents, we have to do a couple of
operations per extent and this can take a while.

When you killed the session -- the data dictionary updates where
simply rolled back.  The data was never touched -- we just put
its extents back into the data dictionary map.
January 27, 2001 Dan -- Thanks for the question regarding "NT vs Unix", version 8.05
You Asked
We are contemplating a complete upgrade at our location, both
hardware and software. We are looking at two different
hardware/os options:

1. Risc (677 Mhz Alpha) with UNIX OS
2. Intel (1Ghz Pentium III)with Windows2000 or NT4.0 Server OS

Oracle 8i or 8i version 2 will be running on these machines.

With the assumption that both platforms are optimized to the
point that both are equal in performance in an Oracle Server
environment, my boss has asked me about the Oracle performance
difference between Unix and NT, and the pros and cons of one
over the other.

I know there are many factors to be considered. Any knowledge
you could give would be most appreciated.

Thanks,
Dan
and we said...
Oracle runs well on both.  The decision should be made based on
your environment, the skill set of the people working on it,
what is already in place in your location.

For example, if I was the "lead" on this -- it would be Unix all
of the way.  That is because I know alot more about Unix then
NT.  On the other hand, if your team has tons of NT knowledge
and little to no Unix -- that might tend to sway you in the
other direction.
Review & Followup
Rating: 4
Don't compare performance with different hardware... October 22, 2001
Reviewer: Sven Bleckwedel from Santos, SP - Brazil
Dan,

Tom gived a polite answer, but I don´t made a comparison with two distinct
hardware platforms.  Some months ago, Oracle made a comparison using the same
machine (Alpha) and installed Unix and NT.  The result was obvious: Unix was
about 3 (three) times faster...

Also, Unix is very stable, too...

Rgds,
Sven Bleckwedel

January 27, 2001 -- Thanks for the question regarding "OCP certifications", version version 8i
You Asked
i m not oracle trained but m planning to be 1.

does the OCP certification  has to be renewd every year?
i m going 4 for DBA certification
and we said...
see
http://education.oracle.com/certification/cp.faqs.html#6
...
January 27, 2001 Rob -- Thanks for the question regarding "Replacing primary key with non unique index", version 8.1.6
You Asked
Hi Tom,
  recently a software manager made a decision which I believe is
very poor design.  Could you help me quantify the effect of his
decision?

  We have an automated process which disables table constraints
while bulk loading tables.  Under certain conditions, this
process will insert a row which violates the primary key.  After
the bulk load, when constraints and indexing is re-enabled, the
table is unusable because of the inserted duplicates. The
software manager insists that removing the primary key and
replacing it with a non unique index will have a minimal effect
on system performance.

  Ignoring the fact that data should never be duplicated, what
will the effect of replacing the primary key with a non unique
index be?  What sort of performance degradation would we incur?
Also, this change is to be applied to several (~50) tables
throughout the database making me very apprehensive about
applying it as I fear the performance degradation will be
increased by the number of affected tables.  Is this change a
recipe for disaster?
and we said...
Well, if the data should not be duplicated -- unique index or no
-- this would obviously be a recipe for disaster.  Data that was
deemed unique will no longer be.  I would expect downstream
issues such as "SELECT INTO's" blowing up with "too many rows"
in certain cases.  I would expect "single row subquery returns
more then 1 row" errors.  And so on.  I would be more worried
about downstream effects then performance myself.  (sorry, I
know you told me to ignore that but I can't ;)

The performance impact is hard to judge.  It'll mostly affect
the optimizer and its choice of indexes.  As a UNIQUE index --
the primary key would be a better candidate for query processing
then a non-unique (it is more expensive to use an index for a
RANGE SCAN then for a UNIQUE).  I would expect some query plans
to change due to this effect.

Oracle itself uses non-unique indexes on primary keys if the
constraint is created deferrable.  The performance implications
will probably be minimal -- mostly from queries that were using
the UNIQUE index and now decide to use a non-optimal OTHER index
instead.  These queries would be tuned in the normal fashion and
performan should be equivalent.  A little extra work is done on
the non-unique index, to see if the next row on the block
(hopefully its on the block and we don't incur an addition IO to
get the next block) would match your predicate as well.
Depending on the circumstances, this additional work would
probably not be noticable (depends on the number of unique scans
you are doing now).
January 27, 2001 Manoj -- Thanks for the question regarding "How to find out which version of solaries is compatible", version 8.1.6
You Asked
Hi Tom

Appreciate for your support to DBA community.

I have a question. Our database (oracle v 8.1.6) is installed on
amachine with  solaries 2.6.  My question is how to find out
whether I can install oracle in machine which has solaries 2.8
as operating system.

Thanks

- Manoj
and we said...
metalink has the compatbility matrices for the various products
on it if you have support.
http://metalink.oracle.com/
I can confirm for you however that 8.1.6 (and 8.1.7 and 8.0.6)
are certified on Solaris Sparc 2.6-2.8 (and 8.0.6 is certified
on 2.5.x as well).  That covers both EE and SE versions.
January 27, 2001 Pete -- Thanks for the question regarding "selecting max value with all columns for distinct values", version Oracle 8.1.5
You Asked
Hi Tom,
I am trying to write a query that will return the one row with
ALL columns for each distinct account that has the highest value
in the SEQ column.

For example with the table below I would like to select these
accounts that have the highest sequence.

NAME    ADDR    ACCT    SEQ
---- -------- --------- ---
Joe   44 Elm St   10040 1
Joe  224 Oak St   10040 2
Joe  199 Town St  10040 3  this one – highest seq for acct 10040
Bill  55 Beverly  10049 1
Bill 339 Juno     10049 2  this one – highest seq fo acct 10049
Jim  210 Maple    10023 1
Jim 3887 Pond     10023 3  this one – highest seq for acct 10023
Jim   87 Lake     10023 2

PS - can you recommend a good SLQ book that can help?
thanks..
and we said...
select *
  from t t1
 where seq = ( select max(seq)
                 from t t2
                where t2.acct = t1.acct )
/

will do that.

I understand Joe Celko (search on amazon) has some books that
people regard highly.
January 27, 2001 Shailesh -- Thanks for the question regarding "Running Multiple databases on Server", version Oracle 8.0.5
You Asked
Dear Tom,

I had emailed earlier emailed you regarding a problem we were
facing under Linux environment. we received your reply. thank
You for the same. now, the problem has been resolved - we
modified certain settings in the init.ora file. Thank You.

I have been facing a question, and i thought of asking you.
On one of my customer sites - i have one application which is a
customised accounts program thta is running on Oracle. We were
not experts in Oracle when we started the implementatin at this
site, hence we did make a few mistakes. Since there was only one
application, we had only one instance. Also, we made only one
user account for this application on the Oracle server. All
users use this user name when accessing the database. Our
program is in VB 6.0 and uses ODBC to connect to this database.

This application did give us some performance problems earlier,
but we resolved this by creating separate table spaces for Data,
Indexes, and temporary segment for this user account.

we also created Indexes for most of the tables. Now, it does not
give us much performance degradation. Although, I have
monitoredin detail, but i shall start that very soon. But, the
users are not complaining about speed or reliability.

We have also developed another application for the same
customer. This application is also in VB 6.0 and uses ODBC. this
application serves as an Enquiry module for the customer. But it
has a lot of tables and will require a lot of space, since it
stores most of the data such as  - enquiry for customer,
quotations, proposals, calculations etc. this program would link
with our Accounts program, so that from enquiry stage until
acounting everything is in the system. Thus, there will be few
tables that will be shared between the Enquiry program and the
Accounts program. the Accounts program doesnot have that many
tables but has data since 1999.

I was wondering whether do we need to create a separate instance
for the Enquiry program, or do we have to just create a separate
table space for it's data, indexes, and temporary segments.

We tried installing the Enquiry application on the server, but
it caused a performance degradation even to the Accounts progarm
users. I am not sure whether this is due to the usage of the
same SGA.

Currently, we have not defined indexes for the Enquiry
application, but we will be doing this today.

Could you suggest us whether we should have a separate instance
for this application or whether only a separate user space,
table space would be fine with some performance tuning.

Also, the user for the Accounts program at the Oracle server -
is only one user which has DBA rights. And this user being used
by everybody accesing the Accounts data. is it better to have
separate users even for the Accounts program? Also, some of
these users would also be using the Enquiry application, how
should we configure the same user to access both the data?

Sorry for writing such a long email, but i hope that it gives
you a brief idea of what we are trying to do here. Shall
appreciate n early response from you.

Thanking You,

Best Regards,

Shailesh
and we said...
You should use 1 instance.

Running 2 instances on the same machine will necessarily use
more resources then a single instance will.  You'll have to size
for 2 data dictionary caches in the sga (which will be mostly
redundant).  You'll need 2 shared pools (again, mostly
redundant).  You'll have 2 sets of Oracle background processes.
You'll have 2 lgwrs contending for limited resources -- and 2
archs as well.

In all cases, if it is possible to do in 1 instance, you should.

Having 2 instances in your current situation would have resulted
in even poorer performance.  Your problem right now is that the
equiry system, being totally not tuned at all, is sucking every
last ounce of resources from the machine.  If it was in another
instance on the same machine -- it would still have taken all of
those resources but there would be even less overall resources
to go around (due to the redundant processes, memory, caches and
so on).

Now, for my 2 cents.  Tuning is not something to do AFTER THE
APPLICATION IS WRITTEN.  Tuning is something that needs to be
designed into a system.  In my opinion, you have done things
totally backwards.  You start with a good design and build the
application.  You don't just "build stuff" and then figure out
how to make it go faster.  You start with "i want this to
perform in this fashion" and at every stage in development you
ensure you are meeting these metrics.  A system should be
developed tuned, not tuned after development.

80% or more of ALL TUNING is done at the application level.  You
need to tune queries before you even consider moving data
around.  If you move the data around and then tune queries, you
just need to move the data around again in order to support the
new query plans you have.

Moving data from tablespace to tablespace and so on is the LAST
step, after all other avenues to tune have been taken.
Review & Followup
Rating: 2
Quite Informative July 20, 2001
Reviewer: Praveen Kumar Talla [getkumaronline@yahoo.com] from India
The information is some what useful for me. but I want to know how the process
should control on Oracle Server running on another platform.

January 27, 2001 RAJNEESH -- Thanks for the question regarding "Script", version 8.1.6
You Asked
Hi Tom,
I have written a Unix Shell script to automate an execution of
Stored Procedures and Functions one after another. These
Procedures/Functions return Success/Failure code.Now what I need
is for example,if one of the procedures fails due to some error
than I want to stop execution of other procedures in queue and
return failure code in shell script otherwise keep continuing
and return success code at the end. I don't know how to
communicate this return code from Oracle to Unix shell script
because this return code becomes no longer available as the
control comes back from Oracle to Unix.
This script will be executed by Autosys scheduler which
schedules other jobs also based on this result.
Hope you understood what I'm looking for. I need your help.

Thanks in advance.
and we said...
I assume you are using SQLPlus to run the SQL... If so, the
WHENEVER SQLERROR directive can help.

We can return a status from 0..255 to the Unix shell.  This is
usually in the $status or $rc environment variable immediately
after execution of a command.  The following is a csh script
that shows how this might work:

#!/bin/csh

sqlplus -s scott/tiger <<EOF

variable rc number
whenever sqlerror exit sql.sqlcode

begin
    :rc := 55;  -- this is really your function call, not 55
    if ( :rc <> 0 )
    then
        raise_application_error( (-20000-224) - :rc, 'Bummer' );
    end if;
end;
/

EOF

set x=$status
echo $x

------------------------------------------

when I run this, I get:

$ test.csh
begin
*
ERROR at line 1:
ORA-20279: Bummer
ORA-06512: at line 5

55

The key is to use:

raise_application_error( (-20000-224) - :rc, 'Bummer' );

to raise the error.  We can raise errors in a given range but
the shell will only keep an unsigned byte in the status return
value (values 0..255).  It takes our exit file and just looks at
that last byte.  By using -20000-224 and subtracting from the
your return code -- we end up exiting with the value of your
return code (given that :rc is in the range 0..255)
January 27, 2001 subhash -- Thanks for the question regarding "stored procedure", version 8.0.5
You Asked
Hi Tom!

my question is:

 how we call an external procedure written in C from stored
 procedure

thanks
and we said...
That is a trick question.

If you have an external procedure foo written in C and have
created the mapping for it via the create or replace procedure
command -- you just call foo as if it were PL/SQL.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:341817437103
it has a java and a C example.
January 27, 2001 Muhammad -- Thanks for the question regarding "java thin driver", version version 8.1.5
You Asked
What is JDBC thin driver and how it works?
and we said...
The thin driver is a total implementation of the Oracle client
in Java.  If you use the thin driver, you do not need to have
any Oracle client software installed on the client other then
the jdbc jar file.

The "thin" client is actually very "fat".  It has a large jar
file.  The thin refers to the "thin client" -- no software need
be installed.

This is in constract to the oci driver.  This is a smaller jar
file but relies on the Oracle client software to be installed on
client machine (net8 and all).
January 27, 2001 suresh -- Thanks for the question regarding "How to find system up and down time", version oracle 8.1.6
You Asked
Hai Tom,
  Thanks for your previous help.
  Is there a file or view to  find the
  oracle server startup and shutdown time ?

  If not Is there any procedure to find out of oracle
  server shutdown and startup for the given period.
and we said...
See the alert log which will be found in the directory specified
in the background_dump_dest init.ora parameter.  It will show
you this and much more.
January 27, 2001 -- Thanks for the question regarding "Displaying records in a control block(MULTI) and linking it to graph.", version 8.1.7
You Asked
Hai Mr.Tom,

SQL> desc mcpp_sinvmast
 Name                            Null?    Type
 ------------------------------- -------- ----
 SINV_NO                                  NUMBER(8)
 INV_DT                                   DATE
 CR_REF                                   VARCHAR2(20)
 INV_TYPE                                 VARCHAR2(2)
 UPD_FLAG                                 VARCHAR2(18)
 BRANCH_ID                                VARCHAR2(2)
 USERID                                   VARCHAR2(25)
 CIVILID                                  NUMBER(12)
 CUSTNAME                                 VARCHAR2(20)
 CUST_PHONE                               VARCHAR2(15)
 INV_AMT                                  NUMBER(12,3)

SQL> desc mcpp_sinvdet
 Name                            Null?    Type
 ------------------------------- -------- ----
 SINV_NO                                  NUMBER(8)
 PART_MODEL_NO                            VARCHAR2(17)
 EXCOL_CODE                               VARCHAR2(5)
 QTY                                      NUMBER(5)
 PRICE                                    NUMBER(12,3)
 DISC_AMT                                 NUMBER(10,3)
 RQTY                                     NUMBER(5)
 SIZE_CODE                                VARCHAR2(5)

My requirement is to display a top 5 sold parts between two
dates in a form and to display a graph on the same screen.

What I did is...
I have created two non-basetable blocks like this..

from date____ To Date ____

Part/model_no  total qtysold      **Here a graph should be
                                                 displayed
____________   ____________
____________   ____________
____________   ____________

I wrote a trigger in key_next of to_date field :

declare
   cursor c1 is select part_model_no, sum(qty) qty from
     mcpp_sinvmast a,mcpp_sinvdet b
    where a.sinv_no = b.sinv_no and
    inv_dt between :ctr.from_date  and :ctr.to_date
    group by part_model_no;
c1_row c1%rowtype;

begin

if :ctr.fdate is null or :ctr.tdate is null then
  message('Enter two dates....');message(' ');
  raise form_trigger_failure;
end if;

open c1;
loop
  fetch c1 into :dummy.part_model_no, :dummy.qty;
    exit when c1%notfound;
    next_record;
end loop;
close c1;
end;

But as a result of above trigger I can able to see only LAST
record of the cursor.  It is displaying all records in the TOP
ROW of detail block only, and it is displaying a message
'FRM-40102- record must be entered or deleted first'.  I think
next_record builtin is causing this message.

(1) How should I display all the records of the above cursor in
a sequence in detail block.

(2) When it comes to graph, If I create basetable block in form
and when I execute it, that chart is automatically populated
with the values that I previously selected as x-axis,y-axis.

   But when I built non - basetable block and execute or display
values in the above cursor fashion, nothing is being displayed
in chart.  How should I do this(linking graph with data being
displayed), as it was doing with a basetable block.

Thank you very much,

regs
Abdullah
and we said...
In the key-next trigger, you are missing the very very
important:

GO_BLOCK( 'dummy' );

your current block is still 'CTR' and the next_record is going
to the next record of THAT BLOCK.  You are stuck on record 1 in
dummy.

The chart would normally update after a query on that block but
a control block doesn't have a query.  You can call
update_chart( 'blockname.chart_name' ) to update the chart after
you fill in the control block.
January 27, 2001 Shailesh -- Thanks for the question regarding "Running Multiple Databases on the Server", version Oracle 8.0.5
You Asked
Dear Tom,

Thanks again for your prompt reply.

I have just discussed this with our managers, and we do agree
that next time onwards we shall have an Oracle DBA assisting us
right from the start of a project.

Thank You also for telling me to use only 1 instance.

I shall try this in the next few days.

But, i guess that you did not answer to the second part of the
email, which i am repeating here -

"Also, the user for the Accounts program at the Oracle server -
is only one user which has DBA rights. And this user being used
by everybody accesing the Accounts data. is it better to have
separate users even for the Accounts program? Also, some of
these users would also be using the Enquiry application, how
should we configure the same user to access both the data?"

For example if the user name on  the Oracle server owning the
Accounts database objects is - SHAILESH. Then all users are
accessing SHAILESH user from the VB6.0 application.

We have an ODBC Connection connecting to user SHAILESH on the
Oracle Server. And this ODBC connection settings is configured
on all workstations. The VB 6.0 applcication connects through
this ODBC connection to access the data of the Accounts program.

Is this configuration ok, or do you feel that i should configure
the ODBC connections based on the user accesing the program
(i.e. Tom could have a user space on the server, and if Tom
logins to the VB6.0 application then it would connect to Tom's
table space, and similarly for other users.) Do you think that
this would help improve performance in some way?

Thank You for your help.As for your 2 cents - i would give you
something more than that - A lot of blessings, for helping us.
Thank You. if you anytime plan to visit Thailand, please let me
know.

Best Regards,

Shailesh
and we said...
Sorry, I didn't see that part, i concentrated on the first part.

The above situation is very very bad.  Terrible.  A DBA has
extremely powerful privileges.  In your installation, I could
fire up any GUI database tool I wanted, connect over that odbc
connection, and do anything i wanted to any object i wanted
to.

It is, in my opinion, a security hole big enough to fly the
space shuttle through -- 10 of them across even.

What I suggest is

o you immediately change the password for this account,
disabling all access to it except by valid users.

o setup another account, say "APPLICATION".  Grant CREATE
SESSION and CREATE SYNONYM to this account only for now. Nothing
else.

o in the SHAILESH account, grant the barest minimal set of
priveleges the people need on the tables.  For example, if
people should only QUERY table T and use a procedure X to
insert/update it --

   GRANT SELECT ON T to APPLICATION
   GRANT EXECUTE ON X to APPLICATION

do not "over" grant -- don't give them insert or anything on a
table if they do not ABSOLUTELY need it.

o in the APPLICATION schema, now create synonyms for all of the
objects

   CREATE SYNONYM T for SHAILESH.T
   CREATE SYNONYM X for SHAILESH.X

Now, change your ODBC connection setup to connect as
application/application.

that is step #1.  Now you have at least made it so that your end
users cannot accidently drop your tables or really do some
serious damage.  It is not optimal but it is something you can
do right now, right away.

Now, as you move on into to future, you should figure out how to
use multiple schemas (i am sure that every end user does not
need access to every object -- you probably have some set of
roles).  These schemas would be setup like application above --
with the barest minimal set of privs to do their job.  People
would start using these schemas instead of all in one.  You
might have a "clerk" schema, an "admin" schema , a "manager"
schema and so on -- each with different capabilities.

To take this further, you would start removing the ability to
insert/update/delete tables from the application.  You would
move ALL of that logic into stored procedures.  Now end users
must use your logic to change the data, they cannot log in using
sqlplus or any other ODBC tool and doing direct
inserts/updates/deletes.  You would create these procedures,
grant execute on them to the appropriate schemas and then REVOKE
insert/update/delete on these objects from these schemas.

To take this yet further, you would do the same to queries.
Instead of having the query in the application -- the
application calls a procedure that returns a ref cursor (see
http://osi.oracle.com/~tkyte/ResultSets/index.html
for examples).  Now, you can remove SELECT priv on tables as
well.  They must go through your application to query the data.
You could create reporting views and what not in the SHAILESH
schema and grant select on them to the correct schemas but in
general, the queries the application does are stored in stored
procedures.

Now, when you find a bug -- you fix the procedure.  All
applications are IMMEDIATELY updated.  Tune a query -- fix the
procedure and all applications are IMMEDIATELY updated.  No more
do you have to install and reinstall and reinstall for patches
and such.  Your system will be more secure, more robust and
easier to maintain and tune.
Review & Followup
Rating: 4
Great Explanation .. November 27, 2002
Reviewer: Vikas Sharma from Delhi india
hi Tom ,

A usual Great Explanation .. from tom.

Regards,

Vikas Sharma

January 27, 2001 -- Thanks for the question regarding "MTS and Parallel Server", version 8.1.6
You Asked
Tom,

What are the pre-requisites for making a Server MTS. And
Pre-requisite for configuring the Parallel Server.  Is there any
documentation available to configure MTS server and Parallel
Server.

What are the pros and cons of both. Can we have more than one
instances and configure either mts or parallel server.

Thanks
and we said...
There are no prerequisites for MTS.  You need to be using net8
but other then that -- nothing special.  There are some
guidelines -- eg, if your machine can handle the load via
dedicated server, there is not much to be gained via MTS.  MTS
comes into play typically when the machine can no longer do it
otherwise.  Some options, such as using EJB's in the database,
will mandate the use of MTS even on a small scale though.

See
http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/toc.htm
and specifically:
http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/mts.htm#450520
for OPS (oracle parallel server) the first pre-req is that you
have a cluster of computers running the hardware and software we
support.  OPS is an option of Oracle that runs on a cluster of
many machines.

See
http://technet.oracle.com/doc/oracle8i_816/paraserv.816/index.htm

for info.  I'll let you read the stuff on MTS and OPS before
getting into a "pros and cons" as they are somewhat large areas
to discuss and I could list dozens of things about them that are
simply not relevant in your environment.  You would need to be a
little more focused in the question before I could respond...
Review & Followup
Rating: 4
Great start, what about pros and cons? March 20, 2002
Reviewer: Doug from CT, USA
Well, an application without a load test is going to tax one of our boxes to the
point where it will not be able to deal. This application uses 2 oracle
connections per user on average, at 100 users this is about 200 connections x
30MB of memory a piece.  The max load will be 300 users or 600 connections for
18GB of memory required.   We simply don't have it. (We have like 4GB)  Can you
help me figure out how much memory I can save using MTS? Also, what are the
drawbacks.  One I can think of is that connections may have to wait on each
other, but by how much?  Although I am very much hoping using MTS will help a
great deal, I still would like to hear what the potential drawbacks are in case
I get the question - "Why didn't we do this before?".   Everthing I am seeing
says to stay with dedicated unless you really have no choice.

January 28, 2001 -- Thanks for the question regarding "Trusted Oracle", version 8i
You Asked
Hi,

What do you mean by Trusted Oracle ?

RO
and we said...
See

www.computerworld.com/cwi/story/0,1199,NAV47_STO53293,00.html

for a quick over view of what it means to be "trusted".

In 1992, Oracle Corporation introduced Trusted Oracle7 MLS
RDBMS, a state-of-the-art product built to support a strict
multilevel security (MLS) policy on trusted operating systems.
Since 1992, adoption of the trusted operating system technology
has been limited. In 1998, Oracle started a research and
development project to replace Trusted Oracle7. In conjunction
with the R&D effort started in 1998, Oracle Service Industries,
Advanced Programs Group worked to define a new access control
model with Oracle customers based on the labeling technology
found in Trusted Oracle7. As a result of that work, the Advanced
Programs Group developed a product called Secure Access and
incorporated a new label based access control model which is a
variant of the strict multilevel security policy found in
Trusted Oracle7. Since the introduction of the Secure Access
product, there has been an overwhelming positive response from
users. In 1999, Oracle Corporation decided to merge the Secure
Access product into the R&D project already underway to replace
Trusted Oracle7. The new product, known as Oracle Label
Security, provides flexibility and security through enforcement
options and user privileges that reflect the requirements of
real world applications.
Review & Followup
Rating: 3
OLS info is so limited September 20, 2001
Reviewer: Ben Lowers from Atlanta, GA USA
Great synopsis of Trusted Oracle7 -->> OLS . We have had a great evaluation of
OLS this summer; a well packaged implementation of the much touted virtual
private database (VPD). "Leaks" of OLS info of any kind are splendid, and info
on the prospects of Common Criteria evaluation of Oracle8i/9i + OLS + Trusted
Solaris for MLS applications would be even more so. (not a question...)

Too bad LBAC can never really fill the shoes of ol' Trusted Oracle7, since
Oracl8i/9i doesn't seem to have any access to the Trusted Solaris's label
encoding, therefore network packets will all be labeled at the highest possible
level.
:(
--

January 28, 2001 Guru -- Thanks for the question regarding "Communicating b/w 2 sessions", version 7.3
You Asked
Dear Tom,

   I know the concepts of DBMS_PIPE & DBMS_ALERT.  But can you
pl. tell me if want to send some message to all who are working
on the various forms in different sessions by using sql or
pl/sql of form.

Thanking You,
Guru Prasad M.R.
and we said...
You would use DBMS_ALERT to send a message to many sessions.
These sessions must be *interested* in hearing that message
(e.g. they must register their interest in this message using
dbms_alert.register).  Additionally, they must occasionally
check for the existence of such a message using
dbms_alert.waitany or waitone.

In forms, the use of a timer is typically used to facilitate the
automated checking for a signal from dbms_alert.
January 28, 2001 suresh -- Thanks for the question regarding "Help Regarding Executing OS command from PL/SQL", version 8.1.6
You Asked
Hai Tom
  Thanks for your help. We got the following error message while
trying to execute the  OS command using java stored procedure
given in ur archieve.
http://osi.oracle.com/wa/ask/owa/ask_tom_pkg.display?p_dispid=952229840241

SQL> exec rc('/bin/ls -l');
java.security.AccessControlException: the Permission
(java.io.FilePermission /bin/ls execute) has
at
java.security.AccessControlContext.checkPermission(AccessControlC
ontext.java:207)
at
java.security.AccessController.checkPermission(AccessController.j
ava)
at
java.lang.SecurityManager.checkPermission(SecurityManager.java)
at
oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityM
anagerImpl.java)
at java.lang.SecurityManager.checkExec(SecurityManager.java)
at java.lang.Runtime.exec(Runtime.java:270)
at java.lang.Runtime.exec(Runtime.java:195)
at java.lang.Runtime.exec(Runtime.java:152)
at Util.RunThis(Util:11)

PL/SQL procedure successfully completed.

How to solve the above problem.

Thanks in Advance..
and we said...
The example, as I have it setup and documented, gives you the
ability to run PS and PS alone.  If you want to run ls, you need
also to:

ops$tkyte@ORA8I.WORLD> begin
  2      dbms_java.grant_permission
  3      ( user,
  4       'java.io.FilePermission',
  5       '/usr/bin/ls',
  6       'execute');
  7  end;
  8  /

PL/SQL procedure successfully completed.
January 28, 2001 ahmad -- Thanks for the question regarding "oracle?", version 8.0.5
You Asked
hi tom;
1.what does oracle mean ,is it a place thing or a adjective
2.what would be the impact of  mircosoft csharp on java's
market,pls the detail and why?
3.how are bitmap indexes stored compressed pls explain in detail
tanx
and we said...
1) Oracle is the name of a software company.  It is also the
name of our flagship product, the database.  The database used
to be referred to as just "Oracle" and still is but its current
name is "Oracle8i".

2) I have no idea.  I'm an open systems sort of person, I work
on Unix, mainframes, and windows.  A language for a platform
isn't something I'm into.  I skipped the whole Visual Basic
thing and stuck with C and PL/SQL (languages that I found
support for on every single platform I've ever worked on).  Now
I do Java as well (mostly snippets it the database or when I
need to do something on the client).  I don't really follow
things like csharp.

3) see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c08schem.htm#5381
basically, it is an index whereby a "leaf row" in the index
points to MANY rows in the table instead of a 1-1 relationship
between index entries and rows in a table (as would be found in
a b*tree index)
January 28, 2001 ahmad -- Thanks for the question regarding "ifile", version 8.0.5
You Asked
hi tom;
1.what does IFILE really do?I know we nest parameter files with
this parameter and upto three level nesting is possible but why
we nest parameter files?
2.Is there any to move one table from one tablespace to another
with all constraints without EXPORT/IMPORT?if any what and how
3.in recovery proccess there is a phrase with the name of:
"using backup controlfile",I read about and it said :
we use this option until either our "time,cancel,change" based
has recoverd or our control file recovers?I dont know what they
,If u could explain in a few clear words.
4.can minextents for a table change?
5.what is catproc.sql script really for?
and we said...
1) it is like #include in C.  It just includes a file into
another file.  It is convienent when you want to keep the files
in ONE place but have then appear to be in another.  For
example, on NT, we look in
$ORACLE_HOME\database\init$ORACLE_SID.ora
for the init.ora.  The file is actually in
$ORACLE_HOME\admin\$ORACLE_SID\pfile\init.ora.  The file in
database is simply IFILE=.....

(this is true on 8.1.6.  In 8.0 and before it might not be).

It is simply a thing of convienence.

2) Yes but you need Oracle8i release 8.1 to do it.  It is a new
feature.  You can:

alter table T move tablespace Y;

otherwise, in 8.0 and before (as you have) you would typically
use export and import.

3) When doing media recovery (recovery from a backup) we roll
forward through archived redo logs.  We can do this until you
tell us to CANCEL (stop right now, this is all I want to
recover).  We can do this till a point in time (I would like you
Oracle to recover this database to the way it was at midnight
last night).  Or, if you know the SCN (system commit number) you
can recover until that SCN as well.

4) You can alter the minextents LOWER (but it will not
unallocate an allocated extent). You can alter it HIGHER but not
any higher then the number of extents already allocated.  You
can alter the table and manually allocate extents and then set
minextents to this new number.

So yes -- you can.  You can go lower (but it will not
unallocate, just changes the data dictionary).  You can go
higher but not any higher then already exists.  You can add more
extents via the alter table command.

5) catproc stands for CATalog script for PROCedural code.  It
installs the basic PLSQL packages we all need.


Subject | Article | Last Updated (East coast time)
Exporting Public Synonyms of A user | article only | Jan 29, 2001 02:08 pm
status of users | article only | Jan 29, 2001 02:14 pm
Transporting tablespaces | article only | Jan 29, 2001 02:20 pm
Not actually a question, bugfix | article only | Jan 29, 2001 02:23 pm
Parallel Query | article only | Jan 29, 2001 04:14 pm
master level in developer | article only | Jan 29, 2001 04:19 pm
DBMS_*function | article only | Jan 30, 2001 02:23 pm
Error ORA-01485 | article only | Jan 30, 2001 02:48 pm
replication & backup recovery | article only | Jan 30, 2001 02:53 pm
SGA Question | article only | Jan 31, 2001 10:03 am
Changing of the export file version | article only | Jan 31, 2001 12:17 pm
Automatic Indexes | article only | Jan 31, 2001 02:45 pm
Check whether a user has a particular role | article only | Jan 31, 2001 04:51 pm
Accounts Payable | article only | Jan 31, 2001 08:00 pm
PL/SQL | article only | Feb 01, 2001 09:28 am
Some Context Search Issues | article only | Feb 01, 2001 01:31 pm
interMedia index after moving a table | article only | Feb 01, 2001 01:40 pm
General Doubts | article only | Feb 01, 2001 02:26 pm
Data Flow - Reg. | article only | Feb 01, 2001 02:27 pm
how to retrive current job id within a running job | article only | Feb 02, 2001 04:42 pm
locally managed TS | article only | Feb 02, 2001 07:25 pm
Data storage - reg. | article only | Feb 02, 2001 07:43 pm
Business Logic - Reg. | article only | Feb 02, 2001 08:12 pm
Desginer 2.1 with personal Oracle 7.3 | article only | Feb 03, 2001 08:25 am
Data Buffer cache/Redo buffer cache/ rollback segment | article only | Feb 03, 2001 08:45 am
Oracle Products - I | article only | Feb 04, 2001 08:44 am
Oracle Products - II | article only | Feb 04, 2001 08:54 am
oracle 8i | article only | Feb 04, 2001 09:04 am
Hash Code | article only | Feb 04, 2001 09:07 am
Rollback Segment | article only | Feb 04, 2001 09:17 am
performance issue for ASP | article only | Feb 04, 2001 09:23 am
how to use padding | article only | Feb 04, 2001 09:25 am
Creating an executable | article only | Feb 04, 2001 09:34 am
Performance Measurement | article only | Feb 04, 2001 01:39 pm
Valid User | article only | Feb 04, 2001 01:45 pm
SQL*DBA and SVRMGRL | article only | Feb 04, 2001 01:48 pm
row(s) 1 - 36 of 36
January 29, 2001 Rupali -- Thanks for the question regarding "Exporting Public Synonyms of A user", version 8.1.5
You Asked
Dear Tom,

I was trying to export a Single User with Exp80.exe.  Kindly do
tell me what exactly is expected to happen when there are some
Public Variables or Synonyms declared by this User?  These
synonyms may be for his own objects or even for those objects on
which he his having grants.

Thanks,

Rupali
and we said...
Public synonyms are never exported except during a FULL database
export.

Public synonyms are not owned by anyone.  All public synonyms
show up in DBA_SYNONYMS with an owner of PUBLIC.

The best you could do is to create an auxillary script to be run
with the export that would create a public synonym for each
object of that user that has a public synonym.  For example:

select 'create public synonym ' || synonym_name ||
       ' for ' || table_owner || '.' || table_name || ';'
from dba_synonyms
where owner = 'PUBLIC'
and table_owner = 'THAT USER'
/

spool that output and it'll rebuild the public synonyms for you.
January 29, 2001 praveen -- Thanks for the question regarding "status of users", version 8.1.6
You Asked
I want to know whether a particular user is logged in the
databse or not and if yes at which time he logged in the
database and from how much time he is inactive?
and we said...
this is the query:
 1  select username, to_char(logon_time,'dd-mon hh24:mi'),
  2        status,
  3        last_call_et
  4* from v$session
ops$tkyte@ORA8I.WORLD> /

USERNAME        TO_CHAR(LOGO STATUS     LAST_CALL_ET
--------------- ------------ ---------- ------------
                17-jan 18:41 ACTIVE          1020688
                17-jan 18:41 ACTIVE          1020688
                17-jan 18:41 ACTIVE          1020688
                17-jan 18:41 ACTIVE          1020688
                17-jan 18:41 ACTIVE          1020688
                17-jan 18:41 ACTIVE          1020688
                17-jan 18:41 ACTIVE          1020688
..
PEOPLE1         29-jan 13:21 INACTIVE           3110
PUBLIC_USER     29-jan 14:10 INACTIVE             92
....

ignore the first lines, they are the server processes.  The
last_call_et is the time in seconds since the last call began.
for status = inactive it will show the time in that status
(idle).

Note: the last_call_et column might not be updated frequently if
you are not using timed statistics.  It'll get updated about
every 40 seconds or so.
January 29, 2001 Vallabh -- Thanks for the question regarding "Transporting tablespaces", version 8.1.1.5
You Asked
For checking whether Tablespace is self contained i tried to
execute dbms.tts.transport_set_check ( .. ). this package is not
defined in database... how wll i get SQL script for this package?
and we said...
exec sys.dbms_tts.transport_set_check

o use SYS, there is no public synonym created by default.
o it is dbms_tts, not dbms.tts

You also need to have the EXECUTE_CATALOG_ROLE role in order to
execute this.
January 29, 2001 Vladimir -- Thanks for the question regarding "Not actually a question, bugfix", version ***
You Asked
This is not a question.
I couldn't find out your webmaster e-mail address on the site,
so i decided to post here.
I've found some bug on your website Q&A section (seen in IE 5).
Description:
(URL:
http://osi.oracle.com/wa/ask/owa/ask_tom_pkg.display?p_dispid=1346602827682
http://osi.oracle.com/wa/ask/owa/ask_tom_pkg.display?p_dispid=1347002836674
 etc.)
The text supposed to be seen on the left (white background) part
of the page, but if one changes IExplorer "text size" to
"Larger" or "Largest", the text rolls over the blue part of the
page.
Best regards, Vladimir
and we said...
Yes, I know about that.  Nothing I can given the template I have
to use.

At the top of each page I have a "View "plain" (no
background/images)" link as my solution to this problem.  For
example, it'll display the page like this:
http://osi.oracle.com/wa/ask/owa/ask_tom_pkg.display_plain?p_dispid=1346602827682
short of explicity setting the font size in the page -- so MS
cannot resize it, there is nothing I can do.

...
January 29, 2001 Winarko -- Thanks for the question regarding "Parallel Query", version 8.1.6
You Asked
Hi Tom,

Can I enable and utilize parallel query on Oracle8i 8.1.6 on Sun
Box with multiple CPU?

Thxs,
Winarko
and we said...
It'll depend on whether you have Enterprise or Standard Edition.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76962/ch4.htm#73594
it explains in a matrix what features/functions are available in
EE vs SE.
January 29, 2001 mahmood -- Thanks for the question regarding "master level in developer", version version 2.5
You Asked
Dear tom,
 I just now finish from all tracks of OCP as Application
developer ,So How I can continue to get master digree in
Application developer.

 best regard
 mahmood kossi
and we said...
See
http://education.oracle.com/masters/appdev.html
for information regarding this.
January 30, 2001 San -- Thanks for the question regarding "DBMS_*function", version 8.1.5
You Asked
Hi Tom,

Where I can get list of all DBMS_* functions and DBMS_*
Packadge?
I have already checked Oracle manuals there are a small listing
for DBMS_* packadges but it's not complete and there is nothing
for DBMS_* functions.

Regards,
San
and we said...
There is an entire document called the Supplied Packages Guide
which covers them all
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/toc.htm
...
January 30, 2001 KARADJIA -- Thanks for the question regarding "Error ORA-01485", version 8.1.5
You Asked
When I call a package from Pro*C program I have this error
(ORA-01485).
According to the Error Message Book (Volume 1), I see that the
array size of the bind variable is exceded.
But I don't understand Why I had this problem.Which buffer size
and what is the meaning of the two bytes of VARCHAR Type.

Thank's a lot for your help and your explanation.

Ayoub.
and we said...
When calling a PLSQL block and passing it a VARCHAR type -- you
must set the LENGTH before calling the block.  Don't just code:

  exec sql execute
  begin
      foo( :my_host_var );
  end;
  end-exec;

rather, code:

   my_host_var.len = 255;
  exec sql execute
  begin
      foo( :my_host_var );
  end;
  end-exec;

(setting .len to the size of the VARCHAR2 element you defined
your host var as)
January 30, 2001 wallacel -- Thanks for the question regarding "replication & backup recovery", version 8.1.6
You Asked
Tom:

i am studying replication right now.
my question is if i set up 3 master site, can i think each one
as a backup of other one?
so i don't need to backup database, also i don't run it in
archive log mode.because i always have two backup at any case,
and it is pretty safe( i means there are little chance that
three database crash at the same time).

or i only need to run one database in archivelog mode in case of

user error I can return it back to some point of time.

Regards,
and we said...
Nope.  In fact it might be MORE important to have excellent
backup and recovery procedures and to ensure you are running in
archive log mode.

Lets say you have DB1, DB2, DB3.  A transaction at DB1 will get
pushed to 2 and then 3.

Ok, DB1 has a transaction, the end user commits.

Db1 pushes this transaction to Db2.  Now Db1 and Db2 have it.

The disk crashes on Db1.  You have no backups.

Now Db2 and Db3 are hopelessly out of sync.  Db1 is responsible
for pushing its transactions out to all involved but it cannot
(you lost it).  Db2 and Db3 will never be the same as eachother
unless you "merge" them and figure out the differences and do it
yourself.

In a distributed database such as this -- making sure everyone
is "singing off of the same sheet of music" is even more
important!

You still need to backup, you still need to run in archivelog
mode.
January 31, 2001 -- Thanks for the question regarding "SGA Question", version 8.1.6
You Asked
Tom

What does the following values indicate, how do we correlate the
values with Init parameters.

Total System Global Area                        502108144 bytes
Fixed Size                                          69616 bytes
Variable Size                                   166313984 bytes
Database Buffers                                335544320 bytes
Redo Buffers                                       180224 bytes

Does oversizing these params cause bottle neck.  Is fixed size
and redo buffers allocated with less value.

Thanks
and we said...
Fixed Size is something you cannot control.  It is our fixed
sized data structures.

Variable Size is the shared pool, large pool, java pool.

Database buffers is db_blocks.
Redo buffers is log_buffers

Oversizing (and undersizing) can definitely kill a system.
Allocate too much to the SGA and the dedicated/shared servers
will be starved for RAM.
January 31, 2001 Francoise -- Thanks for the question regarding "Changing of the export file version", version 8.1.6
You Asked
Dear Tom,

Does it exist a script to change an 8.1.6 Export File into an
8.0.5 Export File?

Best Regards !!!
and we said...
No, you would use the 8.0.5 EXP tool to create an 8.0.5.  the
problem is, there are new features/objects in 8.1.6 that the
8.1.6 export will create that 8.0.5 will not understand.  If you
use the 8.0.5 exp tool -- it will only export what it
understands.

the only conversion that would be possible is to import it into
8.1.6 and export it using 8.0.5 exp.
January 31, 2001 Howie -- Thanks for the question regarding "Automatic Indexes", version 8.0.4
You Asked
Hi Tom !

How can I Find indexes that were automatically created for
columns that have unique constraints ?

Also is there any way to find out the indexes which were created
automatically?

Thanks in Advance

Howie
and we said...
Sort of.  We do not directly keep track of this but we can
deduce it (almost).

If the index name of the index supporting a primary/unique
constraint is system generated -- then we can tell for sure.

If the index name of the index supporting it is the SAME as the
constraint name -- we are pretty sure it was generated.  PRETTY
sure (i can create an index I1 on the pimary key columns and
then create a primary key I1 -- we did not generate the index in
this case).

If the index name if the index is not the same -- then we know
it is not generated.

here is a view that works well (create as SYS)

sys@TKYTE816> create or replace view pk_indexes
  2  as
  3  select     t.name    table_name
  4       ,  u.name    owner
  5       ,  c.name    constraint_name
  6       ,  i.name    index_name
  7       ,   decode(bitand(i.flags, 4), 4, 'Yes',
                   decode( i.name, c.name, 'Probably', 'No') )
  8       generated
  9  from sys.cdef$ cd
 10     , sys.con$  c
 11     , sys.obj$  t
 12     , sys.obj$  i
 13     , sys.user$ u
 14  where cd.type#      between 2 and 3
 15  and   cd.con#       = c.con#
 16  and   cd.obj#       = t.obj#
 17  and   cd.enabled = i.obj#
 18  and    c.owner#  = u.user#
 19  and   c.owner# = uid
 20  /

View created.

sys@TKYTE816> create public synonym pk_indexes for pk_indexes;
sys@TKYTE816> grant select on pk_indexes to public;

And to test it we can:

tkyte@TKYTE816> create table t ( x int primary key,
  2                   y int,
  3                   z int,
  4                   constraint y_unique unique(y) );
Table created.

tkyte@TKYTE816> create index z_idx on t(z);
Index created.

tkyte@TKYTE816> alter table t add constraint z_unique unique(z);
Table altered.

tkyte@TKYTE816> select * from pk_indexes
  2  /

TABLE_NAME OWNER CONSTRAINT_ INDEX_NAME  GENERATE
---------- ----- ----------- ----------- --------
T          TKYTE SYS_C001260 SYS_C001260 Yes
T          TKYTE Y_UNIQUE    Y_UNIQUE    Probably
T          TKYTE Z_UNIQUE    Z_IDX       No
January 31, 2001 -- Thanks for the question regarding "Check whether a user has a particular role", version 816
You Asked
Hi Tom,

Is there a simple that I can check whether a logged in user
possess a particular role from pl/sql.  For example, in Sybase,
there is a system procedure call 'proc_role' which is used to
for this purpose. eg. if (proc_role("sso_role") = 0).
Is there a similar procedure that can be used in Oracle?

Thanks.

David.
and we said...
There is nothing builtin but a procedure can easily be written.
I'll put two below.  One uses the data dictionary views -- the
other uses the base tables.  The reason is -- the data
dictionary views in this case get slow when you have 10's of
thousands of users (as I do).  The base table queries go very
fast.  I'll present both:

ops$tkyte@ORA8I.WORLD> create or replace
     function proc_role( p_role in varchar2 ) return number
  2  is
  3      l_cnt number;
  4  begin
  5      select count(*) into l_cnt
  6        from dual
  7       where exists ( select NULL
  8                        from dba_role_privs
  9                       where grantee = USER
 10                         and granted_role = upper(p_role) );
 11
 12      return l_cnt;
 13  end;
 14  /

Function created.

Elapsed: 00:00:00.61
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> exec dbms_output.put_line(
proc_role('dba') );
1

PL/SQL procedure successfully completed.

Elapsed: 00:00:05.50
ops$tkyte@ORA8I.WORLD> exec dbms_output.put_line(
proc_role('resource') );
0

PL/SQL procedure successfully completed.

Elapsed: 00:00:04.72

So, that shows I have the DBA role but not RESOURCE.  It took 5
seconds each to figure that out (I 50k users and 100k
dba_role_privs).  Going to the base tables:

ops$tkyte@ORA8I.WORLD> create or replace function proc_role(
p_role in varchar2 ) return number
  2  is
  3      l_cnt number;
  4  begin
  5      select count(*) into l_cnt
  6        from dual
  7       where exists ( select null
  8                        from   sys.user$ u1,
  9                               sys.sysauth$ sa
 10                        where u1.user# = sa.privilege#
 11                          and sa.grantee# = UID
 12                          and u1.name = upper(p_role) );
 13
 14      return l_cnt;
 15  end;
 16  /

Function created.

Elapsed: 00:00:00.26
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> exec dbms_output.put_line(
proc_role('dba') );
1

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
ops$tkyte@ORA8I.WORLD> exec dbms_output.put_line(
proc_role('resource') );
0

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01

is it instantaneous.

For the first version -- the owner of the procedure must have
SELECT granted DIRECTLY to them (not via a role) on
DBA_ROLE_PRIVES.  For the second, they need it on USER$ and
SYSAUTH$.  See
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for why the direct grant is needed.
Review & Followup
Rating: 5
PROC_ROLE March 28, 2003
Reviewer: Dana Day from Arizona USA
Very interesting application of data dictionary.

January 31, 2001 Faye -- Thanks for the question regarding "Accounts Payable", version Release 11.03
You Asked
Hi Tom:

I have two questions;
1. I am working as a Business Analyst and have to deal with day
to day issues with users not being able to do different things,
do you recommend any book (other than user guide) that is more
of troubleshooting related to applications.

2; Regarding the 1099 forms, how to print the report on to the
forms with a Laser Printer.  Any step by step information you
have on setting up the printer and computer to work together and
Align.  Thanks a lot!

Regards,

Faye
and we said...
Sorry so long, I have to ask around for apps related stuff (not
exactly what I do day to day...)

They say:

..
Tom,

#1:  The best source of information is the individual user
guides for each of the applications products or the System
Administrator's Guide as well.  However, other good sources of
information is Oracle's on-line support facility MetaLink.
Through MetaLink you can perform on-line searchs on various
topics, download support bulletins and even helpful topical
essays.  Assuming you've got an active support contract with
Oracle, you can access MetaLink at:
http://www.oracle.com/support/metalink/index.html
You can also access the Oracle Applications Network, or AppsNet.
 On AppsNet, there are additional resources that you can use to
get applications related information.  There are even on-line
forums that you can access to ask/answer question for others in
the Oracle Applications community.  AppsNet can be accessed at:
http://www.oracle.com/appsnet/index.html
#2  There are two possibilities here.  The first is that our
standard 1099 printing simply produced output in a standard
format.  The formatting is done to line-up with forms from
Evergreen Inc.  You would simply get the 1099 Evergreen form and
put it in your printer.  The other possibility would be to
modify the 1099 printing program to not only produce the output,
but to produce the forms as well.
February 01, 2001 srinivasa -- Thanks for the question regarding "PL/SQL", version 7.3
You Asked
How do i find all the procedures,functions which are using a
specified table. (which is equivalent to SP_DEPENDS <TABLE_NAME>
in SYBASE)
and we said...
select owner, name, type
  from all_dependencies
 where referenced_name = <table_name>
   and referenced_owner = <owner>
   and referenced_type = 'TABLE'
/
February 01, 2001 Bhavesh -- Thanks for the question regarding "Some Context Search Issues", version 8.1.5
You Asked
Dear Tom,
    This site of your's is really proving a boon for me and I
believe the same for the whole Oracle Community users who are
regular visitors to this site. Thanks for having such a
wonderful site.
    I have certain doubts related to search using context
search.
1. To test this feature I created a table and then created an
index as follows :
    create index on table(lob_field) indextype is
ctxsys.context;
Now I inserted say 3-4 rows and tried to run the query using
contains clause but it retrieved no results even though the word
I was searching was available in the field.
After trying for a couple of times I dropped the table and
re-created the same. This time I did a trick, I first inserted
the rows and then created the index. Surprisingly!! this worked
out fine.
Does this mean that we need to re-create the index every time we
insert the row or if we create index type ctxsys.context on a
blank table it does not work ? I am bit preplexed.

2. To design a search engine I have gone through you reply at
the following url :
http://osi.oracle.com/wa/ask/owa/ask_tom_pkg.display?p_dispid=350017644883
Here things work exactly fine for me upto markup table. Once I
issue the search query say it returns 5 rows and puts them in
the markup table (I have used a cursor to fetch the matching
rows into markup table). I have two doubts at this point.
a. Since the markup table does not have the primary key
(p_dispid) how to populate the desired record from these 5
records existing in the table with same query_id.
b. Is there any way to display the document directly in html
format on screen from the document column of table because the
document column contains a few tags of html but not all.
c. When do you delete the records from markup table and how.
Because after a few searches the table gets many records
inserted into it.

Your guidance in this regard will be of great help. Thanks a lot
in advance.
Regards

Bhavesh
and we said...
1) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1091633271464
for this (or the current issue of Oracle Magazine -- that one is
in this weeks "ask tom".

2) markup has its own primary key -- QUERY_ID.  You send it the
query id.  I markup one document per page view and immediately
delete the marked up document -- I would never markup all 5
documents -- not until the user PICKED one -- and then i would
mark it up, display it and delete it right away (the markup
table is always "empty")

b) I don't understand that question.

c) right after I read them out.  I call markup, read out the
text and htp.p() it and delete the row. That happens all in one
session.  There are never any rows in this table after I am
done.
February 01, 2001 William -- Thanks for the question regarding "interMedia index after moving a table", version 8.1.6
You Asked
Hi Tom,

After moving a table from one tablespace to another, the
interMedia index on that table becomes unusuable.

Is there a quick way to rebuild this index or does it have to be
recreated which takes quite a long time?

Regards

William
and we said...
It has to be rebuilt, which after a move will probably be more
or less the equivalent of a create (the rowids it had are
totally invalid, it cannot find the rows anymore).

You can:

alter index foo_idx rebuild online ;

or

alter index foo_idx rebuild online parameters('memory 50m')
February 01, 2001 Anand -- Thanks for the question regarding "General Doubts", version 8.1.6.0
You Asked
1. I was studying Oracle Documentation and found that bcos of
the Lru(LEast Recently used)  Mechanism used by Oracle datafiles
might contain some data blocks modified by uncommitted
transactions and some data blocks missing changes from committed
transactions. THe First Part is Ok .How is the Second Part True
.Can You Make me understand How Committed Transaction be
Prevented from being stored in the DataFiles

2. Under what circumstance will You  create indexes on tables
that are owned by one user and the indexes being owned by
another user Can U Give me an Example
eg
User A Creates Indexes For Tables of USer B

C V Anand

Thanks In Advance
and we said...
It is not a side effect of LRU, it is the normal state of
events.  LRU is how we manage our buffer cache.

We can have blocks that represent data that has not yet been
committed in the datafiles.  This will happen when we checkpoint
or run out of room in the buffer cache.  We'll write out the
current version of the block to disk.  If we CRASHED right then,
we would startup, the system would recover from the redo logs
(updating the rollback segments) and we would rollback and
recover these uncommitted blocks from the rollback segment.  At
the end of recovery -- the block would be as it was before the
crash and before the transaction that did not commit modified
it.

We can also (and very very frequently do) have blocks in the
datafile that look at the block did before a transaction that
modified it committed.  We do not flush your blocks to disk upon
commit -- rather we write redo entries to the online redo logs.
If you modify a block and commit -- the changes are recorded in
the log files.  If we crash before a checkpoint flushed the
modified block from disk -- we will recover that block from the
redo log and roll it forward to be the way it was before the
crash occured.

We do these operations to the redo log file in order to avoid
the massive scattered writes we would otherwise have to do to
datafiles upon your commit.  We do large sequential writes to
the logs and upon a checkpoint flush the buffer cache of dirty
blocks.  The redo logs + rollback segments protect the integrity
of the datafiles.

as for 2 - i cannot think of a reason why i would personally
want to do that.
February 01, 2001 Patibandla -- Thanks for the question regarding "Data Flow - Reg.", version 8.1.6.0
You Asked
1. When the database is in archievelog mode
and two statements e say
1. insert into  temp values(1,'TESTING')
2. COMMIT
are issued

Then how these statments are handled by the
database. Where are statement and data stored
and where are they finally affected when
commit statement is issued.

2. My rollback segments size has grown up enormously.
   how to minimize them.

   There are 28 Nos of RB Segments created in Tablespace RBS.
   I want to have maximum of 3 only can i do that.

3. What does redolog file contains.
   If the DDL Statements are stored in redolog file
   then how  to see the contents in it.

   what does control files contains.

Regards

Thanks in Advance

Patibandla
and we said...
1) the insert will find a free block in the table -- it may be a block from the
freelist for the table or it may be a newly allocated extent if the freelist was
empty.  Once it has the block, it will modify it in memory.  This modification
will generate REDO which will be written to the redo log buffer and ROLLBACK
which will after blocks in the rollback segment.  The modified block itself will
be in the buffer cache.   When we commit, LGWR will flush the REDO record to the
online redo logs, the modified block will (probably) stay in the buffer cache.

In the event of failure after the commit but while the block is still in the
cache and not on disk -- we have sufficient information in the redo logs to redo
that operation.

When we perform a checkpoint that block will be flushed to its datfile.

2) alter rollback segment RBS_NAME shrink to Nk;

you can go down to 3 (but if you have lots of concurrent users, rethink that
number).  Just drop some of them (making sure to modify your init.ora if they
are listed in there else your database will not autostart the next time).

3) redo stores redo -- AFTER images if you will -- of blocks.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1368003184009
for how they are used.

DDL is not recorded in there but the side effects of it are.  You won't see
"drop table EMP" but using dbms_logmnr (see the supplied packages guide for
details) you can see the DML that was performed against the SYS.OBJ$ table for
example to delete that row for EMP.
February 02, 2001 Thomas -- Thanks for the question regarding "how to retrive current job id within a running job", version Oracle 8.1.6 EE
You Asked
Hi,

how can i get the job id (DBA_JOBS_RUNNING.JOB) within a running
job, started by the job scheduler (dbms_job package)?

thanks for your time
and we said...
You can pass it to yourself.  When you execute a job, we wrap
whatever you pass in the "WHAT" parameter with the following
code:

DECLARE
   job BINARY_INTEGER := :job;
   next_date DATE := :mydate;
   broken BOOLEAN := FALSE;
BEGIN
         WHAT
    :mydate := next_date;
    IF broken THEN :b := 1; ELSE :b := 0; END IF;
END;

If you submit a job like:

dbms_job.submit( l_job, 'my_procedure( JOB );' );

That will pass the local variable JOB to your procedure -- that
will be your job id.

You can use this to facilitate passing parameters to yourself
with jobs.  Instead of hard coding inputs into the WHAT passed
to dbms_job -- which will tend to trash the shared pool with
lots of unique SQL statments if you submit lots of one off jobs
-- I create a table like:

create table T ( job int, parm1 datatype, parm2 datatype, ... );

and when I submit the job I code:

...
  dbms_job.submit( l_job, 'my_procedure( JOB );' );
  insert into t values ( l_job, parm1, parm2, .... );
...

then, I code my_procedure like this:

create procedure my_procedure( p_job in number )
as
   l_inputs  t%rowtype;
begin
   select * into l_inputs from T where job = P_JOB;
   ......
end;

That is as opposed to submitting:

   dbms_job.submit( l_job, 'my_procedure( 5, ''Hello'' );' );

and then later:

   dbms_job.submit( l_job, 'my_procedure( 6, ''Goodbye'' );' );

and so on...
Review & Followup
Rating: 4
March 20, 2001
Reviewer: A reader

Rating: 5
June 07, 2001
Reviewer: A reader

February 02, 2001 -- Thanks for the question regarding "locally managed TS", version 8.1.6
You Asked
We're planning to create all  tablespaces  as locally managed
TS.
Are there any situations that they should not be ?
Should SYTEM TS be created as locally managed ?
Any negative impacts on TS for Rollback Segments and TEMP
segments ?
I think TEMP TS will benefit from being locally managed as the
space
management tables in the dictionary need not be accessed as TEMP
segments are being created and removed for sorting.

Thanks.
and we said...
System cannot be created as a locally managed tablespace.

Rollback and temp are great that way.  (but temp segments are
not removed after sorting -- we manage them in v$ tables after
they are allocated -- as long as the temporary tablespace is
"temporary").  You will find that for sort intensive operations,
locally managed tablespaces will definitely increase
performance.

I use nothing but locally managed tablespaces for everything.
Absolutely love them.
February 02, 2001 patibandla -- Thanks for the question regarding "Data storage - reg.", version 8.1.6.0
You Asked
Hi Tom,

I have a Separate Rollback Segment Table Space
In the RBS Table Space I have datafile called RBS01.DBF
I have Separate User Table Space. In the user table space
I have a datafile called user01.dbf

1. when i issue a statement say select * from emp
   what r the files it is going to search.

2.  When i issue a statement say
    insert into emp(empno)  values(20)
    does both the user01.dbf and rbs01.dbf
    are affected? pls explain?

3.  if user01.dbf is affected then why the others are not
    able to see untill the transaction is committed?

4.  when i issue a commit is the data flushed from the
    rbs01.dbf file;

5.  Is the mechanism same for insert/delete/update?.

Regards
Thanks in Advance
and we said...
1) impossible to say for sure.  I don't know what tablespace emp
is in.

If emp is in users -- it'll read user01.dbf and if necessary
it'll read the rollback segments to provide a read consistent
view of this table.  If other users are modifying emp as you are
reading it, we use rollback data to provide non-blocking
consistent reads.

2) yes, eventually (writes are deferred).  When you insert into
the table, we'll get a block from the freelist of emp and modify
it.  before we modify it -- we save information to "unmodify"
(or roll it back) in the rollback segments.

3) thats the rule.  thats the law.  Thats the way transactional
databases work.  Some databases provide "dirty reads" as a
method of providing a non-blocking read to get around their
locking model.  We provide read consistent, non-blocking reads
without having to resort to breaking the rules.

4) no. rollback is managed much like data is.  see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1368403185587
for a discussion on this mechanism.

5) pretty much except different amount of redo and rollback are
generated for each.
February 02, 2001 koshal -- Thanks for the question regarding "Business Logic - Reg.", version 8.1.6.0
You Asked
Hi Tom
As I told u we are developing Web Based Product using
VB Activex Controls/IIS Server/Oracle 8i Database.

The Business Logic has been stored in PL/SQL.

1. I expressed that since the Data/Business Objects
   are at the same place the performance is always
   better? Is my statement correct if not why?

2. The Development folks expressed that since the business
   logic has been written in PL/SQL. The product has become
   database dependent?

regards
and we said...
1) the performance, in my experience, is usually better.  It is
possible to write poorly performing code at any tier.  If the
business logic is very SQL intensive -- the stored procedure is
the correct place.  I find it much easier to tune PLSQL+SQL then
SQL stored in the middle of some code that has to be broken
apart and recompiled and redeployed anyway.  Also, using stored
procedures makes it slightly more secure (well, a whole lot
more) then have the middle tier do selects, updates, inserts,
and deletes

2) my answer to this is.... you have to become dependent on
something at some point.  You made a couple of choices here:

- VB
- ActiveX
- IIS
- Oracle8i

I could say, that by using VB you have become language dependent
haven't you?  I cannot switch to another language next month can
I?  What if a better language, a faster language, a cheaper
language comes along?  Even more -- the choice of language has
locked you into an operating system.  Your choice of language
not only locked you into a language, it locked you into an
entire OS?  Historically, operating systems come and go.  5
years ago -- Unix was the big thing.  5 years before that VMS.
5 years before that -- mainframes where pretty hot stuff.  5
years from now????   Perhaps Java would be a better language,
more open, not locked into one vendor -- both for the OS and the
language itself.

I could say that by using ActiveX you have become dependent on
MS as they not only own this proprietary, non-internet (eg:
non-open) standard.  How many vendors can you goto to buy
"ActiveX" from??  (i can count that on one finger).  Not only
that, but by using ActiveX I've pretty much locked myself into
the operating system *again* (see above).  Perhaps I should pick
an open standary such as JSP or EJB and any number of open
internent standards.  Some of the upside to that would be that
you would not be locked into a single vendor for one of your
core technologies and you could pick up and move from OS to OS
pretty easily.

I could say that by using IIS instead of an open server such as
Apache that runs on every OS people care about is locking you
into that OS again.  Just think -- if you just used Apache +
Internet Standards + Internet Languages -- you could pick up and
move to the next great OS or allow your customers to pick from
many OS's without doing much extra work.  With the choices you
have made, you've sort of locked yourself into a single platform
-- one size fits all.

I'm sort of amused by the fear of becoming database dependent
when they've made so many other "lock me in tighter then
anything" choices.  It is my belief that you pick your
technologies carefully and then you EXPLOIT them to the MAXIMUM
possible extreme.  You buy these technologies (and pay lots for
them) -- it would be not in your best interest to EXPLOIT them
in the best way possible.  I have to assume they picked the
first three carefully and look forward to fully exploit them.
Why not the fourth choice?

The first three technology choices seem to limit you much more
then a database lock in.  The first three lock you into A vendor
and A operating system.  It is true, you can only buy Oracle
from Oracle but at least it runs on pretty much every OS out
there (and runs in the same way -- I rarely develop on the
platform I'm going to deploy on, I don't need to).
February 03, 2001 Suliman -- Thanks for the question regarding "Desginer 2.1 with personal Oracle 7.3", version 7.3
You Asked
Dear Tom

   Thank you for you help all the time .
 My question is :- can i work with desginer 2.1 with personal
oracle 7.3 pls show me how can i install it ,becuase i did an
ordinary installtion but did not work.

Thank you
and we said...
it depends on which 2.1.x you have.  3 digits is the minimum one
would need to answer this question.  see below.

2.1.0 can work with:

Client
------
Currently certified:

Windows NT 4.0 and Windows 95

Server
------
Currently certified:

  Oracle 7.3.4
  Oracle 8.0.4
  Personal Oracle 7.3.4 (not applicable for Windows NT)

2.1.1 can work with:

Client
------
Currently certified:

Windows NT 4.0,  Windows 95 and Windows 98

Server
------
Currently certified:

  Oracle 7.3.4 Enterprise Edition
  Oracle 8.0.4 Enterprise Edition
  Personal Oracle 7.3.4
  Personal Oracle 8.0.4

2.1.2 can work with:

Client
------
Currently certified:

Windows NT 4.0,  Windows 95 and Windows 98

Server
------
Currently certified:

  Oracle 8.0.5 Enterprise Edition
  Oracle 8.0.6 Enterprise Edition
  Oracle 8.1.5 Enterprise Edition  (separate client server)
  Personal Oracle 7.3.4
February 03, 2001 Ajay -- Thanks for the question regarding "Data Buffer cache/Redo buffer cache/ rollback segment", version 8.1.6
You Asked
Hi Tom,

I have been recommended to you. I am currently preparing for my
8i DBA certification. My question is:

How does the data move between Data buffer cache, data files,
redo log buffer, redo log files, and rollback segments for the
following sequence of statements against a table:

UPDATE
DELETE
COMMIT
UPDATE
COMMIT
UPDATE
DELETE
and then the instance fails

To be more clear, I know that when I first issue an UPDATE
statement, the data is moved from the data files to the data
buffer cache (if already not there). Also, a copy of it is moved
to the rollback segment. What happens next for the current
UPDATE statement and the others lined up as above? Finally, when
the instance recovers, where does it pick up the latest data
from? If you could give an example, I would appreciate it.

Thanks.
Ajay Garg
and we said...
Here is one POSSIBLE sequence of events (really depends on
the many factors, especially the degree of concurrency, how long
it takes to process and volume of data).

we have

1) update
2) delete
3) commit

(1) will read in the block and put it into the cache.  the block
will be modified in the cache.  Some data will be generated for
the rollback segment (the before image of the block if you will
-- just enough data to UNDO the update).  Additionally,
information will be generated for the updated block AND the
rollback segment block to be placed into the redo log buffer (to
REDO this update if necessary later after a failure).

(2) will again, read in the block (unless the block is in cache
-- assuming you are deleting a different row on a different
block) and put it into the cache.  The rest of the above
paragraph is the same here. the block will be modified, rollback
will be created and redo for both will be put into the redo log
buffer.

(3) will cause the redo log buffer to be flushed to disk if it
hasn't already.  It may also revisit some of the cached blocks
from (1) and (2) to "clean them up" but this is not necessary
and doesn't always happen.  The next process that reads these
blocks will clean them out if we do not.

As we get into

(4) update
(5) commit

the process is identical to (1) and (3) above.  The same
sequence of events takes place.

Now, we do

(6) update
(7) delete

and the instance fails.  Well that is no problem, we need to get
back to the point in time of (5) where the last commit took
place.  All of the information needed to redo (1)...(5) is
safely recorded in the redo log buffer (and MAY parts of (6) and
(7), the redo log buffer might have gotten flushed for other
reasons and parts of (6) and (7) may be recorded in there.

We start recovery and we start rolling through the online redo
logs.  We will replay (1)...(5) -- we are now back to where we
should be.  To make it interesting lets say (6) got flushed to
the logs.  We will actually replay (6) which will update the row
and generate rollback for it.  As we never got a commit for that
transaction, recovery will now roll it back.  We can roll it
back since we recovered the rollback as well as the data blocks.
 We are now safely back at point (5).  The database is
recovered.

It is more complex then this, there is lots going on.  The
sequence of events would be different if we hit a checkpoint in
the process somewhere and so on.  In a nutshell, this is how it
works.
February 04, 2001 San -- Thanks for the question regarding "Oracle Products - I", version 8.1.5
You Asked
Hello Tom,

I am totally new for web based stuff and completely confused
about Oracle Products. I know you can directly forward me to
TechNet web site address, but I'll be really appreciated if you
also can tell me little bit about products, so it will be more
Understandable for me. My question can be very basic for you,
even though I need to know about the products I was working on.

Here is my first set of question:

1. (a) In my last job I was using Internet explorer for
accessing the Oracle database. I was typing some sort of host
address http:\\hp-1234....  some thing not remember exactly in
to Internet explorer address window and it was taking to
me to the another window based screen and from there (after
enter login and password) I was able to use that machine like a
local NT workstation. Also when I was I was doing installation
of Oracle Server (was using CD for Oracle server for NT 4.0), my
sys admin was inserting the CD from some other machine and I was
able to see same screen from my machine. I am wondering weather
it was "Oracle Web Server".

1. (b) What are the differences between following products:
A. Web Server
B. Oracle Web Server
C. Oracle Web Application Server
D. Oracle Application Server
E. Oracle WebDB

2. (a) What is the relation between distributed database and
Oracle Replication and Replication Server?
2. (b) What do you mean by exactly "Replication Server"?
2. (c) What does it mean if some one will ask me "Have you ever
worked for Replication Server?" Is he asking weather:
a. I worked for distributed database?
b. What kind of replication I was involved in?
c. Some sort of advance replication.
2. (d) How to implement advanced oracle Replication (or Oracle
Replication Server, if it's correct).

Thanks & Regards,
San
and we said...
first (1) -- does not sound like anything we have.  Sounds like
VNC -- a java based remote access solution for NT and Unix.
http://www.uk.research.att.com/vnc/
second (1) a,b,c,d are all names for different releases of our
application server which is now known as iAS (internet
application server).  there was:

version 1.0 Oracle Internet Server (ois)
version 2.x Oracle Web Server      (ows)
version 3.x/4. Oracle Application Server (oas) ask Web App
Server

latest release: iAS

WebDB is a web site development tool, a portal builder.  It came
with (in 2.x) a lightweight webserver for development but would
typically be deployed using oas.  It now uses iAS.

2) Replication Server is a product offered by Sybase.  Oracle
has basic and advanced replication builtin to the database.  We
do not have a separate server product for a feature that should
be native to the database itself.

The relationship between a distributed database and Oracle's
replication is that we take advantage of our native distributed
database features in order to replicate data.

2-b&c, don't know.  doesn't make sense with regards to Oracle.

2d -- for that I will refer you to the documentation.  It is
complex and has many things to consider.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76959/toc.htm
...
Review & Followup
Rating: 5
Different version of Web Server April 21, 2001
Reviewer: Arvind K Singh from BAHRAIN
It helped to ubderstand about the development of Web Application Server and
latest release

February 04, 2001 San -- Thanks for the question regarding "Oracle Products - II", version 8.1.5
You Asked
Hi Tom:

Here is my Second set of questions: (Continue from previous set)

3. Is there some thing called Hot standby server? If, yes what's
that?

4. What is Multi-threaded server, how different it is from
dedicated and how to implement it?

5. Is that "Oracle Parallel Query Server" and Oracle Parallel
Server are same.

6. What is Oracle Names Server, Is this another different
product of Oracle. How to implement it.

7. What is Data warehousing, Is this another different product
of Oracle. How to implement it.

Warm Regards,
San
and we said...
3) we have a warm standby.  It is warm because it is not 100% on
until you turn it on (a hot one would be up and running before
you even needed it).  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76995/toc.htm
it is a database that is in constant recovery mode, applying the
logs your production system is generating.  It is running a
little behind your production machine. If your production
machine fails, you would activate the standby (take it out of
recovery mode and open it up)

4) MTS is a configuration such that instead of having a PROCESS
per user (dedicated server) we have a pool of shared servers.
So, for 1,000 users I have have 25 shared servers for example
instead of 1,000 dedicated servers.

See
http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/concepts.htm#1009675
for an overview of MTS and
http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/mts.htm#450520
for configuration details

5) they are totally different.  a parallel query server (slave)
is a process that is assigned a portio of a query to perform.
Oracle Parallel Server (OPS) is a configuration of Oracle where
you are mounting and opening the same set of database files by
more then one instance, each instance running on a different
machine.  OPS requires more then 1 computer in a clustered
configuration.  You can do parallel query OVER OPS (a query can
be broken up and shipped out to various nodes within a cluster)
but OPS is very very different from parallel query.

6) see
http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/products.htm#439800
Overview
Oracle Names establishes and maintains an integrated system of
Oracle Names servers which work together like a directory
service. The system stores addresses for all the services on a
network and makes them available to clients wishing to make a
connection.

Much like a caller who uses directory assistance to locate a
telephone number, clients configured to use Oracle Names refer
their connection requests to an Oracle Names server. The Oracle
Names server attempts to resolve the service name provided by
the client to a network address. If the Oracle Names server
finds the network address, it then returns that information to
the client. The client can then use that address to connect to
the service.

7) data warehousing is a career path.  It is a "thing" like OLTP
is.  It is a system you set up.  We have lots of products in
support of data warehousing but it is something you DO not
necessary BUY.
February 04, 2001 ahmad -- Thanks for the question regarding "oracle 8i", version 8.1.5
You Asked
hi tom;
1.what are stored outlines? I mean how are they used
e.g;
if I create out line for the following statement;
select /*+parallel(emp,3)+/ * from emp;
will this statement also use stored outline.
select * from emp;
and when we write queries should we mention hints in the query
or not
e.g i would like to create outline for
select * from emp;I would like to use parallelism should I
mention degree of parallelism.
2.can categories be of any name and any number?(maximum stored
outlines).
3.what are enterprise javabeans and corba .I dont know anything
about them.are they layers,applications or what?
4.what is OCI?I know one oci layer in net8 layer architicture is
it that or other one?
5.I cant still understand REF datatype if u could clear what is
really the relation between the to sets of tables by example.
tanx tom
and we said...
Oracle8i introduced the ability for a developer to save an
outline, a set of “hints to the server” for executing a specific
SQL statement in the database.  This feature is referred to as
“Query Plan Stability” and is implemented via a stored query
plan outline – similar to an outline for a book.  What this
allows us to do is, for a given query or set of SQL statements,
save the optimal set of hints for runtime execution without have
to “hint” the query ourselves in the application.  This allows
us to develop an application, test and tune the queries within,
and then have those plans preserved for us – regardless of the
changes to the underlying database.

The queries must be byte for byte exactly the same.  The two
queries you have above for emp are not the same.

You can use hints and stored the resulting outlines but you must
always use the hint in order to get a hit on that outline.  If
you take the hint out -- that outline cannot be associated with
that query.

If you want a select * from emp to have a stored outline that
uses parallelism, you would create an environment where that
would happen.  EG: you would alter table emp parallel 5; run the
query, save the outline and alter the table back.  The stored
outline would be a parallel query plan.

2) there are no documented limits on the number of outlines you
can store.  They are stored in database tables so it would
appear the sky is the limit.  Catagory names follow the rules
for identifiers in Oracle (start with a letter, are 30
characters in length, etc)

3) EJB and Corba (Common Object Request Broker Architecture) are
standards for setting of distributed objects.  EJBs allow the
application logic to reside in on process on one machine and the
client stubs on another.  The develop calls the stubs, the stubs
find their implementations and send their data to the
implementation.  The implementation runs the code against the
data and returns the results.  Corba is very similar.  These
things have features like "name resolution" (helps a stub find
its implementation), "transaction services", "marshalling
services" (transfer complex data structures over a network) and
so on.

In a very simplistic way, they are stored procedures but they
are much more transparent then stored procedures.

4) OCI is the Oracle Call Interface.  It is a C level API for
accessing Oracle.  It is like "ODBC".  OCI is a layer way on top
of Net8.

5) a REF datatype is like a "char *" in C.  It is a pointer.  In
C I can code:

char * ptr;

    // ptr is now a ref to this
    // constant string
    ptr = "Hello World";

    // now ptr is a ref to this
    // other variable.
    ptr = some_other_variable;

    // I can deref this ref as well..
    *ptr = '\0';

A ref is sort of like a rowid.
Review & Followup
Rating: 4
use_stored_outlines December 14, 2002
Reviewer: William from Australia
Tom,

Just wanted to get your thoughts as to why use_stored_outlines is not an
initialization parameter (for 8.1.7 anyway).

It just means that we then have to create a startup trigger and then use alter
system command.

Cheers

February 04, 2001 Jorge -- Thanks for the question regarding "Hash Code", version 8
You Asked
Hi Tom!

I need an implamentaion of Hash code build in PL/SQL, I
construted one but its not efficient. Can you help me?

I have three numbers (keys of tables) and I need generate one
unique number ... a Hash Code.

Thanks for your time
and we said...
concatenate the three numbers together and use
dbms_utility.get_hash_value
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/dbms_ut2.htm#1002139

eg:
  l_hash := dbms_utility.get_hash_value( n1||'/'||n2||'/||n3,
                                         1,
                                         2048 );

....
February 04, 2001 Valsaraj -- Thanks for the question regarding "Rollback Segment", version 8
You Asked
hi Tom

1) I use a database which do not use parellel server
option.Apart from the default rollback segment I want to create
additional rollback segments. Do I need to specify the names of
rollback segments against the init.ora parameter
rollback_segments ?
2) My database is supposed to be connected by 50 users. will any
problem occur if I don't specify values for parameters
transactions and transactions_per_rollback_segment in init.ora ?
3) If I create more rollback segments - say transactions=50 ,
transactions_per_rollback_segment= 5, so number of rollback
segments to be aquired by instance startup is 10. But I create
15 number of rollback segments .
   a) aquiring the number of rollback segments is applicable to
the database which is not with parellel server option ? ( since
my rollback segments are not private )
   b) Could u explain me please what will be the situation at
instance startup for this particular situation - ( calculation
comes to 10, but i made 15 )
   c) Any perfomace issue will occur because of this ?

thanks
and we said...
1) only if you create them as PRIVATE (the default kind)
rollback segments.  If you use:

create PUBLIC rollback segment ....

they will online themselves at system restart.

2) transactions should be OK (it is a function of sessions).
Since it is rare for all of your users to be simultaneously
doing a transaction, the default is sufficient.

Transactions/rollback segment -- that'll be a function of the
number of rollback segments you have and the number of
concurrent transactions.  If you have 10 rollback segments,
you'll be in great shape.

3) if you create 15 public rollback segments, you'll have 15
rollback segments online in your instance.

a) don't understand the question
b) there is no calculation to be made?  you created 15 rbs's and
we'll give you 15.  That would allow you to have by default 15*5
concurrent transactions, others will wait.
c) no. 15 is small/medium, 30 is big.
Review & Followup
Rating: 3
November 27, 2001
Reviewer: Marc Blum from Aachen, Germany

February 04, 2001 Faisal -- Thanks for the question regarding "performance issue for ASP", version ver 8.1.6
You Asked
Hi Tom,
I am working on converting an ASP(Appication Service Provider)
from mySQL to Oracle8i. It is a web application in which every
user has their own set of data and they dont share any data
amongst themselves. The situation is that the current user base
is around 40-50 but the client anticipates that it will
significantly grow to logically infinite users at some time with
every user having his own set of identical tables but different
data.

1) Now having the same set of tables (repeated for every user)
while having a lot of users, I am thinking about creating a
schema for every user because security is a main issue
(application being ASP). The question is that, does the above
solution produce any performance threats with increasing
userbase/data? OR is there a better solution?

2)Can table partitioning(keeping security in mind) be used here
because having separate schemas creates more DB administrative
work? kindly also highlight the use of Parallel Server/MTS  etc
for this problem

Regards.
FS.
and we said...
1) see
http://osi.oracle.com/~tkyte/article2/index.html
2) yes, definition partitioning can help (but not to solve your
problem, #1 does that).  partitioning will help you when the
database gets bigger and you need to be able to recover things
faster, rebuild things faster, etc.  partitioning will break the
big tables up into lots of little tables logically for you to
manage.

Parallel server is a high availability feature you can use to
help assure your system is always up.

MTS is a feature that when your machine is totally filled up
(dedicated servers cannot be started anymore due to lack of
resources) we can start to shared physical processes across many
users.  It lets you get more people logged in then you could
otherwise.
February 04, 2001 abhinay -- Thanks for the question regarding "how to use padding", version version7.3
You Asked
hi

i am developing app.in my company for stores dept.
in area of stock inventory & records.
i have a matl_id number datatype in format '0001'
but @ runtime i am getting '1'.
please tell me why it is happening & suggest me solution
thanks
regards
abhinay
and we said...
The number type isn't a character type -- leading zeroes are not
relevant to a number so they are never stored.

If you need the leading zeroes, you do not have a number, you
have a character string.  You would use a varchar2 instead.

If the number of zeroes is always the same (eg: this is a 4
digit number with leading zeroes) you can:

 select to_char( number_col, 'fm0000' ) number_col, .....

to turn the number into a string on the way out of the database.
Review & Followup
Rating: 5
rpad a number column March 13, 2003
Reviewer: Steve from UK
Hi Tom

How can I rpad a number column?  Consider:

SQL> create table t (a number(8));

Table created.

SQL> insert into t values(77236);

1 row created.

SQL> select rpad(to_char(a),'#',10) from  t;
select rpad(to_char(a),'#',10) from  t
                       *
ERROR at line 1:
ORA-01722: invalid number

Rating: 1
D'oh March 13, 2003
Reviewer: Steve from UK
Crap syntax!! Ignore question!!  Send questioner back to basic sql course!

Sorry!

February 04, 2001 Rajesh -- Thanks for the question regarding "Creating an executable", version 6
You Asked
Hi ,
    I want to know if it is possible to create an exe out of the
forms and reports that have been created by me.What is the usual
procedure in deplaying an application in oracle forms. (i am new
to oracle)

Thanking you
Rajesh
and we said...
No, you cannot create an exe file.

If you go client server, the clients install the Oracle runtime
software (for forms, reports and net8).

If you go for internet deployment, you put the forms and reports
on a server somewhere and your clients access the applications
with their web browser.

option #2 is preferred by many as you do not have to deploy your
application to lots of clients.  when you find a bug, you fix it
and deploy it to your server and your clients are all updated
right away.
February 04, 2001 Tripti -- Thanks for the question regarding "Performance Measurement", version 8.0.4
You Asked
Hi Tom,

We want to measure the SLA(Service Level Agreement) with our
user.
For this ib my online screen we want to measure the time taken
for getting data to the client side i.e. time taken by the Sever
side as well the client side execution of thye application.

Can there be any automated tool by which I can achieve this.
Some Orale package etc. that I can code in my application.

Thanks

Tripti
and we said...
You may find Oracle Trace useful in that area:
http://technet.oracle.com/doc/server.804/a58246/otrace.htm#3016
...
February 04, 2001 Shruti -- Thanks for the question regarding "Valid User", version 8.0.4
You Asked
Hi Tom,

We find that ovwr the time we have creTED TOO many users which
are probably not being used.

Is there any away to find the list of users not used for last
one week or any duration set by me.

Thanks in advance

Shruti
and we said...
You can enable auditing and audit connects.  In that fashion,
the audit trail tables will give you this information.

Please refer to the admin guide for guidelines on setting up
auditing and the SQL reference manual for the syntax of the
AUDIT command itself.

You'll have to wait one week before finding out who hasn't
logged in in a week however...
February 04, 2001 San -- Thanks for the question regarding "SQL*DBA and SVRMGRL", version 8.1.5
You Asked
Hi Tom,

I think SVRMGRL is same as SQL*DBA and in early version of
Oracle 7, SQL*DBA changed with SVRMGRL. Can you please tell me
exactly up to what version of Oracle SQL*DBA was there and from
which version of Oracle it's been changed to SVRMGRL. Is there
any other conceptual similarity or .... between SQL*DBA and
SVRMGRL.

Thanks
San
and we said...
SQL*Dba was the precursor to svrmgrl.  (Server Manager
Linemode).  Server manager itself was the precursor to OEM.

SQL*Dba was either a line mode or "full screen" character mode
interface to some database administration and monitoring.
Server Manager replaced SQL*dba with version 7.3 of the
database.  In version 7.3, Server Manager with a GUI and a
command line interface replaced the character mode only sqldba.

Now, SQLPlus is slated to replace svrmgrl (you can startup,
shutdown, connect internal and so on from sqlplus) in the near
future.
Review & Followup
Rating: 4
SQL*DBA Vs SVRMGRL August 23, 2001
Reviewer: Sanjeev Varshney from California

Rating: 4
November 05, 2001
Reviewer: A reader


Subject | Article | Last Updated (East coast time)
Oracle Enterprise Edition | article only | Feb 05, 2001 08:09 am
About OWA cartridges | article only | Feb 05, 2001 08:13 am
Group by column value | article only | Feb 05, 2001 08:35 am
I want to insert or update records into some other database dynamically | article only | Feb 05, 2001 08:41 am
Migrating on different platforms | article only | Feb 05, 2001 08:48 am
Column Histograms | article only | Feb 05, 2001 08:53 am
Can I Use Global variable in Reports (6.0) | article only | Feb 05, 2001 09:16 am
MAXLENGTH | article only | Feb 05, 2001 10:59 am
Backup & recovery and regrading database triggers | article only | Feb 05, 2001 11:13 am
Cursors For Loop | article only | Feb 05, 2001 11:16 am
Word count | article only | Feb 05, 2001 11:23 am
Incompatablity with import/export | article only | Feb 05, 2001 11:26 am
How can I prevent inserts on a given table from being written to the redo log? | article only | Feb 05, 2001 11:35 am
Can External Java call PL/SQL? | article only | Feb 05, 2001 12:43 pm
How can we pass value of a PL/SQL variable to Shell variable? | article only | Feb 05, 2001 02:17 pm
Stored Procedure conversion from Sybase to Oracle | article only | Feb 05, 2001 04:15 pm
How to group tables in tablespace | article only | Feb 05, 2001 04:25 pm
Importing data from MS-Access into Oracle | article only | Feb 05, 2001 06:37 pm
netsted tables | article only | Feb 05, 2001 07:16 pm
Array of data into Nested Table | article only | Feb 06, 2001 09:58 am
Resoring data | article only | Feb 06, 2001 10:07 am
Write into Client System | article only | Feb 06, 2001 10:17 am
When to Use Hint CACHE | article only | Feb 06, 2001 10:54 am
script running slow | article only | Feb 06, 2001 11:06 am
SQL*Net data Security | article only | Feb 06, 2001 11:10 am
how can we make one primary key as composite primary key | article only | Feb 06, 2001 11:19 am
triggers on Database Level | article only | Feb 06, 2001 11:45 am
Find out the size of the table. | article only | Feb 06, 2001 11:46 am
reletional operators in decode | article only | Feb 06, 2001 11:56 am
Are holes in a tablespace problematic | article only | Feb 07, 2001 10:51 am
Table constraints & Export & Db link | article only | Feb 07, 2001 11:13 am
sql%rowcount and EXECUTE_IMMEDIATE function | article only | Feb 07, 2001 11:20 am
User Call | article only | Feb 07, 2001 11:33 am
Similar to Kernal Parameter | article only | Feb 07, 2001 11:56 am
Union in select statement | article only | Feb 07, 2001 01:08 pm
Mail | article only | Feb 07, 2001 01:10 pm
Truncating a Table | article only | Feb 07, 2001 02:02 pm
Rman | article only | Feb 07, 2001 02:08 pm
How to measure the Performance of a Stored Procedure | article only | Feb 07, 2001 02:14 pm
DESEncrypt and DESDecrypt | article only | Feb 07, 2001 03:27 pm
Coverting varchar2 to Long Raw (Binary) and insert in a file. | article only | Feb 07, 2001 07:19 pm
Updating using three tables | article only | Feb 07, 2001 07:27 pm
how to determine a SP by application? | article only | Feb 07, 2001 07:32 pm
Two Questions on Migrating from 7.3.4 to 8.1 in Unix Environment | article only | Feb 07, 2001 07:46 pm
creating nested table in other schema's | article only | Feb 07, 2001 08:48 pm
Compile oci program on Sco unix | article only | Feb 07, 2001 08:59 pm
Perform Binary Operation in Oracle??? | article only | Feb 07, 2001 09:07 pm
Examples | article only | Feb 08, 2001 01:38 pm
Global Temporary Tables | article only | Feb 08, 2001 04:21 pm
updating nested tables | article only | Feb 08, 2001 04:37 pm
To get rid of Chained Rows | article only | Feb 08, 2001 04:40 pm
"Silent" exceptions | article only | Feb 08, 2001 06:29 pm
Installing 8.1.5 on same machine which contains 8.1.6 | article only | Feb 08, 2001 06:31 pm
updating nested tables and scalar columns in a single update | article only | Feb 08, 2001 07:40 pm
Get server local hostname | article only | Feb 09, 2001 06:54 am
How to call a function (Pro C) in Oracle 8i environment??? | article only | Feb 09, 2001 08:31 am
is any way to trap IP ADDRESS of a client on net using form 6i | article only | Feb 09, 2001 08:35 am
Recursion of triggers | article only | Feb 09, 2001 09:19 am
Dynamic Temp table | article only | Feb 09, 2001 06:47 pm
Tablespace Recovery | article only | Feb 09, 2001 06:50 pm
how to convert dictionary managed TS to locally managed TS in 8.1.5? | article only | Feb 09, 2001 07:24 pm
Failed when run cdemo2.c program | article only | Feb 09, 2001 07:26 pm
should i store datetype as well as raw data? | article only | Feb 09, 2001 07:30 pm
export import between different db_block_size? | article only | Feb 09, 2001 07:33 pm
table sizing | article only | Feb 10, 2001 10:14 am
Collection Unnesting | article only | Feb 10, 2001 10:18 am
EXAMPLE FORMS | article only | Feb 10, 2001 10:21 am
About DBMS_PIPE | article only | Feb 10, 2001 11:17 am
Some useful doubts !!! | article only | Feb 10, 2001 11:23 am
PL/Sql Tables | article only | Feb 10, 2001 11:28 am
Database Administration | article only | Feb 10, 2001 02:35 pm
Life of Native datatype into multiple loops ... | article only | Feb 11, 2001 10:15 am
Restrict Multi Sessions or Multi Signon for Single User | article only | Feb 11, 2001 10:17 am
too slow v$locked_object | article only | Feb 11, 2001 02:14 pm
row(s) 1 - 74 of 74
February 05, 2001 Krishna -- Thanks for the question regarding "Oracle Enterprise Edition", version 8.1.5
You Asked
We are planning to for oracle 8. Considering 3,00,000 users
which of the following you recommend
1) Oracle Enterpise Edition
2) Oracle Work group server

rgds
krishna
and we said...
The numbers of users that can use it is not as relevant as

o concurrent users (sessions)
o size of database
o needs of the application.

If the application needs bitmapped indexes, or partitioning, or
parallel operations, or function based indexes, etc -- that
would drive you towards EE.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76962/ch4.htm#73594
it will tell you what features/options are available with what
release.  You would make your decision based on that.
February 05, 2001 Vishal -- Thanks for the question regarding "About OWA cartridges", version 8.1.5
You Asked
I have recently downloaded the OWA replacement cartridge. I do
not have much knowledge about cartridges except the conceptual
knowledge. I would like to knowhow the cartridge can be
installed and what can it do?

I basically downloaded it because I want to compress the files
that I store in the database BLOBs. I am looking for a
compression technique that Oracle database supports. The OWAIGZ
was one option that I was looking for. Are there any other
options that I have in this regard.

Sincere Thanks,
Vishal
and we said...
owaigz compresses on the way DOWN when a user requests to
download a blob from the database.  It does not compress on the
way up.  The blob is stored "as is".

Since you have Oracle8i, you have the ability to use java.
There are many java based compression libraries out there.  You
can simply load them into the database and use them.  You would
write a java stored procedure callable from PLSQL that would
allow you to compress a blob.

Another option is to look at the code in the zlib subdirectory
of the owarepl distribution.  This is public domain C code that
implements gzip compression.  You could implement that as an
external procedure in C callable from PLSQL.  It would be
similar to the java suggestion but would not require the Java
option in the database.  In that fashion, you could send the
blob to the C code, it could compress it and write it back into
the database.
February 05, 2001 Loh -- Thanks for the question regarding "Group by column value", version 8.0.5.0.0
You Asked
Hi,
Suppose I have 10000 records to be processed, and each record has been assigned
a code eg. AP, TM, IS or RN. I would like to group the records according to this
column because I need to process the 'IS' records first, 'RN' records second,
followed by 'TM' & 'AP' codes. I need to process the records one by one, but in
the sequence of clearing the 'IS' records followed by 'RN' records, and so on.
How do I format the SQL statement so that I can process in this sequence? ORDER
BY and GROUP BY do not seem to help. Please advice.
and we said...
select *
  from T
 where ....
 ORDER BY decode( code, 'IS', 1,
                        'RN', 2,
                        'TM', 3,
                        'AP', 4,
                              5 )
/

will sort the data such that IS is followed by RN is followed by TM is followed
by AP is followed by whatever remains....
February 05, 2001 Murugavel -- Thanks for the question regarding "I want to insert or update records into some other database dynamically", version Oracle8
You Asked
Actually i have set a of records from a1 database by using
cursors. Now, I want to insert or update those records into some
other database dynamically. How to do this ? Somebody says to
user database link, i tried those also but i couldn't get proper
idea.

Please Help Me ?

I am waiting for u r reply.

Thank U

Regards
Murugavel.R - Cams
Programmer
and we said...
See
http://technet.oracle.com/doc/server.804/a58241/ch10.htm#4464
it shows how to use dbms_sql to dynamically copy data from one
table to another.  In your case, you will copy from table "T" to
table "T@another_site" where another_site is a database link
that you have setup.
February 05, 2001 Ashish -- Thanks for the question regarding "Migrating on different platforms", version 8.1.5
You Asked
HI TOM,

I had some doubts about migrating oracle database from one OS to
another. Let's consider that I have Oracle database 8.1.5 on
Solaris. If suppose I want to now upgrade it to 8.1.7 on windows
NT. Is it possible? Is it possible the other way (from NT to
solaris)? The export dumps from one OS can be imported in
another OS?please guide how to achieve thisthanks a lot in
advance,

regards,
ashish
and we said...
You would use exp/imp to perform the migration across operating
systems.  The export files are cross platform.  Care must be
taken to ensure that the system doing the IMP is *at least* at
the same version as the database doing the EXP or higher.  That
is, 8.0.5 IMP cannot work with an 8.1.5 EXP for example.  8.1.5
IMP however, can read and work with an 8.0.5 EXP.
February 05, 2001 Anand -- Thanks for the question regarding "Column Histograms ", version 8.0.5
You Asked
Hello Tom ,

We are moving a product from Sybase to Oracle . Sybase has a
option for Stored Procedures named "With Recompile " . This
makes the SP to be recompiled for every execution depending on
the user inputs given to the Stored Procedure .This is done so
that the Query Plan is generated on based on the paramaters
passed . With this option the query can execute using an Index
if the values are within a small range and go for a full table
scan if the range is large .

Oracle provides a similar feature using Column Histograms . But
the catch is that they have to be hard-coded and not sent as
parameters as Parsing Happens before Binding !!!

We are know passing them as parameters and we need to pass them
as only paramaters . Do we have work around for this ???

And in Oracle 8.1.5 There is OPEN RefCur For USING ...
Will this reparse the statement every time or only when
the Procedure is compiled .

Thanks in advance !

Best Regards ,

Anand Kumar S
and we said...
For those queries you want this to happen (not entire
procedures, just the query within) you would use

OPEN refcursor FOR

with constants (not binds) where you wanted them.  For exmaple,
say you have a table T ( x int, y int, z int );  You have
histograms on X and Y and would like queries that reference X
and Y to make use of them (but not on Z).  You could code:

create or replace procedure q( p_x int, p_y int, p_z int )
as
  type rc is ref cursor;
  l_cursor rc;
begin
  open l_cursor for
  'select * from T where x = ' || p_x || ' and y = ' || p_y ||
    ' and z = :z' using p_z;

  ......

ref cursors are always parsed with each open.  It'll be a soft
parse if the query matches one that is in the shared pool
already.
February 05, 2001 Dileep -- Thanks for the question regarding "Can I Use Global variable in Reports (6.0)", version Dev. 2000 (6.0)
You Asked
Sir,

   1. Can I Use Global variable in Report ?
      If No, Is there any other alternative is available ?

   2. I want to run a stored Procedure , without  any explict
      call,   after a particulat interval of Time. What I have
      to do ?
   3. What is the use of  ' Express Query ' In report ?
      Please give me  some examples ?

Dileep
and we said...
1) you can create a package in a PLSQL library that looks like:

create package my_globals
as
   var1   date;
   var2   int;
end;

then everything can see my_globals.var1 and my_globals.var2.
Just use a PL/SQL library.  that is one method.

2) dbms_job does this.  see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:302616534115
3) Express is an OLAP tool we have.  Express does some
interesting multi-dimensional queries and such.  It works with
data in a "cube".  See
http://www.oracle.com/ip/analyze/warehouse/servers/index.html?eserver.html
for details.
February 05, 2001 Shonda -- Thanks for the question regarding "MAXLENGTH", version version 8
You Asked
What property is equivalent to Maxlength on the report object
navigator for the parameter form?  Once you deploy the report to
the web, the report server generates HTML that gives the user
the ability to pass parameters.  It seems that the Width
property is converted to Size in the report server generated
HTML, however I'm looking to restrict the number of characters
the user can pass.  So…I need to add maxlength to the HTML code.
 Does Oracle have something that's equivalent….please help
and we said...
I asked Bob Bunting our resident reports expert this and he
says:

MAXLENGTH is set to the WIDTH property for the parameter found
under Data Model-->User Parameters.

Some additional information -

You may control the value of SIZE by creating a parameter form.
Double click on the icon next to "Parameter Form" in the
navigator to create a  parameter form. The SIZE is based on how
wide the field for the parameter is drawn. There is not a
property for you to set a specific number here. A few iterations
of changing the field size in the parameter form editor and you
should be able to get the value for SIZE you want. Any other
HTML attributes may be set by using the "Additional Attributes
(HTML)" property for a field under Parameter Form-->Fields.

The preceding information was verified under Reports 6i.
February 05, 2001 v.srinivas -- Thanks for the question regarding "Backup & recovery and regrading database triggers", version version 8.1.6
You Asked

   Hai Mr.Tom,

  Q 1)    How can I take backup of
database(tables,datafiles,tablespaces,controlfiles,redologfiles
& all database objects) when the oracle is not mounting.

  Q 2) Can we use database triggers in B2B applications.

  Thank You
  srinivas
and we said...
q1) if oracle is not running, you only need to take a copy using
any command you want of the

o datafiles
o controlfiles

that will get the database objects and tablespaces by
definition.  You never backup online redo log (unless you are
copying a "shutdown aborted" instance and are running in
noarchivelogmode).

q2) sure, you can use triggers in any application you want.
There is nothing special about b2b that would make it any
different from anything else.
February 05, 2001 Kashi Ram -- Thanks for the question regarding "Cursors For Loop", version VERSION 8.0.5
You Asked
Sir
I have two Questions :
Q1.
I want to open a curson depending upon the sql_string
that I form in My Procedure.Actually I take in some input
parameters and depending upon the value I form a Sql_string
with  certain conditiosn.Now I want to open a cursor with the
sql_string as my statement.But the open corsor for is expecting
a Select word.How I am supposed to Accomplish this?
Q2.
I want to connect to a different server depending upon
the input parameter in my Procedure.Will creating a DBLink
get stored in the Database and where (remote or local)?can u
throw some more light on
this.
Thanks for the Help in advance.
Kashi
and we said...
q1) you cannot dynamically open a REF CURSOR in Oracle8.0 and
before.  That is a feature of Oracle8i 8.1.5 and up.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
for what it would look like in Oracle8i.

In Oracle8.0, you will have to use DBMS_SQL to accomplish this.
If you search for dbms_sql on my site, you'll find lots of
examples

q2) you'll need to have a database link setup for the servers
you want to connect to.  Then, using dynamic sql with DBMS_SQL,
you can dynamically query 'select .... from t@' || p_database ||
' where ....'
February 05, 2001 Ansel -- Thanks for the question regarding "Word count", version 8.1.6
You Asked
How do I do an wordcount on the database. I know in DB2 there's
a build in function that does this for you.

Also what do I do if the data is stored in a long datatype which
I cannot do any operations on.

Thanks
and we said...
We do not have a wordcount function.  You may write one -- i
have one that will do almost what you want at:
http://osi.oracle.com/~tkyte/SkipCols/index.html
it was built for sqlldr and getting the i'th "word" from a
string but would work as well for counting words.

If the data is stored in a long datatype -- you are using the
wrong datatype in 8.1.6.  It would work best in a CLOB.  There
PLSQL can read and write the entire object.

PLSQL can read the entire long (but not write it) 32k at a time
using dbms_sql.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:665224430110
for an example.
February 05, 2001 Sunil -- Thanks for the question regarding "Incompatablity with import/export ", version 8.0.4
You Asked
I have Oracle 8.0.4 on NT and Personal Oracle 8.1.6 running on
windows 98. I have  a problem in importing into oracle 8.0.4
from an export file created in the 8.1.6 version. Is there any
way this can be done?
and we said...
You must use the 8.0.4 export tool against the 8.1.6 database.
You should be able to setup the listener against 8.1.6 allowing
the remote 8.0.4 install to connect over net8 to your database
to do the export.

If you just need to copy data, look at the sqlplus copy command
as well.
February 05, 2001 Joy -- Thanks for the question regarding "How can I prevent inserts on a given table from being written to the redo log?", version 7.3.4.0.0
You Asked
We are currently running on 7.3.4.0.0. and have a requirement to
stop inserts on a given table from being written to the redo
log.

Our reports write data to this table but its use is only
temporary and the data is deleted almost immediately.

Do you have any suggestions?

I am made to understand that in Oracle 8i, it is possible to
issue a NOLOGGING command to achieve this.  Is this correct?

Thanks.

Joy
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:485221567528
for details on nologging.  It won't do what you ask but a
GLOBAL TEMPORARY table in Oracle8i will remove a extremely large
percentage of the redo generated.

You cannot accomplish what you seek to do on version 7.3.

Example:

ops$tkyte@DEV816> create global temporary table tmp1
  2  as
  3  select * from all_objects where 1=0;

Table created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> create table tmp2
  2  as
  3  select * from all_objects where 1=0;

Table created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> set autotrace on
ops$tkyte@DEV816> insert into tmp1 select * from all_objects;

24193 rows created.

Statistics
----------------------------------------------------------
...
     126004  redo size
...
      24193  rows processed

ops$tkyte@DEV816> insert into tmp2 select * from all_objects;

24193 rows created.

Statistics
----------------------------------------------------------
....
    2691512  redo size
....
      24193  rows processed

ops$tkyte@DEV816> set autotrace off
February 05, 2001 Sharon -- Thanks for the question regarding "Can External Java call PL/SQL?", version 8.1.5
You Asked
We use Oracle8i, but we don't use OAS, we have lot of PL/SQL
code, Can external java call PL/SQL? and How? Should we have to
use stored procedure instead? or Should we have to use OAS? and
How to call PL/SQL from Java?

Thanks

Sharon
and we said...
Java, using JDBC, can call stored procedures easily.

see
http://technet.oracle.com/doc/oracle8i_816/java.816/index.htm
and specifically:
http://technet.oracle.com/doc/oracle8i_816/java.816/a81354/basic5.htm#1002489
....
February 05, 2001 Kalpesh -- Thanks for the question regarding "How can we pass value of a PL/SQL variable to Shell variable?", version 8.1.5
You Asked
I am using Oracle 8.1.5.
I have written one shell script.
I am executing pl/sql procedure into that.
I want the value of a pl/sql variable into the shell variable.
is it possible? If yes then how?
and we said...
Here is one method using the CSH (it'll be different in sh, ksh
and so on - the CONCEPT is the same but the mechanics/syntax
will be different)

----------------------------------------------
#!/bin/csh -f

cat > $$.sql <<EOF

set feedback off
set serveroutput on
set echo off
set termout off
spool $$.csh
declare
    l_most  varchar2(30);
begin
    for x in ( select object_type, count(*)
                 from user_objects
                group by object_type
                order by 2 desc )
    loop
        dbms_output.put_line( 'setenv MOST ' || x.object_type );
        exit;
    end loop;
end;
/
spool off
exit
EOF

sqlplus / @$$.sql
source $$.csh
echo The most frequently occurring object type is '"'$MOST'"'

rm $$.csh $$.sql
----------------------------------------------

The concept here is to have plsql write a script that contains
any settings the shell should get.  The shell will "source" that
newly generated script incorporating any of the environment
variables.

If you just need to get a numeric value back, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1342602684748
for an alternative implementation.
Review & Followup
Rating: 3
Passing Value of a variable from PL/SQL to Shell March 12, 2001
Reviewer: Kalpesh Patel from USA
It is really useful in creation of monitoring scripts in which you need to pass
the value of a PL/SQL variable to Shell.

February 05, 2001 David -- Thanks for the question regarding "Stored Procedure conversion from Sybase to Oracle", version 816
You Asked
Tom,

Thanks for your response.  I accidently drop a function that is
converted from Sybase stored procedure. I'm trying to re-write
it myself but I'm getting sorts of errors.  Please help me
correcting it, it's a small program, thanks.

This is what's in Sybase:
_________________________________

create proc GetExchangeRateToIndic
(@CurrencyID int=null,
 @SwiftCode char(3)=null,
 @ExchangeRateToIndic float output)
as
DECLARE @TargetSwiftCode char(3)

if ( @CurrencyID is null and @SwiftCode is null)
begin
        raiserror 31000 "You must specify either CurrencyID or
SwiftCode!"
        return
end

if ( @SwiftCode is not null )
        select  @SwiftCode=upper(@SwiftCode)
else
        select  @SwiftCode=SwiftCode
        from    MDSCurrency
        where   MDSCurrencyID=@CurrencyID

select    @TargetSwiftCode=SwiftCode
from     MDSCurrency
where    TargetIndic!=0

if ( @SwiftCode != @TargetSwiftCode )
begin
        SELECT  @ExchangeRateToIndic=MDSExchangeRate
        FROM    MDSCurrency
        WHERE   SwiftCode=@SwiftCode

        if ( @@rowcount = 0 )
        begin
                raiserror 31002 "SwiftCode", @SwiftCode
                return
        end
end
else
        SELECT  @ExchangeRateToIndic=1

return @ExchangeRateToIndic
_______________________________________________________

This is after re-written:

create or replace function GetExchangeRateToIndic
(CurrencyID in number default null,
 SwiftCode in varchar2 default null,
 ExchangeRateToIndic in out number)
return integer
as

StoO_rowcnt    INTEGER;
TargetSwiftCode char(3);
bad_data varchar2;
Begin
   if ( GetExchangeRateToIndic.CurrencyID is null and
GetExchangeRateToIndic.SwiftCode is null) then
    begin
      raise_application_error(-20999, 31000 || '-' || 'You must
specify either CurrencyID or SwiftCode!');
          return bad_data;
    end;
   end if;
   if ( GetExchangeRateToIndic.SwiftCode is not null ) then

GetExchangeRateToIndic.SwiftCode:=upper(GetExchangeRateToIndic.Sw
iftCode);
   else
     select  MDSCurrency.SwiftCode
       into GetExchangeRateToIndic.SwiftCode
     from    MDSCurrency
     where   MDSCurrencyID=CurrencyID;

    select    SwiftCode
    into TargetSwiftCode
    from     MDSCurrency
    where    TargetIndic!=0;
   end if;

   if (GetExchangeRateToIndic.SwiftCode != TargetSwiftCode )
then
           SELECT  MDsCurrency.MDSExchangeRate
           into GetExchangeRateToIndic.ExchangeRateToIndic
           FROM    MDSCurrency
           WHERE
MDSCurrency.SwiftCode=GetExchangeRateToIndic.SwiftCode.SwiftCode;

             StoO_rowcnt := SQL%ROWCOUNT;

           if ( StoO_rowcnt = 0 ) then
            begin
                  raise_application_error(-20999, 31002 || '-'
|| 'Invalid SwiftCode');
              return bad_data;
            end;
           end if;
   else
        GetExchangeRateToIndic.ExchangeRateToIndic:=1;
   end if;

return ExchangeRateToIndic;
end;
/
_______________________________________________________________-
and we said...
I believe it'll be this:

create or replace
function getExchangeRateToIndic
         ( p_currencyId          in  int default NULL,
           p_swiftCode           in  char default NULL,
           p_exchangeRateToIndic out number )
return number
as
   l_targetSwiftCode   char(3) default 'nav';
   l_swiftCode         char(3);
begin
  if ( p_currencyId is null and p_swiftCode is null )
  then
      raise_application_error
        ( -21000, 'You must specify currency or swift code');
  end if;

  if ( p_swiftCode is not null )
  then
     l_swiftCode := upper(p_swiftCode);
  else
     select swiftCode into l_swiftCode
       from mdsCurrency
      where mdsCurrencyId = p_currencyId;

     select swiftCode into l_targetSwiftCode
       from mdsCurrency
      where targetIndic <> 0;
  end if;

  if ( l_swiftCode <> l_targetSwiftCode )
  then
  begin
       select mdsExchangeRate into p_exchangeRateToIndic
          from mdsCurrency
         where swiftCode = l_swiftCode;
  exception
       when no_data_found
       then
            raise_application_error
               ( -21002, 'Swiftcode ' || l_swiftCode );
  end;
  else
      p_exchangeRateToIndic := 1;
  end if;

  return p_exchangeRateToIndic;
end;
/

COMMENTS:

- why do i use P_ (parameter) and L_ (local)?  So I don't have
to qualify stuff all over the place.

- why did I initialize targetSwiftCode to nav (Not A Value).
Becuase you probably rely on the Sybase'ism that:

if ( @SwiftCode != @TargetSwiftCode )

would be TRUE if swiftCode was NOT null and targetSwiftCode was
NULL.  It will not be True in Oracle -- comparisions of anything
to NULL is neither TRUE nor FALSE but UNKNOWN.  Hence, if you
ever sent in a NON null swiftCode, targetSwiftCode would never
get set and the comparision would always "fail" -- they would
"appear" to not be NOT EQUAL (but they ain't equal either).  If
you are relying on this, set targetSwiftCode to some value or
change the if to:

if ( l_swiftCode <> l_targetSwiftCode or
     (l_swiftCode is not null and l_targetSwiftCode is null ))
then
.....

- A select INTO will never set SQL%rowcount to zero.  It will do
one of 3 things:

  o succeed because it found at least one and at most one rows
  o fail and RAISE "NO_DATA_FOUND" because it found no rows
  o fail and RAISE "TOO_MANY_ROWS" because if found more then
one

you need to use an exception block around a select into.

SQL%ROWCOUNT is useful after inserts, updates and deletes.

- you never need a return after a raise or
raise_application_error.  Control will never get to that line of
code.
February 05, 2001 Manoj -- Thanks for the question regarding "How to group tables in tablespace", version 8.1.6
You Asked
Hi Tom (A well acknowledged name in Trouble shooter. Thanks for
that.)

I want to decide on the number of tablespaces in our database. A
few basic questions troubles me.

1) If a query uses join on 3 tables, is it better to keep them
in different tablespace and is it better that tablespaces should
be on different disk ?

2) Should their indexes should follow the same guideline as the
tables ?

3) is it good idea to keep static tables ( Which do not grow in
size after initial insertion of data) in locally managed
tablespace ?
and we said...
1) it is hard to say.  These days with raid devices, logical
volumne, striping, etc etc etc -- once we get to the "file"
level, who knows what we are dealing with...

It could by that by putting them in separate tablespaces,
because of the way you laid it out, that they end up being on
the same physical device.  It could be that if you had put them
in the same tablespace  - they might have used different
physical devices.

Now, for 3 tables -- given that you probably have hundreds or at
least dozens, it is pretty hard to optimize.  You have only so
many disks and you have lots of combinations (of tables with
indexes to other tables with indexes and other tables).

I put application tables in one tablespace.  I put their indexes
in another.  I stripe both either via >1 datafile per tablespace
on different devices or using os striping.  I then monitor the
IO and see if I need to move anything.

With apps as big as they are, its just too hard to come up with
an optimal (or even close) distribution -- even if you KNEW what
disk was going where.

2) ....

3) all data except system should be in locally managed if you
ask me.  I use nothing but.
February 05, 2001 Syed -- Thanks for the question regarding "Importing data from MS-Access into Oracle", version 8.1.6
You Asked
Hi Tom:

While importing data from a MS-ACCESS into Oracle using ODBC,
some of the characters are not imported properly.  For example
'10" cabel" in Access is becoming '10? cable' in Oracle.
Similary few other charcters like ('), (") etc becoming a (?) in
Oracle data field.

Are we missing any required set up?

Regards

- Syed

additional info:
===============

Oracle ODBC Version: 8.1.06

OS: SunOS alice 5.7 Generic_106541-11 sun4u sparc SUNW,Ultra-4

SQL> select * from nls_database_parameters;

PARAMETER                      VALUE
------------------------------
----------------------------------------
NLS_LANGUAGE                   AMERICAN
NLS_TERRITORY                  AMERICA
NLS_CURRENCY                   $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS         .,
NLS_CHARACTERSET               US7ASCII
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD-MON-RR
NLS_DATE_LANGUAGE              AMERICAN
NLS_SORT                       BINARY
NLS_TIME_FORMAT                HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZH:TZM
NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZH:TZM
NLS_DUAL_CURRENCY              $
NLS_COMP                       BINARY
NLS_NCHAR_CHARACTERSET         US7ASCII
NLS_RDBMS_VERSION              8.1.6.1.0

18 rows selected.
and we said...
You have created a 7bit database.   The 8bit data you have is
getting converted (high bit will be stripped).

You might consider converting that into the same character set
you use in Windows: WE8ISO8859P1.  thats the western european
8bit character set.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76966/ch3.htm#47136
for the steps to do that.
February 05, 2001 Ambarish -- Thanks for the question regarding "netsted tables", version 8.1.5
You Asked
Hi Tom,

Thanks for answering my previous question.

Please could you calarify a few more:

(a) Does Oracle support nested tables and varrays in triggers ?

(b) Given a table, how do i obtain the nested table type and
definition so that i could create another table with exactly the
same type.

I could use create table X as select * ...
but with that approach i would also be moving data. Is it
possible to specify a column list and to create the mirror table
without moving data from the source table.

Thanks
Chitnis
and we said...
a) yes. as of 8.1.5

tkyte@TKYTE816> create type myTableType as table of number
  2  /
Type created.

tkyte@TKYTE816> create type myArrayType as varray(50) of number
  2  /
Type created.

tkyte@TKYTE816> create table t ( a int, b myArrayType, c
myTableType )
  2  nested table c store as t_c_tab
  3  /
Table created.

tkyte@TKYTE816> create or replace trigger t_trigger
  2  before insert on t
  3  for each row
  4  begin
  5          :new.b := myArrayType(1,2,3,4,5);
  6          :new.c := myTableType(6,7,8,9,10,11,12);
  7  end;
  8  /
Trigger created.

tkyte@TKYTE816> insert into t (a) values (1);
1 row created.

tkyte@TKYTE816> select * from t;

         A
----------
B
-----------

C
-----------

         1
MYARRAYTYPE(1, 2, 3, 4, 5)
MYTABLETYPE(6, 7, 8, 9, 10, 11, 12)

b)
tkyte@TKYTE816> create table t2 nested table c store as t2_c_tab
as select * from t where 1=0;

Table created.

no data moves. the optimizer recognizes 1=0 for what it is and
does nothing.
February 06, 2001 Ramasubbu -- Thanks for the question regarding "Array of data into Nested Table", version Oracle 8i
You Asked
Hi Tom,
      I am using Oracle 8i,PL/SQL,Win NT platform.I am facing
problem in Nested table during array of data insertion.
say,

 My formula  object is
        FormulaObj
             (formulaType,
              formulaDescription,
              derivedValue)

Then I had created a nested table type is called "FormulaTab"

Then I had called in my table...

create table module_formula_table(
               div number(5),
               icno number(3),
               formulae FormulaTab)

Till now I am very perfect and I can insert a record also and I
can view the record also.

My requirement is
          "How to insert array of data into nested table"..or
otherwords "How to insert the records into Nested table by using
arrays"

For my practical scenario is
        "Inside of one calculation procedure I am getting all
values/various steps  which are related with calculation and I
am storing into various arrays which related with oject
declaration.

let say,
a)      cal_formula_type[1..n],it is array variable and storing
all formula types

b)    cal_formula description[1..n],it is array variable and
storing all formula descriptions

c)   cal_derivedValue[1..n],it is array variable and storing all
calculated values

Now I want to insert a record say...

1) insert into module_formula_table(10000,101,FormulaTab(
cal_formula_type[],cal_formula description[],cal_derivedValue[])

ex)
     insert into module_formula_table(10000,101,
                      FormulaTab('Xyz','Mimmal',34),
                      FormulaTab('Xy1','Maxmal',346),
                      FormulaTab('Xz1','Parabolic',234),
                      ...
                      ...
                      ...
                      ...
                      FormulaTab('Xw1','Hyperbolic',343))

In above ex,instead of values I want to use arrays for all
records.

2) insert into module_formula_table(10001,102,FormulaTab(
cal_formula_type[],cal_formula description[],cal_derivedValue[])

...
So values are populated dynamically and I want to insert only
once.So, for a single div & icno I want to insert a arrray of
values.This is my requirement.

I had refrered the oracle 8i doucmentation(topic Collections),it
is not sastisfied my requirments because they r given only
static values.

So please let me know that whether my apporach is correct or
not.But I want to use Nested table for this case.So incase my
approach is wroing(say array process method)...and give the
alternative solution......

Still If u need any more info about my question please let me
know the exact words....

Thank u very much Tom

regards
Muthu
and we said...
In PLSQL this is almost "trivial".  When you created that new
type, you actually extended the PLSQL language as well.  PLSQL
has that table type as a native datatype now.

Here is an example -- you just declare plsql variables using the
same types as your table.  They insert "naturally" (works on the
way out as well with selects)...

tkyte@TKYTE816> create type myScalarType
  2  as object (
  3  formulaType           varchar2(10),
  4  formulaDescription  varchar2(25),
  5  derivedValue        number
  6  )
  7  /

Type created.

tkyte@TKYTE816>
tkyte@TKYTE816> create type myArrayType as table of myScalarType
  2  /

Type created.

tkyte@TKYTE816>
tkyte@TKYTE816> create table module_formula_Table
  2  ( div           number,
  3    icno          number,
  4    formulae   myArrayType
  5  ) nested table formulae store as formulae_table
  6  /

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> declare
  2      l_variable   myArrayType := myArrayType();
  3  begin
  4      for i in 1 .. 5
  5      loop
  6          l_variable.extend;
  7          l_variable(i) := myScalarType( 'type ' ||
                              i, 'description ' || i, i );
  8      end loop;
  9
 10      insert into module_formula_table
 11      values ( 1, 2, l_variable );
 12  end;
 13  /

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816> select * from module_formula_table
  2  /

       DIV       ICNO
---------- ----------
FORMULAE(FORMULATYPE, FORMULADESCRIPTION, DERIVEDVALUE)
-----------------------------------------------------------------
-----------------------------------

         1          2
MYARRAYTYPE(MYSCALARTYPE('type 1', 'description 1', 1),
MYSCALARTYPE('type 2', 'description 2', 2),
MYSCALARTYPE('type 3', 'description 3', 3), MYSCALARTYPE('type
4', 'description 4', 4), MYSCALARTYPE

('type 5', 'description 5', 5))
Review & Followup
Rating: 4
This is it. January 21, 2002
Reviewer: Ranjan from San Francisco, USA
I was looking for some example and I got the one. Thanks Tom.

February 06, 2001 kakali -- Thanks for the question regarding "Resoring data", version Oracle 8.1.6
You Asked
Hi

Thanks for telling me the difference between the flag 'unused
column' and drop column in alter table command.

As stated flag 'unused column' doesn't reclaim the space, is
there any option by which data stored in the dropped column can
be restored even if the column is dropped .

Rgds
kakali
and we said...
No, no chance of getting it back once it is flag deleted other
then restoring the table to the point in time BEFORE the
deletion.

It is as good as gone.
February 06, 2001 Kashi Ram -- Thanks for the question regarding "Write into Client System", version version 8.0.5
You Asked
Sir
I want to write into the Client system by opening a file
at a particular location in the Client Machine.I think
UTL_FILE is for writing into the Server.I think there is
a TEXT_IO package for writing into the client machine.But
Desc Text_io returns object does not exist.Can u throw some more
light into TEXT_IO package?.Any sql I need to run
to load this Package

Thanks
Kashi Ram
and we said...
TEXT_IO is supplied with tools that have a CLIENT SIDE plsql
engine such as Oracle Forms, Reports, and Graphics.

Any and all PLSQL stored in the server runs in the server --
hence if text_io was in the database, it would work like
UTL_FILE.  It would have access ONLY to the servers file system
since that is where it executes.

SQLPlus does not have a client side plsql engine.

You can use SPOOL and DBMS_OUTPUT to achieve a similar effect.
If you find limitations to DBMS_OUTPUT, see:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:146412348066
which shows you a way to build your own.  Your plsql code would
call

  dbms_output.put_line( ..... );

instead of utl_file.put_line( filenhandle, ..... );

and you would SPOOL the output.

dbms_output is limited to 255 bytes/line and 1,000,000
characters of output per plsql call.

my_dbms_output (alternate implementation) is limited to 4000
bytes/line and as many characters of output as you have RAM on
the server.
February 06, 2001 Kashi Ram -- Thanks for the question regarding " When to Use Hint CACHE", version version 8.0.5
You Asked
Sir
What should be considered for providing the Hint CACHE
in a query?Is is dependable on the size of the table
or the relative size of the table compared to that of the
Database?Any general guideline to be followed in this
regard.Kindly suggest

Thanks
Kashi Ram
and we said...
<quote server tuning guide>
The CACHE hint specifies that the blocks retrieved for this
table are placed at the most recently used end of the LRU list
in the buffer cache when a full table scan is performed. This
option is useful for small lookup tables.
</quote>

Normally, when we full scan a table, we put the blocks at the
least recently used end of the LRU list -- we have the idea that
you will not need these discrete blocks again for any indexed
reads so we want to flush them.

If you have lookup tables, you might want to "warm start" your
database and have them cached.  This will let you full scan your
lookups and have them goto the MOST recently used (e.g. Don't
flush these blocks) end of the list.  As long as you use the
blocks, they will stay there.
February 06, 2001 Mohammed -- Thanks for the question regarding "script running slow", version 7.3.4
You Asked
Tom please help me with, why this sql script is running slow,
and also suggest how can we make it run fast.
=================================================================

/*-------- block1 -------------------------------*/
insert into table_1(sys_prefix
            ,sys_job_no
            ,job_no
            ,sys_job_descr
            ,creation_dt
            ,sys_enabled
         )
(select
'PX'
,tnumber
,'sync'
,description
,sysdate
,decode(nvl(completion_date,'01-JAN-90')
   ,'01-JAN-90','Y'
   ,'N')
from snap$_table_2 a
where creation_date = (select max(creation_date)
         from snap$_table_2 b
         where a.tnumber = b.tnumber)
);
/*-------- block2 -------------------------------*/
update table_1 a
set job_no = (select job_no from table_3 b
      where b.job_no = a.sys_job_no)
where sys_prefix = 'PX'
and exists (select 1 from table_3 c
where c.job_no = a.sys_job_no);
/*-------- block3 ------------------------*/
insert into table_1
(sys_prefix, job_no, sys_job_no, sys_job_descr, creation_dt)
select 'PX', job_no, 'sync', descript, sysdate
from table_3 a
where not exists (select 1 from table_1 b
where b.job_no = a.job_no
and sys_prefix = 'PX');
/*-------- block4 ------------------------*/
commit ;
and we said...
The way to make it go faster would be just to have:

commit;

(thats a joke, but it would run faster)

in it.  I see tons of correlated subqueries and such -- looking
at the first query for example

select
'PX'
,tnumber
,'sync'
,description
,sysdate
,decode(nvl(completion_date,'01-JAN-90')
   ,'01-JAN-90','Y'
   ,'N')
from snap$_table_2 a
where creation_date = (select max(creation_date)
         from snap$_table_2 b
         where a.tnumber = b.tnumber)
);

that has to full scan snap$_table_2 and for each row, it runs
another query to find the "max(creation_date)".  Hopefully

o (b.tnumber,b.creation_date) is indexed

o the high water mark of snap$_table_2 is as low as it can be.
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
for a method of obtaining your HWM.

You can try alternate methods of writing the query.  For
example:

select
'PX'
,tnumber
,'sync'
,description
,sysdate
,decode(nvl(completion_date,'01-JAN-90')
   ,'01-JAN-90','Y'
   ,'N')
from snap$_table_2 a,
    ( select tnumber, max(creation_date) max_dt
        from snap$_table_2
       group by tnumber ) b
where a.tnumber = b.tnumber
  and a.creation_date = max_dt
/

May run faster (might run slower).  I have no concept of the
cardinality of data, distribution, situation, etc etc etc.

If table_1 starts out "empty" for example, using an /*+ APPEND
*/ hint might be very useful.  It does a direct path
(unrecoverable) insert and generates lots less REDO entries.

For the update, if there is a unique index on table_3(job_no)
then it might be that:

update ( select table_1.job_no t1_job_no,
                table_3.job_no t3_job_no
           from table_1,
                table_3
          where table_1.sys_job_no = table_3.job_no
            and table_1.sys_prefix = 'PX' )
  set t1_job_no = t3_job_no
/

may be more efficient -- update the join instead of running so
many subqueries.

A tool that will help you greatly, that you already have, is
documented at:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/ch14_str.htm#1018
it'll show the plans in use, the ios done, the cpu time used,
the elapsed time and so on.
February 06, 2001 Kumar -- Thanks for the question regarding "SQL*Net data Security", version 8.1.5
You Asked
Hi Tom,

I want to know about SQL*Net data encryption. By default SQL*Net
use any encryption or not? If not then how to start encryption
for Oracle data transfer between Server and Client. Is there any
level or encryption use for SQL*Net data transfer? Also I want
to know, is there any tool/way to trap/decode the data that is
transferring over SQL*Net?

Thanks

Kumar
and we said...
See
http://www.oracle.com/ip/deploy/database/8i/index.html?advsec.html
by default only the PASSWORD used to connect is encrypted.  All
other data is sent in the clear.

To see what is sent, you can simply set:

trace_level_client=16
trace_directory_client = c:\temp
trace_file_client = sqlnet.trc

in the clients sqlnet.ora file and you'll get packet level dumps
in the sqlnet.trc file.
February 06, 2001 -- Thanks for the question regarding "how can we make one primary key as composite primary key ", version 7.3 or 8.04
You Asked
Hi tom
How r u?
I have one master table and so many child tables and I inserted
lot of records in my master table as well as in my child tables.
After inserting lot of rows I come to know that I need to make
two primary key columns on my master table and now I want add
primary key constraint to another column of the same table.

The question is that how can we make one primary key as
composite primary key with out deleting primary key constraint

Thank u
and we said...
The answer is: you cannot.  You must drop all of the child
foreign key constraints and rebuild them.  You are changing
their foreign key -- not just the parent key.  If this column
does not already exist in the child table -- you'll have to add
it.

the child foreign keys must all be rebuilt if you change the
parents primary key since a foreign key MUST point to a UNIQUE
or PRIMARY KEY constraint.
February 06, 2001 Faisal -- Thanks for the question regarding "triggers on Database Level", version Oracle 8
You Asked
Hi,

1)I know about the trigger on table level. I need to know if
there are any triggers on database level, I have a situation in
which i need to log certain things when ever a user logs on. One
way to this problem is to have a job using dbms_job procedure
and we could trak every user's log on, but it has performace
cost.

Situation:

A user logs on the database and a procedure ABC runs. how can we
run a defined procedure ABC to run the moment a user logs on.
There is no resriction of which user logs on, the user could be
any user, even the dba.

2) what is the differece between the approach when using
Oracle's Fine Grained Access Control AND assigning access
through Roles?

Regards

Faisal
and we said...
You only put Oracle8 in the version so I have no idea if this
applies or not.  In version 8.1 and up, we have database event
triggers.  One of the events is LOGON.  For a quick example see:
http://osi.oracle.com/~tkyte/Misc/NLSDateFormat.html
Since you ask about fine grained access control (a version 8.1
feature) I believe you might have 8.1....

Role cover object level grants.  via a role I can give you
access to the table T.

Fine grained access control goes down to the rows you can see.
Using FGAC I can grant you select on a table T via a role but by
dynamic query modification add a predicate of my choosing at
runtime to your query.

See
http://osi.oracle.com/~tkyte/article2/index.html
for details.
February 06, 2001 vrishali -- Thanks for the question regarding "Find out the size of the table.", version 8.1.6
You Asked
Hi Tom,

   We have one table in database with few millions of rows. I
want to find out how large is the size of table.
Can you please tell me how to calculate the total size of the
table in database?

Thanks
and we said...
well, you could just goto user_segments and see how many bytes
are allocated to it.

Or, you can get more details using the procedure outlined at:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
....
February 06, 2001 sadiq -- Thanks for the question regarding "reletional operators in decode", version version 8.0.3.0.0
You Asked
dear tom
this is my first question
how can i use >,<,>=,<= operators in decode
please explain with som example
and we said...
No, decode uses equality.

To a large degree we can use other functions to do this.
Consider:

ops$tkyte@ORA8I.WORLD> select a, b,
  2         decode( sign(a-b), -1, 'a<b',
                                0, 'a=b',
                                1, 'a>b',
                                   'unknown' )
  3  from t;

         A          B DECODE(
---------- ---------- -------
         5          4 a>b
         4          4 a=b
         4          5 a<b
         4            unknown
                      unknown
                    5 unknown

6 rows selected.

In Oracle8i, release 8.1.6, there is a new CASE operation:

ops$tkyte@ORA8I.WORLD> select a,b,
  2         case when a<b then 'a<b'
  3              when a=b then 'a=b'
  4              when a>b then 'a>b'
  5              else          'unknown'
  6         end
  7    from t
  8  /

         A          B CASEWHE
---------- ---------- -------
         5          4 a>b
         4          4 a=b
         4          5 a<b
         4            unknown
                      unknown
                    5 unknown

6 rows selected.

as well.
February 07, 2001 Robert -- Thanks for the question regarding "Are holes in a tablespace problematic", version 8.0.6.2
You Asked
At what point if any should we be concerned with dropping and
recreating indexes to reduce the number of holes?

We implemented a new process in one of our data warehouse
instances about 2 months ago. We are making the last 6 bitmap
index partitions unusable on our 4 largest fact tables just
prior to loading.  After the load jobs complete we rebuild these
24 index partitions. This is causing the number of holes to
increase in our index tablespaces.

Here is a snippet from my nightly space report:

     Pct Largest(Mb)
TABLESPACE                           Total(Mb) Used(Mb) Free(Mb)
    Free  Contiguous   Holes
------------------------------------ --------- -------- --------
-------- ----------- -------
DWWM_128K_X                             2043.0    887.8   1155.2
    56.5       374.4    1034
DWWM_1M                                  400.0    187.9    212.1
    53.0       212.1       1
DWWM_1M_X                               1000.0    459.1    540.9
    54.1       540.9       1
DWWM_512K_X                             8000.0   5049.1   2950.9
    36.9       693.2     711
DWWM_5M                                42000.0  36490.2   5509.8
    13.1      1450.0      23

The initial_extent = next_extent and pctincreas = 0.

Even though the tablespace name implies 128k we know that oracle
rounds this up to the next 5 block boundary making all extents
in this tablespace 160k since we have an 8k block size.
and we said...
As long as the holes are all the same size, the tablespace is in
great shape.  If they were varying sizes, that would be a huge
problem.

I would do nothing.  I really like the way you size them out.
You'll be a HUGE fan of locally managed tablespaces in Oracle8i
release 8.1.5 and up.
February 07, 2001 anthony -- Thanks for the question regarding "Table constraints & Export & Db link", version Oracle8.1.5
You Asked
Hi,
   Kindly clear my doubts please.

1. How to export & import database objects alone ( without
data)?
2. How to find all constraints(pk,fk,unique,check, not null &
default), datatype & length for a table and create script to
create the same table in another schema?
3. Please explain all the steps involved in database link
creation. I have created the database link, but its not working.

Thanks in advance
anthony
and we said...
1) rows=n can be passed to export to cause it to skip unloading
data or it can be passed to imp to skip loading of data.

2) easiest way is to:

exp userid=old_user/pw tables=That_Table rows=n
imp userid=new_user/pw fromuser=old_user touser=new_user

that'll create the table with all constraints and indexes.  If
you want to create it by hand as a sqlplus script, you will do
the exp as above but then:

imp userid=new_user/pw indexfile=that_table.sql full=y

that will not import the data but will write it to a sql file
for you.  For example, it'll take:

create table t
( x int primary key,
  y int not null,
  z char(1) check ( z in ( 'a','b','c' ) ),
  check (x+y > 55),
  unique(y)
)
/

create index t_idx on t(z,y,x)
/

and after:

exp userid=tkyte/tkyte tables=t rows=n
imp userid=tkyte/tkyte full=y indexfile=t.sql

t.sql has:

REM CREATE TABLE "TKYTE"."T" ("X" NUMBER(*,0), "Y" NUMBER(*,0)
REM NOT NULL
REM  ENABLE, "Z" CHAR(1)) PCTFREE 10 PCTUSED 40 INITRANS 1
REM MAXTRANS 255
REM  LOGGING STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1
REM MAXEXTENTS
REM  4096 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
REM BUFFER_POOL DEFAULT)
REM  TABLESPACE "USERS" ;

CONNECT TKYTE;

CREATE INDEX "TKYTE"."T_IDX" ON "T" ("Z" , "Y" , "X" ) PCTFREE
10 INITRANS
2 MAXTRANS 255 STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1
MAXEXTENTS
4096 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL
DEFAULT)
TABLESPACE "USERS" LOGGING ;

REM  ALTER TABLE "TKYTE"."T" ADD CHECK ( z in ( 'a','b','c' ) )
REM ENABLE ;
REM  ALTER TABLE "TKYTE"."T" ADD CHECK (x+y > 55) ENABLE ;
REM  ALTER TABLE "TKYTE"."T" ADD PRIMARY KEY ("X") USING INDEX
REM PCTFREE 10
REM  INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 131072 NEXT 131072
REM MINEXTENTS
REM  1 MAXEXTENTS 4096 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS

REM 1
REM  BUFFER_POOL DEFAULT) TABLESPACE "USERS" ENABLE ;
REM  ALTER TABLE "TKYTE"."T" ADD UNIQUE ("Y") USING INDEX
REM PCTFREE 10
REM  INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 131072 NEXT 131072
REM MINEXTENTS
REM  1 MAXEXTENTS 4096 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS

REM 1
REM  BUFFER_POOL DEFAULT) TABLESPACE "USERS" ENABLE ;

You just need to remove the CONNECT line and the leading REM's

3) you should have the tnsnames.ora set up on the server.  say
you have a tnsnames alias "remote_db" setup.  You can test this
from the command line of the server via:

sqlplus user/pass@remote_db

make sure that works.  Now, you should be able to:

create database link FOO
connect to user
identified by pass
using 'remote_db'
/

If you have global_names enabled (the default) then FOO must be
the global name of the remote database.  You can see what the
global name of the remote database is when you test the tns
connect string by "select * from global_name".

If you have a specific error, feel free to follow up.  "its not
working" is not descriptive enough to go into any detail.
February 07, 2001 -- Thanks for the question regarding "sql%rowcount and EXECUTE_IMMEDIATE function", version 8.1.5
You Asked
Hi Tom,

I use the following code:

    cmd:='insert into table xx
    select * from ... where ...'
    ;
    EXECUTE_IMMEDIATE(cmd);
    dbms_output.put_line(sql%rowcount||' rows inserted');

but each time, I get the debug message '1 row inserted'. Is
there a way to get that information even for the function
EXECUTE_IMMEDIATE ?

Thanks
and we said...
Are you using a FUNCTION execute_immediate you wrote or the
built in statement execute immediate?

Both can do this -- if you wrote your own, it just needs to be a
function the returns the rows affected.  If you use execute
immediate, sql%rowcount will be filled in.  for example:

ops$tkyte@ORA8I.WORLD> create or replace function
execute_immediate( p_sql in varchar2 )
  2  return number
  3  is
  4      cursor_name  pls_integer default dbms_sql.open_cursor;
  5      rows         pls_integer;
  6  BEGIN
  7      dbms_sql.parse(cursor_name, p_sql, dbms_sql.native);
  8      rows := dbms_sql.execute(cursor_name);
  9      dbms_sql.close_cursor(cursor_name);
 10      return rows;
 11  END;
 12  /

Function created.

ops$tkyte@ORA8I.WORLD> begin
  2          dbms_output.put_line(
  3          execute_immediate(
  4          'insert into t
  5           select user_id
  6             from all_users
  7            where rownum < 50')
  8          || ' rows...' );
  9  end;
 10  /
49 rows...

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> begin
  2          execute immediate
  3          'insert into t
  4           select user_id
  5             from all_users
  6            where rownum < 50';
  7
  8          dbms_output.put_line( sql%rowcount || ' rows...' );
  9  end;
 10  /
49 rows...

PL/SQL procedure successfully completed.
February 07, 2001 marc -- Thanks for the question regarding "User Call", version ORA 817
You Asked
Dear Tom,

Could you tell me what is exactly a USER CALL (in v$sysstat)
Thanks for your help,

Marc
and we said...
The number of user calls to the Oracle kernel. The total number
of calls to the Kernel should be reduced if possible.  The
performance Tuning Guide indicates how to setup  array
processing to reduce the number of calls to Oracle.   Also,
reduce the number of times you parse statements.  Instead of
coding:

   for( i = 0; i < 10; i++ )
   {
      parse
      open
      bind
      execute
      close
   }

code

  parse
  open
  for ( i = 0; i < 10; i ++ )
  {
    bind
    execute
  }
  close

for example.
February 07, 2001 san -- Thanks for the question regarding "Similar to Kernal Parameter", version 8.1.5
You Asked
1. Do we have "something for Windows NT" similar to "Kernal
parameters for Solaris". How we are going to configure the
kernel, shared memory, or semaphore parameters in NT
environment.
2. Where do I get documentation for Oracle 8i "System Level
Performance Tuning" for "Multiple Server" in "Windows NT
Environment".
3. These questions are might be "Out of Scope", even though I'll
be appriciated if you could please give me some explanation:

A. What is "Primary domain Controller" in terms of "Oracle 8i on
NT". How do I manage it in "Oracle 8i 0n NT" environment?
B. What is DNS, What is the use of DNS, how do I use it?
C. What is MMC (I know it's Microsoft product)? How we are going
to use this product in "Oracle 8i 0n NT" environment?
D. what is DHCP?

Thanks,
San
and we said...
1) not relevant on NT.  See
http://technet.oracle.com/docs/products/oracle8i/doc_index.htm
to get a copy of the Windows NT installation guide.  You only
need perform the preinstallation tasks.  Windows NT is very
different from Unix.

2) I'm not familar with that document -- do you have an actual
title?

3) a) see
http://whatis.techtarget.com/WhatIs_Definition_Page/0
4152,283996,00.html

it is a NT term.

b) distributed naming service, it is one method of translating a
hostname like "osi.oracle.com" into an IP address.

c) MMC is the Microsoft Management Console.
http://www.win2000mag.net/Channels/Windows2000/TopicResults.cfm?TopicID=46
has some articles on it.

How to configure the Oracle Management Snap-in within the
Microsoft Management Console (MMC):

1.    Install Oracle 8.1.5 or later on your system.
2.    Install Microsoft Management Console (which must be
        obtained from Microsoft if you are running Windows NT
        4.0) or Install Windows 2000.
3.    Go to Start/Run and type MMC and then enter.
4.    From the Console Menu select Add/Remove Snap-in.
5.    From Add/Remove Snap-in Window select Add.
6.    Select Oracle Primary MMC Snap-In and then click Add and
Close.
7.    Select OK.
8.    Save your Console.

You can now ready to manage Oracle from within Microsoft’s
Management Console.

d) dhcp is the dynamic host configuration protocol.  see
http://www.dhcp.org/
for details.
February 07, 2001 David -- Thanks for the question regarding "Union in select statement ", version 816
You Asked
Tom,

Can we use Order by, or group function such as Group by, Having
when using 'UNION'?
Can you list out what's acceptable and what's not.

Thanks.
and we said...
You can use them all

select ename, empno
  from emp
 union all
select dname, deptno
  from dept
 order by 2, 1
/

if you order by a UNION or UNION ALL, you typically order
"positionally".  Order by 2, 1 orders this query by the 2cnd
column then the 1st.

Alternatively, you can use an inline view:

select *
  from (
select ename, empno
  from emp
 union all
select dname, deptno
  from dept
       )
 order by ename, empno
/

and order by name.  As for group by and having, you can eithr
UNION a group by OR you can group by a UNION with the following
syntax:

select ename, max(empno)
  from emp
 group by ename
having max(empno) > 5
 union all
select dname, max(deptno)
  from dept
 group by dname
/

There we are unioning a group by, just put the having clause
in after any group by you want...

select ename, max(empno)
  from (
select ename, empno
  from emp
 union all
select dname, deptno
  from dept
       )
 group by ename
having max(empno) > 5
/

And there we GROUP BY a union, again putting the having clause
after the group by.
Review & Followup
Rating: 4
Simple Things June 07, 2001
Reviewer: Andy from Kuala Lumpur, Malaysia
Sometimes its the simple things that trip you up.  I was trying to put together
a select query with three sub-select quieries the deepest of which is a union
query.  Just looking through the notes on this suggestion helped me see where I
went wrong.  Thanks.

Rating: 5
Positively? January 25, 2003
Reviewer: A reader
Dear Tom,
Please tell me what you meant by "positively". The two plans are exactly the
same if the order by is used or not. Even when the individual selects use Oracle
Parallel Query the final task that Oracle does is Sort(Unique) which is parallel
to serial, and hence order by is always implicit.

Thanks

Rating: 5
Misread? January 25, 2003
Reviewer: A reader
Dear Tom,
Sorry I misread "positionlly" as "positively".
The reason I asked this question was, though the two plans when we add the order
by in Union and not are the same, the costs are different (the order by has the
higher cost). And, also the run time with the Order by is more. I would try to
include the example that I did on this.
Thanks

February 07, 2001 NOE -- Thanks for the question regarding "Mail ", version 8.05.2.1
You Asked
Excuse by the errors in the writing but it is a translation of
the Spanish to English.
The question is like making to send e-mail automatic from
developer 2000, taking into account that we have a server mail
of Lotus Notes Ver. 4.6 ?
and we said...
I do not have a specific answer for lotus notes as I have no
experience with that product, and I do not have it available to
me.

However, if lotus notes can send email from the command line, a
simple "host()" call from forms will do it.

If lotus notes supports ole automation, the following:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:319216860351
demonstrates what it might look like.  That is for
exchange, you would have to find out how to ole automate lotus
notes.

If lotus notes has a C dll file (API) you can call, the ORA_FFI
package is what you want to look at.
February 07, 2001 Howie -- Thanks for the question regarding "Truncating a Table", version 8.0.5
You Asked
Hi Tom

One of my friend told me as follow bu I am confused please
comment on this

"the TRUNCATE is that the space is reclaimed for the table but
the index space is not reclaim. All the data on the index is
gone but the space it was using before cannot be reclaimed
unless you drop and recreate the index. So if your index used
1MB of data each time you load the table, the index will grow
by about 1MB each time you reload data and will eventually run
out of extents. Also to help reclaim the same space for tables
the REUSE STORAGE option (TRUNCATE TABLE tablename REUSE
STORAGE;) is good so that your table doesn't get
extented in size more than needed."

Please explain with example

Thanks in Advacne

Howie
and we said...
Your friend is confused.

First, I believe he is confusing the MYTH that index space is
never reused when you delete a row from a table with truncate
(neither is true).  That is a TOTAL MYTH.  Space is reused in an
index and it can be reused not only by the value that used to be
there but by any value that fits there.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1336002638218
also, with respect to TRUNCATE -- that gives back 100% of the
space used by the table and the index.  First, if I leave off
the "REUSE" option, all but the minextents extents will be
returned to the system (for the TABLE an the INDEX).  If the
index took 1meg the first time and you truncate the table and
reload the same data -- it will take (surprise) 1meg again.  It
will not need another 1meg, it just needs its one 1meg.

If I use "REUSE" that will free all of the space in the table
and index -- it will not return these extents to the system.
These extents will be used by that table or index and that table
or index only.  If you truncate with REUSE and load *less* data
then before, you will have more space allocated then you need.
It will not affect performance until the object starts growing
-- then the space management overhead will not kick in until you
start to dynamically extend the object.
February 07, 2001 -- Thanks for the question regarding "Rman", version 8.1.6
You Asked
Tom

How does RMAN store the information in the catalog.  For eg, if
im backing up the database of size 20 gig having 15 datafile,
will it store the 20 gig information in the catalog.  What is
the sizing to be followed for creating the Rman catalog, is it
irrespective of size of the target db or changes accordingly.

Thanks

Sriv
and we said...
RMAN stores the data on tape or some other device.  The catalog
tells RMAN what it has stored and where.  the catalog does not
have the data.

Twenty Meg is the recommended minimum size for the catalog
tablespace datfile.
February 07, 2001 Kalpesh -- Thanks for the question regarding "How to measure the Performance of a Stored Procedure ", version 8.1.5
You Asked
Hi Tom ,
   I have some Stored Procedures in my database.
I want to know the some methods so that I can measure the
performance of those Stored Procedures.
   Actually I want time taken by it or CPU usage or disk scan or
table scan.
   I want all above values into some variables so that I can
monitor it using some monitoring tool.

Thanks in Advance
Kalpesh
and we said...
There are two tools you want to use.

1)
http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/ch14_str.htm#1018
describes sql_trace and tkprof.  sql_trace will trace the
execution time of the sql in your procedure.  It can show you
physical/logical IO's, cpu vs elapsed time, number of times
executed, rows operated on and so on.  You can use tkprof to
either create a report or a sqlplus script file to load the
stats into the database.

2) DBMS_PROFILER is a plsql source code profiler built in the
8.1.5 and up database.  In 8.1.5.0, the installation scripts are
not shipped with the server (should have been fixed in 8.1.5.1).
 You can either use metalink and refer to note 1076139.6 to get
them or contact support.

then see:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/dbms_pro.htm#1003424
....
Review & Followup
Rating: 4
Performance Measurement of Stored Procedure March 12, 2001
Reviewer: Kalpesh Patel from USA
Thanks Tom for such a useful information.
It is really a best way to find out where the problem is in our stored procedure
regarding performance issues.
The best thing is it is actually showing the query which is taking lot of
execution time in Stored Procedure.
   Thanks a lot.

February 07, 2001 -- Thanks for the question regarding "DESEncrypt and DESDecrypt", version 8.1.6
You Asked
Tom,

When I execute the follg :

variable x varchar2(25)
exec :x := 'How Now Brown Cow'

declare
l_data  varchar2(255);
begin
l_data := rpad( :x, (trunc(length(:x)/8)+1)*8, chr(0) );

dbms_obfuscation_toolkit.DESEncrypt
( input_string => l_data,
key_string   => 'MagicKey',
encrypted_string=> :x );
end;
/

I get this error, would like to know if i need to run some of
the standard sql provided by Oracle to make it error free.

declare
*
ERROR at line 1:
ORA-06550: line 6, column 1:
PLS-00201: identifier 'DBMS_OBFUSCATION_TOOLKIT.DESENCRYPT' must
be declared
ORA-06550: line 6, column 1:
PL/SQL: Statement ignored
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:788626212960
...
February 07, 2001 Michael -- Thanks for the question regarding "Coverting varchar2 to Long Raw (Binary) and insert in a file.", version Oracle 8.1.5
You Asked
Hi Tom,

I am trying to convert a varchar2 field in the buildings table
to a long raw and insert it on table FAC.  Below is my PL/SQL:

declare
  i long raw (32767);
  cursor c1 is select building_id from buildings;
  begin
  for cur in c1 loop
  i := cur.building_id;
  insert into fac(fac_id) values (i);
  exit when c1%notfound;
  dbms_output.put_line(i);
  end loop;
  end;

... I get the following error:

ERROR at line 1:
ORA-06550: line 6, column 12:
PLS-00382: expression is of wrong type
ORA-06550: line 6, column 3:
PL/SQL: Statement ignored

Can you please help..

Below is the first code I used:

 create table fac
  (fac_id long raw);

INSERT INTO FAC
  (fac_id)
  VALUES
  (HEXTORAW('AAAAAAAA'));

The above does not produce an error.. but when I go to display
the field I see only an 'A'.  I was expecting to see digits.

Thanks
and we said...
You are getting caught up in the implicit STRING <-> RAW
conversions.  UTL_RAW will help you out here.  Consider:

ops$tkyte@DEV816> create table t1 ( vc varchar2(25) );
Table created.

ops$tkyte@DEV816> create table t2 ( lr long raw );
Table created.

ops$tkyte@DEV816> insert into t1 values ( 'Hello World' );
1 row created.

ops$tkyte@DEV816> begin
  2      for x in ( select * from t1 )
  3      loop
  4          insert into t2 values ( UTL_RAW.CAST_TO_RAW(x.vc)
);
  5      end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

ops$tkyte@DEV816> insert into t2 values ( HEXTORAW('AAAAAAAA')
);
1 row created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> begin
  2      for y in ( select * from t2 )
  3      loop
  4          dbms_output.put_line
  5          ( UTL_RAW.CAST_TO_VARCHAR2(y.lr) );
  6      end loop;
  7  end;
  8  /
Hello World
????

PL/SQL procedure successfully completed.

ops$tkyte@DEV816>
ops$tkyte@DEV816>
ops$tkyte@DEV816>
ops$tkyte@DEV816> select to_number( 'aa', 'xx' ) from dual;

TO_NUMBER('AA','XX')
--------------------
                 170

ops$tkyte@DEV816> select chr(170) from dual;

C
-
?

ops$tkyte@DEV816>

UTL_RAW may not be installed on your system.  If not (there
would be a grant execute to public and a public syonym if it is
installed), simply:

o cd $ORACLE_HOME/rdbms/admin
o using SVRMGRL
o connect as INTERNAL or SYS (and only these 2 users, none
other)
o @utlraw
o @prvrawb.plb
Review & Followup
Rating: 5
Inserting into LONG RAW February 25, 2003
Reviewer: Anna Devore from Chico CA USA
Absolutely helpful -- and I enjoy your articles in the magazine.

I've been searching for how to do this -- all over Google and metalink.oracle
for over a year.  C was not an option, nor was any other format, so your answer
was a godsend.  I tried it.  It worked!!

February 07, 2001 Michael -- Thanks for the question regarding "Updating using three tables", version Oracle 8.1.5
You Asked
Hi Tom,

I created a temp table having a value that is needed on two
other
tables.  I want to write a PL/SQL to read the temp table and
update the two other tables with the corresponding value.

I have to find the match on the temp table with each of the
table and then update each field in the table.  Can you please
help.

Thanks
and we said...
You don't want to do this in a loop or anything, a simple update
will do.

first, I'll have to assume that the thing you search TEMP by is
"unique" -- it is a primary key of temp (else you have more then
1 row in temp to be applied to each row in the other two tables
and that won't work very well).  Assuming it is, we can just:

ops$tkyte@DEV816> create table t1 ( x int, data varchar2(25) );
Table created.

ops$tkyte@DEV816> create table t2 ( x int, data varchar2(25) );
Table created.

ops$tkyte@DEV816> create table tmp( x int,
  2                                    new_data varchar2(25) );

Table created.

ops$tkyte@DEV816> alter table tmp add constraint tmp_pk primary
key(x);

Table altered.

ops$tkyte@DEV816> insert into t1 values ( 1, 'before' );
ops$tkyte@DEV816> insert into t1 values ( 2, 'before' );
ops$tkyte@DEV816> insert into t1 values ( 3, 'before' );

ops$tkyte@DEV816> insert into t2 values ( 3, 'before' );
ops$tkyte@DEV816> insert into t2 values ( 4, 'before' );
ops$tkyte@DEV816> insert into t2 values ( 5, 'before' );

ops$tkyte@DEV816> insert into tmp values ( 1, 'after' );
ops$tkyte@DEV816> insert into tmp values ( 3, 'after' );
ops$tkyte@DEV816> insert into tmp values ( 5, 'after' );

ops$tkyte@DEV816> update ( select t1.data,
  2                                  tmp.new_data
  3                     from t1, tmp
  4                    where tmp.x = t1.x
  5             )
  6    set data = new_data
  7  /

2 rows updated.

ops$tkyte@DEV816> update ( select t2.data,
  2                                  tmp.new_data
  3                     from t2, tmp
  4                    where tmp.x = t2.x
  5             )
  6    set data = new_data
  7  /

2 rows updated.

ops$tkyte@DEV816>
ops$tkyte@DEV816> select * from t1;

         X DATA
---------- -------------------------
         1 after
         2 before
         3 after

ops$tkyte@DEV816> select * from t2;

         X DATA
---------- -------------------------
         3 after
         4 before
         5 after

update the join.  it does all of the work for us.
February 07, 2001 minnie -- Thanks for the question regarding "how to determine a SP by application?", version 8i
You Asked
Hi Tom,
There are an application used in a multiple end-users
client-server architecture and calling a stored procedure that
query a very large table by passing different values for
in-variable, if an end-user need to determine his application,
can i get the sid and serial# by getting some certain
information associated with that application, for example, by
V$SQL, V$SQL_TEXT, V$SQL_BIND_DATA,V$SQL_CURSOR and so on, so I
can write an DDL script in some application to kill the
correspending session?

I have an idea that is to get sid and serial# by querying V$SQL,
V$SQL_TEXT, V$SQL_BIND_DATA,V$SQL_CURSOR by a spectial bind
value
in SQL statement in SP, for example, "SELECT * FROM MYTABLE
WHERE :QUERY_SEQUENCE_NUMBER = :QUERY_SEQUENCE_NUMBER and other
where_clause ", in this SQL statement, QUERY_SEQUENCE_NUMBER
might be a value that assigned to a certain application calling
by the application. If we can get the bind value, I think, we
probably can get the sid and serial# for the SP

I searched a lot of materials in both metalink and archive list
of your website, found that it's difficult to get my goal, I
hope you have some idea.

thanks in advance.

Minnie
and we said...
Have each application make a call to

DBMS_APPLICATION_INFO.
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/dbms_app.htm#999107
Using this package, you can put upto 3 values into the v$session
view.  You can put for example

o your application name        V$SESSION.MODULE
o your "step" in the appl
  you are executing            V$SESSION.ACTION
o your bind value, to id
  your session                 V$SESSION.CLIENT_INFO

Now, you just need to look at V$SESSION.  Since you are doing
the query in the stored procedure, it'll be trivial to add this
call to dbms_application_info, just modify the sp and recompile
it.
February 07, 2001 Mike -- Thanks for the question regarding "Two Questions on Migrating from 7.3.4 to 8.1 in Unix Environment", version 8.1.7
You Asked
Hi Tom,

We're in the process of migrating from 7.3.4 and a couple of
questions have come up that I don't see much on in the
documentation.

1)  We have several scripts which spin through the oratab file
and determine whether an instance is up by checking for the
existence of sgadef{sid}.dbf file in $ORACLE_HOME/dbs.  With
8.1, this file is no longer produced.  I have read elswhere that
checking (ps -ef) for PMON or SMON for a particular instance is
a good universal method to substitute.  Is that right?  Does it
matter which one? Is there a better way without attempting to
login?

2)  I have used SQL*Loader for a long time on many versions of
Oracle on  Unix.  The command I have used has always been
'sqlldr'.  At the site I'm at now, all of the users have always
used 'sqlload'.  I have done an unscientific survey of other
Oracle versions here and find that 'sqlload' was a copy of
'sqlldr' under 7x, a symbolic link to 'sqlldr' under 8.0.6, and
is missing entirely under 8.1.7.  I plan to tell the user
community to change to the command 'sqlldr' as part of the
migration to 8.1.  Can you tell me the history of the 'sqlload'
command, why it was there in the first place (did we need an
alias?), and why it's gone now?  I know I could create a
symbolic link named 'sqlload', but I don't want to customize the
installation on dozens of servers to that level.

Thanks for you time,
Mike
and we said...
1) true the sgadef.dbf does not exist.  ps -ef for PMON is a
good alternate if you don't want to physically connect.  If
PMON, LGWR, DBWR, SMON isn't up, neither is the database.  Now,
there is a chance (as there is with the sgadef.dbf trick) that
you will FIND the process -- but the database is not actually
UP.  The lack of an sgadef.dbf or PMON can be used to show the
database is DOWN, but the existence cannot be used to show that
the instance is UP.  For that, you will need to connect.

2) I don't know the history or why it was removed however, bug
#1178490 was filed against this and the observation was made the
sqlload is obsoleted and not documented anymore -- the bug is
actually that the USAGE for sqlldr is incorrect:

> sqlldr

SQL*Loader: Release 8.1.6.2.0 - Production on Wed Feb 7 19:47:2
(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Usage: SQLLOAD keyword=value [,keyword=value,...]

Here is a support note on the issue:

Article-ID:         <Note:100322.1>
Circulation:        PUBLISHED (EXTERNAL)
Folder:             server.Utilities.SqlLoader
Topic:              Technical Articles
Title:              CANNOT USE SQLLOAD TO RUN SQL*LOADER
Open-Remarks:       See <RemarksOn:NOTE:100322.1>
Document-Type:      PROBLEM
Impact:             LOW
Skill-Level:        NOVICE
Server-Version:     07.03.0X to 08.01.0X
Updated-Date:       27-JUN-2000 15:09:35
References:
Attachments:        NONE
Content-Type:       TEXT/PLAIN
Keywords:           SQLLOADERINFO;
Products:           5/SQLLOADER;
Platforms:          UNIX;

Problem Description
-------------------

You are trying to use SQL*Loader to load some tables.  You have
read in the  Oracle Utilities manual that you can use the
command "sqlload" in addition  to the command "sqlldr" to run
SQL*Loader. You have used this "sqlload" command successfully in
Oracle7 but, in Oracle version 8i, you cannot.   It says that
the command is not found.

Solution Description
--------------------

In oracle version 8i, the symbolic link is left out from
O_H/rdbms/lib/ins_rdbms.mk.

Just run the command to create the symbolic link again.

> ln $(ORACLE_HOME)/bin/sqlldr  $(ORACLE_HOME)/bin/sqlload

Now, you can use "sqlload" to run SQL*Loader.

Explanation
-----------

In Oracle7, O_H/rdbms/lib/ins_rdbms.mk file creates a symbolic
link which allows the user to run sql*loader with the command
"sqlload" in addition  to the command "sqlldr".

In Oracle version 8i, O_H/rdbms/lib/ins_rdbms.mk file does not
create the symbolic link.  If you want, you can create the
symbollic link manually and use it.
February 07, 2001 Ambarish -- Thanks for the question regarding "creating nested table in other schema's", version 8.1.5
You Asked
Hi Tom,

Thanks for your last solution.

To take the same one step further on, lets say i have
a table trynested in scott's schema which has a nested column.

I connect as a user or as the DBA with the create any table
privilege.

I try creating a replica of this table in user demo's schmema
like this:

create table demo.trynested
nested table address store as demo_address
as select t.ename, t.address from scott.trynested t where 1=0;

I get an invalid datatype error. What's missing  here ? Do i
need to replicate the nested column type as well in demo's
schema ? If so is there a way to do so by reading the data
dictionary or by some other means ?

Thanks
Chitnis
and we said...
You are probably missing a grant on the TYPE scott created. demo
needs access to the type.  It *really* wouldn't work (it would
work even LESS) if demo created his "own" type since his type
would definitely be different from scotts.  Here is an example
showing the error and the solution:

sys@TKYTE816> grant connect, resource to demo identified by
demo;
Grant succeeded.

now, scott creates a table type and a table that uses it:

scott@TKYTE816> create type myarraytype as table of number;
  2  /
Type created.

scott@TKYTE816> create table t ( x int, y myarraytype ) nested
table y store as y_tab;
Table created.

scott@TKYTE816> grant select on t to demo;
Grant succeeded.

Demo has access to T BUT not t.y!

I get slightly different errors in 8.1.6 then in 8.1.5 but it is
for the same reason:

demo@TKYTE816> create table t as select * from scott.t;
create table t as select * from scott.t
                                      *
ERROR at line 1:
ORA-00942: table or view does not exist

demo@TKYTE816> select x from scott.t ;

no rows selected

demo@TKYTE816> select t.y from scott.t t;
select t.y from scott.t t
                        *
ERROR at line 1:
ORA-00904: invalid column name

demo@TKYTE816> desc scott.t
 Name                          Null?    Type
 ----------------------------- -------- --------------------
 X                                      NUMBER(38)
 Y                                      SCOTT.MYARRAYTYPE

obviously I can see the table, I can see X, i can see that Y
exists but I'm not allowed at it!

Go back to SCOTT and:

scott@TKYTE816> grant execute on myARrayType to demo;
Grant succeeded.

and now it works easily...

demo@TKYTE816> create table t nested table y store as y_tab as
select * from scott.t;

Table created.
February 07, 2001 hu -- Thanks for the question regarding "Compile oci program on Sco unix", version version 8.1.5
You Asked
Dear Tom:
    Does OCI support porgramming on Sco unix? How to comiple and

link the programme?
    Thanks.

                      Husong
and we said...
Yes, see the examples in $ORACLE_HOME/rdbms/demo

to make one of them, simply:

$ make -f demo_rdbms.mk cdemo1

for example.
February 07, 2001 Priscillia -- Thanks for the question regarding "Perform Binary Operation in Oracle???", version Oracle 8i
You Asked
Hi Tom,

I have created tables and used RAW as my char type.Strings of
Binary data ('00101')are inserted into the tables.I need to
extract these data and perform Binary Bitwise Operation
(AND/OR/XOR)in Oracle 8i for my project. Can Oracle support this
operation??? Is there any external packages available in the
market that enable me to do such computation..????

eg:  001
     111
     ---
XOR  110
AND  001
     ---
     000

I would appreciate very much if U could solve my problems ASAP

Thanks.

Have a nice day!!

Best Rgds,
Priscillia
and we said...
If you want to do this to NUMBERS (31 bit positive integers) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1284001741333
with RAWS, you can use UTL_RAW, it has bitand/or/xor/compliment.
 see:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/utl_raw.htm#998101
for details

UTL_RAW may not be installed on your system.  If not (there
would be a grant execute to public and a public syonym if it is
installed), simply:

o cd $ORACLE_HOME/rdbms/admin
o using SVRMGRL
o connect as INTERNAL or SYS (and only these 2 users, none
other)
o @utlraw
o @prvrawb.plb

And thats it, it'll be there now.
February 08, 2001 kenneth -- Thanks for the question regarding "Examples", version version 8.1.5
You Asked
Hey Tom,
          I am a newcomer to the world of ORACLE. I am trying to
find good sources of examples to guide my development path.
Presently I am trying to bring in forms and reports on a HTML
page. I'd like to locate one or more reports/forms surrounded by
additional HTML objects.

           Any help you could throw my way would be appreciated.

Thanks
Ken Fallon
and we said...
Technet is a great place to start.  discussion groups centered
around the products, all the manuals online, white papers,
samples....
http://technet.oracle.com/sample_code/index.htm
...
February 08, 2001 Tom -- Thanks for the question regarding "Global Temporary Tables", version 8.1.5
You Asked
Hi Tom,

Is is possible to create a trigger on a Global Temporary Table?

Thanks in advance,
Tom
and we said...
yes

tkyte@TKYTE816> create global temporary table tmp1 ( x int );

Table created.

tkyte@TKYTE816> create trigger tmp1_trigger
  2  before insert on tmp1 for each row
  3  begin
  4     dbms_output.put_line( 'Thanks for ' || :new.x );
  5  end;
  6  /

Trigger created.

tkyte@TKYTE816> insert into tmp1 values ( 55 );
Thanks for 55

1 row created.
February 08, 2001 Ambarish -- Thanks for the question regarding "updating nested tables", version 8.1.5
You Asked
Hi Tom,

I have a table trynested which has 2 scalar columns and a nested
table of varchar2.

SQL> desc trynested
 Name                                                  Null?
Type
 ----------------------------------------------------- --------
----------------
 PKCOL                                                 NOT NULL
NUMBER(38)
 ENAME
VARCHAR2(100)
 ADDRESS
MYARRAY

SQL> desc myarray
 myarray TABLE OF VARCHAR2(100)

SQL> select t.pkcol, e.* from trynested t, TABLE(t.address) e ;

    PKCOL
---------
COLUMN_VALUE
-----------------------------------------------------------------
------------
        1
40 new street

        1
hello sweetie

I am trying to update 40 new street to 10 new street

so i updated like you earlier suggested:

SQL> update TABLE(select t.address from trynested t where
t.pkcol = 1) P
  2  set P.address = '10 new street' where P.address like '40
new street';

                                        *
ERROR at line 2:
ORA-00904: invalid column name

The invalid column name is reported for P.address in the where
clause. Please could you let me know the error in the update.

Thanks
Chitnis
and we said...
Well, in the example you have -- as shown in the SELECT, the
columns name is COLUMN_VALUE (the default name we use for
un-named collections of a single scalar).

In my example, I created a scalar object type:

create type addrType
as object
( address varchar2(20), city varchar2(20) )
/

and then a table of that type:

create type addrListType as table of addrType
/

So, I had a column called address -- you do not, it is called
COLUMN_VALUE.

tkyte@TKYTE816> create type addrListType as table of
varchar2(20)
  2  /

Type created.

tkyte@TKYTE816>
tkyte@TKYTE816> create table t ( pk int, address addrListType )
  2  nested table address store as addressTab
  3  /

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> insert into t values ( 1,
  2  addrListType('10 new street',
  3               '11 new street' ) );

1 row created.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816>
tkyte@TKYTE816> select *
  2    from table( select e.address
  3                  from t e where e.pk = 1 ) p
  4  /

COLUMN_VALUE
--------------------
10 new street
11 new street

tkyte@TKYTE816> update table( select e.address
  2                  from t e where e.pk = 1 ) p
  3     set p.column_value = '40 new street'
  4   where p.column_value like '10%'
  5  /

1 row updated.

tkyte@TKYTE816> select *
  2    from table( select e.address
  3                  from t e where e.pk = 1 ) p
  4  /

COLUMN_VALUE
--------------------
40 new street
11 new street

tkyte@TKYTE816> rollback;

Rollback complete.
February 08, 2001 chakrapani -- Thanks for the question regarding "To get rid of Chained Rows", version 7.3.4.4
You Asked
Hi,

I saw a Dynamic SQL sript earlier in the archives ( or somewhere
... don't remember exactly ) which automatically removes all
chained rows.

This script disables the triggers on the table, disables he
constraints, truncates the table and then inserts the rows back
into the table.

Can you send me that script ?

thanks a lot.

-chakrapani
and we said...
I never had such a script -- I would never do such a thing.

To get rid of chained rows:

1) run utlchain.sql found in $ORACLE_HOME/rdbms/admin.  it
create a table chained_rows

2) analyze table T list chained rows into chained_rows;

3) create table t_tmp as select * from t where rowid in ( select
head_rowid from chained_rows );

4) delete from t where rowid in ( select head_rowid from
chained_rows );

5) insert into t select * from t_tmp;

6) drop table t_tmp; (don't do this until you are satisfied the
data is back in T)
February 08, 2001 Zsolt -- Thanks for the question regarding ""Silent" exceptions", version 8.1.5
You Asked
Hi Tom,

I have Select into statment.
If there is no data I got an error message (no data etc.).

I'd like the Oracle to display no message at all.

In Delphi there is a so colled silent exception for this :
Abort.

Can I make this in Pl/Sql e.g.

  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      don't raise any error!!!!

Thank you
and we said...
sure, you would code:

  begin
     select x into y
       from t
      where ...
  exception
     when no_data_found
        then null;
  end;

I would RECOMMEND however that in the no_data_found handler, you
set Y to some NULL value, else the value in Y is "unreliable".
February 08, 2001 vrishali -- Thanks for the question regarding "Installing 8.1.5 on same machine which contains 8.1.6", version 8.1.6
You Asked
Hi Tom,

  We have 8.1.6 dtabase on solaris machine. We want to create
8.1.5 database on same machine without removing 8.1.6

Could you please tell me how to do it?

Thanks
and we said...
Sure, you would simply install 8.1.5 into its own Oracle home.
that is it.  Nothing more, nothing less.

If you wanted, you could setup an ora815 unix user and install
into a totally separate unix account all together (no chance of
overwrites of anything that way, permissions won't allow it)
February 08, 2001 Ambarish -- Thanks for the question regarding "updating nested tables and scalar columns in a single update", version 8.1.5
You Asked
Hi Tom,

Thanks for your solution.

How do i update a nested column and a scalar column in a single
update ?

Consider a nested table trynested(a int primary key, b varchar2
(10), c myarray)

where myarray is table of varchar(2).

lets say for a = 1, i have b = 'test' and c =
myarray('1','2','3')

Is it possible to update b to 'test1' and the third element of c
which is '3' to '4' ? I could do this in a two piece update with
transaction semantics. Can i do this in a singular update ?

Thanks
Chitnis
and we said...
First of all and VERY importantly -- there is simply no such
thing as the "third element" of a nested table.  A varray, yes,
a nested table -- no.  You have a nested table element with the
value '3', you would like that to be '4'.

You would have to update the entire collection, you would not be
able to modify an individual "row" within the collection.

You can definitely do this in two updates with "transaction
semantics".

Here are two ways.  One straightforward, the other infinitely
more obscure:

tkyte@TKYTE816> create type myArray
  2  as table of varchar2(2)
  3  /

Type created.

tkyte@TKYTE816>
tkyte@TKYTE816> create table t
  2  ( a int, b varchar2(10), c myArray )
  3  nested table c store as c_tab
  4  /

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> insert into t
  2  values
  3  ( 1, 'test', myArray( '1','2','3') );

1 row created.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816> select * from t;

         A B          C
---------- ---------- -------------------------
         1 test       MYARRAY('1', '2', '3')

tkyte@TKYTE816> update t
  2     set b = 'test1',
  3         c = myArray( '1', '2', '4' )
  4   where a = 1;

1 row updated.

tkyte@TKYTE816> select * from t;

         A B          C
---------- ---------- -------------------------
         1 test1      MYARRAY('1', '2', '4')

tkyte@TKYTE816> rollback;
Rollback complete.

tkyte@TKYTE816>
tkyte@TKYTE816> update t
  2     set b = 'test1',
  3         c =
  4         ( select cast
  5                 ( multiset
  6                    ( select decode(column_value,
  7                                    '3','4',
  8                                     column_value)
  9                        from TABLE( select t2.c
 10                                      from t t2
 11                                     where a=t.a )
 12                      ) as myArray
 13                  ) from dual
 14         )
 15       where a = 1
 16  /

1 row updated.

tkyte@TKYTE816>
tkyte@TKYTE816> select * from t;

         A B          C
---------- ---------- -------------------------
         1 test1      MYARRAY('1', '2', '4')

tkyte@TKYTE816>
Review & Followup
Rating: 4
It was of course April 01, 2003
Reviewer: A reader
thanks - very useful hint - but i shall stick to update the table with new
values of the array!

February 09, 2001 Matthew -- Thanks for the question regarding "Get server local hostname", version 8.1.6
You Asked
I'm wondering how to get the local hostname of an Oracle
database through a stored procedure.

I wrote the following Java code and loaded it into the database
and wrote a PL/SQL SP wrapper:

public class InfrastructureSPs extends Object {

    /** Private constructor:  Can't instantiate this object */
    private InfrastructureSPs()
    {
    }

    /**
    * @param args the command line arguments
    */
    public static void main (String args[])
    {
        System.out.println(getServerHostname());

    }

    /**Returns local hostname, or "unknown host" if the hostname
is unknown*/
    public static String getServerHostname()
    {
        try
        {
            return
java.net.InetAddress.getLocalHost().getHostName();
        }
        catch(java.net.UnknownHostException e)
        {
            return "unknown host";
        }
    }

}

Now everything works just fine, except that I get "localhost" as
the name!  While that will work for apps on the local machine, I
am much more interested in getting the network hostname.

Interestingly enough, the Sun JDK DOES return the local network
hostname when run on my Windows box, but the Oracle JVM returns
"localhost" instead.

Anyway, I'm wondering if you know of a built-in PL/SQL function
I can call to get the network hostname for the DB server, or
else a built-in java library function I can use to do the same
thing.

Thanks for all your previous help,

Matthew Cromer
and we said...
you need either to

  8    dbms_java.grant_permission(
  9       grantee => 'TKYTE',
 10       permission_type => 'java.net.SocketPermission',
 11       permission_name => '*',
 12       permission_action => 'resolve'
 13    );
 14  end;
 15  /

or grant javasyspriv to user (in 8.1.6 and up, dbms_java is
preferred, much more granular).

Then, we can resolve hostnames.  I've no idea why InetAddress
isn't flinging an exception -- it should.

We are running in the "sandbox" in the database.  See
http://java.sun.com/j2se/1.3/docs/api/java/security/Permission.html
And
http://technet.oracle.com/doc/oracle8i_816/java.816/a81353/toc.htm
...
February 09, 2001 Priscillia -- Thanks for the question regarding "How to call a function (Pro C) in Oracle 8i environment???", version Oracle 8.1.6
You Asked
Hi Tom,

I have another three questions to ask U. Hope U can reply me as
soon as possible. They are:

1)I need to perform a Binary Bitwise operation but it can onle
be done in c language & not in SQL stetement..How to call a
function (using Pro C) in oracle 8i environment and return the
computation results??? CAn U advise me with examples???

2)How to call an executable program in Oracle 8i????

3)Tell me more abt CREATE OPERATOR (with examples)

Thks ...

Best Rgds,
Priscillia
and we said...
1) You do not need to call C to do binary operations such as
AND, OR, XOR...  These can ALL be done easily in SQL

If you want to do this to NUMBERS (31 bit positive integers) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1284001741333
with RAWS, you can use UTL_RAW, it has bitand/or/xor/compliment.
 see:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/utl_raw.htm#998101
for details

UTL_RAW may not be installed on your system.  If not (there
would be a grant execute to public and a public syonym if it is
installed), simply:

o cd $ORACLE_HOME/rdbms/admin
o using SVRMGRL
o connect as INTERNAL or SYS (and only these 2 users, none
other)
o @utlraw
o @prvrawb.plb

And thats it, it'll be there now.

If you want to call C (and that'll be much less efficient both
in your personal time -- the code is already written for you and
in system time), see the application developers guide -- the
chapter on external procedures.

In this case, the builtin functionality will be superior.

2)
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:952229840241
3) as for the operators, unless you are going to build your own
datatype, they are not very relevant to you.  The only examples
I have, as I've never seen the need myself to date to create an
entire new datatype for myself, are in:
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76937/toc.htm
and specifically:
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76937/dci07id3.htm#620608
...
February 09, 2001 shamim -- Thanks for the question regarding "is any way to trap IP ADDRESS of a client on net using form 6i ", version ver 8.1.5
You Asked
Dear Tom
 hi
I am using forms 6i ,I want to trap ipaddress of a person who
uses our application, which is built in forms6i/oracle8i (8.1.5)
on net

 is there is any mean in forms  to trap ip address , if it is ps
tell me  using an example.
thanks in advance
shamim
and we said...
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:510222107880
...
February 09, 2001 Hisham -- Thanks for the question regarding
      "Recursion of triggers", version 8.0.5

      You Asked
Hi !

I have a table with 3 columns - ColA, ColB & ColC.

My requirement: After inserting values to ColA & ColB, the
trigger program should perform a self insert to add another
record to the table interchanging the values of ColA & ColB.

I tried this out with an after insert trigger but was issued the
error "mutating table".

Please specify as to how this can be accomplished using any
approach.

Thanks

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:156812348067
for a method of doing this.
February 09, 2001 Op -- Thanks for the question regarding "Dynamic
      Temp table", version 8.1i

      You Asked
Hi Tom,

I would like to create temp table dynamically for each
session.When the session is exit temp table will drop
automatically.

Like in Sybase you can create table with #temp it will create
temp table with a unique sequence no for each session.

The main table name is temp fro everybody.

How I can do the same in Oracle 8i

Thanks

opde

      and we said...
You don't want to do that in Oracle.  It is not necessary, it is
not the proper way to use temporary tables in Oracle. You will
find that what is normal and proper in Oracle is not doable/not
normal in Sybase and vice versa.

DDL is very expensive, it commits a transaction and is a
serialized process.  You do not want to do DDL on a recurring
basis.

Our stored procedure model is very different from sybases.  In
order for the stored procedure to be able to access the
temporary table without resorting to using only dynamic sql, the
table must exist at compile time.

Temporary tables in Oracle are created once per database and
used by many people simultaneously.  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:48812348054
for an example.  Take my advice though -- do not, repeat do not
create a temporary table for each user/procedure call.  That
would just be wrong in Oracle.

Review &
      Followup

      Rating: 3
temporary
      table  August 12, 2003
Reviewer:  vivek
       from uk
Tom,

I am creating temporary tables dynamically in one of mine procedure and then
read one of your thread where you have mentioned

"DO NOT dynamically create them, DO NOT dynamically create
them, please -- do NOT dynamically create them."

Could you please suggest best way to handle this situation.

My client is going to create Work orders and these workorders will be created by

their vendors based on 'Contract number' issued to them.
Now vendors are approx. 150 in number and contract number issued per financial
year could be in range of 500-600.
What i am doing is creating temporary table based on contract number (which will

be unique) and then process the result.

Now after reading this thread, i am not sure, is this the correct method for
this situation. I know the table structure before hand but want to have separate
table for each contract number.

could you please advise us on this.

thanks

Vivek

February 09, 2001 Betty -- Thanks for the question regarding
      "Tablespace Recovery", version 8.1.6

      You Asked
Tom,

I have a development system, which I make RMAN backups of by
tablespaces before the developetors start their testing.  Each
developetor has their own tablespace with a set of tables.  When
the developetor is finished with their tests they need the
tablespace (tables) reset to the original backup.  Is there a
way to use RMAN recovery for the selected tablespace to reset
their data?  Right now we are also taking Exports of the
Users(developetor) and using Imports to restore data.

Thanks,
Betty

      and we said...
Sounds like you really want a transportable tablespace.  It
would be much faster.  You can transport out a copy of the
tablespace (indexes, everything in the tablespace) and when you
want you will just drop that tablespace including contents and
then reattach the previously transported tablespace -- all data,
indexes, etc will be intact.

This will be much easier then using RMAN to do a tablespace
point in time recovery.

See

http://technet.oracle.com/doc/oracle8i_816/server.816/a76955/ch01.htm#40944
for details.

February 09, 2001 pauline -- Thanks for the question regarding "how
      to convert dictionary managed TS to locally managed TS in 8.1.5?", version
      8.1.5

      You Asked
Hi Tom,
You highly recommend to use locally managed tablespace
to avoid tablespace fragmentation. As I know, Oracle 8.1.5 has
no functionality to migrate dictionary managed tablespace to
locally managed tablespace due to
dbms_space_amdin.tablespace_migrate_to_local
is not available in this release.
Now the question becomes if I really want to use locally managed
tablespace for our database, what is the good way you may
recommend?
Thanks in advance.

Pauline

      and we said...
I would in ANY case create a new tablespace and use the alter ..
move and alter ... rebuild commands to move the objects into
there.  In 8.1.5 there is no way to migrate a dictionary to a
locally managed.  That is new with 8.1.6.

Migration of a dictionary to a local does not give you the major
benefit of uniform sizing.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:47812348053
for pointers on doing that.

February 09, 2001 -- Thanks for the question regarding "Failed when
      run cdemo2.c program", version 8.0.5

      You Asked
OS: UNIXWARE v 7.1.1
ORACLE: 8.0.5

When I run the cdemo2 program on UNIX, after enter username and
password, I got "open of async device failed: Permission denied"
 The username and password are correct because I'm able to
access the account from the client site (WinNT)

I also found the same error when I start running the database
using dbstart program.

Please help

Thanks
HN

      and we said...
Oracle is trying to read or write to /dev/async but does not
have permissions
to do so.

 Modify the permissions on /dev/async so that Oracle can access
the file.

  %: cd /dev
  %: chmod 666 async

By modifying the permissions you allow oracle to read or write
the /dev/async device.

February 09, 2001
      wallacel -- Thanks for the question
      regarding "should i store datetype as well as raw data?", version 8.1.6

      You Asked
Tom:

we have requirement to store some picture inside the database,
what should i do? create a table with a blob column?
but if that's the case, how do i know the format of the data?
such as Gif,jpag,bmp?  where is this kind of information stored?

should i store datetype as well as raw data?

Regards,

      and we said...
You would store the image in the blob and then other scalar
information about the image in regular columns.

You might consider interMedia image as it will auto-recognize
images and parse out many valuable pieces of information such as
height/width, color planes (color depth) and so on.  It can
scale, crop and do other simple image things as well.

see

http://technet.oracle.com/doc/oracle8i_816/inter.816/index.htm
...
February 09, 2001 wallacel -- Thanks for the question regarding
      "export import between different db_block_size?", version 8.1.6

      You Asked
Tom:

can i export and import between database with different
db_block_size?

      and we said...
yes, export stores data as data, not as database blocks.  you
can use different block sizes and operating systems.
February 10, 2001 Stanley -- Thanks for the question regarding
      "table sizing", version 8.1.6

      You Asked
hi tom,
can u give me a link where i can find info abt sizing tables and
indexes?
I am confused abt sizing numbers, one book says to allocate 21
bytes for NUMBER.
I can see that TOAD uses the same logic.
What will be the sizing for cols having datatype like
NUMBER(5, 2) or NUMBER(3) etc rather than plain NUMBER?

thanks in advance.
Stanley

      and we said...
I guess this is in followup to the question:

hi tom,
i have a table with the following structure.
pct free is 10
 Name                  Null?    Type

 EMPNO                NOT NULL NUMBER(3)
 ENAME                         VARCHAR2(10)
 MGRNO                         NUMBER(2)

i calculated it manually using the method shown in
oracle dba certification program guide,
the average row length was 58.
.....

Numbers are always stored in varying length strings.  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:147812348066
for an example.  The formula is in the server concepts
manual.  It is a function of the number of significant digits in
the number itself.

Note: the ONLY way to really accurately size a table is to load
it with a small percentage of the real data, analyze it, and
multiply.  All formulas are widely inaccurate.  If I have a
number(5) field but only store the numbers:

1
10
100
1000
10000
2
20
200
2000
20000
(and so on)

in it - that'll take lots less space then if I store

1
11
111
1111
11111
111111

and so on.  Block overhead, Number of columns (things get
interesting over 255 columns), pctfree, how many rows we decide
to put on a block and so on impact the formula in such a way as
to render then unrealistic.  They are typically good for finding
an absolute UPPER bound on the size of the object.  None of them
are good for sizing IOTs, HASH clusters, compressed indexes,
bitmapped indexes, etc etc etc.

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:302216525000
for more details.

February 10, 2001 Jennifer -- Thanks for the question regarding
      "Collection Unnesting", version 8.1.6

      You Asked
Try to understand following SQL
SELECT t1.department, t2.*
   FROM hr_info t1, TABLE(CAST(MULTISET(
      SELECT t3.name, t3.dept, t3.sal FROM people t3
      WHERE t3.dept = t1.dept)
      AS NESTED_PEOPLE)) t2;

specially
TABLE(CAST(MULTISET(
      SELECT t3.name, t3.dept, t3.sal FROM people t3
      WHERE t3.dept = t1.dept)
      AS NESTED_PEOPLE)) t2

Can you tell me where I can find out about CAST, MULTISET at
Oracle Doc? Tried Oracle8i Application Developer's Guide -
Object-Relational Features, PL/SQL user's Guide, SQL Reference,
couldn't find it.

Thanks

Jennifer

      and we said...
It is in the SQL Reference manual:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/express2.htm#1017895
...
February 10, 2001 tony -- Thanks for the question regarding
      "EXAMPLE FORMS", version FORMS 6I

      You Asked
1. Where can I find PL/SQL procedures and Triggers to use in my
forms?
2. Where can I find sample Forms and Report to view theire
functionality ?

Thank You

      and we said...
http://technet.oracle.com/sample_code/index.htm
...
February 10, 2001 Guru -- Thanks for the question regarding "About
      DBMS_PIPE", version 7.3/8

      You Asked
Dear Tom,

   I created a user & i granted connect, resource & dba roles to
the new user.  When i was trying to execute a pl/sql using
DBMS_PIPE & DBMS_ALERT, it was giving compilation error.  I then
granted the execute permission on these packages to the new
user, then it worked.  By granting dba, resource does these
permission will not be granted.  If not is there any other
Oracle role which i have to grant to get the execute permission.

Thanking You,
Guru Prasad M.R.

      and we said...
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
...
February 10, 2001 -- Thanks for the question regarding "Some useful
      doubts !!!", version 8.1.7

      You Asked
Hello Tom,

Can you please help me to find....

1) How to display time taken to execute a query. for example
when I search for a perticular word on this webpage, at the end
it is displaying time.  Is it possible at SQL prompt ?

2)I am using 8.1.5 on Redhad 6.2.  When I tried to migrate an
existing tablespace to LOCAL it displayed following error...
SVRMGRL> BEGIN
          DBMS_SPACE_ADMIN.MIGRATE_TABLESPACE_TO_LOCAL('TEMP');
         END;
          /
 ORA-00406 : COMPATIBLE parameter needs to be 8.1.6.00 or
greater.  But when I query v$version it is displaying 8.1.7.0.0
, But in parameter file I found compatible="8.1.0",  Where I am
missing ?

3) I want to use active 'x' controls in forms.  Can you please
give me resource on this topic. any tutorial links..please!

4) We need to take reports on a perticular date..
    select * from inv_det where trunc(inv_dt) = truc(sysdate);
        or
 ...where
to_char(inv_dt,'DD.MM.RR')=to_char(sysdate,'DD.MM.RR');

But this will bypass index on it, How should I make use of index
on it ?

5)I am having following default parameters in my parameter
file..

parallel_server = false
parallel_server_instances = 1
parallel_broadcast_enabled = false
parallel_adaptive_multi_user = false
parallel_threads_per_cpu = 2
parallel_automatic_tuning = false
optimizer_percent_parallel = 0
parallel_min_servers = 0
parallel_max_servers = 5
parallel_execution_message_size=2148

How I can make use of PARALLEL QUERY option ?

6) What is the best way to avoid/check duplicate entries in a
form's detail block rather than running a loop.  My forms
version is 5.0

Thanks for your attention & help,

best regards
mubeen

      and we said...
1) in sqlplus, just issue:

SQL> set timing on

2) set your compatible init.ora paramter to 8.1.6 as the error
message states.  Your version might be 8.1.7, but your
COMPATIBLE (which enables/disables features) is set to 8.1.0

see also

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1424204062157
i would not use that routine.

3)
http://technet.oracle.com/
and join the discussion groups. They'll be able to help
you out.

4) instead of:

trunc(inv_dt) = truc(sysdate);

code:

where inv_date between trunc(sysdate)
                   and trunc(sysdate)+1-1/24/60/60;

you can use the index then and its the same as the original.

5) just run a query that makes use of it.  you have it setup
withthe min/max servers.

select /*+ FULL(&1) PARALLEL(&1,&2) */
count(*)
from &1
/

for example (put into a script and run @count emp 5)

6) Just call POST.  The database will do that for you.

Review &
      Followup

      Rating:
      5
  April 29, 2001
Reviewer:
      A reader
Excellent !

      Rating: 5
Very
      useful  September 19, 2002
Reviewer:  Ganesh
       from India

February 10, 2001 Madhusudhana Rao -- Thanks for the question
      regarding "PL/Sql Tables", version Oracle 8.1.6

      You Asked
Dear Mr.Tom,

How to handle pl/sql tables returned from procedure using
java with Oracle Driver. Pls do the needful ASAP.

Oracle Version    8.1.6 or 7.3.4
Java              1.2.1
JDBC Driver       Oracle

Regards,
Madhusudhana Rao.P

      and we said...
You cannot return a PLSQL table type to Java.  You can return a
COLLECTION in Oracle8.0 and up (see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:331217279811
for an example of how this works)

There is also a "trick" you can use to "select * from
PLSQL_TABLE" see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:146412348066
where I demonstrate this.  In this fashion, java can "select *
from PLSQL_TABLE" to get the array back.

February 10, 2001 Dhiral -- Thanks for the question regarding
      "Database Administration", version 8.0.5.0

      You Asked
Q:1 How can we create a new datbase by giving command in svrmgr?
give the whole command.
Q:2 What is the use of instance manager,data manager,security
manager,recovery manager,backup manager,storage manager?
Q:3 How can we get backup of database offline and online both
give the answer in detail with all steps.Give the perfect steps
to get backup.

      and we said...
q1) it is the "create database" command and it is documented in
the sql reference HOWEVER -- the true answer is that is depends
on the platform and there is MORE then the create database
command.

you have all of the init files to consider.

you have to consider how we do "sids" on that system -- it is
going to be an environment variable (unix) or a service (nt)

and so on.  Please refer to the OS install and admin guides.
They all have the OS specific step by steps you must undertake
to create a database manually.  I find using dbassist to
generate the scripts to be far easier.

q2) they are used to manage the database.  Their names imply the
usage.  backup manager for example helps you to manage your
backups.

q3) backup is something you need to understand.  Given I have no
idea what your OS is, what your environment is, I cannot do it.
I can only refer you to the backup and recovery guides that go
into this in great detail.

an offline backup is "easy".  do a shutdown (not shutdown abort)
and copy all

o datafiles
o controlfiles

to another location.  You've just done your cold backup (or use
backup manager).  do not copy redo.

a hot backup is only slightly more involved but requires more
book keeping on your part.  Suggest you read the backup and
recover guides and read about RMAN.
February 11, 2001 Ramasubbu -- Thanks for the question regarding
      "Life of Native datatype into multiple loops ...", version Oracle 8i

      You Asked
Hi Tom,
        I am using Oracle 8i,pl/sql,win nt.
        In last week I asked a question which related with array
of data into nested tables and u were also given the
solution.This is a link

http://osi.oracle.com/wa/ask/owa/ask_tom_pkg.display?p_dispid=1386203630384
This was a solution give by u

tkyte@TKYTE816> declare
  2      l_variable   myArrayType := myArrayType();
  3  begin
  4      for i in 1 .. 5
  5      loop
  6          l_variable.extend;
  7          l_variable(i) := myScalarType( 'type ' ||
                              i, 'description ' || i, i );
  8      end loop;
  9
 10      insert into module_formula_table
 11      values ( 1, 2, l_variable );
 12  end;
 13  /

PL/SQL procedure successfully completed.

It is working fine.

But one of my scenario is required like the above block will be
inside of another loop.

The above program has been modified by putting by outer loop(j)
and forming the array(ie,in 2nd loop) and end of 2nd
loop,insertion will be happen for two records.But it is
inserting only one record and for 2nd record it give the
following error(followed by pgm).I tried by put another
extend/next and so on.But it is not working.Please give me the
solution and explain me why its given that error?..Is it any
logical error behinds it?.......How to rectify that error?...

  1  declare
  2         l_variable   myArrayType := myArrayType();
  3     begin
  4     for j in 1..2
  5     loop
  6         for i in 1 .. 5
  7         loop
  8             l_variable.extend;
  9             l_variable(i) := myScalarType( 'type ' ||
 10                               i, 'description ' || i, i );
 11          end loop;
 12         insert into module_formula_table
 13         values ( j,1, l_variable );
 14     end loop;
 15*    end;
SQL> /
declare
*
ERROR at line 1:
ORA-22805: cannot insert NULL object into object tables or
nested
tables
ORA-06512: at line 12

SQL> select count(*) from module_formula_table;

 COUNT(*)
---------
        1

Thank u Tom

I am eagerly waiting for u reply.

regards
Muthu

      and we said...
add:

   l_variable := myArrayType();

on line 6 -- right before the inner loop.

What is happening here is the first time, you extend and add
array elements 1, 2, 3, 4, 5.

The second time, you are working on the same array so when you
call extend it adds 6, 7, 8, 9, 10 but you fill in 1, 2, 3, 4, 5
leaving 6, 7, 8, 9, 10 NULL.  That is what it is complaining
about.  If you set the array to "empty" before the loop that
extends and fills it up, you'll be OK.
Review &
      Followup

      Rating:
      5
  September 24, 2001
Reviewer:  W
       from NJ. USA
Big Help!!!

February 11, 2001 Senthil Kumar -- Thanks for the question
      regarding "Restrict Multi Sessions or Multi Signon for Single User",
      version Oracle 8.1.6

      You Asked
Hello,

Fine.

I wants to restrict a ORACLE user, to signon Multi Sessions into
database.

Senthil Kumar. S

      and we said...
Enable profiles and set a resource limit of sessions/user to 1
for this user.

see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76956/users.htm#1148
for details.
February 11,
      2001 Hakan -- Thanks for the question
      regarding "too slow v$locked_object", version 8.1.6.2

      You Asked
hi tom,
it takes nearly 700 seconds to select * from v$locked_object at
my production database when load is really low. when the load
comes to normal levels (i mean in the daytime) i can't get the
result though i wait lots of quarters.

on the other hand, oracle works like a charm.
i am afraid of whether this is an indicator of something wrong
or bad.

HP-UX 11 (HP V-class) (6GB - 8 cpus)
Oracle 8.1.6.2
MTS
low load : nearly 30 inactive and 3 active users
normal load : nearly 1500 inactive and 30 active users
optimizer mode : first rows (i am suspicious of this)

thanks a lot, sir
have a good day.
hakan.

p.s. select * from v$lock results in a few seconds under a high
load whether.

      and we said...
Very normal.  You should avoid v$ queries at all times.  It will
negatively impact the performance of your system.

A query against v$ tables is a query against data structures.
In order to do these queries, we must latch (serialize access
to) these structures.  In an active system -- you are going to
wait.  While others are modifying the structure, you cannot read
it.

You are negatively impacting performance by querying these
objects -- especially if you "select *" from them with no
predicate.  The more you have going on, the less responsive
these things will get.

Use these tables ONLY when you really need to.  Best approach is
to copy them off to the side and then analyze them (like stats
pack does).


Subject | Article | Last Updated (East coast time)
dropping a column of table in 8.0.5 database | article only | Feb 12, 2001 08:44 am
Most Recent Article For "Oracle Magazine" | article only | Feb 12, 2001 08:54 am
invalid objects | article only | Feb 12, 2001 09:51 am
To select rownum and finding specific records | article only | Feb 12, 2001 10:18 am
regarding the performance of database triggers | article only | Feb 12, 2001 10:21 am
Performance - Tuning - Reg. | article only | Feb 12, 2001 10:27 am
DML Packages vs. in-line DML. | article only | Feb 12, 2001 10:42 am
Oracle blocks | article only | Feb 12, 2001 11:39 am
Timed Statistics | article only | Feb 12, 2001 02:49 pm
ORA-01555: snapshot too old | article only | Feb 12, 2001 03:54 pm
Character Set | article only | Feb 12, 2001 03:56 pm
Need help with a script | article only | Feb 13, 2001 10:54 am
What difference between SQLJ,JSP(Java Stored Procedure) & PL/SQL Java | article only | Feb 13, 2001 10:58 am
What benefit does it use nested record or nested table? | article only | Feb 13, 2001 11:04 am
Jdbc passing dynamic parameters to SQL with IN operator | article only | Feb 13, 2001 11:08 am
XML and SQL | article only | Feb 13, 2001 11:09 am
Reparsing the statments inside the proc/func/package? | article only | Feb 13, 2001 11:26 am
DYNAMIC SQL -- EXECUTE IMMEDIATE | article only | Feb 13, 2001 12:16 pm
High-Water Marks | article only | Feb 13, 2001 12:36 pm
Restricting SQL PLUS access | article only | Feb 13, 2001 12:46 pm
Hetergeneous Services (Generic Connectivity to MS Access) | article only | Feb 13, 2001 06:44 pm
Index-oriented Tables | article only | Feb 13, 2001 07:23 pm
Connecting two apperantly non-relational tables | article only | Feb 14, 2001 09:21 am
rollback segment | article only | Feb 14, 2001 10:12 am
Pls. Explain This. | article only | Feb 14, 2001 10:22 am
Quest on .pll File ! | article only | Feb 14, 2001 11:00 am
Where to obtain JDBC driver compatible with JDK 2? | article only | Feb 14, 2001 11:03 am
no data found error, bulk collect , performance tuning | article only | Feb 14, 2001 01:17 pm
decoding data in RAW after using utl_raw.cast_to_raw??? | article only | Feb 14, 2001 02:03 pm
Picture format | article only | Feb 14, 2001 02:05 pm
Tricky query | article only | Feb 14, 2001 02:33 pm
how to find process id in oralce database tables | article only | Feb 14, 2001 04:49 pm
creating trigger/constraint for unique on a column.. | article only | Feb 15, 2001 09:22 am
Contradict PCTFREE and PCTUSED | article only | Feb 15, 2001 09:38 am
cold backup and recovery with RMAN | article only | Feb 15, 2001 11:04 am
how to process the array output from stored procedure inJDBC program | article only | Feb 15, 2001 04:48 pm
SQL sub query with outter join | article only | Feb 15, 2001 05:03 pm
Sybase Stored Procedure to Oracle | article only | Feb 15, 2001 07:26 pm
Suspending and de-sudpending DBMS_JOB jobs | article only | Feb 16, 2001 08:55 am
Who to define an URL in FORMS | article only | Feb 16, 2001 01:45 pm
Inserting blobs into table | article only | Feb 16, 2001 01:47 pm
Security: Controlling access from Oracle and third party tools | article only | Feb 16, 2001 03:12 pm
Running a procedure in background | article only | Feb 16, 2001 03:21 pm
Major Diffirences between 8 and and 8i | article only | Feb 17, 2001 09:57 am
scripts | article only | Feb 17, 2001 10:14 am
Getting rid of synonyms | article only | Feb 17, 2001 02:10 pm
how to use win_api functions | article only | Feb 18, 2001 10:46 am
PL/SQL-need to return an inserted set | article only | Feb 18, 2001 11:09 am
About Objects | article only | Feb 18, 2001 11:11 am
Create table privilege | article only | Feb 18, 2001 11:14 am
Can Oracle8.16 be installed on Solaris8 | article only | Feb 18, 2001 11:17 am
Who is "current user"? | article only | Feb 18, 2001 11:33 am
Fine-grained Access Package | article only | Feb 18, 2001 11:35 am
Parameter Default Value | article only | Feb 18, 2001 12:54 pm
Querying & copying columns of type LONG | article only | Feb 18, 2001 12:57 pm
row(s) 1 - 55 of 55
February 12, 2001 elham -- Thanks for the question regarding "dropping a column of table in 8.0.5 database", version 8.0.5
You Asked
In Oracle 8.0.5 database, how can I drop a column of table
without dropping the table?
thanks.
elham ashoori
and we said...
You cannot drop a column in 7.x/8.0.  Drop column is a feature
added in Oracle8i release 8.1 and up.

What you would do in 7.x/8.0 is to drop column C2 from T is:

rename table T to T_Table;

create view T as select  C1, C3, ... from T_Table;
February 12, 2001 Gordon -- Thanks for the question regarding "Most Recent Article For "Oracle Magazine"", version 8.1.5
You Asked
Tom

In your most recent article for "Oracle Magazine":

=====================================
                     Ask Tom

       Tips on Speeding Up, Working Out, and
                   Getting Secure

                     By Tom Kyte
=====================================

I have a question about your solution to the first
problem in the article.

A portion of your solution is shown below:

=====================================
         ...
         The index you want to
         create would take the form:

         SQL> create index t_idx on
          2 t(substr( last_modified_by,
          3 instr(last_modified_by,'#',1,1)+1,
          4 instr(last_modified_by,'#',1,3)
          5 instr(last_modified_by,'#',1,1)-1 )
          6      )
          7 /
         Index created.

         If I'm off on the placement of the #'s,
         you just need to adjust the fourth parameter
         to instr in the above —
         I'm looking for the first and third ones.
         ...
=====================================

My question is this:

  Should there be a minus sign "-" at the end of
  "instr" function on SQL line 4 above?

Thanks in advance!

Gordon
and we said...
Yes, it got lost in the edit.  Sorry about that.

the original Q/A is:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:823026924920
....
February 12, 2001 -- Thanks for the question regarding "invalid objects", version 8.1.6
You Asked
Dear Tom,
Recently I upgraded my database from 8.0.5 to 8.1.6.0 by running
u800050.sql script.I ran post migration scripts like urep.sql to
compile invalid objects.After that when I checked for invalid
objects I found few sys objects(views&packages) which are still
invalid(only user sys).I tried to compile them again and I got
the message statement processed.But they are still showing as
invalid even after recompilation.Can u pls tell me the reason
for that.At the same time can u pls provide me the necessary
post migration checks to be performed to maintain the database
consistent as I am planning to do it on production very
shortly..
2)Do I need to recreate the controlfile for migrating the
standby database(from 8.0.5 to 8.1.6) or the old controlfile
allows to apply the archive logs generated on the primary
machine after the database is migrated???How to identify the old
archive logs(8.0.5)with respect to newones(8.1.6)??
Thanks,
Geeta.
and we said...
1) what views, give me the names of say 5 of them.  do a

SQL> alter view <viewname> compile;
SQL> show errors view <viewname>

as well for those 5.

You'll want to refer to
http://technet.oracle.com/doc/oracle8i_816/server.816/a76957/toc.htm
for all of the proper procedures.

If you follow the steps in the migration guide for upgrading
your database, that is it.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76957/migaftrm.htm#166
for tasks to complete after migrating or upgrading.

2) see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76957/migaftrm.htm#6235
for the procedures.
February 12, 2001 Riaz -- Thanks for the question regarding "To select rownum and finding specific records", version 8.1
You Asked
Hi Tom!

I am facing the following problems:

(1) I want to select rownum and all columns for a table without
using the column names. How i could do this. I have tried yhe
following Statment but failed:

select *, rownum from emp;

(2) How can i select the specific record from a table. e.g
suppose i want to select the 50 to 100 records. How i can do
this?

Plz Help me
and we said...
1) select emp.*, rownum from emp;

2) well, forgetting for a moment that there is no such thing as
records 50..100 in a table, you can get the 50'th tuple from a
result set like this in Oracle8i:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:127412348064
...
February 12, 2001 ganesh -- Thanks for the question regarding "regarding the performance of database triggers", version 8i
You Asked
is it advisable to use database triggers over web when the
expected hit rate is 3 requests/second? how do you justify it?
and we said...
3 requests per second is tiny.  Triggers are used in many
systems in many cases.  They are typically more performant then
doing it in the client code.  They tend to be SQL intensive --
doing the logic in a client would involve lots more round trips
to/from the database.

There would be no issues with a well code trigger.
February 12, 2001 patibandla -- Thanks for the question regarding "Performance - Tuning - Reg.", version 8.1.6.0
You Asked
We are developing a web based product.  We are Using IIS Sever
ASP 3.0 and Oracle 8i.   There are around 150 to 200 ASP forms
and each form is associated with a view.  In the Front end form
we are showing 20 records and in case of next 20 records are
records are required the user clicks on the next button.
Similar to what we have it in ask tom.

Instead of going to database for every 20 records
they r getting first 500 records and displaying.
20 records by 20 reords. That is at every 26th click of
next button they will be going to the database and getting
the records.  The total no. of records in a particular
table may contain thousands of records. We are using first
rows in all the views.  All the views contains no. of
Tables and PL/SQL Functions.

This being the case do u suggest the usage of Cursor
or any other better method. Or the current procedure we
are following is Ok.

How is procedure followed in the case of  ASK Tom Questions

Regards

Patibandla
and we said...
Again, I will say that a result set of more then 500 records
will never be looked at by anyone.  If I do a search on the web
and I am looking at the results of 20 rows/page -- it would take
25 "next" clicks to exceed 500 rows.  It is my opinion there is
0% chance you'll ever go past 500 rows - ever.

Who would have the patience to manually look at all of that
data?  Why even bother with a database at that point.

Anyway -- on ask tom, i do this:

  cnt = 0;
  for x in ( select * from .... )
  loop
      cnt = cnt+1
      exit when ( cnt > max_row )
      if ( cnt > min_row ) then
          print it
      end if;
  end loop

I run your query for every page and throw away the first n rows.
 I make sure the queries I do this on the web return the first
rows "quickly".  No one ever clicks more then 10 pages down --
ever.  they get bored and refine their search.
Review & Followup
Rating: 5
How about when dumping all the data retrieved into a excel or csv file November 06, 2001
Reviewer: Nag
via Delphi we select out data  and dump it into a csv file.
The issue here is that our query is taking very less time to execute , but the
problem is
that delphi collects all the records returned by the query, and then writes it
to the respective csv or excel file. Both the operations are not simultaneous.

is there an easier way to write the selected data to the csv file. The select is
complicated and includes several tables.
( apologize sincerely, for asking too many, but under a lot of pressure, working
on multi assignments, I promise that I will regulate my ?'s from next week.)

February 12, 2001 malcolm -- Thanks for the question regarding "DML Packages vs. in-line DML.", version 8.1.7 (UNIX)
You Asked
Hi Tom,

I'm Currently working on a conversion from Informix to Oracle
8.1.7.
At the moment there are a number of 4gl batch programs
(Basically a bunch of related procedures).

These call a number of library 4gl programs that carry out
business logic. (Again a bunch of related procedures)

Which in turn call DML procedures for the
Inserts/Updates etc.

Our plan (so far) is to convert both the
highlevel batch 4gl and library 4gl to similar ORACLE PACKAGES.

But there has been alot of discussion about the DML. The two
options to us are:

1 - Have DML Packages which reflect the existing DML 4gl.

2 - Move the DML so it's in-line with the rest of the code (ie.
put the INSERTS/UPDATES within the higher level packages.)

I favoured the first option (less duplication of code) But are
there any performance issues?

Any comments would be appreciated.

Thanks in advance

Malc
and we said...
There won't be any performance issues related to using a "DML"
package versus inlining the code.

the tradeoffs are -- reduced code to manage in the SGA vs the
cost of doing a procedure call.  inline code may work marginally
faster then non-inlined code but this is usually offset by the
huge amount of extra code.

Go with the modular approach.
February 12, 2001 Ravi -- Thanks for the question regarding "Oracle blocks", version Oracle 8.0
You Asked
How does the increasing of Oracle block size affect memory
requirements? The blocks of data is read from the disk in the
buffer cache..what does that mean??
and we said...
If you have db_block_buffers set to X and you double the size of
your blocks from 2k to 4k, you will increase your memory usage
in the block buffer cache by 2.

If you half your db_block_buffers when you double the size of
your block size, your required memory will not increase at all.

As for what does reading data from disk and storing in the
buffer cache means -- it means we store data we read in memory,
in a cache, to avoid having to reread it frequently from disk.

see also
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:329017235004
...
February 12, 2001 Kenneth -- Thanks for the question regarding "Timed Statistics", version 8.1.6.3
You Asked
Reading Oracle8i Internal Servcies by O'Reilly
Page 12 said the overhead of Timed_statistics=true
is negligible.
I have alway heard never to leave as true only for
tuning/testing and turn it off.

What is your option of leaving this parameter true in a
production database.

Thanks,
and we said...
I myself typically leave it off now (but didn't use to).

You can turn it on with an ALTER SYSTEM or even ALTER SESSION
command.  Used to be you had to restart.  I would still have it
on it I needed to restart to get it.

As it is, I turn it on when I want it.
February 12, 2001 Mark -- Thanks for the question regarding "ORA-01555: snapshot too old", version 8.1.5
You Asked
I've been dealing with this error off and on for the last 3 years and I just
wanted to verify that my understanding of its cause is accurate.

Cause 1)

There is only one user logged into the database.  That user is
updating\inserting\deleting a lot of database records without committing.
Oracle clears out any unneeded transactions in the rollback segment but
eventually it fills up and the error occurs.

Cause 2)

User A logs into the data base.

User B logs into the data base and is updating\inserting\deleting a lot of
database records, but is committing every 100 records.  Oracle clears out any
unneeded transactions in the rollback segment but eventually it fills up and the
error occurs.  Oracle cannot clear out any of user B's transaction since they
are needed to maintain user A's consistent view of the database, which is before
user B logged in.

Therefore, commiting every so often would fix cause 1, but can do nothing about
cause 2.

Are there any other scenarios where ORA-01555 can occurr?

Thanks

Mark
and we said...
cause 1) no, that will not cause a 1555.  That might cause

$ oerr ora 1562
01562, 00000, "failed to extend rollback segment number %s"

cause 2) the description:

user a logs in

user b logs in and deletes/updates/inserts X records commits  in a loop.

MAY cause A to experience an ORA-1555 if A is performing a long running query
against the object(s) B is modifying.  It will not cause it for the reason you
state.  Rollback data is not preserved for SELECTS.  As soon as B commits, his
rollback might be overwritten.  It is when it is overwritten that user A will
get the ORA-1555.

An ORA-1555 is never about running out of rollback.  It is about rollback that
was generated being overwritten.  A select statement will not cause rollback to
be "held".  As soon as the transaction that generated the rollback commits -
that rollback may be reused and if it is and it is needed by some query, you
will get an ORA-1555.

I myself have never hit an ORA-1555 in a live system (development sure, we were
sizing it then tho).  if you size your rollback adequately, neither will you.

The ORA-1555 happens when people try to save space typically.  They'll have
small rollback segments that could grow if they needed (and will shrink using
OPTIMAL).  So, they'll start with say 10 or so 1meg rollback segments.  These
rollback segments COULD grow to 100meg each if we let them (in this example)
however, they will NEVER grow unless you get a big transaction.

If your database does lots of little transactions, the RBS will never grow on
their own.  They will stay small.

Now, someone needs to run a query that will take 5 minutes.  On your system
however the rollback wraps every 2 minutes due to lots of little transactions
going on.  In this system, ORA-1555's will happen frequently.  What you need to
do here is size rollback so that it wraps less frequently (less frequently then
your long running queries).  Here if I sized the rollback so that I had 10,
10meg segments (not so they could GROW to 10meg but that they are starting at
10meg) we would wrap maybe every 20minutes now.  that'll give that 5minute query
plenty of time to complete without reusing rollback it needs.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:275215756923
for more details.
February 12, 2001 Sam -- Thanks for the question regarding "Character Set", version 8.1.5
You Asked
Hi Tom,

I have a database of almost 50 GB. And I wanna change the
character set of that existing database. Some one told me there
is some import/export way for doing that, but not sure though.
Do you have any idea how I can do that?

Thanks
Sam
and we said...
See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76966/ch3.htm#47136
you may be able to do this in place.
February 13, 2001 Sanjay -- Thanks for the question regarding "Need help with a script", version 7.3.4.5
You Asked
I have inherited a database (OLTP) running on HP UX 11 and
Oracle 7.3.4.5. There are more than 500 tables, both big (more
than 1.5 million records) and small (less than 500,000 records)
all in a single tablespace. V R in the process of migrating the
database to 8.1.7 and for performance reasons I would like to
create these tables in 7 different tablespaces.  I plan to take
a export and then change the tablespace name in the DDL before
importing. I want to know if there is a script which will modify
the export file to create the tables to  the desired tablespace
based on various business criteria. Like tables less than 100 MB
to tablespace 1, 101 MB – 500 MB to tablespace 2, … and Tables
whose name start with say the work PROD and some other criteria.
I want to save myself the trouble of going in and manually
change the tablespace name for the 500 tables.
and we said...
There are no scripts to modify EXP dmp files.   They are in
binary -- tools like sed and such may destroy them.

What you can do is:

exp ... owner=application_schema rows=n .....
imp .... indexfile=new.sql ....

new.sql will be a script where all of the create tables are
included as comments.  You can then write an awk script or such
to whip through this and extract the create tables to another
script, rewriting what you want as you go.

OR, what might work better (easier) is to generate a couple of
list of tables from the existing data dictionary.  So, you could
come up with 7 queries that based on the data dictionary info
came up with 7 mutually exclusive list of tables.  Now, you can
do 7 exports:

exp userid=u/p grants=n indexes=n rows=n constraints=n
'tables=(list 1) ...
imp userid=u/p indexfile=list1.sql full=y
exp userid=u/p grants=n indexes=n rows=n constraints=n
'tables=(list 2) ...
imp userid=u/p indexfile=list2.sql full=y

(the imp wont import -- it'll just create a script)

and so on.  You now have 7 scripts.  everything in list1 should
go into tablespace T1 -- just global change the old tablespace
name to T1 and remove the REM's.  everything in list2 should go
into tablespace T2, global change and so on.

Now, run the scripts in the new database to precreate the
tables.  Do the imp with IGNORE=Y and the tables will be loaded
in the tablespaces they now exist in.

(hint: you might want to use the parfile on the export to have
the lists of tables be in parameter files -- not on the command
line)

(hint: use LOCALLY MANAGED tablespaces with UNIFORM extent
sizing in 8i)
February 13, 2001 Jennifer -- Thanks for the question regarding "What difference between SQLJ,JSP(Java Stored Procedure) & PL/SQL Java", version 8.1.6
You Asked
Hi Tom;

I really want to understand what difference between SQLJ,JSP and
PL?SQL with Java.

Thanks
and we said...
SQLJ is a method of embedding SQL in Java, much like Pro*C is a
method of embedding SQL in C/C++.

SQLJ is a programming tool for java programers.  Instead of
putting jdbc calls into an application, they can embed SQL calls
in java and have a precompiler generate the JDBC code for them.

A little SQLJ snippet might be:

    for(int i = 0; i < list.length; i++)
    {
        element = list[i];
        #sql { INSERT INTO DIR_LIST (FILENAME)
               VALUES (:element) };
    }

the #sql is the SQLJ

A JSP is a java server page.  This is where you embed JAVA into
HTML. it allows you to have dynamic content in an other static
page.  You can actually mix SQLJ with JSP if you want -- or just
use JDBC to access the database from java.

PL/SQL with Java -- that would be either PLSQL calling a java
stored procedure or vice versa.
Review & Followup
Rating: 2
PL/SQL vs SQLJ October 31, 2001
Reviewer: A reader from ca
perhaps not answerable, but are there tools that will convert business logic
written as pl/sql into sqlj?

February 13, 2001 Jennifer -- Thanks for the question regarding "What benefit does it use nested record or nested table? ", version 8.1.6
You Asked
Hi Tom:

I just want to know what benefit is it to use nested record or
nested table? what do you gain most? what kind situation I have
to use nested record or table? any performance impact?

any disadvantages to use it?

Thanks

Thanks
and we said...
You gain the syntactically simplicity of not having the
explicity code a join between a parent and child in SQL.

You gain the ability to get 100 detail records without having to
get the parent record 100 times as well (eg: a JOIN between DEPT
and EMP brings back the dept record for each EMP record.  If EMP
was a nested table of DEPT -- the dept record would come back
once with all of the details in a single row).

Programming wise, i find nested tables to be a nice extension to
PLSQL.

disadvantages: not everything understands what a nested table is
(reporting tools and such)
February 13, 2001 -- Thanks for the question regarding "Jdbc passing dynamic parameters to SQL with IN operator", version version 8.1.6
You Asked
I am trying to use the following SQL with the prepared statement

SELECT * FROM WAITING_ROOM WHERE ADVISOR_ID IN ( ?)

The only difference is I want to pass in
500
or 500, 501 to the question mark.
With the later I get the following error message.
 ORA-01722: invalid number

I tried using setString as well as setObject methods.

Is there a solution other than building the SQL before executing
it.

Krishnan
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:210612357425
Your query will become:

select * from waiting_room where advisor_id in
 ( select *
    from THE ( select cast( in_list( ? ) as mytableType )
                 from dual ) )

Do NOT build the query using constants as that would prevent the
use of bind variables and that is the #1 performance inhibitor.
Do it as above with bind variables.
February 13, 2001 Jennifer -- Thanks for the question regarding "XML and SQL", version 8.1.6
You Asked
Hi Tom:

I know Oracle can transfer SQL's resultset into XML file, but
I'm not sure whether it has to use OAS or not? Since we don't
use OAS and want to move to JAVA/XML/SQL environment, in other
words, can we ONLY use Oracle XML developer Kit to build
communication channel between PL/SQL and XML or between Java and
XML?

Thanks

Jennifer
and we said...
see
http://technet.oracle.com/tech/index.htm
its all done in the database, OAS does not fit into the picture
at all unless you want it to.
February 13, 2001 Ravi -- Thanks for the question regarding "Reparsing the statments inside the proc/func/package?", version 805
You Asked
Tom,

Could you please clarify the following :

I have a table t1 and the procedure P1 which depend on the table
t1, ie) there are some sql statements on t1 in the procedure P1.

I read in a book that the pack/proc/functions donot need to be
parsed  when they are loaded into the database. I could not
understand that.

What about re-parsing of the sql statement inside the procedure.

Let us assume that I created the procedure today, that means all
the statments in the procedure also got parsed and the execution
plan is ready for all the statments. The table is growing and I
also analyze the tables. Analyzing a table does not invalidate
the objects(procedure, etc.) depending on it. Then how oracle
comes to know that reparsing need to be done for the sqls in the
procedures.

If no reparsing occurs, I assume that the execution plan for the
sql statements are  based on the old data and it may not be
accurate.

I will be grateful to you, if you can explain how oracle
resolves it.

Thanks in advance.
Ravi
and we said...
What they meant by "pack/proc/functions donot need to be
parsed  when they are loaded into the database" is that we store
the PLSQL compiled into pcode (like java byte code).  When we
load a package, we don't compile it -- its already compiled.

Now that package has SQL in it.  That SQL is just stored as
strings -- as data.  We execute that SQL in the same way any
other sql is executed.  The very first time the server sees the
sql it'll generate a plan for it and stuff that into the shared
pool.  Now, if we analyze a table, add an index, etc -- the
cursors that are cached that reference that object we just
modified are invalidated.  Their plans will be re-evaluated on
their next execution.

It happens in PLSQL the same way it does in pro*c, jdbc, sqlplus
and so on.  For example:

ops$tkyte@DEV816> set autotrace on explain
ops$tkyte@DEV816> select empno, ename from emp where empno < 0;

no rows selected

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
   2    1     INDEX (RANGE SCAN) OF 'EMP_PK' (UNIQUE)

ops$tkyte@DEV816> analyze table emp compute statistics;

Table analyzed.

ops$tkyte@DEV816> select empno, ename from emp where empno < 0;

no rows selected

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1
   1    0   TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=1 Bytes=8)

Same exact query -- run two times in succession but with
different plans.  the analyze invalidated the prior plan and the
CBO re-evaluated its options and changed the plan.
February 13, 2001 Oscar -- Thanks for the question regarding "DYNAMIC SQL -- EXECUTE IMMEDIATE ", version Oracle8i Enterprise Edition Release 8.1.5.0.0
You Asked
The following procedure to create a table using the EXECUTE
IMMEDIATE feature is basically out of the Oracle documentation.
I cannot execute it without getting an "insufficient privileges"
(ORA-01031) error message even though I am the system manager of
the database (nor can I do it in a different database where I
have DBA privileges). I cannot find any indication in the Oracle
documentation, sample code or error messages that will tell me
why this is happening. Any suggestions? Your help will be much
appreciated.

Thanks.

Oscar Soto
Covista Communications
osoto3@hotmail.com

-----------------------------------------
CREATE OR REPLACE PROCEDURE add_emp AS
BEGIN
  EXECUTE IMMEDIATE 'CREATE TABLE EMP
  (EMPNO NUMBER(8,0), NAME VARCHAR2(50))';
END;
/
and we said...
see
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
...

and then GRANT CREATE TABLE to <owner of procedure>

(or investigate if invokers rights are more appropriate for you
-- see
http:/technet.oracle.com/doc/oracle8i_816/appdev.816/a77069/07_su
bs.htm#12848

for details.
February 13, 2001 Keith -- Thanks for the question regarding "High-Water Marks", version 8.0.5
You Asked
What is High-Water Marks ?
What is it used for ??
If I delete all 10000 records from a table, it will talk a long
time if i submit a count(*) ??

Can you advise some web-site for DBA ? (other than Oracle.com)

Thanks a lot
and we said...
A high water mark is the set of blocks that have at one pointed
contained data.  You might have 1000 blocks allocated to a table
but only 500 are under the HWM.

The blocks under the HWM are the blocks that will be read when
the table is full scanned.  So, in your example above - if you
put 10,000 record in the table, delete from table and commit --
when we do the count(*) IF WE FULL SCAN THE TABLE, we will hit
those empty blocks.  If we fast full scan the index -- it'll be
different.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
for how to find the HWM.

As for web sites -- I'm not sure.  Oracle.com is a pretty large
place.  I assume you've been to technet.oracle.com then?
February 13, 2001 Shruti -- Thanks for the question regarding "Restricting SQL PLUS access", version 8.0.4
You Asked
Hi Tom,

To my previous question and your reply was as given below  thank
you very much for the same . I had some more quesry on that. Our
problem was that some of our smart users they write anonymous
PL/SQL block and just run them on SQL prompt though I have not
given them (INSERT,DELETE,UPDATE,EXECUTE) access with the help
of PRODUCT_USER_PROFILE.

How can we stop that?

2.I am using PRODUCT_USER_PROFILE for restricting user from
using INSERT,UPDATE command.  For some users I want to stop
access to SqlPlus and Sql Forms itself. Is there any way of
doing it.

This would really be a great help to me

Thanks

and I said...

1) you cannot.

2) for sqlplus, you would disable all possible commands (sqlplus

and SQL commands).  there is no way to disable access to sqlplus

itself.

Forms does not use the product_user_profile table.. You would
have to incorporate this functionality into your forms yourself.
and we said...
1) fire your smart users.  They ar

Actually, I prefer to never give anyone insert/update delete.  I
would put my application login in plsql packages -- grant
execute on the packages.  The "smart" end users cannot even see
the tables, let alone touch them.  The application is the only
way to access the data.

you can use PUP to disable DECLARE, BEGIN, and EXECUTE --
that'll stop PLSQL from being executed.

2) Say you could cut off sqlplus (you cannot, its just a
program).  What stops them from downloading TOAD, or using
Excel+ODBC, or ...... any of thousands of other things that
connect to Oracle.....

You might be interested in my answer to:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1445204371337
as well.
February 13, 2001 Patricia -- Thanks for the question regarding "Hetergeneous Services (Generic Connectivity to MS Access)", version 8.1.6.3.1
You Asked
Tom:

I am really needing help.  Oracle support is not getting
anywhere with this one.  I have setup HS to connect to an
Adaptive Server Anywhere (Sybase) database and everything
appears to be working fine.

The problem is that the database we really need to connect to is
MSA.  So..., using the same process I set up a connection to a
MSA database.  Unfortunately, I can only do a 'select * from
<table>@<db link>'.  In ALMOST ALL cases, when I specify a
column name it returns the error 'ORA-0904: invalid column
name'.

FYI.., the columns are appearing in the
ALL_TAB_COLUMNS@<db_link>.

The database I am trying to connect to is MSA 2000; however, I
have also tried MSA 97.  My ODBC driver is the Microsoft Access
Driver Version 4.00.5303.01.

Would there be a setting in the MSA ODBC Driver configuration
that is causing the problem?

Any help would be VERY MUCH appreciated!
THANKS!
Patty.

Reply:  I GOT IT using double quotes around the column names AND
recognizing that the column names were case sensitive.

THANKS!!
Patty.
and we said...
MS column names will be in mixed case.

try:

select "c1", "c2", ... from

using quoted identifiers to match exactly the case of the
columns in MSA.
February 13, 2001 Keith -- Thanks for the question regarding "Index-oriented Tables", version Oracle8i 8.1.5 & 6 & 7
You Asked
Tom,

Does a index-oriented table slow down inserts?

Keith M Cutler
and we said...
An index ORGANIZED table may be faster then a single table with
a primary key index.  It depends.

An IOT is a table stored in an index.  If you had just a flat
table with no indexes on it -- that would probably be faster
then the IOT (as index maintenence adds overhead).  However,
once you start adding the index to the table -- things start to
even out.

If you setup a proper overflow size and such, so as to not
overfill the index blocks with too much non-index data -- the
IOT will go through the same sort of splits and re-arranges that
a regular tables primary key index would.

Here is a totally unscientific test.  T1 is an IOT with a 2k
rowsize (stored in the index block).  T2 is a "regular table
with a primary key index on it (again, every row is 2k).  T3 is
an IOT where the extra data is stored in an overflow (the
non-primary key columns)

ops$tkyte@DEV816> drop table t1;
Table dropped.

ops$tkyte@DEV816> create table t1 ( x int primary key, y
char(2000) default '*' )
  2  organization index;
Table created.

ops$tkyte@DEV816> drop table t2;
Table dropped.

ops$tkyte@DEV816> create table t2 ( x int primary key, y
char(2000) default '*' );
Table created.

ops$tkyte@DEV816> drop table t3;
Table dropped.

ops$tkyte@DEV816> create table t3 ( x int primary key, y
char(2000) default '*' )
  2  organization index including x overflow tablespace users;
Table created.

ops$tkyte@DEV816> set timing on
ops$tkyte@DEV816> insert into t1(x) select rownum from
all_objects where rownum < 1500;

1499 rows created.

Elapsed: 00:00:37.17

ops$tkyte@DEV816> insert into t2(x) select rownum from
all_objects where rownum < 1500;

1499 rows created.

Elapsed: 00:00:10.92

ops$tkyte@DEV816> insert into t3(x) select rownum from
all_objects where rownum < 1500;

1499 rows created.

Elapsed: 00:00:10.72

ops$tkyte@DEV816> begin
  2          for i in 10000..11500 loop
  3                  insert into t1(x) values(i);
  4          end loop;
  5  end;
  6  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:35.02

ops$tkyte@DEV816> begin
  2          for i in 10000..11500 loop
  3                  insert into t2(x) values(i);
  4          end loop;
  5  end;
  6  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:11.78

ops$tkyte@DEV816> begin
  2          for i in 10000..11500 loop
  3                  insert into t3(x) values(i);
  4          end loop;
  5  end;
  6  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:12.02
ops$tkyte@DEV816>

As you can see, T3 (the "smart" IOT) is comparable with T2.  T1
-- the poorly implement IOT with really big rows on the index
pages, performs poorly, probably due to the excessive splitting
that is happening in the index structure.
February 14, 2001 Sridevi -- Thanks for the question regarding "Connecting two apperantly non-relational tables", version Oracle 8
You Asked
I have two tables
Table A
data_Date date
amt01 number(7,2)
amt02 number(7,2)
amt03 number(7,2)
amt04 number(7,2)

Table B
Code         Number(4)
Description  Varchar2(30)

Table B contains codes 1,2,3,4 and their respective
descriptions.
amt01 in Table A refers to the amount corresponding to code 1
amt02 in Table A refers to the amount corresponding to code 2
and so on

columns will  be added in Table A as and when codes are added
in Table B

Will I be able to get the output this way....
"data_date, code, description, amount"

...... using a single select statement WITHOUT USING UNION
The select statement should take into consideration the fact
that columns may be added in  Table A.

Due to some organisational constraints i do not want to change
the table structures.
and we said...
Sure, a simple cartesian product of A with B is all we need.  I
would recommend using a VIEW on AxB so that when you add a
column to A, you can simply rebuild the view to include that new
column and all existing apps will just see the new data.

Here is an example.  We'll start with 2 amts and show how to
goto 3:

ops$tkyte@DEV816> create table a
  2  ( data_date date,
  3    amt01     number,
  4    amt02     number
  5  )
  6  /
Table created.

ops$tkyte@DEV816> create table b
  2  ( code         number,
  3    description  varchar2(10)
  4  )
  5  /
Table created.

ops$tkyte@DEV816> insert into b values ( 1, 'desc 1' );
1 row created.

ops$tkyte@DEV816> insert into b values ( 2, 'desc 2' );
1 row created.

ops$tkyte@DEV816> insert into a values ( sysdate, 1, 2 );
1 row created.

ops$tkyte@DEV816> insert into a values ( sysdate-1, 3, 4 );
1 row created.

ops$tkyte@DEV816> create or replace view
  2  a_view
  3  as
  4  select a.data_date,
  5         b.code,
  6         b.description,
  7         decode( b.code, 1, a.amt01,
  8                         2, a.amt02 ) amount
  9    from a, b
 10  /
View created.

ops$tkyte@DEV816> select * from a_view;

DATA_DATE       CODE DESCRIPTIO     AMOUNT
--------- ---------- ---------- ----------
14-FEB-01          1 desc 1              1
13-FEB-01          1 desc 1              3
14-FEB-01          2 desc 2              2
13-FEB-01          2 desc 2              4

Now for the steps to add a column.  You'll add it, recreate
the view, and then add a row to B.  It'll just show up after
that

ops$tkyte@DEV816> alter table a add amt03 number;
Table altered.

ops$tkyte@DEV816> update a set amt03 = 100+rownum;
2 rows updated.

ops$tkyte@DEV816> create or replace view
  2  a_view
  3  as
  4  select a.data_date,
  5         b.code,
  6         b.description,
  7         decode( b.code, 1, a.amt01,
  8                         2, a.amt02,
  9                         3, a.amt03 ) amount
 10    from a, b
 11  /
View created.

ops$tkyte@DEV816> insert into b values ( 3, 'desc 3' );
1 row created.

ops$tkyte@DEV816> select * from a_view;

DATA_DATE       CODE DESCRIPTIO     AMOUNT
--------- ---------- ---------- ----------
14-FEB-01          1 desc 1              1
13-FEB-01          1 desc 1              3
14-FEB-01          2 desc 2              2
13-FEB-01          2 desc 2              4
14-FEB-01          3 desc 3            101
13-FEB-01          3 desc 3            102

6 rows selected.
February 14, 2001 wallacel -- Thanks for the question regarding "rollback segment", version 8.1.6
You Asked
Tom:

based on the way oracle use rollback segment, it is possible
that some rollback go all the way to unlimited.

1.
let's say that T1 and T2 are using rollback segment,
T1 write some information to E1 and then stay idle there,
T2 write E1, and when E1 full, it go to E2,E3,E4.
let's say T2 commit now, which rollback segment should next
transaction T3 use?  E2 ? E5?
since you tell me it use ring mode, it should use E5.
am i right?

2.
since T1 is idle all the time, some later time Tn make En (last
one) full, it can't write to E1 since T1 is using it, then it
need to assign a new one En+1, and then En+2...
which means if a transaction idle for a long time, it is
possible
some rollback segment goes to very big.

am i right?

Regards,
and we said...
1) E5 is correct (or a new extent if E5 doesn't exist since E1
is still used)

2) absolutely.
February 14, 2001 Ganesh -- Thanks for the question regarding "Pls. Explain This.", version 8.1.6
You Asked
Hi Tom,

I Created the below Function

Create Or Replace Function Rand Return Number As Language Java
Name "Math.random() return double"

The Function Created Successfully but when i tried to Invoke the
function i am getting a Error Sysing that Class Math Not Found.

So I tried to create a java source and which calls Math.random()
and created a function that calls this class.

This works can u pls enlighten me on this issue.

Thanks
Ganesh R
and we said...
You just needed to qualify it a little more:

Create Or Replace Function
Rand Return Number
As Language Java
Name 'java.lang.Math.random() return double';
/

The database comes with a dbms_random package which if you are
doing stuff in PLSQL will be much faster then using Java.
February 14, 2001 OP -- Thanks for the question regarding "Quest on .pll File !", version 8.1.6.0
You Asked
Dear Tom,

Hi !

How are you Doing !

Is there any file exits in Reports (Developer 2000)
with the extension .pll.

If Yes,Is .pll is a library file.Is it design time or runtime
or both ?

Thanks and Regards
OP Lalwani
and we said...
PLL is a PLsql Library file.  It contains compiled PLSQL code.

You build it at design time.
We run it at runtime.
February 14, 2001 Lito -- Thanks for the question regarding "Where to obtain JDBC driver compatible with JDK 2?", version Oracle8i v.8.1.6 r.2
You Asked
Thomas:

Thank you for your previous answer. You suggested me to look for
the "classes12.zip" file in the $ORACLE_HOME/jdbc/lib directory.
However, I couldn't find such a file in the directory. All I
found were:
classes111.zip
classes111_g.zip
jndi.zip
jta.zip
nls_charset11.zip

It seems that by default, Oracle8i v.8.1.6 release 2 that comes
with Bobrowski's book doesn't have the classes12.zip file. May
you suggest where I could obtain the classes12.zip file? I've
looked everywhere in the oracle.com, the download section. I
found jdbc driver for download, but they are for Solaris and NT
platform.

-Lito

PS. My platform is Linux RedHat 7.
and we said...
http://technet.oracle.com/software/tech/java/sqlj_jdbc/software_index.htm
the thin drivers are OS independent (they are just java).  Grab
Solaris thin jdbc driver
February 14,
      2001 patibandla -- Thanks for the
      question regarding "no data found error, bulk collect , performance
      tuning", version 8.1.6.0

      You Asked
1. I am handling no_data_found error  in  three ways

a. Checking the count(*)  before selecting the data.
b. Using Cursors.
c. By Using Nested Blocks

In general which is the better way.

By Using Multiple Blocks is there going to be performance
overhead

2. I am  handling multiple rows fetch using
   a. bulk collect into array
   b. Open Cursor loop.. end loop

3.

a. execute immediate ('update '||v_table_name||' set
sm_Datecreated=sysdate');

   b.    execute immediate ('update '||:v_table_name||' set
sm_Datecreated=sysdate') using in v_table_name;

In reply to one of the question u have given
quote

"First and foremost -- this routine USES BIND VARIABLES.  It
does  not make the horrible mistake of putting character string
and numeric literals into a statement.  This is the worst thing
in
the world you can do in your case.  For every row you are
fetching right now -- you are building a unique, never before
seen insert statement that must be parsed, security checked,
optimized and so on.  I can promise you that in your routine
upwards of 90% of the execution time will be spent parsing
queries (inserts).  Using bind variables will reduce that to 10%

or less.  Removing the need to do individual inserts for each
row (you do not need to) will speed this up as well.  Never do
procedurally what you can do in a single SQL statement!"

unquote

In this case the table name is dynamically passed. Is the
performance going to imporove by using b. in this case.
or is it same in both the cases of a and b.

4. In an web based application a client has opened two
   ie windows and  it is connected to the database and
   two seperate database sessions have been created.
   after some time the connection to the database has been
   disconnected. But the  ie windows are still open and again
   it is connected to the database.

   I want to track the id of each window as long as it is open.
   Is it possible. Even if he disconnects and reconnects and if

   the windows is not closed i should get the  same id. and id
of  each open windows should be different.

      and we said...
1) select count(*) is the worst possible way and it does not
even WORK.  There is no reason why between the time you select
count(*) and the time you actually fetch the data, someone else
will have deleted that row.

A cursor works but it is slower then select into.

the proper way is:

   ...
   begin
      select a, b, c into x, y, y from t where ...
   exception
      when no_data_found then
         ...
   end;

you'll find that to be the safest and fastest way to do this.

2) great, unless you find yourself array fetching more then a
couple of dozen/hundred rows.  they'll all be going into ram so
be careful with that.  You can use the LIMIT clause on the fetch
to array fetch only N rows at a time.

3) bind variables can only be used where a character string
constant could be used.  for example in:

  update t set c = SOMETHING;

something should be a bind variable because we could code:

  update t set c = 'something';

on the other hand, we cannot code:

  update 't' set c = SOMETHING;

hence T cannot be a bind variable.  You cannot BIND identifiers,
only things that could be constants.  The query plan for

  update t ...

versus

  update t2 ....

would be very different, we need different queries with
different plans and security checks and so on.

4) in a real web based application you would not maintain a
connection.  What technology are you using in the middle tier to
maintain a session....  the answer to this deserves a whole
separate question as it could get involved.  One would need to
know the technologies you are using (eg: if this is the PLSQL
module/cartridge -- its not an issue, the datbase session only
lives as long as the stored procedure call is executing and then
it is gone.

February 14, 2001 Priscillia -- Thanks for the question regarding
      "decoding data in RAW after using utl_raw.cast_to_raw???", version 7.3.2
      & 8.1.6

      You Asked
Hi Tom!!

I have created two tables(test & test1) with columns data &
data1 in Oracle 8.1.6. Declare data = 88 & data1 = 20 . Then
execute:
select utl_raw.bit_and(utl_raw.cast_to_raw(a.data),
utl_raw.cast_to_raw(b.data)) from test a, test1 b

The result shows: 3A3B

Example 2:
data = 20
data = 30

result = 3230
WHY????

CAn U pls intrepret ????

Moreover I found that if I execute
utl_raw.cast_to_raw(8)

the result shows: 38
&
A=41
G=47
O=4F

Why the results are not in terms of 1 & 0 (binary format)???

LAst but not least,
Can I perform the above mentioned statements in Trusted Oracle
7.2.3????
If not, what sggestions???? becos all my info are in Trusted
Oracle ......

      and we said...
You are mixing up datatypes and doing lots of IMPLICIT
conversions.  Lets look at the utl_raw.cast_to_raw(8) first.

that is really utl_raw.cast_to_raw('8') (the number is converted
into a string -- cast to raw only does STRINGS).  So, we now
have RAW data '8'.  When you select that in sqlplus, sqlplus
converts the RAW into a VARCHAR -- it doesn't know how to
display RAW data -- only strings.  The rules for converting from
RAW to VARCHAR says to take EACH byte of the RAW data and
convert it into 2 hex characters.  Hence the '8' which is ascii
(decimal) 56 becomes hex 83.  Here is the logical progression:

number 8 - implicitly becomes ->
    string '8' - explicitly becomes ->
       raw '8' - implicitly become -> varchar2 again

ops$tkyte@DEV816> select utl_raw.cast_to_raw(8) from dual;

UTL_RAW.CAST_TO_RAW(8)
---------------------------
38

ops$tkyte@DEV816> select to_number(38,'xx') from dual;

TO_NUMBER(38,'XX')
------------------
                56

ops$tkyte@DEV816> select chr(56) from dual;

C
-
8

that shows it did exactly what you asked.

Now, the same thing happened for 88 and 20.  They were turned
into '88' and '20'.  You converted them into raw -- and the
STRINGS '88' and '20' were bitanded, not the numbers.  It
bitanded for example '8' and '0'.  Now, we know that

'8' = 56 decimal = 111000 binary
'0' = 48 decimal = 110000 binary
                   -------
                   110000 binary = 48 decimal = 30 hex

When I do 88 and 20, i get 3030 as the answer (not 3a3b, don't
know how you got that with that data)

select
utl_raw.bit_and(utl_raw.cast_to_raw(88),utl_raw.cast_to_raw(20))
from dual
ops$tkyte@DEV816> /

UTL_RAW.BIT_AND(UTL_RAW.CAST_TO_RAW(88),UTL_RAW.CAST_TO_RAW(20))
----------------------------------------------------------------
3030

which matches my expectation totally.

To get binary, you can get my hexdec packages from

http://osi.oracle.com/~tkyte/hexdec/index.html
Using that you can:

ops$tkyte@DEV816> set linesize 20
ops$tkyte@DEV816> l
  1  select lpad(to_bin(88),20,'0'),
  2        lpad(to_bin(20),20,'0'),
  3        lpad(to_bin(bitand(88,20)),20,'0')
  4* from dual
ops$tkyte@DEV816> /

LPAD(TO_BIN(88),20,'
--------------------
LPAD(TO_BIN(20),20,'
--------------------
LPAD(TO_BIN(BITAND(8
--------------------
00000000000001011000
00000000000000010100
00000000000000010000

which seems to be more like what you want.

Review &
      Followup

      Rating:
      5
Excellent  February 14, 2002
Reviewer:
      amol  from Sweden
You save me once again Tom

      Rating: 5
great
      script  November 20, 2002
Reviewer:  sv
       from Chicago, IL USA
Thanks for sharing the code.
It helped me to code more efficiently and not invent the wheel again.

      Rating: 3
varchar2 to
      hex  July 12, 2003
Reviewer:  Emad
       from Qatar
I have to convert a string to hex format in ucs2 encoding.
I have written a java program to do it, it works fine from command line, but
when I load it into database I only get ? marks.
here is what I've written

public class t {
public static void main (String arr[])throws Exception {
        System.out.println (
                toHex(
                        new String (
                                arr[0].getBytes("Cp1252"), "Cp1256")
                     ));

}

public static String toHex(String inStr) {
        String retVal = "";
        String tmp = "";
        char buff [] = inStr.toCharArray();
        for (int i = 0; i < buff.length; i++) {
                tmp = Integer.toHexString(buff[i]);
                int tmpLen = tmp.length();
                if (tmpLen < 4) {
                  for (int k = tmpLen; k < 4; k++) {
                        tmp = "0" + tmp;
                  }
                }
                retVal += tmp;
        }
        return retVal;
}

}

My database character set is "AR8MSWIN1256".
DB version is 9.2, after upgrading from 7.3 to 9.2 we first decided to go for
UTF8 encoding for out database but there were many problems, all our clients
were developer 2000 and 6/6i whenever they connect to UTF-8 9.2 DB they just
used to get crashed, so we reverted back to out charset of "AR8MSWIN1256".

The thing to note is that when I set my nls_lang
to AMERICAN_AMERICA.WE8ISO8859P1 and execute the java stored procedure from sql
plus it works fine.
but I need to execute the code from an asp client by calling stored procedure.
when I connect from IIS it takes the nls_lang("ar8mswin") of the database and
thus I get question marks when ever I execute it.
Is there any way to do this in pl/sql , for example
given a string in arabic
"&#1575;&#1579;&#1605;&#1605;&#1582;&#1610;&#1582;&#1587;&#1601;" should return
me
"0627062b06450645062e064a062e06330641" ucs2 hex-encoded
string.
Hope I am clear in my explanation
Thanks
Emad

----------------------------
Your server is converting the arabic string into #encoded values.
----------------------------

February 14, 2001 G-JoE -- Thanks for the question regarding
      "Picture format", version 8.1.5.5.0

      You Asked
how to retrieve an image from oracle database and view it in web?

      and we said...
depends on your middleware and what language you use.

for an example using the PLSQL module

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:232814159006
with webdb:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:384218737255
....

February 14, 2001 Dan -- Thanks for the question regarding "Tricky
      query", version 8.1.5

      You Asked
I´ll try the best to explain the problem.

The problem is that I want to indicate which services in the
query below that is active..(I compare all the service_id´s in
T_SERVICE against the subscriber active service_id´s in
T_ACTIVE_SERVICE) I have put som code(the if-then) that does not
work just to illustrate what I want to do.
As ju can se I use a ref_cursor and hope I still can do.

Is it possible to declare a variable and use the variable like I
do in the select?

PROCEDURE getActiveContainersByCategory(
            subscriber_id IN T_SUBSCRIBER.subscriber_id%TYPE
           ,category_id   IN T_MENU_CATEGORY.category_id%TYPE
           ,result          IN OUT ref_cursor) IS

t varchar2(10);

BEGIN
 OPEN result
 FOR SELECT DISTINCT mi.item_id, mi.jsp_path, mi.display_name,t
 FROM T_MENU_ITEM mi, T_ACTIVE_SERVICE a, T_SERVICE s
 WHERE mi.category_id =
getActiveContainersByCategory.category_id
 AND mi.item_id IN (SELECT item_id
                    FROM t_service
                    WHERE service_id IN (SELECT service_id
                         FROM t_active_service
                        WHERE subscriber_id =
getActiveContainersByCategory.subscriber_id))
      AND IF t_service.service_id IN (SELECT service_id
                 FROM T_ACTIVE_SERVICE.service_id
        WHERE getActiveContainersByCategory.subscriber_id =
subscriber_id) THEN T := 'active';

      and we said...
This looks like a cartesian product to me.

For every row in MI that is in the subquery, it'll be joined to
every row in A and then every row in MIxA will be joined to
every row in S.

Is that what you really want to do?

You can

open result for
'SELECT DISTINCT mi.item_id, mi.jsp_path, mi.display_name,
 (select ''active''
    from dual
   where exists ( select null
                    from t_active_service
                   where subscriber_id = :bv0
                     and subscriber_id = s.service_id ) T
 FROM T_MENU_ITEM mi, T_ACTIVE_SERVICE a, T_SERVICE s
 WHERE mi.category_id = :bv1
 AND mi.item_id IN (SELECT item_id
                    FROM t_service
                    WHERE service_id IN (SELECT service_id
                         FROM t_active_service
                        WHERE subscriber_id = :bv2 ))'
using subscriber_id, category_id,subscriber_id;

You have to use dynamic sql to select a select in PLSQL
currently, hence the quotes around the select.

February 14, 2001 vrishali -- Thanks for the question regarding
      "how to find process id in oralce database tables", version 8.1.6.2.0

      You Asked
Hi

  I have a question related to how to find out unix process id
on database table.

If I will open sqlplus session on unix box then I can find
process id by doing

ps -ef | grep sqlplus

oracle  5493  5481  0 16:14:29 pts/4    0:00 grep sqlplus
oracle  5479  5462  0 16:14:04 pts/4    0:00 sqlplus

But I want to know can I find out related record with this
process id 5479 in oracle database.
I have tried to find out in v$process table I can not able to
find out. Could you please tell me is it possible?

Thanks
Vrishali

      and we said...
select process from v$session where audsid =
userenv('sessionid')

will give you sqlplus's process id.

select spid from v$process where addr =
( select paddr from v$session where audsid =
userenv('sessionid'))

will get your DEDICATED servers process id.
February 15, 2001 -- Thanks for the question regarding "creating
      trigger/constraint for unique on a column..", version 8.1.6

      You Asked
hi ,
i have a table which has columns as below
primarykey is on (col1 + col2)

col1 col2 col3

0 1 a
1 1 a
2 1 b

0 2 c
1 2 b(*)
2 2 a(*)

it should not take the values because they are already there in
the previous row with col2 = 1

ie since (0,1,a) is already there (#,2,a)or (#,$,a) shouldnot be
allowed..
or since (2,1,b) is already existing (#,2,b)or (#,$,b) shouldnot
be allowed.(# means any number)($ means any number other than 1
ie col2)

ie the column col3 should be unique across col2..

i want to create a trigger(or any other constraint) to check
this ..how can i do this.
please advice..

regards

15 Feb '01:

sorry ..that was a mistake in my explanation...

let me reframe my sentence:

ie since (0,1,a) is already there (#,2,a)or (#,$,a) shouldnot be
allowed.. (1,1,a),(2,1,a),(3,1,a)...etc are to be allowed

or since (2,1,b) is already existing (#,2,b)or (#,$,b) shouldnot
be allowed.

(# means any number)($ means any number other than 1 ie other
than the col2 value with which it is associated now)

ie for every different value of col2 there has to be a different
col3; but for the same col2 there can be different col3.

for example:

col1 col2 col3
0 1 a
1 1 a
2 1 b

0 2 c
1 2 b(should not be allowed)
2 2 a(should not be allowed)
3 2 d

0 3 e
1 3 f
2 3 c(should not be allowed)
3 3 g
4 3 d(should not be allowed)

regards

      and we said...
With the creative use of

o IOT's (index organized tables)
o unique constraints
o foreign keys
o deferrable constraints
o a trigger

we can do this.  Here is an example:

ops$tkyte@ORA8I.WORLD> create table t_unique
  2  ( col3 char(1) unique,
  3    col2 int,
  4    primary key(col3,col2)
  5  )
  6  organization index
  7  /
Table created.

This will be a parent table.  You will never insert into this,
we'll do it in a trigger.  We want at most one value for col3 in
there (one 'a', one 'b' and so on) but the true primary key of
this object is col2,col3 (thats what our "child" table will
point to.

ops$tkyte@ORA8I.WORLD> create table t
  2  ( col1 int,
  3    col2 int,
  4    col3 char(1),
  5    constraint t_constraint
  6       foreign key(col3,col2)
  7       references t_unique
  8       deferrable );
Table created.

Now, here is our "child" table.  It references t_unique.  Now,
col3 must be unique in t_unique and col3,col2 must appear in
there.  That is the rule you want to enforce...

ops$tkyte@ORA8I.WORLD> create or replace trigger t_trigger
  2  after insert on t for each row
  3  begin
  4      execute immediate
  5        'set constraint t_constraint deferred';
  6      insert into t_unique
  7      ( col2, col3)
  8      values ( :new.col2, :new.col3 );
  9      execute immediate
 10         'set constraint t_constraint immediate';
 11  exception
 12      when dup_val_on_index
 13      then
 14         execute immediate
 15            'set constraint t_constraint immediate';
 16  end;
 17  /
Trigger created.

Here is the trigger that does the real work.  We defer
constraints for a moment, insert the row into the parent table
(if it already exists, we ignore it) and then check the
constraint straight away.  If the parent/child relationship
isn't enforced -- it'll fail.

Now to test it:

ops$tkyte@ORA8I.WORLD> insert into t values ( 0, 1, 'a' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1, 1, 'a' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 2, 1, 'b' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 0, 2, 'c' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1, 2, 'b' );
insert into t values ( 1, 2, 'b' )
*
ERROR at line 1:
ORA-02291: integrity constraint (OPS$TKYTE.T_CONSTRAINT)
violated - parent key not found

There you go -- rejected...

ops$tkyte@ORA8I.WORLD> insert into t values ( 2, 2, 'a' );
insert into t values ( 2, 2, 'a' )
*
ERROR at line 1:
ORA-02291: integrity constraint (OPS$TKYTE.T_CONSTRAINT)
violated - parent key not found

ops$tkyte@ORA8I.WORLD> insert into t values ( 3, 2, 'd' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 0, 3, 'e' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1, 3, 'f' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 2, 3, 'c' );
insert into t values ( 2, 3, 'c' )
*
ERROR at line 1:
ORA-02291: integrity constraint (OPS$TKYTE.T_CONSTRAINT)
violated - parent key not found

ops$tkyte@ORA8I.WORLD> insert into t values ( 3, 3, 'g' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 4, 3, 'd' );
insert into t values ( 4, 3, 'd' )
*
ERROR at line 1:
ORA-02291: integrity constraint (OPS$TKYTE.T_CONSTRAINT)
violated - parent key not found

Just to test multi-row inserts as well:

ops$tkyte@ORA8I.WORLD> insert into t
  2  select rownum, rownum, chr(ascii('A')+rownum-1)
  3  from all_users where rownum < 26;

25 rows created.

ops$tkyte@ORA8I.WORLD> insert into t
  2  select rownum+1, rownum+1, chr(ascii('A')+rownum-1)
  3  from all_users where rownum < 26;
insert into t
*
ERROR at line 1:
ORA-02291: integrity constraint (OPS$TKYTE.T_CONSTRAINT)
violated - parent key not found

February 15, 2001 Pri -- Thanks for the question regarding
      "Contradict PCTFREE and PCTUSED", version 8.1.6

      You Asked
What happens when the two setting PCTFREE and PCTUSED contradict
each other? Say, PCTUSED= 90% and PCTFREE= 40%?

      and we said...
trick question, they cannot:

ops$tkyte@ORA8I.WORLD> create table t ( x int ) pctfree 40
pctused 90;
create table t ( x int ) pctfree 40 pctused 90
*
ERROR at line 1:
ORA-04000: the sum of PCTUSED and PCTFREE cannot exceed 100

February 15, 2001 minnie -- Thanks for the question regarding "cold
      backup and recovery with RMAN", version 8i

      You Asked
hi Tom,
we are testing a cold database level 0 backup and recover for a
NOARCHIVE MODE database using the following scripts, backup was
secceed but recovery failed which cause "suggestion: media
recovery necessary,database is inconsistant ".
I noticed the in the manual of "BACKUP AND RECOVERY", there says
that BACKUP DATABASE includes control file but RESTORE DATABASE
does not include the control file. Does it mean it need to
restore the control file first in mode of database nomount?
please figure out if there are any problem in my scripts.

thanks

minnie

BACKUP:
SVRMGRL>connect internal
SVRMGRL>startup restrict open
SVRMGRL>shutdown immediate

SVRMGRL>connect internal
SVRMGRL>startup mount

RMAN nocatalog

RMAN> connect target 'user/pwd'

RMAN> run {
# Cold database level 0 backup
allocate channel t1 type 'SBT_TAPE';
allocate channel t2 type 'SBT_TAPE';
backup
  incremental level 0
  tag cold_db_bk_level0
  filesperset 5
  format 'bk_%s_%p_%t'
    (database);

# now that the backup is complete, open the db.
sql 'alter database open';
}

RECOVERY:
SVRMGRL>connect internal
SVRMGRL>startup mount

RMAN nocatalog

RMAN> run {
# Restore all datafiles, and recovers them completely.
allocate channel t1 type 'SBT_TAPE';
allocate channel t2 type 'SBT_TAPE';
  restore
    (database);
  recover
    database;
}

      and we said...
this shows how to backup a noarchivelog mode database:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76990/usingrma.htm#435660
and this is the example restoring it:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76990/rmanreco.htm#443066
....
February 15, 2001 Gajanan -- Thanks for the question regarding "how
      to process the array output from stored procedure inJDBC program", version
      8.1.6

      You Asked
Hi Tom
I am trying to write a procedure which select varchar field from
table using one selection  criteria and that returns multiple
rows.I want to get this output of multiple rows in my JDBC
program and display those rows.
I tried using VARRAY in Stored procedure but not sure exactly
how to use it also.ALso I tried a lot with JDBC programs but not
able to process those mulitple rows.
Can you please give me one example of how to write this
procedure and process it using JDBC program

Thanks in Advance and Regards ,

Prashant

      and we said...
I would use a ref cursor, see

http://osi.oracle.com/~tkyte/ResultSets/index.html
for examples.  If you really want to do the array, see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:331217279811
for an example.

February 15, 2001 Pete -- Thanks for the question regarding "SQL
      sub query with outter join", version Oracle 8.1.6

      You Asked
Hi Tom,
I have 2 tables that look like this.

Acct from   Acct from      name
Table 1        table 2
-----------------------------------------------------------
 80360181 00160360181 ENGEL, HERMAN W
 10869832 00170869832 ROLAND, MICHAEL
 10869832 00230869832 ROLAND, MICHAEL
 10869832 00250869832 ROLAND, MICHAEL
 10869832 00260869832 ROLAND, MICHAEL

The right most 7 digits of the acct numbers from table-2 relate
to the right most 7 digits acct numbers from table-1. The high
order digits in the acct number from table 2 are a sequence
number within the acct. I am trying to do an outer join using
table-1 as the master and select all accts from table1 and join
them with only the matching acct from table-2 with the highest
sequence number.
This is the query I am using…
SELECT
b.hcurrmrn "pm mrn",
lpad (wx_pt_no_woscd, 11,0) "sms acct",
sms.WX_PT_NAME "sms name"
FROM
hpbasic b,  WX_REC_DATA_AREA_DEMOG sms
where substr(hcurrmrn, -7, 7)  = substr(wx_pt_no_woscd (+) , -7,
7)
and
substr ( (lpad (wx_pt_no_woscd, 11, 0)), 1, 4 ) =
(select max (substr ((lpad (wx_pt_no_woscd, 11, 0)), 1, 4 ) )
from wx_rec_data_area_demog sms2
where substr (sms.wx_pt_no_woscd, -7, 7 ) = substr
(sms2.wx_pt_no_woscd, -7, 7 ) )

I can’t get the outer join to work so all accts from table 1 are
selected.
Can you help?

      and we said...
Here is a case where selecting a select (new 8i feature) comes
in very handy.  This will be much cleaner to code as well:

select table1.*,
       ( select max(acct)
           from table2
          where substr(table2.acct,length(table2.acct)-7) =
                substr(table1.acct,length(table1.acct)-7) )
  from table1
/

if you created a function based index on
   table2 ( substr(acct,length(acct)-7) )

this could be very efficient (see

http://osi.oracle.com/~tkyte/article1/index.html
for info on fbi's).

This selecting a select can make some hard to write queries
easier to understand and write and when used appropriately --
can increase performance as well in many cases
February 15, 2001 David -- Thanks for the question regarding
      "Sybase Stored Procedure to Oracle", version 816

      You Asked
Tom,

I can't understand the following stored procedure (only partial)
in Sybase while I'm converting it to Oracle.

*****************************************
1  select    CountryID = @CountryID,
2    PlatformID = @PlatformID,
3    pl.VendorID PlatformVendorID,
4    PlatformVendorAcctNum,
5    BillingVendorID = convert(int,null),
6    MDSViaID,
7    SvcID,
8    VendorID = convert(int,null),
9    MDSID = convert(varchar(16),null),
10    MDSP_ID = convert(int,null),
11    PVID = convert(int,null),
12    Num = count(*),
13    Type = convert(varchar(64),"Svc id not mapped")
14   into    #ExtSvcIDs
15   from    ExtSvcUsage e,
16    Platforms pl
17  where    e.CountryID = @CountryID
18  and    e.PlatformID = @PlatformID
19  and    e.Year = @CurrentYear
20  and    e.Period = @CurrentPeriod
21  and    pl.PlatformID = e.PlatformID
22  and    upper(e.SvcID) like upper(isnull(@SvcID,e.SvcID) +
'%')
23  group by pl.VendorID,
24    PlatformVendorAcctNum,
25    MDSViaID,
26    SvcID
***************************************************************
In line 1, CountryID = @CountryID what does it really do.  I
know you talked about alias, but since the right hand side is a
variable now, what the the effect?

In line 9, while I was compiling this store proc. it complaint
that there is no 'MDSID' column exist.  But anyway, what does it
try to do here?

Thanks.

David.

      and we said...
Well, TSQL is not my usual forte however....

@CountryID is a parameter to the procedure.  They are just
selecting a constant.  It is no different then if the selected a
column....

MDSID is not a column -- MDSID is an alias again.  We won't even
need it.

The query in oracle could be (assuming you named the INPUT
parameter countryId p_countryId)

create or replace procedure ..( p_countryid in number,
                                p_platformId in number,
                                p_SvcId  in varchar2.,
                                p_currentYear ..,
                                p_currentPeriod ... )
as
begin
   insert into
   ExtSvcIds -- this is a global temporary table you've created
   ( countryId, platformId, platformVendorId,
     PlatformVendorAcctNum, MDSViaId, SvcID, Num,
     Type )
   select  p_CountryID, p_PlatformID,
           pl.VendorID,  PlatformVendorAcctNum,
           MDSViaID, SvcID, count(*),
           'Svc id not mapped'
     from  ExtSvcUsage e,
           Platforms pl
    where    e.CountryID = p_CountryID
      and    e.PlatformID = p_PlatformID
      and    e.Year = p_CurrentYear
      and    e.Period = p_CurrentPeriod
      and    pl.PlatformID = e.PlatformID
      and    upper(e.SvcID) like
                  upper(nvl(p_SvcID,e.SvcID)||'%')
    group by pl.VendorID,
             PlatformVendorAcctNum,
             MDSViaID,
             SvcIDp;

February 16, 2001 David -- Thanks for the question regarding
      "Suspending and de-sudpending DBMS_JOB jobs", version 7.3.4.5 and
      8.1.6.0.0 and hopefully generic

      You Asked
Hi Tom,

We have the requirement to automate the function of teporarily
suspending all DBMS_JOB jobs, waiting until currently running
jobs are finished, before firing certain processes, and then
de-suspending all DBMS_JOBS after the process in question. So my
question, bearing in mind that if a job is marked as broken
whilst currently running then all details, including broken
status, are reset on successful completion, what is the optimum
way to suspend all DBMS_JOB jobs, check and wait for currently
running jobs to finish, and, seperately de-suspend all DBMS_JOB
jobs.

TIA
Regards
David

      and we said...
Well, in 8.0 and up, the easiest approach is:

ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;

that'll shutdown the job queues after they finish their jobs.
Unfortunately, that'll not work in 7.3 as that parameter could
not be changed online.

In 7.3, I cannot think of a way to do this at the database
level.  All of the parameters for the jobs are reset pretty much
at the end of the job -- so if you tried to set the NEXT_DATE
way out in the future, at the end of the job, it'll just set it
back on you (like broken is).  Changing the interval of a
running job won't help as the interval is used immediately
BEFORE the job is started.

I guess you would have to (in 7.3) set the broken flag on all
jobs that are not running and then monitor dba_jobs_running.  As
jobs complete, set their broken flag as well.  Running a query
such as:

  1  select job, cnt
  2     from user_jobs,
  3        ( select count(*) cnt
  4           from dba_jobs_running )
  5    where broken = 'N'
  6      and job not in ( select job from dba_jobs_running )
  7  union all
  8  select -1, count(*) cnt
  9*   from dba_jobs_running

and while CNT > 0, setting the broken flag for any positive job
that is returned.

February 16, 2001 Boris -- Thanks for the question regarding "Who
      to define an URL in FORMS", version forms 6i

      You Asked
Hi Tom,

Do you know how we could define an URL in forms6i ? We are
building our application in Forms6i. In every pages we need to
have lots of cool links which are basically external links. Our
intension is to pop up a new browser and direct the request to
the appropriate web site once user clicks the link. We can
easily do it in ASP by defining an URL, but havent find any clue
how to do it in FORMS. We are using oracle 8.1.7 database.
Please let me know, if it is not possible then we have to go
back to VB/ASP model.

Thanks

Boris

      and we said...
If you are running on the web, web.show_document is what you
want.  If you are client/server, HOST() will work.

WEB.SHOW_DOCUMENT(url, target);

Built-in Type:   unrestricted procedure
Enter Query Mode:  yes

Description:

Specifies the URL and target window of a Web application.

Parameters:

url    Datatype is VARCHAR2.  Specifies the Uniform Resource
Locator of the document to be loaded.
target    Datatype is VARCHAR2.  Specifies one of the following
targets:

_SELF  Causes the document to load into the same frame or window
as the source document.
_PARENT Causes the target document to load into the parent
window or frameset containing the hypertext reference.  If the
reference is in a window or top-level frame, it is equivalent to
the target _self.
_TOP Causes the document to load into the window containing the
hypertext link, replacing any frames currently displayed in the
window.
_BLANK Causes the document to load into a new, unnamed top-level
window.

Restrictions:

Can only be used from within a form run from the Web.

Example:

/*

** Built-in:  WEB.SHOW_DOCUMENT
** Example:   Display the specified URL in the target window.
*/
BEGIN
  Web.Show_Document(‘
http://www.abc.com’/
 ‘_self’);
END;

February 16, 2001 konstantina -- Thanks for the question regarding
      "Inserting blobs into table", version Oracle 8i

      You Asked
Hello Tom!

I would be gateful if you could help me with my problem...

I have created the table lobby
id varchar2(10)
b_lob blob
c_lob clob
n_lob nclob
f_lob bfile

and I try to insert a file in b_lob with the following code

declare
l_blob    blob;
l_bfile    bfile;
begin
insert into lobby values ( 1,
empty_blob(),empty_clob(),empty_clob(),null );
select b_lob into l_blob from lobby where id=1;
l_bfile:=bfilename( 'lobby_dir', 'CVKP.doc' );
DBMS_LOB.FILEOPEN( l_bfile );
DBMS_LOB.LOADFROMFILE( l_blob, l_bfile,
                                     dbms_lob.getlength( l_bfile
) );
DBMS_LOB.FILECLOSE( l_bfile );
end;

When I run the code I get the message :

declare
*
ERROR at line 1:
ORA-22285: non-existent directory or file for FILEOPEN operation
ORA-06512: at "SYS.DBMS_LOB", line 475
ORA-06512: at line 8

The directory and the file CVKP.doc exists as I tested it with a
simple bfile insertion.
What is the problem?

Thanks for your time
konstantina

      and we said...
Most likely, you created the directory like this:

create directory lobby_dir as ....;

That created a directory LOBBY_DIR, not lobby_dir (as unquoted
identifiers are upper cased).

When you call bfilename, you need to pass 'LOBBY_DIR'.  If you
like and prefer to use lower case you need to:

create directory "lobby_dir" as .....

using double quotes to avoid the upper casing.
February 16, 2001 Tomás A. -- Thanks for the question regarding
      "Security: Controlling access from Oracle and third party tools", version
      7.3.4.5.0, 8.1.7.0.0.

      You Asked
Dear Tom

We have a database security schema supported by Oracle roles
that are enabled depending on the user's business profile, but
we need to maintain these roles enabled by default for a subset
of users while an application issue is resolved.

How can we control the access from third party applications,
like EXCEL, Toad, ODBC Test, etc., while the all the user's
roles are still enabled by default?

It is possible to control the access from third party
applications using the product profile table?

NOTE: Currently we are using 7.3.4.5 but we will migrate to
8.1.7.0.0 soon.

Thanks in advance.

Tomás

      and we said...
Nope -- PUP cannot do this.  The applications have to do this.

Lets say your program (application) was called "myapp.exe".  I
could simply:

rename myapp.exe hold.exe
rename toad.exe myapp.exe

and all of a sudden TOAD looks just like myapp.  Applications
are not "signed" -- there is not too much we can do to prevent
an application from doing anything.

SQLPlus implemented the PUP in order to let you constrain what
users could do in it -- nothing else uses it and we have NO way
of knowing really what application is connected to the database
(copy your sqlplus.exe to hello.exe and use it to connect to
oracle, know look at the PROGRAM column in v$session -- we
cannot tell that it is really sqlplus).

Fine Grained Access control (FGAC), in 8i, can be very useful in
a situation like this (see

http://osi.oracle.com/~tkyte/article2/index.html
for info on that).  In 7.x -- I'm not sure what to tell you.  It
is for this reason I myself like to put the application INTO the
database (stored procedures).  I grant execute on my application
to the appropriate people.  I could care less if they run my
application from SQLPlus or Excel or the pretty GUI i created
for it.  The only way to touch my data is via my application.
FGAC expands that sort of protection out further.

February 16, 2001 Sridevi -- Thanks for the question regarding
      "Running a procedure in background", version Oracle 8.1.6

      You Asked
I am running two procedures from inside a form trigger/ another
procedure.

These procedures are run immediately one after the other but are
independent of each other.

Is it possible to run the first procedure as a background
proceess so that the execution of the second procedure can also
take place simultaneously.

      and we said...
You can perhaps use DBMS_JOB -- it runs procedures on the server
in background processes.

See the supplied packages guide or search for dbms_job on this
site for examples/details.
February
      17, 2001 Kishore -- Thanks for the
      question regarding "Major Diffirences between 8 and and 8i", version 8/8i

      You Asked
Hi Tom
 Iam Kishore
 I used to work as Oracle Programmer with oracle 8 database.
 currently
 I am working on oracle 11i Apps(Oracle 8i database.)
 would u Please tell me the major Differences between
 oracle 8 and 8i.
 thank u

      and we said...
see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76962/toc.htm
...
February 17, 2001 ahmad -- Thanks for the question regarding
      "scripts", version 8.1.5

      You Asked
hi tom;
I think u are really busy right?
1.what srcript should we run to create the package dbms_tts
2.what script should we run while migrating from earlier oracle
versions to oracle 8.1.5 which is used to convert the system
tablespace (upadate the data dic)?
tanx

      and we said...
1) it should already be installed.  By default in there is no
public synonym for it.  As sys, see if it is there:

SQL> desc dbms_tts

if that works, its there.  Then, as another user, try:

SQL> desc sys.dbms_tts

if that fails, you do not have EXECUTE on the package.  as sys,
grant execute on dbms_tts to whomever...  Then just use
sys.dbms_tts

2) see the migration guide for your system.  It has the exact
steps.  If you use the tools to automate this, they just do it
for you.  See

http://technet.oracle.com/doc/server.815/a67774/toc.htm
for the 8.1.5 migration guide.

February 17, 2001 Dusan -- Thanks for the question regarding
      "Getting rid of synonyms", version 8.1.6

      You Asked
Hi Tom.

The statement alter session set current_schema=some_schema is
great way how to get rid of synonyms. Nevertheless, since that
moment I see my objects as my_schema.my_object only, not just as
'my_object'. So, in this case I need (?) to create synonym for
my objects to work with them as before issuing statement 'alter
session  set current_schema=some_schema'.
Is there any other tricky way (except synonyms) how see objects
in more than 1 schema with no owner prefixes?

Thanks,

Dusan

      and we said...
Views are another method.

You have but one default schema active at a time.  There is no
hierarchy of default schemas to search through.
February 18, 2001 praveen -- Thanks for the question regarding "how
      to use win_api functions", version forms 6i Ver-1

      You Asked
How can I use win_api functions in Developer-2000 . Which
Library I have to include and what is its path ?

      and we said...
Problem Description
-------------------

D2KWUTIL files, d2kwutil.pll and d2kwut60.dll, are missing/not
installed with the Developer 6i (Forms 6i) installation.

Solution Description
--------------------

Install/copy these files from the Forms and Reports Demos CD.
The CD is bundled with the Oracle Tools Cd Pack.

Explanation
-----------

The d2kwutil.pll and d2kwut60.dll files have been moved to a
separate CD and need to be installed/copied manually.  These
files were installed automatically in previous versions of
Developer(Developer/2000).

Review &
      Followup

      Rating: 1
Answer was not
      clear....  October 30, 2001
Reviewer:  Riaz
      Shahid  from Islamabad,Pakistan
Tom,

Please explain ur answer by giving the details of preocedures and some examples
of the win_api library...

Regards

February 18, 2001 Doug -- Thanks for the question regarding
      "PL/SQL-need to return an inserted set", version 8.1.5 / 8.1.7

      You Asked
Tom, we need to insert about 800-1000 rows into a table within
the PL/SQL framework, and return that information from the
procedure/function to a piece of server code - (java based app
server).  We thought of a few options, using an array type,
table of, ref cursor; maybe you can think of more.  What would
be the most appropriate construct for this sort of operation?

Thanks..
Miss you on the newsgroups.

      and we said...
Ref Cursor is probably the right answer.  See

http://osi.oracle.com/~tkyte/ResultSets/index.html
for details.  It will be the most efficient way to return
800-1000 rows from PLSQL.  If you happen to have the data in a
SQL table type already you don't have to return a ref cursor or
an array, the client can just "select" from the plsql variable.
For example, below I have a procedure that fills the array up
and bulk inserts it (much much faster then inserting a row at a
time).  The client can then select * from the array -- this may
or may not apply in your case:

ops$tkyte@ORA8I.WORLD> create type myRecordType as object
  2  ( a int,
  3    b varchar2(10),
  4    c date
  5  )
  6  /
Type created.

ops$tkyte@ORA8I.WORLD> create table t
                      ( x int, y varchar2(10), z date );
Table created.

ops$tkyte@ORA8I.WORLD> create or replace type myTableType
  2  as table of myRecordType
  3  /
Type created.

ops$tkyte@ORA8I.WORLD> create or replace package my_pkg
  2  as
  3          procedure my_procedure;
  4
  5          function my_function return myTableType;
  6  end;
  7  /
Package created.

ops$tkyte@ORA8I.WORLD> create or replace package body my_pkg
  2  as
  3
  4  g_data myTableType;
  5
  6
  7  procedure my_procedure
  8  is
  9  begin
 10          g_data := myTableType();
 11
 12          for i in 1..50
 13          loop
 14            g_data.extend;
 15            g_data(i) := myRecordType( i, 'row ' || i,
                                                 sysdate+i );
 16          end loop;
 17
 18          insert into t
 19          select *
 20            from TABLE ( cast( g_data as mytableType ) );
 21  end;
 22
 23  function my_function return myTableType
 24  is
 25  begin
 26          return g_data;
 27  end;
 28
 29  end;
 30  /

Package body created.

ops$tkyte@ORA8I.WORLD> exec my_pkg.my_procedure;
PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> select * from TABLE ( cast(
my_pkg.my_function() as mytableType ) )
  2  /

         A B          C
---------- ---------- ---------
         1 row 1      19-FEB-01
         2 row 2      20-FEB-01
         3 row 3      21-FEB-01
.....
        49 row 49     08-APR-01
        50 row 50     09-APR-01

50 rows selected.

as for the newsgroups -- working on a book right now.  deadline
is end of march (hope I make it ;).  After its published in May,
I might be able to find some time to drop back in on the
newsgroups -- but there is always this forum...

February 18, 2001 Guru -- Thanks for the question regarding "About
      Objects", version 7.3 & above

      You Asked
Dear Tom,

   While creating a object table, like in relational table can
we add primary key, not null & other constraints to a object
table.

Thanking You,
Guru Prasad M.R.

      and we said...
definitely.  see

http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76976/adobjmng.htm#1003315
for all of the details.
February
      18, 2001 Kurian -- Thanks for the
      question regarding "Create table privilege", version 8.0.4

      You Asked
I have two schemas 'S1' and 'S2'. How do I grant 'S1' the
privilege to create tables in 'S2' ? I don't want to give the
create any table privilege.

      and we said...
You will do the following:

1) grant S2 the create table priv DIRECTLY (not via a role).
See

http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for why this is so.

2) in S2's schema you will create:

create or replace procedure create_table( p_sql in varchar2 )
is
    cursor_name     pls_integer default dbms_sql.open_cursor;
    ignore          pls_integer;
BEGIN
    dbms_sql.parse( cursor_name,
                   'CREATE TABLE ' || p_sql,
                    dbms_sql.native);
    ignore := dbms_sql.execute(cursor_name);
    dbms_sql.close_cursor(cursor_name);
END;
/

3) as S2 you will grant execute on CREATE_TABLE to S1.

4) now S1 can:

SQL> exec s2.create_table( 't ( x int )' );

and the table will be created in S2's schema.

February 18, 2001 Andy -- Thanks for the question regarding "Can
      Oracle8.16 be installed on Solaris8 ", version 8.1.6

      You Asked
Hi,

  I want to install Oracle8.1.6 with OPS on Solaris8 and Sun
cluster2.2,but I can not find any relative document about them.
What patches must be applied? .Could you give some instruction
or give me some document location?

Thanks very much

Feb,28,2001
Andy Wu

      and we said...
Version 8.1.6 OPS has been certified on 2.8 and 2.6 Solaris.

Operating System: Sun SPARC Solaris Version:2.8
Oracle Parallel Server (OPS) Version: 8.1.6
N/A Version: N/A
Status: Certified

Product Version Note:
None available for this product.

Certification Note:

VxVM 3.x required for O/S 2.8.

There is an installation issue:

Oracle Parallel Server (OPS) Version: 8.1.6
Bug Number: 1289644
NEW UDLM PACKAGE WITH SOLARIS8/SUNCLUSTERSOFTWARE3.0 SUPPORT
UDLM 3.3.4.4 required.

You may contact support regarding getting that patch.

All of this information is available on metalink.oracle.com.
February 18, 2001 Irina -- Thanks for the question regarding "Who
      is "current user"?", version 8.1.6

      You Asked
Hi, Tom.
Help me please to understand,
what must sys_context('USERENV','CURRENT_USER') return inside
procedure with definer rights?
Example:
14:43:03 backln@8.1> connect backln/psw@test
Connected.
14:43:14 backln@8.1> select
sys_context('USERENV','CURRENT_USER') from dual;

SYS_CONTEXT('USERENV','CURRENT_USER')
-----------------------------------------------------------------
---------------
BACKLN

14:43:49 backln@8.1> select count(*) from bl_ledger;

       COUNT(*)
---------------
           2128

Then BACKLN calls procedure of user FRONTLN (with definer
rights), which will print "CURRENT_USER"
-----------------------------------------------------------------
---------------
procedure cr_cont as
i pls_integer;
Begin
select count(*) into i from bl_ledger;
dbms_output.put_line('i = '||i);
dbms_output.put_line(sys_context('USERENV','CURRENT_USER'));
End cr_cont;
-----------------------------------------------------------------
---------------

14:44:08 backln@8.1> exec frontln.cr_cont
i = 1667
BACKLN

PL/SQL procedure successfully completed.

Why current user is BACKLN (not FRONTLN) inside procedure
cr_cont?

      and we said...
because the current USER is backln.  The "privilege" domain is
frontln but the USER is backln.

If you want the "privilege" schema, do something like this:

scott@ORA8I.WORLD> create or replace procedure sysctx
  2  as
  3  begin
  4      dbms_output.put_line
  5      ( sys_context( 'userenv', 'current_user' ) );
  6
  7      for x in ( select username, user_id
  8                   from all_users
  9                  where user_id = userenv('schemaid') )
 10      loop
 11          dbms_output.put_line
                  ( x.username || ' ' || x.user_id );
 12      end loop;
 13  end;
 14  /

Procedure created.

scott@ORA8I.WORLD> exec sysctx
SCOTT
SCOTT 34

PL/SQL procedure successfully completed.

scott@ORA8I.WORLD> @connect /

ops$tkyte@ORA8I.WORLD> exec scott.sysctx
OPS$TKYTE
SCOTT 34      <<<<======

PL/SQL procedure successfully completed.

February 18, 2001 Nilo -- Thanks for the question regarding
      "Fine-grained Access Package", version 8.1

      You Asked
Hi Tom,

In a package for fine-grained access associated with a table I
need to apply some logic based on the contents of the table
itself. Which predicate would apply to the SELECT of the table
inside the package? Or I can't do such thing? Would happen some
type of recursivity?

TIA

Nilo R. Paim

      and we said...
see

http://osi.oracle.com/~tkyte/article2/index.html
and search for "chicken".  This is what I call the "chicken and
egg" problem with FGAC.  If the policy function needs to read
the table -- but in order to read the table we need the policy
function -- we have a problem.  I show how to do this in that
paper.
February 18, 2001 Zsolt -- Thanks for the question regarding "
      Parameter Default Value", version 8.1.5

      You Asked
Hi Tom,

The parameter default value doesn't work for me, except if
I give Null to it.
In the following code snippet I give 'M' to Nyelv parameter
and the raise_application_error shows that the Nyelv string is
empty, if I call the function without a value.

For that reason the If statement is useless, so I can't benefit
of the Default value at all.
The _only_ value that I can give to default and really puts in
the parameter is null.
I've read the documentation but I saw nothing special concerning
this topic.

Function GetCegAdatLista( Azonosito VarChar2,Nyelv Char Default
'M') Return T_CEG_LISTA Is
  CegAdatRek T_CEG_LISTA ;

  Megnevezes VarChar2(50) ;
Begin

 raise_application_error(-20101,Nyelv ) ;

 If Upper(Nyelv) = 'M' Then
   Megnevezes := ' Torzs_Megnevezes_Magyar1 ';
 ElsIf Upper(Nyelv) = 'N' Then
   Megnevezes := ' TORZS_MEGNEVEZES_NEMET1 ';
 ElsIf Upper(Nyelv) = 'A' Then
   Megnevezes := ' TORZS_MEGNEVEZES_ANGOL1 ';
 End If ;

.............

Thank you in advance

      and we said...
Not having a full example from you I can only speculate as to
what you are doing incorrectly -- however I can assure you that
defaults work.  I use them extensively.

I can think of two possible reasons for your issue:

o You are sending NULL down explicitly, you are not allowing it
to default

o You are using a PACKAGE and you have the DEFAULT in the body
but not in the spec -- in which case, the DEFAULT doesn't really
exist (defaults must be in the spec).

Here is an example of both cases.  I would need a test case
similar to this if neither of these cases match your conditions
-- something I myself can run in my database.

tkyte@TKYTE816> create or replace
  2  function my_function( Azonosito VarChar2,
  3                        Nyelv Char Default 'M') Return number
  4  as
  5  begin
  6      raise_application_error( -20101,
                             'nyelv = "' || Nyelv || '"' );
  7  end;
  8  /
Function created.

tkyte@TKYTE816>
tkyte@TKYTE816> exec dbms_output.put_line(my_function (
'afdafda' ));
BEGIN dbms_output.put_line(my_function ( 'afdafda' )); END;

*
ERROR at line 1:
ORA-20101: nyelv = "M"
ORA-06512: at "TKYTE.MY_FUNCTION", line 5
ORA-06512: at line 1

That shows if I call my_function and do not pass anything for
nyelv, the value M is in fact supplied

tkyte@TKYTE816> exec dbms_output.put_line(my_function (
'afdafda', NULL ));
BEGIN dbms_output.put_line(my_function ( 'afdafda', NULL ));
END;

*
ERROR at line 1:
ORA-20101: nyelv = ""
ORA-06512: at "TKYTE.MY_FUNCTION", line 5
ORA-06512: at line 1

If on the other hand I pass NULL -- then NULL is in fact
passed...

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> create or replace package my_pkg
  2  as
  3      function my_function( Azonosito VarChar2,
  4                            Nyelv Char ) Return number;
  5  end;
  6  /

Package created.

Note that the spec does not have a DEFAULT

tkyte@TKYTE816> create or replace package body my_pkg
  2  as
  3
  4  function my_function( Azonosito VarChar2,
  5                        Nyelv Char  default 'M' )
                                             Return number
  6  is
  7  begin
  8      raise_application_error( -20101, 'nyelv = "' ||
                                              Nyelv || '"' );
  9  end;
 10
 11  end;
 12  /

Package body created.

But that the body does -- it doesn't count though, the default
must be in the spec as demonstrated below:

tkyte@TKYTE816>
tkyte@TKYTE816> exec dbms_output.put_line(my_pkg.my_function (
'afdafda' ));
BEGIN dbms_output.put_line(my_pkg.my_function ( 'afdafda' ));
END;

*
ERROR at line 1:
ORA-06550: line 1, column 28:
PLS-00306: wrong number or types of arguments in call to
'MY_FUNCTION'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

That is telling me there is NO default for nyelv

tkyte@TKYTE816> exec dbms_output.put_line(my_pkg.my_function (
'afdafda', NULL ));
BEGIN dbms_output.put_line(my_pkg.my_function ( 'afdafda', NULL
)); END;

*
ERROR at line 1:
ORA-20101: nyelv = ""
ORA-06512: at "TKYTE.MY_PKG", line 8
ORA-06512: at line 1

and if I pass NULL, NULL it is then...  NULL is a value like
any other -- it will not be replaced by a DEFAULT value.

February 18, 2001 Hanan -- Thanks for the question regarding
      "Querying & copying columns of type LONG", version Oracle Enterprise
      Ver-8.1.6

      You Asked
Dear Tom,

I'd b most grateful if u could answer these questions.
(And also if u cannot).

1) Say I've got the following table:
   ---------------------------------
   create table KUKU
   (
     id   number,
     xml  long     --(Consists of very long XML strings)
   );

- When I issue the following query,(using SQLPLUS), I get only a
  partial fragment of the values:

  SQL> spool d:\temp\kuku.spool  --(I need to analyze the
output)
  SQL>
  SQL> select xml from kuku
  SQL> where id=1234;
  SQL>
  SQL> spool off

  Seems that there's some kind of SQLPLUS environment setting
  for an output buffer size, which limits the outputs length.

  Do u know of any way in which I can overcome this problem ?

2) Say I've got another similar table KUKU1 (which is empty).
   ----------------------------------------------------------
   create table KUKU1
   (
     id   number,
     xml  long
   );

- And I wish to copy KUKU's contents into KUKU1, I find that
  when running the following SQL statement,(again on SQLPLUS):

  SQL> insert into KUKU1
          select * from KUKU;

  I receive the following error msg:
  "ORA-00997: illegal use of LONG datatype".

  Is there any other way of copying long type columns ?

  Thanks alot in advance.
      Hanan.

      and we said...
first -- you should not be using LONG, you should be using CLOB,
it is infinitely more flexible.

1)

SQL> set long 5000

and now you'll see the first 5000 bytes.  set long 50000, and
you'll get 50000 bytes and so on.

2) use a CLOB (longs are depricated datatypes only available for
backwards compatibility).  Do not use a LONG.

In sqlplus, you can copy using the copy command.  this works
ONLY in sqlplus.  see

http://osi.oracle.com/~tkyte/Misc/MoveLongs.html
for an example. (but don't use LONGS in the first place.  A
simple insert into with CLOBS works great)


Subject | Article | Last Updated (East coast time)
Poor performance in call PLSQL Stored from Java | article only | Feb 19, 2001 09:06 am
retrieve the column | article only | Feb 19, 2001 10:16 am
External Procedure calling Pro*C | article only | Feb 19, 2001 10:46 am
Transfer of data from Table A (test) to Table B(temp_main) | article only | Feb 19, 2001 10:53 am
Is This Impossible..... | article only | Feb 20, 2001 07:22 am
retrieve blobs from database in directory | article only | Feb 20, 2001 02:49 pm
multiple oreder by using connect by clause | article only | Feb 20, 2001 03:20 pm
diff result | article only | Feb 20, 2001 03:54 pm
query | article only | Feb 20, 2001 04:02 pm
Regular table to Temp table | article only | Feb 20, 2001 04:10 pm
multi-platform code to transfer data in db | article only | Feb 21, 2001 09:10 am
Calling java from PL/SQL | article only | Feb 21, 2001 09:12 am
Run a Unix Shell Script from inside a Form | article only | Feb 21, 2001 10:45 am
Converting and index | article only | Feb 21, 2001 03:15 pm
Obtaining Release Version | article only | Feb 21, 2001 03:18 pm
log question | article only | Feb 22, 2001 08:49 pm
about BLOB's | article only | Feb 22, 2001 08:50 pm
ID's without Gaps | article only | Feb 22, 2001 09:22 pm
Performance and Overhead | article only | Feb 22, 2001 09:25 pm
Random text generation | article only | Feb 22, 2001 09:34 pm
sending notification | article only | Feb 22, 2001 09:36 pm
utl_file.Write Error | article only | Feb 22, 2001 09:44 pm
RMAN and Cold Backups | article only | Feb 23, 2001 08:39 am
default variables in SQL*Plus | article only | Feb 23, 2001 08:44 am
DBMS_RLS | article only | Feb 23, 2001 09:20 am
Foreign Key | article only | Feb 23, 2001 01:14 pm
Using an Executable in an Pl Sql Block And Scripts | article only | Feb 24, 2001 09:19 am
database | article only | Feb 24, 2001 09:43 am
ANALYZE INDEX | article only | Feb 24, 2001 01:56 pm
Rollback During Killing a transaction | article only | Feb 24, 2001 05:06 pm
fine grained access control | article only | Feb 25, 2001 09:46 am
Role of network files (tnsnames.ora, listener.ora. sqlnet.ora) | article only | Feb 25, 2001 09:49 am
CBO and one table is not analyzed. What happens. | article only | Feb 25, 2001 09:55 am
Reducing the size of system tablespace | article only | Feb 25, 2001 10:08 am
HOW TO COMPARE TWO SCHEMAS | article only | Feb 25, 2001 10:11 am
running app (or executable) when value changes in oracle DB | article only | Feb 25, 2001 04:49 pm
row(s) 1 - 36 of 36
February 19, 2001 Alessandro -- Thanks for the question regarding "Poor performance in call PLSQL Stored from Java", version 8.1.7
You Asked
Hi,
I am converting a huge java application from SQL Server 7 to
Oracle 8.1.6. All interface to data was written with 300 very
simple TSQL Stored Procedure like select * from ..... where..
etc where a ResultSet (cursor is returned).
My Oracle DBA converted all Stored Procedure but all application
the procedure is very slow.
Afer 2 days of profilng I understand :
ALL call to Stored procedure from Java to Oracle is 2 times more
slow than original SQL Server.
I use ORACLE JDBC 8.1.7 driver with Callable statement.

The DB performance is the same : table are right indexes.

1000 calls to a simple TSQL Stored procedure like this

select * from address where ID = 1001

take 1612 milliseconds in SQL 7
and in Oracle for the same thing the result is 3101 !!!!

After profling the real problem is not the data on DB (the
stored lanchued from PL/SQL takes 0.0 seconds) but is the call
from Java to Oracle (I see tons of questions about it but
nothing REAL answer). This is confirmed because if i call the
PL/SQl procedure 1000 times from PL/SQl the time is 0.2
!!!!!!Now for me is very hard rewrite all access to data and I
Think that this is a good choiche (pattern MVC) to divide access
to view data.

All this code is used in 137 JSP pages on our site.
Is very difficult (or impossible) to obtain all data in a single
call. ALL texts in the pages are stored in DB and all data too.

Now the SQL Stored Procedure (in the GET package) :

PROCEDURE word1_b(IDWord1 IN NUMBER,str OUT varchar2) IS
begin
select word into str from Words where ID=IDWord1 and rownum <= 1
order by IDLanguage ;
exception when no_data_found then str:=null;
end;

PROCEDURE wordb(IDWord1 IN NUMBER,IDLang1 IN NUMBER,str1 OUT
varchar2) IS
begin
select /* INDEX(WORDS,XAK1WORDS) */ word into str1 from Words
where ID=IDWord1 AND IDLanguage=IDLang1;
exception when no_data_found then str1:=null;
end;

and the Java code (this routine is used for profiling ):

synchronized String getWordb(int ID,int IDLang,Connection conn)
throws SQLException {
            CallableStatement stmt = null;
            ResultSet rs  = null;
              String word="";
        stmt = conn.prepareCall("{ call get.wordb (?,?,?)}");
            stmt.setInt(1,ID);
         stmt.setInt(2,IDLang);
        stmt.registerOutParameter (3, java.sql.Types.VARCHAR);
        stmt.execute();
        word = stmt.getString (3);
        if (word == null) {
          stmt=conn.prepareCall("{ call get.word1_b (?,?)}");
              stmt.setInt(1,ID);
              stmt.registerOutParameter (2,
java.sql.Types.VARCHAR);
              stmt.execute();
          word =  stmt.getString (2);
            }
        stmt.close();
            return word;
    }
and we said...
Ok, first -- not all databases are the same.  What is a best
practice in one is not in the other.  The above is definitely
not a "best practice" in Oracle...

I myself would have coded that much differently -- it would
definitely have been 1 stored procedure, not two chained
together by the client over the network.

I definitely would optimize this code as follows (without
changing the database and without changing the way it behaves on
anyones database):

 CallableStatement stmt;
 CallableStatement stmt2;

synchronized String getWordb(int ID,int IDLang,Connection conn)
throws SQLException
{
        String word="";
        if ( stmt = null )
           stmt = conn.prepareCall("{ call get.wordb (?,?,?)}");
        stmt.setInt(1,ID);
        stmt.setInt(2,IDLang);
        stmt.registerOutParameter (3, java.sql.Types.VARCHAR);
        stmt.execute();
        word = stmt.getString (3);
        if (word == null)
        {
          if ( stmt2 = null )
             stmt=conn.prepareCall("{ call get.word1_b (?,?)}");

          stmt2.setInt(1,ID);
          stmt2.registerOutParameter (2,java.sql.Types.VARCHAR);
          stmt2.execute();
          word =  stmt2.getString (2);
        }
        return word;
    }

at a minimum that is what I would do.  preparing a statement
before each and every call is the very worst thing you can do to
us.  You are doing what is called a soft parse before each and
every call to the database.  You might just as well compile each
class method before any invocation as well -- the effect is
pretty much the same.  You wouldn't dream of invoking javac and
dynamically loading a class every time to invoke a method -- you
are effectively doing that to us by preparing a call each and
every time.

even more so -- the above database logic really belonged in the
database.  You could fix this immediatly by using a single
statement that does:

   declare
      w varchar2(255);
   begin
      get.wordb( ?,?, w );
      if ( w is null ) then
          get_wrod1_b( ?, w );
      end;
      ? := w;
   end;

or creating a stored procedure really_get_word() that does the
above logic.

Just to show you the difference between "compiling a statment
and executing" and "compile it once, execute it many" I wrote a
small java program.  The results are:

> java test
JDBC driver version is 8.1.6.2.0
2001-02-19 09:02:14.46: Going to bad
2001-02-19 09:02:16.932: Going to good
2001-02-19 09:02:17.992: done

2.472 seconds the "bad" way.
1.060 seconds the "good" way.

the test code was:

import java.sql.*;
import oracle.jdbc.driver.*;
import oracle.sql.*;

class test
{

public static void showTimeStamp( String msg )
{
    System.out.println( (new
       Timestamp(System.currentTimeMillis())).toString() +
                  ":" + msg );
}

static CallableStatement cstmt_persistent;

public static void good_way(Connection conn ) throws Exception
{
    if ( cstmt_persistent == null )
    {
        cstmt_persistent =
             conn.prepareCall("{ call proc2( ?, ? ) }" );
        cstmt_persistent.registerOutParameter
                          ( 2, java.sql.Types.VARCHAR );
    }
    cstmt_persistent.setInt(1, 1);
    cstmt_persistent.execute();
    String w = cstmt_persistent.getString(2);
}

public static void bad_way(Connection conn ) throws Exception
{
    CallableStatement cstmt =
        conn.prepareCall("{ call proc1( ?, ? ) }" );

    cstmt.setInt(1, 1);
    cstmt.registerOutParameter( 2, java.sql.Types.VARCHAR );

    cstmt.execute();
    String w = cstmt.getString(2);
    cstmt.close();
}

public static void main(String args[])throws Exception
{
    DriverManager.registerDriver
     (new oracle.jdbc.driver.OracleDriver());

    Connection conn=DriverManager.getConnection
      //("jdbc:oracle:thin:@aria-dev:1521:ora816dev"
      ("jdbc:oracle:oci8:@ora816dev.us.oracle.com"
          ,"scott","tiger");

    DatabaseMetaData meta=conn.getMetaData();
    System.out.println
    ("JDBC driver version is "+meta.getDriverVersion());

    conn.setAutoCommit(false);

    // stmt.execute( "alter session set sql_trace=true" );

    showTimeStamp( "Going to bad" );
    for( int i = 0; i < 1000; i++ ) bad_way(conn);

    showTimeStamp( "Going to good" );
    for( int i = 0; i < 1000; i++ ) good_way(conn);

    showTimeStamp( "done" );
}
}

proc1 and proc2 were simply:

scott@DEV816> create or replace procedure proc1( x in int, y out
varchar2 )
  2  as
  3  begin
  4     y:='hello';
  5  end;
  6  /

Procedure created.
scott@DEV816> create or replace procedure proc2( x in int, y out
varchar2 )
  2  as
  3  begin
  4     y:='hello';
  5  end;
  6  /

Procedure created.
Review & Followup
Rating: 5
Good answer, critical for anyone wanting to scale June 04, 2001
Reviewer: Harrison from Haymarket, VA USA
For anyone who has not seen the almost identical discussion
of bind variables, this a good primer.  There are so many
tools (prepared statements, callable statements) that speed
things up that you have to wonder why every class on
programming doesn't start with a short list of "Don't
do this", kinda like they do in soccer:"Don't shoot into
own goal".

Rating: 5
Informative but has a compile time error August 17, 2001
Reviewer: Franz Holzinger from Germany
There's an Error in the following statement:
        if ( stmt = null )
           stmt = conn.prepareCall("{ call get.wordb (?,?,?)}");

It must be:

        if ( stmt == null )
           stmt = conn.prepareCall("{ call get.wordb (?,?,?)}");

Followup:
absolutely correct - sorry about that, it needs to be == not just =

February 19, 2001 geetha -- Thanks for the question regarding "retrieve the column", version 8
You Asked
How do I retrieve a same column in a table in ascending and
descending values at a time?
eg. rollno rollno
1 3
2 2
3 1
and we said...
In Oracle8i (you did not really specify a version) and up, you
can:

scott@DEV816> create table t
  2  as
  3  select substr('data ' || to_char(rownum,'09'), 1, 10 ) data
  4    from all_users
  5   where rownum < 11;

Table created.

scott@DEV816>
scott@DEV816> select data1, data2
  2    from ( select rownum r1, data data1
  3               from ( select *
  4                        from t
  5                       order by data ) t ) t1,
  6         ( select rownum r2, data data2
  7               from ( select *
  8                        from t
  9                       order by data DESC ) t ) t2
 10   where t1.r1 = t2.r2
 11  /

DATA1    DATA2
-------- --------
data  01 data  10
data  02 data  09
data  03 data  08
data  04 data  07
data  05 data  06
data  06 data  05
data  07 data  04
data  08 data  03
data  09 data  02
data  10 data  01

10 rows selected.
February 19, 2001 Andrea -- Thanks for the question regarding "External Procedure calling Pro*C", version 8.1.7
You Asked
I tried to use External Procedure along with Pro*C. First time I
always failed to call Pro*C and the error is something like lost
RPC connection. As I read Pro*C/C++ Precompiler Programmer's
Guide, I change my old code in the way of connect like sample
code there,

void test(epctx)
OCIExtProcContext *epctx;
{
    int  num_ret;
    EXEC SQL WHENEVER SQLERROR DO sql_error("Connect error:");

    EXEC SQL REGISTER CONNECT USING :epctx;

    EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error:");
    EXEC SQL DECLARE c1 CURSOR FOR
        SELECT username, program, machine into v_username,
v_program, v_machine
FROM v$session
         where username is not null and program is not null and
program not like
 'insert%';
    EXEC SQL OPEN c1;

which using REGISTER CONNECT USING ... rather than EXEC SQL
CONNECT :username IDENTIFIED BY :password; in the old one.

1. Problem arrise when I try to compile that code, it show error
around OCIExtProcContext.
Why this could happened ? Is it because I have to put header
file in my code ? If yes, what library / header should I use ?

2. If I want to use External Procedure calling Pro*C, is it the
same manner as the conventional one ? Because in the book it
show a little bit difference between them like
"CREATE OR REPLACE PROCEDURE xxx AS EXTERNAL NAME "yyy" LIBRARY
"zzz" WITH CONTEXT PARAMETERS(CONTEXT)"
in the Pro*C manual, compared with
"CREATE OR REPLACE PROCEDURE XXX AS EXTERNAL LIBRARY "zzz"
CALLING STANDARD C NAME "yyy" PARAMETERS (a,b)" in the ordinary
External Procedure.

3. Do I have to make library first in the External Procedure
calling Pro*C ?

4. Can I use trigger calling Pro*C ? How ?

5. How can I handle error in the Database Logon Trigger when I
use RAISE_APPLICATION_ERROR ? because when I try to raise that
error, I get 3 error message instead of 1 that I want to be.
and we said...
1) if you cannot get the code to compile, don't even bother
trying to execute it!!!

You need to get a clean compile.  Yes, you need to include
"oci.h" to get the definition of OCIExtProcContext.

2) I prefer to be totally explicit in my calls, for example -- I
use the syntax:

function write( p_path in varchar2, p_filename in varchar2,
                p_lob in blob )
return binary_integer
as
language C
name "lobToFile"
library lobtofile_lib
with context
parameters( CONTEXT,
            p_path     STRING,
            p_path     INDICATOR short,
            p_filename STRING,
            p_filename INDICATOR short,
            p_lob      OCILOBLOCATOR,
            p_lob      INDICATOR short,
            RETURN INDICATOR short );

That particular binding layer maps to the C routine:

int lobToFile( OCIExtProcContext * ctx,
               char *              path,
               short               path_i,
               char *              filename,
               short               filename_i,
               OCIBlobLocator  *   blob,
               short               blob_i,
               short *             return_indicator )

3) yes, you need a library in order to do an extproc.  On NT you
need a dll, on Solaris a .so file.  If you do not have that --
you cannot get anywhere.

4) once you get the code compiled and you create the PLSQL
binding layer in demonstrated in (2) you can write a trigger
that is just a CALL to the external procedure.

5) user errors like that will be wrapped in other error
messages.  That is the way the errors work in Oracle.  You will
get an exception stack -- not a single message.
February 19, 2001 Priscillia -- Thanks for the question regarding "Transfer of data from Table A (test) to Table B(temp_main)", version 7.2.3
You Asked
Hi Tom!

Attached below is the template for Table A:

Name                        Null?      Type?
----------------------------------------------------
stu_name                    Not Null   varchar2(30)
matrix_no                   Not Null   varchar2(10)
no_of subj                  Not Null   varchar2(50)
grades                      Not Null   varchar2(50)
yr_of enrolment             Not Null   varchar2(4)
no_of_units                 Not Null   varchar2(100)
ECA                                    varchar2(100)
no_ECA_pts                             varchar2(200)

There are thousands of records stored inside my database.
Each record consists of stu_name, matrix_no, no_of_subj, grades,
yr_of_enrolment,no_of_units,ECA & no_ECA_pts.(ie. Each record
have 8 items in Table A)Furthermore, when Null column is blank,
it is considered Null.

I need to transfer all the records from Table A to Table B and
add another item (string_to_bits) into Table B. Therefore, Table
B will have something like :

Name                        Null?      Type?
----------------------------------------------------
stu_name                    Not Null   varchar2(30)
matrix_no                   Not Null   varchar2(10)
no_of subj                  Not Null   varchar2(50)
grades                      Not Null   varchar2(50)
yr_of enrolment             Not Null   varchar2(4)
no_of_units                 Not Null   varchar2(100)
ECA                                    varchar2(100)
no_ECA_pts                             varchar2(200)
string_to_bits              Not Null   varchar2(128)

I would appreciate very much if U could advise me to write a
loop function so that I can transfer thousands of records from
Table A to Table B and insert additional data(string_to_bits)
into Table B.
Note: String_to_bits will have data like
      '000000000000011001000010010101011100000101.....010111'
There are a total of 128 bits in a string.

Hope U will reply me ASAP...

Thks ..

Best Rgds,
Priscillia
and we said...
insert into tb
select ta.*, string_to_bits(....) from ta;

does it all.  Or you can use the sqlplus copy command.  See
http://osi.oracle.com/~tkyte/Misc/MoveLongs.html
for an example of that.
February 20, 2001 Ganesh -- Thanks for the question regarding "Is This Impossible.....", version 8.1.5
You Asked
Hi,

I have a Table

Tab1(Name Varchar2, Sex Varchar2)

Values are as Follows...

Name         Sex
AA           M
BB           M
CC           M
XX           F
YY           F
ZZ           F

I need a Output Like This

Male     Female
AA       XX
BB       YY
CC       ZZ

As Regards u'r Question are the same number of Male And Femal
Records "No".

No There are No Upper Bounds to This Query.

Thanks.

Regards,
Ganesh R
and we said...
There is but it'll be pretty slow.  Since the M/F's don't have
the same number of rows we'll need to synthesize a set of
numbers that is as big as the biggest count of M or F's.  Then,
we can outer join the other two sets to it.  It could look like
this:

ops$tkyte@DEV816> create table t ( name varchar2(2), sex char(1)
);

Table created.

ops$tkyte@DEV816> insert into t values ( 'aa', 'm' );
1 row created.

ops$tkyte@DEV816> insert into t values ( 'ab', 'm' );
1 row created.

ops$tkyte@DEV816> insert into t values ( 'ac', 'm' );
1 row created.

ops$tkyte@DEV816> insert into t values ( 'xw', 'f' );
1 row created.

ops$tkyte@DEV816> insert into t values ( 'xx', 'f' );
1 row created.

ops$tkyte@DEV816> insert into t values ( 'xy', 'f' );
1 row created.

ops$tkyte@DEV816> insert into t values ( 'xz', 'f' );
1 row created.

ops$tkyte@DEV816> select b.name, c.name
  2    from ( select rownum r
  3             from all_objects
  4            where rownum <= ( select max(count(*))
  5                                from t
  6                               group by sex )
  7         ) a,
  8         ( select rownum r1, name
  9             from t
 10            where sex = 'm' ) b,
 11         ( select rownum r2, name
 12             from t
 13            where sex = 'f' ) c
 14   where a.r = b.r1(+)
 15     and a.r = c.r2(+)
 16  /

NAME                           NAME
------------------------------ ------------------------------
aa                             xw
ab                             xx
ac                             xy
                               xz
February 20, 2001 konstantina -- Thanks for the question regarding "retrieve blobs from database in directory", version 8i
You Asked
Hi Tom!!

I wonder if there is a way retrieve a blob ( or a lob generally)
from the database and place it in a directory . The blob can be
a pdf , excel ,doc or image file .Is this possible to do this
with a PL/SQL program?Give me an example if you can..
I think this is possible using java and sqlj,right?

Thank you..
Konstantina
and we said...
Possible via Java and C and many other 3gls, not possible via
PLSQL only.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:238014476571
for a java example.  It writes a long to a blob but they
are both just streams as a file would be.  same concept.
February 20, 2001 deepti -- Thanks for the question regarding "multiple oreder by using connect by clause ", version 8i
You Asked
I have this a table something like

msg_no  number
thr_no  number
msg_desc varchar2
p_date  date

where thr_no and msg_no have a parent child relationship
I am using the connect by prior to get the data in a herarchial
form.
  I also need to sort the data on msg_desc asc and then on
p_date descending , while maintaing the herarchy of the data.

I have managed to sort on the msg_desc successfully , but the
moment i add , the date or sort on the date seperately I loose
my heirarchy.
  Please help .

thanks
and we said...
Sorry, but connect by and order by just do not mix.  there is no
real way to do this reliably.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:9212348049
You might be able to create an index on

( msg_no, msg_desc, p_date DESC )

if you connect by prior thr_no = msg_no

or

( thr_no, msg_desc, p_date DESC )

if you connect by prior msg_no = thr_no and if the optimizer
chooses to use your index -- the data would tend to come out
sorted by msg_desc, p_date.
February 20, 2001 alan -- Thanks for the question regarding "diff result", version 8.1.6
You Asked
Hi, Tom,

under non-sys dba account using SQL*PLUS, and you will see
different reults:
I want to know why is this?

1.
declare
cnt integer;
begin
select count(*) into count1 from all_objects;
dbms_output.put_line ( 'cnt: ' || count1);
end;
/

2.
create or replace procedure test2
as
cnt integer;
begin
select count(*) into count2 from all_objects;
dbms_output.put_line ( 'cnt: ' || count2);
end;
/

exec test2
and we said...
do this:

SQL> set role none;

and then run the example.  roles are not enabled in procedures
(well, with invokers rights they can be but that is totally
different).

See
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for why this is.
February 20, 2001 alan -- Thanks for the question regarding "query", version 8.1.6
You Asked
Facing one small problem. I have following data in a table

Rec No Cust_id Date
------- -------- -----
1 1001 01/01/2001 10.20.00
2 1001 01/01/2001 10.30.00
3 1001 01/01/2001 09.30.00

I need the record - one less than max date. i.e. Rec No. 1

Please advise what query/PL SQL i should run.

Thank in advance
and we said...
Well, here are a couple of ways that work in 8.1.6 (the order by
in the inline view is 8.1.5 and up, the rank() is 8.1.6 EE and
up):

scott@DEV816> select ename, empno, hiredate
  2    from emp
  3   order by hiredate desc
  4  /

ENAME           EMPNO HIREDATE
---------- ---------- --------------------
adams            7876 12-jan-1983 00:00:00
scott            7788 09-dec-1982 00:00:00
miller           7934 23-jan-1982 00:00:00
james            7900 03-dec-1981 00:00:00
ford             7902 03-dec-1981 00:00:00
king             7839 17-nov-1981 00:00:00
martin           7654 28-sep-1981 00:00:00
turner           7844 08-sep-1981 00:00:00
clark            7782 09-jun-1981 00:00:00
blake            7698 01-may-1981 00:00:00
jones            7566 02-apr-1981 00:00:00
ward             7521 22-feb-1981 00:00:00
allen            7499 20-feb-1981 00:00:00
smith            7369 17-dec-1980 00:00:00

14 rows selected.

scott@DEV816> select ename, empno, hiredate
  2   from ( select ename, empno, hiredate, rownum r
  3           from ( select ename, empno, hiredate
  4                    from emp
  5                   order by hiredate DESC )
  6          where rownum <= 2 )
  7  where r = 2
  8  /

ENAME           EMPNO HIREDATE
---------- ---------- --------------------
scott            7788 09-dec-1982 00:00:00

scott@DEV816>
scott@DEV816> select ename, empno, hiredate
  2    from emp
  3   where ( select count(*)
  4             from emp b
  5            where b.hiredate > emp.hiredate ) = 1
  6  /

ENAME           EMPNO HIREDATE
---------- ---------- --------------------
scott            7788 09-dec-1982 00:00:00

scott@DEV816>
scott@DEV816> select ename, empno, hiredate
  2    from ( select ename, empno, hiredate,
  3                  rank() over ( order by hiredate DESC ) r
  4             from emp )
  5   where r = 2
  6  /

ENAME           EMPNO HIREDATE
---------- ---------- --------------------
scott            7788 09-dec-1982 00:00:00
February 20, 2001 David -- Thanks for the question regarding "Regular table to Temp table", version 816
You Asked
Hi Tom,

Is there a way that I can convert regular tables to temp tables
in a bulk?
For example, say in a procedure I suppose to create a temp table
for it to be referenced to, but instead I made a mistake, I
created a regular table.  I think the procedure still works but
it's just right.  Hence, I would like to convert those tables to
actually temp tables.

Another question is...you mentioned about a temp table must be
created statically, meaning can't create it on the fly. So that
means if I have 300 store procedures which all need temp tables
with different or slightly different columns, then I'll have to
create 300 temp tables? And all 300 temp tables occupy physical
spaces, am I correct? In that case, wouldn't the database grow
ennormously?

Please advise, thank you.

David.
and we said...
create global temporary table T as select * from old_table;
drop table old_table;
rename T to old_table;

that'll convert them.

temporary tables consume a row in the data dictionary -- thats
all.  They do not consume space in segments like a real table
does.
February 21, 2001 alan -- Thanks for the question regarding "multi-platform code to transfer data in db", version 8.1.6
You Asked
Help needed when inserting data from a UNIX box running Oracle
7.3.4 to an NT box running Oracle 8.1.6.

When trying to insert data from the UNIX box to the NT box I
receive the following error:

ORA-02085: database link SYS_LINK.CCB.COM connects to SYS.WORLD

1) On the NT box I created the following database link:
create database link sys_link connect to scott identified by
tiger using 'sys';

2) I submitted the SQL statement:
insert into table_a
select * from table_a@sys_link;

3) I receive this error:
ORA-02085: database link SYS_LINK.CCB.COM connects to SYS.WORLD

The tables on both boxes are setup exactly the same. I can
insert from one instance to other just as long as I'm on the
same platform. It's when I try to cross platforms when I receive
the error.

Tell me(some code) that i can trnsfer data between different
platform(JAVA?).

Any help would be greatly appreciated.

Thanks,
and we said...
02085, 00000, "database link %s connects to %s"
// *Cause: a database link connected to a database with a
    different name.
//  The connection is rejected.
// *Action: create a database link with the same name as the
    database it
//  connects to, or set global_names=false.
//

very straight forward.

either

alter session set global_names=false;

or

create database link sys.world .....

and use sys.world which is the global name of the remote
database.

see
http://asktom.oracle.com/pls/ask/f?p=4950:7:::::F4950_P7_SEARCH_CRITERIA:global_names
for more info.
February 21, 2001 KK -- Thanks for the question regarding "Calling java from PL/SQL", version 8.1.6
You Asked
I try to call System.currentTimeMillis()
from PL/SQL, how can I change the timezone?
and we said...
By using different java calls.  here is a brief example that
returns time in GMT:

static public void java_get_gmt( String[] p_gmt )
{
DateFormat    gmtDateFormat =
               new SimpleDateFormat( "yyyyMMdd HHmmss z" );
    gmtDateFormat.setTimeZone( TimeZone.getTimeZone("GMT") );
    p_gmt[0] = gmtDateFormat.format(new Date());
}

see the java docs for what is possible.
February 21, 2001 Sridevi -- Thanks for the question regarding "Run a Unix Shell Script from inside a Form", version Oracle 8.1.5, Developer 6
You Asked
Hi Tom,
I am working on Oracle 8.1.5, Developer 6(not 6i) - Client
Server - two tier architecture.

CLIENT : Windows 98
SEVER: SCO Unix

I use the Host command to run dos commands from inside forms 6.
Is there any way I can run Unix shell scripts from within the
form?

Thanks in Advance.
and we said...
You can teach the database to run a shell script via a java
stored procedure or a C external procedure.

The database must provide a stored procedure for the client to
run.

C external procedures are documented in chapter 10 of the
application developers guide.  Java stored procedures in the
java stored procedure developers guide.
February 21, 2001 GALIA -- Thanks for the question regarding "Converting and index", version 8i
You Asked
I have a table PRODUCT ( NUM NUMBER (6)
                         CAPTION VARCHAR2(50))
And on PRODUCT.NUM i have an index (IndPRODUCT_NUM)

If i do :
         SELECT * FROM PRODUCT
            WHERE NUM = To_Number('2')
my index IndPRODUCT_NUM are Use

Now If i do :
         SELECT * FROM PRODUCT
            WHERE to_char(NUM) = '2'
my index IndPRODUCT_NUM are NOT Use

It is exactly on not ?

Thanks for your answer
and we said...
Because you applied a FUNCTION f(num) to the column -- the index is on NUM, not
on f(NUM).  We cannot take the string '2' and goto an index built on a number
and find the index entries that match '2' -- there are NO index entries that
match '2', only the number 2.

Consider it this way.  Say the function was reverse() instead of to_char and you
have:

select * from t where reverse( num ) = '12';

That should really be looking for the number 21, not the string '12' in the
index.  but the ONLY thing in the index is the number 21.

Once you used the function on the column, the index on the column cannot be
used.  You can index a function on the column to allow it to be used again.

see
http://osi.oracle.com/~tkyte/article1/index.html
....
February 21, 2001 steve -- Thanks for the question regarding "Obtaining Release Version", version 8.1.6
You Asked
Hi,

from sqlplus, "show release" reports the server version.

However there is no such name 'release' in v$parameter,
where is this info kept?

(I know it's easier to look at v$version but the patches
 don't seem to always update this correctly).

Thanks

Steve
and we said...
ops$tkyte@ORA8I.WORLD> declare
  2  ver varchar2(255);
  3  com varchar2(255);
  4  begin
  5     dbms_utility.db_version( ver, com );
  6     dbms_output.put_line( ver );
  7     dbms_output.put_line( com );
  8  end;
  9  /
8.1.6.2.0
8.1.6.0.0

PL/SQL procedure successfully completed.

is one way to get it -- ver is the version, com is the
compatibility string (from the init.ora)
February 22, 2001 Jonathan -- Thanks for the question regarding "log question", version 8.1.5
You Asked
In :

    Oracle8i Administrator's Guide
    Release 8.1.5
    6 Managing the Online Redo Log
    chapter : Online Redo Log Contents

I've read this :
    "Redo records can also be written to an online redo log file
before the

corresponding transaction is committed. If the redo log buffer
fills, or another

transaction commits, LGWR flushes all of the redo log entries in
the redo log buffer     to

an online redo log file, even though some redo records may not
be committed. If

necessary, Oracle can roll back these changes."

If a rollback occurs how does Oracle do to process it?
I mean it must have stored somewhere the information that a
modification has not been

commited yet.
Where is stored this information?

Then, you told me that the dbmslogmnrd script should only be
executed once and by user

'sys'.
But it will only work with his schem.
When I try to use the logminer utility with a specific user I
got an error which tells me

that the identifiers (DBMS_LOGMNR.NEW for example) haven't been
declared.

I've read that in the documentation
EXECUTE ANY PROCEDURE         Execute procedures or functions
(standalone or packaged)
                Reference public package variables in any schema
except SYS
What should I do?
and we said...
Rollback is stored in a rollback segment.  Redo in the redo
logs.  We do not use REDO to rollback -- the two are somewhat
inter-related but yet not really.

If we need to rollback that transaction, everything we need is
in the rollback segment.  We will not touch the redo logs to
rollback.

If the session requests to rollback, we do not need to see if
the transaction has committed or not -- we know it has not since
IT is requesting to rollback.

If the instance fails after SOME of our transaction got written
to the logs but BEFORE we committe, then upon startup, the
system will apply the redo logs upto the point of the crash.
This will "replay" our failed transaction and will recover the
rollback segments as well.  Obviously, after we've rolled
forward -- any transaction open needs to be rolled back (we are
doing crash recovery).

If we fail (get killed, dedicated server crashes, etc) it is
implicit we want (need) a rollback.  PMON will take care of that
for us.

Hence, we never need to store the fact that we've committed
anywhere -- its implied.

By default,

grant execute on dbms_logmnr to execute_catalog_role;

is done so any user with execute_catalog_role can in fact run
it.  A public synonym is NOT created so they must either

create synonym dbms_logmnr for sys.dbms_logmnr

or just prefix dbms_logmnr with SYS.

If you desire a user to run this and the user does not have the
execute_catalog_role, then SYS can "grant execute on dbms_logmnr
to that_user"
February 22, 2001 Pencho -- Thanks for the question regarding "about BLOB's", version version 8.1.6
You Asked
Hi, Tom
I have a table with BLOB field. How can I populate this field
with immages with size less then 2 GB.

Thank you.
and we said...
See
http://technet.oracle.com/doc/oracle8i_816/appdev.816/index.htm
there are programming guides for various languages.  Also search
for "load lob"   or "load blob" on my site for various examples.

It'll depend on the language you wish to use.
February 22, 2001 Reddy -- Thanks for the question regarding "ID's without Gaps", version 8.1.6
You Asked
I have a batch process which inserts about 100 rows into a table
every 2 hours. I don't have a problem with insert.

The problem is there is a document_id field. This field gets
populated from a Oracle sequence. No gaps are allowed in this
field (business rule). Recently I found gaps. The problem is
there are some transactions rolled back due to some errors. Now
I am looking for alternative solutions to solve this problem.
Any ideas ?
and we said...
change the rule.  No gaps = serialization = slow slow slow.

Sequences gaurantee gaps.  If you shutdown and restart, you will
probably find gaps as well.

Since you know have gaps, it might be a really good time to
convince someone that gap free numbers is a hold over from the
days when you did this processing on paper and the impact of
doing it on a computer system is really bad.

Short of that, you have to create a table like:

my_seqs ( seq_name varchar2, seq_val number );

and a function like:

create function get_next_val( p_seq_name in varchar2 )
return number
as
   l_val number;
begin
   update my_seqs set seq_val = seq_val + 1
     where seq_name = p_seq_name
    returning seq_val into l_val;

   return l_val;
end;

but remember -- you'll now have a level of concurrency that is
basically ONE user at a time.  Not a very scalable solution, but
if you have one user it would work OK.
February 22, 2001 Abhijit -- Thanks for the question regarding "Performance and Overhead", version version 8.1.6
You Asked
Hi Tom.
    I want to ask you two things.

1. Is there any overhead when oracle generates redologs.

2. Is there any performance improvement if i stop oracle
   from generating redo logs? If yes then just help me
   how to do it.

Thanks in advance

Abhijit
and we said...
1) no, overhead implies you are doing something that could be
stopped.  Since redo is a necessary component of the database,
it by definition is not overhead, it is part of the processing.

2) there are certain OPERATIONS that can bypass redo log
generation.  I can load a large chunk of data unrecoverable
using the direct path loader.  I can create a table as select
unrecoverable.  I can create an index unrecoverable.  Once I've
created or loaded these objects -- logging takes place as
normal.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:485221567528
and make sure to backup right after any and all NOLOGGING
operations in order to protect your ability to recover that
object in the future (so therefore  NOLOGGING is not "for free")
February 22, 2001 V Siva -- Thanks for the question regarding "Random text generation", version 8.1.6.0.0
You Asked
Hi Tom,

In on of my table, there is column, which need to be  generated
randomly with 2 character string, like 'AB', 'GT', 'AG',
'UI',...
Is there any way to do this? Can I use sys_guid() function some
how? I tried this, but each time I ran this only middle 2 or 3
numbers are changing, but not  the alphabets. Or can I use the
DBMS_RANDOM package any way?

Thanks,
Siva
and we said...
you can use dbms_random:

SQL> select chr( ascii('A') + mod(dbms_random.random,26) )
       from dual;

CH
--
L

ops$tkyte@ORA8I.WORLD> /

CH
--
R

ops$tkyte@ORA8I.WORLD> /

CH
--
I

ops$tkyte@ORA8I.WORLD> /

CH
--
7
February 22, 2001 chris -- Thanks for the question regarding "sending notification", version 4.5
You Asked
How do i automatically notify probably my supervisor who is
logged into the same oracle database as myself on a different
terminal about a transaction which has exceeded my limit and
needs approval.

We are developing a banking package and the front office
staff(tellers) have a limit on the amount they can issue to
customers, if the amount exceeds their limit a supervisor who is
a user created in oracle and logged in should be notified
automatically, He either approves or rejects the trans.

Hope to hear from you soon

thanks

Chris
and we said...
You'll have to write a program that the supervisor runs that is
waiting for an event to occur.  They would have to have the
program running constantly.

If you are using forms, you can use the TIMER builtin
functionality in forms to periodically look to see if an event
has happened.  You would use the DBMS_ALERT package to register
your interest in an event and the client would use dbms_alert to
signal that the event has occured.
Review & Followup
Rating: 3
Parag March 31, 2002
Reviewer: Parag from India
Sir .... Small Example Please

Rating: 4
Example please September 20, 2002
Reviewer: A reader
Please give a suitable example ,it will helps a large audience.

February 22, 2001 Stu -- Thanks for the question regarding "utl_file.Write Error", version 8.1.6
You Asked
I developed the script and had it running on a different version
of Oracle, 8.1.5, I believe. The server was upgraded and the
script no longer works.  The 2nd pass thru the loop gens an
Exception.
I am running the script as oracle, the "file" owner.

$ ls -ld /tmp /tmp/ora2ora
drwxrwxrwx  10 bin        bin           3072 Feb 22 11:54 /tmp
drwxrwxrwx   2 oracle     dba             96 Feb 22 11:39
/tmp/ora2ora

Output from execution:

 start utl
Select log From aradmin.TT_ACCUWAN Where Ticket___ =
'000000000010440'
TT_ACCUWAN_10440.dat
Len: 6606
Offset: 1
Bytes1: 2000
Offset: 2001
Bytes1: 2000
Write Error
User-Defined Exception

PL/SQL procedure successfully completed.

total 0
-rw-r-----   1 oracle     dba              0 Feb 22 11:36
TT_ACCUWAN_10440.dat

Code Snipet:
        lFileName := lLobTable || '_' || ltrim(lTicketNb,'0') ||
'.dat';
        dbms_output.put_line(lFileName);
        lDataFile := UTL_FILE.FOPEN('/tmp/ora2ora', lFileName,
'W');

        lLobLength := dbms_lob.getLength(lLobLocator);
        dbms_output.put_line('Len: ' || to_char(lLobLength));

        lDataOffset := 1;
        WHILE lDataOffset < lLobLength LOOP -- Until no more
data
                dbms_output.put_line('Offset: ' ||
to_char(lDataOffset));
                dbms_lob.read(lLobLocator, kBufferSize,
lDataOffset, lDataBuffer
);
                dbms_output.put_line('Bytes1: ' ||
length(lDataBuffer));
                UTL_FILE.PUT_LINE(lDataFile, lDataBuffer);
--              UTL_FILE.PUT_LINE(lDataFile, kNewLine);
                lDataOffset := lDataOffset + kBufferSize;
        END LOOP;

EXCEPTION
        WHEN No_Data_Found THEN
                UTL_FILE.PUT_LINE(lDataFile, kNewLine);
                UTL_FILE.FFLUSH(lDataFile);
                UTL_FILE.FCLOSE(lDataFile);
                dbms_output.put_line('Wrote: ' ||
to_char(lDataOffset - 1));
and we said...
It would be to your benefit to use an exception block like this:

exception
    when utl_file.invalid_path then
        raise_application_error(-20001,
            'INVALID_PATH: File location or filename was
             invalid.');
    when utl_file.invalid_mode then
        raise_application_error(-20002,
            'INVALID_MODE: The open_mode parameter in FOPEN was
             invalid.');
    when utl_file.invalid_filehandle then
        raise_application_error(-20002,
            'INVALID_FILEHANDLE: The file handle was invalid.');
    when utl_file.invalid_operation then
        raise_application_error(-20003,
            'INVALID_OPERATION: The file could not be opened or
             operated on as requested.');
    when utl_file.read_error then
        raise_application_error(-20004,
            'READ_ERROR: An operating system error occurred
             during the read operation.');
    when utl_file.write_error then
        raise_application_error(-20005,
            'WRITE_ERROR: An operating system error occurred
             during the write operation.');
    when utl_file.internal_error then
        raise_application_error(-20006,
            'INTERNAL_ERROR: An unspecified error in PL/SQL.');

but the answer here is easy to see.  I do not think the upgrade
has anything to do with it -- the data in the blob must be
different.

UTL_FILE has a default limit of 1022 bytes per line. Unless your
blob has a NEWLINE somewhere in the middle of it -- the write of
2000 bytes blows up because you exceeeded this default limit.

In the earlier release -- you must have been lucky and
encountered a newline in every 2000 byte chunk, that broke the
line into 2 lines and it works.

All you need to do is:

  lDataFile := UTL_FILE.FOPEN('/tmp/ora2ora', lFileName, 'W',
                               32000 );

and it should be OK.  that'll let you create upto a 32k line
length without failing.
Review & Followup
Rating: 5
UTL_FILE max line size problem July 16, 2001
Reviewer: David Seibold from Wilsonville Oregon
This article had the solution for our write error.

Rating: 5
UTL_FILE exception handler August 13, 2002
Reviewer: Jeremy Becker from SF, CA
Thanks for the tip.  Glad I could find it on the site, as I left my copy of your
book at home.  Very functional exception handling for UTL file operations and
makes me rethink just 'copping out' and using WHEN OTHERS all the time.

February 23, 2001 Mike -- Thanks for the question regarding "RMAN and Cold Backups", version 8.1.7
You Asked
Hi Tom,

We're just starting to use RMAN to handle our backups
(converting from EBU on 7.3 databases).  For some of our
databases, we want to do cold backups.  We used a script to
shutdown the database to do cold backups under EBU.  We know
that RMAN can handle the database states itself without need for
a shell script.  We read in the documentation that RMAN requires
the database to be mounted to do cold backups.

Is there a command that RMAN can issue to bring an open database
to a mounted state without first closing the database and then
mounting it?  What command sequence would you recommend?

Thanks,
Mike
and we said...
What goes up, must come down.  We have to shutdown.

Example is
http://technet.oracle.com/doc/oracle8i_816/server.816/a76990/usingrma.htm#435660
...
February 23, 2001 Rob -- Thanks for the question regarding "default variables in SQL*Plus", version 8.0.4
You Asked
Dear Tom,

Is there any way to set up a default value in a SQL*Plus script
so that I can just hit return if it is correct? For example,
when generating scripts, it would be more convenient to set a
default (specially if it is used more than once) and let the
script run. I tried using "define", but couldn't make it work
the way described above. Here's what I was working on:
SELECT 'drop sequence ' || sequence_owner || '.' ||
sequence_name || ';'
FROM all_sequences
WHERE sequence_owner = UPPER('&owner')

I'd appreciate any suggestions you can make.

Thanks

Rob Das
and we said...
Here is a sqlplus snippet that will prompt for a USERNAME and
defaults it to the currently logged in username:

column username new_value default
set termout off
select user username from dual;
set termout on

accept owner default &default prompt 'Owner enter=[&default] '

select '&owner' from dual
/
February 23, 2001 Gilles -- Thanks for the question regarding "DBMS_RLS", version 8.1.7
You Asked
Hi Tom,

In your article
http://osi.oracle.com/~tkyte/article2/index.html
concerning fine grained access control, you mention an important
caveat about cursor caching.
I tested your example both with PL/SQL 8.1.6 and PL/SQL 8.1.7
on Aix 4.3.3
In 8.1.6, i get your results but in 8.1.7 the results are now
correct.

I didn't check with PRO*C but i'm curious to know if Oracle
changed something in 8.1.7 implementation of RLS ?

Thanks in advance
and we said...
Well, look at that.  Thanks for pointing that out.

This was enhancement request 896488.  It was implemented in
8.1.7.  The SERVER (so this works with plsql, pro*c and so on)
will slilently recognize the predicate is different and silently
reparses.

I'll have to update that -- thanks again.
February 23, 2001 Preeti -- Thanks for the question regarding "Foreign Key", version 7.3.4
You Asked
Dear Sir,

Thanks for such a quick reply.

Actually I want syntax for defining foreign key.

I will put a example for my case.
I have two tables :

1.Code_Master

Code       Code Desc
----------------------
800000     State Codes
800001     Madhya Pradesh(A State Of India)
800002     TamilNadu     (A state Of India)
900000     Country Codes
900001     India
900002     USA

i.e. Every State starts from 8000 & every country starts from
9000.

2. Party_Master

Party_id  Party_Name  State_id
------------------------------
1          xyz         01 (Equivalent to State 800001 of
                   Code_master)
2          abc         02

Now I want to create a foreign key in table party_master like :

constraint fk_party_state foreign key('8000'||state_id)
refereces code_master.

i.e. I know that every state code starts with 8000 which I have
stored in my main code_master table, but I don't want to store
this 8000 in my whole database for state id, because I have
fixed it one time & it will consume space also.

So I am seeking for such a solution that I can store the data in
above manner & also create integrity constraint for the same.

I have tried to explain my problem more clearly.

Waiting for your kind reply.

Thanks & Regards
    Preeti
and we said...
You cannot -- The primary key of code_master is code and a
foreign key MUST by definition point to a primary key or unique
constraint column.  You cannot do what you are attempting to do
in any way shape or form.  You must store 800001 in the
party_master table.

If space is your primary concern, use the number type and store
the code as:

0.8   state codes
1.8   Madhya Pradesh(A State Of India)
2.8   TamilNadu     (A state Of India)
0.9   Country Codes
1.9   India
2.9   USA

and that'll use many less bytes in a NUMBER field then 800001
would in a char field.
February 24, 2001 Subbu -- Thanks for the question regarding "Using an Executable in an Pl Sql Block And Scripts ", version Oracle8i Ent Edition Release 8.1.6.0.0
You Asked
question 1
Dear Sir
I KNOW THAT WE CAN GET THE SCRIPTS FOR THE CREATION OF TABLES
AND INDEXES FROM THE EXPORT FILE (SAY 23FEB.DMP)
NOW HOW TO GET THE SCRIPTS FOR OBJECTS LIKE TRIGGERS OR
PROCEDURES OR  FUNCTIONS INDIVIDUALLY FROM the dump file
is there any other method to get back the source of objects(like
triggers ,procedures or functions)  that have been accidentally
dropped or the code deleted without importing the  entire
database.

question 2

How do U call an executable file from an pls sql block
using sql*Plus Host command can be used to execute an executable
.but it is not working with Plsql blocks
Please tell me how to execute and exe from a pl sql block

Thanks In Advance

Anand
and we said...
1) you cannot easily retrieve those objects from the dmp file
however you can do this:

say the code exists in U1's schema.

create a temporary user TMP.

imp userid=tmp/tmp fromuser=u1 touser=tmp rows=n grants=n
indexes=n constraints=n analyze=n recalculate_statistics=n

And then you'll have the code in TMP to extract from.

2) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1101433464993
...
February 24, 2001 kavitha -- Thanks for the question regarding "database", version 8
You Asked
Respected Sir,
I am a programmer in C++ and java.
I have learnt c,c++,java,vb,asp.
I dont have a knowledge of database at all.
But right now I am developing a web application for a
Multinational bank using asp,vbscript and Oracle 8.
I am really facinated with oracle.
I am want to become a first class DBA.
before involving my self in this task I just want to know what
is scope of being a DBA.

Please help me.
and we said...
Well, you sound like you are a developer -- a DBA is the person
who installs the database, sets it up, tunes the instance,
manages its interaction with the OS, backs it up, recovers it,
manages accounts and privs, and so on.  They don't really write
programs.

A developer on the other hand needs to understand Oracle
architecture (so they can use it efficiently), how it locks
data, what multi-versioning read consistency is and what it
means to them, what transactions are, how to tune their
application (not the database -- their app running in a
database), and what features/functions the database provides (so
they do not re-invent the wheel over and over).

Both people should start by reading the Server Concepts manual
from cover to cover.  then the developer would continue onto the
application developers guide and the plsql manual (whereas the
dba would go off to the admin guide).

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/toc.htm
...
February 24, 2001 Steven -- Thanks for the question regarding "ANALYZE INDEX", version 8.x
You Asked
Tom,

When I analyze an index (analyze index inx_name compute
statistics), are the stats which are gathered used by
the optimizer when deriving a query plan, or does the
optimizer only look at the stats gathered by
analyzing tables?  Should I analyze indexes whenever
I analyze my tables, more often, less often?  I use
both 8.0.5 and 8.1.6 - does your answer to the above
depend on the version of the RDBMS?

Thanks for any feedback you can give me.
and we said...
It works the same in all releases -- the optimizer uses the
stats on a index when evaluating the plan.

You might analyze the index as often as the table if the stats
on the index are changing as frequently as the table.  Lets say
you infrequently insert/delete from the table but frequently
update (changing the column distributions).  If you DO NOT
update an indexed column -- the index is changing at a much
slower rate then the table is -- you don't have to analyze as
often.  On the other hand, if you update an indexed column --
that index is changing rapidly as well.

You must decide based on that.  It may be that the table and
index are analyzed on different schedules.
February 24, 2001 Ravi -- Thanks for the question regarding "Rollback During Killing a transaction", version 817
You Asked
Tom,

I am quite often face this problem. There is a long running
transaction which generated lot of redos and undos. We decide to
kill the session using "alter system kill session" cmd. But it
takes a long time to rollback the trx. When we issue the cmd
shutdown immediate also, the same problem exists. I assume this
is due to rollback of the trx is done serially by "PMON" and the
parameter cleanup_rollback_entries="integer" in oracle 7 and
oracle8

Starting with oracle 8i, at times, I issue "shutdown abort" and
"startup" thinking that rollback phase of the recovery shall be
parallized and the database opens
quickly(Fast_start_parallel_rollback and fast start rollback on
demand features).

Now oracle desupported cleanup_rollback_entries parameter. So, I
donot understand how oracle rollback a long trx when the user is
killed or a trx is dead. My question is how to improve the
efficiency of the rollback in such situation averting the
"shutdown abort"

2) I wish to kill a long running trx either using a 'alter
system " or "kill cmd in unix". Now, what is the
process(PMON/SMON/foreground process) that actually rollback the
trx in both the cases. Between these two, which is the best
method of killing a session.

Thanks
Ravi
and we said...
In Oracle8i PMON defers transaction recovery of "killed"
sessions
to SMON which may use fast start parallel rollback if necessary.

This frees up locks held by the killed process immediately. (see
that init.ora parameter definition)

Note: you should not allow yourself to get into a situation
where this is happening frequently.  Something is really wrong
if this is a frequently occurence.  This should be the exception
to the rule, not standard operating procedure.
February 25, 2001 -- Thanks for the question regarding "fine grained access control", version 8.1.6
You Asked
i have implemented fine grained access control in my project..

i have 4 different users with access levels set based on
particular records using the security policy..

so if one user tries to select something from a table he will be
able to view only his records..

if he tries to update records other than to which he has access
he gets "0 rows updated" message in sqlplus

if he tries to delete records other than to which he has access
he gets "0 rows deleted" message in sqlplus

if he tries to insert records other than to which he has access
he gets "policy with check option violation"

now i want an error in case of update and delete also
because i am developing a web based application and i donot want
to take the user to the success screen even if "0 rows are
deleted/updated"
in case of insert i get an error and i trap the oracle error and
flash a message "Cannot insert etc etc..."

so if i dont get any errror the user will be sent to success
screen and he will think he was able to update/delete when he
has not actually done so..

how should i solve this problem?
and we said...
An update or delete that does not see any records is never an
error.  You can get an error from the update IF you update a
record and make it such that you would not be able to see it
(like the INSERT).

An update of ZERO records is not an error, ever.
A delete of ZERO records is not an error, ever.

If your application would like to treat an update of zero
records as an error, you must include logic such as:

   update t set .....;
   if ( sql%rowcount = 0 )
   then
      raise_application_error( -20001, 'Expected to update!' );
   end if;

It would be very bad indeed if an update (or delete) that
updated zero records was considered an error in any case.
February 25, 2001 ali -- Thanks for the question regarding "Role of network files (tnsnames.ora, listener.ora. sqlnet.ora)", version oracle 8.0.5
You Asked
Dear Sir Tom,

I am ali from hyderabad pakistan, i am wishing to know the role
of network related files i.e. tnsnames.ora, listener.ora,
sqlnet.ora with respect to client side and server side.

Thanks

Ali Naqi
and we said...
The tnsnames.ora is used to find a Net8 listener and connect to
it and pass to it the details of the database instance you would
like to connect to.  It will be found on the client side.  Note
that a SERVER can be a client of another database so it is
typical to find it on the SERVER as well.

The listener.ora is used to setup the configuration of the net8
listener.  to specify the port it will listen on, give it the
details of the databases it can connect to and so on.  This file
is on the SERVER only.

The sqlnet.ora is an optional file expressing more parameters
about the connection (eg: the trace level for debugging, the
types of authentication you would like to support and so on).
It may be found on the client or the server.

see
http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/toc.htm
for all of the details.
February 25, 2001 Ravi -- Thanks for the question regarding "CBO and one table is not analyzed. What happens.", version 8.1.6
You Asked
Tom,

The following is not a healthy way. But I wish to understand.

Select * from A, B where <some conditions>

Table A is a big table and not analyzed
Table B is analyzed
optimizer_mode=choose

----Oracle Doc-------

If the optimizer uses the cost-based approach for a SQL
statement, and if some tables accessed by the statement have no
statistics, then the optimizer uses internal information (such
as the number of data blocks allocated to these tables) to
estimate other statistics for these tables.

----End Quote----------

Could you please explain how oracle gets the other statistics
using just the number of blocks allocated.

Whether full table scan is performed for analyze of table A when
such statment is issued, which was not analyzed before the
select statement is issued.

What shall be the time for such analysis. Will it be equivalent
to analyzing table A explicity.

Thanks in advance.
Ravi
and we said...
It is basically saying in light of the fact that it has no
details about table A, it will look at things such as the number
of blocks allocated to the table under the high water mark and
the potential width of the rows from the data dictionary to try
and guess how big the table is (in total volume and number of
rows).  It will then apply some heuristics (rules) to the
results to try and determine the data distribution of things (it
doesn't know the high and low values for anything, it doesn't
know the number of distinct values in a column and so on).

It effect, it totally GUESSES at what the stats for A should be
using rules.

It will not be equivalent to analyzing table A, it is a guess.
February 25, 2001 Sameer -- Thanks for the question regarding "Reducing the size of system tablespace", version 8.0.5
You Asked
i have three datafiles for the system tablespace
1) sys10orcl.ora  200 mb
2) smconvert1.ora 500 mb
3) smconvert2.ora 500 mb

the free space  for datafile 1) 177 mb
                             2) 495 mb
                              3) 498 mb

i want to reduce the size of the system tablespace

But when i issue the ALTER DATABASE DATAFILE
'...\...\SMCONVERT1.ORA' RESIZE 400 MB '

i GET A ERROR SAYING :ORA-03297 FILE CONTAINS 1230 BLOCKS  OF
DATA BEYOND REQUESTED RESIZE  VALUE

HOW TO SOLVE THIS ..?
and we said...
It is generally not possible to reduce the size of system.  If
it is so large with so much free space, it would tend to imply
that you created and then dropped objects in the tablespace.

The reason the file cannot be shrunk is becase there is data out
there at the end of it.  Consider smconvert1.ora -- its
utilization must be something like:

0meg        100meg      200meg    300meg     400meg     500meg
free free free free free free free ..........         ALLOCATED

you have lots of free space at the head of the file but way out
there at the end is something.  You will NOT be able to shrink
that file as long as that SOMETHING exists.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:153612348067
for a script maxshrink that will tell you what the smallest
size these files can be.

You might also investigate what extent is way out there.  You
can use this script:

---------------------------------------------
column block_id new_val block_id

select max(block_id) block_id
  from dba_extents
 where file_id = &1
/

select owner, segment_name, segment_type
  from dba_extents
 where file_id = &1
   and block_id = &block_id
/
----------------------------------------------

run that and pass it the file_id of the file in question
(dba_data_files will give you the file_id).  It'll report back
the object that is way out there.  If it is YOUR object (owner
<> sys), you can get rid of it and fix it up.  If it is owned by
SYS and is part of the data dictionary, there is not too much
you can do.
Review & Followup
Rating: 4
Review to answer for Reducing the size of system tablespace March 18, 2002
Reviewer: Lusiana Lusiana from Wollongong, Australia
Very straightforward answer. I immediately can find out
why I cannot shrink my tablespace and how to attempt
to shrink it.

February 25, 2001 SUBRAMANIYAM -- Thanks for the question regarding "HOW TO COMPARE TWO SCHEMAS", version 8.1.6
You Asked
Hi,

we are having two  schema at two differnt server.
say  user1/pwd1@dev_1 , user1/pwd2@prod_1. I am able to make a
dblink between two servers. I want to compare two schema objects
without data. This means I want to check any of the
tables,triggres or packages differs from one schema to other
schema.  Can you help me?

Thanks in Advance.

With regards
shanmugam
shanmugam@fusion.com.sg
and we said...
Designer (a CASE tool) and many other third party tools do that.

Otherwise, you will have to write the queries that diff the data
dictionary yourself.  Eg to find all tables in database A not in
database B, you will:

1) log into database A
2) have a database link to B that logs in using user1/pwd2
3) select table_name from user_tables
   minus
   select table_name from user_tables@b;

to find all tables in B not in A, do the reverse query:

   select table_name from user_tables@b
   minus
   select table_name from user_tables;

and so on.  For tables that are in both, you compare
user_tab_columns, user_constraints, user_cons_columns and so so.

For source code, you use user_source.

for triggers, you use user_triggers (but that must be done via
plsql because the trigger text is in a long).

Suggest you look into a tool, I can suggest designer.  I know
others exist.
February 25, 2001 -- Thanks for the question regarding "running app (or executable) when value changes in oracle DB", version 7.3
You Asked
Hi, please can anyone help me, I am a amature programmer doing a
project with wml (WAP) and asp to make a site have dynamic
content from an access database. As I am a complete beginner,
what would be the easiest way of executing a program when
certain constraints are meet in a field in the database?

To help explain what I am would like, for example:-

Say in my table I have a field called ALARM,
and all the cells are always 0. When a cell changes to 1 I will
then executed this application (a telnet script to dial out and
sent an sms message to a mobile phone).

The database is an oracle 7.3 (ODBC DSN connection). (for
development I am using a snap-shot
of this in MS access).
Some way of doing it in my some code or if anyone has seen a
utility.

Can this easily be done?

Any help will be appreciated

Regards
Matthew
and we said...
If you can setup the program to be run from a URL (eg: you could
run it from a web browser), you just need to:

  response := utl_http( 'http: //host/path/program?inputs=..' );

in 7.3, the easiest way to run an external process is via a URL
like that.


Subject | Article | Last Updated (East coast time)
how to use sendmail function from db to unix sendmail | article only | Feb 28, 2001 10:28 am
Multiple Databases - Oracle to Oracle/Oracle - SQL Sever | article only | Feb 28, 2001 10:58 am
storage parameters | article only | Feb 28, 2001 11:00 am
variable type nested table | article only | Feb 28, 2001 04:55 pm
Is there a self-reference to my PL/SQL program's name? | article only | Mar 01, 2001 07:32 am
implicit commit. | article only | Mar 01, 2001 07:48 am
Oracle External Procedures - DLL | article only | Mar 01, 2001 08:05 am
Regarding the Snapshot too old error. | article only | Mar 01, 2001 08:46 am
decode and sqlloader | article only | Mar 01, 2001 09:00 am
Returning a Result Set from PL/SQL stored procedure to JDBC. | article only | Mar 01, 2001 09:15 am
Get Error Description By Error Number | article only | Mar 01, 2001 02:39 pm
quoted string | article only | Mar 01, 2001 02:41 pm
upgrate from 8.1.6 to 8.1.7 on HP | article only | Mar 01, 2001 02:47 pm
Use SQLERRM function in SQL Statement | article only | Mar 01, 2001 04:24 pm
Dynamic SQL | article only | Mar 02, 2001 08:41 am
how do i know my current session setting? | article only | Mar 02, 2001 08:49 am
Locally Managed Tablespaces | article only | Mar 02, 2001 09:11 am
Mapping a long varchar to a number. | article only | Mar 02, 2001 09:41 am
Wrapped code | article only | Mar 02, 2001 10:04 am
Percentages | article only | Mar 02, 2001 10:07 am
Back up and Recovery | article only | Mar 03, 2001 08:13 am
DBWR and Server process | article only | Mar 03, 2001 08:21 am
Timestamp replication | article only | Mar 03, 2001 08:27 am
oracle | article only | Mar 03, 2001 08:32 am
ABOUT DATABASE | article only | Mar 03, 2001 08:58 am
environment variables (set oracle_ sid= | article only | Mar 03, 2001 09:03 am
Oracle Query | article only | Mar 03, 2001 09:18 am
\Dynamic condition ! | article only | Mar 03, 2001 09:48 am
denormalization | article only | Mar 04, 2001 09:07 am
Oracle 8.1.7 (Release 3) missing "libaurora.a" | article only | Mar 04, 2001 09:24 am
stored procedure for grants | article only | Mar 04, 2001 09:30 am
Distinct Values of a column to be displayed | article only | Mar 04, 2001 03:15 pm
row(s) 1 - 32 of 32
February 28, 2001 Steven -- Thanks for the question regarding "how to use sendmail function from db to unix sendmail", version v7.3
You Asked
Tom,

I would appreciat it if you could give some help:

I would like to have database to send mail out.   I know our
version may not come with utl_smtp, but can I get sth around it?

I would have Oracle db send mail to unix sendmail, then going
outside.

Thank you very much,

Steven
and we said...
What I've done with 7.3 in the past is to use UTL_HTTP to run a
cgi-bin program under a webserver.  I can send mail via cgi-bin
in a variety of methods -- so I just setup a URL I can call:

http: //host/cgi-bin/mail?to=someone@somewhere&body=Hi

then, UTL_HTTP from plsql can easily run it.
February 28, 2001 Abhijit -- Thanks for the question regarding "Multiple Databases - Oracle to Oracle/Oracle - SQL Sever", version Version 8.1.6
You Asked
Hi
 I would be happy if you guide me or provide me the information
for the following.

Is there any way available in Oracle by which my one Oracle
database talks to another Oracle database. OR One Oracle
database talks to another database like SQL Server.

Thanks in Advance

Abhijit
and we said...
Every Oracle database can talk to another Oracle database
easily.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76960/toc.htm
this is a native Feature.  To talk to SQLServer you need a
gateway
http://www.oracle.com/gateways
...
February 28, 2001 Branka -- Thanks for the question regarding "storage parameters", version 8.1.6
You Asked
Tom,

If I use LOCALLY MANAGED TABLESPACE, and AUTOALLOCATE option
1. Do I have to think about initial extent, or I can make 16KB
to be default for all objects in that tablespace?
2. Do I have to think about PCTINCREASE and PCTUSED?

Branka
and we said...
In my opinion -- don't use autoallocate, use UNIFORM.  Group
objects by their classes of size into tablespaces.  Have all
extents always be the same size.

1) with locally managed tablespace, you cannot think about the
initial extent at all -- it is done for you.

2) pctincrease is meaningless with locally managed.  Pctused is
unchanged from before -- you still need to think about it.
February 28, 2001 Natalia -- Thanks for the question regarding "variable type nested table", version Oracle8i Release 3(8.1.7)
You Asked
Hi Tom!

We've migrated from SQL Server to Oracle8i.
Our procedures were created only for retrieving set of data.

Our application was written on SmallTalk and it doesn't
understand ref cursor.
To return set of data I am using datatype nested table and then
in application code I do

'SELECT * FROM THE (SELECT CAST (<function_name>) AS
<type_name>) FROM DUAL;'.
There are a lot of temporary table in procedures and sometimes
it's impossible recreate
it in one select statement.

1. Can I insert data in temporary table and then select it in
variable type nested table?
   I've tried. But I received an error.

Example.

 CREATE GLOBAL TEMPORARY TABLE emp_temp
(ename           varchar2(20),
 newsal          number(10),
 deptno          number(2))

on commit delete rows;

CREATE TYPE EMP_TY  AS OBJECT (

    ename         varchar2(30),
        sal              number(10),
    dname             varchar2(20)
);

CREATE TYPE EMP_NT AS TABLE OF EMP_TY;

CREATE FUNCTION employeers

RETURN EMP_NT
AS
   TABLE_NT EMP_NT := EMP_NT();
BEGIN

INSERT INTO EMP_TEMP
SELECT ename,
       sal * 10,
       deptno
FROM emp;

/*I would like to do something like this. It's work without
temporary table but
 doesn't work with it. When I have 7 or more temporary table
it's difficult to
recreate select statement.*/

SELECT CAST (MULTISET (SELECT e.ename, e.newsal, d.dname
                    FROM emp_temp e, dept d
                       WHERE e.deptno = d.deptno)
             AS EMP_NT)
INTO table_nt
FROM dual;
RETURN table_nt;
END;

2. Sometimes I need update data in variable type nested table
like in regular table.
   Can I do it? And how? I'm using DECODE function but sometime
it's big WHERE clause
   and I cann't recreate it.

Thank you.
Best Regards.
Natalia.
and we said...
see
http://osi.oracle.com/~tkyte/autonomous/index.html
I do something similar there.  You need to use an autonomous
transactions to avoid the

ORA-14551: cannot perform a DML operation inside a query

(note: telling me WHAT the error message instead of making me
guess what it is would be very helpful)

Your function can be:

ops$tkyte@DEV816> CREATE or replace FUNCTION employeers
                            RETURN EMP_NT
  2  AS
  3     pragma autonomous_transaction;
  4     TABLE_NT EMP_NT := EMP_NT();
  5  BEGIN
  6     INSERT INTO EMP_TEMP
  7     SELECT ename,  sal * 10, deptno
  8       FROM emp;
  9
 10     SELECT CAST (MULTISET
 11           (SELECT e.ename, e.newsal, d.dname
 12              FROM emp_temp e, dept d
 13             WHERE e.deptno = d.deptno)
 14         AS EMP_NT)
 15       INTO table_nt
 16       FROM dual;
 17
 18     commit;
 19     RETURN table_nt;
 20  END;
 21  /

Function created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> select *
  2    from TABLE ( cast( employeers() as emp_nt ) )
  3  /

ENAME                                 SAL DNAME
------------------------------ ---------- --------------------
clark                               24500 ACCOUNTING
king                                50000 ACCOUNTING
miller                              13000 ACCOUNTING

2) nested tables cannot be "updated".  You can put it into a
temporary table, update it and select it back out.
March 01, 2001 Raghu -- Thanks for the question regarding "Is there a self-reference to my PL/SQL program's name?", version 8.1.6
You Asked
Hi Tom,
Is there a PL/SQL variable equivalent of the $0 variable in
Unix. Within a procedure/function if I want to know the name of
the program that I am running, can I get it from a system
variable. I plan to write into a log table and I want to pass
the program name and comments as parameters. Now, I need to
hardcode the program name - is there a way to pick this off an
environment variable?
Thanks,
Raghu
and we said...
See
http://osi.oracle.com/~tkyte/who_called_me/index.html
there i have a procedure "who_called_me" and a function
"who_am_i" that returns what you want.
Review & Followup
Rating: 4
broken link November 30, 2001
Reviewer: Paul Druker from Fairfax, VA
Tom, link on this page is broken, it's pointing to
http://osi.oracle.com/~tkyte/who_
instead of
http://osi.oracle.com/~tkyte/who_called_me/index.html

March 01, 2001 vrishali -- Thanks for the question regarding "implicit commit.", version 8.1.6.2.0
You Asked
Hi Tom,

   If I will run any DML statement and without doing commit
immediately I run any DDL statement. Then does DDL statement
causes commit implicitely for previously run DML statements ?
and we said...
Yes, DDL is always:

   commit;
   DDL;
   commit or rollback -- depending on the outcome of the DDL

If that is not desirable, you can use an autonomous transaction
in Oracle8i:

ops$tkyte@DEV816> create table t ( x int );
Table created.

ops$tkyte@DEV816> insert into t values  (1);
1 row created.

ops$tkyte@DEV816> declare
  2  pragma autonomous_transaction;
  3  begin
  4     execute immediate 'create table abc ( x int )';
  5  end;
  6  /

PL/SQL procedure successfully completed.

ops$tkyte@DEV816> rollback;

Rollback complete.

ops$tkyte@DEV816> select * from t;

no rows selected

ops$tkyte@DEV816>

as you can see -- the create table abc did not commit the insert
since it is done in an autonomous (independent) transaction.
Review & Followup
Rating: 5
Perfect Sir. December 03, 2002
Reviewer: Selidan

March 01, 2001 Seetharaman -- Thanks for the question regarding "Oracle External Procedures - DLL", version Oracle 8.0
You Asked
Hi Tom,

 Greetings!...

1. I have written a dll in VC++ which will print a file.  I tried executing it
thro vb and it is doing it.

   But when i called thro' oracle external function it was not able to do it.
However, it returns the output error code which is in the success block of the
code.  To debug, i copied the same file to some other name.  It copied.  Is
there anything we need to configure in the listener or other files to access the
devices connected to the server.  Actually, i'm calling the function thro oracle
forms.

2. One very basic question.  I really feel bad to ask this anyway i need a
solution.

  In a table i create a composite primary key having two columns.  I have
created another table with one of the fields in the primary key in this new
table and i need to mark it as foreign key.  It will throw an error stating that
the keys are not matching each other.  Is it possible to do that?

  create table a
(   field1 varchar2(10) not null,
    field2 varchar2(10) not null
    field3 varchar2(20)
);

 alter table a add constriant pk_id1 primary key (field1, field2);

  create table b
(  field1 varchar2(10) not null,
   field4 varchar2(10)
);

  alter table b add constraint pk_id2 primary Key(field1);

  alter table b add constraint fk_id1 foreign key(field1) references a;

3.  My third problem is how to write a crontab -e job for a stored procedure.
Becoz i'm concerned to use the traditional dbms_job which will get deactivated
after failing for 16 times or so.  I know the crontab -e which will do the
initial file cleaning stuff and backup stuff at the filesystem level.  But how
to do it for Oracle Stored Procedures.  I'm using Sun solaris intel version
Solaris 8

thanks in advance,

Sorry for bugging you,

regards

Seetharaman Srinivasan
and we said...
1) it would be much easier if you let me know the error code.  yes, you must set
up and configure extprocs.  I would suggest testing it in sqlplus first.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1172035350154
for how to configure the server for extprocs.

2) No, not unless there is a unique constraint on a.field1.  By the looks of
your data model however -- table A is the child table -- table A could have a
foreign key to B -- not the other way around.

3) Use dbms_job.  Don't use cron. dbms_job will break the job it if FAILS 16
times in a row -- this is true.  HOWEVER, if the job to be run it:

begin
    my_job( .... );
exceptions
    when others then
        rollback;
        insert into a log table sqlerrm......
        commit;
end;

that job will NEVER fail -- your job "my_job" might fail but the JOB itself
always succeeds -- it catches its error and logs it.

If you use cron, just write a script that sets up the neccessary environment
(oracle_home, oracle_sid, ld_library_path, path and so on) and run your job
using sqlplus.  something like:

#!/bin/csh -f

setenv ORACLE_SID ora8i
setenv ORACLE_HOME /export/home/oracle8i
set path=( $path $ORACLE_HOME/bin )

sqlplus / <<EOF
exec my_job;
exit
EOF
March 01, 2001 wallacel -- Thanks for the question regarding "Regarding the Snapshot too old error.", version 8.1.6
You Asked
Tom:

I recently read some document Regarding the Snapshot too old
error.

the document says that:
size the buffer cache as high as possible(without straining
system resource) to increase the chances of previous data-block
versions being acquired via logical hits.
If the previous version of the block is still present in the
buffer cache, it can be easily retrieved from there(Via a logial
read). However,  if the required version is not in the buffer
cache, it has to be retrieved from the rollback segment that was
used by the writer that changed the block.

what i don't understand is that:
1. why there are chance that "previous data-block version
can be acquired via logical hits"

based on my understanding.
if session A update a row in a datablock. it first read the
block in(physical read), then modify the block and record the
before-image in rollback segment, so when session B want to
read the before-image, it always need to goto rollback segment
to rebuild the before-image, it never have chance that
the previous version of the block is still present in the buffer
cache.

Regards,
and we said...
1) because rollback segments are cached in the buffer cache just
like tables, indexes and so on.  We use rollback to get previous
versions of data blocks.  If the rollback data is still buffered
-- then we will do a logical IO.  If the rollback data has been
flushed to disk by DBWR, we will do a physical IO when we need
that rollback.

your understanding is correct however you must simply add to it
that rollback segments are treated just like data segments and
will be cached in the buffer just like a table.

BTW: sizing the buffer cache "as high as possible without
straining system resources" is a bad rule of thumb.  size the
buffer cache so you get a good cache hit ratio in the block
buffer cache.  No need to make it bigger if it won't give you
any positive results.  Make it BIG ENOUGH, not as BIG AS
POSSIBLE.
March 01, 2001 -- Thanks for the question regarding "decode and sqlloader", version Oracle 8.0.5.
You Asked
Hi Tom,

1) Can one use select-statment in a decode function?
e.g:

select t.id,t.type,decode(t.type,1,(select * from tab1),
                                 2,(select * from tab2),
                                 3,(select * from tab3),
                                   'unknown')
from tab t
where t.id = &id;

Why doesn't work?

2) Can one use decode in a from clause?
e.g:
select * from tab t,decode( if t.type = 1 then from tab1,
                            elsif t.type = 2 then from tab2,
                            elsif t.type = 3 then from tab3,
                            else null)
where t.id = &id;
The decode in from clause has to decide if t.type = 1 then
select * from tab t, tab1 where t.id = &id; elsif t.type = 2
then
select * from tab t, tab2 where t.id = &id; and so on.

3) I have a table like:

create table TAB
(TAB_ID     number(38,1) not null,
 INT_FIELD  number(38,1) not null,
 CHAR_FIELD varchar2(20),
 LONG_FIELD long );
-----------------------------------------------------
My data( file.txt )looks like:
1234;54687;chartext;<longtext in one row (xml-code)>
1574;23587;chartext;<longtext in one row (xml-code)>
1394;53387;chartext;<longtext in one row (xml-code)>
1297;50017;chartext;<longtext in one row (xml-code)>
and so on.....
The longtext is xml-code and variing and can be too large,
begin with < and end with />.
-------------------------------------------------------

Would you please explain me, how can I insert long data into a
longfield with sqlloader.
I tried it with the following example:

OPTIONS (BINDSIZE=256782)
LOAD DATA
 INFILE "file.txt"
 REPLACE
INTO TABLE <tabname>
 FIELDS TERMINATED BY ';'
( TAB_ID ,
  INT_FIELD ,
  CHAR_FIELD,
  LONG_FIELD VARCHAR(256000)
)

3.I) two first characters (like "<l" ) on every longfield
disapear ( they won't be inserted in the table).
My longfield looks like   "ongtext in one row (xml-code)>"
instead of              "<longtext in one row (xml-code)>"
why?

3.II) if my longdata goes over a couple of lines (it vary every
time) how is the syntax to insert it with sqlloader?

3.III) How about CONSTRAINTS in my table when i use allways
       the REPLACE statment above and have old data in table
       which are related to other tables?

I hope it is understandable whah i mean :-)
Thanks a lot

   Nick
and we said...
1) not until Oracle8i (8.1) and up.

2) no

for 1&2, until you have 8i, you would:

create or replace function my_func( t_type in t.type%type )
return varchar2
as
  l_return varchar2(4000);
begin
  if ( t_type = 1 ) then
      select ... into l_return from tab1;
  elsif ( t_type = 2 ) then
      .....
  end if;
  return l_return;
end;
/
and then use my_func in your SELECT

3) do NOT use varchar -- that would mean the data starts with a
2 byte integer that describes the length of the data.  that is
where your first two characters are going to.

loading data with embedded newlines is hard in 8.0 (trivial in
8i with a new feature in sqlldr).

Your options are:

ƒá Load the data with some other character in the data that
represents a newline (e.g. put the string \n in the text where a
newline should appear) and use a SQL function to replace that
text with a chr(10) during load time.  Since your data is >4000
bytes, that won't work.

ƒá Use the FIX attribute on the infile directive and load a
fixed length flat file.  Probably not good.

ƒá Use the VAR attribute on the infile directive and load a
varying width file that uses a format such that the first few
bytes of each line are the LENGTH of the line to follow.  This
is probably your answer.

For example, use a ctl file that looks like this:

OPTIONS (BINDSIZE=256782)
LOAD DATA
 INFILE test.dat "var 4"
 REPLACE
INTO TABLE tab
 FIELDS TERMINATED BY ';'
( TAB_ID ,
  INT_FIELD ,
  CHAR_FIELD,
  LONG_FIELD char(256000)
)

and then a test.dat file with:

  541234;54687;chartext;<longtext in one
row (xml-code)>
  531574;23587;chartext;<longtext in one row (xml-code)>
  531394;53387;chartext;<longtext in one row (xml-code)>
  531297;50017;chartext;<longtext in one row (xml-code)>

the first 4 bytes are a number -- the line with the break in it
is 54 bytes in line, the remaining three are 53 bytes.  This
loads right up.
Review & Followup
Rating: 2
A better way March 30, 2001
Reviewer: John Flack from Arlington, VA USA
Tom -
The guy who wanted to select from different tables, depending on a value could
have used an inline view, if you assume that the columns of the tables have
identical datatypes.
SELECT * from
(select 'Tab1' table_name, tab1.* from tab1
 union all
 select 'Tab2', tab2.* from tab2
 union all
 select 'Tab3', tab3.* from tab3)
where table_name = 'Tab2';
This works on Oracle 7.3 and later.

Rating: 3
"A Better way" may not be "a better way" April 26, 2001
Reviewer: Hugo GB from Spain
Someone has recommended to use an in-line view , making a union of all tables .
I think it`s not a good solution ,
on depending on the number of rows of each table , it migth
be very slow to make a union of 3 tables , and then a join with another one ,
when you only needs a to make a join of two tables.

A possible way is to use Native Dynamic SQL or the DBMS_SQL package (Oracle7.1).

Rating: 2
About first question. May 06, 2001
Reviewer: Absalam Hichri from Los Angeles California
select t.id,t.type,decode(t.type,1,(select * from tab1),
                                 2,(select * from tab2),
                                 3,(select * from tab3),
                                   'unknown')
from tab t
where t.id = &id;

result from bad table design. He or she had better merge
three table - tab1, tab2, tab3.
like this : all columns, type

Rating: 5
How can I arrange Table June 05, 2001
Reviewer: Nuray from Turkiye
Hi Tom,

I want help from you because my SQL knowledge is not enough.
I have a table that is IKY_DIL_V. It likes so,
LOC_ID    EMP_NUM    SEGMENT1
21    8    ENG
21    8    FRAN
21    8    GER
21    2    ENG
21    2    GER
21    1    ARA
20    5    ENG
20    5    RAN
20    7    ENG
20    7    GER

I WANT TO ARRANGE  IT TO ANOTHER EMPTY TABLE
( I have an empty table which is name IKY_TEMP. I want to arrange all knowledge
on this table like so)

IKY_TEMP

LOC_ID    EMP_NUM    LANG1    LANG2    LANG3
21    8    ENG    FRAN    GER
21    2    ENG    GER
21    1    ARA
20    7    ENG    GER
20    5    FRAN    GER

Would you please explain me, how can I do.
I hope it is understandable what I mean
Thanks a lot

March 01, 2001 Sasha -- Thanks for the question regarding "Returning a Result Set from PL/SQL stored procedure to JDBC.", version 8.06
You Asked
Hi Tom,

I have searched and read through your answers and other sources
regarding this subject - it basically involves returning a ref
cursor through jdbc.

Here is what we would like to do:

Write a PL/SQL stored proc to populate a temporary table.  I
need to use multiple SQL statements and various PL/SQL
conditional logic in order to accomplish this task.  This will
allow us to keep the business logic in PL/SQL.
We would rather use the temp table approach, since we only need
it in the memory of the execution of the PL/SQL proc, instead of
creating a physical table in the db.

It seems like the only PL/SQL way to do this in 8.06 (I see that
temp tables do not exist until 8i) is to use a VARRAY of RECORDS
(or OBJECTS) to mimic a table structure (multiple columns/rows).
 Can you return such a structure back to java through jdbc?  I
don't think I can return a ref cursor based on this structure
(ref cursors need to go off of Select statements).

What is the best way of accomplishing this?  Can we make a ref
cursor without using SQL - can it go off of a VARRAY of RECORDS?

Thanks for taking the question,
Sasha Amnuel
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:246014735810
...

it shows how exactly to do what you describe.
Review & Followup
Rating: 2
Still no JDBC example given March 13, 2001
Reviewer: J?rn Hansen from Aarhus, Denmark
The answer contains a nice walkthrough of creating the
refcursor.

But I would like to have seen an example of using it from
a JDBC program.

Rating: 5
JDBC Example is here March 24, 2001
Reviewer: A reader
http://osi.oracle.com/~tkyte/ResultSets/index.html

      Rating: 5
great
      minds...  April 12, 2001
Reviewer:  Simon
      Wenham  from Reigate, UK
I have just posted a question in the OTN discussion database on this very topic.
 Had I seen this first I wouldn't have had to as it answers my query

March 01, 2001 Andey -- Thanks for the question regarding "Get
      Error Description By Error Number", version 7.3

      You Asked
Hi, Tom

I'm using VB to access Oracle database. I have the problem to
read the Oracle error message, but I can get the error number
such like ORA-00971. so my question is if there is any way I can
get the real error message by looking up by the error number. Is
there any system table which I can look up? Something like:
ORA-00971 --> missing SET keyword

Thanks a lot.
Have a good day.

Sincerely,

Andey Zhu

      and we said...
it is a little known fact that sqlerrm is a function with a
default value.  if you pass it an error code, it gives you the
message:

ops$tkyte@ORA8I.WORLD> set serveroutput on
ops$tkyte@ORA8I.WORLD> exec
                          dbms_output.put_line( sqlerrm(-971) );
ORA-00971: missing SET keyword

PL/SQL procedure successfully completed.

March 01, 2001 joel -- Thanks for the question regarding "quoted
      string", version 8.1.5

      You Asked
hi tom
how do i quote a string whithin a string or backslash
a special characters my qurey is
veriable s varchar2 (80);
s := 'select sku_no from pricemaster where flag = 'D' ';
then it tells me quoted string not properly ended

thank you

      and we said...
You should always use bind variables -- then it is NOT a
problem.

but to put a quote in a string, use 2 quotes:

.... where flag = ''D'' ';

March 01, 2001 muhamed -- Thanks for the question regarding
      "upgrate from 8.1.6 to 8.1.7 on HP", version 8.1.6

      You Asked
I am looking for any documentation  about upgrading the oracle
database from 8.1.6 to 8.1.7. We are running on HP UX.

Thank you,
Muahmed.

      and we said...
It should come with your media -- an OS admin/installation
guide.  If not, goto

http://technet.oracle.com/docs/products/oracle8i/doc_index.htm
the pdf's for HP/UX are there.
March
      01, 2001 Andey -- Thanks for the
      question regarding "Use SQLERRM function in SQL Statement", version 7.3

      You Asked
Hi, Tom

Thanks a lot for your response to my last question about the
error message and error number, which is very helpful. I'm
wondering if there is any way I can use the function SQLERRM in
an SQL statement such as in a SELECT statement, probably not
directly, but some way around. I tried it in SQL worksheet:
SELECT SQLERRM(-971) FROM dual, which didn't work. Thanks a lot.

Sincerely,

Andey

      and we said...
You'll have to write a wrapper routine to do that.

ops$tkyte@ORA734.US.ORACLE.COM> create or replace
  2  function my_sqlerrm( p_err in number )
  3  return varchar2
  4  as
  5  begin
  6          return sqlerrm( p_err );
  7  end;
  8  /

Function created.

ops$tkyte@ORA734.US.ORACLE.COM> select my_sqlerrm(-917) from
dual;

MY_SQLERRM(-917)
--------------------------------
ORA-00917: missing comma

ops$tkyte@ORA734.US.ORACLE.COM>
March 02, 2001 Raj -- Thanks for the question regarding "Dynamic
      SQL", version 8.0.5

      You Asked
Tom,

I am having problem with the creation of sequence dynamically.
Here are the steps I did. Intention of this is to create the
sequence everyday.

CREATE OR REPLACE PROCEDURE create_sequence IS
         cursor_handle INTEGER;
         feedback INTEGER;
BEGIN
         cursor_handle := DBMS_SQL.OPEN_CURSOR;
         DBMS_SQL.PARSE (cursor_handle, 'CREATE SEQUENCE MYSEQ
', DBMS_SQL.v7);
         feedback := DBMS_SQL.EXECUTE (cursor_handle);
         DBMS_SQL.CLOSE_CURSOR (cursor_handle);
END create_sequence;
/
Procedure created.

exec
dbms_job.isubmit(999,'create_sequence;',sysdate,'sysdate+(1)');

PL/SQL procedure successfully completed.

exec dbms_job.run(999);
BEGIN dbms_job.run(999); END;

*
ERROR at line 1:
ORA-12011: execution of 1 jobs failed
ORA-06512: at "SYS.DBMS_IJOB", line 405
ORA-06512: at "SYS.DBMS_JOB", line 267
ORA-06512: at line 1

I am not sure what I am missing?  Any suggestions.

Thank you.

      and we said...
Well, I'll have a couple of comments here.

first, I would not create a seqence per day.  that would be DDL,
it will invalidate all procedures that use it.  It would be much
better to "fix" the sequence.  I'll guess that you want the
sequence to be reset. What you should do instead is "reset" the
sequence.  Here is an example (shows that dependent objects will
not go invalid as well)

ops$tkyte@ORA734.US.ORACLE.COM> create sequence myseq;
Sequence created.

ops$tkyte@ORA734.US.ORACLE.COM> create or replace
        procedure dependent_on_myseq
  2  as
  3      l_val number;
  4  begin
  5      select myseq.nextval into l_val from dual;
  6      dbms_output.put_line( l_val );
  7  end;
  8  /

Procedure created.

ops$tkyte@ORA734.US.ORACLE.COM> CREATE OR REPLACE
  2  PROCEDURE reset_seq
  3  IS
  4      l_cursor integer := dbms_sql.open_cursor;
  5      l_val   number;
  6  BEGIN
  7      select myseq.nextval into l_val from dual;
  8      dbms_sql.parse(l_cursor,
  9                    'alter sequence myseq increment by -' ||
                        to_char(l_val) ||
 10                    'minvalue -1',
 11                     dbms_sql.native );
 12      l_val := dbms_sql.execute( l_cursor );
 13
 13      select myseq.nextval into l_val from dual;
 14
 14      dbms_sql.parse(l_cursor,
 15          'alter sequence myseq increment by 1 minvalue 0',
 16                     dbms_sql.native );
 17      l_val := dbms_sql.execute( l_cursor );
 18
 18      dbms_sql.close_cursor( l_cursor );
 19  exception
 20      when others then
 21          if ( dbms_sql.is_open( l_cursor ) )
 22          then
 23              dbms_sql.close_cursor( l_cursor );
 24          end if;
 25          raise;
 26  END;
 27  /

Procedure created.

ops$tkyte@ORA734.US.ORACLE.COM> select myseq.nextval from dual;

   NEXTVAL
----------
         1

1 row selected.

ops$tkyte@ORA734.US.ORACLE.COM> select myseq.nextval from dual;
... [snip] ...
ops$tkyte@ORA734.US.ORACLE.COM> select myseq.nextval from dual;

   NEXTVAL
----------
         6

1 row selected.

ops$tkyte@ORA734.US.ORACLE.COM> select object_type, object_name,
status
  2  from user_objects
  3  where status = 'INVALID'
  4  order by object_type, object_name
  5  /

no rows selected

ops$tkyte@ORA734.US.ORACLE.COM> exec reset_seq

PL/SQL procedure successfully completed.

ops$tkyte@ORA734.US.ORACLE.COM> select object_type, object_name,
status
  2  from user_objects
  3  where status = 'INVALID'
  4  order by object_type, object_name
  5  /

no rows selected

ops$tkyte@ORA734.US.ORACLE.COM> select myseq.nextval from dual;

   NEXTVAL
----------
         1

1 row selected.

As for why the job is failing, that will be recorded in your
SERVERS alert.log.  Odds are it is a "insufficient privs" error.
 You should try running that procedure in the database "as is",
not through jobs and it'll fail in the same way.  See

http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for why that is.

March 02, 2001 wallacel -- Thanks for the question regarding
      "how do i know my current session setting?", version 8.1.6

      You Asked
Tom:

connect scott/tiger
alter session set nls_date_format='yyyymmdd';

how do i know my current setting for nls_date_format?
show parameter nls_date_format don't work
either is v$parameter

      and we said...
select * from nls_session_parameters;

Review &
      Followup

      Rating: 4
What about
      other sessions?  May 30, 2002
Reviewer:
      Doug  from CT, USA
Tom - what if you wanted to find out the parameters and events in a different
session other than your own.  Is there any way to do that?

March 02, 2001 Quang -- Thanks for the question regarding
      "Locally Managed Tablespaces", version 8.1.6

      You Asked
Dear Tom,
I have read an article in Oracle Magazine regarding locally
managed tablespaces.  It seems to me that there many benefits to
be gained if a DBA would make all his tablespaces to be locally
managed.
I would welcome your opinion on locally managed tablespaces.
Are there any disadvanges, drawbacks, costs, ..., etc. if one
will create a new database with all tablespaces to be managed
locally?

Thank you very much for your opinion and comments.

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:7:::::F4950_P7_SEARCH_CRITERIA:locally
I love them.  They are the only thing I use now.  All of my
tablespaces are always locally managed with UNIFORM extents
(except system which cannot yet be locally managed)
March 02, 2001 Tom -- Thanks for the question regarding "Mapping
      a long varchar to a number.", version 8.1.6

      You Asked
We have a string value (20chars) that is the primary key in a
number of tables.  We've mapped this value onto a number to save
space (this could be totally wrong--that's why I'm writing); so
that we've got the following tables:

    table_a(
        sampleid NUMBER PRIMARY KEY,
        sampleno VARCHAR2(20), ...);

    table_b(sampleid NUMBER, ... table_b_data ...);
    table_c(sampleid NUMBER, ... table_c_data ...);
    ....
    table_z(sampleid NUMBER, ... table_z_data ...);

We have a single function for inserting or looking up sample
numbers from table_a.  It's called sampleno_to_id, and it looks
something like this:

    FUNCTION sampleno_to_id(i_sampleno IN VARCHAR2)
    RETURN NUMBER
    IS
        CURSOR c1(i_sno) IS
            SELECT sampleid FROM table_a WHERE sampleno=i_sno;

        m_id NUMBER;
    BEGIN
        m_id := NULL;
        OPEN c1(i_sampleno);
        FETCH c1 INTO m_id;
        CLOSE c1;

        IF m_id IS NULL THEN
            INSERT INTO table_a(sampleid, sampleno)
            VALUES(sq_sampleid.NEXTVAL, i_sampleno)
            RETURING sampleid INTO m_id;
        END IF;
        return m_id;
    EXCEPTION
        WHEN dup_val_on_index THEN
            OPEN c1(i_sampleno);
            FETCH c1 INTO m_id;
            CLOSE c1;
            RETURN m_id;
    END sampleno_to_id;

The exception part is used if another process calls this
function to add the same sampleno into the table that we're
trying to add between our first select and our insert.

Having two fetches seems like a very cumbersome way to handle
this.  I've read your other submissions using dbms_lock with a
hash value to ensure only one transaction is using a block at
the same time, but wouldn't that cause a loss of concurrency in
this case since any lookup would have to dbms_lock.
Again, this seems cumbersome and overthought, and I've found
that cumbersome normally means I'm trying to do something not
quite right.  So I'd love to hear your suggestions or opinions.

Thank you,
Tom Wurzbach

      and we said...
Mixing apples and oranges here.  It looks like you are trying to
create a function such that it will return an existing value if
there is one -- otherwise it will CREATE a row and return that
value (and the dup value on index is there in case two people do
it at the same instant).

My dbms_lock example is to PREVENT the dup_val_on_index from
happening by turning it into an IMMEDIADTE ORA-54, resource
busy.  Your logic would break as the one session would not wait
for the other session to finish inserting -- it would get an
error and then return without doing the lookup.

Your logic is sound above, however you would find it faster and
easier to code:

    FUNCTION sampleno_to_id(i_sampleno IN VARCHAR2)
    RETURN NUMBER
    IS
        CURSOR c1(i_sno) IS
            SELECT sampleid FROM table_a WHERE sampleno=i_sno;

        m_id NUMBER;
    BEGIN
        select sampleid into m_id
          from table_a
         where sampleno = i_sno;

        return m_id;
    exception
        when no_data_found then
        begin
            INSERT INTO table_a(sampleid, sampleno)
            VALUES(sq_sampleid.NEXTVAL, i_sampleno)
            RETURING sampleid INTO m_id;

            return m_id;
        EXCEPTION
            select sampleid into m_id
              from table_a
             where sampleno = i_sno;

            RETURN m_id;
    END sampleno_to_id;

select/into is faster and easier to code then OPEN/fetch/close
is.

March 02, 2001 rajeeva -- Thanks for the question regarding
      "Wrapped code", version oracle8.0.4

      You Asked
hi tom
its my priveleges to write u .
i have a question for u .Pl tell me is it possible to see the
wrapped code (Pl/Sql)? if yes then how ?
thanks in advance

bye
rajeeva

      and we said...
Nope, that would utterly defeat the sole purpose of wrapping the
code in the first place.  It is there only to protect the code
from prying eyes.
March 02, 2001
      Usama -- Thanks for the question regarding
      "Percentages", version 8.1.5.0.0

      You Asked
Hey Baby!

My question is ..Can u tell me that as far as memory allocation
of the SGA is concerned, can we categorize the buffers like DB
buffers should be 25 % of the total SGA, or Shared pool be 30 %
of the total SGA, second question is by default JAVA POOL SIZE
in 8i is 20 MB, how can i make it 0 b'coz i don't need it.

      and we said...
No, you cannot generalize like that at all.

I've seen SGAs where the shared pool is many times the size of
the block buffer cache and vice versa.  depends totally on your
system.

In 8.1.5, the java pool size may be set to a minimum of 1048576
(1m).  In 8.1.6, it can go a little smaller.  You do need it one
way or the other -- you cannot get rid of it entirely.
March 03, 2001 Anand -- Thanks for the question regarding "Back
      up and Recovery", version oracle 8i(8.1.6 )

      You Asked
Dear TOM SIR
I am beginner in recovery i am facing problem in performing
incomplete recovery.
This is the way i have proceeded.
First I tool the physical backups of all the datafiles .
I have created a table called Emnployee that resembles the emp
table.
CREATE TABLE EMPLOYEE
(
EMPNO
NUMBER(4),
ENAME
VARCHAR2(10),
JOB
VARCHAR2(9),
MGR
NUMBER(4),
HIREDATE
DATE,
SAL
NUMBER(7,2),
COMM
NUMBER(7,2),
DEPTNO
NUMBER(2)
) TABLESPACE USERS ;

Then i have created a file called bacth  whose contents as
follows

==================
Batch.sql
# REM JUST FOR TEST

insert into employee (select * from emp);
commit;

===================
sql > @batch.SQL

100  rows inserted

commit;

time is 1-MAR-2001 12:00:00 please be carefull about the time

At time  1-MAR-2001 12:10:00  I ran the program again say this
time accidentally .It again inserted 100 rows.
This is something i dont want to happen.So now i want to bring
the database as it was at time is 1-mar-2001 12:00:00
To do this i want to perform incomplete recovery.How to do that
? ( I DONT WANT TO DELETE THE ROWS MANNUALLY)

shutdown the database

I have replaced all the datafiles including system's  with
backups that were taken prior to the
creation of the employee table because I want to roll forward

startup restrict mount

recover database until time '1-MAR-2001 12:00:00'

I GOT THE FOLLOWING MESSAGES.

ORA-01547: warning: RECOVER succeeded but OPEN RESETLOGS would
get error below
ORA-01194: file 1 needs more recovery to be consistent
ORA-01110: data file 1: 'D:\ORACLE\ORADATA\TEST\SYSTEM01.DBF'

WHAT TO DO NOW .HAVE I GONE WRONG WAY ANYWHERE .PLEASE GUIDE .
AFTER RECOVERY MY EMPLOYEE TABLE MUST HAVE EXACTLY 100 ROWS IF
THE RECOVERY IS SUCCESSFUL UPTILL THE TIME SPECIFIED

AND ONE MORE THING I WANT TO EXPERTISE THE AREA OF BACKUP AND
RECOVERY .PLEASE GUIDE ME WHAT MUST
BE THE APPROACH.ARE THERE ANY GOOD BOOKS THAT CAN BE PRACTICALLY
USEFUL FOR ME.HOW TO PROCEED ? I MEAN
WHERE TO START.BASICALLY ALL THESE DAYS I WAS PURELY IN
DEVELOPMENT NOT ADMINISTRATION

THANKS IN ADVANCE

      and we said...
http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/performi.htm#14678
goes through all of the steps.  You most likely did not do a
backup controlfile in your backup steps and did not restore the
control file correctly.

That manual and the other backup/recovery manuals are what you
need to read:

http://technet.oracle.com/doc/oracle8i_816/server.816/index.htm
....

March 03, 2001 ali -- Thanks for the question regarding "DBWR
      and Server process", version 8.0.5

      You Asked
Hi sir,

this is ali from hyderabad pakistan. i am little bit confused,
how oracle server determine about the changed blocks (dirty
blocks) after a checkpoint event by which the DBWR writes dirty
buffers in data files and still user do not commit the
transaction or rollback. i mean.

1. If user decided to rollback the transaction, what steps
server process will take to roll back the transaction effect.

2. And if user decided to commit the transaction , what steps
server process will take to make the change permanent, becuase
the transaction data already written in data files because of
any prvious checkpoint (suppose log file switch).

thanks

ali

      and we said...
It is complex -- here is a short scenario.

You update 1,000 rows with a single statement.  Oracle will:

o generate modified datablocks in the SGA
o generate rollback records in the SGA
o generate redo for BOTH datablocks and rollback in the SGA

We may flush some of the REDO generated to the logfiles during
this process (or not). Remember also that before we checkpoint a
block -- the REDO that protects that block is flushed first,
before DBWR can flush it.  There is never a block on disk that
doesn't have its redo written first.  Let's say the system fails
right now in the middle of our update.  We know the above 3
things have happened and either:

o some REDO had been written to the logs and NO data/rollback
blocks have been. When the system restarts, this REDO will be
applied. This will reconstruct the ROLLBACK blocks as well as
the modified DATABLOCKS.  After we roll forward in recovery, we
will roll back using the rollback blocks we just reconstructed.
It will be as if the transaction never happened.

o some REDO and SOME data/rollback blocks have been written.
Same as above then -- we rollforward, applying the REDO to the
blocks that were not checkpointed -- and then we rollback.

o NO redo had been written to the logs.  When the system
restarts -- it is simply as if the transaction never happened.
we are done. no recovery needed.

Now, let's say the system does not fail during our update and it
succeeds.  We have

o generated redo and it is in the SGA (probably)
o generated modified datablocks and they are in the SGA
o generated rollback records and they are in the SGA.

we commit.  LGWR flushes our redo to disk.  Thats it -- we've
committed at that point.  If the system fails right after we
commit, when we restart we apply the REDO to redo that
transaction -- we have all of the information needed to replay
it and we just do.

Hope that helps.

If we do flush some redo to disk and we crash
Review &
      Followup

      Rating: 2
number of dirty
      buffers reaches the a threshold value  March 11, 2001

Reviewer:  ali  from hyderabad,pakistan
dear sir tom,

infact i was confused by the steps taking when a checkpoint occurs if it reaches
its threshold value (how we determine this limit). next thing , is DBWR writes
all dirty blocks
(data and rollback) to their respective segments, whether its transaction became
committed or not, if is this happend then is DBWR writes again on changed data
from rollback segment data, if user rollback the transaction.

thanks

ali

      Rating:
      5
  December 18, 2003
Reviewer:
      A reader
greate help. thanks a lot

March 03, 2001 James -- Thanks for the question regarding
      "Timestamp replication", version 8i

      You Asked
Q1.  Does multimaster replication supports master database of
different version?
     (Say 7.3.4 vs 8.1.6.)

Q2.
I have a multimaster replication setup with 2 masters.  In a
particular table, t1,
there are 2 groups of columns that can be updated exclusively by
the 2 masters.
That is users of db1 can update column c1,c2,c3 while users of
db2 can update column
c4,c5,c6.  How can I setup conflict group using timestamp method
so that update of
c1,c2,c3 in db1 will not cause c4,c5,c6 of db1 overwrite
c4,c5,c6 of db2?
On the other hand, it is also hope that update of c4,c5,c6 of
db2 will not cause its own
c1,c2,c3 to overwrite that of db1.

Thanks for your attention

      and we said...
q1) yes it does.

q2) you would not use timestamp at all.  It seems to me that you
will have a trigger (business rule) at db1 that will reject any
attempt to update c4,c5,c6 and a similar rule at db2 for
c1,c2,c3.  Therefore, the colum group c1..c3 will be sent from
db1 to db2 and the column group c4..c6 from db2 to db1.  There
will never be a conflict.

<quote from the replication manual>
Column Groups

Oracle uses column groups to detect and resolve update
conflicts. A column group is a logical grouping of one or more
columns in a replicated table. Every column in
a replicated table is part of a single column group. When
configuring replicated tables at the master definition site, you
can create column groups and then assign columns and
corresponding conflict resolution methods to each group.

If your replicated table contains multiple column groups, each
group is viewed independently when analyzing updates for
conflicts. For example, consider that columns A1, A2, and A3
belong to Column Group A and columns B1, B2, and B3
belong to Column Group B. If user01 updates column A1 of row 1
at site01 and user02 updates column B2 of row 1 at site02,
both sets of updates are replicated and do not result in a
data conflict.
</quote>
Review & Followup

      Rating: 2
timestamp
      conflict resolution with site priority conflict
      resolution  September 21, 2001
Reviewer:  victor
      tsien  from illinois, usa
I have a case of 2 columns in a table.  One is site_name and the other is
timestamp.  I have 3 sites: siteA, siteB and siteC.  If table-update is siteA in
site_name column, siteA got the priority; otherwise if table-update is from
siteb or siteC, then timestamp takes the charge.  In other words, whoever
updates with the latest timestamp is given priority.  I got error message:

===================================================
---------------------------------------------------
-- site & time priority groups follows:
---------------------------------------------------
--Suspend replication activity on the master
definition site

CONNECT repadmin/repadmin@gddt_ih.ih.lucent.com

BEGIN
  DBMS_REPCAT.SUSPEND_MASTER_ACTIVITY (
     gname => 'gddt_mg');
END;
/

--After you have added the SITE column to your table,
you need to make
--sure that this field is part of the column group
that your site
--priority conflict resolution mechanism is used for.
Use the
--ADD_GROUPED_COLUMN procedure to add this field to an
existing
--column group. If you do not already have a column
group, you can create a
--new column group using the
DBMS_REPCAT.MAKE_COLUMN_GROUP procedure.

BEGIN
  DBMS_REPCAT.MAKE_COLUMN_GROUP (
     sname => 'ccmsadm',
     oname => 'cr_gmt',
     column_group => 'cr_CG1',
     list_of_column_names => 'site_mastered,
create_date');
END;
/

--Before you begin assigning a site priority value to
the sites in your
--replicated environment, you must create a site
priority group that will
"hold"
--the values that you defined.

BEGIN
  DBMS_REPCAT.DEFINE_SITE_PRIORITY ((
     gname => 'gddt_mg',
     name => 'SITE_PG');
END;
/

--Define the priority value for each of the sites in
your replication
--environment using the
DBMS_REPCAT.ADD_SITE_PRIORITY_SITE procedure.
--Execute this API as often as necessary until you
have defined a site
--priority value for each of the sites in our
replication environment.

BEGIN
  DBMS_REPCAT.ADD_SITE_PRIORITY_SITE (
     gname => 'gddt_mg',
     name => 'SITE_PG',
     site => 'gddt_ih.ih.lucent.com',
     priority => 100);
END;
/

BEGIN
  DBMS_REPCAT.ADD_SITE_PRIORITY_SITE (
     gname => 'gddt_mg',
     name => 'SITE_PG',
     site => 'gddt_mh.mh.lucent.com',
     priority => 50);
END;
/

BEGIN
  DBMS_REPCAT.ADD_SITE_PRIORITY_SITE (
     gname => 'gddt_mg',
     name => 'SITE_PG',
     site => 'gddt_cb.cb.lucent.com',
     priority => 49);
END;
/

--After you have completed assigning your site
priority values, you need to
--add the SITE PRIORITY resolution method to your
replicated table. The
--following API examples shows that it is the third
conflict resolution
method
--for the specified column group (SEQUENCE_NO).

BEGIN
  DBMS_REPCAT.ADD_UPDATE_RESOLUTION (
     sname => 'ccmsadm',
     oname => 'cr_gmt',
     column_group => 'cr_CG1',
     sequence_no => 1,
     method => 'SITE PRIORITY',
     parameter_column_name => 'site_mastered',
     priority_group => 'SITE_PG');
END;
/

--Use the DBMS_REPCAT.ADD_UPDATE_RESOLUTION API to
define the conflict
--resolution routine for a specified table. This
example will specify the
--"LATEST TIMESTAMP" conflict resolution routine using
the TIMESTAMP column
--that you created earlier.

BEGIN
  DBMS_REPCAT.ADD_UPDATE_RESOLUTION (
     sname => 'ccmsadm',
     oname => 'cr_gmt',
     column_group => 'cr_CG1',
     sequence_no => 2,
     method => 'LATEST TIMESTAMP',
     parameter_column_name => 'create_date');
END;
/

--After you have defined your conflict resolution
routine, you need to
--regenerate replication support for the table that
received the conflict
--resolution routine.

BEGIN
   DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT (
     sname => 'ccmsadm',
     oname => 'cr_gmt',
     type => 'TABLE',
     min_communication => TRUE);
END;
/

--After replication support has been regenerated, you
need to resume
replication
--activity by using the RESUME_MASTER_ACTIVITY
procedure API.

BEGIN
  DBMS_REPCAT.RESUME_MASTER_ACTIVITY (
     gname => 'gddt_mg');
END;
/

Connected to:
Oracle8i Enterprise Edition Release 8.1.6.3.0 -
Production
With the Partitioning option
JServer Release 8.1.6.3.0 - Production

SQL> ho
$ env| grep ORA
ORACLE_BASE=/opt/oracle/app/oracle
ORACLE_SID=gddt_ih
ORACLE_TERM=sun5
ORA_NLS33=/opt/oracle/app/oracle/product/8.1.6/ocommon/nls/admin/data
ORACLE_HOME=/opt/oracle/app/oracle/product/8.1.6
$ exit

SQL> @time_site_prio
Connected.
BEGIN
*
ERROR at line 1:
ORA-23326: object group "PUBLIC"."GDDT_MG" is quiesced
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 95
ORA-06512: at "SYS.DBMS_REPCAT_MAS", line 3666
ORA-06512: at "SYS.DBMS_REPCAT", line 851
ORA-06512: at line 2

BEGIN
*
ERROR at line 1:
ORA-23330: column group CR_CG1 already exists
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 2173
ORA-06512: at "SYS.DBMS_REPCAT", line 713
ORA-06512: at line 2

SP2-0042: unknown command ""hold"" - rest of line
ignored.
     name => 'SITE_PG');
                       *
ERROR at line 4:
ORA-06550: line 4, column 24:
PLS-00103: Encountered the symbol ";" when expecting
one of the following:
) , * & | = - + < / > at in mod not rem => ..
<an exponent (**)> <> or != or ~= >= <= <> and or like
as
between from overlaps using is null is not || is
dangling
The symbol ")" was substituted for ";" to continue.

BEGIN
*
ERROR at line 1:
ORA-23338: priority or value already in priority group
SITE_PG
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 86
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 1011
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 1338
ORA-06512: at "SYS.DBMS_REPCAT", line 195
ORA-06512: at line 2

BEGIN
*
ERROR at line 1:
ORA-23338: priority or value already in priority group
SITE_PG
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 86
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 1011
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 1338
ORA-06512: at "SYS.DBMS_REPCAT", line 195
ORA-06512: at line 2

BEGIN
*
ERROR at line 1:
ORA-23338: priority or value already in priority group
SITE_PG
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 86
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 1011
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 1338
ORA-06512: at "SYS.DBMS_REPCAT", line 195
ORA-06512: at line 2

SP2-0042: unknown command "method" - rest of line
ignored.
BEGIN
*
ERROR at line 1:
ORA-23339: duplicate conflict resolution information
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 643
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 1415
ORA-06512: at "SYS.DBMS_REPCAT", line 252
ORA-06512: at line 2

BEGIN
*
ERROR at line 1:
ORA-23339: duplicate conflict resolution information
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 643
ORA-06512: at "SYS.DBMS_REPCAT_CONF", line 1415
ORA-06512: at "SYS.DBMS_REPCAT", line 252
ORA-06512: at line 2

PL/SQL procedure successfully completed.

SP2-0734: unknown command beginning "replicatio..." -
rest of line ignored.

PL/SQL procedure successfully completed.

SQL>

      Rating:
      5
replication  October 24, 2001
Reviewer:
      Jian Wu  from New York, USA
The answer was very clear and helpful.

March 03, 2001 sammaiah -- Thanks for the question regarding
      "oracle", version "version8.1.5"

      You Asked
what way properly utilize sqlplus?
how it should maitain database? In database at back end?
how to learn more sql language skills?
Its necessary RDBMS concepts?
Is any relation between sqlplus and pl/sql?
what is oracle 8i?

      and we said...
SQLPlus is a command line tool. You'll use it to connect to your
database to run some interactive SQL queries, compile stored
procedures, test things out.

You can use it to start/stop the database if you are
appropriately priveleged.  You can use it on the server or from
the client.

To learn more sql skills -- write more sql.  It is like
everything else or any programming language, the more you use it
the better you get.  There are many books on the market to help
you get started writing sql.

It is absolutely necessary to understand and learn RDBMS
concepts if you want to use an RDBMS -- 100% necessary.

SQLPlus is a command line tool -- like a DOS prompt or a Unix
prompt.  PLSQL is a language, like C or Java.  They are not the
same.

Oracle8i is the latest production release of Oracle the
database.

I would suggest you read the server concepts manual from cover
to cover to get a good understanding.  All documentation is
available at:

http://technet.oracle.com/doc/oracle8i_816/products.htm
Concepts manual, the MOST IMPORTANT document is:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/toc.htm
if you read and understand half of that, you will already know
more then most.

March 03, 2001 Intiyaz -- Thanks for the question regarding
      "ABOUT DATABASE", version 8.1.6

      You Asked
Can you please explain me SHOW SGA output with reference to
INIT.ORA Parameters.

      and we said...
ops$tkyte@DEV816> show sga

Total System Global Area  186658800 bytes
Fixed Size                    69616 bytes
Variable Size             141443072 bytes
Database Buffers           45056000 bytes
Redo Buffers                  90112 bytes
ops$tkyte@DEV816>

Total size is the sum of the pieces.

The fixed size is dependent on version, os, and options
installed.  It is a chunk of the SGA we set aside for ourselves,
mainly to point into the other areas of the SGA.  Consider that
the "roadmap" to the rest of the SGA.  There are no init.ora
parameters that control this, it is fixed (as its name implies)

The Database buffers is controled by db_block_size *
db_block_buffers.  It is the buffer cache.

ops$tkyte@DEV816> show parameter db_block

NAME                                 TYPE    VALUE
------------------------------------ -------
--------------------
db_block_buffers                     integer 5500
db_block_size                        integer 8192

ops$tkyte@DEV816> select 5500*8192 from dual;

 5500*8192
----------
  45056000   <<<=== matches the show sga output.

ops$tkyte@DEV816>

The redo buffers is control by the log_buffer but has OS
specific minimums (so your size may be different from what you
asked).  For example:

ops$tkyte@DEV816> show parameter log_buffer

NAME                                 TYPE    VALUE
------------------------------------ ------- ------------------
log_buffer                           integer 32768

I asked for 32k but got more then that.

The variable size is mostly made up from

shared_pool_size
large_pool_size
java_pool_size

but other things contribute to it as well.  These are typically
such a small percentage of the total that its not even worth
going thru.  For example, each control file you have specified
in your init.ora constribute 250 some odd bytes to the variable
size of the SGA.  This is where all of the varying sized data
structures will go.
March 03,
      2001 jawad -- Thanks for the question
      regarding "environment variables (set oracle_ sid=", version 8i

      You Asked
1)i have to set d:\set oracle_sid=<sidname> each time to connect
to svrmgrl using "internal" and to start my manually created
database,but this is not the problem with database created by
"database configration assistent" created database.wats to set?
(operating sys:windows 2000
database:oracle 8i)

details:
1)database config assistent created a database by creating
service(auto shutdown,startup,pfile,oracle_sid given in
registery).it starts the database,shutsdown at mechine shutdown
automatically.....every thing nice and well(oracle ...a really
managed product...i have to manage myself like this product)
1)Now i am creating database manually(think no any other
database,no any preivous sid,service....)
2)through oradim i created a service with all options
(as aresult a service is created,in regestry all options i.e
auto start,pfile,auto shut are given(really same as of db config
assistent)
2)now the problem starts,i am going to start svrmgrl,it gives me
error while connecting through internal password......
3)I exit svrmgrl and write this
    d:\>set oracle_sid=<mysidname>
4)now i connect to svrmgrl it connects,i create database every
thing well....i manually start database and exit svrmgrl(with
out sutting down db)
5)now each time i have to set oracle_sid & also i have to start
the database manually
6)i have checked auto exec.bat,registery,environment variables
in controlpanel>system>environement variables option(win 2000
advance server)& compared each thing with automatically created
database.....but alas

(oracle installed in d:drive(logical)(svrmgrl etc)  oracle
folder is in c:\programfiles)

                                 Thankyou for ur services

      and we said...
Use ORADIM to modify the instance to autostart

http://technet.oracle.com/doc/oracle8i_816/nt.816/a73008/ch5.htm#1027981
That should solve the "have to start from the command line"
issue.

As for having to set the Oracle sid before you connect, you
should setup Net8 so that you can specify the database in the
connect string:  scott/tiger@db1, scott/tiger@db2.  Otherwise,
you have to set the oracle_sid to tell us what database to
connect to.
March 03, 2001 Richa -- Thanks for the question regarding
      "Oracle Query", version oracle 8.1.6

      You Asked
Hi Tom

I need an oracle query - in which I give  from_date and  to_date
and it returns me one record for each day in that date range.

If I have a table like this :

sales
=====
invoice_id       number(5) - (PK)
sales_date     date
qty                number(10)

e.g.  If I give from_date = 01/01/2000 and to_date = 05/01/2000,
then I need a recordset like this :

date                      Total_Sale
01/01/2000                500
02/01/2000                0
03/01/2000                450
04/01/2000                123
05/01/2000                230

Pls note that the table may not have a record for 02/01/2000,
but I still need that row in my resultset with total_sales = 0.

      and we said...
Sure, we just need to "make up" some dates and outer join to
your table by date.  For example:

ops$tkyte@DEV816> create table t ( invoice_id number,
  2                   sales_date date,
  3                   qty        number );

Table created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> insert into t values ( 1, trunc(sysdate), 500
);

1 row created.

ops$tkyte@DEV816>
ops$tkyte@DEV816>
ops$tkyte@DEV816> REM my start date is trunc(SYSDATE-2)
ops$tkyte@DEV816> REM my end date is   trunc(SYSDATE+2)
ops$tkyte@DEV816> REM you would use your own dates of course
ops$tkyte@DEV816>
ops$tkyte@DEV816> select theDate, nvl(t.qty,0)
  2    from t, ( select trunc(SYSDATE-2)+r theDate
  3                from (select rownum-1 r
  4                        from all_objects
  5                       where rownum <=
  6                       trunc(SYSDATE+2)-trunc(SYSDATE-2)+1 )
  7            ) dates
  8   where dates.theDate = t.sales_date (+)
  9  /

THEDATE   NVL(T.QTY,0)
--------- ------------
01-MAR-01            0
02-MAR-01            0
03-MAR-01          500
04-MAR-01            0
05-MAR-01            0

ops$tkyte@DEV816>

Review &
      Followup

      Rating:
      3
TRUNC(DATE)  February 11, 2002
Reviewer:
      Sivababu  from GERMANY
Hello TOM,
       Which one is faster when i want to round the date (without time).

 TRUNC(SYSDATE)
or
TO_DATE(TO_CHAR(SYSDATE,'DD-MON-YY'))

thanks in advance

regards,
sivababu

March 03, 2001 OP -- Thanks for the question regarding "\Dynamic
      condition !", version 8.1.6.0

      You Asked
Dear Tom,
Hi !

How are you Doing !

Hope Enjoying Life.

Today,my Ques to you is

I want to fetch some data from a table for which
the condition in the where cluase varies
according to the need.

For example

select ecode,ename from emp
where ecode=102 and ename='ATUL';

select ecode,ename from emp
where j_date='01/01/99' and
deptno=10

Is it possible to pass the complete where clause
as a parameter while creating a CURSOR in a
PL/SQL Block.

When I write

declare
cursor c1(p1 varchar2)
as
select ecode,ename from emp || p1; (It gives ERROR for - || p1)

begin
..
..

end;
/

I there any method so that we can pass different
conditions as parameters in a CURSOR ?

Thanks and Regards
OP Lalwani

      and we said...
Yes you can

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
for how to do this. Please take heed of the caution to use bind
variables.  It is more important then you can ever imagine.
March 04, 2001 Tanveer -- Thanks for the question regarding
      "denormalization", version 8.0

      You Asked
When would you use De-Normalization and why?
What is the advantages and disadvantages of using this query?

I would really appriciate it if ou could help me answer these 2
questions, thanx

      and we said...
I would use de-normalization in a data warehouse/mart situation.
 when the data is predomninantly read only and used for
reporting purposes.  there, the side effect of denormalization
that the data is repeated more then it need be, is OK since I
don't have transactions updating it.  My batch programs can take
care of it correctly.
March 04,
      2001 Chian Yuh -- Thanks for the
      question regarding "Oracle 8.1.7 (Release 3) missing "libaurora.a"",
      version 8.1.7 (Release3) SUN SPARC

      You Asked
I have installed ORACLE 8.1.7(Release3) (Sun SPARC) version into
my new server. Our SunOS is 5.7 in 32Bit. I didn't faced any
error during installation process. But I missing a important
library file which is "libaurora.a". It should be located at
/ORACLE_HOME/lib directory. I found this problem because one of
my application required this file for installation. Can you help
me how to get this file? Or I need to re-install ORACLE? I hope
you can provide other solutions instead if re-install ORACLE?

thankyou,

      and we said...
libaurora.a is not part of the 8.1.7 release.  Why do you
believe you need it?  libjox8.so should have all you need.

the oracle libraries you link into your code change from release
to release.  you probably have a makefile that was designed for
8.1.6.  you should just include

include $(ORACLE_HOME)/rdbms/demo/demo_rdbms.mk

into your makefile and use the symbolics it defines, for exmaple
to link a static OCI program:

-L$(ORACLE_HOME)/lib $(SSDBED) $(DEF_ON) $(OCISTATICLIBS)

or a shared:

-L$(ORACLE_HOME)/lib $(OCISHAREDLIBS)

that will avoid you running into issues like this.  If you are
using pro*c see:

http://osi.oracle.com/~tkyte/proc_makefile/
for how you might do this.

March 04, 2001 -- Thanks for the question regarding "stored
      procedure for grants", version 8.1.6

      You Asked
hi
i have a schema s1 with some objects(tables,views,trigs,procs
etc..)
i have 2 users who have access to all these objects.
one is a superuser and another is a developer.
i want the superuser to be able to create new developers so i
give create user privilege to the superuser.

the superuser should also be allowed to give grants on the
objects in s1 to the newly created developers..so i plan to have
 stored procedure which will be in schema s1 and have execute
privilege to superuser..the stored procedure will contain the
list of grants on the objects and also the create synonym
statements..
is it possible to do like this..is it possible that i include
all the grant statements and create synonym statements in a
stored procedure?
i tried to do that but i get error like this:
"Line # = 3 Column # = 2 Error Text = PLS-00103: Encountered the
symbol "GRANT" when expecting one of the following:

   begin declare exit for goto if loop mod null pragma raise
   return select update while <an identifier>
   <a double-quoted delimited-identifier> <a bind variable> <<
   close current delete fetch lock insert open rollback
   savepoint set sql execute commit forall
   <a single-quoted SQL string>"

my stored procedure is like this :

create or replace procedure sproc_grantstodev
 as
 begin
 GRANT SELECT ON "s1"."table_name" TO "DEVELOPER";
 GRANT EXECUTE ON "s1"."pkg_name" TO "DEVELOPER";
 GRANT EXECUTE ON "s1"."procedure_name" TO "DEVELOPER";
 create synonym DEVELOPER.'table_name' for s1.table_name;
end sproc_grantstodev;
/

please suggest..

thankyou.

      and we said...
create procedure grantstodev
as
begin
   execute immediate
   'grant select on "s1"."table_name" to "DEVELOPER"';
   ....

to do ddl in plsql requires dynamic sql.  Are you really
purposely using lower case object names -- that wouldn't be
recommended.  many tools (especially 3rd party tools) will have
a hard time with that as not everyone supports quoted
identifiers.

Make sure you see:

http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
if you hit an "insufficient privs" issue in your stored
procedures that do DDL.

Review &
      Followup

      Rating:
      5
  August 06, 2003
Reviewer:
      A reader

March 04, 2001 Sridevi -- Thanks for the question regarding
      "Distinct Values of a column to be displayed", version Forms 6

      You Asked
Dear Tom,
Thanks for the immense help so far.

Lets us consider a table of structure
TAB1
(COL1 NUMBER(2),
COL2 NUMBER(6))
Here the column COL1 has unique values. COL2 has repititions.

I want to base my block in Forms 6 on this table TAB1 and I want
to display ONLY DISTINCT VALUES OF COL2 on the canvas.

COL1 is NOT dispalyed on the canvas.

Is this possible DIRECTLY, say by creating a summary item, to
display only distinct values of COL2 on the canvas WITHOUT
HAVING TO USE LOVS, RECORD GROUPS, LIST ITEMS ETC.?

Thanks......

      and we said...
Sure, here is what you do..

1) create a default block on TAB1 with just the COL2 column
2) change the "query data source" property of this block from
table to "from clause query"
3) change the "query data source name" block property from tab1
to "select distinct col2 from tab1"
4) change the "primary key" property of the ITEM tab1.col2 to
"YES"

thats it.  You'll probably want to disable insert/udpate/delete
on this block unless you code the ON- triggers for those actions.
Review &
      Followup

      Rating:
      4
  May 23, 2001
Reviewer:
      A reader


Subject | Article | Last Updated (East coast time)
Convert decimal to hexadecimal | article only | Mar 05, 2001 06:16 am
Function Based Indexes | article only | Mar 05, 2001 06:33 am
Replication | article only | Mar 05, 2001 06:41 am
UTL_FILE | article only | Mar 05, 2001 06:58 am
How to search for keyword in text? | article only | Mar 05, 2001 07:13 am
Usage of Random Numbers | article only | Mar 05, 2001 08:15 am
Sys context and param views | article only | Mar 05, 2001 06:54 pm
Rollback segments' extents | article only | Mar 05, 2001 07:44 pm
Dynamic SQL and binding | article only | Mar 06, 2001 08:56 am
cursors vs. "select...into" | article only | Mar 06, 2001 08:58 am
Displaying HTML documents containing one or multiple gif's | article only | Mar 06, 2001 09:05 am
Calling user defind Funtion from query | article only | Mar 06, 2001 04:26 pm
No of Transactions in Oracle | article only | Mar 07, 2001 08:43 am
data encryption & decryption. | article only | Mar 07, 2001 08:53 am
Chained Rows | article only | Mar 07, 2001 09:02 am
temporary tablespace, xxx_tab_modifications | article only | Mar 09, 2001 09:18 pm
Use of Rollback during the recovery phase | article only | Mar 09, 2001 11:18 pm
passing array from java to oracle | article only | Mar 10, 2001 12:45 am
Read/Write to the database - Reg | article only | Mar 10, 2001 01:00 am
overhead due to data security - reg. | article only | Mar 10, 2001 01:08 am
Usage of Bind Variables - Reg. | article only | Mar 10, 2001 01:40 am
Backups & RMAN | article only | Mar 10, 2001 03:54 am
oracle server with webtogo | article only | Mar 10, 2001 05:03 am
export / import | article only | Mar 10, 2001 10:29 pm
performance tuning | article only | Mar 10, 2001 11:30 pm
Database design | article only | Mar 11, 2001 01:45 am
How to call a remote stored procedure from pro*c, and how to compile the pro*c program? | article only | Mar 11, 2001 02:40 am
Securty | article only | Mar 11, 2001 05:57 am
email from database | article only | Mar 11, 2001 07:05 am
how to use sql plus copy command | article only | Mar 11, 2001 05:18 pm
query | article only | Mar 11, 2001 10:56 pm
Database user Passwords | article only | Mar 11, 2001 11:48 pm
row(s) 1 - 32 of 32
March 05, 2001 tim -- Thanks for the question regarding "Convert decimal to hexadecimal", version 8.0.4
You Asked
Do oracle DB have a function that Converting decimal to
hexadecimal in a column?
If not, is there a work around?
and we said...
In 8.0.4, there is nothing builtin.  You can use the base
conversion routines I have at:
http://osi.oracle.com/~tkyte/hexdec/index.html
In 8i (8.1) and up, it is simply:

  select to_char( number, 'xxxxxxx' ) from t;
March 05, 2001 Narendar -- Thanks for the question regarding "Function Based Indexes", version Oracle 8.1.6
You Asked
Hi Tom,

I am trying to create a function based index for the following.
I am hitting this error. Please advise

create index LNP00701_IDX1 on CARE_LNP00701_SA
(to_number
(to_char(to_date(lpad(to_char(lhpost),6,0),'ddmmyy'),'YYYYMM')));

to_number(to_char(to_date(lpad(to_char(lhpost),6,0),'ddmmyy'),'YY
YYMM')))
                          *
ERROR at line 2:
ORA-01743: only pure functions can be indexed

Thanks
Narendar
and we said...
This is bug #902506 which is still open in 8.1.7.  It is the
to_date function that appears to be "not pure enough" to be
called from SQL.

The workaround is to "hide" the to_date function in a plsql
function.  It'll make it easier to write the above as well.

create or replace function my_func( lhpost in number ) return
number
deterministic
as
begin
    return to_number( to_char( to_date(
              lpad(to_char(lhpost),6,0),'ddmmyy' ), 'YYYYMM'));
end;
/
You can index table( my_func(column) ) then.  When you query,
it'll be easier as well as it will just be:

  select * from table where my_func(column) = value;

instead of that really be function.

Although in your particular case, you could just index:

  200000 + mod(lhpost,100)*100 + mod(trunc(lhpost/100),100)

since you are using YY anyway (year 2000 is the only century
you'll be adding).

Are you SURE you want to use YY and not RR??  Looks like this is
still in need of y2k remediation -- if you do fix it, just use a
DATE column.
March 05, 2001 Nikunj -- Thanks for the question regarding "Replication", version 8.0.5/8.1.6
You Asked
hi tom,

please send me detail steps for how can i do replication for
below perpose.

i have windows nt server 4.0, with Oracle 8.0.5 on both side.

i would like to create readonly replica with the singal table.

thankx,
nikunj
and we said...
Well, first I would urge you to read the replication guide.
There are no shortcuts to knowledge.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76959/toc.htm
The problem is there is more then one way to tackle this problem
and only YOU can decide which is correct.

One method:

o on the "primary site" issue "create snapshot log on T"

o on the copy site, create a database link to primary

o on the copy site issue:

create snapshot my_copy
refresh fast
start with sysdate
next trunc(sysdate)+1+3/24
as
select * from t@other_database;

o on the copy site, set up job_queue_processes and
job_queue_interval in the init.ora file

Now, every night at 3am, this snapshot will copy all of the days
changes from the other site and apply them.  Yes, the interval
can be shorter, it can be longer, it can be manual, whatever.
Review & Followup
Rating: 5
Solutions that has increased my confidence December 11, 2003
Reviewer: shashikant naik from India
Dear Tom,

   Beleive me, not only this article but I am reading and trying to read more
and more data from you site. I like the ways you  answer every question. I am
learning a  lot from this site.

March 05, 2001 Siva -- Thanks for the question regarding "UTL_FILE", version V 7.3.4
You Asked
1. Can you tell me all that needs to be done to set Oracle
Scheduler to run a stored procedure that will query a set of
tables from the Oracle database and use UTL_FILE to create a
comma separated file on the server that hosts the database.

2. Can you also give me an example program to create (ie. output
data from a database) a comma separated file using UTL_FILE.

Thanks
Siva Gabbita
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:68212348056
for a stored procedure to dump a query to a file.  be aware
that until 8.0.5 the output line length limit with utl_file is
1022 bytes -- anything bigger will fail and there is no
workaround other then to get to 8.0.5 and above.

In order to use utl_file, you must set the utl_file_dir init.ora
parameter.

To schedule this on a recurring basis, you would use dbms_job.
You must set the init.ora parameters job_queue_interval and
job_queue_processes to have dbms_job work.  To see how to use
dbms_job, either search for it on my web site here or

select text
from all_source
where name = 'DBMS_JOB
and type = 'PACKAGE'
order by line;

that'll give you the "docs" on dbms_job.
March 05, 2001 Dan -- Thanks for the question regarding "How to search for keyword in text? ", version 8.1.6
You Asked
Hi Tom.

I am building a search- engine in PL and have now reached a
problem.

The procedure 'parses' a input- string to single keyword(s) and
builds a dynamic sql statement that finally (after all words
been parsed) is executed.
I first used the like'%..%' function to find the keyword(s) in
the text- column but soon I realized that I got some unwanted
hits. Like if I search for the word 'cat' I retrieve pages with
for ex. the words 'cat', 'cats', 'catepillar'.....

Is there a way (simple, I need good performance) to do a search
for the hole keyword?

It would be a simple solution suffixing and prefixing with a
space like search for '% cat %'. But I still have to 'take care'
of the possibility that the keyword not always is separated by a
space on both sides.
Like:
1 .cat
2 cat,
3 cat.

Sure, I could search for all possible appearances of the word
but I dont like that. The already big query would be even bigger
and slower...

Thanks in advance
-Dan
and we said...
It is called intermedia.  It provides extensions to SQL to allow
for keyword (and many other) types of searches.

See
http://technet.oracle.com/doc/oracle8i_816/inter.816/index.htm
and
http://asktom.oracle.com/pls/ask/f?p=4950:7:::::F4950_P7_SEARCH_CRITERIA:intermedia
...
March 05, 2001 Bhavesh -- Thanks for the question regarding "Usage of Random Numbers", version 4.0.5
You Asked
Hi Tom,
      Hope you must be doing fine. This question I have for you
is not Oracle product specific but rather application specific.
I have seen on some sites (viz yahoo mail) that once user enters
the username and password a random number is generated. Also I
have read in past in an answer from you on this very Q&A forum
that random number can be generated and used as parameter to
display the information pertaining to user.
In my application I am passing username and session id but I
want to know how random number can be used to add security to
the page. I know that session id is unique but a random number
may or may not be unique. Moreover once a random number is
generated and user goes from one page to another how can this
number be used. Is this number needs to be stored in the table
when user logs in ? Because if this random number is passed as a
parameter to another page then how it can be verified that this
is the same random number generated by the system when user
logged in ?
Thanking you in Advance.
Regards

Bhavesh
and we said...
The random number is used upon session "startup".  When I log in
I would use a function such as:

  select dbms_random.random ||
         to_char( sequence.nextval,'fm0000000')
    from dual;

that generates a very large, non-guessable, random -- yet unique
-- number.  It is similar to the way I generate id's for ask tom
(see the disp_id in the URL).

When I log in, i would put that number into a table with the
session state (it is the primary key).  I would pass that number
from screen to screen.  It is good for lightweight security as
long as the sessions don't last too long and are perhaps even
tied to an ip_address (eg: you remember the remote_addr as well
as the session id).  You can change them from page to page as
well -- each time you send the session id, generate a new one
and update the state.  That would make it much more secure.
March 05, 2001 Sasa -- Thanks for the question regarding "Sys context and param views ", version 8.1.7
You Asked
Hi Tom,

I created one view as:

create  view as create or replace view  Testctxview as
 select * from account where idaccount
=sys_context('MyCtx','test1')  and  idcustomer=
sys_context('MyCtx','test2');

 and created one function which set up sys_context variables :
functx

 when I start :

 select functx (10,20) from dual

 it set up new MyCtx context  values accross one package
SetUpCtx( i didn show it here)

 in v$context I can see values

and according that  view Testctxview works fine - it select
record with idaccount=10 and idcustomer=20.

But I am trying to do something in one step for example :

select a.* from (select functx (10,20) from dual),TestCtxView a

ie. to dinamicly set up in one step new values and call view
with new param values ..

Is it possible ?

Thanks in advance ..

Sasa
and we said...
chicken and egg problem here.  SYS_CONTEXT is treated much the
same way as a bind variable would be.  It is setup and bound at
query PARSE time, before the execute phase of the query.
Therefore, before that query is executed -- the values of
sys_context have already been bound in.  the fact that you come
back and change them later during the execution phase won't
work.

What you can do is "select * from function" instead.  It might
apply in your case:

tkyte@TKYTE816> create or replace type myScalarType
  2  as object
  3  ( ename varchar2(30),
  4    job   varchar2(30)
  5  )
  6  /

Type created.

tkyte@TKYTE816>
tkyte@TKYTE816> create or replace type myTableType
  2  as table of myScalarType
  3  /

Type created.

tkyte@TKYTE816>
tkyte@TKYTE816> create or replace
  2  function get_data( p_search in varchar2 ) return
myTableType
  3  as
  4      l_data      myTableType;
  5      l_search    varchar2(25)
                        default '%'||upper(p_search)||'%';
  6  begin
  7
  8      select cast( multiset( select ename, job
  9                               from emp
 10                              where ename like l_search )
 11                      as myTableType )
 12        into l_data
 13        from dual;
 14
 15      return l_data;
 16  end;
 17  /

Function created.

tkyte@TKYTE816>
tkyte@TKYTE816> select * from table ( cast (get_data( 'a' ) as
myTableType ) );

ENAME                          JOB
------------------------------ ------------------------------
ALLEN                          SALESMAN
WARD                           SALESMAN
MARTIN                         SALESMAN
BLAKE                          MANAGER
CLARK                          MANAGER
ADAMS                          CLERK
JAMES                          CLERK

7 rows selected.
March 05, 2001 Michel -- Thanks for the question regarding "Rollback segments' extents", version 7.3.4
You Asked
Hi Tom,

I have a very short question about the INITIAL_EXTENT and
NEXT_EXTENT parameters for rollback segments. I read in several
sources, including your list of answers, that these two
parameters should be equal for rollback segments. Could you
explain me why ?

All the best,
and we said...
Well, a really short answer is that you cannot have pct increase
set for a rollback segment therefore all NEXT extents are equi
sized so only the initial extent could be different and why have
one extent out of 25 or 35 be a different size?

The long answer is comes from v6 of the database actually since
v7 killed the pctincrease for RBS making the question sort of
"moot" -- rbs's will basically have equi-sized extents and there
is nothing you can do about it.

Article-ID:         <Note:10595.1>

Although there is no direct link between the number of extents
in a rollback segment and the number of transactions that can
make use of that rollback segment, multiple, equally-sized
extents will maximize the number and size of transactions that
may make use of that rollback segment.  The SYSTEM rollback
segment and deferred rollback segments are special system
resources not under the control of the DBA, so they are ignored
in the following discussion.

Assume:

     o  Rollback segments with N bytes total space.

     o  Transaction t such that between the first statement in t
        and the ROLLBACK or COMMIT that terminates t, Nt bytes
        are
        written to s by all transactions using s, including
        transaction t.  Whether or not t itself writes any bytes
        to s is irrelevant. The total number of bytes written
        to s during the internal between the start and end of t
        is
        the value of Nt to assume here.  Measuring or
calculating
        Nt for a transaction is not discussed in this bulletin;
        Nt is merely used to derive a useful result.

When the database fills up one extent of s with rollback
information for one or more transactions, it attempts to enter
the next extent e of s.  When the database enters extent e after
the previous extent has been filled, the previous contents of
extent e will no longer be accessible.  Thus, extent e will
never be entered if any active update transaction is making use
of e. This is different than transaction t requesting that the
database allocate it some space: a transaction can be allocated
space in an extent that is also used by other transactions.  The
prohibition against entering an extent that has active update
transactions in it applies only when extent boundaries are
crossed.  Transactions involving only queries (SET TRANSACTION
READ ONLY or SELECT statements) are not considered update
transactions, while transactions having any UPDATE, INSERT,
DELETE, CREATE TABLE ... AS SELECT, etc. statements
are.

If e cannot be entered, the database attempts to allocate
another extent for s.  If another extent can not be allocated,
errors such as ORA-1555 "snapshot too old", ORA-1562 "failed to
extend rollback segment", or ORA-1547 "failed to allocate extent
of size num in tablesapace 'name'" may result.

Example:

Let s have 2 equally sized extents, e1 and e2, and let

     Nt = .75 * N
(1)

If t begins in the first half of e1, then t will complete before
the database will need to re-enter e1 (see Figure 1).

       e1               e2               e1
       entered          entered          re-entered
       |                |                |
     |-|-------|+-------|--------+------||-------+--------->
               |                        |
               transaction t            t
               begins                   ends

                               Figure 1

If t begins in the latter half of e1, then the database will
need to re-enter e1 before t completes (see Figure 2).

       e1               e2               e1
       entered          entered          re-entered
       |                |                |
     |-|--------+|------|--------+-------||------+--------->
                 |                        |
                 transaction t            t
                 begins                   ends

                               Figure 2

Although rollback segment s has N bytes available, t might not
successfully run even though Nt < N.

Multiple, Equally-Sized Extents:

Clearly, if Nt > N, and t is using rollback segment s, t will
not complete successfully unless more extents are added to s as
t runs.

In order to discuss cases where Nt < N, the statistic Ne, the
effective number of bytes in s, is useful.

     Ne = N - Nm
(2)

where Nm is the number of bytes in the largest extent of s.  If

     Ne < Nt < N
(3)

t may finish without needing another extent to be added to s.
If

     Nt < Ne
(3.1)

t will finish without needing another extent to be added to s
unless another transaction interferes.  Assume transaction T
such that during the duration of T, the number of bytes NT
written to s is greater than the Nt for any other transaction t.
 Confining the discussion to a single rollback segment s,
clearly then the condition

    NT < Ne
(4)

is sufficient to ensure that T have enough space available in s.
 If T has enough space to run, then any other transaction t also
has sufficient space. Maximizing Ne allows the database to more
effectively use the space allocated to a rollback segment.

Ne is maximized for a particular E when each extent (including
the initial extent) of s is the same size.  In that case,

    N = E * Nm
(5)

and thus

                       N         (E - 1)
    Ne = N - Nm = N - --- = N * ---------
(6)
                       E            E

and, more simply, the useful relationship is

              (E - 1)
    Ne = N * ---------
(7)
                 E

where E is the number of extents in s.  As E grows, Ne will
asymptotically approach N, as illustrated in Figure 3.

                        E      (E - 1)/E       Ne
                       ---    -----------   --------
                        2         0.5       0.5  * N
                        5         0.8       0.8  * N
                       10         0.9       0.9  * N
                       20         0.95      0.95 * N
                       50         0.98      0.98 * N

                               Figure 3

Interactions Between Rollback Segments:

Inequality (4) was derived by limiting our attention to a single
rollback segment s.  When more than one rollback segment is used
at once, the interactions between rollback segments must be
considered.  When the database needs to enter the next extent e
in s, in addition to checking the status of e, the statuses of
all other rollback segments are also checked.  Extent e will
not be entered if there is an active update transaction t in
another rollback segment that began before the oldest
(committed) transaction in e.  Extent e will not be entered
because entering e will remove information that could
potentially be required for giving t a read-consistent view of
data.  Read-only transactions will never deter the database from
entering extent e.

Because transaction t may use any (non-SYSTEM) rollback segment
in the database, for multiple runs of t, the Ne available to t
will be more consistent if the rollback segments in the database
have equivalent Ne.

The Moral:

Create each rollback segment with several extents of equal size.

Increasing the number of extents in a rollback segments beyond
20 will have very little impact on the size of transactions able
to use a rollback segment.

Variables:

The variables used in this bulletin are listed in alphabetical
order.  Note that two-letter variable names are used.

     e  The extent in rollback segment s that the database will
        attempt to enter when another extent is needed in s.

     e1 The first extent of rollback segment s having two
extents.

     e2 The second extent of rollback segment s having two
extents.

     E  The number of extents in rollback segment s.

     N  Size in bytes of rollback segment s.

     Ne The 'effective number of bytes' in rollback segment s.
        Maximizing this statistic for a rollback segment
        is the point of this bulletin.

     Nm The number of bytes in the largest extent of rollback
        segment s.

     Nt Number of bytes written to rollback segment s by all
        transactions during the running of transaction t.

     NT The maximum Nt for rollback segment s.
     s  Rollback segment.

     t  A Transaction.

     T  The transaction that requires NT bytes in s to complete.
March 06, 2001 Easwar -- Thanks for the question regarding "Dynamic SQL and binding", version Oracle 8.1.6
You Asked
Hi Tom,

I have a dynamic SQl wherein both the columns and the table name
are dynamic

eg.

'Select ' || listofcolumns || ' from ' || tablename;

where listofcolumns and tablename are determined at runtime.

This query when executed will obviously return more than 1 row
(a cursor would be needed).

I have a need to execute this cursor and get the column values
and perform further processing. I am not sure how to perform the
Binding at run time as the number of columns is not a fixed
value.

Is there a way to do this?

Thanks in advance for your help.

Easwar
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:68212348056
it shows how to use dbms_sql to process any result set -- it is
a routine to dump a query to a flat file and it has no idea the
datatypes or number of columns until runtime.
March 06, 2001 Jim -- Thanks for the question regarding "cursors vs. "select...into"", version 8.1.6.3
You Asked
Are there any general guidelines about when it would be better
to use cursors as opposed to "select...into" statements ?  Is
performance or overhead an issue between these two methods ?

Thanks
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1544606261686
if you are going to get at least one row and at most one row --
select into is superior to any other method.
March 06, 2001 Bhavesh -- Thanks for the question regarding "Displaying HTML documents containing one or multiple gif's", version 4.0.5
You Asked
Hi Tom,
   Thanks for all your help in past. I am developing a portal
whereby user needs to create html file and stores it into the
database so that all other users can view the same. I am storing
this information in a CLOB field. Now the user requirement is
that in this HTML file what he creates, he sometimes may have 1
or multiple graphic images viz. gif's, jpeg.  What is the best
way to address this issue. I mean after creating the html where
should I ask the user to upload the image files on the server
and then what code he should have in the html file so that the
html is displayed with appropriate graphics, when some other
user view this file.
    Thanks in advance.
Regards

Bhavesh
and we said...
This is hard -- since the URLS they have embedded in the HTML
have to reference these uploaded images -- not the ones on their
hard drives.

Not sure what to tell you here -- this is a pure application
design issue.  You'll probably end up having to REWRITE their
HTML to reference the uploaded images -- but then it makes it
hard for them to edit their documents later.

You might want to consider doing this:

o give the user a "gallery" application where they can upload
images, documents and such.  Perhaps going as far to user
intermedia to index documents and generate thumbnails of the
images.

o the user creates their HTML and their HTML references the
already uploaded content.  They never reference anything on
their local machine, only uploaded content.

o the user uploads their HTML which "just works" because it
references the already uploaded (and indexed, searchable)
content.
March 06, 2001 Venkata -- Thanks for the question regarding "Calling user defind Funtion from query ", version 8.0.5.0
You Asked
Hi Tom,

Here is the EXP. for my ?' which I asked U previously.

Please me know if U need more Info.

Thank you

++++++++++++++++++++++++++++++++++++

FUNCTION f_get_Date(p_dt varchar2)
return Date
is
begin

-- This Function converts a Given String in the Format YYYYMMDD
into Date Value.

 if(f_is_Date(p_dt)) then
 if substr(p_dt,1,2) <=12 then
   return to_date(p_dt,'MMDDYYYY');
 else
   return to_date(p_dt,'YYYYMMDD');
 end if;
 else
  return null;
 end if;
end;

SQL> create table x( ddd varchar2(10));

Table created.

  1  insert into x(
  2* select ddd from asr_admin_extr where rownum<=30)
SQL> /

30 rows created.

  1  insert into x(
  2  select ddd from asr_admin_extr where rownum<=30
  3* and substr(ddd,1,2) <= '12')
SQL> /

13 rows created.

SQL> select ddd from x;

DDD
--------
20000405
20000405
20000406
20000406
20000407
20000407
20000407
20000407
20000407
20000406
20000412
20000414
20000421
20000406
20000414
20000411
20000425
19990524
19990601
20000424
20000411
20000421
19990601
19990617
19990617
19990609

01990531

01990531

SQL> select f_get_date(ddd) from x;

F_GET_DAT
---------
05-APR-00
05-APR-00
06-APR-00
06-APR-00
07-APR-00
07-APR-00
07-APR-00
07-APR-00
07-APR-00
06-APR-00
12-APR-00
14-APR-00
21-APR-00
06-APR-00
14-APR-00
ERROR:
ORA-01847: day of month must be between 1 and last day of month
ORA-06512: at "FCADEV.F_GET_DATE", line 10
ORA-06512: at line 1

SQL> select count(*) from (
  2  select f_get_date(ddd) from x);

 COUNT(*)
---------
       52

+++++++++++++++++++++++++++++++++++++

Hi Tom,

How RU?

 I have one function F_GET_DATE ( p_val  in varchar2) . The
parameter p_val value, I am
Passing from a table column.  While testing function, I find one
interesting thing.

1. Select F_GET_DATE (DDD) from asr_admin_log_extr;

The above query 1 fails because of the data related issue (I
knew the problem, I fixed the function).

2 . Select count(*) from ( select F_GET_DATE (DDD) from
asr_admin_log_extr);

The above query 2 did not fails, even I have data related issue.

Now, my? Is.  Why Oracle won’t return the error, when I use the
same query as in-line view?
My best knowledge query 2 has to be failed with same error. But
it did not.

Please let me know the mystery.

Thanks,

Venkat R. Jangala
Oracle DBA
and we said...
A small test case would be something I could run on my system --
however, I was able to derive the gist of your issue from the
above.

It is normal and expected.  It is the optimizer doing its job.
Consider:

ops$tkyte@DEV816> create or replace FUNCTION f_get_Date(p_dt
varchar2)
  2  return Date
  3  is
  4  begin
  5     return to_date(p_dt,'MMDDYYYY');
  6  end;
  7  /
Function created.

ops$tkyte@DEV816> create table x( ddd varchar2(10));
Table created.

ops$tkyte@DEV816> set arraysize 1

ops$tkyte@DEV816> insert into x values ( '12012001' );
1 row created.

ops$tkyte@DEV816> insert into x values ( '13012001' );
1 row created.

ops$tkyte@DEV816> select f_get_date(ddd) from x;

F_GET_DAT
---------
01-DEC-01
ERROR:
ORA-01843: not a valid month
ORA-06512: at "OPS$TKYTE.F_GET_DATE", line 5
ORA-06512: at line 1

ops$tkyte@DEV816> select count(*)
  2    from ( select f_get_date(ddd) from x);

  COUNT(*)
----------
         2

ops$tkyte@DEV816> select count(f)
  2    from ( select f_get_date(ddd) f from x);
  from ( select f_get_date(ddd) f from x)
                *
ERROR at line 2:
ORA-01843: not a valid month
ORA-06512: at "OPS$TKYTE.F_GET_DATE", line 5
ORA-06512: at line 1

The optimizer understands that

select count(*)
  from ( select f(x) from t )

is identical to

select count(*)
  from (select NULL from t)

and that is what it does.  You were counting on a side effect --
that of the function executing -- but there is no rule saying
the function will execute (or that it won't).  The optimizer
just got rid of it as it does not affect the outcome of the
subquery with regards to a count(*).

My query forced the database to run your function (but it is
DIFFERENT then count(*)).  It counts NON-NULL return values from
your function whereas count(*) just counts rows.
March 07, 2001 Kalpesh -- Thanks for the question regarding "No of Transactions in Oracle", version 8.1.5
You Asked
Hi Tom,
 I want to know the no of transactions taken place today in my
Oracle Database.
  These transaction means no of inserts , no of updates and no
of deletes.
  How can I get that?

Thanks in Advance
Kalpesh
and we said...
We do not track the number of individual inserts/updates/deletes
however you can get many statistics from v$sysstat.

You can find out how many logins you've had.

How many commits/rollbacks you've had (thats the number of
transactions).

etc.etc.etc.

A tool such as statspack will help you collect and report on
this data:
http://www.oracle.com/oramag/oracle/00-Mar/o20tun.html
....
March 07, 2001 Kannan -- Thanks for the question regarding "data encryption & decryption.", version 8.05,8.1.5
You Asked
Hi Tom,

We need to store our application user's password in Oracle
database (Version 8.0.5) in a encrypted form. Oracle supplied
package DBMS_OBFUSCATION_TOOL_KIT is available on version 8.1.6
onwards. I would like to know, is any way to implement
encryption& decryption on version 8.0.5.

Thanks in advance.

Kannan
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:95412348059
for how I would solve this.  Much like Oracle itself, I
would not store the passwords encrypted but rather as a digest.
Lets you validate the password but you cannot ever "get" the
password back (un-reversable)
Review & Followup
Rating: 4
DBMS_OBFUSCATION_TOOL_KIT July 06, 2001
Reviewer: Rodriguez from Switzerland
Thanks, it's exactely what I search

March 07, 2001 -- Thanks for the question regarding "Chained Rows", version 8.1.6
You Asked
Tom

In one of your question abt how to avoid chained rows you have
mentioned the following

>> First -- couple of sanity checks

>> o you are sure the rows can be unchained.  They are smaller
>> then your blocksize correct?  if they contain a long or long
>> raw, they will be chained no matter what.

My question is there will there not be chained rows If i create
a table with BLOB, CLOB. Does the chained row affect only long
and long raw.

If so how do I change long flds in CLOB and Long Raw into BLOB

Thanks
and we said...
clobs and blobs will never be reported as chained rows UNLESS

o they are created with enable storage in row
o they are less then 4,000 bytes
o the sum of the other pieces of the row + its length exceeds
  the block size

You would use the TO_LOB function to convert a long/long raw
into a clob/blob.
March 09, 2001 ted -- Thanks for the question regarding "temporary tablespace, xxx_tab_modifications", version 8.1.6
You Asked
thomas,

1. temp tablespace initial 64k next 64k pctincrease 0
   sort_area_size 256k
   a. does temp tablespace ever get used ? since 64k <256k+block
size
   b. If it is used. In what manner it gets used and how
inefficient
      is it ?
2. how is all(user)_tab_modifications get populated ?

thnx ted chyn
and we said...
1a) yes temp will get used.  sort more then 256k of data and
it'll get used.

1b) it'll be used inefficiently.  the extent size of temp should
be an even multiple of your sort area size (setting it to the
sort area size is a good idea).  right now, it needs 4 extents
just to hold one sort swap section.

2) from the doc on ALL_TAB_MODIFICATIONS in the server reference
manual:

These views are populated only for tables with the
MONITORING attribute. They are intended for statistics
collection
over a long period of time. For performance reasons, Oracle may
not populate these views until a few hours after the actual
modifications occurred.
March 09, 2001 Wayne -- Thanks for the question regarding "Use of Rollback during the recovery phase", version 8i
You Asked
Tom,

  You had several different articles that I am pulling different
inferences from as I pose this question:

  You mentioned that the Rollback Segments Must be backed up ...
is that true in 8i as well?
(1)  I was under the impression that any rollback segments that
are missing during recovery would be re-created using the redo
log's undo vectors ...
(2)  I was also under the impression that the undo vectors in
both the Rollback and Redo blocks' are essentially the same
change vectors, do I have that correct?

Thanks

Wayne
and we said...
Yes, rollback must be backed up.

1) it will be recovered HOWEVER it needs a base to start with.
Consider this statement:

"data segments that are missing during recovery would be
re-created using the redo log's data vectors"

they will be HOWEVER the data that should have been in there
from the beginning is now missing.

If you do not backup rollback, you need to keep your archives
infinitely long.  If there is a long running transaction, you
have to go back arbitrarily far into the past to recover all of
the undo for it.

2) No they are not.  Rollback is just another segment.  It is
protected by redo so we can recover it.  It is treated very much
like a data segment.  We need something to "start with" in order
to roll it forward.  Rollback is checkpointed to disk
March 10, 2001 Alex -- Thanks for the question regarding "passing array from java to oracle", version 8i
You Asked
I don't know how to create pl/sql function which will accept
array as input parameter from java code.

Could you help me to create.

Thanks!

Alex.
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::NO::F4950_P8_DISPLAYID:712625135727
...
March 10, 2001 Patibandla -- Thanks for the question regarding "Read/Write to the database - Reg", version 8.1.6.0
You Asked
From one particular session is it possible to read and write
simultaneously. If so how?

Suppose I have table t1 normally i say

1. select * from t1
2. Update t1 set col1=value

After executing 1st Statement it is executing the second
statement.

In yr reply to snapshot too error old u said that this is one of

reason for the error.
quote

'1. Session 1 starts query at time T1 and QENV 50

    2. Session 1 selects block B1 during this query

    3. Session 1 updates the block at SCN 51

    4. Session 1 does some other work that generates rollback
information.

    5. Session 1 commits the changes made in steps '3' and '4'.
       (Now other transactions are free to overwrite this
rollback information)

    6. Session 1 revisits the same block B1 (perhaps for a
different row).

unquote

Pl clarify.
and we said...
Well, technically speaking your UPDATE is reading and writing.

You can code:

declare
   some_variable   t1.col2%type;
begin
   update t1 set col1 = value where returning col2 into
some_variable;
end;

to read and write a row in one call.  Is that what you mean?

for the snapshot too old -- consider this:

   for x in ( select * from t where x > 50 )
   loop
        update t set c1 = c1 * 2 where t.pk = x.pk;
        commit;
   end loop;

Ok, so this is session1 (and the only session we really need).
It is reading table T through an index on X in this case.  Lets
say on block b1 we have the rows:

   x = 50
   x = 5,000,000

Now, on other blocks there are many other values for x between
50 and 5,000,000.  At QENV 50 (the beginning of the loop -- the
first iteration) our session reads block b1 because the index on
x told it to.  It gets the row x=50.  Session 1 updates that
block setting c1 to c1*2.  It commits that change. The ROLLBACK
it just generated is now allowed to be overwritten.

We continue processing the for loop.  We do many hundreds of
updates.  We OVERWRITE the rollback for B1 we just generated in
the first iteration of the loop.  The index finally tells us to
read block B1 again to get x = 5,000,000.  We need to perform a
consistent read of that block -- we need to read it as it
existed when our QUERY began (for the queries purposes).  Only
now we cannot because we can nolonger reconstruct the block as
it appeared at the beginning of our cursor for loop -- that
rollback is gone.  You will get the ORA-1555 right then and
there.
Review & Followup
Rating: 5
ORA-1555 March 13, 2001
Reviewer: B.N.Sarma from USA
Excellent Tom.

Rating: 5
Read/Write to the database - Reg February 22, 2002
Reviewer: Venkat from India
It was really very very...very useful info.

March 10, 2001 Patibandla -- Thanks for the question regarding "overhead due to data security - reg.", version 8.1.6.0
You Asked
1. Normally what is the approximate overhead
   due

   1. archive log mode
   2. maintaining of Standby Database
   3. Data Replication.

   In an intranet Application/Internet Application.
   Assuming all the paramteters are optimised.

2. For example a single statement say
   update table set column=value  is updating 20000 records.
   in 2 seconds. then what would be approximate if are running
   the databe in following modes.

   1. archive log mode
   2. maintaining of Standby Database
   3. Data Replication.
and we said...
1.1 none, overhead is something that can be avoided.  Archive
log mode is crucial for all production systems -- hence it is
not "overhead" (but I'm being technical with terms).

The additional resources you need will be related to disk IO.
ARCH will be reading and writing the logs -- you need to ensure
that ARCH and LGWR do not contend with each other.  In the
perfect world, you would have 5 devices dedicated to logging.  I
would have four 2-4 gig drives (disk1-4) and then a big disk
(disk5).

I would have my first redo log group have its members on disk1
and disk3.  The second redo log group has members on 2 and 4.
the third on 1 and 3, the fourth on 2 and 4 (and so on).  Now,
LGWR will write to disk 1 and 3.  When those logs fill up, LGWR
will switch to 2 and 4.  ARCH will now read 1 and 3 and write to
5.  When LGWR fills up 2 and 4, it will stop writing those disks
and start writing 1 & 3.  ARCH will read 2 and 4 and write 5.
At no point in time does ARCH contend with LGWR and vice versa.

1.2 No overhead.  the standby is one another machine by
definition.  The logs must be generated and archived anyway so
this is a true "freebie".

1.3 Probably at least 20% or so.  Updates are most affected as
we queue the before and after images.  Inserts and deletes are
sort of the same -- we save either the before or after image.
Replication adds the most overhead.

2.1 same speed.  ARCH does not affect your processing speed.
Just make sure ARCH is tuned so that the IO completes as fast as
it can and it does not contend with LGWR.

2.2 same speed.

2.3 slower.  Cannot guess, it will generate more data to be
saved, it will generate more rollback, more redo and more dirty
buffers.

The one option you are missing is OPS.  see
http://www.oracle.com/oramag/oracle/00-May/index.html?o30tom.html
for more details and a little more background information on the
above.
March 10, 2001 Patibandla -- Thanks for the question regarding "Usage of Bind Variables - Reg.", version 8.1.6.0
You Asked
1. In reply to one of the questions u said that 90% time is
spent on
   parsing if bind variables are not used.

2.  Is it the same in the case sql statements executed at sql
prompt
    as in the case of execute immediate statement in pl/sql.

3.  It is same in the case of  dynamic cursors/select into/bulk
collect into.

Regards
Koshal
and we said...
1) that is true

2) yes it is.  When using SQLPlus to interactively query the
database, there is little you can do however.  You can:

alter session set cursor_sharing = force;

and Oracle will "auto bind" the sql for you.

3) this is an issue with DYNAMIC sql in PLSQL only.  All static
sql in plsql uses bind variables.  When you code:

declare
   x number default 5;
begin
   select * from t where col = x;
end;

PLSQL is really executing:

select * from t where col = :bv;

and it binds the value of x in at runtime.  It is when you code
something like:

declare
   type rc is ref cursor;
   l_cursor   rc;
   x          number := 5;
begin
   open l_cursor for 'select * from t where col = ' || x;
end;

that you need to worry about in PLSQL.  You need to code that
as:

  open l_cursor for 'select * from t where col = :x' USING x;

instead.
March 10, 2001 Lynn -- Thanks for the question regarding "Backups & RMAN", version 8.1.5
You Asked
We have a 24/7 system running on NT4 and the size of our
database is around 50GB; running in ARCHIVELOG mode.

I am a bit confused about how to co-ordinate backups using hot
backup and RMAN together.

We plan to take a full database backup once a week. During the
week we want to take incremental backups using RMAN.

Say on Sunday, I take a full backup using OS commands. During
the week, how do I get RMAN to backup only changed blocks? Will
it automatically do it even if I didn't use RMAN to do the
baseline backup?

Thanks & regards
Lynn
and we said...
You must use RMAN in both cases.  The incremental needs to know
about the status of the last backup (the date time of each file
and such).  Only if rman manages it all will this work.
March 10, 2001 -- Thanks for the question regarding "oracle server with webtogo", version 8.1.6
You Asked
Hi,
I am using oracle database server and webtogo in my project
I am using webtogo for the online/offline feature which it
offers.
is it possible that when the user goes offline taking some
records from the server table,
those records should get locked, and they should remain locked
until the user
comes back online.
is there any feature in oracle like this.
to be very brief:
there is a readonly type of snapshot where you can update on the
server but not on the client.
in this case i want something reverse of this, you can update at
the client but those particular
records should be locked at the master site until he does a
synchronisation.
how can i implement this feature.
please give some suggestion..
also if there is any other record locking feature in oracle
please give me a hint..
regards
and we said...
There are no locks that survive across sessions and that is what
you want (but you don't really, it would be really messy).

What you would do in this case is very much like the "dynamic
site ownership" implementation we use in replication.  Using
this, only one site at a time can modify data -- to avoid update
conflicts.

You would model into the application a column that signifies who
currently owns the data.  Only that user or site (depending on
what you decided to put in there) could update it.  If the value
was set to PUBLIC, anyone could (that would be the value when
the data was not "checked out").  When the value is SCOTT --
then only scott can modify it and scott has it copied to his
machine and has detached from the network.

A trigger on the table would enforce this business rule you
have.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76959/repadv.htm#1767
for more details on this concept.  That is the replication guide
but the concepts apply totally to what you are doing.
Review & Followup
Rating: 4
thankyou March 15, 2001
Reviewer: A reader from frankfurt
thankyou

March 10, 2001 Alex -- Thanks for the question regarding "export / import", version 8i
You Asked
I had exported a table from oracle 8i version 8.17.
I then tried to import the table into oracle 8i version 8.16.

I recieved an error message imp 00069

Please help.  Do I need to the same version #?

HELP
and we said...
You must use the 8.1.6 exp against 8.1.7 in order to create an
DMP file that can be imported into 8.1.6 using the 8.1.6 IMP.

It is like a word processor and backwards compatibility.  If you
create the dmp file with 8.1.6 exp, then 8.1.6 imp can read it.
If you create the dmp file with 8.1.7 exp, then the 8.1.6 imp
won't be able to read it.

Use Net8 and let the 8.1.6 exp do the extraction (or more
simply, use the SQLPLUS copy command to copy data and tables
from database to database without creating an intermediate flat
file)
Review & Followup
Rating: 5
February 24, 2003
Reviewer: Alex D. from Toronto, ON Canada

Rating: 4
December 18, 2003
Reviewer: Mikael Wallberg from SWEDEN

March 10, 2001 Jin -- Thanks for the question regarding "performance tuning", version oracle8i
You Asked
I have two tables to perform the join.

table1(col1 integer, col2 integer, col3 integer) the primary key
is col1 and an index is built on col1. The size of table1 is
around 5,000 rows. The values of col1 and col2 are unique. There
are repeated values in col3.

table2(col1 integer, c2 varchar2(32), c3 varchar2(32), c4
varchar2(32), ... , c971 varchar2(32)) the primary key is col1
and an index is created on col1. There are 972 columns. The size
of table2 is around 350,000 rows.

The SQL statement is:
SELECT a.col2, b.c2, b.c3, b.c4, ... , b.c971
FROM table1 a, table2 b
WHERE a.col1=b.col1 and a.col3=12345

When I execute the SQL statement, the execution time is quite
slow, say around 180 seconds. I don't know whether my SQL
statement has any problem. What kind of join is the fast one in
this case? Do I need rebuild the indexes? Would you give me some
advice? Thanks a lot.
and we said...
You need to set autotrace on in sqlplus and see what the plan
is.  See
http://osi.oracle.com/~tkyte/article1/autotrace.html
for how to enable that if you don't know already.

If I had to guess -- the tables are not analyzed and we are
using the rule based optimizer.  It is driving the query then
using table2 b and the plan will be:

step 1: FULL SCAN TABLE2 (350,000 rows)
step 2: apply the predicate "where a.col3 = 12345"
step 3: if the prediate was satisfied, search the index on
table1
step 4: table access table1 by rowid

Full scanning table2 is going to be very slow, ESPECIALLY since
is has so many columns (bad design?).  That row will be stored
in 4 row pieces so it will take about 4 logical IO's to
construct each row.  a big multi-block-read-count won't even
help you there.

Suggestions:

o is it possible to index col3?  is it selective enough?
o is the design of 972 columns in a table a really good idea?
is there a better structure you could use?
March 11, 2001 Rod -- Thanks for the question regarding "Database design", version 8.3
You Asked
Could you please advise me where I can find an example of what
an Oracle database looks like.
I am a Pick/Universe person so I am aware of relational
databases, but how does an Oracle compare, or is it similar.
Many thanks.
and we said...
The document you are looking for is the Oracle8i server concepts
guide:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/toc.htm

it goes through all of this.
March 11, 2001 Yanxin -- Thanks for the question regarding "How to call a remote stored procedure from pro*c, and how to compile the pro*c program?", version 7.3.4
You Asked
How to call a remote stored procedure from pro*c, and how to
compile the pro*c program?

Thanks in advance!
and we said...
You just need to create a database link (see the create database
link syntax in your SQL reference).  Then in pro*c you just:

  exec sql execute
  begin
     procedure@database_link( :x, :y, :z );
  end;
  end-exec;

You do not need to compile the program any differently then
normal using this. See
http://osi.oracle.com/~tkyte/proc_makefile/
for a generic makefile I use with pro*c on Unix to precompile
and compile my programs.
March 11, 2001 Mohammed -- Thanks for the question regarding "Securty", version 8i
You Asked
Dear MR.Tom

Thanks for answering question .

Well I am programmer one day I create a user and create project table in that
user .But I forget  the password  I go to system/manger and I write this SQL
statement

SQL> select * from dba_users;

USERNAME                         USER_ID PASSWORD
ACCOUNT_STATUS
------------------------------ --------- ------------------------------
----------------
SYS                                    0       D4C5016086B2DC6A
OPEN
SYSTEM                           5       D4DF7931AB130E37                OPEN

PO8                                   23     7E15FBACA7CDEBEC              OPEN

DEMO                              21     4646116A123897CF
OPEN
DBSNMP                         19     E066D214D5421CCC                  OPEN

SCOTT                             20     F894844C34402B67
OPEN
TT                                    25     294CE6E7131DD890
OPEN
STUDENT                       31    7E4CDDF247985063                     OPEN

I tried to login to the lost password by using Password above but I couldn’t  I
tried many time but with no response .So I delete that user and create my
database again

My Question Is Are there any solution if A DBA or Authorized Person forget the
Password to login to his database user ?
and we said...
A DBA or anyone with the ALTER USER privilege can issue:

alter user USERNAME identified by NEW_PASSWORD;
Review & Followup
Rating: 3
March 11, 2001
Reviewer: A reader

March 11, 2001 Navdeep -- Thanks for the question regarding "email from database", version 8.0.4
You Asked
hi tom
   is there any way by which i can send emails directly from
oracle applications developed in D2k. if yes then suppose i dont
have net connection but send and receive mails through microsoft
outlook or lotus cc-mail. then how can i send mails through
these applications.
thanx
Navdeep
and we said...
Well, your subject and your body don't say the same thing.

the subject is "email from the database", the body is "email
from d2k".

for email from d2k, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::NO::F4950_P8_DISPLAYID:319216860351
for email from the database, in 8.0 as you have -- you would
need to write a C external procedure to interface with the OS
or, if you have a webserver setup, you can use UTL_HTTP from
PLSQL to run a cgi-bin program that does email for you.  That
is, if you setup a URL so that:

http: //host/cgi-bin/mail?to=x@y&body=hello+world

would send an email to x@y with a body of "hello world", plsql
can call that as well from a stored procedure.
March 11, 2001 Alex -- Thanks for the question regarding "how to use sql plus copy command", version oracle 8i
You Asked
You Asked

I had exported a table from oracle 8i version 8.17.
I then tried to import the table into oracle 8i version 8.16.

I recieved an error message imp 00069

Please help.  Do I need to the same version #?

HELP

-----------------------------------------------------------------
---------------
and we said...

You must use the 8.1.6 exp against 8.1.7 in order to create an
DMP file that can be imported into 8.1.6 using the 8.1.6 IMP.

It is like a word processor and backwards compatibility.  If you

create the dmp file with 8.1.6 exp, then 8.1.6 imp can read it.

If you create the dmp file with 8.1.7 exp, then the 8.1.6 imp
won't be able to read it.

Use Net8 and let the 8.1.6 exp do the extraction (or more
simply, use the SQLPLUS copy command to copy data and tables
from database to database without creating an intermediate flat
file)

Was this response helpful to you? Let us know!

Can you please give me an example how to use the sql plus
command to copy data and table to another remotely??

Thank you

Alex
and we said...
Sure, I have a quick example at:
http://osi.oracle.com/~tkyte/Misc/MoveLongs.html
but for all of the details see:
http://technet.oracle.com/doc/oracle8i_816/sqlplus.816/a75664/ch63.htm#1003261
it has quite a few examples as well.
March 11, 2001 David -- Thanks for the question regarding "query", version 8.1.6
You Asked
Hi, Tom,

I have two tables and when I join them I would get something
like

Column A---Column B
New York----David
New York----John
New York----Alex
Atlanta-------Chris
Florida-------Phil
L.A-----------David
L.A-----------Jenny
L.A-----------Boris
L.A-----------Joseph
Miami--------Alex
Miami--------Will

Now I want the query to return just a limited rows using rownum,
for example

where rownum <= 3

However this would return

Column A---Column B
New York----David
New York----John
New York----Alex

ONLY

But I need all results of first column <= 3, what i am saying is
that I need the query to return me

Column A---Column B
New York----David----1
New York----John----1
New York----Alex----1
Atlanta-------Chris----2
Florida-------Phil----3
L.A------Johnes----4
L.A------Mark----4
L.A------Jim----4
.....

where column A has 3 values

I have seek a few ways but cant do it!!!

Thanks,
Dave
and we said...
select *
  from ta, tb
 where <join conditions>
   and ta.columna in ( select columna
                         from ta
                        where rownum <= 3 );

The trick will be to generate the set of three locations you
want.  Alternatively, you could use the analytic functions in
8.1.6 if you are using personal or EE:

scott@DEV816> select ename, loc, dense_rank() over ( order by
loc ) r
  2    from emp, dept
  3   where emp.deptno = dept.deptno
  4  /

ENAME      LOC                    R
---------- ------------- ----------
allen      CHICAGO                1
blake      CHICAGO                1
martin     CHICAGO                1
james      CHICAGO                1
ward       CHICAGO                1
turner     CHICAGO                1
smith      DALLAS                 2
adams      DALLAS                 2
scott      DALLAS                 2
ford       DALLAS                 2
jones      DALLAS                 2
clark      NEW YORK               3
king       NEW YORK               3
miller     NEW YORK               3

14 rows selected.

scott@DEV816> select *
  2    from ( select ename, loc, dense_rank() over ( order by
loc ) r
  3             from emp, dept
  4            where emp.deptno = dept.deptno
  5             )
  6   where r <= 2
  7  /

ENAME      LOC                    R
---------- ------------- ----------
allen      CHICAGO                1
blake      CHICAGO                1
martin     CHICAGO                1
james      CHICAGO                1
ward       CHICAGO                1
turner     CHICAGO                1
smith      DALLAS                 2
adams      DALLAS                 2
scott      DALLAS                 2
ford       DALLAS                 2
jones      DALLAS                 2

11 rows selected.
Review & Followup
Rating: 4
Very efficient March 12, 2001
Reviewer: Alan from OKC

March 11, 2001 anand -- Thanks for the question regarding "Database user Passwords", version 8.1
You Asked
Hi tom,
I would like to know where the user passwords are stored in
oracle database and how can we crack them.
bye.
Anand
and we said...
the DIGEST of a password is stored in the DBA_USERS view, it is
not reversible.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:124012348063
i do not know how to "crack" them short of a brute force attack
of trying every password you can think of.


Subject | Article | Last Updated (East coast time)
About Oracle Parallel Server | article only | Mar 12, 2001 01:35 am
Question on Data Link ! | article only | Mar 12, 2001 04:08 am
Forms In Developer & Items Property Function | article only | Mar 12, 2001 04:08 am
Historical Growth of Objects | article only | Mar 12, 2001 04:44 am
Index scan vs table scan | article only | Mar 12, 2001 05:14 am
Personal Oracle Vs Oracle Enterprise Edition | article only | Mar 12, 2001 05:16 am
iif | article only | Mar 12, 2001 05:59 am
image into Database,multilingual support | article only | Mar 12, 2001 06:27 am
Exporting Conditional Data | article only | Mar 12, 2001 06:39 am
Nested Table | article only | Mar 12, 2001 06:48 am
How to print dynamic SQL where SELECT, FROM and WHERE is dynamic | article only | Mar 12, 2001 07:09 am
Creating Dynamic Partitions | article only | Mar 13, 2001 09:20 am
Determine when an ORA-4068 will happen | article only | Mar 13, 2001 09:32 am
Continue Query | article only | Mar 13, 2001 09:46 am
When should the log switch occur? | article only | Mar 13, 2001 10:05 am
How can I concatenate fields/values using SQL *Loader? | article only | Mar 13, 2001 10:14 am
Row Chaining | article only | Mar 13, 2001 10:39 am
Clear question | article only | Mar 13, 2001 06:12 pm
SQLJ or JDBC | article only | Mar 13, 2001 07:20 pm
alter database check datafiles | article only | Mar 13, 2001 07:32 pm
FAX PURCHASE ORDERS | article only | Mar 14, 2001 03:06 pm
Tunning(SGA info) | article only | Mar 14, 2001 03:17 pm
Import to locally managed tablespace | article only | Mar 14, 2001 03:38 pm
Migration | article only | Mar 14, 2001 04:36 pm
Trigger and sqlloader | article only | Mar 14, 2001 04:45 pm
Authentication in OAS | article only | Mar 14, 2001 05:54 pm
The opposite of SQL*Loader | article only | Mar 14, 2001 07:02 pm
active transaction | article only | Mar 15, 2001 11:00 am
How to do bulk collect in Pro*C variables | article only | Mar 15, 2001 11:12 am
Select Question | article only | Mar 15, 2001 11:29 am
Replication FK constraints & indexes, UK constraints & indexes | article only | Mar 15, 2001 11:40 am
problem with rowid and chained rows | article only | Mar 15, 2001 12:08 pm
Data Encryption | article only | Mar 15, 2001 12:59 pm
convert numeric values in word | article only | Mar 16, 2001 08:53 am
Select Help | article only | Mar 16, 2001 09:17 am
Passing of text parameters from one frame to other frames in HTML | article only | Mar 16, 2001 09:59 am
Does Oracle have ODBC on Sun Nuix system? | article only | Mar 16, 2001 10:05 am
Oracle 7.3 on Windows 2000 | article only | Mar 16, 2001 08:09 pm
enable novalidate primary key | article only | Mar 16, 2001 09:00 pm
table partition/how to export it | article only | Mar 16, 2001 09:17 pm
Finding Invalid session | article only | Mar 16, 2001 09:28 pm
Query Optimization | article only | Mar 16, 2001 10:19 pm
Update rows from Table1 to Table2 depending upload flag field value of Table1 | article only | Mar 17, 2001 01:16 am
applicationwise tables space / database creation | article only | Mar 17, 2001 04:02 am
imp oracle 8.1.6 data into oralce 8. | article only | Mar 17, 2001 04:07 am
nvl2() -- CASE | article only | Mar 17, 2001 04:08 am
How to make the duplicate database in another server or notebook? | article only | Mar 17, 2001 04:35 am
How to handle row id's in a materialized view | article only | Mar 17, 2001 06:46 am
Password | article only | Mar 17, 2001 07:06 am
Is the connection to DB2 is possible using PL/SQL ? | article only | Mar 17, 2001 07:22 am
Run some procedures during database startup | article only | Mar 18, 2001 02:01 am
How to insert image file in database table | article only | Mar 18, 2001 05:33 am
Is Developer is going to be obsolute?? | article only | Mar 18, 2001 08:07 am
NO_DATA_FOUND when querying SESSION_ROLES inside a function!! | article only | Mar 18, 2001 08:58 am
Transportable Tablespace: Are packages in target made invalid? | article only | Mar 18, 2001 09:13 pm
row(s) 1 - 55 of 55
March 12, 2001 Ankur -- Thanks for the question regarding "About Oracle Parallel Server", version 8.0.5.0.0
You Asked
Can I Implement Oracle Parallel Server using two different
Oracle DB Instances of Different Versions ?
Like
Oracle DB of Version 8.0.5
Oracle DB instance of 8.1.5
Using shared nothing configuration
If yes please provide enough details of How to do this
and we said...
No you cannot.

OPS is a shared EVERYTHING architecture.  The instances will be
homogenous with regards to version.

See
http://technet.oracle.com/doc/oracle8i_816/paraserv.816/a76968/toc.htm
for an overview of OPS.

If you want a shared NOTHING configuration, you are just talking
about a distributed data.  We can do that with 8.0 and 8.1.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76960/toc.htm
...
Review & Followup
Rating: 2
Oracle Parallel Server Implementation March 13, 2001
Reviewer: Ankur Bhargava from India
Oracle Parallel Server I think could be implementation not only by shared
Everything Config. but also by memory sharing etc. and even shared nothing arch.

March 12, 2001 OP -- Thanks for the question regarding "Question on Data Link !", version 8.1.6.0
You Asked
Dear Tom,

Hi !

How are you Doing !

Today my Quest to you is as follows

Scenario
========

We have 2 database servers at our site S1 and S2 with
2 database D1 and D2 installed on them.

I want to write a join from table t1 in D1 and table t2
in D2.

Is it possible to make a join across the database i.e
between tables lying on different database.Is there
anything data link which I need to create.

Questions

Q1) What is database Link ?

Q2) How is it created ?

Q3) What privilege is required to create this ?

Q4) ON what server it should be created Is there any
specification ?

Q5) How it can be used after successful creation ?

Kindly help.

Thanks and Regards
OP Lalwani
and we said...
You just need to create a database link.

A database link is how you tell one Oracle database to log into
another.  Lets say you wanted to access the database "d2" from
"d1", you might issue:

create database link d1
connect to scott
identified by tiger
using 'd1';

Now you can "select * from t, t@d1 t2 where t.x = t2.x"  and the
data will be joined for you.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/ch4f5.htm#12782
for all of the details -- what it is, how to create, privs
required and so on.
March 12, 2001 Mohammed -- Thanks for the question regarding "Forms In Developer & Items Property Function", version 6.0
You Asked
Dear Mr.Tom

Good Morning .

Well I have two Question .

1-
  Some of my friend accomplished   a project using Developer and he  is using
about 50 Forms *. Fmb .
My question here is about Performance ,What if he compress his 50 forms to 5 or
10 forms by separating other Forms in Blocks and canvases  in the 5 or 10
forms(Moudles).

My Question again which is better to have many forms or one Form contains many
blocks instead of  many forms ?

2-
 When I am using the function set_item_property(it_id , property , Property_true
OR property_false)

I use instead of Property TRUE Or  FALSE  a string of  varchar2(20) and I call
this function by Procedure .But it does not work I have this Error FRM-41046
:invalid Parameter used for ste_item_property .

The calling  Procedure  is  :

       Enabling_disenabling_item('false');

The Procedure is:

PROCEDURE Enabling_disenabling_item(state in varchar2 )IS

  it_id1 item;
    it_id2 item;
    it_id3 item;
    it_id4 item;
    it_id5 item;
  it_id6 item;
  enabled_value varchar2(20);

  x number;

BEGIN
    If state = 'true' then
      enabled_value := 'property_true';
    else
        enabled_value := 'property_FALSE';
    end if;

    it_id1 := find_item('toolbar.delete_record');
    set_item_property(it_id1,ENABLED,enabled_value);

    it_id2 :=find_item('toolbar.previous_block');
    set_item_property(it_id2,ENABLED,enabled_value);

    it_id3 := find_item('toolbar.previous_record');
    set_item_property(it_id3,Enabled,enabled_value);

    it_id4:=find_item('toolbar.Next_Block');
    set_item_property(it_id4,Enabled,enabled_value);

  it_id5 :=find_item('toolbar.next_record');
    set_item_property(it_id5,enabled,enabled_value);

    it_id6 :=find_item('toolbar.insert_record');
    set_item_property(it_id6,enabled,enabled_value);
end;

My Question Is How can  I use this function  :
set_item_property(it_id , property , Property_true OR property_false)
to accept  string value as my procedure above work ?

                                                     Best wishes,
and we said...
1) from a performance perspective, there should be no difference once the form
is opened.  It will of course take longer to do a call_form or open_form then to
just display a canvas in one large form.

there is the trade off between being able to modularize your code and manage
small chunks and the initial hit your end user will take doing the open form.  I
myself would probably prefer many forms over one monolithic one.

2) the property_true/false are NUMBERS not strings.

declare
   ...
   enabled_value NUMBER;
begin
    If state = 'true' then
      enabled_value := property_true;
    else
        enabled_value := property_FALSE;
    end if;
    .....
Review & Followup
Rating: 4
when ever you want answer just ask Mr TOM March 12, 2001
Reviewer: Mohammed Al-moayed from Yemen
Well I think that Mr tom is ding his best for answering the
Question for all individuals in the world, and the answers are Very good and
confident, and I really thank him and all his coworkers.

Rating: 4
Review in Forms In Developer & Items Property Function March 12, 2001
Reviewer: Mohammed Al-moayed from Yemen
Well I think that Mr tom is ding his best for answering the
Question for all individuals in the world, and the answers are Very good and
confident, and I really thank him and all his coworkers.

March 12, 2001 Alison -- Thanks for the question regarding "Historical Growth of Objects", version Oracle 7.3
You Asked
Hi there,

I am running the following script to give me information about
the size and growth of objects..

All data is pulled from the data_dictionary except check_date
which is sysdate..

insert into APRODBSEC
( TS , Seg_Owner , Seg_Name , Seg_Type , bytes , Blocks ,
Extents
next_extent , max_extents , Check_Date)
select
d.Tablespace_Name, d.Owner, d.Segment_Name, d.Segment_Type,
d.bytes, d.blocks, d.Extents, d.next_extent, d.max_extents,
TRUNC(SysDate)
from DBA_SEGMENTS@APRODBSEC.world D
where Owner = UPPER('schema_owner')

DBA_SEGMENTS@APRODBSEC.WORLD is a database link I have set up to
another database on another server (this all works fine)

I am looking to pull information from this table which will give
me information of the growth of the objects.

I have a script which works using a decode function
select
TS,
Seg_Owner,
Seg_Name,
Seg_Type,
MAX_EXTENTS,
MAX(DECODE(Check_Date, TRUNC(SysDate-7),
extents,0)) LastWeek,
MAX(DECODE(Check_Date, TRUNC(SysDate),
extents,0)) Today,
MAX(DECODE(Check_Date, TRUNC(SysDate-7),
extents,0)) Change
from APRODBSEC
group by
TS,
Seg_Owner,
Seg_Name,
Seg_Type,
MAX_EXTENTS;

The problem with this is that if the script is ran on a
different day than the data is inserted I get no output

This means for instance if the data was inserted into the table
on 27-FEB-01 and the script was run on 01-MAR-01 the DECODE part
show up with a 0.

I am looking for help in adapting this scrip so that it works no
matter what day it's ran..

I was thinking of something using
CHECK_DATE-(MAX(CHECK_DATE)-TRUNC(SYSDATE))
but I can't get it to work

A solution in pure SQL is prefered, I am very unsure about PLSQL
and would rather not use it at the moment.

Many thanks for any help

Alison
and we said...
I believe that:

select TS, Seg_Owner, Seg_Name, Seg_Type, MAX_EXTENTS,
       lastweek, today, today-lastweek change
  from ( select TS, Seg_Owner, Seg_Name, Seg_Type, MAX_EXTENTS,
              MAX(DECODE( trunc(sysdate)-Check_Date,
                        7, extents, 8, extents, 9, extents, 10,
extents,
                        11, extents, 12, extents, 13, extents,
NULL)) LastWeek,
              MAX(DECODE( trunc(sysdate)-Check_Date,
                        0, extents, 1, extents, 2, extents, 3,
extents,
                        4, extents, 5, extents, 6, extents,
NULL)) Today
         from APRODBSEC
        group by TS, Seg_Owner, Seg_Name, Seg_Type, MAX_EXTENTS
)
/

will get you what you want.

We know that "lastweek" was between 7 and 13 days ago -- this
week was between 0 and 6 days ago.  We pick off those values and
return them.  If there are multiple entries in the week, we take
the "largest" one and return it.
Review & Followup
Rating: 5
March 12, 2001
Reviewer: Alison from Scotland (Glasgow)

Rating: 5
January 21, 2003
Reviewer: Lynn from Middle East

March 12, 2001 Michel -- Thanks for the question regarding "Index scan vs table scan", version 7.3.4
You Asked
Hi Tom,

I have a question concerning the use of an index scan and the
time I may save using it.

I work on an Oracle database, version 7.3.4. The parameter
V733_PLANS_ENABLED is set to YES. The OPTIMIZER_MODE is set to
CHOOSE but there is no statistics available for any table so I
assume the optimizer will work in static mode.

I have a table T made of :
Name                            Null?            Type
 ------------------------------- -------------------------------
 C1                                NOT NULL VARCHAR2(20)
 C2                                NOT NULL VARCHAR2(8)
 C3                                NOT NULL VARCHAR2(15)
 C4                                NOT NULL NUMBER(9,2)
 C5                                NOT NULL NUMBER(9,2)
 C6                                NOT NULL NUMBER(9,2)
I have a unique index I1 containing C1, C2, C3.

Table T is very large (30 000 000 lines) and I wanted to use a
fast full scan on the index I1 for a SELECT and a DELETE
transaction. These two transactions have a simple WHERE clause
in which the condition is on C3 (C3 = something or C3 <
something). The SELECT transaction returns all the columns of T.

Here are the results for the execution plan of several
transactions :

SELECT C1, C2, C3, C4, C5, C6 FROM T1 WHERE C3 = string
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (FULL) OF 'T'

SELECT /*+ INDEX_FFS(T I1)*/ C1, C2, C3, C4, C5, C6 FROM T1
WHERE C3 = string
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=27 …
   1    0   TABLE ACCESS (BY ROWID) OF 'T' (Cost=27 …
   2    1     INDEX (FULL SCAN) OF 'I1' (UNIQUE)

The results are the same for the DELETE transactions save that
the root statement was DELETE and that the cost was 26 rather
than 27.

After searching into your full list of questions, I assume that
it is probably normal that I obtain an index full scan rather
than a Fast Full Scan since C3 is not the first column of the
index (cf. question Ratnaprabha, Monday May 15, 2000 ).

Am I correct assuming this ?

I wonder if a full index scan followed by a table acces by rowid
will be really faster than a simple table full scan even on a
very large table, the index being definitely smaller than the
table. I don’t have a definitive idea concerning the percentage
of the table’s rows that can be selected/deleted by these
transactions. I would say  it will be definitely less than 10 %
and probably around 5%.

Is there a way to estimate the effectiveness of the index full
scan vs the table full scan other than testing it on the base ?

All the best,
and we said...
The INDEX (FULL SCAN) is the ffs.  You are getting exactly what
you asked for.

A FAST FULL SCAN is simply a full scan of the index, we'll use
multi-block IO to read every block in the index.

As for the question:

"I wonder if a full index scan followed by a table acces by
rowid
will be really faster than a simple table full scan even on a
very large table"

the answer is "it depends".  Lets say the predicate "c3=string"
returns a large percentage of the table.  Say 50% of the table
is returned by that.  You'll end up doing all of the IO to read
the index plus 15million scattered IOs to read the rows in the
table.  That'll probably be slower then full scanning the table
using multi-block io.  It'll tend to blow out the buffer cache
as well.

On the other hand, lets say that returns 1% of the rows.  You'll
end up doing 300,000 scattered reads of the table.  If the index
is much smaller then the table, the overhead of full scanning
the index + 300k scattered reads may very well be less then the
overhead of full scanning the table.

So, like everything with regards to an index, it depends on the
amount of data that will be returned.
Review & Followup
Rating: 4
Fast full index March 12, 2001
Reviewer: Michel A. Bonade Bottino from Paris, FRANCE
The answer describes the output of EXPLAIN PLAN referring to a fast full index
scan. It provides an interesting discussion about the effectiveness of index
fast full scan vs table full scan.

On the overall, this answer is usefull when considering using the INDEX_FFS
hint.

March 12, 2001 KANUMURI -- Thanks for the question regarding "Personal Oracle Vs Oracle Enterprise Edition", version 8i
You Asked
Hi Tom,

Could you tell me , What are diff. between Personal Oracle and enterprise
edition of oracle in database point of you.(Other than parallel server.

Thanks&Regards
Kvs Raju
and we said...
This chapter in the getting to know oracle8i document explains that in great
detail:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76962/ch4.htm#73594
....
Review & Followup
Rating: 4
Thanks you March 12, 2001
Reviewer: KVS Raju from Finland
Thank you for your help

March 12, 2001 Sajjad -- Thanks for the question regarding "iif", version 8
You Asked
is there any equivalent of iif statement as provided by MS access.
Decode doesnot fullfil all requirements of the iif i.e. > and < checks
and we said...
You were not very specific in your version -- you only mention "8".

In Oracle8i release 8.1.6 and up there is the ANSI SQL case statement:

 1  select ( case when sal > 4000 then 'Big'
  2                              else 'Small'
  3               end ), sal
  4* from emp
scott@ORA8I.WORLD> /

(CASE        SAL
----- ----------
Small        800
Small       1600
Small       1250
Small       2975
Small       1250
Small       2850
Small       2450
Small       3000
Big         5000
Small       1500
Small       1100
Small        950
Small       3000
Small       1300
Small          5

15 rows selected.

Before that DECODE using the SIGN function typically worked:

  1  select ( case when sal > 4000 then 'Big'
  2                              else 'Small'
  3               end ), sal,
  4        decode( sign(sal-4000), 1, 'Big', 'Small' )
  5* from emp
scott@ORA8I.WORLD> /

(CASE        SAL DECOD
----- ---------- -----
Small        800 Small
Small       1600 Small
Small       1250 Small
Small       2975 Small
Small       1250 Small
Small       2850 Small
Small       2450 Small
Small       3000 Small
Big         5000 Big
Small       1500 Small
Small       1100 Small
Small        950 Small
Small       3000 Small
Small       1300 Small
Small          5 Small

15 rows selected.

instead of asking "a > b" you ask if the sign(a-b) is positive.  Sign returns
-1, 0 or 1 if a is less then b, equal to b, or greater then b.
March 12, 2001 ravikiran -- Thanks for the question regarding "image into Database,multilingual support", version 8i
You Asked
1.How to insert an image into a database using SQL?what  data
type can be used to store images more efficently?

2.i am doing an application ,which uses Bangla language.how to
store the Bangla data in the database?
and we said...
You would use the BLOB type.  See
http://technet.oracle.com/doc/oracle8i_816/appdev.816/index.htm
for tons of documentation on LOBs in various languages.  You can
also search for:

load blob

on my site.  there are many ways to load a BLOB, one of the
easiest is dbms_lob.loadfromfile (search for loadfromfile on my
site for examples)

As for Bangla language, you would pick a characterset that can
support your data.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76966/toc.htm
for information regarding that.
March 12, 2001 Muhammad Amjad -- Thanks for the question regarding "Exporting Conditional Data", version 8.1.6
You Asked
Q1.

I want exporting data by using Select Statement like
'select * from emp where job like 'K%' ;'

Q2.

How can I align centre to my resulting column in sql* plus.
result looks like as:

Job
----------
   ABC
  DEDET
 DDDEJIF
    D

Waiting for reply

amjad.
and we said...
Use the query= parameter on export, for example:

$ exp userid=scott/tiger tables=emp query=\"where job like
\'K%\'\"

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76955/ch01.htm#37997
for the details on that parameter.

There is no formatting command to center data in a column.  we
can however use lpad() to do this:

scott@ORA8I.WORLD> column ename format a10
scott@ORA8I.WORLD> select
lpad(ename,(10-length(ename))/2+length(ename),' ') ename
  2   from emp
  3  /

ENAME
----------
  SMITH
  ALLEN
   WARD
  JONES
  MARTIN
  BLAKE
  CLARK
  SCOTT
   KING
  TURNER
  ADAMS
  JAMES
   FORD
  MILLER
   KING

15 rows selected.

replace the number 10 with the width of the field as you would
like it to be.
Review & Followup
Rating: 5
Thanks for prompt replay March 13, 2001
Reviewer: Muhammad Amjad Masood from Pakistan
Dear Tom,

I am most thanksfull to you and your team on this quick and prompt reponce that
is most useful for me in futre.

March 12, 2001 Balazs -- Thanks for the question regarding "Nested Table", version 8.1.6
You Asked
Hello Tom,

I have a problem with a nested table. I am looking for the
records of the 'parent' table which includes some special nested
(child) record.
I use this:
SELECT * FROM T1 WHERE 'SPEC' IN (SELECT name FROM
TABLE(T1.var_list))

desc T1:
 Id number,
 value varchar2(10),
 Var_List Nt_Type

desc Nt_Type:
 Name varchar2(10)
 Value Varchar2(10)

This query gives good result but it is very slow.
How can I increase the performance?
Please suggest me how to filter the nested table.
Thanx!

 Ambruzs
and we said...
First, make sure that you have an index on the hidden
NESTED_TABLE_ID column in the nested table -- else joining the
parent to the child is going to be sloooowww.

create index t_idx on nested_table_name( nested_table_id );

Then, consider:

select t1.*
  from t1 t1, table(t1.var_list) t2
 where t2.name = 'SPEC'
/

instead.

OR....

create index t_idx on nested_table_name( name );

and use the same query I just gave you. -- the optimizer will
query the nested table via the index and join back to the parent.
Review & Followup
Rating: 5
March 12, 2001
Reviewer: A reader

March 12, 2001 -- Thanks for the question regarding "How to print dynamic SQL where SELECT, FROM and WHERE is dynamic", version 7.3.4
You Asked
I want to write a procedure which executes my dynamic query. I
want to call this procedure to execute different queries and
print the results (Columns)
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:235814350980
it shows how to dynamically create a flat file from any query
using DBMS_SQL.  Change the UTL_FILE calls to dbms_output and
you have what you need.

See also:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1035431863958
which is another example of the above which uses dbms_output.
It prints query results down the page instead of across.
Review & Followup
Rating: 5
March 13, 2001
Reviewer: A reader

March 13, 2001 Omar -- Thanks for the question regarding "Creating Dynamic Partitions", version 6i
You Asked
Hi Tom
   We have here a payroll system that stores payments in a table
'payment_hist' how could we create partitions to store each year
payment in a certain partition, and how can I dynamically create
ones every new year.

thanks in advance
and we said...
Well, you cannot "dynamically" create them.  You have to do
something to have them created.

You would create a partitioned table.  There would ALWAYS be an
empty partition at the end.

At the end of a year, you would split the empty partition (see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:660224234238
for an example) into a partition for next year and an empty
partition at the end.

Next year, you fill up the newly split partition.  At the end of
that year, you do it all over again.

You could create a JOB using DBMS_JOB that runs sometime in
DECEMBER of each year to do this if you wanted.
March 13, 2001 Jeff -- Thanks for the question regarding "Determine when an ORA-4068 will happen", version 8.1.7.0.0
You Asked
I know that package variables will cause ORA-4068 error messages
when another user tries to re-compile the package body that is
already in use. I know why I am getting these errors, I need to
know how I can detect these errors before the user compiles a
package body.
--
For example, a user creates a package:
session1 > l
1 create or replace package foo
2 is
3 function bar return varchar2;
4* end foo;
session1 > /

Package created.

Then, in the same session, the user creates the package body:
session1 > l
1 create or replace package body foo
2 is
3 v2 varchar2(80);
4 function bar return varchar2
5 is
6 ver varchar2(80);
7 begin
8 v2:='this is a package variable.';
9 ver := v2;
10 return ver;
11 end bar;
12* end foo;
session1 > /

Package body created.

Then the user executes the package:
session1 > set serveroutput on
session1 > exec dbms_output.put_line(foo.bar);
this is a package variable.

PL/SQL procedure successfully completed.

Now another sqlplus session is started in window#2 as the same
user and he executes the package:
session2 > set serveroutput on
session2 > exec dbms_output.put_line(foo.bar);
this is a package variable.

PL/SQL procedure successfully completed.

Now, the user needs to recompile the body of foo. If he
recompiles the package in session1, an ORA-4068 error will be
generated in session2. Before the first session recompiles the
package body, I want to be able to find out if he will generate
an ORA-4068 error for any other users using that package.
and we said...
Run catblock.sql found in $ORACLE_HOME/rdbms/admin when logged
in as SYS using svrmgrl (if you haven't already).

That'll give you a view DBA_DDL_LOCKS.  Now you can:

scott@DEV816> select a.username, b.owner || '.' || b.name
  2  from v$session a, dba_ddl_locks b
  3  where a.sid = b.session_id
  4  and b.type like '%/Procedure/%';

USERNAME                       B.OWNER||'.'||B.NAME
------------------------------
--------------------------------------------
SCOTT                          SYS.DBMS_APPLICATION_INFO
SCOTT                          SYS.DBMS_OUTPUT

Now, if scott starts using other stuff:

scott@DEV816> exec ops$tkyte.print_table( 'select * from dual'
);
DUMMY                         : X
-----------------

PL/SQL procedure successfully completed.

scott@DEV816> /

USERNAME                       B.OWNER||'.'||B.NAME
------------------------------
---------------------------------------------
SCOTT                          OPS$TKYTE.PRINT_TABLE
SCOTT                          SYS.DBMS_SYS_SQL
SCOTT                          SYS.DBMS_SQL
SCOTT                          SYS.DBMS_APPLICATION_INFO
SCOTT                          SYS.DBMS_OUTPUT

I can see that by scott running print_table, which uses DBMS_SQL
which uses DBMS_SYSS_SQL -- scott has breakable parse locks on
all of the above code....
Review & Followup
Rating: 3
Missed reference to modify_package_state July 25, 2003
Reviewer: Martin from Austria
The article is ok, but I missed to give a hint, that for the own session a reset
is possible using dbms_session.modify_package_state(1)

The solution would be, if this procedure could be executed for a foreign session
(i consider this a suggestion for product enhancement), if this would be
possible technically.

have a nice day,
martin

March 13, 2001 Alan -- Thanks for the question regarding "Continue Query", version 8.1.6
You Asked
Hi, Tom,

Quote:
--------------------------------------------
I have two tables and when I join them I would get something
like

Column A---Column B
New York----David
New York----John
New York----Alex
Atlanta-------Chris
Florida-------Phil
L.A-----------David
L.A-----------Jenny
L.A-----------Boris
L.A-----------Joseph
Miami--------Alex
Miami--------Will

Now I want the query to return just a limited rows using rownum,

for example

where rownum <= 3

However this would return

Column A---Column B
New York----David
New York----John
New York----Alex

ONLY

But I need all results of first column <= 3, what i am saying is

that I need the query to return me

Column A---Column B
New York----David----1
New York----John----1
New York----Alex----1
Atlanta-------Chris----2
Florida-------Phil----3
L.A------Johnes----4
L.A------Mark----4
L.A------Jim----4
.....

where column A has 3 values

I have seek a few ways but cant do it!!!

Thanks,
Dave

-----------------------------------------------------------------
---------------
and we said...

select *
  from ta, tb
 where <join conditions>
   and ta.columna in ( select columna
                         from ta
                        where rownum <= 3 );

The trick will be to generate the set of three locations you
want.  Alternatively, you could use the analytic functions in
8.1.6 if you are using personal or EE:

scott@DEV816> select ename, loc, dense_rank() over ( order by
loc ) r
  2    from emp, dept
  3   where emp.deptno = dept.deptno
  4  /

ENAME      LOC                    R
---------- ------------- ----------
allen      CHICAGO                1
blake      CHICAGO                1
martin     CHICAGO                1
james      CHICAGO                1
ward       CHICAGO                1
turner     CHICAGO                1
smith      DALLAS                 2
adams      DALLAS                 2
scott      DALLAS                 2
ford       DALLAS                 2
jones      DALLAS                 2
clark      NEW YORK               3
king       NEW YORK               3
miller     NEW YORK               3

14 rows selected.

scott@DEV816> select *
  2    from ( select ename, loc, dense_rank() over ( order by
loc ) r
  3             from emp, dept
  4            where emp.deptno = dept.deptno
  5             )
  6   where r <= 2
  7  /

ENAME      LOC                    R
---------- ------------- ----------
allen      CHICAGO                1
blake      CHICAGO                1
martin     CHICAGO                1
james      CHICAGO                1
ward       CHICAGO                1
turner     CHICAGO                1
smith      DALLAS                 2
adams      DALLAS                 2
scott      DALLAS                 2
ford       DALLAS                 2
jones      DALLAS                 2

11 rows selected.
---------------------------------------------------------------
Quote end.

What i really want is for each category, i really want to return
only 3 rows based on the same location; and probably less than 3
rows if there isn't enough rows satisfied the condition for each
category .

Thanks,
Alan
and we said...
Ahh, ok, i see now. analytic functions can do this for us.
consider:

scott@DEV816> select ename, loc,
              row_number() over ( partition by loc order by
ename )r
  2    from emp, dept
  3   where emp.deptno = dept.deptno
  4  /

ENAME      LOC                    R
---------- ------------- ----------
allen      CHICAGO                1
blake      CHICAGO                2
james      CHICAGO                3
martin     CHICAGO                4
turner     CHICAGO                5
ward       CHICAGO                6
adams      DALLAS                 1
ford       DALLAS                 2
jones      DALLAS                 3
scott      DALLAS                 4
smith      DALLAS                 5
clark      NEW YORK               1
king       NEW YORK               2
miller     NEW YORK               3

14 rows selected.

scott@DEV816> select ename, loc
  2    from (
  3       select ename, loc,
           row_number() over ( partition by loc order by ename
)r
  4         from emp, dept
  5        where emp.deptno = dept.deptno
  6             )
  7    where r <= 3
  8  /

ENAME      LOC
---------- -------------
allen      CHICAGO
blake      CHICAGO
james      CHICAGO
adams      DALLAS
ford       DALLAS
jones      DALLAS
clark      NEW YORK
king       NEW YORK
miller     NEW YORK

9 rows selected.
March 13, 2001 -- Thanks for the question regarding "When should the log switch occur?", version 8.1.6
You Asked
Tom,

The size of the online redo log of our database is 10M and
log_checkpoint_timeout and log_checkpoint_interval are 3600 and
9999999, respectively. So I expect the log switch occur either
when the online redo logs are filled up or the passing time is
3600 seconds after the previous log switch. But this is not
case: I still see the time lapse between log switches are more
than 2 or 3 hours. Could you explain to me what is going on
here?
Thanks for your help.

Best regards,

Derek
and we said...
See
http://tkyte:tkyte@asktom.oracle.com/pls/flows/f?p=4950:8:::::F4950_P8_DISPLAYID:344617462392
for details on the meaning of these settings.   NEITHER will
cause a log switch.  They cause CHECKPOINTS.  They do not cause
log switches.

You would have to schedule a job that issues "alter system
switch logfile" if you really have a need to physically switch
logfiles (might apply in a standby database configuration).
March 13, 2001 andy -- Thanks for the question regarding "How can I concatenate fields/values using SQL *Loader?", version 8.0.5
You Asked
Example

My data file NameAddress.dat is in the following format:
'john      msmith     125 any road....'
'mary      xpoppins   Super Highway...'

first name is characters 1-10, middle initial is character 11
and second name is characters 12-21

Importing these to seperate colums is ok as in the control file
below:

LOAD DATA

INFILE 'NameAddress.dat'
BADFILE 'NameAddress.bad'
DISCARDFILE 'NameAddress.dsc'

APPEND

INTO TABLE S_ACCOUNT_IF
(FIRST_NAME    POSITION(001:010) CHAR,
 INITIAL        POSITION(011:011) CHAR,
 LAST_NAME      POSITION(012:021) CHAR, .....

However I have a column (FIRST_AND_LAST_NAME) which I would like
to populate with characters 1-10 concatenated to characters
12-21.

Is this possible from within SQL *Loader?
I have tried with ||, CONCAT etc... but can not find any syntax
that will work.
and we said...
INTO TABLE S_ACCOUNT_IF
(FIRST_NAME    POSITION(001:010) CHAR,
 INITIAL        POSITION(011:011) CHAR,
 LAST_NAME      POSITION(012:021) CHAR,
 FIRST_AND_LAST_NAME position(1:1) ":first_name || ' ' ||
:last_name",

will do it.  You'll just use a SQL function to access the bind
values :first_name and :last_name.  Note that
first_and_last_name can have any old position you want - you
won't be using that bind column.
March 13, 2001 Howie -- Thanks for the question regarding "Row Chaining", version 8.0.5
You Asked
Hi Tom

What is row chaining/migration ? what are the consequences of
Row Chaining/Migration ? How I can find whether it is there in
my database or not ? and if it is there what is the solution to
get rid from it?

Thanks in advance

Howie
and we said...
For other background on this:
http://asktom.oracle.com/pls/ask/f?p=4950:7:::::F4950_P7_SEARCH_CRITERIA:chaining
http://asktom.oracle.com/pls/ask/f?p=4950:7:::::F4950_P7_SEARCH_CRITERIA:migrated
A migrated row is a row that was moved to another block due to
an update making it too large to fit on its original block with
the other rows there.  We cannot just "move" the row -- we have
lots of indexes pointing to the original block.  We therefore
leave behind a forwarding address on the original block and
migrate the updated row to a new block.  now, when you access
that row, we discover it is not really there -- it is migrated
and we read the other block to get it.

A chained row is a row that is too large to fit on a single
block.  If you have a 2k blocksize but your row size is 4k, we
will use 3 blocks to store that row in pieces.  Any table with a
long/long raw will have chained rows.  Any table whose rowsize
exceeds the blocksize will have chained rows.  Any table with
more then 255 columns will have chained rows (we break really
wide tables up).

You can see if you "have it" by looking at the system wide
statistic:

sys@OSI816> select * from v$sysstat where name like 'table fetch
cont%';

STA NAME                                CLASS      VALUE
--- ------------------------------ ---------- ----------
158 table fetch continued row              64    2267554

that shows that in that database, since it was up, i had
2,267,554 requests for rows that were migrated or chained.  You
have to take that with a grain of salt however since

155 table scan rows gotten                 64 8544809978
156 table scan blocks gotten               64  190361236
157 table fetch by rowid                   64  419291785
158 table fetch continued row              64    2267577

that is a VERY small percentage of my total rows.

You can analyze a table to find the chained rows.  See

http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/ch20_io.htm#3552
for more details, including "how to get rid of it".

March 13, 2001 Alan -- Thanks for the question regarding "Clear
      question", version 8.1.6

      You Asked
Hi, Tom

Sorry to confuse you.

If I issue:
 select ename, loc , r
  from (select ename, loc,row_number() over ( partition by loc
order by ename)r
    from t1, t2  where t1.deptno = t2.deptno )
   where r <= 3;

it will give:
ENAME      LOC                    R
---------- ------------- ----------
ALLEN      CHICAGO                1
BLAKE      CHICAGO                2
JAMES      CHICAGO                3
ADAMS      DALLAS                 1
FORD       DALLAS                 2
JONES      DALLAS                 3
CLARK      NEW YORK               1
KING       NEW YORK               2
MILLER     NEW YORK               3

9 rows selected.

But i want result set:        (R)****

ENAME      LOC                    R
---------- ------------- ----------
ALLEN      CHICAGO                1
BLAKE      CHICAGO                1
JAMES      CHICAGO                1
ADAMS      DALLAS                 2
FORD       DALLAS                 2
JONES      DALLAS                 2
CLARK      NEW YORK               3
KING       NEW YORK               3
MILLER     NEW YORK               3
DAN        OKC                    4
DARLIN     L.A                    5
DFEGT      L.A                    5
......
......
......

The diff. is: you number(R) is 1,2,3; 1,2,3;....
What i want R is as follows: 1,1,1; 2,2,2;3,3,3;....
The "DAN", "DARLIN", ....  is just for demo(above), not related
with the question itself. Hope i'm clear now.

The other conditions are same(limit 3 or less for each cat).

Please help.

Thanks,
Alan

      and we said...
select ename, loc , r,
       dense_rank() over ( order by loc ) r2
 from (select ename, loc,
              row_number() over ( partition by loc order by
ename) r
         from emp t1, dept t2
        where t1.deptno = t2.deptno
       )
 where r <= 3

ENAME      LOC                    R         R2
---------- ------------- ---------- ----------
allen      CHICAGO                1          1
blake      CHICAGO                2          1
james      CHICAGO                3          1
adams      DALLAS                 1          2
ford       DALLAS                 2          2
jones      DALLAS                 3          2
clark      NEW YORK               1          3
king       NEW YORK               2          3
miller     NEW YORK               3          3

9 rows selected.

Review &
      Followup

      Rating:
      5
  March 14, 2001
Reviewer:  Alan
       from OKC

March 13, 2001 Buck -- Thanks for the question regarding "SQLJ
      or JDBC", version 8.1.6

      You Asked
I am curious as to the prevalency of SQLJ versus JDBC.  I am
comfortable with Java and Oracle, so I am wondering if you
thought I should spend my time learning JDBC or SQLJ?  Perhaps I
should learn them both serially.

Do you find that people prefer one over the other, or tend to
use one over the other?

Thanks very much for any advice and direction.

      and we said...
I personally find most people either

o use a code generator
o use JDBC directly

I do not see wide spread use of SQLJ.  I myself use SQLJ in many
of my snippets (its much easier to code then jdbc) but most java
programmers seem to tend towards jdbc (more control over what is
really going on).

That is just one persons perspective though...
March 13, 2001 --
      Thanks for the question regarding "alter database check datafiles",
      version 8.1.6

      You Asked
Tom:

Oracle8i administrator's guide page 9-21 mention
"alter database check datafiles"
what does that used for?

I check oracle reference , but don't have information for that.

      and we said...
Sorry, thats a doc bug.  Should read "alter SYSTEM check
datafiles"

CHECK DATAFILES

in a distributed database system, such as an Oracle Parallel
Server environment, updates an instance’s SGA from the database
control file to reflect information on all online datafiles.

GLOBAL performs this synchronization for all instances that have
opened the
database. This is the default.

LOCAL performs this synchronization only for the local instance.
Your instance should have the database open.

See Also: Oracle8i Parallel Server Setup and Configuration Guide.
Review &
      Followup

      Rating:
      5
great  March 13, 2001
Reviewer:
      wallacel  from CA USA
I learn a lot from ask Tom, that's my favorate website.

      Rating: 5
Magnum
      Opus  March 14, 2001
Reviewer:  Balaji
       from CA, USA
I wonder how could one get so much of knowledge, Tom is the great buddy, If god
gives me the power to ask anything I want, I will ask god that I need to be
knowledgeble like Tom.

      Rating:
      4
  March 14, 2001
Reviewer:  A. Li
       from Canada

March 14, 2001 Kathy -- Thanks for the question regarding "FAX
      PURCHASE ORDERS", version 8.0.6.2.0

      You Asked
Oracle Purchasing, Rel. 11.0.3, RDBMS 8.0, IBM RS6000
Applications are loaded on the desktop.
What third-party tool or Oracle product will manage, export, and
fax  purchase orders to suppliers?

      and we said...
I asked for some help on this one (i don't do apps myself) and
this is what I got back:

...
Tom,

The one I am most familiar with is called CommercePath -

http://www.commercepath.com/
The once were even integrated with the Oracle Apps standard demo
instance.

Of course, this is not an endorsement.

I would also advise this person to pose the same question to the
Oracle
Applications User's Group which is an independent organization -

http://www.oaug.org/

On this site there are chat forums that they
could pose the same question.  I would prefer to stay vendor
neutral.

March 14, 2001 -- Thanks for the question regarding "Tunning(SGA
      info)", version generic

      You Asked
When we do show sga at svrmgrl prompt what does it mean by fixed
size and variable size?

      and we said...
Fixed size is the size of a fixed component of the SGA (fixed at
the compile time of Oracle itself).  It is a fixed sized chunk
of memory we set aside for ourself to point into other pieces of
the SGA.

Variable sized is where varying sized chunks of memory are
allocated.  You will find the shared pool, large pool, java
pool, cursor area and many other structures inside of the
variable size of the SGA.
Review & Followup

      Rating:
      4
  March 14, 2001
Reviewer:
      A reader

      Rating: 4
fixed size and
      variable size  March 15, 2001
Reviewer:
      Srinivasan  from Chennai , India
Hi Tom,

Its quite interesting about to such a information, I was searched in
documentations, books and other places about these size information.

I would like to know more information like this, is it possible you to address
our doubts in some forums, where we can submit doubts.

March 14, 2001 Fan -- Thanks for the question regarding "Import
      to locally managed tablespace", version 8.1.6

      You Asked
Hi, Tom

Would you please clarify the case that when importing to a
locally managed tablespace, the extent size will be if the
parameter compress=y was applied while doing export.

For example, if a locally managed tablespace has the uniform
size 4M, the importing table has its size 6M and the compress=y
was applied while doing export.

Will the tablespace automatically use two 4MB extents to hold
the data or use one 6BM extent?

Thanks,

      and we said...
In a locally managed tablespace with uniform extents -- all new
extents will be exactly the same size - it'll use 2 4mb extents.

The only exception would be a dictionary managed tablespace
migrated to a locally managed, the old "bad" extents are still
there with their "bad" size.
Review &
      Followup

      Rating:
      5
  March 14, 2001
Reviewer:  Fan Zeng
       from NJ USA

March 14, 2001 -- Thanks for the question regarding "Migration",
      version generic

      You Asked
Suppose in a database size of 350GB i have one table of size
60GB and i have to port this database from sun solaris box to Hp
box (so i can't use clonning)What are the ways i can do it and
what is the most efficient way?Please reply taking the scenario
that once i am porting the whole database of 350GB and next time
i am intrested in porting only 60GB table.

      and we said...
I would probably do something similar to the following:

1) I would precreate the new instance.
2) I would "precreate" the users from the old instance -- eg:
  select 'create user ' || username || ' identified by values
''' ||
          password || ''';'
    from dba_users;

  spool that and run the resulting script.

3) I would do the same for all system level privs and roles
(grant create table, grant conect, etc...) to create a script
that recreates the basic privs.

Now I have a database that is ready to accept my data more or
less.

for "small" schemas, I might do a user level export from the
source database for each user in parallel (fire off exp many
times) and then import them in parallel (running imp many
times).  that will totally recreate those schemas.

For the really big objects -- I would precreate the tables and
either

o use the SQLPLUS COPY command (i've found this to be very fast
and you can control the array size and everything with it)

o dump the data using pro*c or oci:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:459020243348
and then direct path load it using SQLLDR (beware the newline!
hard to do in versions before 8i with sqlldr, works well with
data that does not have a newline)

o use exp to export just the rows and then use imp to import it.

I would then create the indexes using UNRECOVERABLE and
PARALLEL.

Review &
      Followup

      Rating:
      5
  March 15, 2001
Reviewer:
      A reader

March 14, 2001 gaurang -- Thanks for the question regarding
      "Trigger and sqlloader", version 8.1.6

      You Asked
hi tom
This is from Oracle8i Application Developer's Guide

"Do not create recursive triggers. For example, creating an
AFTER UPDATE statement trigger on the Emp_tab table that itself
issues an UPDATE statement on Emp_tab, causes the trigger to
fire recursively until it has run out of memory. "

I created after update trigger(statement) and try to update base
table and i got error like
  "exceed max open cursor" (i don't know excetly.)

and i updated my init.ora  parameter
 open_cursor=1000

i got same error.

Can u explain me in detail about why this happen and above
Application Developer's Guide statement.

2)i am using sqlloder to load data and generating
sequence number like
 aaa sequence(1,1)..
now i want to attach contstant character to that generated
number.
like   ABC1
       ABC2
       ABC3 etc..

how can i do that. (i don't want to use before insert trigger on
table.)

Thanks

      and we said...
1) that is easy.  If you have an AFTER TRIGGER on a table T and
that trigger updates T -- then

 a) you update T
 b) the after trigger fires
 c) that updates t
 d) goto b

You are in an infinite recursive loop.  that b,c,d loop will
happen until you run out of memory or some other resource.  In
this case, since each trigger fire will allocate a cursor --
after 1,000 loops you run out of cursors.

2) i do not know of a way to do that with the builtin SEQUENCE()
of sqlldr.  If you

ops$tkyte@ORA8I.WORLD> create sequence myseq start with 1;

Sequence created.

then:

LOAD DATA
INFILE *
INTO TABLE T
REPLACE
(
  aaa "'ABC' || myseq.nextval",
  bbb )
BEGINDATA
data1
data2

will work for you.

Review &
      Followup

      Rating:
      4
  March 15, 2001
Reviewer:
      A reader

      Rating:
      4
  January 06, 2003
Reviewer:
      A reader

March 14, 2001 Bhavesh -- Thanks for the question regarding
      "Authentication in OAS", version 4.0.8

      You Asked
Hi Tom,
    On tuesday I asked about how to achieve the functionality of
getting username and password from user within a realm and you
have replied me to look for Authentication schemes. This one is
in continuation of that.
   After your answer I have been able to create realm, groups
and users and associate the security level with cartridge.
Things upto here work fine and exactly as were desired. But now
every time when I have to create a user I have to login as
administrator of OAS. Further more I do not have a control over
the users, groups table because I do not know in which tables
OAS is storing the user, group information.
Is it possible to achieve this functionality using my own set of
database tables. Actually what i want is that first of all I ask
the user to create his profile by keying in the desired
information through a web form (similar to what we do when we
fill up the otn form) and then store the information in these
tables. Later when the user wants to log in I validate the user
based on information available in these tables. Actually when
the user wants to log in I want to show him the login screen
like the one shown in OTN giving realm, group and asking for
username and password. I believe in otn site the url calls some
authenticate.htm form which in turn somehow calls the
authentication method used by OAS. I have tried to find how to
achieve this in OAS document but could not figure out.
Another problem what I am facing is that when I want to display
data of CLOB type. In my database I can see carriage return but
the same is not visible when I view the data in browser using
using dbms_lob.substr. Your kind help in this matter will be of
immense help.
Anticipating to hear soon from you.
Thanks in advance.
Regards

Bhavesh

      and we said...
Goto:

http://technet.oracle.com/docs/products/oas/doc_index.htm
and grab:

Developer's Guide: PL/SQL and ODBC Applications (362 KB)
PL/SQL Web Toolkit Reference (602 KB)

the first one has a chapter "Authentication and Security".  It
sounds like you are interested in the "Custom Authentication"
section therein.  The other documents the package used to
implement this.

As for the CLOB issue -- unless you have surrounded your CLOB
with

<pre>
....
</pre>

HTML will ignore whitespace and do its own word wrapping and
formatting.  Your workarounds to this are:

o use the PRE tag, the text will be displayed in a fixed font
with all whitespace preserved

o htp.p( replace( l_string, chr(10), '<br>' ) );

instead of htp.p( l_string );  that'll turn newlines into HTML
break.

March 14, 2001 Steven -- Thanks for the question regarding "The
      opposite of SQL*Loader", version 8.0.5

      You Asked
SQL*Loader provides the ability to import a flat file into a
table. Is there another utility to do the opposite, i.e. to
export data out of an Oracle table and into a flat file, e.g. a
comma delimited file?

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:459020243348
for a pro*c way (fast)

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:235814350980
for a plsql way (flexible)

see

http://osi.oracle.com/~tkyte/flat/index.html
for a sqlplus way

Review &
      Followup

      Rating: 4
The opposite of
      SQL*Loader  March 14, 2001
Reviewer:  Steve
      Jonik  from Sydney
I knew that I could always write the routines myself, but your speedy reply
(within half an hour) has saved me some time. Thanks.

      Rating: 3
The opposite of
      SQL-Loader  March 27, 2002
Reviewer:  Piotr
      Plizga  from POLAND
Hello All,
Oracle 9i introduce new future. External tables can be used for selecting data
from -- external ascii files --! It is the useful opposite solution for
SQL-Loader!

March 15, 2001 muhammad -- Thanks for the question regarding
      "active transaction", version 8!

      You Asked
How to find an active transaction on a tablespace.

Thanks
Muhammad

      and we said...
Transactions do not take place on tablespaces -- they take place
on tables.

You can find out who has a transaction on various tables this
way:

ops$tkyte@ORA8I.WORLD> l
  1  select type, id1,
  2 (select owner||'.'||object_name from all_objects where
object_id = id1) obj,
  3 (select username from v$session where sid = v$lock.sid ) who
  4    from v$lock
  5*  where type = 'TM'
ops$tkyte@ORA8I.WORLD> /

TY        ID1 OBJ                  WHO
-- ---------- --------------------
------------------------------
TM      97599 SCOTT.EMP            SCOTT

that shows that SCOTT has a transaction that is working on
SCOTT.EMP

Review &
      Followup

      Rating: 5
active
      transaction  March 15, 2001
Reviewer:
      Muhammad
This has been really very helpful. ?Thanx

      Rating:
      5
  March 15, 2001
Reviewer:
      A reader

March 15, 2001 Kalpesh -- Thanks for the question regarding "How
      to do bulk collect in Pro*C variables", version 8.1.5

      You Asked
Hi Tom,
 I am writing one Pro*C code.
    In that code I want to get values from a table and want to
write them into one file.

     How can I do bulk collect using Pro*c variables so that in
one single statement I will get all the values from a table into
Pro*C variables and I can write them in a file.

My select statement is
     SELECT /*+PARALLEL(tbtick,6)*/
            NVL(symbol_id,0),
            NVL(trade_price,0),
             TO_CHAR(trade_date ,'YYYY/MM/DD'),
             TO_CHAR(ROUND(trade_date ,'MI'),'HH24:MI:SS')
      BULK COLLECT
      INTO
        p_arr_symbol_id,
        p_arr_trade_price,
        p_arr_trade_date,
        p_arr_trade_time
      FROM   tkdaily.tbtick
   where symbol_id in ( select symbol_id from tbsymbols where
symbol_type_id=1);

    I want to use my select statement only once , I don't want
to make cursor or anything.

I want  p_arr_symbol_id,
        p_arr_trade_price,
        p_arr_trade_date,
        p_arr_trade_time       into Pro*C .

How can I get them?

Thanks
Kalpesh

      and we said...
In Oracle8i, release 8.1 and up, the easiest method would be to
set the PREFETCH option on the precompiler command line or to
place that option in your C code.

Oracle will then array fetch for you magically.  You ask for a
row and it'll prefetch however many you want.

Otherwise, you can just declare your host variables as arrays
and array fetch them manually:

exec sql begin declare section;
  /* array fetch upto 100 rows at a time */
  varchar   value[100][25];
exec sql end declare section;

   EXEC SQL OPEN C;
   for( rows_fetched = 0, done = 0;
        !done;
        rows_fetched=sqlca.sqlerrd[2] )
    {
        EXEC SQL FETCH C INTO :value;
        done=(sqlca.sqlcode==1403);

        for( i = 0; i < sqlca.sqlerrd[2] - rows_fetched; i++ )
        {
            printf( "row %d is '%.*s'\n",
                     rows_fetched+i+1,
                     value[i].len, value[i].arr );
        }
    }
    EXEC SQL CLOSE C;

Review &
      Followup

      Rating: 4
Bulk collect
      into Pro*C variables  March 16, 2001
Reviewer:
      Kalpesh Patel  from Fort Lee, NJ USA
        This is really useful when someone doesn't want to use PL/SQL variables
for bulk collect.
        With this , we can do bulk collect into Pro*C variables and we can use
them into our Pro*C code for some calculation or manipulation.
   Thanks Tom, for such a useful information.

March 15, 2001 Arthur -- Thanks for the question regarding
      "Select Question", version 8.1.5

      You Asked
Tom,

I realize that there are many ways to create a select statemen
within a PL/SQL procedure.  You can hard code values, use bind
variables, use REF cursors, etc.

Here, I have a select statement that I want to use twice.  The
only difference is the relational operator.  It would make my
code easier to read and cut the procedure in half if I could
find a way to use the same code twice.

In this select, I really want 2 totals.  One for misc14 = '012'
and one for all others.......

SELECT SUM(NVL(amt_paid,0) * 100
INTO v_total
FROM payment_history
WHERE date_time_batch_closed > v_start_date AND
      date_time_batch_closed <=v_end_date   AND
      misc14 = '012';

Can this be done in one select?

Thanks as always.

      and we said...
SELECT SUM((NVL(amt_cash,0) *100,
       decode( misc14, '012', '012', 'Others' ) which
  FROM payment_history
 WHERE date_time_batch_closed >  v_start_date
   AND date_time_batch_closed <= v_end_date
 group by decode( misc14, '012', '012', 'Others' )

that will return two rows.  another way is:

SELECT SUM((decode(misc14,'012',amt_cash,0) * 100   c_012_amt,
       SUM((decode(misc14,'012',0,amt_cash) * 100   c_others_amt
  INTO v_o12_total, v_oth_total
  FROM payment_history
 WHERE date_time_batch_closed >  v_start_date
   AND date_time_batch_closed <= v_end_date

that gets both values in 1 row.

Another way, that gets one or the other depending on a flag, is

v_which := '012';

SELECT SUM((NVL(amt_cash,0)*100
  FROM payment_history
 WHERE date_time_batch_closed >  v_start_date
   AND date_time_batch_closed <= v_end_date
   AND decode( v_WHICH, '012', decode( misc14, '012', 'Y', 'N'
),
                               decode( misc14, '012', 'N', 'Y' )
) = 'Y'
/

to get misc14 = '012' and

v_which = 'xxx';

to get misc14 <> '012'
March 15,
      2001 -- Thanks for the question
      regarding "Replication FK constraints & indexes, UK constraints &
      indexes", version 8.1.7

      You Asked
I am fairly new to Oracle and am already setting up replication
for a State application.  So far, so good!  I understand about
how PK keys and SET COLUMNs are used - no problem.  However, I
am confused about how foreign key & indexes and unique key &
indexes are managed on the snapshot site.  There is little to no
documentation discussing this subject.  Are these constraints
and indexes applied to the snapshot as if you were building a
new database?

      and we said...
On snapshots, foreign keys and all other constraints should be
defined as DEFERABLE.  All deferable constraints will be defered
during a snapshot refresh and validated upon commit.

You may place any indexes on a snapshot with the exception of a
unique index (you may have a unique constraint on a snapshot but
make it deferable.  that'll use a non-unique index).

You would also need to create a snapshot group to logically
collect together all tables related by declaritive integrity
constraints into one group.  This group of objects will be
refreshed in an atomic fashion.

The reason this is so is because snapshots refresh a table at a
time.  If you have the EMP and DEPT table -- and you have
deleted a departement and its employees and added a deptartment
with new employees, the following events will occur:

1) emp is refreshed.  you will now have rows in EMP that have no
dept.
2) dept is refreshed.  your EMP rows now have a dept
3) commit; the changes are permanent

step 1 shows why constraints must be deferable -- during the
refresh process, the data is "not consistent".  No one will see
these inconsistencies and when we commit, everything is OK.

step 2 shows why we need a snapshot group.  if we committed each
snapshot individually, the emp refresh would never work (emps
without a valid DEPT).  Additionally, the refresh of DEPT would
never work either (we need to delete a DEPT but there are
employees assigned to it).

Review &
      Followup

      Rating:
      5
  March 15, 2001
Reviewer:  Lise
       from USA, Nashville, TN

      Rating:
      5
  March 16, 2001
Reviewer:
      ANONYMOUS  from USA

      Rating:
      5
  March 28, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

      Rating:
      5
  May 17, 2001
Reviewer:  Nuno Souto
       from Sydney, Australia

      Rating:
      5
  August 23, 2001
Reviewer:  vijaya

March 15, 2001 Jonathan -- Thanks for the question regarding
      "problem with rowid and chained rows", version 8.1.5

      You Asked
I'd like to know if the physical location of data can be changed
automatically by Oracle.
In fact I'm trying to build a reference of the rowid but if they
changed my table will be wrong.
If the rowids are modified because of an action of the DBa, I
can have him to send a message to my soft and then 'refresh' my
data , but if Oracle can change it automatically I won't be
awared.

So I'd like to know if it's possible or not and if it is, is it
possible to get the information about that modification?

Now ,i'd like to know about chained rows and logminer.
You told me logminer failed when there was chained rows.

Is it only when it process a query that was targeting a chained
rows?
Does it totally crash or will I be able to have the other query
anyway?

      and we said...
A rowid assigned to a row will change under two special
conditions:

1) you have a partitioned table, this table has ENABLE ROW
MOVEMENT defined on it.  If you update the partition key that
causes the row to become a member of another partition, a new
rowid will be assigned to it.

2) you have an index organized table.  the rowid (really a
urowid at that point) is a function of the primary key value.
If you change the primary key, causing the row to move in the
index, the urowid will change.

I would suggest that you use the PRIMARY KEY of the table, not a
rowid.  Over time there may be other cases where the rowid will
change.

In the begining, Oracle snapshots used rowids.  As of version 8
however, they switched that over to primary key as using the
rowid will become less and less reliable.

Logminer will not display the data for the single chained row.
It will continue to function as normal against all other data.

March 15, 2001 Michelle -- Thanks for the question regarding
      "Data Encryption", version 7.3

      You Asked
I need to encrypt large amounts of payroll data in Oracle
version 7.3 then decrypt the data for viewing in financial
reports. Can you offer suggestions on the best way to do this in
the version of Oracle I am using?

      and we said...
There is no way to do this in Oracle7 short of writing your own
encrypt/decrypt in PLSQL.

The client application would have to insert the data already
encrypted and decrypt it after fetching it out.

Oracle8i added native encryption as a feature in the database.
Review &
      Followup

      Rating:
      1
  March 16, 2001
Reviewer:
      A reader

March 16, 2001 syed faheem -- Thanks for the question regarding
      "convert numeric values in word", version 5.0

      You Asked
now i am making a account software.i have a problem in numeric
values
convert into word. for example.
my today sale is 9250/= so
i want to this value in this format.
nine thousands two hundred and fifty only.
so i hope you will solve and send me as soon as possiable.
thank a lot.
syed faheem ahmed.

      and we said...
See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1407603857650
and

http://osi.oracle.com/~tkyte/Misc/SpellANumber.html
....

March 16, 2001 Arthur -- Thanks for the question regarding
      "Select Help", version 8.1.5

      You Asked
Tom,

I need help to create a very complex query.  First, here is a
sample of my data:

Date         Batch#     Tran#     Seq#     Corrstat
---------------------------------------------------
02/03/2001   20141      9167      0001
02/03/2001   20141      9167      0002

02/03/2001   20101      9123      0001       B
02/03/2001   20101      9123      0002       B

02/03/2001   20201      9567      0001       B
02/03/2001   20201      9567      0002
02/03/2001   20201      9567      0003
02/03/2001   20201      9567      0004       B

Basically I need to write a query that will search my table and
return a list of date, batch#, tran# that have some seq# with a
corrstat not equal to space and other seq# with a corrstat of
space.

An example of this is above in my 20201 batch.  The other
batches above are valid.

Thanks Tom.

      and we said...
Not complex at all really:

ops$tkyte@ORA8I.WORLD> select distinct dt, batch#, tran#
  2    from t
  3   where corrstat = ' '
  4     and exists ( select null
  5                    from t t2
  6                   where t2.dt = t.dt
  7                     and t2.batch# = t.batch#
  8                     and t2.tran# = t.tran#
  9                     and t2.corrstat = 'B' )
 10  /

DT             BATCH#      TRAN#
---------- ---------- ----------
02/03/2001      20201       9567

March 16, 2001 Rajashekar H.S -- Thanks for the question
      regarding "Passing of text parameters from one frame to other frames in
      HTML", version 8.1.7

      You Asked
Hi,

I am developing and application using HTTP server of oracle
8.1.7 using mod pl/sql.

I have a problem passing the parameters from one frame to the
other since i am calling the frames i have to use the get method
when the data is of text type and if the value of the text is
having spaces.

Please suggest me some of the other methods / solution to go
ahead please.

I am getting the values for the in_campaign & in_product from
the previous screen by post method.

Regards
Raj

Sample Code
===========

PROCEDURE main_index(
            in_print_ses_list     in     number     default 0,
            in_campaign     in     varchar2     default null,
            in_product     in     varchar2     default null,
            in_previous    in    number    default 0,
            in_mediacard    in    number     default 0,
            x         in    number     default null,
            y         in    number     default null
            )
--Tar No SA4 Added by Raj Ends Here
IS
--Tar No SA4 Added by Raj Starts Here
v_count        number:=0;
--Tar No SA4 Added by Raj Ends Here
BEGIN

-- Validate user
com360engine.security.validate_user(in_application=>g_application
);

--Tar No SA4 Added by Raj Starts Here
--Validate campaign_name
if  in_previous =0   then
v_count:=com360engine.pub_orderlist.check_campaign(in_camp_name=>
in_campaign);
    if v_count>0 then

------com360.err_msg.print(in_address=>'order_infonew.main_index'
,in_errmsg=>'Campaign Name Already Exists for this user');
        htp.p('<script language="Javascript">alert("Campaign
Name Already Exists for this user");

document.location.href="'||com360engine.sysglobal.get_systemattr(
'PUBLICADDRESS')||'order_infonew.main_index";
        </script>');
    end if;
end if;
--Tar No SA4 Added by Raj Ends Here

htp.p('<html>
<head>
<title>360com.com'||sessiondata.g_sesid||'</title>
</head>
<frameset rows="33,72,*" border="0" frameborder="0"
framespacing="0">
     <frame name="topframe" scrolling="no" noresize target=""
src="navigation.main_topframe" border="0" frameborder="0"
marginwidth="0" marginheight="0">
     <frame name="linkbar" scrolling="no" noresize target="rtop"
src="order_media.main_V31linkbar" border="0" frameborder="0"
marginwidth="0" marginheight="0">
    <frameset cols="154,*"  border="0" frameborder="0">
    <frame name="left" scrolling="no" noresize target="rtop"
src="navigation.main_navigation?in_button=ORDERMEDIA"
border="0" marginwidth="0" marginheight="0">

    <!--Tar No. SA4 commented by Raj Starts Here
    <frame name="main"
src="order_media.main_V31haku?in_print_ses_list='||in_print_ses_l
ist||'"  border="0" frameborder="0" framespacing="0"
marginwidth="0" marginheight="0" scrolling="auto" >
    Tar No. SA4 commented by Raj Ends Here-->

    <!--Tar No. SA4 added by Raj Starts Here-->
    <frame name="main"
src="order_media.main_V31haku?in_print_ses_list='||in_print_ses_l
ist||'&in_camp_name='||in_campaign||'&in_product_name='||in_produ
ct||'&in_previous='||in_previous||'"  border="0" frameborder="0"
framespacing="0" marginwidth="0" marginheight="0"
scrolling="auto" >
    <!--Tar No. SA4 added by Raj Ends Here-->

  </frameset>
  <noframes>
  <body>

<p>'||com360engine.adm_application.fetch_text(555,sessiondata.g_l
anguage,'no frame support')||'</p>

  </body>
  </noframes>
</frameset>
</html>
');

EXCEPTION
--bug no:8        Name:Ezhil        Date:08-03-2001
status:NEW
--Desc:    Session Error Exception handling
 WHEN NO_DATA_FOUND THEN
    htp.p('<script
language="Javascript">alert("'||com360engine.adm_application.fetc
h_text(556,sessiondata.g_language,'sessio
error')||'");document.location.href="'||com360engine.sysglobal.ge
t_systemattr('PUBLICADDRESS')||'login.logout_page?in_user_id='||s
essiondata.g_user_id||'";</script>');

  when others then
   -- Handle cookie exceptions
   if sqlcode=-20101 or sqlcode=-20102 then

com360.err_msg.print(in_address=>'login.main_index',in_errmsg=>''
||com360engine.adm_application.fetch_text(556,sessiondata.g_langu
age,'sessio error')||' ('||sqlcode||')');
   else

com360engine.logs.error_log(in_sqlcode=>sqlcode,in_errm=>sqlerrm)
;
  end if;

END;

      and we said...
You need to URL encode parameters in a GET like that.  this is
not specific to PLSQL or anything, this is just something every
URL you build needs to take into consideration.

Here is a routine you can use and the output from it:

ops$tkyte@ORA8I.WORLD> l
  1  create or replace
     function urlencode( p_str in varchar2 ) return varchar2
  2  as
  3     l_tmp   varchar2(12000);
  4     l_len   number default length(p_str);
  5     l_bad   varchar2(100)
                default ' >%}\~];?@&<#{|^[`/:=$+''"' || chr(10);
  6     l_char  char(1);
  7  begin
  8     if ( p_str is NULL ) then
  9             return NULL;
 10     end if;
 11
 12     for i in 1 .. l_len loop
 13             l_char :=  substr(p_str,i,1);
 14             if ( instr( l_bad, l_char ) > 0 )
 15             then
 16                     l_tmp := l_tmp || '%' ||
                         to_char(ascii(l_char), 'fm0X');
 17             else
 18                     l_tmp := l_tmp || l_char;
 19             end if;
 20     end loop;
 21
 22     return l_tmp;
 23* end;
ops$tkyte@ORA8I.WORLD> /

Function created.

ops$tkyte@ORA8I.WORLD> select
urlencode( 'This string contains bad things? / Yes, it does!' )
from dual;

URLENCODE('THISSTRINGCONTAINSBADTHINGS?/YES,ITDOES!')
---------------------------------------------------------------
This%20string%20contains%20bad%20things%3F%20%2F%20Yes,%20it%20do
es!

March 16, 2001 Amy -- Thanks for the question regarding "Does
      Oracle have ODBC on Sun Nuix system?", version 8.17

      You Asked
Dear Tom,

We are going to port our application from NT to Sun Solarios.
Could you let me know what is short cut to convert ODBC part to
OCI? Or does Oracle have ODBC driver on Unix system?

Thanks for all your help.

Amy

      and we said...
There are ODBC drivers for Oracle on UNIX.  Oracle does not
provide them, they are 3rd party implementations.  See

http://www.orafaq.com/faqodbc.htm
for a partial list of vendors.
March
      16, 2001 ernesto -- Thanks for the
      question regarding "Oracle 7.3 on Windows 2000", version 7.3

      You Asked
Is is possible to install Oracle ver. 7.3 to a Windows 2000
Advanced Server OS?

I tried to install Oracle 7.3 to Windows 2000 Advanced Server
but a notification occured.  "Unable to delete the NT Service
for the SQL*Net V2 Listener."  If it is possible, how can I
resolve the problem.

Thanks!

      and we said...
Oracle8i, release 8.1.6 and up are the ONLY releases of Oracle
installable on Win2k.

7.3 specifically will not function on that operating system.
Review &
      Followup

      Rating: 2
Thanks for the
      question regarding "Oracle 7.3 on Windows 2000", version
      7.3  April 27, 2001
Reviewer:  Michael
       from Columbus, OH USA
I had no problem installing personal Oracle 7.3 on Windows 2000, once I
installed the y2k updated installer the process of installing PO7.3, Designer
2000, and Developer 2000 went flawlessly.
Unfortunately I had no luck installing 8i as the version I have is 8.1.5 and
this is not compatable with 2000, is there any way to update 8.1.5 to win2k as
the 8.1.6 product download is one file of approx 600Mb which is impossible for
me to try at the moment?

March 16, 2001 -- Thanks for the question regarding "enable
      novalidate primary key", version 8.1.6

      You Asked
Tom:

create table emp( empno number(5) primary key disable);
insert into emp values (10);
insert into emp values (10);
 alter table emp enable novalidate primary key;
ERROR at line 1:
ORA-02437: cannot validate (JIM.SYS_C001704) - primary key
violated
so although i said novalidate, it still try to validate.

      and we said...
It is because the alter table emp enable was trying to add a
unique index in order to enforce the newly enabled constraint.
By default, this will be a unique index.

You either need to:

...
ops$tkyte@ORA8I.WORLD> create index emp_idx on emp(empno);
Index created.

ops$tkyte@ORA8I.WORLD> alter table emp enable novalidate primary
key;
Table altered.

which causes the primary key to pick up and use the non-unique
index or:

ops$tkyte@ORA8I.WORLD> create table emp
           ( empno number(5) primary key DEFERRABLE
disable);

Table created.

ops$tkyte@ORA8I.WORLD> insert into emp values (10);

1 row created.

ops$tkyte@ORA8I.WORLD> insert into emp values (10);

1 row created.

ops$tkyte@ORA8I.WORLD> alter table emp enable novalidate primary
key;

Table altered.

which causes us to use a non-unique index out of the box.

March 16, 2001 Vernon Edson -- Thanks for the question regarding
      "table partition/how to export it", version oracle 804

      You Asked
1). I have a table of 25 million rows and I want it to partition
it, my problem is I don't have  any experience on how to
partition a big table, is it possible in version 804, pls. help
me how to do it.

2). I try to export it and I got an error...I think it reach the
maximum file size which is 2G, is there any other way to export
it?

Many thanks,
Vernon

      and we said...
1) it is possible.  It is done via DDL on the CREATE TABLE
statement.  You need to read the documentation on it.  I can
give you examples (search for partition on my site) but to tell
you specifically how to partition your 25 million record table
-- that is something I cannot do here.

2) You don't mention an OS version.  On unix see:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:122612348063
...

On NT, you'll have to wait for 8i export which can export to
many files, each of upto 2 gig in size.

Review &
      Followup

      Rating:
      4
  March 19, 2001
Reviewer:
      A reader

March 16, 2001 Bhavesh -- Thanks for the question regarding
      "Finding Invalid session", version 4.0.8

      You Asked
Hi Tom,
    Thanks a lot for all your help in past. I am designing an
internet application. In my session table I keep the session id
and a random number which is passed as parameter from one page
to another. The question what I need to know in case the user
disconnects the connection from the server (it can be an error
in the OS/browser or normal closing of the browser) then how the
application server will come to know that the session has got
disconnected because oAS has to delete the record for this
session from the database.
Regards

Bhavesh

      and we said...
keep a timestamp and expire the session at some point in the
future.  Everytime they hit your site, update the timestamp.
have a job that cleans out rows that are too old.

It is the way this very application you are using works.
March 16, 2001 Souren -- Thanks for the question regarding
      "Query Optimization", version 8i

      You Asked
(1)How can i automate the Cost-Based Query optimization
procedures in  Oracle 8i.

(2) How can i open web sites from SQL prompt ?

(3) Please provide me some scripts that will automate the
Database Memory and Space Management process.

Looking forward to your reply.

Regards

Souren

      and we said...
1) if you mean the collecting of statistics, you would use
DBMS_JOB to do that.

http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/dbms_job.htm#999107

2) UTL_HTTP can be used:

ops$tkyte@ORA8I.WORLD> exec dbms_output.put_line( substr(
utl_http.request( '
http://www.oracle.com','www-proxy1'/
),1,80) )

<html>
<head>
<title>Oracle Corporation</title>
<meta http-equiv="Content-Type"

PL/SQL procedure successfully completed.

http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/utl_http.htm#998100

3) OEM (Oracle Enterprise Manager) has many of these.  I don't
have any such scripts myself.
March
      17, 2001 Bhushan -- Thanks for the
      question regarding "Update rows from Table1 to Table2 depending upload
      flag field value of Table1", version 8

      You Asked
Dear Sir,

I have Two sets of table. Better I will give example
Table T1 & Table T2 having similar structure except
one additional field called flag in table T1.

Every day I Upload data in Table T1 as fresh Upload & run a
script
to Update existing rows in table T2 depending Upon value of flag
field in Table T1.

I have written a procedure which will first read a row in table
T1
and
if flag value is 'A' then add that record in Table T2
if flag value is 'E' then search & Update that record in Table
T2
if flag value is 'D' then delete that record in Table T2

To perform this transactions I have maintain similar Primary Key
or composite keys in table T1 & Table T2 to identify unique
record.

I have implemented Cursor concept in the said script.
But it seems to be too slow when data in table 1 is more than
100.
Many times it get hangs or give some wrong row count.

I have to do this procedure on about 50 tables.

Will you plese help me out so that I can perfom this operation
in fastest way with full accuracy.

Regards,
Bhushan

      and we said...
I would just do this in 3 sql statements:

delete from t2 where t2.pk in ( select t1.pk from t1 where flag
= 'D' );
insert into t2
select ..... from t1 where flag = 'A';

update ( select t1.c1 t1_c1, t1.c2 t1_c2, ...
                t2.c1 t2_c1, t2.c2 t2_c2, ...
           from t1, t2
          where t1.pk = t2.pk
            and t1.flag = 'E' )
   set t2_c1 = t1_c2, t2_c2 = t2_c2, .....;

Let the database do the work for you here.  If you can do it in
a single sql statement is almost certainly will be faster then
doing it procedurally yourself.

Review &
      Followup

      Rating:
      4
  March 19, 2001
Reviewer:  Bhushan
       from India
Thanks for your prompt reply.
Before going for procedure writing.
I had tried this. What I did that time
simply written sqls in one sql file
and run it & but after performing one transaction
it used hanged so I decided to adopt for solution
mentioned in my first file.
Now again I will try sql given by you & get back to you
ASAP.

Thanks & regards.

March 17, 2001 Nikunj -- Thanks for the question regarding
      "applicationwise tables space / database creation", version 8.1.6

      You Asked
hi tom,

i have oracle enterise edition 8.1.6.

thanks for giving solution so far.

i had developed 3 application as below

1. financial accounting system
2. payroll
3. sales order processing system

at present i had keeped those all application on singal database
& all are on same tables space (user_data, temporary_data).

those all three aplication not linked to each other.

if i take below steps it increase performance.

1. if i create a different database for each application ?
2. in singal database i create a new tablespace and assosiate
those application individualy ?

tia,
nikunj

      and we said...
1) if you create a separate database for each application and
keep all three on the same machine, you will DECREASE
performance.  Only split them out if you plan on giving each
their own machine.

It takes more resources to run 2 instances then one and more for
3 then 2.

2) If introducing new tablespaces would also result in spreading
IO out over more disks AND you are currently experiencing IO
slowdowns, this will help.

If you put all the tablespaces on the same device they currently
are on, no change will be noticed.  Tablespaces are a logical
separation of objects.  Having everything in 1 tablespace is
just as efficient as having everything separated out if the
tablespaces are all on the same disk. Look at this from an IO
perspective and try to separate the objects out to evenly spread
IO across all of your disks.

And PLEASE, before you do anything, identify WHY your system is
"slow" and identify your goals.  Moving things about, playing
with init.ora parameters -- you won't achieve dramatic gains
that way.  You need to have an understanding of what is slow in
your system and why before you can fix it.
March 17, 2001 Nikunj -- Thanks for the question regarding "imp
      oracle 8.1.6 data into oralce 8.", version 8.1.6

      You Asked
hi tom,

i have Oracle8i Enterprise Edition Release 8.1.6.0.0 -
Production

i would like to export a user which can be able to import in
Oracle8 Enterprise Edition Release 8.0.4.0.0 - Production

i had try but i get the below errors on oracle 8.0.4.0.0.

imp-00010: not a valid export file, header failed verification
imp-00021: operating system error - error code (dec 2, hex 0x2)
imp-00000: import terminated unsuccessfully.

i read in oracle 8i utility realeas 8.1.6 part no. a76955-01 u
can able to do this how can i do this ?

tia,
nikunj

      and we said...
You have to use the 8.0.4 export tool over SQLNet to do this.

On the 8.0.4 database, simply run:

$ exp user=u/p@8idatabase owner=u

and then the 8.0.4 import can use it.
March 17, 2001 Nikunj -- Thanks for the question regarding
      "nvl2() -- CASE", version 8.1.6

      You Asked
hi tom,

i see the function nvl2().

but its give me result when there is value is null i.e. as per
oracle doc.

select ename,nvl2(to_char(comm),'sal & comm','sal') income from
emp;

it give us sal & comm in income if comm is not null otherwise
sal.

but in one of my table as below value i have

C_DISCOUNT    OCTROI1    OCTROI2    FREIGHT     REBOOK
---------- ---------- ---------- ---------- ----------
     253.5          0          0         67          0

i want

result     when

a     if rest of all columns value=0 other than c_discount
a_b    if c_discount & octoi1 !=0 and others = 0
a_b_d    if every values != 0

how can i do this

thanx,
nikunj

      and we said...
tkyte@TKYTE816> select t.*,
  2         (case when (c_discount!=0 and
  3                    (octroi1+octroi2+freight+rebook)=0)
  4               then 'a'
  5               when (c_discount!=0 and
  6                     octroi1!=0 and
  7                     (octroi2+freight+rebook)=0)
  8               then 'a_b'
  9               when (0 not in
(c_discount,octroi1,octroi2,freight,rebook))
 10               then 'a_b_d'
 11               else null
 12          end)
 13  from t;

C_DISCOUNT    OCTROI1    OCTROI2    FREIGHT     REBOOK (CASE
---------- ---------- ---------- ---------- ---------- -----
         1          0          0          0          0 a
         1          1          0          0          0 a_b
         1          1          1          1          1 a_b_d
         1          1          0          1          1

will do it.  CASE is new in 8.1.6.
Review &
      Followup

      Rating: 3
Senior
      Executive - IT  March 19, 2001
Reviewer:  Nikunj
      Thaker  from India
goods

March 17, 2001 Pertisth -- Thanks for the question regarding
      "How to make the duplicate database in another server or notebook?",
      version Oracle 8i

      You Asked
Dear Tom,

Is there any shortest way to copy the entire database from one
server to another server or to any laptop ?

Thanks
with regards

      and we said...
if the platforms are "homogenous", a backup and restore (copy
the datafiles) is the fastest if you need the entire database.

if the platforms are not "homogenous" (eg: sun server, windows
laptop), export/import is the path you would take.
Review &
      Followup

      Rating: 2
Performance
      Issue ?  March 20, 2001
Reviewer:  Y
      Srinivas  from VA USA
Well if the DB is in Gigs then I think I should even think of that. I mean it
would take a lot of time. In this case what alternatives do we have?

March 17, 2001 Jonas -- Thanks for the question regarding "How
      to handle row id's in a materialized view", version 8.1.7

      You Asked
My problem is that i have a mview that is based on rowid. This
mview is partititioned and my first problem occure when i want
to split a partition and change tablespace... it seems that it
doesen't delete old invalid rowid's so when i try to refresh the
view i get error invalid rowid's. next question is what happens
when i do a export/import? the thing is that i can't rebuild the
view because it is huge and it takes a week to build it.

Thanks

      and we said...
Well, anything built on a rowid like that is very prone to
having to be rebuilt whenever the base object is physically
altered.

splitting the partition, export/import -- anything that assigns
a new rowid will "break" it.

I would recommend that right now you bite the bullet one time
and rebuild the MVIEW as a primary key based object.  Using
rowids is very much discouraged.

Otherwise, never split the partitions, never move them, never
exp/imp them -- don't do anything like that to them -- or you
will break the mview refresh.

I cannot imagine a materialized view that would literraly take a
week to recreate.  You do know that you could create it offline
using a parallel create table as select unrecoverable.  It
should take a reasonable amount of time in that fashion.

March 17, 2001 Marcel -- Thanks for the question regarding
      "Password", version 8.1.5.0.4

      You Asked
Oracle 8.1 on a Netware 5.1 server :

How can I change the password on a database for the user
'INTERNAL'
This password was entered at installation of the Oracle database
on the server but I would like to change it now

      and we said...
This is done typically using the ORAPWD command line application
when the database is shutdown to recreate the password file.

Search my site for orapwd for details.

If REMOTE_LOGIN_PASSWORDFILE is set to exclusive, simply
changing the SYS password will change internals password as they
are the same.
Review & Followup

      Rating:
      4
  March 17, 2001
Reviewer:  Pauline

      Rating: 4
oracle
      password:  March 17, 2001
Reviewer:  asia
       from saudi arabria
how can i know the password of a cd of oracle?

      Rating:
      5
password  March 18, 2001
Reviewer:
      A reader
dear Tom Sir,

very good I was thinking that we can't change password of internal.

try kumar

March 17, 2001 murlidhar -- Thanks for the question regarding
      "Is the connection to DB2 is possible using PL/SQL ?", version 8i

      You Asked
Hi, Mr. Tom,

This is again Mr. Murlidhar.

I have one more Question to U. Please do not feel
bad for my question as my question may be foolish
one.

My requirement is transfering data from say DB2
to oracle 8i without human intervention.

This I want to do by Scheduling the job using
dbms_job.

For this I will write a PL/SQL

1) to connect to remote DB2 database,

   (Oracle remote databases access possible,
    so is the feature available to connect third
    party database thru PL/SQL? like ODBC)

2) procedure to read and transfer data

Presently I do this using VB6, but every day it is to
be done. So I want to schedule this.

Is the connection to DB2 is possible using PL/SQL ?
If Yes, then How ?

Please suggest.

Thanking You,

Murlidhar

      and we said...
Just a reminder to all -- please check your email address when
you ask a question.  If you leave off the domain, I cannot get
in touch with you!

You can use the SQLPLUS copy command with ODBC to transfer data
like this.  See

http://tkyte:tkyte@asktom.oracle.com/pls/flows/f?p=4950:8:::::F4950_P8_DISPLAYID:1139834557335
for a description of that functionality.
Review &
      Followup

      Rating: 3
Is it possible
      to connection to DB2 using PL/SQL (SQL*plus)?   March 19,
      2001
Reviewer:  Murlidhar Mallya  from Ahmedabad,
      Gujarat, India
Thank you very much for your answer. Deffinitely, your answer helped me to some
extent.

But I want some validations to be performed and based on
that, data to be transferred.  And I do not want to create temporary table,
validate and transfer.

That is in PL/SQL I want to estableish connection and
a procedure to validate data and transfer accordingly
and this I want to schedule.

Thanking U once again.

With Regrds

Murlidhar

March 18, 2001 Anil -- Thanks for the question regarding "Run
      some procedures during database startup", version Oracle 8i

      You Asked
How can i run some proc/func during my database start ?And some
some proc/func before i shut down. Start of the day procedures
and end of the day procdures. Also things like inserting into
table the time when the database was shut ?

Thanks

      and we said...
You can use database triggers AFTER STARTUP and BEFORE SHUTDOWN.

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:263215360334
for an example of a startup trigger.
Review &
      Followup

      Rating:
      4
  July 20, 2001
Reviewer:  Pichaimani
      Balasubramanian  from San Jose, CA USA

March 18, 2001 Fahim -- Thanks for the question regarding "How
      to insert image file in database table", version 7

      You Asked
Dear Tom,

Hi,

I have a table name xyz.It has a long raw column for image
storage.would u plz tell me how do I insert image file from my
file system.My image file is d:\ab.jpg.

Plz give me complete statement by using above objects.

Regards,

Fahim Ahmed.

      and we said...
It will depend on the client.

If you are using Oracle forms, the builtin READ_IMAGE_FILE()
will do this.

If you are using Java/JDBC, you will use a stream.  see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:238014476571
for an example.

If you are using Pro*C,

   insert into xyz values ( :blob_data );

if you are using OCI, you'll use the API obindps

and so on.

March 18, 2001 Inam Ullah -- Thanks for the question regarding
      "Is Developer is going to be obsolute??", version 2

      You Asked
Hi Dear & Respected Sir,
   There r too many talk around our country that developer is
being
obsolute in near future. Kindly inform us is it true or not?

Thanking U.
Inam Ullah Bukhary
Pakistan

      and we said...
Absolutely not.

When the choices for developing a rich interface are:

o write it by hand in java
o have it done for you in a 4gl

Many people will still opt for having most of it done for them
in a 4gl.  Forms and reports are very good at what they do, they
fill a niche (a rather large niche) in a way no other tools or
languages do.
Review & Followup

      Rating: 5
Pay attention
      to JDeveloper !  March 19, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
Jdeveloper supports SQLJ as well as JDBC. SQLJ is SQL embedded in Java and
pre-processed to become JDBC using SQLJ translator. SQLJ ofers mainly "cleaner"
code and static type checking. And it's definately a very good tool !

March 18, 2001 Arul -- Thanks for the question regarding
      "NO_DATA_FOUND when querying SESSION_ROLES inside a function!!", version
      8.1.6

      You Asked
Hi Tom,

I am using SESSION_ROLES data dic. view inside a stored function
in 8i database to chk. wether the user has a particular role or
not.

Irrespective of wether the user has that role or not , it is
raising NO_DATA_FOUND. Why? Am i not supposed to use it ??

Here is the code:

***********************************************

CREATE OR REPLACE FUNCTION        Proc_Role (lvp_role_name
VARCHAR2)
RETURN NUMBER IS
-- Error. Handling
      stoo_selcnt   INTEGER       := 0;
      stoo_rowcnt   INTEGER       := 0;
      stoo_error    INTEGER       := 0;
      stoo_errmsg   VARCHAR2 (255);
lv_role varchar2(200);
   BEGIN
      BEGIN
-- Check wether the user has specified role or not!
-- checked using SESSION_ROLES data dictionary table!
         SELECT 1
         INTO stoo_selcnt
         FROM dual
         WHERE EXISTS (SELECT role
                        FROM session_roles
                        WHERE UPPER(LTRIM(RTRIM(role))) =
UPPER(LTRIM(RTRIM(lvp_
role_name))));

    RAISE_APPLICATION_ERROR(-21111,'JUST CHKING....StoO_selcnt
:'||StoO_selcnt);

      EXCEPTION
         WHEN NO_DATA_FOUND     THEN
                raise_application_error (-20101, 'U do not have
the necessary pr
ivileges.!!'||stoo_selcnt);

           WHEN OTHERS             THEN
            stoo_error := SQLCODE;
            stoo_errmsg := SQLERRM;
      END;
      IF stoo_error != 0
      THEN
         raise_application_error (-20101, 'Error in Chking
Role!' || stoo_errmsg
);

      END IF;
      RETURN 0;  -- SUCCESS!
END proc_role;

***********************************************

Note - We r writing this code to simulate the behavior of
PROC_ROLE built-in function of SYBASE.

The above fn. always raises NO_DATA_FOUND... pl. let me know the
reason. Any other alternatives..?

Thank You.
Arul.

      and we said...
Roles are not enabled in the execution of a stored procedure.
Stored procedures execute with the base set of privileges of the
OWNER (definer) of the procedure.

There is the special case of an invokers rights routine in
Oracle8i, however if an IR routine is called from definers
rights routine, there will be no roles (the DR routine didn't
have any roles so when it calls the IR, no roles will be there)

If you are simply trying to see if a user has been granted a
role or not, see:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:484621563404
it shows you various queries to retrieve this information.

March 18, 2001 sonal -- Thanks for the question regarding
      "Transportable Tablespace: Are packages in target made invalid?", version
      8.1.6.2

      You Asked
Hi,

We have two identical dbs(volumedb and testdb), except one has lots of data and
other none. Both have pl/sql packages, views. To move data from the volumedb to
testdb using transportable tablespaces, we need to drop the tablespace on testdb
than recreate from volumedb. My question is will packages in testdb be still
valid after bringing in the tablespace? or will drop tablespace invalidate/drop
packages?

Sonal.

      and we said...
It will invalidate the procedures.  It will not drop them.

It is perfectly OK and normal for the procedures to go invalid.  It is not
something to be overly concerned about. they will automagically recompile
themselves as you use them.
Review & Followup

      Rating:
      5
  March 18, 2001
Reviewer:
      A reader


Subject | Article | Last Updated (East coast time)
Exception | article only | Mar 19, 2001 08:41 am
Loading Documents, Export & Import into different database | article only | Mar 19, 2001 08:54 am
SENDING MAIL FROM DB | article only | Mar 20, 2001 08:38 am
Oracle performance tuning | article only | Mar 20, 2001 08:59 am
Use of Pseudo Column - Currval | article only | Mar 20, 2001 09:00 am
SGA Size | article only | Mar 20, 2001 09:12 am
Whats the difference between the v$sql* views | article only | Mar 20, 2001 10:17 am
Multiple Questions | article only | Mar 20, 2001 09:53 pm
privileges using dbms_sql | article only | Mar 20, 2001 10:08 pm
What's the best way to check if a table exists before creating it? | article only | Mar 20, 2001 11:04 pm
What is the different between Application Server & File Server ? | article only | Mar 20, 2001 11:35 pm
Bootstrap Segment | article only | Mar 21, 2001 01:02 am
regarding clob and table storage parameters | article only | Mar 21, 2001 06:15 pm
Which column is updated | article only | Mar 21, 2001 06:51 pm
RI & performance | article only | Mar 21, 2001 10:08 pm
a Summary Column with where condition | article only | Mar 22, 2001 12:51 pm
RAID 10 | article only | Mar 22, 2001 12:54 pm
Convert Oracle Date into Unix date | article only | Mar 22, 2001 08:40 pm
oracle designer 6i and oracle repository 6i | article only | Mar 22, 2001 09:48 pm
Will Update Result in a Slower Performance | article only | Mar 22, 2001 10:47 pm
Oracle 8.1.7 Java option | article only | Mar 23, 2001 01:26 pm
RBA | article only | Mar 23, 2001 01:29 pm
Unused Columns of a table | article only | Mar 23, 2001 01:36 pm
How to cut alert log file | article only | Mar 23, 2001 01:51 pm
Auto ORACLE installation for UNIX | article only | Mar 23, 2001 02:00 pm
designer version | article only | Mar 23, 2001 06:16 pm
Oracle 7.3.4 to Oracle 8.1.7 | article only | Mar 23, 2001 11:27 pm
Another owa_util.listprint issue | article only | Mar 24, 2001 01:47 am
Check fragmentation and eliminate | article only | Mar 24, 2001 02:17 am
Restrict IP address to Oracle | article only | Mar 24, 2001 03:15 am
SQL Hints | article only | Mar 24, 2001 01:19 pm
Oracle & JSP | article only | Mar 24, 2001 03:03 pm
JDBC -- How to bind a PL/SQL table type using JDBC? | article only | Mar 24, 2001 08:00 pm
How UGA/PGA, Rollback Segment, and Context contribute to the Cursor process | article only | Mar 24, 2001 10:51 pm
Validations in a Multi-Row Block | article only | Mar 24, 2001 11:29 pm
milli seconds | article only | Mar 25, 2001 01:12 am
oracle performnace tuning | article only | Mar 25, 2001 02:46 am
Partially cloning databases using RMAN or Hot backups | article only | Mar 25, 2001 09:24 am
execute a shell command from a oracle job | article only | Mar 25, 2001 11:49 am
multiple CPU | article only | Mar 25, 2001 12:02 pm
all dependant on db bock size | article only | Mar 25, 2001 09:54 pm
row(s) 1 - 41 of 41
March 19, 2001 murali -- Thanks for the question regarding "Exception ", version 8.0.5
You Asked
i have a procedute like this

declare
a number(1) := 123123213123123;
begin
a := 1;
end;

this i know will create an exception with value error , why i asked this was i
want to accept a name which is entered by user and can be long so it always give
me an exception, can i trap this exception by  some means.

Regards
Murali Menon
and we said...
Don't do the assignment in the declare section then.

scott@DEV816> create procedure p ( p_input in varchar2 )
  2  as
  3          a       number(1);
  4          value_error exception;
  5          pragma exception_init(value_error,-6502);
  6  begin
  7          begin
  8                  a := to_number(p_input);
  9                  dbms_output.put_line( 'OK!!!' );
 10          exception
 11                  when value_error then
 12                          dbms_output.put_line( 'Error!!!' );
 13          end;
 14  end;
 15  /

Procedure created.

scott@DEV816> exec p(1);
OK!!!

PL/SQL procedure successfully completed.

scott@DEV816> exec p(22);
Error!!!

PL/SQL procedure successfully completed.
March 19, 2001 Jennifer -- Thanks for the question regarding "Loading Documents, Export & Import into different database", version 8.1.6
You Asked
Hi Tom:

1. I need to initial one table called DOCS, only contain id and doc (CLOB), can
I use SQL Loader to load into DOCS? If so, should I put all documents into one
file?,That's hard, what is the best way to do that? Can I replicate DOCS after I
load? I checked Utilities reference, couldn't understand secondary data file,
Does it have to define at first data file?

2. I have some image files which already loaded into database, I want to load
other instances which they are not connected, i.e. not database link at all, can
I use export then import?

Thanks
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:627223659651
basically, you'll want to have a file:

doc_id,filename
doc_id,filename
doc_id,filename

and you'll sqlldr that file.  SQLLDR will actually load the contents of filename
for you.

replication supports LOB types.

2) yes, you can exp/imp the clobs.
March 20, 2001 gaurang -- Thanks for the question regarding "SENDING MAIL FROM DB", version 8.1.6
You Asked
hi tom
how can i send mail from database.(without java);
can i use utl_tcp package?
and we said...
You can use UTL_SMTP built on UTL_TCP however -- both require the java option as
they are built on java themselves.  search for utl_smtp on my site for
examples/info.

Short of that, writing an extproc in C for this is not too terribly difficult.
You could then send email by invoking a command line email program.

For another idea, search for

utl_http email

on my site as well.  shows how to send email using a webserver via cgi-bin if
you have access to one.
Review & Followup
Rating: 4
March 20, 2001
Reviewer: A reader

March 20, 2001 sandeep -- Thanks for the question regarding "Oracle performance tuning", version 8.1.6
You Asked
Hi !

I am working on a oracle datawarehouse + OLAP system. we will be using oracle
database for storing data and oracle express server, oracle express objects to
create olap reports.

one of the table in the warehouse is having 10 lacs rows per year and we want to
retain data for that for 5 years.
the table contains sales data and will be populated daily with approx. 2500 rows
daily.

what should be the values of storage parameters like PCTFREE, PCTUSED ? and
offcoures the sizes of rollback segments and temporary tablespace ?
and we said...
I don't know how many rows a "lac" is however...

If this is a warehouse and you'll never be UPDATING or DELETEING data in this
table, then

PCTFREE=0  (fill the blocks up upon insert - all the way, don't need rooms for
updates)

PCTUSED=90 (as you never delete, this will never be used anyway).

As for the sizes of rollback -- thats something you'll have to decide.
Insufficient data to compute.  You need enough rollback to satisfy your
transaction load and avoid ora-1555 (search for 1555 on my site for details).

Same with temporary, you'll need to size that as you determine how big your
queries are and how many you'll be running concurrently.
Review & Followup
Rating: 3
Oracle performance tuning March 25, 2001
Reviewer: sandeep ketkar from PUNE (INDIA)
Because of the insufficient information in the question
TOM could not answered it correctly.
I have posted my question to tom again
I am sorry for inconvinince caused to him.

Rating: 4
Terms in Indian Subcontinent September 05, 2003
Reviewer: GovindanK from CA, USA
One Lakh (Lac) = 100,000
10 Lacs = 1 million
100 Lacs = 1 Crore (=10 millions)

March 20, 2001 Janardhana -- Thanks for the question regarding "Use of Pseudo Column - Currval", version 7.3
You Asked
Hi,

I want to know the following.

Assume I have a sequence named abc
In SQL PLUS if i say
Select abc.currval from dual;
I get an error
ora-08002 Sequence not initilised in this session;

But if i get the nextval first, then the above query does not have problem.

I have seen procedure where .currval is referred inside the procedure.
Will it have error at any time or not? If not why?

Thanks

Janna
and we said...
Currval is valid in a session if and only if nextval has been called in that
session at least once.

You many times see it in a procedure selecting currval without seeing the
nextval.  The nextval is generally done in a trigger as a side effect of an
insert.  You might see:

  insert into t values ( .... );
  select my-seq.currval into x from dual;  -- get the newly inserted records
                                           -- primary key value
Review & Followup
Rating: 4
March 21, 2001
Reviewer: Janardhana from London

March 20, 2001 Randy -- Thanks for the question regarding "SGA Size", version 8.1.6
You Asked
Hi Tom,

Can you tell me how does the size of SGA matters with the process parameter in
init.ora file ? My database is configured with about 300M of SGA and I had
process parameter set to 200. When I bumped it up to 300 to accomodated more
concurrent users, I could not start the database, it was giving me error "Cannot
Create SGA" - Sorry I dont have the exact error message. But I remember the
reason was system could not find a continuous segment in the memory to hold the
entire SGA. When I set it back to 200 I could start the database without any
problem.

Can you explain me the phenomena ?

Thanks

Randy
and we said...
It was semaphores, not shared memory that caused the problem.  You need to
reconfigure the system with more semaphores.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:480021477095
for a discussion on this and links on howto do this on solaris.  If you are not
solaris, refer to your Oracle OS install/admin guide for details.
Review & Followup
Rating: 4
SGA Size March 20, 2001
Reviewer: Randy from Chicgao
Thanks, that was my initial impression too. But I got confused with SGA error.

March 20, 2001 Alan -- Thanks for the question regarding "Whats the difference between the v$sql* views", version 8.1.6
You Asked
What is the diff between:

v$sql
v$sqlarea
v$sqltext
v$sqltext_with_newlines

when I query v$sql joining with v$session and filter by a SID I get more than
one SQL (expected) but if I join v$sqltext with v$session with same conditions I
get one sql statement only (last SQL issued) why is this?

Thanks
Alan
and we said...
v$sql the details -- if you have multiple copies of the query:

"select * from T"

in your shared pool, v$sql will have a row per query.  This can happen if user
U1 and user U2 both have a table T and both issue "select * from T".  Those are
entirely different queries with different plans and so on.  v$sql will have 2
rows.

v$sqlarea is a aggregate of v$sql.  It selects out DISTINCT sql.  "select * from
T" will appear there.

It is not clear to me how you are joing v$session to v$sql to get more then one
row.  If you wish to see the queries a session has open (maybe open, we cache
cursors so you might see some queries that are closed) use v$open_cursor by sid.

v$sqltext is simply a way to see the entire query.  the v$sql and v$sqlarea
views only show the first 1000 bytes.  newlines and other control characters are
replace with whitespace.

v$sqltext_with_newlines is v$sqltext without the whitespace replacment.
Review & Followup
Rating: 5
This always cunfuses me ! March 20, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Thanks for the explanation. I always confuse these views. Especially the other
day, I had problems reading past the first 1000 characters of the query, which
now I remember is solved by v$sql_text.

Rating: 5
March 21, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

Rating: 5
March 21, 2001
Reviewer: Ramesh Vasudevan from Ruwi, Sultanate Of Oman

Rating: 5
March 21, 2001
Reviewer: Ramesh Vasudevan from Ruwi, Sultanate Of Oman

Rating: 5
Makes a nice reference October 30, 2002
Reviewer: A reader from Ct, USA
Handy explanation to lookup.

March 20, 2001 Prasanna -- Thanks for the question regarding "Multiple Questions", version 8.1.6
You Asked
Hi tom,

I have 2 databases named fcc and cbr. one of the tables of fcc database is
populated to a table on cbr database. every day increment data comes, about
100000 rows. i want to insert those rows in the cbr table which has been
inserted or changed into the fcc table as of the present day.one way i find the
difference is using 'select * from fcc minus select * from cbr;' would give me
the records inserted as of today. But i feel the full table scan would slow up
the process over time. is there any other way or any procedure that you can help
me that could speed up the process.

Is there any way of estimating the size of the tables and indexes without
actually loading some data, some procedure ? what should be the estimate for the
log files for database. in my case i would have 50 tables having 50 columns and
record insertion rate into these tables would be 100000 records daily. These
insertion is done in a batch.  I have read that log files should be large so as
to prevent frequent log switch, but how large.

Is locally managed tablespace useful in oracle parallel server also?

Thanks in adv
prasanna
and we said...
1) you should use a snapshot.  It will record the changes for you and automate
this entire process. See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76959/toc.htm
for details.

Short of that either:

o add a column to the table that defaults to SYSDATE.  Now you have something to
query on (you can find all of the new rows).

o add a trigger that stores the primary key of newly inserted rows in another
table.  Now you can find the rows to insert.

o if the table is populated with a key that is generated by a sequence, simply
remember the highest sequence you have see in cbr table and fetch all rows with
a sequence higher then that.

2) sizing is done by loading a representative set of rows -- anywhere from 1/10
of 1% to 10% of the data (enough to get a reasonable set of data) and then
analyzing the data.  You then multiply the results.  In your case, just load up
100k records and analyze.  You do not need to load up the entire data set.

there are formulas but they are widely inaccurate and return the worst case
number.  The only way to really see is to load some and analyze it to see how
many rows per block you actually get and so on.

sizing of redo log files, you want the aggregate size of your log files to be
large enough to get you through your peak periods without seeing "checkpoint not
complete" in your alert.log.  the larger the individual files are -- the more
time between checkpoints, the more time to recover after a failure.  You have to
trade off between how often you want to checkpoint and how long you want it to
take to recover.  That is something you have to decide.

Locally managed tablespaces are especially useful in OPS.  they reduce
contention for space management functions greatly.
Review & Followup
Rating: 4
March 22, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

March 20, 2001 Irina -- Thanks for the question regarding "privileges using dbms_sql", version 8.0.5
You Asked
Hi, Tom.
Thank you for taking time to review my question.
I am using your function long_length  to find out the length of long field. It
goes thru compilation step , but when I execute the function I am getting
ORA-00942: table or view does not exist.
I think it has something to do with privileges but can't figure out what to do.
Please, advise...
Irina.
and we said...
You need direct SELECT on that table. See
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for the details.
Review & Followup
Rating: 3
March 22, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

March 20, 2001 Leigh -- Thanks for the question regarding "What's the best way to check if a table exists before creating it?", version 8.1.6
You Asked
Hi Tom,

I need to write a script to check if a table exists in a schema, if it does not
exist, run a cr_table.sql script then insert a row of data into it. If it does,
then just insert a row of data in it.

What is the best way to accomplish it? I am a beginner in PL/SQL.

Thanks,
Leigh
and we said...
I might have a script install.sql with the following:

-------------------------------------------------------------------------
set heading off
set feedback off
spool tmp.install
select '@cr_table.sql'
  from dual
 where not exists ( select null
                      from user_tables
                     where table_name = 'T' )
/
spool off
set feedback on
set heading on
@tmp.install
--------------------------------------------------------------------------

If table T exists, no rows will be selected.  If T does not exist, 1 row will be
selected and captured in tmp.install.  Plus will then run tmp.install.

In cr_table.sql I had:

--------------------------------------------------------------------------
create table t ( x int );
insert into t values ( 1 );
commit;
--------------------------------------------------------------------------

When I run:

tkyte@TKYTE816> @install

@cr_table.sql

Table created.

1 row created.

Commit complete.

tkyte@TKYTE816> @install
tkyte@TKYTE816>

You can see the first time it creates the table, the second time it does not.
Review & Followup
Rating: 2
March 21, 2001
Reviewer: Ravi from Dallas TX

Rating: 1
what's the best way to check if the table exists or not before creating it? March 21, 2001
Reviewer: fariha from india
can you simplify your answer

Rating: 5
Thank you, it servers what I need to do March 21, 2001
Reviewer: Leigh
Thank you, it serves the purpose that I was trying to do.

Rating: 5
March 22, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

March 20, 2001 Keith -- Thanks for the question regarding "What is the different between Application Server & File Server ?", version 8.0.5
You Asked
As I know Apllication Server is used to centralize the program. If I placed all
my programs on a File Server, then I can rollout the program as what the
Application Server done. So what is the different ?

Thanks

Keith
and we said...
You cannot put all of your programs on a file server.  That is the difference.

For example, say your program requires Net8 or any database vendors client
libraries.  These must be installed on each client as they update the registry,
set paths, and perform other customizations on the client.

then you are back into the situation described in:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:376767427785
If you only run code you write yourself in your company and never use a single
third party application, a file server might work OK.  If you use anything from
outside your company, you will be doing client installs -- unless they were
designed to run under an application server.
March 21, 2001 Sriram -- Thanks for the question regarding "Bootstrap Segment", version 8.1.6
You Asked
What is a bootstrap segment?
and we said...
It is a set of tables that tell us all about where the rest of the tables are.
sort of a data dictionary for the data dictionary.  It is in a fixed place --
like the "boot record" on a disk drive. We can always find it in a known
location.
Review & Followup
Rating: 5
What is a bootstrap segment? March 23, 2001
Reviewer: M. Elangovan from INDIA
I would like to know about what is bootstrap segment. It would be most usefule
to me.

Rating: 4
ORA-00704: bootstrap process failure May 01, 2002
Reviewer: Santosh Jadhav from India
just rnd.

i deleted obj$ on my dummy database.
while startup gives above error.

before that i even tried to delete dual table. i even dropped it successfully.

but database was working fine. except whatever i select from dual table. whats
impact of dual tabel on database.

March 21, 2001 Vrishali -- Thanks for the question regarding "regarding clob and table storage parameters", version 8.1.6.2.0
You Asked
Hi Tom,

1. How to calculate no. of rows are stored in single data block from a table if
it contains clob datatype?

2. How to calculate row length of a table if it contains clob datatype? Is
"avg_row_len" column from dba_tables calculates row length of clob column also?

3. I would like to know how to find out how much data is transfered to disk in
single I/O? I read in the documentation that I/O size = db_block_size*
db_file_multiblock_read_count.
If db_block_size=16 K and  db_file_multiblock_read_count = 64
then I/O size = 1 MB. Does that mean process waits till 1 MB data gets
accumulated then only it gets transfered in I/O operation?

4. How to decide initial and next extents of a table which contains CLOB field
with "enable storage in row" ?

Thanks
and we said...
1) no differently then a table without a clob.  The only way to estimate the
number of rows per block accurately is to load some representative data and
analyze.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:302216525000
for details.  A CLOB will be stored out of line if it exceeds 4000 bytes, inline
by default otherwise.  Make sure to load up REPRESENTATIVE rows that include
clobs of various representative sizes.

2) avg_row_len will include inline clobs.  clobs over 4000 bytes are stored out
of line in another segment.  clobs may be stored out of line under 4,000 bytes
as well if you tell us to.

3) that is how much data is transferred FROM disk when doing a multi-block read.

The data transferred to disk is typically done a block at a time by DBWR.  It
has to put block 1, 10001, 20253243, 12342141 back to disk.  It does scattered
writes all over.  Its IO size is a block.

We generally max out at 64k per IO on a read but that is OS dependent.

4) same way you would with a varchar2(4000).  Actually, I use LOCALLY MANAGED
tablespaces with UNIFORM extent sizes.  In that case, the storage parameters
initial, next, and pctincrease are pretty much ignored.  I highly recommend
then.

You would put tables into tablespaces that have a UNIFORM extent size that is
appropriate for them.  If you have a table you expect to be about 100meg, you
might pick a tablespace that has 10meg extents.  If the table was going to be
10meg, you might pick one that has 512k or 1m extents.
March 21, 2001 Alan -- Thanks for the question regarding "Which column is updated", version 8.1.6
You Asked
Hi, Tom,

I have a trigger somthing like:

create .....after update of col1,col2... on table t
---- I want to identify which column is updated:
IF :new.col1 <> :0ld.col1 OR (:new.col1 is null and :0ld.col1 is not null) OR
(:new.col1 is not null and :0ld.col1 is null) THEN
do...1;
ELSE
do....2
END IF;

My question:

Can I use "IF updating('col1') instead of the long "<> or NUll" things above? I
saw them in the docus, but it seems not working for me? Please help.

Note: the docus is :
Oracle8 i
Application Developer’s Guide - Fundamentals
Release 2 (8.1.6)
December 1999
Part No. A76939-01
---------------------- Page 500

Thanks
and we said...
It works, but it won't tell you if the VALUE changed.  Many applications update
all of the columns in a table -- setting them to their old value, rather then
trying to figure out exactly which columns have been updated by the client.
Forms does this by default for example.

Here is a simple sample:

ops$tkyte@ORA8I.WORLD> create table t ( x int, y int, z int );
Table created.

ops$tkyte@ORA8I.WORLD> create or replace trigger t_trigger
  2  after update of x,y on t
  3  for each row
  4  begin
  5          if updating( 'X' ) then
  6                  dbms_output.put_line( 'X is being updated' );
  7          end if;
  8
  9          if updating( 'Y' ) then
 10                  dbms_output.put_line( 'Y is being updated' );
 11          end if;
 12  end;
 13  /

Trigger created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 0, 0, 0 );
1 row created.

ops$tkyte@ORA8I.WORLD> update t set x = 1;
X is being updated

1 row updated.

ops$tkyte@ORA8I.WORLD> update t set y = 1;
Y is being updated

1 row updated.

ops$tkyte@ORA8I.WORLD> update t set x=1,y=1;
X is being updated
Y is being updated

1 row updated.

ops$tkyte@ORA8I.WORLD> rollback;

Rollback complete.

Now, lets try it with a check to see if the VALUES of x and y actually
changed.  Note I am using NVL() instead of the longer method above.  I am using
"-1" as the value to return when X is in fact NULL.  -1 is a value I know X will
never take on in real life so it is a "safe" value...

ops$tkyte@ORA8I.WORLD> create or replace trigger t_trigger
  2  after update of x,y on t
  3  for each row
  4  begin
  5          if ( nvl(:new.x,-1) <> nvl(:old.x,-1) )
  6          then
  7                  dbms_output.put_line( 'X is being updated' );
  8          end if;
  9
 10          if ( nvl(:new.y,-1) <> nvl(:old.y,-1) )
 11          then
 12                  dbms_output.put_line( 'Y is being updated' );
 13          end if;
 14  end;
 15  /

Trigger created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 0, 0, 0 );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> update t set x = 1;
X is being updated

1 row updated.

ops$tkyte@ORA8I.WORLD> update t set y = 1;
Y is being updated

1 row updated.

ops$tkyte@ORA8I.WORLD> update t set x=1,y=1;

1 row updated.

ops$tkyte@ORA8I.WORLD> rollback;

Rollback complete.

ops$tkyte@ORA8I.WORLD>

Now, the update of x and y to 1 together doesn't report X or Y as being updated
-- even though they were.
Review & Followup
Rating: 4
March 22, 2001
Reviewer: A reader

Rating: 5
Did column change or not change when doing an UPDATE trigger? November 19, 2001
Reviewer: Timothy Madsen from Bethlehem, PA USA
Answered my question precisely.
Thanks.

March 21, 2001 andrew -- Thanks for the question regarding "RI & performance", version 8i
You Asked
Hi

I have heared someone told me that if I am using any RI in tables, I may suffer
performance degradation while processing large amount of data, is that true?
if it is true, do you have any suggestion?
Thanx a lot
and we said...
Everything has a price.

Yes, using declaritive RI will go slower then not using it.  We must make a
check to ensure a parent record exists.  More code is executed.

However, consider the flip side.  If we do not make this check, the integrity of
your data is questionable.  You'll have child records with no parent records.
Your data is unreliable.

I've always found that the cost of having bad data is infinitely high when
compared to a little additional processing.
Review & Followup
Rating: 5
March 22, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil

Rating: 5
March 22, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil

Rating: 5
Don't forget locking ! March 22, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Don't forget to index your FK columns in the child table, to avoid performance
problems due to the locking of the entire table.

March 22, 2001 Sridevi -- Thanks for the question regarding "a Summary Column with where condition", version 6
You Asked
Product Version : Forms 6 in developer 6, Oracle 8.1.5.
Windows 98 Client, SCO Unix Server.

In my Form I have  base Table block with many columns. It is a multirecord
block.
There is a column "AMT" which is numeric and stores the amount.
Ther is another column "DRCR" which is of datatype of char(1). This DRCR column
will have either "D" or "C" as its value[referring to "DEBIT" and "CREDIT"
transactions respectively]

My requirement is as follows....
I need to show two progressive totals for the "AMT" column depending on the
value in "DRCR" column....
i.e. One Summary Column will be called "DEBIT_TOTAL" and will contain the SUM of
all Amounts where DRCR = 'D'.
Another Summary Column will be called "CREDIT_TOTAL" and will contain the SUM of
all Amounts where DRCR = 'C'.

THESE TOTALS HAVE TO BE DISPLAYED PROGRESSIVELY AS AND WHEN THE USER KEYS IN
DATA EVEN BEFORE THE TRANSACTIONS ARE COMMITED.

Can I do this directly using Summary/Formula columns? without any programming
effort?

Please Help.
and we said...
With a LITTLE code we can.  Here is what I did:

1) created a view to have a credit and debit column:

tkyte@TKYTE816> create view t_v as
  2  select amt, drcr,
            decode( drcr, 'C', amt, 0 ) credit,
            decode(drcr,'D',amt,0 ) debit
  3  from t;

View created.

2) created a DEFAULT block on that view, including the credit and debit columns.

3) set the property "precompute summaries" on that block

4) created a POST-CHANGE trigger on AMT and DRCR that has the code:

if ( :t_v.drcr = 'C' ) then
    :t_v.credit := :t_v.amt;
    :t_v.debit  := 0;
else
    :t_v.credit := 0;
    :t_v.debit  := :t_v.amt;
end if;

5) set the QUERY-ONLY property on the DEBIT and CREDIT columns (they will not be
sent as part of an insert, update statement, only READ from the database)

set the visible property to NO for these items (we cannot see them)

6) created a block "SUMMARY" with the single record property set to TRUE

7) added items CREDIT and DEBIT to this block.

I set the datatype to NUMBER for these.
DATABASE ITEM to NO for these.
calculation mode to summary
summary function SUM
block T_V
item credit or debit.

then ran the form.  That works.
Review & Followup
Rating: 3
A Reader August 15, 2002
Reviewer: A Reader from India
Its so usefull but i have some problem related with this .I have a field Amount
.I want to find the running total of this Amount only if the next check box is
checked .I tried this but i couldnt succeed .If any of this viewer knows any
suggessions pls let me know.

Amount   Process

1000     Y
2000     N
500      Y
3000
500

Total(Summary Field) = 1500

This should be keep changing as the user selects the Check box Process_YN

Thanks

March 22, 2001 Nick -- Thanks for the question regarding "RAID 10", version 8.1.7
You Asked
My company is in the process of upgrading our Oracle environment with new Sun
Solaris dedicated database servers under 8.1.7. We will be using RAID.

All the Oracle documentation I have seen refers to RAID 0+1 or RAID 5. However
some web sites are now talking about RAID 10 as the best solution for database
applications.

Can you tell me if RAID 10 is appropriate for Oracle?

Also, can you give me any info on choosing an appropriate striping size? Is it
related to db_blocksize or OS block size?

Thanks for any information you can provide.
and we said...
Raid 10:
http://www.acnc.com/04_01_10.html
is just striped arrays whose segments are raid 1 arrays.

since raid 0 is stripes -- and 0+1 is striped mirrors, raid 10 is actually 0+1

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:359617936136
...

Here is a support note on stripe size settings:

Article-ID:         <Note:106991.1>
Folder:             server.DBA.Storage
Topic:              Draft Articles
Title:              Understanding striping mechanism
Document-Type:      BULLETIN
Impact:             LOW
Skill-Level:        NOVICE
Server-Version:     08.01.0X
Updated-Date:       28-APR-2000 19:44:38
References:
Shared-Refs:
Attachments:        NONE
Content-Type:       TEXT/PLAIN
Keywords:           SIZE; STRIPE; STRIPING;
Products:           5;
Platforms:          UNIX;

*************************************************************
This article is being delivered in Draft form and may contain
errors.  Please use the MetaLink "Feedback" button to advise
Oracle of any issues related to this article.
*************************************************************

PURPOSE
-------

With this note you can learn some news about Striping Disks
mechanism by Operating System Software.

SCOPE & APPLICATION
-------------------

To get better performances in great systems and in multi-user
environments.

Understanding striping mechanism
---------------------------------

Striping divides a large table's data into small portions and stores
these portions in separate datafiles on separate disks. This permits
multiple processes to access different portions of the table
concurrently without disk contention.
Striping can either be performed manually, through careful data file
allocation to tablespaces, or through operating system striping
utilities.

In this note, we treat some news about Striping Disks mechanism by
Operating System Software.
This approach usually performs better than manual striping, specially
in not small systems and in multi-user environments.

With striping software, the concern is choosing the right stripe
size (it's often needed using a large stripe size of at least 64KB
with OS striping when possible).
This depends on the Oracle block size and disk access method.
In particular, the outstanding Oracle parameter is constituted by the
I/O size, which is given by
DB_BLOCK_SIZE * DB_FILE_MULTIBLOCK_READ_COUNT.
The values of these two parameters are fixed in init.ora file:
DB_BLOCK_SIZE specifies the size in bytes of Oracle database blocks
and its default value is operating-system dependent;
DB_FILE_MULTIBLOCK_READ_COUNT specifies the maximum number of blocks
read in one I/O operation during a sequential scan and its default
value is 8.
The maximum I/O size is platform-specific (for example, in a range of
64KB to 1MB).

Stripe size must be at least as large as the I/O size.
Having a large value of stripe size it allows the system to perform
more sequential operations on each disk, since it decreases the
number of seeks on disk, but it reduces the I/O parallelism so fewer
disks are simultaneously active.

However, if you have problems, it's preferible increasing the I/O size
of scan operations (going, for example, from 64KB to 128KB), instead of
changing the stripe size.
A good trade-off is to make stripe size larger than I/O size by a
factor of 2 or 4.

Striping supports multiple users running sequentially as well as single
users running in parallel, but it's particularly useful in optimizing
random access to tables with many rows.
In fact, for operations such as full table scan, it permits to reach
the maximum I/O throughput for your platform, because it increases
the number of disk seeks, but in the same time it consents to have a
large I/O size.
Also, for operations such as a nested loop join or parallel index
range scan, operating system striping enables you to avoid hot spots:
I/O is more evenly distributed across the disks.
March 22, 2001 -- Thanks for the question regarding "Convert Oracle Date into Unix date", version 8.1.6
You Asked
Tom,

How to Convert Oracle date into Unix date (i.e. millisecond format).

Thanks
and we said...
If by Unix date, you mean the number of seconds since jan 1st, 1970, see
http://osi.oracle.com/~tkyte/Misc/CTime.html
....
March 22, 2001 -- Thanks for the question regarding "oracle designer 6i and oracle repository 6i", version 8.1.6
You Asked
Tom:

I successfully install "Oracle Designer 6i and Oracle Repository 6i"
CD, everything is fine , except that one item is missing,
suppose we should have an item named "Oracle Designer for tutorial user" under
start->program->oracle designer6i Tutorial, but it is
simply not there,

I installed version 6 and it is there, am i wrong with the installation or that
release don't have that one?
and we said...
Sorry, I have no experience in the install of that product.  Suggest you either
use:

1) If you have support for this product, contact support.

2) if you do not, goto:
http://www.oracle.com/corporate/contact/index.html?content.html
Look for OracleInstall, they handle installation issues

3) use the technet.oracle.com discussion forums for designer.  product
management monitors those forums and should be able to help you out.
March 22, 2001 Ganesh -- Thanks for the question regarding "Will Update Result in a Slower Performance", version 7.3 to 8i
You Asked
When it Comes to Millions of Records in a Table, Does Updating the Table lead to
slower the Performance in Oracle 7.3 to 8i?

Assumptions:
1) Indexes are created For Columns in Where Clause
2) Using a Cost Based Approach.

Please also Comment On Insert's Performance Over Update.
and we said...
An update should proceed at about the same rate in any of the versions.

Comparing an inserts performance to an updates performance is like comaring an
Apple to a Toaster Oven.  Does not make sense.  They are two TOTALLY different
operations.

An insert will find free space from the freelist of an object, format data to
fit on the block, generate a tiny amount of rollback (just the rowid to delete
in the event of a rollback) and enough redo to replay the insert.

An update will have to query the table to find the row, ensure there is
sufficient space on the block for the row to fit after the update (else migrate
it), format the data to fit on the block (perhaps coalescing the data on the
block), generating enough rollback (which is logged) to UNDO the update (save
the before image of the changed columns), generate enough redo to replay the
update if need be.

they do totally different things and are not interchangable -- hence comparing
them does not make sense.
March 23, 2001 -- Thanks for the question regarding "Oracle 8.1.7 Java option", version 8.1.7
You Asked
Enterprise Edition.
--
Solaris 2.6 and Oracle 8.1.7.
Custom install option
was used. After a database instance had been created, I ran the initjvm.sql
under user SYS. It ran OK and I see the DBMS_JAVA package had been created
and it has  valid status.
So I thought the Java option has been installed successfully. But when I
select * from v$option, the result was

parameter    value
---------    -----
java         false

Does that mean Java option is not there?
Any scripts I need to run other than initjvm ?
Is there something I omitted during the custom install?

Thanks.
and we said...
Learn something new every day.

Apparently --

1) java was an option.  Hence it had a row in v$option
2) java is no longer an option.  It is always there.  Hence, the row in v$option
is always false now (8.1.6 on up)

If the flag was on -- sqlplus would print "with the java option" but since it
isn't the java OPTION anymore, that would be wrong.  So the solution was to set
the flag to false in v$option -- which is misleading....

There you go.  FALSE=TRUE....
March 23, 2001 -- Thanks for the question regarding "RBA", version 8.1.7
You Asked
What is RBA ?
What do these hex numbers mean ?
I saw this in the alert log

Oralcel 8.1.7

Mon Mar  5 21:47:26 2001
Completed checkpoint up to RBA [0x1c5.2.10], SCN: 0x0000.00047fc0
Tue Mar  6 20:45:21 2001
Beginning log switch checkpoint up to RBA [0x1c6.2.10], SCN: 0x0000.00047fd1
Thread 1 advanced to log sequence 454

thanks.
and we said...
Redo Byte Address (RBA)

An RBA points to a specific location in a particular redo thread. It
is ten bytes long and has three components: log sequence number,
block number within log, and byte number within block.
Review & Followup
Rating: 3
RBA associated with fast start checkpointing March 26, 2001
Reviewer: Y Srinivas from VA USA
After reading this answer I recollect that now checkpointing is done at the
block level (fast start checkpointing). Is the RBA address the last block used
for checkpointing?

March 23, 2001 Bhaskara -- Thanks for the question regarding "Unused Columns of a table", version 8.1.6.0.0
You Asked
Tom,
   It is possible make a column unused, so it will not be visible and
later the unused column can be dropped. Once if you make a column as UNUSED, how
to revert back to USED?
Thank you in advance,
Bhaskara
and we said...
You do not.  If you believe you need this ability -- do this instead:

1) rename table T to T_OLD;
2) create view T as select <columns you want to keep> from T_OLD;

when you are ready to really drop them, set them unused on T_OLD, drop the
unused, drop the view, rename T_OLD back to T (or just keep the view forever).

Once you mark a column unused, it is impossible to get it back.
March 23, 2001 Miladin -- Thanks for the question regarding "How to cut alert log file", version 816
You Asked
I am dealing with very large alert log files .So I would like to
archive one part of the alert file and the keep rest of it.

I am affraid that Oracle will stop writing into alert log.I had this problem
before.

Please help.

Thanks in advance.

Miladin
and we said...
Oracle always:

opens the alert in append mode
writes to it
closes it

It is safe to "mv" or rename it while we are running.  Since chopping part of it
out would be lengthly process, there is a good chance we would write to it while
you are editing it so I would not advise trying to "chop" part off -- just mv
the whole thing and we'll start anew in another file.

If you want to keep the last N lines "online", after you mv the file, tail the
last 100 lines to "alert_also.log" or something before you archive off the rest.
March 23, 2001 Stanton -- Thanks for the question regarding "Auto ORACLE installation for UNIX", version 8.1.7
You Asked

  IS there a automate install script for ORACLE 8i on UNIX and NT. We do on a
average 10 to 20 installation of ORACLE per week. I want a script or program
that will run the ./runInstaller with the correct parameter necessary
automaticaly
and we said...
Grab you copy of the OS Specific installation guide and look for the section on
non-interactive installs.

Here is the NT 8.1.7 one for example:
http://technet.oracle.com/docs/products/oracle8i/doc_library/nt_817_installguide/start/advance.htm#1028252
....
March 23, 2001 -- Thanks for the question regarding "designer version", version 8.1.6
You Asked
Tom:

I am confused by how oracle use version.

for example:
from oracle website, there are
Oracle designer 6i Release 2 for windows.
also have Oracle Designer 6i Release 2,R1.3.2 to R.60 Upgrade.

what's relationship?
am i suppose first install Oracle designer 6i Release 2 for windows
and then run Oracle Designer 6i Release 2,R1.3.2 to R.60 Upgrade?

if so , why oracle provide two of them instead of one?

by the way , my version is 6.5.40.2.0,is it the latest?
and we said...
Oracle Designer 6i Release 2 for Windows is a "brand new, don't have the product
yet" install.

Oracle Designer 6i Release 2, R1.3.2 to R.60 Upgrade  is the "i already have a
release 1.3.2 to release 6.0 version installed and would like to upgrade it to
6i" install.

6.5.40 looks very current.
March 23, 2001 Madhusudhana Rao -- Thanks for the question regarding "Oracle 7.3.4 to Oracle 8.1.7", version 7.3.4 TO 8.1.7
You Asked
Hi Tom,

Can you pls give us the steps to follow while migrating Oracle 7.3.4
to Oracle 8.1.7.

Thanks & Regards,
Madhusudhana Rao.P
and we said...
This:
http://technet.oracle.com/docs/products/oracle8i/doc_library/817_doc/server.817/a86632/toc.htm
covers the steps in some detail.

You can get that in html or pdf:
http://technet.oracle.com/docs/products/oracle8i/doc_library/817_doc/server.817/index.htm
...

Also, you'll want the install guide as well
http://technet.oracle.com/docs/products/oracle8i/doc_index.htm
...
March 24, 2001 Bhavesh -- Thanks for the question regarding "Another owa_util.listprint issue", version 4.0.8
You Asked
Hi Tom,
    Thanks a lot for your reply of my previous question on the subject topic. I
am now facing another problem with owa_util.listprint.
I know that in this procedure when we write SQL query we can define three
columns. 1st one is the value of option tag, 2nd is value what user sees and 3rd
one specifies if or not the row is marked as SELECTED.
I am having problem with defining the third column. Let us again take the same
statement follows which works fine.

owa_util.listprint('select cod_country, nam_country, '||' decode(cod_country,
''USA'', ''SELECTED'', null) from country order by
cod_country', 'p_cod_country', 1, FALSE);

Now in case of ''USA'' i want to have a parameter value SELECTED, say I want to
have SELECTED value from p_country which is already in the form how can I do
that.

owa_util.listprint('select cod_country, nam_country, '||' decode(cod_country,
p_country, ''SELECTED'', null) from country order by
cod_country', 'p_cod_country', 1, FALSE);

Thanking you in Advance.
Regards

Bhavesh
and we said...
Say you have a PLSQL variable p_country with the value you want selected in it.

You can code:

  dbms_application_info.set_client_info( p_country );

  owa_util.listPrint
  ( 'select cod_country, nam_country,
            decode( cod_country, USERENV(''client_info''), ''Y'', null )
       from country
      order by cod_country',
    'p_code_country',
     1,
     FALSE );

for example:

ops$tkyte@ORA8I.WORLD> declare
  2          p_country  varchar2(30) default 'SYS';
  3  begin
  4    dbms_application_info.set_client_info( p_country );
  5
  6    owa_util.listPrint
  7    ( 'select user_id, username,
  8              decode( username, USERENV(''client_info''), ''Y'', null )
  9         from all_users
 10        where username like ''S%''
 11        order by username',
 12      'p_code_country',
 13       1,
 14       FALSE );
 15  end;
 16  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> exec owa_util.showpage
<SELECT NAME="p_code_country" SIZE="1">
<OPTION value="3827">S
<OPTION value="2890">SAMPLEUSER
<OPTION value="13273">SB
<OPTION value="13274">SBADMIN
<OPTION value="13275">SB_ADMIN
<OPTION value="13276">SB_PUBLIC
<OPTION value="35562">SCHEDULER
<OPTION value="975">SCHED_ADMIN
<OPTION value="976">SCHED_USER
<OPTION value="34">SCOTT
<OPTION value="417">SEC
<OPTION value="10321">SECAPP
<OPTION value="1804">SEEAST
<OPTION value="887">SEMINAR
<OPTION value="3266">SENATE
<OPTION value="35567">SHARON
<OPTION value="4210">SHEPPELL
<OPTION value="2628">SITE_BUILDER
<OPTION value="40279">SITE_TRACKER
<OPTION value="469">SLEUNISS
<OPTION value="7621">SPATIAL
<OPTION value="804">SPEARSON
<OPTION value="9154">SPOT
<OPTION value="1153">SQLSTUFF
<OPTION value="1851">STATS
<OPTION value="1822">STOCKS
<OPTION value="3261">SURVEY
<OPTION SELECTED value="0">SYS   <<<<======
<OPTION value="5">SYSTEM
<OPTION value="7331">S_AND_L_ROLLUP
</SELECT>

PL/SQL procedure successfully completed.
Review & Followup
Rating: 5
Another owa_util.listprint issue March 25, 2001
Reviewer: Bhavesh
I  am short of words to express my gratitude for driving me out from deep water.
Thanks a lot Tom.

March 24, 2001 Umesh -- Thanks for the question regarding "Check fragmentation and eliminate", version 8.1.5
You Asked
Hi Tom

What is fragmentation ?
How do I check fragmenatation is present?
How do I eliminate?

Best Regards

Umesh
and we said...
search for fragmentation on my site.  you'll get about 14 hits that discuss
this.

If you use locally managed tablespaces with uniform extent sizes it is
physically impossible to have fragmentation.

If you persist in using dictionary managed tablespaces but create all objects
with initial=next and pctincrease=0 and keep all same sized objects in a
tablespace together, you'll never have fragmentation.
Review & Followup
Rating: 2
fragmentation March 24, 2001
Reviewer: Umesh Kasturi from Bangalore India
It is good but moe info needs to be packed in answer itself

March 24, 2001 Chirag -- Thanks for the question regarding "Restrict IP address to Oracle", version 8.1.6
You Asked
Hi there again,

I am tryin this out on a Windows 2000 server.
However I have my TNS_ADMIN set properly. and in the
C:\Oracle\Ora81\Network\admin I had already checked that before sending you my
first email.

In this directory I have files:
listener.ora
tnsnames.ora
protocol.ora
and snmp_ro.ora and snmp_rw.ora that agent creates
and I DO NOT USE SQLNET.ORA

Thanks
and we said...
Ok, I see now.  I did not realize you were on windows.  I found a bug, if you
create a directory %ORACLE_HOME%\net80\admin and put it (protocol.ora) in there,
it will work.  This is bug1169877, fixed in 8.1.6.3 and 8.1.7
...
Review & Followup
Rating: 2
Some more help March 25, 2001
Reviewer: Chirag Andani
Thanks heaps for your help.
Even after Remove IPC as a protocol from my listener.ora, and restarting the
listener, I can still access the database from the IP address that I have
excluded in my protocol.ora.
Do I need any other setting in my protocol.ora apart from the 4 lines I had in
the question.
There is not enough information as well which explains in brief about
protocol.ora and how to use it on the net.

Please help

Rating: 3
yes, it works in my case March 25, 2001
Reviewer: chaos from china.
i tested it and find it works fine.
oracle817 on a win2000 pro.

Rating: 5
Excellent March 26, 2001
Reviewer: Chirag
Was very useful, and thanks for your help again, I would have never figured out
that its a bug or else

March 24, 2001 Mario -- Thanks for the question regarding "SQL Hints", version 8i
You Asked
Hi Tom:

Great Column! Here is my question:

Our company uses a third party tool to develop
web-based reporting applications. The tool,
which I will not name here, makes excellent
user interfaces and autmatically generates
the SQL required for the reports (it accesses
the DB through ODBC on the web server),
which is very helpful for developers who
have only rudimentary knowledge of Oracle.

The problem lays exactly here though. The SQL
that is generated is usually quite good but there
is no way to modify it to add hints. The same queries
generated but with the addition of appropriate
hints run MUCH faster. The vendor is refusing to
add any functionality to add hints.

Are we now relegated to using the rule based
optimizer? Do you have any other ideas/suggestions
aside from buying their developers a basic book
on tuning ;-)?

Any help would be appreciated.

Regards,
Mario
and we said...
Well, I would put forth that if you analyze the tables appropriately and have
the proper init.ora parameters setup, using HINTS should in general not be
necessary.

Since you are using the RBO over CBO, I'll assume that the CBO is choosing FULL
or HASH access plans in favor over an index (since the RBO is "index happy" and
will use an index if at all possible).  If this is the case, you should look
into the init.ora parameters:

OPTIMIZER_INDEX_CACHING
OPTIMIZER_INDEX_COST_ADJ

Using these (you can play around with them at the session level to see their
effect), you can make the CBO a lot more "index happy" as well.  This will let
you take advantage of query plans that are simply NOT possible using RBO (eg: a
function based index will not be seen under RBO) and achieve plans that use
indexes more frequently.

also, look at the way you analyze tables, making sure that the statistics are up
to date and collected in the proper fashion.  For example, you might consider
something like:

analyze table T
collect statistics
for table
for all indexed columns
for all indexes
/

to gather statistics on the table, all of its indexes, and generate histograms
for the indexed columns (that will give the CBO even more information about when
to use indexes or not)...
Review & Followup
Rating: 5
March 25, 2001
Reviewer: Mario Techera from Munich, Germany

Rating: 3
Thanks for your thoughts... March 25, 2001
Reviewer: Mario Techera from Munich, Germany
Essentially, IMHO, you are correct and in fact, taht is the approach we are
currently using. The only problem with this is that all the methods are global
and will affect all queries against the tables/views. The truth is that usually
our developers have a better insight into the data and can experiment at
development time with which algorithms are best for resolving the query. The CBO
doesn't have the luxury of time to do this but then again that is why Oracle
built the hint interface... For the particularly pernicious queries we are
looking into building views where the hints are "built-in". Thanks again, Mario

March 24, 2001 Sergey -- Thanks for the question regarding "Oracle & JSP", version 8.1.7
You Asked
Hi Tom.
I have one short question to you. Could you please answer which Oracle's product
supports JSP?
and we said...
JDeveloper lets you build them.

iAS lets you deploy them in the middle tier.

Oracle8i lets you deploy them in the database if you want.

....
March 24, 2001 Khalid -- Thanks for the question regarding "JDBC -- How to bind a PL/SQL table type using JDBC?", version Oracle 8
You Asked
Dear Tom:

I have had much success with my applications using your sample code in the past.
Thank you.

This time, I am trying to pass a pl/sql table type as an OUT param, and somehow
bind it to an array using JDBC (not the latest version). My application works,
if I write my data out from pl/sql to temporary tables, and then use a
ref-cursor, but I am trying to avoid this because of the extra overhead.

Any suggestions will be appreciated.

Thanks,
Khalid
and we said...
Prior to the 8.1.7 driver -- you cannot bind to PLSQL table types from Java.  In
8.1.7 you can.

Before that you must use a SQL NESTED TABLE which are functionally equivalent.
Search for

java array

on my site for many examples.  See
http://technet.oracle.com/docs/products/oracle8i/doc_index.htm
for how this works with the 8.1.7 driver (which you could use against 8.x to get
this functionality)
Review & Followup
Rating: 5
JDBC -- How to bind a PL/SQL table type using JDBC? March 25, 2001
Reviewer: Khalid Rahim from Columbia, MD
Yes, as always, I got the answer that I wanted.

March 24, 2001 Peter -- Thanks for the question regarding "How UGA/PGA, Rollback Segment, and Context contribute to the Cursor process", version 8.1.7
You Asked
Hi Tom:

Can you give us better picture of - how UGA/PGA, Rollback Segment and context
contribute to the cursor process (implicit or explicit)?

Thanks,
Peter Cheng
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:267215452482

The cursor context (session related information) would be in the UGA and the UGA
is in the PGA in dedicated server mode or the SGA in MTS.

The rollback segment really has nothing to do with a cursor directly.  It may be
that as you are processing a result set, we will READ the rollback segment to
rollback a block that changed since your query began but there is no direct
relationship between a cursor and a rollback segment in that respect.

A cursor used for a modification (update for example) will have its changes
recorded to the rollback segment but the rbs is assigned to the transaction, not
the individual cursors therein.

I do not know what you mean by the "context".

Internally there are no differences between an implicit and explicit cursor to
Oracle -- they are the same. Implicit and explicit is wholly a "client thing".
The client (plsql for example) gives you the illusion of implicit and explicit
but under the covers they are identical to the database -- it cannot tell the
difference.  Just like with dynamic and static sql -- there is no such
difference to the database -- it is ALL dynamic sql.  client languages give the
illusion of static and dynamic sql.
Review & Followup
Rating: 4
How UGA/PGA, Rollback Segment, and Context contribute to the Cursor process March 26, 2001
Reviewer: Peter Cheng from MD USA
It gives me the better picture on cursor process and UGA.

March 24, 2001 Rama Subramanian G -- Thanks for the question regarding "Validations in a Multi-Row Block", version 6.0.5.0.2
You Asked
Hi,

I have a multi-row block with more than 10 columns.  As the user enters values
into each of these columns, I have WHEN-VALIDATE-ITEM triggers on each of these
columns for validations.  The validations on more than one column depend on the
values of the previous columns.  All is fine if the user navigates normally
starting from the left to right, top to bottom.

Suppose after entering a few rows of data in the block, the user changes a value
in a column of a row, it might or might not affect the validations on other
columns of that row.  Can you suggest the best way to handle this situation?  Is
WHEN-VALIDATE-ROW the best way or should I have flags (Control items on every
row, for every column) to check the validation status of each column?

Regards,
Rama Subramanian G
and we said...
It is up to you and the way you want YOUR interface to operate.

Me, I prefer to put the rules into the database and use POST.  Let a check
constraint catch the errors -- the database does all of the work.  These rules
MUST be in the database anyway (you have to replicate the validations you do in
the form at the database to assure yourself of integrity) so you might as well
use the database.

I would only put the minimal number of checks in the form that I needed to make
the interface pleasant (eg: if a field must be a number -- i would validate
that).  Complex intra-field validations -- i let the database do that.
March 25, 2001 Omar -- Thanks for the question regarding "milli seconds", version 8.1.6
You Asked
Hi Tom,
   Does oracle provide milli seconds with the system date, if yes how, if not
how can I distinguesh between 2 records inserted in the same second. And if you
please provide me with java code that returns a milli second.

thanks in advance
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:341817437103
for how to get this in the database.

You should not be using a DATE field as a primary key or anything.  Even to the
millisecond the probability of two records have the same value is very high (if
the chance of the same second is high, the chance of the same millisecond is
high as well).

You should use a SEQUENCE number instead.
March 25, 2001 sandeep -- Thanks for the question regarding "oracle performnace tuning", version 8.1.6
You Asked
Hi tom !

I had asked you the question regarding PCTFREE and PCTUSED parameters
for a data warehouse table. But as you said, the question was not containing
enough details. so i am asking same question again, please appologies me.

Tom, we are currently working on a datamart rather than a datawarehouse. and we
will be populating the sales table with a frequency of 2500 rows per day. This
table will expected to have one million rows in a year and we would be maintaing
this for 5 years.
Beside the inserts this table may have deletes that will be deleting and
reinserting some thousands of rows, but according to our application requirement
there will not be a single update statement against this table.
1. Now can you please suggest me  values of PCTFREE and PCTUSED for this table ?
and the space for rollback segment ?
and what is the logic/formulae for calculating the above ?

2. Again this table will be used to populate some other tables which will have
aggregated data from sales table. and offcourse when we will call report from
OLAP on this table there will be runtime aggregation.
Suppose maximum 100000 rows are going to be selected for aggregation (group by
queries) at a time then
WHAT size should be enough for temporary tablespace ?
and we said...
1) if the rows never grow, PCTFREE should remain very low.  PCTFREE is used to
save space for updates -- to allow rows to grow.  If the rows do not grow, then
we want to pack the block fully.  PCTFREE=0

For the deletes, if you want to reuse space as much as possible, would have you
set a high PCTUSED.  If you would like the block to be considered for subsequent
inserts after getting rows deleted.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
for how to analyze space usage in your segments but consider this example:

tkyte@TKYTE816> create table t
  2  ( x int, y char(2000) default 'x' )
  3  pctfree 0 pctused 99;

Table created.

Here each row will be about 2k in size (char's are always maxed out)

tkyte@TKYTE816> insert into t (x)
  2  select rownum
  3    from all_objects
  4   where rownum < 500;

499 rows created.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> exec show_space('T');
Free Blocks.............................3
Total Blocks............................128
Total Bytes.............................1048576
Unused Blocks...........................0
Unused Bytes............................0
Last Used Ext FileId....................6
Last Used Ext BlockId...................457
Last Used Block.........................64

PL/SQL procedure successfully completed.

 So I'm getting 4 rows / block (expected, I have an 8k block size... On the
free list there are only 3 blocks, only three blocks have free space left for
more inserts.  Lets delete rows 1, 5, 9, .... (the first row on each block in
theory)

tkyte@TKYTE816>
tkyte@TKYTE816> delete from t
  2   where mod(x-1,4) = 0;

125 rows deleted.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816> exec show_space('T');
Free Blocks.............................127
Total Blocks............................128
Total Bytes.............................1048576
Unused Blocks...........................0
Unused Bytes............................0
Last Used Ext FileId....................6
Last Used Ext BlockId...................457
Last Used Block.........................64

PL/SQL procedure successfully completed.

Now, as I expected every bock is on the freelist (the first block of the table
will never be there -- its part of the overhead of the table itself)

tkyte@TKYTE816>
tkyte@TKYTE816> insert into t (x)
  2  select rownum
  3    from all_objects
  4   where rownum < 100;

99 rows created.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816> exec show_space('T');
Free Blocks.............................29
Total Blocks............................128
Total Bytes.............................1048576
Unused Blocks...........................0
Unused Bytes............................0
Last Used Ext FileId....................6
Last Used Ext BlockId...................457
Last Used Block.........................64

PL/SQL procedure successfully completed.

And the inserts effectively reused that space for us.... And that is probably
what you want to achieve in a data mart.

As for sizing rollback segments, you want to ALWAYS use

o a couple of them (from 5-30 depending on the number of concurrent
transactions.  In a data mart, with low concurrent transactions 5 might be
enought)

o INITIAL=NEXT=fixed size.  All extents should be the same size

o MINEXTENTS=large number and the same number for all

o MAXEXTENTS=little larger then MINEXTENTS but not unlimited

o enough preallocated space to handle your largest set of concurrently executing
transactions (eg: if you do two sessions that each update 100meg of data, you
probably want your rollback segments to be at least 250meg each, about 2.5 times
the size of your transaction).

o enough preallocated space to hold your rollback for the life of your longest
running concurrent transaction.  If you query and update at the same time, you
want to make sure your rollback segments do not wrap around during the execution
of your query (ORA-01555 will result otherwise, search for 1555 on my site for
details).  So, if you have a query that takes 5 minutes to complete AND you are
running your updates concurrently -- you need to have enough rollback
pre-allocated so that you do not wrap around and reuse it in a 6-7 minute period
of time

o take the max of the above two -- you want that much.

2) not possible to say.  don't know how big the data you are grouping by is, how
many rows will result.  It could be that:

select x, count(*), sum(sales) from one_billion_row_table group by x;

takes 100k (there are only 5 values of X and X is a number) or 1gig (there are
500,000 values of X and X is a char(2000)).

Temp will be sized based on your data and the types of queries you do, start big
and go bigger as needed.
Review & Followup
Rating: 4
oracle 8.1.6 performnace related March 26, 2001
Reviewer: sandeep ketkar from pune (INDIA)
Hi Tom !

Thankx for the prompt and detailed reply.
The solution/guidelines provided by you are very useful to us.
Tnaks again.

Rating: 4
Table sizing May 01, 2001
Reviewer: Pichaimani from San Jose, CA, USA
Hi Tom,
   Thanks a lot for lending a helping hand at all times. Your archives are the
best source for any doubt.

March 25, 2001 Simon -- Thanks for the question regarding "Partially cloning databases using RMAN or Hot backups", version 8.1.6
You Asked
Hi Tom,

I have 2 questions hovering over my head:
1. Can I clone a source database to a target database using RMAN dumps?Assuming
that the target database is on a different server and with a differenct DB_NAME,
but on the same platform, same blocksize, same character set.
2. Using hot backups of a particular tablespace, can I restore the tablespace to
another database? Assuming both databases are of the same version and on the
same platform, same blocksize and same char set.

Any answers or hints are much appreciated!
Simon
and we said...
1) yes, there is a whole chapter on this called
Creating a Duplicate Database with Recovery Manager
in the RMAN guide:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76990/dupdb.htm#441628
2) not a HOT backup.  You can transport a tablespace using EXP and IMP.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76955/ch01.htm#40944
for details.  You can take a HOT backup, restore what you want to another
machine, detach the tablespace from that database and attach it to another
database if you do not want to have to put the primary databases tablespace into
read only mode for a moment.
Review & Followup
Rating: 3
methods of db cloning June 19, 2003
Reviewer: jianhui from DC
I dont use rman duplicate command, instead, i take a rman backup from production
and then restore it to a different host for testing. This way the DBID is the
same as production. Since i dont user catalog database, so i need to restore the
control files first then restore and recover the whole database. If using
catalog database, then the DBID should not be the same and i need to use rman
duplicate command.

There are some other methods can be used to do database level cloning, For
example, hot or cold backup without using rman.

For tablespace level or user level, exp & imp can come into play, Transportable
TBS is another good option which has better performance.

For table level, use DBlink and write PL/SQL or SQL in SQL*PLUS can do the work.

Rating: 3
rman duplicate command June 23, 2003
Reviewer: jianhui from DC
Tom,
I want to clone DB1 in HOST1 to HOST2 with different directory structure.

Following the Ch7 of the duplicate database to remote host with different
directory, i've done steps 1-5 sucessfully, but the step6 i got problem.

When I used rman duplicate to clone the database, i got the message says that
the rman is not able to find the backup or image copy of the datafiles.

I have rman backup of DB1 in HOST1 's local disk, and my allocate channel
command points the format to HOST1's local disk, RMAN also runs in HOST1.

1)So, the question is why doesnt RMAN see the backup set? Because RMAN use
target control file as repository in my case, so it knows the location of the
backup set. This location is in the same HOST1 where rman runs, so rman should
be able to find the backup set. I'm totally lost.

Besides, i also copy the backup set to HOST2, and tried to allocate the
auxiliary channel to HOST2's directory, but i got the same error message.

2) question, assume HOST2 cant see HOST1's file system, then where should i put
the backup set? The document says it should be seen by the machine where RMAN is
running.

March 25, 2001 Alfio -- Thanks for the question regarding "execute a shell command from a oracle job", version 8.1.6
You Asked
Do you know if is possible to execute a shell command (NT) like "export.exe" or
"import.exe" from a procedure that is execute in a oracle job ??
and we said...
Using a java stored procedure or a C external routine -- yes, it is easy.
see:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1101433464993
for details.

Using PLSQL straight away -- not really.  If you have cgi-bin's setup under a
webserver, PLSQL can run these programs by running a URL using UTL_HTTP.
March 25, 2001 Raja -- Thanks for the question regarding "multiple CPU", version 8.1.5
You Asked
Dear Tom ,

We have 2 CPU's in our Solaris Box running an hybrid application ( predominatly
OLTP).
Will you please give a  run through of what are all the features of Oracle 8i (
8.1.5) which we can make use of in our site for improving the performance to
take advantage of the multiple CPU .
Thank You
Raja
and we said...
Well, out of the box Oracle's multi process architecture will take full
advantage of both CPU's - architecturally speaking, it is ready to take full
advantage of both CPU's.  Your OLTP system would reap immediate benefit from
this.

On an OLTP system, using features such as parallel query would not be advised --
you are using highly tuned queries in an OLTP system as it is, they are not
massive DSS type of queries processing gigabytes of data, they are typically
keyed reads and such.

In an OLTP system, the parallel operations are typically used by a DBA to reduce
downtime and increase availability of the data.  For example, if you need to add
an index to the system -- it can be done using "parallel 4" so that there are
four processes out there building the index, not just one serial one.  You might
use 4 because while 2 of them are waiting on IO, the other two can be sorting
their results.  The DBA will be using parallel operations therefore in this to
speed up their work.

The DSS side of this system should avoid use of parallel operations as it would
give them the ability to totally take over the machine and utilize all resources
(thats the goal of PQ - to completely utilize EVERYTHING).  In a mixed
environment -- that would not be advisable.  Your DSS users would take over the
machine and starve the OLTP users of resources.

Beware however -- adding an additional CPU might make things go slower for the
majority of your users!  Sounds counter intuitive but it can happen.  Assume
your system is totally CPU bound right now.  Your OLTP users are typically IO
intensive with very little CPU needs.  Your DSS users are typically CPU
intensive and IO intensive (lots of read/compute/read/compute).  By adding more
CPU you might speed up your DSS users (thats good) but now they will really
flood the IO requests even faster (thats bad).  Your OLTP system could possibly
be negatively affected by this.  I call this the "whack a mole" principle --
named after the childs arcade game where you have a big soft hammer and the
'moles' or some other animal pop up out of holes and you have to whack them back
down.  Everytime you whack a mole, another one pops up elsewhere.  Removal of a
bottleneck may lead to a bigger bottleneck rearing its head elsewhere.  Just
food for thought.
March 25, 2001 Raja -- Thanks for the question regarding "all dependant on db bock size", version 8.1.5
You Asked
Dear Tom ,

In Oracle there are many many features that are directly dependent on the Oracle
Block size. It is scattered around in the Documentations. Can you please give an
overview  of these block size dependent items which we should consider before
deciding on the the correct Block Size ?
Thank You
Raja
and we said...
I would not say that there are many features that are dependent on this.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:329017235004
for an overview of the considerations.


Subject | Article | Last Updated (East coast time)
Clarification for Locally Managage tablespace | article only | Mar 26, 2001 12:23 am
Randolmy select the records from a table | article only | Mar 26, 2001 12:57 am
SQL Tuning | article only | Mar 26, 2001 10:04 am
History and referential integrity | article only | Mar 26, 2001 10:11 am
backup | article only | Mar 26, 2001 12:49 pm
XML file import | article only | Mar 26, 2001 05:39 pm
Moving table partitions | article only | Mar 27, 2001 08:26 am
How cursors are stored in memory? | article only | Mar 27, 2001 08:43 am
Making Unused columns Used. | article only | Mar 27, 2001 12:08 pm
Default Timezone/date grouping | article only | Mar 27, 2001 03:57 pm
SYS-owneed stored procedures and packages | article only | Mar 27, 2001 04:07 pm
Using application context in Dynamic SQL | article only | Mar 28, 2001 12:52 pm
Trigger Question | article only | Mar 28, 2001 03:13 pm
Group BY #, why same defination in Package spec and Body ? | article only | Mar 28, 2001 03:37 pm
PREFETCH | article only | Mar 29, 2001 09:13 am
updating long raw datatype | article only | Mar 29, 2001 09:40 am
Partitioned Tables | article only | Mar 29, 2001 09:46 am
Auditing package compilations. | article only | Mar 29, 2001 09:53 am
Exception processing with UTL_FILE functionality | article only | Mar 29, 2001 12:06 pm
Reading indexes | article only | Mar 29, 2001 01:14 pm
Cursor not consistent | article only | Mar 29, 2001 01:46 pm
Finding the Appropriate, Read-Consistent Block | article only | Mar 29, 2001 01:58 pm
Data segment | article only | Mar 29, 2001 01:59 pm
Character Set conversion | article only | Mar 29, 2001 03:00 pm
call form, query mode | article only | Mar 29, 2001 03:29 pm
Ordering Results In a Query that uses Union | article only | Mar 29, 2001 04:06 pm
A few Doubts | article only | Mar 29, 2001 04:10 pm
SQL query to exclude the desired column | article only | Mar 29, 2001 04:23 pm
General Question Sort | article only | Mar 29, 2001 04:26 pm
java | article only | Mar 29, 2001 09:25 pm
Grants/Rights - Reg | article only | Mar 29, 2001 10:53 pm
Regarding full export of tablespace ! | article only | Mar 29, 2001 10:58 pm
Specifying datafile block to create an object | article only | Mar 30, 2001 11:36 am
how to run a jsp page throught oracle 8i procedure | article only | Mar 30, 2001 11:17 pm
architecture whether 32-bit/64-bit | article only | Mar 31, 2001 09:34 am
trapping an invalid create table as select statement | article only | Mar 31, 2001 11:03 am
new features of 8i | article only | Mar 31, 2001 05:31 pm
Is it possible to subscribe to your questions? | article only | Mar 31, 2001 06:04 pm
One Trigger for more than one table | article only | Mar 31, 2001 11:47 pm
How to Replicate two remote database | article only | Apr 01, 2001 12:26 am
Migrating from Oracle7(VMS), Oracle8(AlphaNT) to Oracle 8i (Tru64 Unix) | article only | Apr 01, 2001 04:46 am
How to find the free space based on datafile? | article only | Apr 01, 2001 05:30 pm
Spring forward is o.k. but what happens when we Fall back? (April 1) | article only | Apr 01, 2001 09:31 pm
row(s) 1 - 43 of 43
March 26, 2001 Velayutham -- Thanks for the question regarding "Clarification for Locally Managage tablespace", version 8.1.5
You Asked
Hi Tom,

Thank you for the suggestions that you have given me.

I am having a table called HOLDING. Which is a very huge table.

The table will get updated only 1 time in 3 months.  But the insert will be
around 4 lakh records.

Is the following setting will be OK.

CREATE TABLESPACE HOLDSTMT 'c:\oradata\holding.dbf' SIZE 500M
   EXTENT MANAGEMENT LOCAL UNIFORM SIZE 8K;

CREATE TABLE HOLDING_STMT
(ID                       NUMBER(8, 0),
STATEMENT_DATE            DATE,
BRANCH_ID                 NUMBER(8, 0) NOT NULL ENABLE,
DPM_CLIENT_ID             VARCHAR2(10) NOT NULL ENABLE,
CLIENT_CATEGORY           VARCHAR2(2) NOT NULL ENABLE,
ISIN_CODE                 VARCHAR2(12) NOT NULL ENABLE,
ACCOUNT_TYPE              VARCHAR2(2) NOT NULL ENABLE,
QUANTITY                  NUMBER(15, 3) NOT NULL ENABLE,
CC_ID                     VARCHAR2(8),
MARKET_TYPE               VARCHAR2(2),
SETTLEMENT_NUMBER         VARCHAR2(7),
BL_FLAG                   VARCHAR2(1) NOT NULL ENABLE,
BL_CODE                   VARCHAR2(2),
LOCK_RELEASE_DATE         DATE)
TABLESPACE HOLDSTMT
/

My data block size is 8K.

As per your instructions I have not mentioned any storage clause in the table.

Can I follow the same logic in my creation of all the tables.

I am totally having 5 tablespace with me.

Can I give the same syntax of the tablespace which I have mentioned.

Thank You.

Regards

S. Velayutham.
and we said...
8k would be a really bad size for a table that is going to be large.

You would want the extent size for this tablespace to be around the size needed
to handle your bulk insert perhaps.  You should measure your table with a
representative amount of data in it, find out how much space you need to hold 4
lakh records, and then set the extent size to be about that big.

An 8k extent size would have this table go into hundreds of thousands of extents
which would be really not a good idea.

The idea behind locally managed tablespaces is to pick an extent size that suits
the size of the objects you put in there.  You don't need to keep anything in a
single extent but you want to have it setup so that objects use low 100's of
extents.
Review & Followup
Rating: 5
March 27, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

March 26, 2001 waseem -- Thanks for the question regarding "Randolmy select the records from a table", version 2.1
You Asked
i have two tables one have auditors and other have cases. i want to allocate the
cases to the auditors randomly + an auditor can have only five cases not more
then that.
how i can randomly select the records.

waht is the difference between oracle 7 and oracle 8?
and we said...
See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76962/toc.htm
for what is new in 8.0-8i over 7.x

In 8.x you can use dbms_random.random:

  1* select ename, dbms_random.random from emp order by 2
scott@ORA8I.WORLD> /

ENAME          RANDOM
---------- ----------
KING       -2.123E+09
TURNER     -2.115E+09
KING       -1.933E+09
WARD       -1.861E+09
JAMES      -1.777E+09
SMITH      -1.666E+09
MILLER     -1.426E+09
BLAKE      -347977364
ADAMS       902220833
ALLEN       948887828
JONES      1038058332
MARTIN     1239650092
FORD       1885560229
SCOTT      1909821649
CLARK      2128746009

15 rows selected.

scott@ORA8I.WORLD> /

ENAME          RANDOM
---------- ----------
SCOTT      -2.107E+09
FORD       -2.098E+09
MILLER     -1.574E+09
KING       -1.453E+09
WARD       -966993275
KING       -701822849
ALLEN      -445731607
SMITH        18925931
MARTIN      222644722
CLARK       878873486
ADAMS      1092686973
JAMES      1166841638
TURNER     1608416407
BLAKE      1666520984
JONES      1838111492

15 rows selected.

to order the data randomly.  In 7.x-8.x you can use a random package I have
written:

scott@ORA8I.WORLD> select ename, random.rand from emp order by 2;

ENAME            RAND
---------- ----------
SMITH            1937
FORD             5903
KING             7110
MILLER           9980
BLAKE           12493
JAMES           13865
KING            14939
ADAMS           17392
SCOTT           25382
TURNER          25441
CLARK           26186
MARTIN          26300
WARD            27843
JONES           28995
ALLEN           31798

15 rows selected.

scott@ORA8I.WORLD> /

ENAME            RAND
---------- ----------
TURNER           1205
KING             1243
CLARK            4811
ADAMS           11025
JONES           11574
JAMES           12781
SCOTT           16189
MILLER          16906
SMITH           20408
ALLEN           20903
MARTIN          22073
FORD            25422
BLAKE           29253
WARD            30405
KING            31606

15 rows selected.

to do the same.  See
http://osi.oracle.com/~tkyte/Misc/Random.html
for more info on both.
Review & Followup
Rating: 4
March 29, 2001
Reviewer: Eric Grancher from CERN, Switzerland

Rating: 4
December 10, 2002
Reviewer: Kasi Perumal from Rockville, MD USA

March 26, 2001 Mohamed -- Thanks for the question regarding "SQL Tuning", version Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production
You Asked
Hello Tom,

We have a data warehouse of financial data with lakhs of records.

1. Which is the best way of assigning storage parameters for TEMP and DATA
tablespace? Smaller Initial Extent or Larger ?
2. When I query the data using Oracle Discoverer 3.1, it normally takes between
2-5 minutes. Can you please give me some
     tuning tips? Does creation of indexes will speed up? What type of index?
The tables don't have a primary key or unique column.
3. When the extents allocated for TEMP tablespace during sorting are released?
If I run a set of sql SELECT statements as a batch file,
     will the extents allocated for a SELECT statement released immediately
after its execution?

Thanks in advance.

regards,
rafi
and we said...
1) temp should be a function of your sort area size.  You want your temporary
extents to be the same size as your sort area size as that is the unit at which
we write.

your data segments -- that is wholly a function of your table size (not
necessarily a function of row count -- a skinny table versus a fat table for
example will result in two totally different sizes at the end).  You want to
have your extents sized up so that your objects fit in a less then thousands of
extents.  A 200gig table -- that'll take 100 2 gig extents (biggestest extent
size possible).  A 500meg table, I might use 50 meg extents on that.  It depends
on how fast the data grows as well.  You don't want the tables to be extending
more then say 1 extent/month or there abouts.

2) hmmm, if I could do that with that much information -- I'd really be popular.
 The only thing I can tell you to do is to use a tool such as

TKPROF, SQL_TRACE, TIMED_STATISTICS

to analyze the performance of your queries and then  to see what kind of
indexing scheme you might want to use.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/toc.htm
for all of the details.

3) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:374218170986
...
March 26, 2001 Johan -- Thanks for the question regarding "History and referential integrity", version 8.1.6
You Asked
Tom,

In one of your answers you suggest using timestamped entries in a single table
to keep an audit trail of changes to the data, with the associated code to
translate updates and deletes into the appropriate inserts.

This sounds like a very good idea, but how would one implement this if you also
need a primary key on this table (say table A) that references a foreign key on
another table (say table B)? One could expand the existing key on A (not usable
as primary key any more, because duplicate entries are required to identify a
record uniquely) by combining it with the timestamp (for now ignoring the
problem that even this combination may or may not be unique), but then you need
to either change an associated timestamp on B when changes are made to A, or
insert a copy of the referenced record(s) in B with the timestamp used in A, or
... can you suggest an alternative ?

In a similar fashion, the problem could become even more complicated if auditing
is to be done on table B as well, or the scenario where we need, say, ten
related tables all with auditing.
and we said...
We'll, it gets quite complex as you can imagine.  It probably would not be the
correct implementation in that case.

You run into issues like:

o what do I do when I update a child record -- need i clone the parent?
o cascading updates -- yuck.

I might still use the end_date concept but I would not have that be part of the
foreign key necessarily.

You could keep a VARRAY of old data as well (or a nested table but I'm not
terribly fond of nested tables as a storage mechanism -- too many "magic"
columns happening).

Here is a small example where the history of changes for a row is kept in a
VARRAY associated with the row.  As we update, we copy all non-key columns into
a new VARRAY element.  Since varrays preserve Order, they are in the order of
modification.  The "end_date" isn't in the relational component at all.  At any
time, we can get the history at a point in time back by using the TABLE()
built-in (note this syntax is 8i specific, it can be done in 8.0 but would look
a little different)

ops$tkyte@ORA8I.WORLD> create or replace type p_type
  2  as object
  3  ( end_date   date,
  4    data      varchar2(20)
  5    -- ANY OTHER ATTRIBUTES....
  6  )
  7  /

Type created.

ops$tkyte@ORA8I.WORLD> create or replace type p_type_arr
  2  as varray(512) of p_type;
  3  /

Type created.

That will hold the history for our parent table P

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create or replace type c_type
  2  as object
  3  ( end_date  date,
  4    data      varchar2(20),
  5    data2     varchar2(20)
  6    -- any thing else....
  7  )
  8  /

Type created.

ops$tkyte@ORA8I.WORLD> create or replace type c_type_arr
  2  as varray(512) of c_type;
  3  /

Type created.

and that is for the child table C...

ops$tkyte@ORA8I.WORLD> create table  p
  2  ( x          int primary key,
  3    data       varchar2(20),
  4    history p_type_arr
  5  )
  6  /

Table created.

ops$tkyte@ORA8I.WORLD> create table  c
  2  ( x          int references p,
  3    y          int,
  4    data       varchar2(20),
  5    data2   varchar2(20),
  6    history c_type_arr ,
  7    primary key(x,y)
  8  )
  9  /

Table created.

ops$tkyte@ORA8I.WORLD> create or replace view p_view
  2  as
  3  select x, data
  4    from p
  5  /

View created.

ops$tkyte@ORA8I.WORLD> create or replace view c_view
  2  as
  3  select x, y, data , data2
  4    from c
  5  /

View created.

We do the trick with the view to HIDE the history from normal apps and so we
can inject our own update logic...

ops$tkyte@ORA8I.WORLD> create or replace trigger p_view_IO
  2  instead of update
  3  on p_view
  4  declare
  5      l_history p_type_arr;
  6  begin
  7      select     history into l_history
  8        from p
  9       where x = :old.x;
 10
 11      if ( l_history is NULL ) then
 12          l_history := p_type_arr();
 13      end if;
 14      l_history.extend;
 15      l_history(l_history.count) := p_type(sysdate,:old.data);
 16
 17      update p
 18         set data = :new.data, history = l_history
 19       where x = :old.x;
 20  end;
 21  /

Trigger created.

ops$tkyte@ORA8I.WORLD> create or replace trigger c_view_IO
  2  instead of update
  3  on c_view
  4  declare
  5      l_history c_type_arr;
  6  begin
  7      select     history into l_history
  8        from c
  9       where x = :old.x and y = :old.y;
 10
 11      if ( l_history is NULL ) then
 12          l_history := c_type_arr();
 13      end if;
 14
 15      l_history.extend;
 16      l_history(l_history.count) := c_type(sysdate,:old.data,:old.data2);
 17
 18      update c
 19         set data = :new.data, data2 = :new.data2, history = l_history
 20       where x = :old.x and y = :old.y;
 21  end;
 22  /

Trigger created.

The triggers just get the old history, add a new element, and update the row.
We could use a nested table and obviously you could use your own parent/child
HISTORY tables...

ops$tkyte@ORA8I.WORLD> insert into p_view
  2  values ( 1, 'hello' );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into p_view
  2  values ( 2, 'World' );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into c_view
  2  values ( 1, 1, 'he', 'llo' );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into c_view
  2  values ( 1, 2, 'Wor', 'ld' );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into c_view
  2  values ( 2, 1, 'How', 'Now' );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into c_view
  2  values ( 2, 2, 'Brown', 'Cow' );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> update p_view set data = 'Hello'
  2  where x = 1;

1 row updated.

ops$tkyte@ORA8I.WORLD> update p_view set data = 'HEllo'
  2  where x = 1;

1 row updated.

ops$tkyte@ORA8I.WORLD> update p_view set data = 'HELlo'
  2  where x = 1;

1 row updated.

ops$tkyte@ORA8I.WORLD> update p_view set data = 'HELLo'
  2  where x = 1;

1 row updated.

ops$tkyte@ORA8I.WORLD> update p_view set data = 'HELLO'
  2  where x = 1;

1 row updated.

ops$tkyte@ORA8I.WORLD> update c_view set data = data2, data2 = data;

4 rows updated.

The following shows the entire history for a row in a single row:

ops$tkyte@ORA8I.WORLD> select * from p
  2  where x = 1;

 X DATA  HISTORY(END_DATE, DATA)
-- ----- ------------------------------
 1 HELLO P_TYPE_ARR(P_TYPE('27-MAR-01',
         'hello'), P_TYPE('27-MAR-01',
         'Hello'), P_TYPE('27-MAR-01',
         'HEllo'), P_TYPE('27-MAR-01',
         'HELlo'), P_TYPE('27-MAR-01',
         'HELLo'))

and we can un-nest that column to look at it "relationally" as well.

ops$tkyte@ORA8I.WORLD> select p.x, p.data, h.*
  2    from p p, table( p.history ) h
  3  /

 X DATA  END_DATE  DATA
-- ----- --------- -----
 1 HELLO 27-MAR-01 hello
 1 HELLO 27-MAR-01 Hello
 1 HELLO 27-MAR-01 HEllo
 1 HELLO 27-MAR-01 HELlo
 1 HELLO 27-MAR-01 HELLo

same with C...
ops$tkyte@ORA8I.WORLD> select * from c
  2  /

 X  Y DATA  DATA2  HISTORY(END_DATE, DATA, DATA2)
-- -- ----- ------ ------------------------------
 1  1 llo   he     C_TYPE_ARR(C_TYPE('27-MAR-01',
                   'he', 'llo'))

 1  2 ld    Wor    C_TYPE_ARR(C_TYPE('27-MAR-01',
                   'Wor', 'ld'))

 2  1 Now   How    C_TYPE_ARR(C_TYPE('27-MAR-01',
                   'How', 'Now'))

 2  2 Cow   Brown  C_TYPE_ARR(C_TYPE('27-MAR-01',
                   'Brown', 'Cow'))

ops$tkyte@ORA8I.WORLD> select c.x, c.y, c.data, c.data2, h.*
  2    from c c, table(c.history) h
  3  /

 X  Y DATA  DATA2  END_DATE  DATA  DATA2
-- -- ----- ------ --------- ----- ------
 1  1 llo   he     27-MAR-01 he    llo
 1  2 ld    Wor    27-MAR-01 Wor   ld
 2  1 Now   How    27-MAR-01 How   Now
 2  2 Cow   Brown  27-MAR-01 Brown Cow
March 26, 2001 -- Thanks for the question regarding "backup ", version 8.1.6
You Asked
Tom:

our server have a tape driver attathed to it.
our database is less than 2g, and tape is about 12g.
so one tape can contain one weeks content if i backup everyday.
i don't have much experience use tape driver before, and i notice that each time
after backup something to driver, it will automatic rewind. to avoid that , i
use "tar cvf /dev/rmt/0n" instead of "tar cvf/rmt/0"

my question is ,  if i want to restore thursday's content,
what should i do?

what i did now is, to let tape go to the correct location.
I need to
1. run tar tvf /dev/rmt/0n to let tape go to monday.
2. run it again to get tuesday.
3. run it again to get wedenday.
4. run tar xvf /dev/rmt/0n to restore the content of thursday.

it works, but first 3 steps take a long time. I think maybe we
can avoid it,but don't know how. is there a better choice?

Regards,
and we said...
No, you cannot avoid it.  A tape is a sequential device, as opposed to a disk
which is a random access device.  On a tape, the ONLY way to get to the third
file is to read over the first two.

You can buy more sophisticated tape management systems.  They will leave markers
on the tape and "remember" where data begins and end.  They are similar to the
fast rewind devices you might get for your VCR.  They do not remove the problem,
they just make it go faster (but not too fast -- go to fast and you'll break the
tape right in half).

Most tape devices support a device name that enables their hardward compression
to kick in.  YOu might be able to use that to speed up the amount of tape you
must skip over.
March 26, 2001 Reji -- Thanks for the question regarding "XML file import", version 8.1.6
You Asked
Tom:
     I have a set of xml files.  I want to import into a table with CLOB field.
What would be the bext way?

Thx
Reji

More Info:  I have a DB server and the XML files are on the same machine.  I
would like to use Java or any Oracle tools if it is
possible.  I have few tables with CLOB fields and would like to
import the files into these columns.

Thx
Reji
and we said...
If the files are on the database server, by far the easiest method is simply
DBMS_LOB.LOADFROMFILE

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:232814159006
for details.
March 27, 2001 Johan -- Thanks for the question regarding "Moving table partitions", version 8.1.6
You Asked
Tom,

Is it possible to move a table partition from one tablespace to another in the
same way it is now possible to move a table from one tablespace to another ?
and we said...
Yes.

tkyte@TKYTE816> CREATE TABLE partitioned
  2  ( x int,
  3    a int default to_char(sysdate,'d')
  4  )
  5  PARTITION BY RANGE (a)
  6  (
  7  PARTITION part_1 VALUES LESS THAN(2),
  8  PARTITION part_2 VALUES LESS THAN(3),
  9  PARTITION part_3 VALUES LESS THAN(4),
 10  PARTITION part_4 VALUES LESS THAN(5),
 11  PARTITION part_5 VALUES LESS THAN(6),
 12  PARTITION part_6 VALUES LESS THAN(7),
 13  PARTITION part_7 VALUES LESS THAN(8)
 14  )
 15  /

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> insert into partitioned (x) values (1);

1 row created.

tkyte@TKYTE816>
tkyte@TKYTE816> select * from partitioned partition(part_3);

         X          A
---------- ----------
         1          3

tkyte@TKYTE816> alter table partitioned move partition part_3 tablespace users;

Table altered.

tkyte@TKYTE816> alter table partitioned move partition part_3 tablespace data;

Table altered.
Review & Followup
Rating: 5
March 28, 2001
Reviewer: A reader

Rating: 5
March 28, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

March 27, 2001 Juan Carlos -- Thanks for the question regarding "How cursors are stored in memory?", version 8.1.6
You Asked
Hi.
If I have a cursor with an ORDER BY clause that returns 10,000 rows but I'm
restricting it to 500 rows with ROWNUM, does Oracle store in memory 10,000 or
just open the cursor with 500 rows, i believe since there is an ORDER BY, Oracle
has to resolve all the rows and keep them in some area, is he release them later
when the cursor got opened for the first 500?
Thanks,
Juan Carlos Gonzalez.
ie.

SELECT empno, empnm
FROM   ( SELECT empno, empnm    -- let's say this inner query
         FROM  employee         -- will process 10,000 rows.
         ORDER BY empno )
WHERE  ROWNUM < 500;
and we said...
Well, in general, Oracle does not sort an entire result "in memory" -- consider
what would happen with:

select * from one_billion_row_table;

Oracle will generally answer the query on the fly whenever possible.  In the
above case - IF empno is INDEXED and EMPNO is NOT NULL -- the optimizer would
read the index and stop after reading 500 rows.  For example:

ops$tkyte@ORA8I.WORLD> create table emp as select object_id empno, object_name
ename from all_objects;

Table created.

ops$tkyte@ORA8I.WORLD> desc emp
 Name                                                  Null?    Type
 ----------------------------------------------------- -------- ----------------
EMPNO                                                 NOT NULL NUMBER
 ENAME                                                 NOT NULL VARCHAR2(30)

ops$tkyte@ORA8I.WORLD> create index emp_idx on emp(empno);

Index created.

ops$tkyte@ORA8I.WORLD> set autotrace traceonly

ops$tkyte@ORA8I.WORLD> select empno, ename
  2  from ( select empno, ename from emp order by empno )
  3  where rownum < 500;

499 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   COUNT (STOPKEY)
   2    1     VIEW
   3    2       TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
   4    3         INDEX (FULL SCAN) OF 'EMP_IDX' (NON-UNIQUE)

So, it starts the scan the index, accesses the table, and STOPS after 500 rows.

If you did something like:

ops$tkyte@ORA8I.WORLD> select *
  2  from ( select ename, count(*) from emp group by ename )
  3  where rownum < 500;

499 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   COUNT (STOPKEY)
   2    1     VIEW
   3    2       SORT (GROUP BY STOPKEY)
   4    3         TABLE ACCESS (FULL) OF 'EMP'

it would have to ANSWER the subquery first and then select 500 rows from it.  In
this case the temporary result set of the subquery would typically be
materialized into the temporary segments and then read back from there depending
on the size.
Review & Followup
Rating: 5
March 28, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

Rating: 5
September 26, 2001
Reviewer: Danny Lam from HK

Rating: 5
helpful explanation! September 25, 2002
Reviewer: A reader from Denver, USA

March 27, 2001 Sridevi -- Thanks for the question regarding "Making Unused columns Used.", version Oracle 8.1.5
You Asked
I happened to be going through ur Tips ad learnt that the following command
makes a column unused...
alter table table_name set unused column column_name;

I would like to know if such a column is deleted from the data dictionary . Can
we reuse this column again? if we can, then what about the data previously
stored in it [before making it unused] - will that data be retrieved?

In Short, is is possible to make an unused column used?
If not, then what is the use fo making it unused?
Cant we drop it directly?
and we said...
You cannot retrieve an unused column.  Once unused -- it is gone.

Marking a column unused is useful as a FAST way to drop a column from a big
table.

You can also drop the column, that will physically rewrite each block in the
table.  that could take a long time on a big table.

You can mark N columns UNUSED and then drop all unused as a single rewrite later
as well.
Review & Followup
Rating: 5
March 28, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

March 27, 2001 Gunjeet -- Thanks for the question regarding "Default Timezone/date grouping", version v8.1.6
You Asked
Hi Tom,

I have two questions :

1. How do I get the SYSDATE in GMT on any database server ?
I can use the new_time function to convert b/w timezones
but how do I determine the default timezone of the machine
in PL/SQL code ?
I have stored all the dates in GMT internally and if I want
to mark a record with SYSDATE, I want that date to be also
logged in GMT. How do I do that ?

2. If I gather data every 2 mins or every 5 mins, how can I
compute average every 30 mins ? It's easy to compute it
every hour by doing a group by on a date format with 'HH24',
but is there an easy way to do it every half an hour ?

Thanks in advance,

Gunjeet
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:452820143983
for how to do this in Java or C from PLSQL.

for half hour intervals one method is:

alter session set nls_date_format='dd-mon-yyyy hh24:mi';

select dt, trunc(dt,'hh24')+floor(to_char(dt,'mi')/30)*30/24/60
from
( select sysdate+rownum/24/60 dt from all_objects where rownum < 100
 )
/

that example just shows it works -- its the part in bold you are interested in.
Review & Followup
Rating: 4
Default Timezone/date grouping March 28, 2001
Reviewer: Gunjeet Singh from CA, USA
The solution was very helpful. For my env, I had
a follow-up question which I have already mailed
to you.

Thanks again.

Rating: 3
Sysdate in GMT May 04, 2001
Reviewer: conqst2001@yahoo.com
In my case unfortunately I couldn't use Java, Oracle 7.1
I guessed that oracle it self can do some translation on it, may be by using
NLS_Date_format ?

March 27, 2001 -- Thanks for the question regarding "SYS-owneed stored procedures and packages", version 8.1.7
You Asked
Oracle 8.1.7 enterprise edition
Are there any SYS-owned procedures or packages that we should not grant excute
any
to users ?
and we said...
As whether there are some that you should *not* -- that is entirely upto you.
If you do grant on the un-granted ones, make sure you know why you are granting
and what the package allows the grantee to do.

There are many that we DO NOT grant by default for various reasons.  If you are
curious, you can run the following query as SYS to see them.  I've annotated a
few:

  1  select distinct object_name
  2    from user_objects
  3   where object_name not in
  4       ( select table_name from dba_tab_privs where table_name is not null )
  5*   and object_type in ( 'PACKAGE', 'PROCEDURE', 'FUNCTION' )
sys@TKYTE816> /

OBJECT_NAME
------------------------------
DBJ_LONG_NAME
DBMS_AQADM_SYS
DBMS_AQADM_SYSCALLS
DBMS_AQ_EXP_ZECURITY             Anything with _EXP_, _IMP_ is solely for the
DBMS_AQ_IMP_ZECURITY             use of exp and imp to get these objects in and
DBMS_AQ_SYS_EXP_ACTIONS          out.
DBMS_AQ_SYS_EXP_INTERNAL
DBMS_AQ_SYS_IMP_INTERNAL
DBMS_BACKUP_RESTORE
DBMS_CRYPTO_TOOLKIT_FFI
DBMS_CRYPTO_TOOLKIT_TYPES
DBMS_DEFER_SYS
DBMS_HS_ALT
DBMS_HS_CHK
DBMS_HS_UTL
DBMS_INTERNAL_TRIGGER
DBMS_ISNAPSHOT
DBMS_OBFUSCATION_TOOLKIT    <<<=== this one you should grant to those that need
DBMS_OBFUSCATION_TOOLKIT_FFI
DBMS_ORB_CONTEXT
DBMS_PLUGTS
DBMS_PRVTAQIM
DBMS_PRVTAQIP
DBMS_PRVTAQIS
DBMS_PRVTRMIE
DBMS_RCVMAN
DBMS_REPAIR               <<<=== DBA's can run this with their privs already
DBMS_SNAP_INTERNAL
DBMS_SNAP_REPAPI
DBMS_SPACE_ADMIN
DBMS_SUMADV
DBMS_SUMREF_CHILD
DBMS_SUMREF_PARENT
DBMS_SUMREF_UTIL
DBMS_SUMREF_UTIL2
DBMS_SUMVDM
DBMS_SYSTEM               <<<=== useful for some things as well.
DBMS_SYS_ERROR
DBMS_SYS_SQL              <<<----- DON'T grant that one, I can do ANYTHING if
DBMS_ZHELP                         I have execute on this.
GET_NEXT_OBJECT_TO_COMPILE
INITJVMAUX
PBREAK
PBRPH
PBUTL
PUBLIC_DEPENCY_FUNCTION
PUBLIC_DEPENDENCY_FUNCTION
RMJVM
SUBPTXT2
SYS_STUB_FOR_PURITY_ANALYSIS
Review & Followup
Rating: 3
March 28, 2001
Reviewer: Dude from LA

Rating: 2
March 28, 2001
Reviewer: The query speed is slow from Want a faste query

March 28, 2001 Juan Carlos -- Thanks for the question regarding "Using application context in Dynamic SQL", version 8.1.6
You Asked
How performance is affected when using application context in a dynamic SQL
statement?
Is there any other method to use when you don't know how many bind variables are
in your query?

Thanks,
Juan Carlos
and we said...
Not much, if at all.

I ran:

tkyte@TKYTE816> declare
  2          l_cnt number;
  3  begin
  4          for i in 1 .. 1000
  5          loop
  6                  my_proc(i);
  7                  select count(*) into l_cnt
  8                    from all_objects
  9                   where object_id = to_number(sys_context('my_ctx','id'));
 10          end loop;
 11  end;
 12  /

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> declare
  2          l_cnt number;
  3  begin
  4          for i in 1 .. 1000
  5          loop
  6                  select count(*) into l_cnt
  7                    from all_objects
  8                   where object_id = i;
  9          end loop;
 10  end;
 11  /

PL/SQL procedure successfully completed.

A couple of times.  sometimes the bind variable was marginally faster, sometimes
sys_context -- meaning that they are pretty much the same:

SELECT COUNT(*)
FROM
 ALL_OBJECTS  WHERE OBJECT_ID = TO_NUMBER(SYS_CONTEXT('my_ctx','id'))

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.02       0.02          0          0          0           0
Execute   2000      0.36       0.36          0          0          0           0
Fetch     2000      1.70       1.80          0      39358          0        2000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total     4002      2.08       2.18          0      39358          0        2000

********************************************************************************

SELECT COUNT(*)
FROM
 ALL_OBJECTS  WHERE OBJECT_ID = :b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.02       0.02          0          0          0           0
Execute   2000      0.34       0.32          0          0          0           0
Fetch     2000      1.89       1.88          0      39358          0        2000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total     4002      2.25       2.22          0      39358          0        2000

Using DBMS_SQL is another method without using sys_context as it allows you to
procedurally bind.

Cursor_sharing=force is another way -- but I would prefer the sys_context or
dbms_sql approach over cursor_sharing as it introduces its own issues and should
be considered a crutch for poorly written programs, not as a solution.
March 28, 2001 -- Thanks for the question regarding "Trigger Question", version 8.1.6
You Asked
I have two tables: table1 and table2, and i want to create a trigger

like:
create or replace trigger trig_1
after insert on table1
....
update table2 set col1 = ....(based on sum(col2 of table1))
       where key_condition
....
Within this trigger i want to update table2. This update is based on
column1 in table1(basically on summation of column1 for table1), if i do "select
sum(col1) from table1" ---- they must be mutating.

BTW, there is not foreign key relationship and the col1 in table2, col2 in
table1 are not keys in both tables.

Can i solve that by:

0). create package pck1 as
s1 NUMBER;
key1 VARCHAR2(3);
first_date DATE;
....;

1). create or replace t_1
before insert on table1 for each row
pck1.key1 := :old.key1;
...;

2). create or replace t_1
before insert on table1
pck1.s1 := select sum(col1) from table1 where key1 = pck1.key1;
pck1.first_date := select min(col_date) from table1 where key1 = pck1.key1;
...;

3). create or replace t_1
after insert on table1 for each row
update table2 set col1 = pck1.s1 + :new.col1,
                  col_date = pck1.first_date
       where key1 = pck1.key1;
....

Is that a possible solution or are there other more efficient solution?

Thanks
and we said...
Might be time for a materialized view:

ops$tkyte@ORA8I.WORLD> create table t1 ( a int,
  2                    b int,
  3                    y number,
  4                    primary key(a,b) )
  5  /

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create materialized view log on t1
  2  with rowid ( a, y ) including new values
  3  /

Materialized view log created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create materialized view t2
  2  build immediate
  3  refresh on commit
  4  as
  5  select a, count(*), count(y), sum(y) from t1 group by a
  6  /

Materialized view created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> begin
  2      for i in 1 .. 10
  3      loop
  4          for j in 1 .. 10
  5          loop
  6              insert into t1 values ( i, j, dbms_random.random );
  7          end loop;
  8      end loop;
  9  end;
 10  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> commit;

Commit complete.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select * from t2;

         A   COUNT(*)   COUNT(Y)     SUM(Y)
---------- ---------- ---------- ----------
         1         10         10 -4.236E+09
         2         10         10 -7.931E+09
         3         10         10 2307803256
         4         10         10 1408579220
         5         10         10 -1.380E+09
         6         10         10 -1.474E+09
         7         10         10 -2.940E+09
         8         10         10 -1.749E+09
         9         10         10 4978605153
        10         10         10  -67988546

10 rows selected.

ops$tkyte@ORA8I.WORLD> select a, sum(y) from t1 group by a;

         A     SUM(Y)
---------- ----------
         1 -4.236E+09
         2 -7.931E+09
         3 2307803256
         4 1408579220
         5 -1.380E+09
         6 -1.474E+09
         7 -2.940E+09
         8 -1.749E+09
         9 4978605153
        10  -67988546

10 rows selected.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> update t1 set y = -y;

100 rows updated.

ops$tkyte@ORA8I.WORLD> commit;

Commit complete.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select * from t2;

         A   COUNT(*)   COUNT(Y)     SUM(Y)
---------- ---------- ---------- ----------
         1         10         10 4235894392
         2         10         10 7930633525
         3         10         10 -2.308E+09
         4         10         10 -1.409E+09
         5         10         10 1380031060
         6         10         10 1474167088
         7         10         10 2940467473
         8         10         10 1749008288
         9         10         10 -4.979E+09
        10         10         10   67988546

10 rows selected.

ops$tkyte@ORA8I.WORLD> select a, sum(y) from t1 group by a;

         A     SUM(Y)
---------- ----------
         1 4235894392
         2 7930633525
         3 -2.308E+09
         4 -1.409E+09
         5 1380031060
         6 1474167088
         7 2940467473
         8 1749008288
         9 -4.979E+09
        10   67988546

10 rows selected.

ops$tkyte@ORA8I.WORLD>

If that doesn't work for you, see
http://osi.oracle.com/~tkyte/Mutate/index.html
for the cookbook on how you can avoid the mutant tables
March 28, 2001 Pramod -- Thanks for the question regarding "Group BY #, why same defination in Package spec and Body ?", version 8.1.5
You Asked
1. Just Like 'Order BY number' (Order by 3), is 'Group BY number' (group by 1,2)
 is being enhanced ???

2.Why there is need to define in Package and Package Body again for
procedure/function definations ?

eg. Package p1 IS
    procedure prc(i In varchar2);
    end;

    package body p1 is
    procedure prc(i IN varchar2);
    end;
and we said...
1) not that I am aware of.

2) the spec is the specification, the external interface.  It is a forward
declare of what is to come.  It defines what will be in the body.  It is like
the table of contents for a book.

the body is the book.  Just like in a book the chapter title is repeated
verbaitim with each chapter.

It makes even more sense when you see:

create or replace package p1
as
   procedure prc( i in varchar2 );
   procedure prc( i in date );
   procedure prc( i in number );
end;
/

Now it is obvious that prc must be seen verbaitim in the body to match the right
prc with the right prc by type.
Review & Followup
Rating: 4
2. question March 29, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

March 29, 2001 Juan Carlos -- Thanks for the question regarding "PREFETCH", version 8.1.6
You Asked
Hi Tom:

Thank you very much for answering all my previous questions.

I have been trying to find a sample code of how to use the Pro*C directive
"PREFETCH" with no results yet.
Could you provide me with some of it, using it inside the program, i.e. before
opening the cursor versus in a configuration file.

Thanks again,
Juan Carlos.
and we said...
Prefetch is a new 8i feature whereby the client will automagically array fetch
for you -- you don't have to do array fetching anymore, it'll just happen.

You use it the same way you would ANY of the options for.  Typically it is used
on the command line

$ proc ... prefetch=N ...

but you can embedded it in your program like this:

main( argc, argv )
int argc;
char *  argv[];
{
exec sql begin declare section;
char  oracleid[500]="scott/tiger";
int   empno;
exec sql end declare section;

    EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();
    EXEC SQL WHENEVER SQLWARNING DO sqlerror_hard();
    EXEC SQL CONNECT :oracleid;
    exec sql alter session set sql_trace=true;

    exec sql declare c1 cursor for select empno from emp A;
    exec sql declare c2 cursor for select empno from emp B;

    exec oracle option( prefetch=5 );
    exec sql open c1;
    for( ;; )
    {
        exec sql whenever notfound do break;
        exec sql fetch c1 into :empno;
    }
    exec sql close c1;

    exec oracle option( prefetch=50 );

    exec sql open c2;
    for( ;; )
    {
        exec sql whenever notfound do break;
        exec sql fetch c2 into :empno;
    }
    exec sql close c2;

    exec sql commit work release;
}

and then to verify it worked -- I'll run tkprof on the trace file:

select empno
from
 emp A

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        3      0.00       0.00          0          3          4          15
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        5      0.00       0.00          0          3          4          15

select empno
from
 emp B

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          1          4          15
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.00       0.00          0          1          4          15

and sure enough -- the first cursor was actually fetched from 3 times for 15
rows and the second one fetched from only once since the array size was changed.
Review & Followup
Rating: 5
Multiple settting of prefetch is very interesting September 18, 2001
Reviewer: Harrison Picot from Haymarket, VA USA (Venice without the water)
Thanks Tom, resetting prefetch in the middle of the code points out an
interesting ability.  I am not sure where it will come in handy but everything
seems to.  The example is really good, a reminder of how to test. Prefetch is
definitely a valuable  tool, both for traffic reasons on high speed connections,
and time on low speed. This is much better than the documentation, which give
prefetch short shrift.

Thanks.

March 29, 2001 BMW -- Thanks for the question regarding "updating long raw datatype", version 8.1.6
You Asked
I would like to update a long raw datatype with a string. Any ideas how I can do
it?
Do I have to convert the string to raw before I do the update?

Thanks.
BMW
and we said...
In Oracle8.0 and up, you should use a LONG or LONG RAW type -- CLOBs and BLOBs
are the way to go.  Infinitely better then longs/long raws.

declare
   l_tmp  long raw;
begin
   l_tmp := utl_raw.cast_to_raw( 'How Now brown cow' );
   update t set lr_column = l_tmp where....
end;
/

will do it upto 32k in size (plsql max).

UTL_RAW might not be installed on your system -- it comes with
Oracle7.1.6 and up.  To install if you do not have it:

o cd $ORACLE_HOME/rdbms/admin
o connect as SYS or INTERNAL only using SVRMGRL
o @utlraw
o @prvtrawb.plb
Review & Followup
Rating: 5
March 29, 2001
Reviewer: A reader from OH

Rating: 5
March 30, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

March 29, 2001 Alan -- Thanks for the question regarding "Partitioned Tables", version 8.1.6
You Asked
Hi Tom,

I have a partition table, partitioned on a date column and it has an index on
that column. That table contains about 100 million rows and it could grow
rapidly. My question is that in order to minimize the table scan on that table,
I could provide a partition hint/name on the from clause to instruct Oracle to
go to the specified partition to retrieve the rows, is there any other way like
putting a hints on the query like use the partitioned index (e.g. /*+
Index(partitioned table, partition_index */) or I could put a additional WHERE
condition on the COLUMN where the partitioned was based upon?

Thanks and more power to you.

EAFS
and we said...
Oracle will automatically remove partitions whenever possible using partition
elimination.  No hinting is necessary.  If it cannot determine from the original
query that a partition could be eliminated, no amount of hinting will cause it
to do otherwise.

If your predicate allows it to use partition elimination -- it will, otherwise
it will not.
March 29, 2001 Nitin -- Thanks for the question regarding "Auditing package compilations.", version 8.1.6.0.0
You Asked
Is there a way to find out which OS user compiled a package/procedure and from
which terminal (userenv)?

Basically, we have a situation where someone in the development environment
keeps compiling the Global Package (containing Global constants) anonymously.
This renders all the dependent stored procedures (almost all of them) invalid. I
was wondering if there is any way we can catch the person compiling the Global
package? Please note that all the developers use a common Oracle user id. The
only distinguishing feature between them is their OS user id, terminal id, SID
etc.

Note: By compile I mean both "CREATE OR REPLACE' and 'ALTER ... COMPILE'.
and we said...
You could use a DATABASE "create or alter" trigger:

tkyte@TKYTE816> create table log
  2  as
  3  select cast( ' ' as varchar2(30)) xoperation,
  4         cast( ' ' as varchar2(30)) xowner,
  5             cast( ' ' as varchar2(30)) xname,
  6             cast( ' ' as varchar2(30)) xusername,
  7             sysdate timestamp,
  8             v.*
  9    from v$session v
 10   where 1=0
 11  /

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> create or replace trigger alter_trigger
  2  before create or alter on DATABASE
  3  begin
  4          insert into log
  5          select ora_sysevent,
  6                 ora_dict_obj_owner,
  7             ora_dict_obj_name,
  8                     USER,
  9                     sysdate,
 10                     v.*
 11            from v$session  v
 12           where sid = ( select sid
 13                           from v$mystat
 14                                          where rownum=1 );
 15  end;
 16  /

Trigger created.

tkyte@TKYTE816>
tkyte@TKYTE816> @do_mod
tkyte@TKYTE816> set define off
tkyte@TKYTE816>
tkyte@TKYTE816> create or replace procedure do_mod
  2  as
  3          cnt number := 0;
  4  begin
  5          dbms_profiler.start_profiler( 'mod' );
  6          for i in 1 .. 500000
  7          loop
  8                  cnt := cnt + 1;
  9                  if ( mod(cnt,1000) = 0 )
 10                  then
 11                          commit;
 12                  end if;
 13          end loop;
 14          dbms_profiler.stop_profiler;
 15  end;
 16  /

Procedure created.

tkyte@TKYTE816> set define on
tkyte@TKYTE816> alter procedure do_mod compile;

Procedure altered.

tkyte@TKYTE816>
tkyte@TKYTE816> select xoperation, xowner, xname, xusername, timestamp, osuser,
terminal
  2    from log
  3  /

XOPERATION                     XOWNER                         XNAME
------------------------------ ------------------------------
-----------------------------
XUSERNAME                      TIMESTAMP OSUSER                         TERMINAL
------------------------------ --------- ------------------------------
----------------
CREATE                         TKYTE                          DO_MOD
TKYTE                          30-MAR-01 Thomas?Kyte
TKYTE-DELL

ALTER                          TKYTE                          DO_MOD
TKYTE                          30-MAR-01 Thomas?Kyte
TKYTE-DELL

the owner of that trigger needs SELECT on v_$session and v_$mystat granted
DIRECTLY to them -- not via a ROLE.

Happy Hunting.
Review & Followup
Rating: 4
Occasional ORA-03113 errors on 9.2.0.1.0 September 22, 2003
Reviewer: Ian Weaver from Cheshire, UK
Hi Tom,

  Thanks for this handy piece if sql. I am using it to keep good tabs on the
developers.

  We have seen a few ORA-03113 errors and other sessions locking up on compiles
with debug turned on (ALTER SESSION SET PLSQL_DEBUG = true; or in plsqldeveloper
using option "add debug info when compiling").

  Changing trigger to an "after" instead of "before" seems to resolve this.

March 29, 2001 Chad -- Thanks for the question regarding "Exception processing with UTL_FILE functionality", version Oracle 7.3.3
You Asked
My current project requires me to dump data from an Oracle table to a flat file.
 I decided I would use the UTL_FILE function in PL/SQL instead of writing a
large Pro*C program.  I was able to select data from my table and export the
data into a flat file with a delimitted character.  However, one of the
requirements is to have the job fail if there was no data selected from the
table.

This leads me to the question does the use of the UTL_FILE handle the WHEN
NO_DATA_FOUND option?  I have no data in my table and it does not go into this
exception.  I am declaring a cursor which I found out does not use a
NO_DATA_FOUND so I used the IF SQL%NOTFOUND and tried to RAISE the exception,
this did not work either.  Could you please advice as to how do I get my PL/SQL
to catch an error when there is no data selected or fetched.  The following
pl/sql is the problem:  This is not perfect, I was running out of ideas and
started trying other options.

set serveroutput on
whenever sqlerror exit 2;
VARIABLE ret_status NUMBER;

DECLARE
-- Variables to write out to text file.

V_BUS_PRTNR_CODE        BUS_PRTNR.BUS_PRTNR_CODE%TYPE;
V_REPRT_NAME            BUS_PRTNR.REPRT_NAME%TYPE;
V_ST_ADDR_LINE_1        BUS_PRTNR.ST_ADDR_LINE_1%TYPE;
V_ST_ADDR_LINE_2        BUS_PRTNR.ST_ADDR_LINE_2%TYPE;
V_PR_GP_SDIV_ABBR       BUS_PRTNR.PR_GP_SDIV_ABBR%TYPE;
V_STREET_POST_CODE      BUS_PRTNR.STREET_POST_CODE%TYPE;
V_CRNCY_CODE            BUS_PRTNR.CRNCY_CODE%TYPE;
V_CRNCY_NAME            BUS_PRTNR.CRNCY_NAME%TYPE;
V_BUS_PRTNR_NAME_1      BUS_PRTNR.BUS_PRTNR_NAME_1%TYPE;
V_BUS_PRTNR_NAME_2      BUS_PRTNR.BUS_PRTNR_NAME_2%TYPE;
V_POST_OFFIC_BOX        BUS_PRTNR.POST_OFFIC_BOX%TYPE;
V_PRIM_INDIC            BUS_PRTNR.PRIM_INDIC%TYPE;
V_PLACE_CODE            BUS_PRTNR.PLACE_CODE%TYPE;
V_RECORD_STATUS         BUS_PRTNR.RECORD_STATUS%TYPE;
V_CTRY_CODE             BUS_PRTNR.CTRY_CODE%TYPE;
V_NATV_LANG_CR_NAME     BUS_PRTNR.NATV_LANG_CR_NAME%TYPE;
V_CTRY_ABBR             BUS_PRTNR.CTRY_ABBR%TYPE;
V_NATV_LANG_PL_NAME     BUS_PRTNR.NATV_LANG_PL_NAME%TYPE;
V_PR_GP_SDIV_CODE       BUS_PRTNR.PR_GP_SDIV_CODE%TYPE;
V_PR_GP_SDIV_NAME       BUS_PRTNR.PR_GP_SDIV_NAME%TYPE;
V_TRD_NAME_1            BUS_PRTNR.TRD_NAME_1%TYPE;
V_TRD_NAME_2            BUS_PRTNR.TRD_NAME_2%TYPE;
V_DIV_NAME              BUS_PRTNR.DIV_NAME%TYPE;
V_DEPT_NAME             BUS_PRTNR.DEPT_NAME%TYPE;
V_PHONE_NUM             BUS_PRTNR.PHONE_NUM%TYPE;
V_FAX_NUM               BUS_PRTNR.FAX_NUM%TYPE;
V_PO_BOX_POST_CODE      BUS_PRTNR.PO_BOX_POST_CODE%TYPE;
V_SEC_GP_SDIV_CODE      BUS_PRTNR.SEC_GP_SDIV_CODE%TYPE;
V_SEC_GP_SDIV_NAME      BUS_PRTNR.SEC_GP_SDIV_NAME%TYPE;

no_data   exception;

--Declare File Handle.

   v_MYFileHandle UTL_FILE.FILE_TYPE;

-- Cursor declaration to fetch data from table, row by row.

CURSOR c_BUS_PRTNR IS
       SELECT
        BUS_PRTNR_CODE,
        REPRT_NAME,
        ST_ADDR_LINE_1,
        ST_ADDR_LINE_2,
        PR_GP_SDIV_ABBR,
        STREET_POST_CODE,
        CRNCY_CODE,
        CRNCY_NAME,
        BUS_PRTNR_NAME_1,
        BUS_PRTNR_NAME_2,
        POST_OFFIC_BOX,
        PRIM_INDIC,
        PLACE_CODE,
        RECORD_STATUS,
        CTRY_CODE,
        NATV_LANG_CR_NAME,
        CTRY_ABBR,
        NATV_LANG_PL_NAME,
        PR_GP_SDIV_CODE,
        PR_GP_SDIV_NAME,
        TRD_NAME_1,
        TRD_NAME_2,
        DIV_NAME,
        DEPT_NAME,
        PHONE_NUM,
        FAX_NUM,
        PO_BOX_POST_CODE,
        SEC_GP_SDIV_CODE,
        SEC_GP_SDIV_NAME
FROM BUS_PRTNR
WHERE RECORD_STATUS = '10';

BEGIN
-- Open File for writing.

v_MYFileHandle :=
UTL_FILE.FOPEN('GRP_ROOT:[COMMON.CT.LOG]','VSC02P53_WEB_BUS_PRTNR_ADDR_SNAP.DAT',
'W');

--  Open the cursor.

    :ret_status := 1;

           OPEN c_BUS_PRTNR;

        LOOP

-- Get each row, one at a time.

                FETCH c_BUS_PRTNR INTO
                        v_BUS_PRTNR_CODE,
                        v_REPRT_NAME,
                        v_ST_ADDR_LINE_1,
                        v_ST_ADDR_LINE_2,
                        v_PR_GP_SDIV_ABBR,
                        v_STREET_POST_CODE,
                        v_CRNCY_CODE,
                        v_CRNCY_NAME,
                        v_BUS_PRTNR_NAME_1,
                        v_BUS_PRTNR_NAME_2,
                        v_POST_OFFIC_BOX,
                        v_PRIM_INDIC,
                        v_PLACE_CODE,
                        v_RECORD_STATUS,
                        v_CTRY_CODE,
                        v_NATV_LANG_CR_NAME,
                        v_CTRY_ABBR,
                        v_NATV_LANG_PL_NAME,
                        v_PR_GP_SDIV_CODE,
                        v_PR_GP_SDIV_NAME,
                        v_TRD_NAME_1,
                        v_TRD_NAME_2,
                        v_DIV_NAME,
                        v_DEPT_NAME,
                        v_PHONE_NUM,
                        v_FAX_NUM,
                        v_PO_BOX_POST_CODE,
                        v_SEC_GP_SDIV_CODE,
                        v_SEC_GP_SDIV_NAME;

-- Output as .txt file.
     DBMS_OUTPUT.PUT_LINE('ERROR 1 ' || to_char(SQLCODE) || SQLERRM);
                 IF SQL%NOTFOUND THEN
                        dbms_output.put_line('Error - New test');
                        raise no_data;
                 end if;

              --        EXIT WHEN c_BUS_PRTNR%NOTFOUND;

         UTL_FILE.PUT_LINE(v_MYFileHandle, v_BUS_PRTNR_CODE || '?' ||
                        v_REPRT_NAME || '?' ||
                        v_ST_ADDR_LINE_1 || '?' ||
                        v_ST_ADDR_LINE_2 || '?' ||
                        v_PR_GP_SDIV_ABBR || '?' ||
                        v_STREET_POST_CODE || '?' ||
                        v_CRNCY_CODE || '?' ||
                        v_CRNCY_NAME || '?' ||
                        v_BUS_PRTNR_NAME_1 || '?' ||
                        v_BUS_PRTNR_NAME_2 || '?' ||
                        v_POST_OFFIC_BOX || '?' ||
                        v_PRIM_INDIC || '?' ||
                        v_PLACE_CODE || '?' ||
                        v_RECORD_STATUS || '?' ||
                        v_CTRY_CODE || '?' ||
                        v_NATV_LANG_CR_NAME || '?' ||
                        v_CTRY_ABBR || '?' ||
                        v_NATV_LANG_PL_NAME || '?' ||
                        v_PR_GP_SDIV_CODE || '?' ||
                        v_PR_GP_SDIV_NAME || '?' ||
                        v_TRD_NAME_1 || '?' ||
                        v_TRD_NAME_2 || '?' ||
                        v_DIV_NAME || '?' ||
                        v_DEPT_NAME || '?' ||
                        v_PHONE_NUM || '?' ||
                        v_FAX_NUM || '?' ||
                        v_PO_BOX_POST_CODE || '?' ||
                        v_SEC_GP_SDIV_CODE || '?' ||
                        v_SEC_GP_SDIV_NAME);

                    IF SQL%NOTFOUND THEN
                        dbms_output.put_line('Error - After load');
                        raise no_data;
                 end if;
                  EXIT WHEN c_BUS_PRTNR%NOTFOUND;

        END LOOP;

-- Close Cursor
        CLOSE c_BUS_PRTNR;

        -- Close file.
        UTL_FILE.FCLOSE(v_MYFileHandle);
 EXCEPTION
 WHEN no_data THEN
    dbms_output.put_line('ERROR - NO DATA FOUND IN BUS_PRTNR');

    :ret_status := 4;
END;
/
COLUMN tmp new_value proc_value
break on tmp
SELECT :ret_status tmp FROM dual;
EXIT proc_value

Thank you....
and we said...
Well, you might just want to use the utility i have at:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:235814350980
it returns the number of rows it dumped to the file given any query....

You would just code:

ops$tkyte@8i> declare
  2      l_rows    number;
  3  begin
  4      l_rows := dump_csv( 'select *
  5                             from bus_prnt
  6                            where record_status = ''10'' ',
  7                          '?',
  8                          '/tmp',
  9                          'test.dat' );
 10      if (l_rows = 0) then raise_application_error(-20001,'ERROR');
 11      end if;
 12  end;
 13  /

Otherwise, you should just put a counter in there.  something like:

  for i in 1 .. 9999999999999999999999
  loop
      fetch c_bus_prtnr into .....;
      if ( i = 1 and c_BUS_PRTNR%NOTFOUND )
      then
          raise_application_error( -20001, 'No data found and I should have..');
      end if;
      EXIT WHEN c_BUS_PRTNR%NOTFOUND;

      ....
  end loop;
March 29, 2001 Steven -- Thanks for the question regarding "Reading indexes", version 8.0 and 8.1.6
You Asked
When accessing an index, are the reads done via single block access,
or are they accessed via multi-block reads?  If they can be accessed
via multi-block reads, what influences this behavior - i.e. init
parameters, index statistics, access path (FFS, range scan etc).
Are there any differences between 8.0 and 8.1.x?
and we said...
In a typical index range scan, the blocks are read using single block IO.  This
is because the blocks are accessed as a data structure, not just as a clump of
blocks (like a full scan of a table is).

We would read the "head" block (block 1) of the index and decide to go "right"
or "left".  Going right means we need block 10,002.  Going left means we need
block 502.  We read one of those and decide to go right or left again.  Another
random seek and read and so on.

Now, we can use an index fast full scan whereby we read the index like a table.
Here the data will not be ORDERED as it is in a index scan, rather we get the
data as we see it.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:351837928011
for more details.
March 29, 2001 -- Thanks for the question regarding "Cursor not consistent", version 8.1.6
You Asked
Hi, TOm,

Here is a example ( Note its not a puzzle, it's just something one of our
customers wrote which landed up in infinite loop in SQL server, this could
happen with Oracle too..)

This example might not be syntactically correct.. but shows what they did..this
is a part of a stored procedure (Oracle version 8.0.6 on NT)

DECLARE CURSOR Temp_work_cursor
IS
SELECT Temp_work_ID, Temp_work_level
FROM branchtemp
where Temp_work_level > 5
and temp_date between x and y;

Begin
OPEN Temp_work_cursor ;
Loop
FETCH Temp_work_cursor
INTO inOld_ID, inLevel;
EXIT WHEN Temp_work_cursor%NOTFOUND;

For date between x and y
begin
insert into branchtemp(Temp_work_ID, temp_work_level, temp_date)
values(temP_work_id_seq.nextval, 5, x);
x= x+1
end for loop;

End loop;
CLOSE Temp_work_cursor;
End ;

--------------------------------------------------
What this is doing is selecting a records from a table by opening a cursor for
perticular date range and then inserting records to the same table for that date
range.

Now my question is if the cursor fetches all the rows which satisfies the where
clause at 1st before opening it, it will not go in infinite loop right because
it will have fixed number of rows before processing ?
But if the cursor is fetching records from a table after each loop

OPEN Temp_work_cursor ;
Loop
...
...
...
End loop;

In this case it will go in infinite loop right , because the next time it
fetches records from the table it will have more records matching the condition
and so on...

Note: this is cursor technically might not make sense because I took out other
logic to make it simple.

So how doses cursor work ? Does it keep records in memory the 1st time you
declare and those are the only rows it will process or does it selects from the
table after each loop ?
and we said...
I remember doing that to myself in Sybase once upon a time ago myself.  It was
the infinite table!

I used isql to generate updates and piped that into isql.  something like:

for x in ( select * from t )
loop
   print 'update t set .... where ....'
   print 'go'
end

and piped the updates into isql.  The first row would be updated -- but that was
really a DELETE and an INSERT.  the insert (it was a non-clustered table mind
you) went the last page of course.  By the time we got to the end of the table
-- it read the first row we updated AGAIN.  After it had updated 25,000 records
(out of 5,000 rows in the table) I knew something was up.

That is PHYSICALLY impossible in Oracle.  It is only too easy in Sybase and
SQLServer.

We use a multi-versioning scheme that GUARANTEES a consistent result set.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c23cnsis.htm#17882
Basically, the results of your query are pre-ordained at the point in time you
open the query (before you fetch the first row).  We do not make a copy of this
in memory or get all of the rows or anything like that, rather we use the
rollback segments to provide consistent reads.

Read that section in the server concepts and feel free to followup on this.  One
of my favorite topics actually.  It is really something you need to understand.
It is how we provide non-blocking reads as well.
Review & Followup
Rating: 5
March 29, 2001
Reviewer: Reader from USA

Rating: 5
April 02, 2001
Reviewer: A reader

March 29, 2001 Ted -- Thanks for the question regarding "Finding the Appropriate, Read-Consistent Block", version 8.1.7
You Asked
Dear Tom:

Just want to start by saying what a great service it is you're providing to the
Oracle user community.  Your site ranks high in my list of Oracle bookmarks, as
I'm sure it does for many others out there.

My question concerns getting the appropriate, read-consistent block from a
rollback segment.  Reading the Oracle documentation has left me with merely a
fuzzy understanding of the process.  In particular, I'm wondering what happens
when a block undergoes a large number of changes via several transactions within
a short period of time.  This should leave many, point-in-time versions of the
block scattered among various rollback segments.  In that case a long-running
query will need to find the one version which was consistent at the time it
began.  How exactly does it locate it?  I imagine, if there are many
transactions operating on a block at the same time, each will create its own
rollback image, adding to the choices.  In the same vein, if the long-running
query reads one million blocks, does it have to read the latest version of each
block, examine the transaction header, discover there is a rollback segment
associated with it, then read the rollback segment header, which, after all that
I/O, may have a version of the block that is too recent?  Then what does it do
to find an older version?  And how does it even find which rollback segment to
examine, given the header in the data block?  As you can see, I'm just not clear
on this.

Does the algorithm change any when using Parallel Server?

Many thanks in advance.

Ted
and we said...
Good questions.

Basically, it'll keep rolling the block back.  It finds the current block (which
has a transaction header -- that points to the RBS) -- discovers it is too new,
rolls it back, it's still too new (but it now has restored the transaction
header to that point in time) rolls that back, still too new and so on.

A hot block like that will have its rollback in the buffer cache, meaning this
all goes pretty fast.  It is not doing IO as rollback is cached just as anything
else is.

While that sounds like a lot of work -- the alternatives are:

o give you the wrong answer.  we could just select dbms_random.random for you
instead.  many databases do this by default.  Their reads block on uncommitted
data as well (ours don't, we just roll it back)

o leave shared read locks on all data read (informix, sybase, sqlserver, db2,
etc -- they do this to provide consistent reads).  now your writes block reads
and reads block writes and your queries can and will deadlock with your
transactions.

neither of those options is very appealing...

OPS does the same thing.
March 29, 2001 gchandra -- Thanks for the question regarding "Data segment", version 8.1.6
You Asked
Hi Tom

my block size is 8K.

I just created a segment like this

SQL :> create table exam1(x varchar2(10))
  2  tablespace GCS
  3  storage (initial 64k next 64k minextents 1 pctincrease 0);

Table created.

when queried dba_segment found that initial_extent = 64k and bytes=80K.

My question is why i am getting bytes 80K , when table created above is empty.

Thanks
Gudala
and we said...
Your initial might be 64k but in a dictionary managed tablespace we round
allocations up to be multiples of 5 blocks -- hence your initial allocation is
really 10 8k blocks (80k).

There is only 1 block used in this table (table overhead, we use the first block
of every table).  The other 9 are allocated but not used.
March 29, 2001 Reji -- Thanks for the question regarding "Character Set conversion", version 8.1.6
You Asked
Tom:
   I have a DB with character set WE8ISO8859P1 and would like to
convert the DB into UTF-8.  Is it possible? if the answer is yes, how?

Thx
Reji
and we said...
Yes it is.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76966/ch3.htm#47136
for the steps.
March 29, 2001 Feroz -- Thanks for the question regarding "call form, query mode", version 6
You Asked
How do I know a form is called in NO_QUERY_ONLY or QUERY_ONLY mode, without
attempting to insert a record or update a record ?
and we said...
There is no built-in to detect whether a form invoked with call_form
is called in query-only-mode.

The simplest way to detect whether a form is running in query-only-mode
is to set a global variable before the call_form is invoked.
When all call_forms are performed via one procedure this is easily done:

procedure invoke_form
(formname in varchar2, call_type in varchar2, qmode in varchar2) is
begin
  if call_type = 'OPEN_FORM' then
    OPEN_FORM (formname);
  elsif call_type = 'NEW_FORM' then
    NEW_FORM (formname);
  elsif call_type = 'CALL_FORM' then
    if qmode = 'QUERY_ONLY' then
      :global.qmode := 'QUERY_ONLY';
      call_form (formname, HIDE, NO_REPLACE, QUERY_ONLY);
    else
      :global.qmode := 'NO_QUERY_ONLY';
      call_form (formname, HIDE, NO_REPLACE, NO_QUERY_ONLY);
    end if;
  end if;
end;
Review & Followup
Rating: 1
March 30, 2001
Reviewer: Feroz Khan from FL USA
I am currently using something like the solution you have provided. I was
thinking something better than Global variables. Anyway thank you for the help.

March 29, 2001 Thiruvaiyaru -- Thanks for the question regarding "Ordering Results In a Query that uses Union", version 8.1.6
You Asked
Tom,

I use a union in a Query and I want the query to retrieve
the results in an order where the results of the 1st query
be retrieved first and then the 2nd one be retrieved.

Here is an example :-

select x,y from z where a  between 1 and 10
union
select x,y from z where a between 30 and 40
/

Rightnow i get a mix of results from query1 and query2.
Instead i want the results of query1 to be displayed first
and then query 2.

Thanks
Sai
and we said...
Well, a UNION is really not what you want -- you want a UNION ALL.

(query 1)
union
(query 2)

is

distinct ( sort( (query 1)+(query 2) ) )

(query 1)
union all
(query 2)

is simply

(query 1)+(query 2)

Now, in your case, you want:

select 1, x, y from z where a between 1 and 10
union ALL
select 2, x, y from z where a between 30 and 40
order by 1
/
March 29, 2001 Vijay -- Thanks for the question regarding "A few Doubts", version 8.1.5
You Asked
Hi Thomas,

1. When ever any type of error is displayed by oracle, how and from where does
these messages are generated.  I mean whether these messages or stored some
where in any of the memory structures or ...

2. As far as the logbuffer size is considered what ever value u give in the
init<sid>.ora file is not considered by Oracle.  From where and how does the
value generated by Oracle is taken.  Is there any calculation for this?

3. In most of the Oracle manuals I find the message

'refer to your operating system specific documentaion'

I am not able to locat this.  where is this stored?

4. Is it possible to automate the Backup routine's using Windows NT?

5. Is there any method to download the documentaion from Technet or u  have to
select chapter by chapter and use File..Save As option from the browser?

Thanks.

With Best Regards,
Vijay.
and we said...
1) they are in compiled message files on the server.

2) thats not true.  Your value is used.  There are OS specific minimums but if
you set the log buffer really small -- you'll discover the minimum.  If you set
above the minimum -- you should see that reflected in the show sga command after
a restart.

3) it would be on the install CD.  For some platforms, it is also on
http://technet.oracle.com/
see
http://technet.oracle.com/docs/products/oracle8i/doc_index.htm
for windows, solaris, linux, hp-ux, and aix

4) yes, RMAN and OEM do that.

5) there are PDF versions of almost everything there.  Just grab the PDF
version, it'll be the whole book.

see
http://technet.oracle.com/doc/oracle8i_816/products.htm
...
March 29, 2001 Ramasamy -- Thanks for the question regarding "SQL query to exclude the desired column", version 8X
You Asked
HI,

Is there any option in a select statement to exclude the
desired column alone in a table.

Example :

SELECT * FROM DEPT will fetch me all the columns.

now can i select like

SELECT * ( excluding DEPTNO column) FROM DEPT;

I would not like to type all the columns in the select list
excluding DEPTNO column as i am doing now.

Thanks,
Ramasamy T
and we said...
In sqlplus, you can issue:

scott@TKYTE816> column deptno noprint
scott@TKYTE816> select * from dept;

DNAME          LOC
-------------- -------------
ACCOUNTING     NEW YORK
RESEARCH       DALLAS
SALES          CHICAGO
OPERATIONS     BOSTON

this works in SQLPLUS only...
Review & Followup
Rating: 4
SQL query to exclude the desired column March 30, 2001
Reviewer: Ramasamy T from Charlotte , NC USA
Hi Tom,

Thanks for your Help.
It was very useful and i got the reply soon

Rgds,
Ramasamy T

March 29, 2001 Seetharaman -- Thanks for the question regarding "General Question Sort", version Oracle 8162
You Asked
Hi Tom,

  Greetings!..

  Good to see the new FACE of Ask Tom Page.  Great going keep it up.

  1.  I want to know what is the difference between
      MERGE JOIN,
      SORT JOIN,
      NESTED JOIN.

  2.  What are types of Encryption do Oracle support?

  3.  Which one of the query is faster?  either
      1.  EXISTS , NOT EXISTS
      2.  IN
      3.  column_name = (select * from tab).  Pls explain this question in
brief.  What happens in INTERNALS.  This was the question which was in my minds
for years.

         How this query is run when there is index on some fields.

         Out of the above three which one gives good performance.

  4.  Is it possible to install Oracle on a Linux OS with Oracle Installation CD
is in a WINNT Server on a NETWORK?..  if yes how to proceed?..

  Pls help me as installation is very urgent one

TIA

regards

Seetharaman Srinivasan
and we said...
merge join

The two tables have already been sorted by key (perhaps both are indexed by key)
and they are MERGED together -- like shuffling cards in a deck.

sort MERGE join i think you mean...
In sort merge join, the two row sets being joined are sorted by the join keys,
if they are not already in key order. then they are merged.

nested LOOPS join procedurally would look like this:

  for x in ( select * from dept ) loop
     for y in ( select * from emp where emp.deptno = x.deptno ) loop
         output x+y;
     end loop;
  end loop;

you typically full scan one table, use each row to index scan into the other
table and pick up the mates.

2) dbms_obfuscation_toolkit: In Oracle8I release 2, support for single DES (Data
Encryption Standard) encryption using a 56bit key is provided.  In Oracle8I
release 3, support for both single and triple DES encryption is provided
allowing for the use of 56, 112, or 168 bit keys.

3) none of the above, all of the above.  If any of them were inherently faster,
we would not have implemented the others!

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:953229842074
for some details and guidelines.

4) If you are asking "can I install the windows binaries on linux", the answer
is NO.  If you are asking "can I stuff a linux install cd into a windows
machine, mount the cd on Linux and install" the answer is yes.
Review & Followup
Rating: 5
In and Exists March 29, 2001
Reviewer: KP from India
Excellent Reply

Rating: 4
General Question Sort", version Oracle 8162 March 31, 2001
Reviewer: Seetharaman Srinivasan from Chennai, TamilNadu, India
Hi Tom

  Your answers are always "bullseye".. perfect..

  One thing.. you said it is possible to install Oracle on Linux OS from an
Windows Network..

   Pls explain me how to do it.  I need it urgently.. or link to show the
procedures..

  Thanks a lot

Rating: 5
Can you pleas show me how to install it thro' Windows ? excessed ? September 25, 2002
Reviewer: A reader

Rating: 5
Can you pleas show me how to install it thro' Windows ? excessed ? September 25, 2002
Reviewer: A reader

March 29, 2001 -- Thanks for the question regarding "java", version 8.1.6
You Asked
after i loadjava, can i retrieve the source code somehow?

like after i create procedure, i can use user_source to retrieve
source code.

i tried loadjava ...    something.java.
and found the source code at user_source.
and we said...
see dbms_java:

-- convenience functions to support development environments --
-- There procedures allow PL/SQL to get at Java Schema Objects.
-- There are a lot of them, but they can be understood from the
-- grammar
--     export_<what>(name, [schema,] lob)
--
-- <what> is either source, class or resource
-- name a varchar argument that is the name of the java schema object
-- schema is an optional argument, if it is present it is a varchar that
--   names a schema, if it ommitted the current schema is used
-- lob is either a BLOB or CLOB.  The contents of the object are placed
--   into it. CLOB's are allowed only for source and resource (i.e. not
--   for class). Note that the internal representation of source uses
--   UTF8 and that is what is stored into the BLOB

33. PROCEDURE export_source
        (name varchar2,
         schema varchar2,
         blob BLOB) as language java name
      'oracle.aurora.rdbms.ExportSchemaObjects.exportSource(java.lang.String,
java.lang.String, oracle.sql.BLOB)'

34. PROCEDURE export_source
        (name varchar2,
         blob BLOB) as language java name
      'oracle.aurora.rdbms.ExportSchemaObjects.exportSource(java.lang.String,
oracle.sql.BLOB)';

35. PROCEDURE export_source
        (name varchar2,
         schema varchar2,
         clob CLOB) as language java name
      'oracle.aurora.rdbms.ExportSchemaObjects.exportSource(java.lang.String,
java.lang.String, oracle.sql.CLOB)';

36. PROCEDURE export_source
        (name varchar2,
         CLOB clob) as language java name
      'oracle.aurora.rdbms.ExportSchemaObjects.exportSource(java.lang.String,
oracle.sql.CLOB)';
March 29, 2001 Patibandla -- Thanks for the question regarding "Grants/Rights - Reg", version 8.1.6.0
You Asked
1. i am having user u1
   with  table t1 and views v1,v2,v3 on table t1

   I granted selected on t1,v1,v2,v3 to user u2.

   Now once i revoke  rights on t1, rights on all the objects
   associated   with t1 should be revoked can it be done.

Regards

Koshal
and we said...
Only if you revoke them yourself. There is no relationship between having a
privilege on T1 and having a priv on a view of T1.

It would be bad if there was.  One of the #1 major use of a view is to provide
access to parts of the underlying table T1 without granting access to T1 itself.

You'll need to revoke on V1, V2, V3 manually.
March 29, 2001 OP -- Thanks for the question regarding "Regarding full export of tablespace !", version 8.1.6.0
You Asked
Hi Tom,

How are you.

This Quest of mine is somewhat in relation with the previous
one.

Consider I have 2 differnt Database servers where D1 and
D2 are the database names.

D1 has a tablespace TS1 which contains the data for the
user TUSER1.

The tablespace TS1 is not existing in the Database D2.
Nor the user TUSER1 is existing in the database D2.

Quest
=====

1) I need to have the tablespace TS1 in D2 of the same
size containing the same objects from D1.

Do I need to manually give create tablespace command
in D2 to create this tablespace or I can excport
the complete tablespace from D1 and import it completely
in D2 without issue the create tablespace command.

2) Is it compulsory that the user TUSER1 should exits
in the D2 database or is it possible that after
import in D2 ,I can make user TUSER2 and assign him
suffiecient previleges to access all the objects from the
tablespace TS2.

Thanks and Regards
OP Lalwani
and we said...
1) you do not need to create the tablespace in most cases.  You will import into
some user using the

FROMUSER=TUSER1 TOUSER=some_user_at_d2

the objects will be created in that users default tablespace.

Multi-segment objects (IOT's with overflows, tables with LOBS, partitioned
tables, etc) are special cases however.  In this case, the objects won't be
imported into the users default tablespace -- they will fail.  In this case, the
solution is to precreate the objects:

imp userid=u/p tables=TABLE_THAT_NEEDS_TO_BE_CREATED indexfile=temp.sql

edit temp.sql and fix up the tablespaces in the CREATE TABLE statement and run
it.  Then, imp ... IGNORE=Y, to ignore object creation errors.

2) No, TUSER1 does not need to exist.  You would do a FROMUSER TOUSER to get the
objects into the other account.
Review & Followup
Rating: 5
Tablespace Export ! March 31, 2001
Reviewer: OP Lalwani from INDIA
Yes,apart from answering the Quest very
precisely,a very useful additional
information is also being given about
Table with LOB columns and Partitioned
tables which I never thought of.

Yes Tom you really corelate things with
maximum probabilities.

Thanks and Regards
OP

March 30, 2001 andre -- Thanks for the question regarding "Specifying datafile block to create an object", version 816
You Asked
Is there any way to specify the datafile block where to create an object ( Index
/ Table ) ?
This would be good, to avoid tbspace fragmentation.
and we said...
No there is not (and no it wouldn't), and if you use locally managed tablespaces
with uniform extents, it is not an issue whatsoever.

Fragmentation is impossible in that type of tablespace.

Fragmentation is caused by using initial != next and pctincrease != 0.  it has
nothing to do with where the initial extent for an object starts.

In a locally managed tablespace, initial=next and pctincrease=0 and no one can
get around that.
March 30, 2001 parin -- Thanks for the question regarding "how to run a jsp page throught oracle 8i procedure", version 8i
You Asked
My Question is that everyday at a specific time say 6.00 in the morning or any
other time i want to invoke a jsp page from oracle procedure
is it possible to make a procedure run by itself at a specific time and if yes
then how and can i invoke a jsp page throught oracle procedure

please explain me with suitable example
and we said...
DBMS_JOB is the procedure you want to use to schedule the job
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/dbms_job.htm#999107
and UTL_HTTP is the procedure you want to use to execute the jsp
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/utl_http.htm#998100
...
March 31, 2001 ravindranath -- Thanks for the question regarding "architecture whether 32-bit/64-bit", version 8.1.5
You Asked
Tom,

Is there any way to check the architecture of Oracle whether it is 32-bit/64-bit
for Oracle 8.1.5 version.

Thank you in anticipation,

Ravindranath.
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:364418037604
...
March 31, 2001 Bryan -- Thanks for the question regarding "trapping an invalid create table as select statement", version 8.1.x
You Asked
I have a 3rd party application which is failing with a SQL error -invalid
statement.  I need to trap the statement so I can figure out what is configured
incorrectly.  As this is a DDL statement it isn't in v$sqlarea, right?  How do I
find out what it is?
and we said...
If you set SQL_TRACE on -- either by getting the application to issue:

alter session set sql_trace=true;

or by using dbms_system.set_sql_trace_in_session
or by setting SQL_TRACE=TRUE in the init.ora and tracing all sessions.

we can see this in the trace file.  Consider:

tkyte@TKYTE816> alter session set sql_trace=true;
Session altered.

tkyte@TKYTE816> create table t ( x this is bad int );
create table t ( x this is bad int )
                        *
ERROR at line 1:
ORA-00907: missing right parenthesis

tkyte@TKYTE816> @gettrace
tkyte@TKYTE816> select c.value || '\ORA' || to_char(a.spid,'fm00000') || '.trc'
  2    from v$process a, v$session b, v$parameter c
  3   where a.addr = b.paddr
  4     and b.audsid = userenv('sessionid')
  5     and c.name = 'user_dump_dest'
  6  /

C.VALUE||'\ORA'||TO_CHAR(A.SPID,'FM00000')||'.TRC'
--------------------------------------------------------------------------------

C:\oracle\admin\tkyte816\udump\ORA00776.trc

tkyte@TKYTE816> edit C:\oracle\admin\tkyte816\udump\ORA00776.trc

Looking in the trace file i can see:

=====================
PARSE ERROR #3:len=38 dep=0 uid=220 oct=1 lid=220 tim=6385920 err=907
create table t ( x this is bad int )
Review & Followup
Rating: 4
April 01, 2001
Reviewer: Pauline from U.S.A

Rating: 5
April 02, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

March 31, 2001 hasan tonguc -- Thanks for the question regarding "new features of 8i", version 8.0.5.1
You Asked
I am migrating my 8.0.5.1 db to 8.1.7 and looking for some new features for
performance and availability issues at both develoment & administration sides,
here are some of them i really like, but is there a document which explains all
of these new features ?..
thanx

Export with the where clause
Simplified dynamic SQL
Bulk binds
Nocopy
Rollup, Cube, Top N
Temporary tables
Log Miner
Materialized views
Partitioning
Function-based indexing
Locally MAnaged Tablespaces
and we said...
http://technet.oracle.com/doc/oracle8i_816/server.816/a76962/toc.htm
the "getting to know" guide has all of that.  And the

http://technet.oracle.com/docs/products/oracle8i/doc_library/817_doc/addendum.817/a85455/toc.htm
8.1.7 doc addendum
Review & Followup

      Rating:
      4
  March 31, 2001
Reviewer:
      A reader  from turkey

      Rating: 3
from
      India  April 02, 2001
Reviewer:  srinivas
       from India
hi Tom..,
i have been trying to use loadjava command in oracle 8.1.5 and getting the
following error.

loadjava command issued:
loadjava -u sys/change_on_install -o -r -v -g public Sample.class

initilization complete
loading  : Sample
creating : Sample
Error while creating class Sample
    ORA-00922: missing or invalid option

resolver:
Error while resolving class Sample
    ORA-00904: invalid column name

loadjava: 2 errors

java class file
import java.io.*;
public class Sample{
  public Sample(){
  }
  public int method(){
    return 21;
  }
}

can u plz help me out...
Thanx and regards
Srinivas

March 31, 2001 Andrew -- Thanks for the question regarding "Is
      it possible to subscribe to your questions?", version 8

      You Asked
Tom,

I am enjoying your page very much. Is it possible to subscribe to your
Question/Answers? So they mailed to my address as you publish them?

Andrew Lapides

      and we said...
No, I'm afraid thats a bit more then I want to do.  Trying to push that much
email and making sure I don't flood someone by accident and setting up the "add
me", "remove me" stuff, dealing with bounced emails and so on is something I
really don't want to tackle.

I can suggest however that you visit:

http://asktom.oracle.com/pls/ask/f?p=4950:6
once a week.  That has all the published stuff in one big page by week.  You can
just run a week behind and have them all to read at your leisure.
Review &
      Followup

      Rating:
      5
  March 31, 2001
Reviewer:  Andrew
      Lapides  from Calgary Canada
this is even better than email!

the only thing if i could suggest that you publish this link on your main page
(so to avoid similar Question from someone else)

      Rating:
      3
  April 29, 2001
Reviewer:  amol
      joshi  from Stockholm,Sweden
Was Looking for this kind of solution for a long time
and i fully agree with the headaches of mailing -lists.

March 31, 2001 Omar -- Thanks for the question regarding "One
      Trigger for more than one table", version 8.1.6

      You Asked
Hi Tom,

Q1.  I need to build a DB trigger that fires when more than one table is updated
 , what I mean I need to perform the same action when more than one table is
updated and I don't want to write the same code more than once ,is there anyway
way to implement this functionality.

Q2. Is it common to use a date data type column as a primary or as a
field in a primary key , if not why.

      and we said...
q1) you would put the necessary code/logic into a packaged procedure or just a
standalone procedure.

The for each table you wanted this functionality to occurr for, you would create
a trigger that calls this procedure.

q2) it would be highly ill advised to use the date data type as a primary key.
As PART OF a primary key -- maybe (but does not make sense to me)

If you use it as a primary key, you will have issues as only one row per second
can be inserted.  If you make it part of a primary key -- you have to give
something unqiue for the second part so the date would be redudant in that key.

A better key for you will be a NUMBER column that is populated by a sequence.  A
sequence is a highly scalable, nonblocking, surrogate key generator.
Review &
      Followup

      Rating:
      4
  April 01, 2001
Reviewer:  Pauline
       from U.S.A

      Rating:
      4
  April 01, 2001
Reviewer:  Pauline
       from U.S.A
For the answer of Q1, if give the smaple will be great.

      Rating:
      5
Q2  April 02, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

April 01, 2001 Bernard -- Thanks for the question regarding "How
      to Replicate two remote database", version 8.1.6

      You Asked
Mr. Tom,

I have two database at two remote locations.  I have to move the data from
selected table of one database to another daily.  I have couple idea in my mind,
can you tell me which should work better:

1) Export the tables of one database then ftp the file to the other server.
Then import those data into the other database. (we can use cron job :-) )

2) We can create a DB link between two database and update the second database
daily.

3) Setup a gateway server and let them communicate each other.

Or do you have any better idea please?

Thanx

Bernard Ho

      and we said...
How about:

- create a database link.
- optionally create a snapshot log on the master copy (for changes only refresh
  if that is what you want)
- create a snapshot at the site that needs a copy.

done.  See

http://technet.oracle.com/doc/oracle8i_816/server.816/a76959/toc.htm
for details on snapshots.  These are part of Standard & Enterprise edition

Review &
      Followup

      Rating:
      5
  April 02, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

April 01, 2001 Javed -- Thanks for the question regarding
      "Migrating from Oracle7(VMS), Oracle8(AlphaNT) to Oracle 8i (Tru64 Unix)",
      version 8.1.7

      You Asked
I have two production databases on two Alpha/4100 machines. The first one 40 GB
Oracle7.3.3.6 is on Alpha OpenVMS 7.2 (200 users) and the second one 25 GB
oracle 8.0.5 is on Alpha Windows NT 4 (350 users). Oracle7 is running the Oracle
Applications release 10.7 and Oracle8 is running varios in-house developed
applications. Morever two test databases simulating the production environment
with a few GBs.

My objective is to migrate to Oracle 8.1.7 on Tru64 Unix and cut down the
databases to single production and a test and introduce a middle tier acting as
the Application Server.

Please advise your recommendations in this situation.

      and we said...
Moving the in house stuff -- piece of cake, you control it, you can fix it

The APPS have me concerned.  8.1.7. is probably a big "no go" with 10.7 apps --
not supported/supportable.  I asked someone who knows more about this then me
and they said:

Tom,

A couple of things on this one.

First, Oracle has an upgrade program through Oracle Services:

http://www.oracle.com/consulting/offerings/implementation/index.html?11iupgrade.html
Also, there are a number of notes out on Metalink that they should probably take
a look at including:

Note:117539.1  -  this note references a few others.

I would also go to AppsNet -
http://appsnet.oracle.com/
  and take a look at the
11.5.3 upgrade documentation to get an idea of what it takes to perform such an
upgrade.

However, in general what I would do to actually work this issue is to install
Oracle Apps 10.7 on Tru 64 Unix first and then export/import my database from
the VAX systems.  This gets you over to the Unix side of the house quickly while
maintaining the system that you are the most familiar with - 10.7.  At that
point, you could intheory patch the system up to the same level as the VAX side
to make sure things are working correctly.  It really depends upon the number of
custom objects they have in their system and number of patches.  If he wants to
stay on 10.7 he can, but he'll need to run both 7.3 and 8.1.6 - not a big deal,
just don't blow away the older code tree.

At that point, I would upgrade to R 11.5.3 (or 4 which is due out soon).

I checked certify and you are correct, 8.1.6 is the latest version of the RDBMS
that is supported with the Apps.

Hope that helps a bit.

Review &
      Followup

      Rating:
      3
  April 02, 2001
Reviewer:  Javed
      Jadoon  from Jeddah, Saudi Arabia

April 01, 2001 pauline -- Thanks for the question regarding "How
      to find the free space based on datafile?", version 8.1.5

      You Asked
Tom,
Usually I use script to find the free space based on the tablespace.But it seems
like much more difficult to find how many free space left for each datafile in
one tablespace.

Your help will be appreciated.

Pauline

      and we said...
tkyte@TKYTE816> select tablespace_name, file_id, sum(bytes)
  2  from dba_free_space
  3  group by tablespace_name, file_id;

of course you could join to get the file name as well.

followup to comment below:

Well, you asked how to find the free space left in each datafile -- thats what
the above does.  If you want to know zero byte files as well -- we can use
something like this:

  1  select tablespace_name,
  2        file_name,
  3       (select nvl(sum(bytes) ,0 )
  4              from dba_free_space b
  5          where b.file_id = a.file_id ) free_bytes
  6*  from dba_data_files a
ops$tkyte@DEV816> /

TABLESPACE_NAME                FILE_NAME                      FREE_BYTES
------------------------------ ------------------------------ ----------
SYSTEM                         /d01/oradata/ora816dev/system0  133865472
                               1.dbf

UTILS                          /d02/oradata/ora816dev/utils.d    8814592
                               bf

RBS_TS_01                      /d01/oradata/ora816dev/rbs_ts_          0
                               01.dbf
......
Review
      & Followup

      Rating: 4
Oracle DBA
        April 03, 2001
Reviewer:  Pauline
       from U.S.A
If the tablespace has 3 datafiles and first 2 datafiles are
already filled up, this query won't show 0 bytes left for
them.

April 01, 2001 Harrison -- Thanks for the question regarding
      "Spring forward is o.k. but what happens when we Fall back? (April 1)",
      version 8.1.7

      You Asked
Hi Tom:

On my Sun box, time jumped forward this morning, so Oracle
was at 2am, and then it was 3am (I may have hours messed up,
it may start at 3).  So far so good, but what happens when the
time falls back an hour this Fall, does Oracle care that
something that happened at (say) 2:30am, can be followed by
something at 2:15am, forty-five minutes later?  I actually
may have seen this discussed in a point-in-time recovery, and I
know it happens every year to millions of transactions, but I
am curious how (I am guessing) system change numbers or row
numbers can keep these transactions straight. Also, what
are other downsides to setting a server's clock backwards? How
about logs?

Cheers,

Harrison

      and we said...
Oracle uses an internal clock -- the system change number (SCN).  We really
don't care what time it is externally as far as anything goes.

The only place where this might have an effect is during a POINT IN TIME
RECOVERY where you use "recover until <time>".  If we are doing the "fall back"
then there are two 1:30 AM's.  If you recover until 2:30am, we recover until the
FIRST 1:30 AM.  If you need to recover to the second 1:30am, you need to do an
SCN based recovery.
Review & Followup

      Rating:
      5
  April 02, 2001
Reviewer:  Harrison
      Picot  from Haymarket, VA USA

      Rating: 2
Fine for Oracle
      database, but not necessarily applications  April 02, 2001

Reviewer:  Todd Flanders  from Detroit, Michigan

Any sort or lookup by timestamp would produce wrong results if time was set
back...


Subject | Article | Last Updated (East coast time)
Error while Export and Import | article only | Apr 02, 2001 12:11 am
Adding company web page to Oracle navigation home page | article only | Apr 02, 2001 12:49 am
Creating initials from christian names | article only | Apr 02, 2001 01:15 am
return rowid or a field after insertion immediately | article only | Apr 02, 2001 01:24 am
Performance comparison between SQL and PL/SQL stored procedures | article only | Apr 02, 2001 09:30 am
Using where clause in imp/emp command | article only | Apr 02, 2001 11:06 am
Cross tab of text strings | article only | Apr 02, 2001 11:33 am
database and instance | article only | Apr 02, 2001 11:55 am
One Schema Backup/Restore | article only | Apr 02, 2001 08:58 pm
Getting a result set into a text file | article only | Apr 02, 2001 11:22 pm
hotbackup, all files or single | article only | Apr 03, 2001 12:51 pm
Constraints using SNAPSHOT | article only | Apr 03, 2001 12:55 pm
How to avoid loading from browser cache in PLSQL ? | article only | Apr 03, 2001 01:01 pm
Long time transactions | article only | Apr 03, 2001 01:43 pm
Improve PL/SQL procedure performance. | article only | Apr 03, 2001 02:39 pm
Hi Thomas. | article only | Apr 03, 2001 09:39 pm
full export and import | article only | Apr 03, 2001 09:58 pm
Export - direct mode | article only | Apr 04, 2001 10:31 am
analyzing only partition of table | article only | Apr 04, 2001 10:43 am
Setting NEXT_NAVIGATION_ITEM property to NULL value | article only | Apr 04, 2001 10:46 am
Using unknown table name in the procedure | article only | Apr 04, 2001 11:28 am
querying 2 tables with CONTEXT to return ONE recordset | article only | Apr 04, 2001 04:58 pm
What is the equivalent of 'set echo on' in PL/SQL? | article only | Apr 04, 2001 05:05 pm
PLSQL query regarding cursors attributes %NOTFOUND | article only | Apr 05, 2001 08:31 am
A question on one to one aggregation. | article only | Apr 05, 2001 08:41 am
How | article only | Apr 05, 2001 09:16 am
How many maximum tablespaces ! | article only | Apr 05, 2001 10:54 am
UGA Memory | article only | Apr 05, 2001 10:48 pm
OPS, Archive logs | article only | Apr 05, 2001 11:19 pm
Where Clause for Long Datatype | article only | Apr 05, 2001 11:54 pm
RAW FILE SYSTEM | article only | Apr 06, 2001 01:27 am
Sqls to tune | article only | Apr 06, 2001 10:44 am
commit frequency | article only | Apr 06, 2001 11:02 am
Upgrade to 64 bit. | article only | Apr 06, 2001 11:07 am
looking for info on rowid | article only | Apr 06, 2001 09:37 pm
data sorting of records in block | article only | Apr 07, 2001 12:10 am
Login Script file | article only | Apr 07, 2001 01:36 am
sql load and global temp table | article only | Apr 07, 2001 03:57 pm
Help in Array / Type or PL/SQL table as Input and OutPut Params in Procedure | article only | Apr 08, 2001 02:48 pm
Archiving huge database | article only | Apr 08, 2001 10:25 pm
Importing Problem | article only | Apr 08, 2001 11:18 pm
Extending Rollback segments | article only | Apr 08, 2001 11:37 pm
row(s) 1 - 42 of 42
April 02, 2001 Prem -- Thanks for the question regarding "Error while Export and Import", version 8.1.5.0
You Asked
I am having two users in a Database, I am trying to export all the objects,
tables from user1 to user2 using export and import of oracle. During Export I
did not find any problem, but while importing the dmp file I recive the
following error

Warning: the objects were exported by TESTOBJ, not by you

import done in US7ASCII character set and US7ASCII NCHAR character set
IMP-00017: following statement failed with ORACLE error 2304:
 "CREATE TYPE "ADDRESS" TIMESTAMP '2001-03-31:10:42:11' OID '80C48826DB898ED0"
 "E030000380C40175'   as object ("
 "Street varchar2(20),"
 "City   varchar2(20),"
 "zip   number);"
IMP-00003: ORACLE error 2304 encountered
ORA-02304: invalid object identifier literal
IMP-00017: following statement failed with ORACLE error 2304:
 "CREATE TYPE "PERSON" TIMESTAMP '2001-03-31:10:42:54' OID '80C48826DB8E8ED0E"
 "030000380C40175'   as object ("
 "Name varchar2(20),"
 "age  date,"
 "empno number);"
IMP-00003: ORACLE error 2304 encountered
ORA-02304: invalid object identifier literal
IMP-00063: Warning: Skipping table "GEMINI"."TEST" because object type "GEMINI".
"PERSON" cannot be created or has different identifier
Import terminated successfully with warnings.

If I drop the user1 and import the dmp to user2 it works fine. My requrement is
the user1 has to be present with his objects and table , and I would like to
import the dmp file to user2. Is there any solution to this or what care should
I take while export or import.

Here I am adding more information,

I have tried keeping the objects in other schema as types as per your earlier
solution. Here goes my table structure and the object I have created ( here I
have simplified to understand the problem ).

gemini schema.
---------------
SQL> desc cr_users;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 USER_ID                                            NUMBER
 FIRST_NAME                                         VARCHAR2(20)
 SECOND_NAME                                        VARCHAR2(20)

SQL> desc documents;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 DOC_ID                                             NUMBER
 DESCRIPTION                                        VARCHAR2(50)
 USER_NAMES                                         TYPES.USERNAME

types schema.
--------------
create or replace type username as object (
loader_id    number,
owner_id    number,
member function loader_name return varchar2,
member function owner_name  return varchar2
);
/

create or replace type body username as
    member function loader_name return varchar2 is
        user_name gemini.cr_users.first_name%type;
    begin
        select first_name into user_name from gemini.cr_users where user_id =
loader_id;
        return user_name;
    end;
    member function owner_name return varchar2 is
        user_name gemini.cr_users.first_name%type;
    begin
        select first_name into user_name from gemini.cr_users where user_id =
owner_id;
        return user_name;
    end;
end;
/

In this the documents, the documents can be handled by 2 types of users like
owner and loader.  Now I can get the loader, owner name
running the sql

select cd.doc_id,cd.description,cd.user_names.loader_name() from documents cd;

This query works fine.

I have export the schema gemini and imported to testobj, while importing I have
given "Ignore create error to Yes", and it has imported well. Now I am modifying
the information on cr_users table ( example I am updating the first_name ). By
running the above query it retrives the old result, because the object is
pointing to gemini schema. Now this situation is really trapped me. If I pass
the schema name to the function how to access the table by prefixing the schema
name to the table in the object. Here I have given execute permission on the
object to both gemini and testobj schema, select permission on gemini.cr_users
to types schema.
and we said...
ahh, you want INVOKERS rights.

You will LEAVE the schema qualification off off in the type definition.  it'll
be resolved at runtime based on WHO uses it.

See
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76976/adobjdes.htm#441626
for details.
Review & Followup
Rating: 2
Error while Export and Import April 03, 2001
Reviewer: A reader
This solution holds good, when there is no members(PL/SQL) procedures/functions.
If any members present, the PL/SQL code referes some tables then the PL/SQL code
will not go under a successfull compilation. Will Oracle help in this? or any
solution

Rating: 4
April 05, 2001
Reviewer: Prem Kumar from India

April 02, 2001 Norah -- Thanks for the question regarding "Adding company web page to Oracle navigation home page", version 11i
You Asked
Tom,

A client has asked for the ability to access their company web page from the
navigation screen, please can you advise how we can do this.

Kind regards, Norah
and we said...
I asked around and this is the feedback I got:

...
Yes, this can be done.  If they're refering to the R11i Personal Home Page, a
user can personalize their page if they have the 'Preferences' responsibility.
With that responsiblity, users can then click on 'Create/Modify Pages' icon on
the Personal Home Page and add a 'Favorites' region to their page.  After they
have created the 'Favorites' section of their PHP, they can go back to their PHP
and click on 'Customize' in the Favorites region.  Here is where they would add
the new link by clicking on the 'Add Custom ...' button and supplying the Name
and URL of the site they wish to add.

As another alternative, they can also link a URL to an Application's function
and call the web page from the main menu.

Hope this helps.
.........
April 02, 2001 Gavan -- Thanks for the question regarding "Creating initials from christian names", version 7.3.4
You Asked
Tom

I am trying to create initials from christian names.

The table has the following structure:

surname varchar2(50)
cnames varchar2(50)
.....

I have tried using the following combination of substr but I have a problem
where there are more than two(2) christian names.

Where there are 3 christian names, I get the first and last initial only.

substr(cnames,1,1)||' '||
substr(substr(cnames,length(rtrim(cnames,'ABCDEFGHIJKLMNOPQRSTUVWXYZ
')) +1),1,1)||' ')

Can you help?

Regards

Gavan Waters
and we said...
It looks a little strange but it works:

ops$tkyte@ORA8I.WORLD> create table t ( names varchar2(30) );

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into t values ( 'Thomas Jeffrey Kyte' );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 'Tom Kyte' );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 'Thomas J. Kyte' );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
SQL> select replace(
  2           translate( names,
  3             translate(names,'ABCDEFGHIJKLMNOPQRSTUVWXYZ',rpad('x',26,'x')),
  4             rpad('x',length(names),'x')
  5                ),
  6           'x',
  7           '' )
  8  from t
  9  /

REPLACE(TRANSLATE(NAMES,TRANSL
------------------------------
TJK
TK
TJK

Basically it works by

1) turn all UPPER case characters in the string into lowercase X

translate(names,'ABCDEFGHIJKLMNOPQRSTUVWXYZ',rpad('x',26,'x'))

this will be a translate "from" table.  For Tom Kyte -- the resulting string is

xom xyte

2) translate all of the characters in the above "from" table into lower case "x"

translate( names, "from table", "xxxxxxxxxx...." )

So, given Tom Kyte and the from table of "xom xyte" we get:

TxxxKxxxx

3) replace all lower case x's in that string with '' (nothing)

replace( "output of 2", "x", "" )

That gives me TK
Review & Followup
Rating: 5
Creating initials from christian names April 02, 2001
Reviewer: Gavan Waters from Australia
Very useful

Rating: 5
April 03, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

April 02, 2001 andrew -- Thanks for the question regarding "return rowid or a field after insertion immediately", version 8i
You Asked
Hi, Tom

could you tell me how to return a field or rowid right after inserting a new
record, please?

I have tried to use [insert into.....return], and it worked. But, I need a way
that is independent from DBMS!!

Thanx a lot
and we said...
If you are getting a rowid back, and given that rowid is unique to Oracle -- I
am confused by "but I need a way that is independent of the DBMS"????

You'll have to

   insert into t ....;
   select rowid from t where PK = primary key of row just inserted;

if you want it to be really independent.  But then again, given that rowid is an
Oracle'ism, I don't know how much that will buy you.
April 02, 2001 -- Thanks for the question regarding "Performance comparison between SQL and PL/SQL stored procedures", version 8.1.6
You Asked
hi tom,

we are using jdbc to access the database via stored procedures. however, we
intend on developing our product across multiple DB platforms such as SQL Server
and DB2. This poses a problem of sorts for us. Since we are heavily dependent on
stored procedures, this will mean coding the same business logic in stored
procedures for SQL Server and DB2. This could mean a maintenance/logistical
nightmare for us.

Someone here has recommended converting all the stored procedures to standard
SQL so that we can have the portability we desire. However, another issue
confronts me and that is performance of SQL versus stored procedures. I need to
prove that PL/SQL stored procs are much faster than SQL and are preferrable for
enterprise scale applications.
Can you please shed some light on my dilemma and what would you do in my
situation. Please be mindful of the fact that we do get some really huge volumes
of data. Please give pros and cons of both i.e. SQL and stored procedures.

Many Thanks

Rajat
and we said...
Well, I've always found the porting issue between various databases to be
trivial when compared to the "logic" issues.  the same exact set of sql executed
in the same exact sequence on the same exact data will produce two entirely
different results when executed in different databases.

How will you code your application so that

- it is independent of the fact that Oracle gives you non-blocking queries,
whereas the others will not.  The application that works fine in Oracle may/may
not work find in the others.

- Oracle gives you consistent reads, others will not.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:431163879856
for a somewhat amusing story with regards to that.

Basically, you may well get different answers to the same queries run in the
SAME exact set of circumstances on different database engines.

- it is independent of the locking model employed by the database?  Concurrency
control is the major differentiator between databases.

And the list goes on.  Stored procedures will not only POSSIBLY provide a
performance boost (you can write bad code in any language), but since you will
need to implement them for each database -- they will give you the opportunity
to exploit the underlying database fully.  They will give you the opportunity to
solve some of the above issues (the logic you need will be different in
different databases for different things).

Unless you are building a READ ONLY application, your best bet would be stored
procedures for portability of the rest of the appication.  There will be
subtle differences, with different solutions, for each RDBMS you use.  You will
be able to exploit the underlying RDBMS to its fullest by using stored
procedures as there will be no hesitation to implement a function as it should
be given the target RDBMS.  Not as it has to be in order to be generic.

Just my 2cents worth.  I've been there, done that.  The right way to do things
varies by database. Sybase -- they need you to use temp tables, Oracle -- we
don't like you to (not necessary).  DB2 -- if you want a consistent result set,
you must use repeatable read isolationn, Oracle not so.   And so on.
Review & Followup
Rating: 5
April 03, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

April 02, 2001 Jamil -- Thanks for the question regarding "Using where clause in imp/emp command", version 8.1.6
You Asked
Hello

Can I take dump for selected data.can I export data with some critaria .

regards

Jamil
and we said...
Yes you can.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76955/ch01.htm#37997
for details on the QUERY parameter to EXP
April 02, 2001 Dave -- Thanks for the question regarding "Cross tab of text strings", version 8i
You Asked
I am looking for a method of creating a cross tab report that contains text
rather than numeric values.

I have a table:

id NUMBER
att_name VARCHAR2
att_value VARCHAR2

What I want as the resultset is:

id  att_name1  att_name2  att_name3 ...
1    'value1'   'value2'   'value3'

I have used the DECODE technique for numeric cross tabs, but it doesn't work for
VARCHAR2 columns because it depends on aggregate functions.
and we said...
Oh, decode works great for this:

select id,
       max( decode( att_name, 'att_name1', att_value, NULL ) ) att_name1,
       max( decode( att_name, 'att_name2', att_value, NULL ) ) att_name2,
       ...
  from t
 group by id;
April 02, 2001 nag -- Thanks for the question regarding "database and instance", version 8i
You Asked
Iam a novice to oracle.

I have the following basic questions.

What is the relationship between a database and an instance.

When we have multiple instances for the same database, can we start them
simultaneously?

Can we restrict each instance to look at only a choosen restricted set of
tables?

Can you give me a simple example of single database with multiple instances.
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:533422350794

Under OPS, the answer to

"When we have multiple instances for the same database, can we start them
simultaneously?"

is yes.  see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:936229578864

As for
"Can we restrict each instance to look at only a choosen restricted set of
tables?"

No, each instance on a node will have full access.
April 02, 2001 M -- Thanks for the question regarding "One Schema Backup/Restore", version 8.1.7
You Asked
We are developing a web application which set a database for each customer user.
We used to use MS SQL Server and created one database for each user. Now we are
switching to Oracle. My questions are:

 1. We can create a schema for each user. We can also create a database for each
user. The second way looks unusaul in Oracle. But what is the difference
(advantages/disadvantages) between two ways?

 2. How can I backup/restore one single schema? I also want to backup/restore
the related user's information including name, passwaord, privileges etc.. Can I
use tablespace backup to do that if I use separate tablespace for each user? But
it seems the meta data is stored in SYS tablespace.

Thanks for any help.
and we said...
1) to create a schema per customer would be infinitely preferred.  A SQLServer
"database" in a database is equivalent to our Schema.

Creating a physical database instance per customer would be very undesirable,
hard to maintain, impossible to tune, and consume many more resources then
necessary.

2) You would back up each customers set of tablespaces -- this is correct.  They
are recoverable to different points in time -- so it is possible to restore
different customers to different points in time if need be.

To backup their priveleges, you just backup the system tablespace.  That will
get them all.  You need to back up system (and rollback and so on) anyway on a
recurring basis.
April 02, 2001 Rajeewa -- Thanks for the question regarding "Getting a result set into a text file", version 7.3 - 8i
You Asked
Hi,

  I want to take a result set of a query into a text file. And I want to make it
work without spool option. Any help is much appriciated.

/Rajeewa
and we said...
well, you can always:

sqlplus username/password @script > output.dat

but you can also use PLSQL if your DBA has setup the UTL_FILE_DIR init.ora
paramter, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:235814350980
for an example.
April 03, 2001 LS -- Thanks for the question regarding "hotbackup, all files or single", version 8.1.6.3
You Asked
Hi

I was wondering the pros and cons in a hot backup between backing up all files
or single

basically it4s
1.-
alter tablespace xxx begin backup
alter tablespace yyy begin backup
alter tablespace zzz begin backup

alter tablespace xxx end backup
alter tablespace yyy end backup
alter tablespace zzz end backup

or it4s better
2.-
alter tablespace xxx begin backup
alter tablespace xxx end backup
alter tablespace yyy begin backup
alter tablespace yyy end backup

and so on

Also what would be potential problem in each situation if database crashes
during the hot backup process? Can we recover faster in situation 2?

Cheers
and we said...
#2 is better -- while in backup mode the files generate more redo information
then when not in backup mode.  #1 puts the files into backup mode for the
longest possible period of time -- increasing the amount of redo generated
during the entire backup process.  If the database is "quite" during this time,
that might not be an issue for you.

#2 will recover faster as only one tablespace will need any sort of assistance
during recovery.
April 03, 2001 Gurdip -- Thanks for the question regarding "Constraints using SNAPSHOT", version 8.0.6
You Asked
How to provide foreign key constraint using SNAPSHOT.

Carreir table in datbase A has been used as a master tbale for snapshot as a
carrier in database B. in datbase B the foreign key constrains need on carrier.
how this could be implemented?
and we said...
If you use deferrable constraints on the snapshots (you must if you want a
constraint), the Oracle will issue

set constraints all deferred;

before performing the refresh.  In this fashion, the constraint check will be
deferred until the end of the snapshot refresh -- ensuring the integrity of the
data but allowing the refresh to take place.

see
http://technet.oracle.com/doc/server.804/a58245/ch4.htm#8048
"Manipulating a snapshots base table"
April 03, 2001 Marina -- Thanks for the question regarding "How to avoid loading from browser cache in PLSQL ?", version 8.1.7
You Asked
Hi Tom,
    i'm searching for a technique to automatic reload the page of my internet
browser after inserted or updated a record in my Oracle db.
I have defined procedures in PLSQL and i have to refresh manually the page from
the browser to see the changes.

Is there a PLSQL command that avoid the loading of the page from the browser
cache ?
Like the one that i found for ASP  "Response.Expires = 0" (i don't know if this
example may help you to better understand my need ... )

Greetings from Italy while waiting for your response
Marina
and we said...
If you write the headers -- directing the browser to not cache the document --
you can do this.  For example:

create or replace procedure dont_cache_me
as
begin
    owa_util.mime_header( 'text/html', FALSE );
    htp.p( 'Pragma: no-cache' );
    htp.p( 'Cache-control: no-cache' );
    htp.p( 'Cache-control: max-age=0' );
    htp.p( 'Expires: ' ||
            to_char(sysdate-1,'Day, dd Mon YYYY HH24:MI:SS' ) || ' +0000' );
    owa_util.http_header_close;

    htp.p( 'This should not be cached ' ||
               to_char( sysdate,'Day, dd Mon YYYY HH24:MI:SS' ) );
end;
/

should thwart the caching scheme on most browsers....
Review & Followup
Rating: 5
April 04, 2001
Reviewer: Eric Grancher from CERN, Switzerland

April 03, 2001 José -- Thanks for the question regarding "Long time transactions", version 8.1.6
You Asked
Hi Tom

I have a multi-user application that creates/deletes/updates objects in a visual
fashion.
The user presses a button to create one or several objects that appear in a
workspace of the app and the objects are inserted (with ID and one default name)
into the database.
After, the user can characterize the object (with one form) and this is UPDATEd
into the DB.

The workspace of the app has one Cancel button (rollback) and one Save button
(commit).
So my transaction could last a long time but there isn’t much entitie’s
modify/create/delete actions.

I need your opinion/alerts for using the transaction to control all the actions
made with the persistent objects within my field of business.

The use of the transactions is easier for the GUI since we don’t distinct
objects that already exist in DB (created before) from the new ones that the
user hasn’t saved yet from the workspace. Another advantadge is that the rules
of my business are in DB not in GUI.

Thanks for the help
and we said...
Sounds perfect to me.  Oracle has no issues with locks as other databases might.
 You are not blocking anyone from reading anything in the database -- to them,
it is as if you are not logged in.  You are only preventing others from
modifying your objects -- and that is EXACTLY what you want.

Its perfect.  As long as you ensure the id generation is non-blocking (eg: you
are using sequences) -- its 100% correct.

The only consideration will be in the sizing of the rollback segments.  You will
need enough rollback segment space allocated in each segment to support these
longer then average transactions.  We will not reuse an extent that has an
active transaction still in it -- we'll allocate  a new one instead.  So, if you
have a transaction that takes an hour to complete, you'll need enough rollback
space allocated to last for an hour without wrapping around.
Review & Followup
Rating: 3
April 04, 2001
Reviewer: Jose Goncalves from Portugal
I am not afraid of blocking the others users from reading, I am afraid what
happen to DB when the transaction during a long time (ends when the user
save/cancel the workspace).

Rating: 3
April 04, 2001
Reviewer: Jose Goncalves from Portugal
I am not afraid of blocking the others users from reading, I am afraid what
happen to DB when the transaction during a long time (ends when the user
save/cancel the workspace).

Rating: 5
April 04, 2001
Reviewer: Jose Goncalves from Portugal
Thanks for your second answer

April 03, 2001 Milla -- Thanks for the question regarding "Improve PL/SQL procedure performance.", version 8.0.5
You Asked
Hi Tom:

I am trying to tune a series of procedures. They all have the same pattern:

procedure p1(a1, a2) is
begin
  for c1 in (select * from table_name1 where col1 = a1
             and col2 = a2)
  loop
    delete from table_name2 where c1.col1 = table_name2.col1;

    insert into table_name2 values(c1.col1,
                                   c1.col2,
                                   c1.col3,...);
  end loop;
end;

I have modified the procedure to use PL/SQL index by tables, but it only make
the procedures run 3 times longer. The table_name2 doesn't have any indexes in
them, so DML on these tables shouldn't have overhead related to indexes. I also
tried to use parallel hints (parallel and append), both of also make processing
time suffer. Do you have any suggestions that I could try? Please help! Thanks
in advance.

Milla
and we said...
Just do this:

begin

delete from table_name2
where col1 in ( select col1 from table_name1 where col1 = a1 and col2 = a2 );

insert into table_name2 select * from table_name1 where col1 = a1 and col2 = a2;

end;

don't do procedurally what you can do in a single statement.  It is almost
always slower if you do it procedurally when it can be done in a single
statement.  Also, the fact that you do not have any indexes on table_name2 is
what is probably killing you here!  You need an index on col1 to make the delete
avoid a full scan of the table for each and every row in table_name1.  At least
doing the delete with the subquery will only full scan table_name2 once.
April 03, 2001 Vijay -- Thanks for the question regarding "Hi Thomas.", version 9i
You Asked
Hi Thomas,

Your site is just amazing and it's very very helpful for us to

become stronger with Oracle.  I am very curious about the next

release of Oracle(ie 9i).  When is it getting launched and a

few talks are also there like, Oracle is removing certain

JAVA oriented features which they had planned to implement in

Oracle9i.  Is this true? and one more thing is,  Oracle Corp.

has not yet updated the Technical White Paper about the

new features of Oracle9i.  All I can find is the Paper which

was published in December, 2000 (or) am I wrong. In that

case do update me where I can find that information.

All the best and CONGRATULATIONS for doing a fine service.

With Best Regards,
Vijay.
and we said...
You would get the features summary at
http://technet.oracle.com/products/oracle9i/index.htm
The 12/2000 paper is the current one.  The code would have been frozen at that
point featurewise to start the beta test.  You would expect to see 9i early this
summer.

I know of no published features that have been retracted.  Some features that
might have been hinted at -- but not promised -- may not have made the december
feature freeze, they will be in subsequent dot releases of 9i.
April 03, 2001 -- Thanks for the question regarding "full export and import", version 8.1.6
You Asked
Tom:

reducing database fragmentation:
1. Do a full database export(FULL=y) to backup the entire database.
2.shut down oracle after all users are logged off.
3.delete the database.
4.re-create the database using the create database command.
5. do a full database import(fill=y) to restore the entire database.

my questio is if i re-create the database at another machine.
do i need to follow the directory structure of the original one?
can i just use dbassist delete and create a database and
then do a full dataase import?
and we said...
if you use locally managed tablespaces with uniform extent sizes -- as all 8i
databases should -- fragmentation is IMPOSSIBLE TO HAVE.

Even so, in 8i, I would never use exp/imp to do this.  I would alter table move
and alter index rebuild.  The above steps take way too long and are far too
error prone.

If you recreate the database at another site, you can either use the existing
strucutre (imp will create the tablespaces with the old datafile names) or you
can precreate the tablespaces.  Again though, if the platforms are the same
(solaris to solaris for example) I would simply BACKUP and RESTORE or at most
TRANSPORT the tablespaces.
April 04, 2001 -- Thanks for the question regarding "Export - direct mode", version 8.1.7
You Asked
Oracle 8.1.7 enterprise edition
Solaris 2.6

I had DIRECT=Y in my Export parm file. I noticed that
some SYS-owned tables are exported in conventional mode.
Just curious  why ?
Are there any other DB objects that must be exported in
conventional mode ?

EXP-00067: Table DEF$_LOB will be exported in conventional path.
. . exporting table                       DEF$_LOB
                                                            0 rows exported
. . exporting table                    DEF$_ORIGIN
                                                            0 rows exported
. . exporting table                DEF$_PROPAGATOR
                                                            0 rows exported
. . exporting table       DEF$_PUSHED_TRANSACTIONS
                                                            0 rows exported
EXP-00067: Table DEF$_TEMP$LOB will be exported in conventional path.
. . exporting table                  DEF$_TEMP$LOB
                                                            0 rows exported
. about to export OUTLN's tables via Direct Path ...
. . exporting table                            OL$
                                                            0 rows exported
. . exporting table                       OL$HINTS
                                                            0 rows exported
. about to export DBSNMP's tables via Direct Path ...

Thanks.
and we said...
I think you mean SYSTEM owned since SYS owned objects are not exportable...

Yes, tables with LOBS and objects cannot be direct path exported.  They will use
the conventional path.  The documentation very "unclearly" states:

<quote>
In versions of SQL*Loader prior to 8.1.5, you could not use direct path export
for tables containing objects and LOBs. If you tried to, they were exported
using the conventional path method. This behavior has changed and you can now
use direct path export for tables containing objects and LOBs.
</quote>

it should read more like:

in versions of sqlldr prior to 8.1.5, tables containing lobs and objects were
SKIPPED during a direct path export.  They are no longer SKIPPED however they
will be exported using the conventional path.

In 8.0, a direct path export of system would give you:

. . exporting table                    DEF$_AQCALL
EXP-00067: Direct path can not export DEF$_AQCALL which contains object or lob
data.
. . exporting table                   DEF$_AQERROR
EXP-00067: Direct path can not export DEF$_AQERROR which contains object or lob
data.
. . exporting table                  DEF$_CALLDEST          0 rows exported

In 8.1.5 and up, you get the more friendly behavior above.
Review & Followup
Rating: 5
April 05, 2001
Reviewer: A reader

Rating: 5
April 05, 2001
Reviewer: Marc from Belgium

Rating: 5
July 20, 2001
Reviewer: Stefan from Munich, Germany

April 04, 2001 SURESH -- Thanks for the question regarding "analyzing only partition of table", version 8i
You Asked
Dear Tom,

Is it possible to analyze <compute option> only a partition of a table. <using
DBMS_STATS package> i want to analyze a table <table having 83 million rows>
parallely. when using ANALYZE table command for estimating statistics it is
taking 90 minutes <for sample 30 percent>. the table used is  a DATA WAREHOUSE
table. <very big table>

i heard that using ANALYZE command we cannot analyze just a partition. for
oracle documentaion i cannot find out the exact syntax for analyzing a partition
of the table using DBMS_STATS command. Can you provide an example how to do this
?
and we said...
tkyte@TKYTE816> analyze table emp partition(p1) compute statistics;

Table analyzed.

tkyte@TKYTE816> select table_name, partition_name, num_rows from
user_tab_partitions;

TABLE_NAME                     PARTITION_NAME                   NUM_ROWS
------------------------------ ------------------------------ ----------
EMP                            P2
EMP                            P3
EMP                            P4
EMP                            P1                                      0

that shows just one partition is analyzed.  But yes, DBMS_STATS, supports this
as well.  See the "partname" parameter to the gather routines.

tkyte@TKYTE816> exec dbms_stats.gather_table_stats( user, 'EMP', 'P2' );

PL/SQL procedure successfully completed.

tkyte@TKYTE816> select table_name, partition_name, num_rows from
user_tab_partitions;

TABLE_NAME                     PARTITION_NAME                   NUM_ROWS
------------------------------ ------------------------------ ----------
EMP                            P2                                      6
EMP                            P3
EMP                            P4
EMP                            P1                                      0

for example.
Review & Followup
Rating: 5
April 04, 2001
Reviewer: Pauline from U.S.A

Rating: 5
Simple and to the point! October 15, 2002
Reviewer: Robert from Memphis, USA

April 04, 2001 -- Thanks for the question regarding "Setting NEXT_NAVIGATION_ITEM property to NULL value", version 6.0.5.0.2
You Asked
First of all , excuse my english.

I have a problem because I need to change the NEXT_NAVIGATION_ITEM on runtime ,
and sometimes I`ll need to set this property to NULL .
If I do so , when I try to execute the program , what I get is the FRM-40105
error .

I`ve tried with '',' ',NULL,'NULL'..... but I always get the same error.

How can I 'clean' this property ?

Thanks.
Hugo.
and we said...
Simply set the next navigation item to the SAME item:

set_item_property( 'dept.deptno', NEXT_NAVIGATION_ITEM, 'dept.deptno' );

That'll trap the user in that fild which it seems is what you want.
Review & Followup
Rating: 2
It isn't the problem April 09, 2001
Reviewer: A reader
Hello :
What you told may be useful , but not in my case .
What I need it´s to put the defaults settings , not to
get the user trap in the field. What I want is that if the user press the key
"next item" , the cursor should go to the next item in the default sequence .

Thanks.

April 04, 2001 ramesh -- Thanks for the question regarding "Using unknown table name in the procedure", version 8.0.5
You Asked
Hi Tom,
My task is to update a column value in all tables. We have a master table which
lists names of all tables. I have to retrieve the name of each table and process
update on that table. Note: I am the owner of the mastertables.
The following is the code that I wrote. I am getting an error on compilation as
follows:
(1):PLS-00356: 'r_tablename.tablename' must name a table to which the
user has access.

Procedure UPDATE_DATE
   IS
   v_total_rows number;

   cursor c_tablename is
   select tablename from mastertables;
   r_tablename c_tablename%ROWTYPE;

Begin

  if c_tablename%ISOPEN then close c_tablename; end if;
  OPEN c_tablename;
  LOOP
    fetch c_tablename into r_tablename;
    exit when c_tablename%NOTFOUND;

    select count(*)
    into v_total_rows
    from r_tablename.tablename;

    update r_tablename.tablename
    set date=sysdate
    where number between 1 and 2000;
    commit;
  END LOOP;
end;

How will I have to modify the code to accomodate the situation. I know, you may
have the answer.
Thank you very much in advance.

Ramesh
and we said...
You need to use dynamic sql for this.  In 8.0 it could look like this:

create or replace procedure execute_immediate( p_sql in varchar2 )
is
    cursor_name     pls_integer default dbms_sql.open_cursor;
    ignore          pls_integer;
BEGIN
    dbms_sql.parse(cursor_name, p_sql, dbms_sql.native);
    ignore := dbms_sql.execute(cursor_name);
    dbms_sql.close_cursor(cursor_name);
END;
/

procedure update_date
is
begin
   for x in ( select tablename from mastertables ) loop
      execute_immediate( 'update ' || tablename ||
                           ' set date = sysdate
                           where number between 1 and 2000' );
      commit;
   end loop;
end;

If the number between 1 and 2000 is really VARIABLE -- you need to use bind
variables.

to read about this:

select text from user_source where name = 'DBMS_SQL' and type = 'PACKAGE' order
by line;
Review & Followup
Rating: 4
April 04, 2001
Reviewer: Dan from USA

Rating: 5
"Using unknown table name in the procedure" April 04, 2001
Reviewer: Ramesh from Minneapolis, MN USA
Thanks you very much for your prompt reply and useful suggestion.

April 04, 2001 neil -- Thanks for the question regarding "querying 2 tables with CONTEXT to return ONE recordset", version 8.0.6.0.0
You Asked
We have a search feature on our website that will search our Magazine Issue
articles for key words or phrases. We would like to be able to search our daily
news table as well. Both the Daily and the Mag. Issue tables have identical
fields. What we want to do is use CONTEXT in a query on both tables. The query
should return one recordset sorted by the Score. In other words, the user wants
to search both tables and get results starting with the most "hits" in the
either the Dail or Mag. Articles.

I'd like to avoid creating temp tables and using a Proc. since we may have alot
of users on the site at one time.

Thanks for your help Tom!,
Neil
and we said...
In Oracle ConText 8.0.6, you can create a ConText index on a view.
In this case, your view would be a UNION ALL of your daily issue
and your magazine issue articles.  Then, your ConText
query would correctly calculate the score based on this view.

Keep in mind that with interMedia Text (in Oracle8i 8.1.5 and later),
text indexes on views are no longer supported.  You will be able to
get around this hurdle by converting this solution of an index on
a view to a USER_DATASTORE...a facility which lets you synthesize
the documents at indexing time.
April 04, 2001 raj -- Thanks for the question regarding "What is the equivalent of 'set echo on' in PL/SQL?", version 8.1.6
You Asked
Hi Tom,

I have a SQL*PLUS script which is 95% insert statements and just one if/else if
branching, based on the parameter that was passed in to the script. Because I
have to check the value of the paramter, I am forced to place all inserts within
a BEGIN...END (PL/SQL block). The problem is that the insert statements are not
being displayed as they are being processed (something similar to 'set echo on'
in plain SQL*PLUS script. Is there a way to echo the SQL statements within a
PL/SQL script as they are being processed?

Thanks,
Raj
and we said...
No, the entire PLSQL block is a SINGLE sql statement itself.  If you really want
them to be "seen" as they go, you would put them into a separate file -- so say
you have a file called:

inserts.sql   (all of your inserts)
noop.sql      (a empty file basically)

Your PLSQL could be:

set feedback off
set serveroutput on
spool temp.sql
begin
   if ( some_condition ) then
      dbms_output.put_line( '@inserts.sql' );
   else
      dbms_output.put_line( '@noop.sql' );
   end if;
end;
spool off
set feedback on
set echo on
@temp

Now, at that point, @temp.sql will have in it either @inserts.sql -- in which
case it'll run the inserts or it will have @noop.sql (no operation) and do
nothing.
Review & Followup
Rating: 4
What is the equivalent of 'set echo on' in PL/SQL? April 06, 2001
Reviewer: S.ANANDAN from INDIA,TN,CHENNAI
it was a clear explanation. and i thought of asking the same question long back.
thank u.

April 05, 2001 harshada -- Thanks for the question regarding "PLSQL query regarding cursors attributes %NOTFOUND", version 8.1.6
You Asked
 I read in oracle study material(introduction to :sql and plsql) volume 2 for
PLSQL exam that

before the first fetch .%NOTFOUND evaluets to null.so if fetch never executes
successfully ,the loop is never exited

can you explain this in more detail with and example which i can
execute and see for myself as I think that the above statement is wrong
and we said...
Sorry, I have no idea the context the above statement was taken from, but yes --
if you NEVER fetch and you have "exit when C%notfound" -- you will never exit
the loop.  That should be obvious -- regardless of the setting of the %notfound
-- you have not fetched so NOTFOUND should not be true so it will never exit.

Your test case would be:

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create table t ( x int );

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> declare
  2          cursor c1 is select * from t;
  3          l_x number;
  4  begin
  5          open c1;
  6          for i in 1 .. 10
  7          loop
  8                  exit when c1%notfound;
  9                  dbms_output.put_line( i );
 10          end loop;
 11          close c1;
 12  end;
 13  /
1
2
3
4
5
6
7
8
9
10

PL/SQL procedure successfully completed.

that shows that loop was exited due to I exceeding 10 -- not because of the
NOTFOUND.  If you never fetch, obviously NOTFOUND will never be true.

Here is how notfound is designed to be used:

ops$tkyte@ORA8I.WORLD> declare
  2          cursor c1 is select * from t;
  3          l_x number;
  4  begin
  5          open c1;
  6          loop
  7                  fetch c1 into l_x;
  8                  exit when c1%notfound;
  9          end loop;
 10          close c1;
 11  end;
 12  /

PL/SQL procedure successfully completed.
Review & Followup
Rating: 4
April 05, 2001
Reviewer: archana from india

April 05, 2001 Prasad -- Thanks for the question regarding "A question on one to one aggregation.", version Oracle 8.1.6
You Asked
While designing a database, on which factors we should decide whether to create
two separate tables having 1-1 cardinality where one table depends on other
table for the existance or merge these two tables into one because anyway its
1-1 cardinality??
and we said...
If it is a mandatory one to one relationship (A must have a row in B and B must
have a row in A) I would store it as one table.

If the relationship between A and B was optional (A might have a row in B) I
would consider two tables.

If the number of columns was getting high (over say 200) I might also consider
two tables -- putting the infrequently accessed columns in one table and the
always accessed columns in another.
Review & Followup
Rating: 3
April 05, 2001
Reviewer: A reader

April 05, 2001 -- Thanks for the question regarding "How", version 8.1.6
You Asked
Hi, TOm

CREATE OR REPLACE PROCEDURE p1(
 a IN ANY_DATATYPE := NULL )
AS
BEGIN
 ....
 IF ( a IS NULL ) THEN
   print ('a IS NULL by default');
 ELSE
   print ('a is null by passing parameter');
 END IF;
 ....
END;

Both of the following statements will tell me that 'a = NULL':

1. p1;
2. p1(NULL);

Is there any way at all to distinguish, within the procedure, between the above
two calls?

Basically, I need to know whether a parameter was actually passed to the
procedure or not.
I don't want to change the default to others but NULL(restrict), and it should
be suitable for ANY DATATYPES ---- generic one.

Please help

Thanks
and we said...
Forgetting for the moment that there is not such thing as "any_datatype" unless
you've created your own user defined type called any_datatype....

the only way to do this is to use an overloaded procedure in a package.  One
procedure will take inputs (with NO defaults) and the other will not take
inputs.  I'll use varchar2 since every type can be cast to varchar2 implicitly
and hence it will server as our "any datatype" type:

tkyte@TKYTE816> create or replace package my_pkg
  2  as
  3          procedure p;
  4          procedure p( a in varchar2 );
  5  end;
  6  /

Package created.

tkyte@TKYTE816> show err
No errors.
tkyte@TKYTE816>
tkyte@TKYTE816> create or replace package body my_pkg
  2  as
  3          procedure p
  4          is
  5          begin
  6                  dbms_output.put_line( 'No parameters passed' );
  7          end;
  8
  9          procedure p( a in varchar2 )
 10          is
 11          begin
 12                  dbms_output.put_line( 'parameters passed' );
 13          end;
 14
 15  end;
 16  /

Package body created.

tkyte@TKYTE816>
tkyte@TKYTE816> exec my_pkg.p
No parameters passed

PL/SQL procedure successfully completed.

tkyte@TKYTE816> exec my_pkg.p( 'hello world' );
parameters passed

PL/SQL procedure successfully completed.
April 05, 2001 OP -- Thanks for the question regarding "How many maximum tablespaces !", version 8.1.6.0
You Asked
Hi Tom,

Is there any limit for the creation of tablespaces in the
Database or

as many as tablespaces can be created depending on the
harddisk capacity and sixe of the tablespace.

Thanks and Regards
OP Lalwani
and we said...
there is a 64k maximum in 8i which is what you have..
http://technet.oracle.com/doc/oracle8i_816/server.816/a76961/ch43.htm#11789
...
April 05, 2001 Eduardo -- Thanks for the question regarding "UGA Memory ", version 8.1.7
You Asked
Hi Tom

Tankx for you help.
I'am a novice DBA, this is my doubt :

I run next query :

SELECT username, value || 'bytes' "Current UGA memory"
FROM v$session sess, v$sesstat stat, v$statname name
WHERE sess.sid = stat.sid
AND stat.statistic# = name.statistic#
AND name.name = 'session uga memory';

USERNAME                       Current UGA memory
------------------------------ ----------------------------------------------
                               14796 bytes
                               17340 bytes
                               14732 bytes
                               17992 bytes
                               38824 bytes
                               37484 bytes
                               17932 bytes
                               18920 bytes
                               20760 bytes
                               22064 bytes
SYS                            91204 bytes
SIPWEB                         46516 bytes
OUTLN                          46516 bytes
SYSTEM                         46516 bytes
SIPGUIAS                       46456 bytes
SCOTT                          46516 bytes
RAGUILAR                       45456 bytes

1. Why the user SYS takes more space than other users ..?

if all user get disconnected :

USERNAME                       Current UGA memory
------------------------------ ----------------------------------------------
                               14796 bytes
                               17340 bytes
                               14732 bytes
                               17992 bytes
                               38824 bytes
                               37484 bytes
                               17932 bytes
                               18920 bytes
                               20760 bytes
                               22064 bytes
SYS                            99892 bytes

2. Why user SYS has now more memory space as previous query ...?

3. What users are USERNAME left in blank .?

4. Exactly, what means the amount of memory assigned for each user ?

thanx for you kindly help.
and we said...
UGA is the user global area.  It is memory private to the session.  As SYS runs
stuff, it is allocating cursors and bind space and so on.  It is normal to see
this grow and shrink over time.

The blank users are the Oracle threads/processes themselves.  Add program to the
select list and you'll see that:

tkyte@TKYTE816> SELECT username, program, value || 'bytes' "Current UGA memory"
  2  FROM v$session sess, v$sesstat stat, v$statname name
  3  WHERE sess.sid = stat.sid
  4  AND stat.statistic# = name.statistic#
  5  AND name.name = 'session uga memory'
  6  /

USERNAME                       PROGRAM         Current UGA memory
------------------------------ --------------- -------------------------
                               ORACLE.EXE      23304bytes
                               ORACLE.EXE      21600bytes
                               ORACLE.EXE      23236bytes
                               ORACLE.EXE      22464bytes
                               ORACLE.EXE      42800bytes
                               ORACLE.EXE      40280bytes
                               ORACLE.EXE      21464bytes
TKYTE                          SQLPLUS.EXE     108872bytes
April 05, 2001 -- Thanks for the question regarding "OPS, Archive logs", version 8.1.7
You Asked
Tom

Is there any difference in configuring the OPS in linux and OPS in Solaris.

Assume I have a db built using hot backup and applied all the logs and it is
working just fine.  Is there any possibility of updating the database by
bringing the new archive logs generated in production. If so how ?

Thanks
and we said...
No, you cannot take logs from one database and apply them to another database --
there is a standby database setup but then you really have 2 copies of the SAME
database.  Perhaps this is what you are looking for?

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76995/toc.htm
You must do this on a homogenous environment as well -- solaris to solaris or
linux to linux.
April 05, 2001 Srinivasan -- Thanks for the question regarding "Where Clause for Long Datatype", version 8.1.6.0.0
You Asked
How Can i find a text or character in Long Datatype Column.

E.g.
     To find a Package name in USER_TRIGGERS Table - Column Name is Trigger_body
and we said...
I can show you how to do that but a better way to answer your question is to use
the builtin dependency tracking in Oracle:

tkyte@TKYTE816> create table t ( x int );

Table created.

tkyte@TKYTE816> create trigger t_trigger
  2  before insert on t
  3  for each row
  4  begin
  5     dbms_output.put_line( 'x ' );
  6  end;
  7  /

Trigger created.

tkyte@TKYTE816> select distinct name from user_dependencies where
referenced_name
  2  = 'DBMS_OUTPUT' and type = 'TRIGGER';

NAME
------------------------------
T_TRIGGER

I don't have to "grep" the code to find the relations -- they are all there.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:665224430110
for a "longsubstr" that you can turn into longINSTR if you like or simply code:

begin
   for x in ( select * from user_triggers ) loop
      if ( instr( upper(x.trigger_body), 'MY_PKG' ) > 0 )
      then
         dbms_output.put_line( x.trigger_name );
      end if;
   end loop;
end;
/
Review & Followup
Rating: 4
Long Data Type - To Search April 06, 2001
Reviewer: Srinivasan from SINGAPORE
It is very Useful to find out the package name in user_triggers.

Rating: 5
August 12, 2003
Reviewer: Jiten
Excellent way of searching the contents of the trigger

April 06, 2001 Vikas -- Thanks for the question regarding "RAW FILE SYSTEM", version 8.0.4
You Asked
Tom,
I have a query
How one can identify & Create RAW file system at OS(SUN SOLARIS 2.6) &
Database(ORACLE 8.0.4) level ?

Thanks & Regards
Vikas
and we said...
Adding a raw datafile is no different then a cooked one. We just need a device
name.

You need to identify the raw partition to us.

See
http://technet.oracle.com/doc/solaris/server.805/adminref/ch3_opt.htm#10585
for solaris specifics on 8.0
April 06, 2001 hasan tonguc -- Thanks for the question regarding "Sqls to tune", version 8.0.5.2.1
You Asked
i have a production database which is shutdown for offline backup daily, i have
very very bad sql statements waiting for my help to tune them, in order to force
my developer group how can i generate a report daily (from which v$ views) which
will show the full table scanning statements and give them some tuning advices ?
than you,
regards
and we said...
something like:

select sql_text,
       decode( executions, 0, 0, buffer_gets/executions ) buffs_per_call,
       buffer_gets,
       executions
  from v$sqlarea
 where decode( executions, 0, 0, buffer_gets/executions ) > SOME_THRESHOLD
 order by 2
/

should do it.  pick a big number to get the biggest offenders and downsize that
number over time as they fix them.
April 06, 2001 -- Thanks for the question regarding "commit frequency", version 7.3.3
You Asked
We have a script that reads from a flat file of 16 million records and inserts
them as
16 million rows into a table.
How do we determine how often to commit (every 5000, 10000 ...) ?

Thanks
and we said...
commit as infrequently as you can.  committing causes a wait. LGWR must flush
the redo log buffers to disk, you must wait until it does.  defer committing as
long as you can.

Actually, with 16million records, I would be using the direct path loader -- no
way I would load that using SQL inserts.  If SQLLDR cannot load the data, I
would write a script to transform the data into something SQLLDR can load and
use a named pipe in unix to load it up.  No redo, no log, as fast as it gets.
April 06, 2001 Randy -- Thanks for the question regarding "Upgrade to 64 bit.", version 8.1.7
You Asked
Great column ! I am really enjoying it very much and good thing is, it's only
getting better.

I have few ques in regard to upgrade from Oracle 7.3.4 to 8.1.7.

1. We are planning to upgrade our oracle 7.3.4(32 bit) in Solaris 2.6 to 8.1.7
(64 bit) in Solaris 8 (64 bit). The main reason to upgrade to 64 bit is the get
the advantage of BOB (Big Oracle Block) and to have datafiles bigger than 2gig.
But our current database block size is of 2k. Can the upgrade to 64 bit would
help to change the blocksize to say 32K ?

2. I know the advantages of having 64 bit database that it can have higher
addressable memory, higher SGA blah blah blah... but is there any disadvantages
over 32 bit database ? Is there any parameter which I might have to tune
specailly for 64 bit other than SGA parameters ?

3. How can I change the existing dictionary managed tablespace to locally
managed tablespace without the whole exp/imp operation ?

Thanks in advance.
and we said...
1) i would not recommend that.  You can use a 16k block easily without 64bit.
Also, you do not need 64bit to get large file support -- you can do that with
32bit.

64bit will get you a bigger SGA.
64bit could run slower if you could be running 32bit (do not need the larger
SGA).

2) There is a chance it will run slower all together.  This depends.  Unless you
are using a huge SGA, I see no advantage to using 64bit.  You might even have to
have two installs as some tools will require a 32bt Oracle home to link with
anyway.

3) there is a routine to do it DBMS_SPACE_ADMIN.TABLESPACE_MIGRATE_TO_LOCAL but
you don't get all of the advantages this way (the extent sizes WON'T be uniform
for these existing objects, you'll still have wierd sized "holes").

I myself like to use the alter table move/alter index rebulid (new with 8i) to
do this.  I'll move objects from dictionary to locally managed and then drop
dictionary.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:47812348053
for the entire procedure.  Safe, fast, no drop and rebuild (no lost grants and
stuff)

followup to the comment

The 64bit Oracle implementation is useful - if you need a really large SGA,
bigger then 2gig or thereabouts.  If your SGA is not really huge, you do not
need huge blocks either -- really big, 32k blocks, were introduced in order to
make managing gigs of block buffer cache easier -- more reasonable.

So, if you don't have gigs of block buffer cache, you do not need really huge
blocks and don't really need 64bit.

I would say that given your goals above -- the means to the end is not 64bit.

You do not need it to have large files.
You do not need it to have big blocks.
Hence I would probably not introduce it into my environment at this point in
time.  When EVERYTHING is compiled 64bit - it'll be the natural thing to do.

Followup to comment

You cannot do a simple migration to change the block size, you must rebuild the
database.  It'll be an EXP/IMP process or, dump and reload with SQLLDR.  To
change the block size currently requires a database rebuild.
Review & Followup
Rating: 3
Upgrade to 64 bit April 06, 2001
Reviewer: Randy from Chicago,IL
It appears to me that the 64 bit oracle is not much of use yet. Then is the BOB
really helpful ?

Rating: 4
Upgrade to 64bit April 09, 2001
Reviewer: A reader
Thanks for clearing my confusion. Still my question remains how could I change
the block size of my 7.3.4 datbase from 2K to 16k in 8.1.7 database using oracle
migration technique ?

Rating: 4
Upgrade to 64bit April 09, 2001
Reviewer: Randy from Chicago,IL
Thanks for clearing my confusion. Still my question remains how could I change
the block size of my 7.3.4 datbase from 2K to 16k in 8.1.7 database using oracle
migration technique ?

April 06, 2001 Eben -- Thanks for the question regarding "looking for info on rowid", version 8.0.3
You Asked
I am selecting from a table (built by others) and trying to identify the last
record prior to a certain date.  Unfortunately this table has many instances of
transactions to the same PART# at identical date-hour-minute-second.

So I use rowid and select the larger rowid, but I remember reading that there is
a risk in using rowid to select among rows.

Can you point me to info on rowid and its risks and
Can you suggest a way to differentiate between to rows processed sequentially
but having the same date-time?

Many thanks Eben
and we said...
You must change the structure of the table to include a column you can order by
on.  You CANNOT use rowid to determine the order of insertion.  It is not a
valid way to do that.  ROWID is an address.  It does NOT imply order.

You will just have to pick a "random" record from that hour/minute/second -- any
of them will be as good as any other since ROWID quite simply CANNOT be used to
determine which one came first.
April 07, 2001 bipin -- Thanks for the question regarding "data sorting of records in block", version 6.0
You Asked
dear sir ,
i 'm working on oracle 8.0 and d2k forms 6
usually i 'm facing the problem that records i have fetched in block
updated by user at run time in block  but not commited to any database
can i change order / sorting of data in block at run time
and we said...
In order to do this you would:

POST; (post the data to the database but do not commit, your session can see it
but others cannot)

set_block_property to chang the order by property to what you want

execute_query;  to get the newly sorted data.
April 07, 2001 anand -- Thanks for the question regarding "Login Script file", version 8i
You Asked
Hi tom,
Thanx for all ur responses till now.
My issue is is there any file or can we create a script/sql file which will be
run every time the user is logged into the oracle . If yes ,do we hace to write
saperate script files for every user or can we write a common file which will be
used by every user and we can bifurcate the users by coding of that script.
Thanx
anand
and we said...
You can use an AFTER LOGON trigger either at the schema level or globally at the
database level.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:920229344791
for a quick example.

See
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76939/adg14evt.htm#1000872
for a list of attributes available to you in that trigger.
Review & Followup
Rating: 4
Login Script file April 09, 2001
Reviewer: Anand Krishna from India
The solution given by u seems to be very useful. The only fact is I will code
that trigger according to my requirements and let u know later.
Thanx a lot.
anand

April 07, 2001 Jane -- Thanks for the question regarding "sql load and global temp table", version 8.1.6
You Asked
We tried using sqlload to a global temp table which is not allowed. We just want
to have a very temporary table holder for data. We receive one file which has 4
different record types with each type going to 4 different tables. Instead of
parsing then loading individually, we thought that one temp table then apply sql
or pl/sql to send data to respective table. Also, we need to clean data first
before inserting to tables. Do you have any technique we can use? Thanks again
Tom!
and we said...
Well, if you could load into a global temporary table -- you would have just
wasted your time.  When SQLLDR finishes, its session is disconnected and the
table would appear empty.  temporary table data can only be seen by the session
that creates it and the data disappears when that session disconnects (or
commits depending on how you created the table).

Now, what I would do here is DIRECT PATH load a real table and then process the
real table use sql/plsql.  A temporary table would not provide you any
efficiencies in this regard (especially since the data would vanish upon
completion of the load)
April 08, 2001 M. -- Thanks for the question regarding "Help in Array / Type or PL/SQL table as Input and OutPut Params in Procedure", version 8.1.5
You Asked
Hi Tom,

(Version 8.1.5 on NT) Please also let me know how could I execute in SQL *Plus..
Thanks

Can you please help me out in this Frustrated situation. I need to have
Procedure that should accept a Type or Array or PL/SQL Table and return the
result set in a Cursor.

Here is that we are using previously but this takes as single parameter and
return in Ref Cursor. Now The Parameters  MediaIndicator, PropertyId ,
NetworkCode, EpisodeNumber, TitleId Have to be Given in Array/Type/ Or in PL/SQL
Table and the Other Parameters will be the Same.. Still I have to Return the
Result set in Ref Cursor.  Currently the Java Side does Loops it and Executes
the Procedure 100 Times, Becuase the Parameters are in Single values. The
Application will pass the Above said Parameters in a Record and I other
parameters in Single values.

Roughly .. Like many Employees are in one Department. So the Deptno is One value
but at a Time may be 100 Enames have been given to Execute the Procedure...

At the End I am Giving you the Structutre of the tables... Actualy it's spanning
about 18 tables, So I am giving you an Example of only 4 Tables. Please H E L P
Me.

Create or Replace Package Testpack
  is
    Type MedRecType is REF Cursor;
    Procedure MediaDetails (MediaCursor     IN OUT     MedRecType,
                MediaType    IN    Varchar2,
                MediaIndicator    IN    Char,
                PropertyId    IN    Number,
                Barcode        IN    Varchar2,
                TitleId        IN     Number,
                NetworkCode    IN    Varchar2,
                EpisodeNumber    IN    Number,
                FormatCode    IN    Varchar2);
End Testpack;
/

Create or Replace Package Body Testpack
  is
    Procedure MediaDetails (MediaCursor     IN OUT     MedRecType,
                MediaType    IN    Varchar2,
                MediaIndicator    IN    Char,
                PropertyId    IN    Number,
                Barcode        IN    Varchar2,
                TitleId        IN     Number,
                NetworkCode    IN    Varchar2,
                EpisodeNumber    IN    Number,
                FormatCode    IN    Varchar2)
    Is
        MediaTypeClause        Varchar2(100);
        IndicatorClause        Varchar2(100);
        PropertyClause        Varchar2(100);
        BarcodeClause        Varchar2(100);
        TitleIdClause        Varchar2(100);
        NetworkClause        Varchar2(100);
        EpisodeClause        Varchar2(100);
        FormatClause        Varchar2(100);
        SelectClause        Long;
        FromClause        Long;
        WhereClause        Long;
        FinalSelectClause    Long;
    Begin
        SelectClause := ' Select    Med.Media_Id,
                        Med.Barcode,
                        Med.Internal_Media_Ind,
                        Med.Format_Code,
                        Med.Language_Code,
                        Mep.Property_Id,
                        Mep.Network_Code,
                        Mep.Media_Title_Id,
                        Mep.Episode_Number,
                        Fmt.Code_Dscr     ';
        FromClause := ' From     Media         Med,
                    Media_Episode    Mep,
                    Format_Code    Fmt ';

        WhereClause := 'Where    Med.Media_Id     = Mep.Media_id
                and    Med.Format_Code = Fmt.Code_Id ';

        FinalSelectClause := SelectClause || FromClause || WhereClause;

    If     MediaIndicator = 'N' Then
        IndicatorClause := ' and Med.Internal_Media_Ind =
'''||MediaIndicator||'''';
        PropertyClause    := ' and Mep.Network_Code = '''||NetworkCode||'''';
        EpisodeClause    := ' and Mep.Episode_Number = '||EpisodeNumber;
        FinalSelectClause :=     SelectClause || FromClause ||WhereClause ||
                    IndicatorClause || PropertyClause || EpisodeClause;
    End If;

    If     MediaIndicator = 'Y' Then
        IndicatorClause := ' and Med.Internal_Media_Ind =
'''||MediaIndicator||'''';
        SelectClause := SelectClause ||', Imt.Media_Title_Id as Media_Title_Id,
                Imt.Title as Title ';
        FromClause := FromClause || ', Internal_Media_Title Imt ';
        WhereClause := WhereClause || ' and Mep.Media_Title_Id =
Imt.Media_Title_Id';
        FinalSelectClause := SelectClause || FromClause || WhereClause ||
                    IndicatorClause;
    End If;

    If     MediaType is NOT NULL Then
        MediaTypeClause := ' and Med.Media_Type = '''||MediaType||'''';
        FinalSelectClause := SelectClause || FromClause || WhereClause
||MediaTypeClause;
    End If;

    If    FormatCode is NOT NULL Then
        FormatClause := ' and Med.Format_Code = '''||FormatCode||'''';
        FinalSelectClause := SelectClause || FromClause || WhereClause ||
FormatClause;
    End If;

    Open    MediaCursor      For FinalSelectClause;

    End MediaDetails;
End Testpack;
/

CREATE TABLE MEDIA (
  MEDIA_ID                  NUMBER        NOT NULL,
  MEDIA_TYPE                VARCHAR2 (8),
  NETWORK_CODE              VARCHAR2 (8),
  LANGUAGE_CODE             VARCHAR2 (8),
  RECORD_LOCATION_ID        NUMBER,
  INTERNAL_MEDIA_IND        CHAR (1),
  BARCODE                   VARCHAR2 (30),
  CONTAINER_NUMBER          VARCHAR2 (16),
  FORMAT_CODE               VARCHAR2 (8),
  ENTERED_BY                VARCHAR2 (30),
  ENTERED_ON_DATE           DATE,
  LAST_UPDATED_BY           VARCHAR2 (30),
  LAST_UPDATED_ON_DATE      DATE,
  CONSTRAINT XPKMEDIA
  PRIMARY KEY ( MEDIA_ID ) )
/

CREATE TABLE MEDIA_EPISODE (
  MEDIA_ID          NUMBER        NOT NULL,
  MEDIA_EPISODE_ID  NUMBER        NOT NULL,
  EPISODE_NUMBER    NUMBER,
  MEDIA_TITLE_ID    NUMBER,
  PROPERTY_ID       NUMBER,
  NETWORK_CODE      VARCHAR2 (8),
  CONSTRAINT XPKMEDIA_EPISODE
  PRIMARY KEY ( MEDIA_ID, MEDIA_EPISODE_ID ) )
/
CREATE TABLE INTERNAL_MEDIA_TITLE (
  MEDIA_TITLE_ID  NUMBER        NOT NULL,
  TITLE           VARCHAR2 (60),
  EPISODE_IND     CHAR (1),
  TITLE_CODE      VARCHAR2 (8),
  AKA_IND         CHAR (1),
  TITLE_TYPE      VARCHAR2 (8),
  TITLE_ALPHA     VARCHAR2 (8),
  EPISODE_COUNT   NUMBER,
  EPISODE_NUMBER  NUMBER,
  LICENSEE        VARCHAR2 (15),
  CONSTRAINT XPKINTERNAL_MEDIA_TITLE
  PRIMARY KEY ( MEDIA_TITLE_ID ) )
/

CREATE TABLE FORMAT_CODE (
  CODE_ID    VARCHAR2 (8)  NOT NULL,
  CODE_DSCR  VARCHAR2 (80),
  CONSTRAINT XPKFORMAT_CODE
  PRIMARY KEY ( CODE_ID ) )
/
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:712625135727
for how to pass an array to plsql from java.

And I BEG OF YOU -- use BIND VARIABLES!  You cannot underestimate the need for
bind variables as it regards scalability.  It is crucial.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
for how to build a parameterized query that does not "hardcode" values into it
as you are doing now.
April 08, 2001 Azman -- Thanks for the question regarding "Archiving huge database", version 8.1.6
You Asked
Hi Tom,
I need your views on the above.

Currently we in the mist of developing a huge system. The system hinge around 3
huge tables. These tables are projected to store about 1 million records per
month with ave size of each records is 500 bytes.

The requiremnts is to move records that is more that 6mths to a historical
database whre it would be kept for th next 1.5 years. Thereafter it should be
kept offline for 10 years.

Whaa we had done so far.

1. Crate two database - active and historical.

2. Create partition tables (range partition by month)for those 3 huge tables. -
So that we can easily drop a partition monthly after six month.

3 Issue to consider

1. ALthough it is simple to drop a partition, we had yet to decide on how tpo
move the partition form the active database to the historical database. We are
considering import/export utilities , copying thru dblinks and transportable
tablespace.

Any recommendations.

2. For archiving of historical data (records that are more than 2 years and to
be kept offline for 10 years) what would you think should be the most
appropriate format for these data to be stored offline. FYI , we are given 3
days lead time to make the archive data online. We are considering export files
while by developers recommends xml format. Do you know what is the industry
practicesot deal with huge databases. Any recommendations?

Thanks..

Azman Diron
and we said...
1) use transportable tablespaces.
http://technet.oracle.com/doc/oracle8i_816/server.816/a76955/ch01.htm#40944
you can easily detach a tablespace(s) from one database and re-attach them to
another.  No reload, no rebuilds, just file copies of datafiles.

2) I would just keep the datafiles themselves (detach them and re-attach them
later in minutes).  Short of that, I would just use plain old flat files -- why
explode the size of them with XML when a fixed width or delimited file would
more then suffice.
Review & Followup
Rating: 5
April 09, 2001
Reviewer: Azman Diron from Singapore
Clear and concise

April 08, 2001 T.S.V.S. -- Thanks for the question regarding "Importing Problem", version 8.1.5
You Asked
Hai Tom,

How r u?

I am working a Manufacturing company. We have recently upgraded from Oracle v6.0
on Digital Unix to Oracle v8.1.5 on Solaries v5.7.
Every day we have to export our transactions (In Factory) to our Head Office.
There we are using
Oracle v7.3 on Digital Unix. There is no network connection between Factory and
head office.

Now the problem is we are tried to import the data in Head Office which is
exported from factory using export utility. But it is not importing and says the
below errors

    IMP - 00010 : not a valid export file, header failed verification
    IMP - 00021 : Operation system error - error code (dec2, hex 0x2)

Pl give any solution for this or any alternative.

Thaking You
Kishore
and we said...
You need to get and install the Oracle7.3 software on the Solaris 5.7 box (just
the client software -- you need exp).

Exp is backwards compatible -- not forwards.  You need to use the 7.3 exp tool
to create a file the 7.3 imp tool can understand.  All you need do is install
the 7.3 client software, set up sqlnet on the single machine and connect over
sqlnet to the 8.1 instance.  that'll let you create the export file.

Make sure to run catexp7.sql in the 8.1 database (found in
$ORACLE_HOME/rdbms/admin) for the 7.3 exp tool to work.
April 08, 2001 T.S.V.S. -- Thanks for the question regarding "Extending Rollback segments", version 8.1.5
You Asked
Hai Tom,

I am porting the data from old structures to New structures. Some times I can
prot more than 1,00,000 records also. At that time it is giving the following
error :
 ora-1562:failed to extend rollback segment no.2
 ora-01628:max#extents (249) reached for rollback segment block.

I know how to increase max# extents and size of extents for tables. But rollback
segements how I can increase?

Thanking You,
Kishore
and we said...
You can chang the maxextents via:

alter rollback segment rbs2 storage ( maxextents N );

if you are going to change next, you could:

alter rollback segment rbs2 storage ( next 524288 );

but I would recommend DROPPING and recreating them so they have uniformly sized
extents.


Subject | Article | Last Updated (East coast time)
parallel query | article only | Apr 09, 2001 01:19 pm
DATE vz NUMBER comparison | article only | Apr 09, 2001 01:59 pm
Two databases on one machine | article only | Apr 11, 2001 01:55 am
Is there anything other then DBMS_SQL | article only | Apr 11, 2001 09:14 am
Conversion of data from an ORACLE database into indexed-PDF documents | article only | Apr 11, 2001 09:17 am
Calling Java methods from PL/SQL | article only | Apr 11, 2001 09:18 am
Long Data Type | article only | Apr 11, 2001 09:59 am
Does object with $ in their name are treated differently by Oracle? | article only | Apr 11, 2001 01:27 pm
sql loader | article only | Apr 11, 2001 07:15 pm
Stored Procedure Compilation Error -- | article only | Apr 12, 2001 12:32 pm
sqlldr | article only | Apr 12, 2001 01:01 pm
Dynamic where clause in PL/SQL | article only | Apr 12, 2001 01:01 pm
Reparsing SQL | article only | Apr 12, 2001 03:44 pm
Which one is faster? | article only | Apr 12, 2001 04:09 pm
SQL plus - optimization | article only | Apr 12, 2001 10:28 pm
Control File - Reg. | article only | Apr 12, 2001 11:44 pm
Cursor Life - Reg | article only | Apr 12, 2001 11:47 pm
Using Savepoints | article only | Apr 12, 2001 11:50 pm
Execution Processs of Sql Statement - Reg. | article only | Apr 13, 2001 12:08 am
CALLING FUNCTIONS FROM VB | article only | Apr 13, 2001 11:44 am
Getting back a table from a procedure | article only | Apr 13, 2001 12:16 pm
Union of CLOB datatype -> ORA-00932: inconsistent datatypes | article only | Apr 13, 2001 12:35 pm
Table to datafile mapping and some misc. questions. | article only | Apr 13, 2001 01:12 pm
rollup average | article only | Apr 13, 2001 04:44 pm
Query Vs. Transaction | article only | Apr 13, 2001 06:07 pm
Better emailing method UTL_SMTP/UTL_TCP/Enqueing | article only | Apr 13, 2001 06:25 pm
Oracle Journey | article only | Apr 14, 2001 10:43 am
Developing WEB based application - Update and questions on Priviledges | article only | Apr 14, 2001 10:46 am
Porting Forms/Reports Applications from NT to SUN Solaris 2.8 | article only | Apr 14, 2001 12:59 pm
Data types of Functions | article only | Apr 14, 2001 02:28 pm
PL/SQL Procedure | article only | Apr 15, 2001 12:23 am
Query for finding out the %age output | article only | Apr 15, 2001 12:49 am
Whats different during a HOT backup | article only | Apr 15, 2001 04:47 pm
Procedural dependencies. | article only | Apr 15, 2001 09:37 pm
PL/SQL book | article only | Apr 15, 2001 09:41 pm
row(s) 1 - 35 of 35
April 09, 2001 Suresh -- Thanks for the question regarding "parallel query", version Oracle 8i
You Asked
Hi,
  Thanks for all your help. I have 3 questions today.

1. Parallel Query:
   ***************
   I have created a table as below

     create table emp(
     empno         number(4)  not null,
     constraint emp_pk primary key (empno));
   I have inserted nearly 1000 records into the table. Now, I altered the table
by saying

   Alter table emp Parallel 4;
   Table Altered.

  and also modified the Parallel_max_servers = 5 and
  parallel_min_servers = 4 in the
  init.ora file, and I brought up the server.

 a)  Now,  how will I know that Oracle is using parallel query option or not for
the query
     select count(*) from emp;

 b)  For update,insert statements, is it manadtory to have partitioned table for
the
     parallel execution to work?

2. In CBO, the optimizer decides whether to use an index or not for a query.
Even though
   I am analysing the objects regularly, if for some reason, the optimizer
decides
   to not to use the index, even though the index is available
   for that query, what is the point in we pushing the oracle to use the index
by
   using the index hint. Is it not going to degrade the performance? Where and
how
   exactly can the optimizer go wrong in deciding not to use an available index?

3. In a database procedure, how do you select a list of distinct values from a
   column in PL/SQL table?
and we said...
1) sql_trace or autotrace can help you:

ops$tkyte@DEV816> drop table t;
Table dropped.

ops$tkyte@DEV816> create table t as select * from all_objects;
Table created.

ops$tkyte@DEV816> alter table t parallel 4;
Table altered.

ops$tkyte@DEV816> set autotrace on
ops$tkyte@DEV816> select count(*) from t;

  COUNT(*)
----------
     24514

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=10 Card=1)
   1    0   SORT (AGGREGATE)
   2    1     SORT* (AGGREGATE)                                        :Q117000
   3    2       TABLE ACCESS* (FULL) OF 'T' (Cost=10 Card=27282)       :Q117000

   2 PARALLEL_TO_SERIAL            SELECT /*+ PIV_SSF */ SYS_OP_MSR(COUNT(*)) F
                                   ROM (SELECT /*+ NO_EXPAND ROWID(A2) */ 0 FRO
                                   M "T" A2 WHERE ROWID BETWEEN :B1 AND :B2) A1

   3 PARALLEL_COMBINED_WITH_PARENT

You'll see it in the plan.

Yes, in order to use PDML you MUST partition the object.

2) one could write a book on such a topic.  Sometimes, we as humans, just know
better -- thats when a hint it OK.

You can use the init.ora or session parameters:

optimizer_index_caching
optimizer_index_cost_adj

to nudge the optimizer towards (or away) an index based on your knowledge of
your system.

3) you do not -- plsql tables are just arrays.  Now, if this was a COLLLECTION
variable based on a sql type -- that would be different.

ops$tkyte@DEV816> create type myRecordType as object
  2  ( seq int,
  3    a int,
  4    b varchar2(10),
  5    c date
  6  )
  7  /
Type created.

ops$tkyte@DEV816> create or replace type myTableType
  2  as table of myRecordType
  3  /

Type created.

ops$tkyte@DEV816> create or replace procedure my_proc
  2  is
  3      l_data myTableType;
  4  begin
  5      l_data := myTableType();
  6
  7      for i in 1..50
  8      loop
  9          l_data.extend;
 10          l_data(i) := myRecordType( i, mod(i,5), 'row ' || i, sysdate+i );
 11      end loop;
 12
 13
 14      for x in  (select distinct a
 15                   from TABLE ( cast (l_data as myTableType) ) )
 16      loop
 17          dbms_output.put_line( x.a );
 18      end loop;
 19  end;
 20  /

Procedure created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> exec my_proc
0
1
2
3
4

PL/SQL procedure successfully completed.
April 09, 2001 Reji -- Thanks for the question regarding "DATE vz NUMBER comparison", version 8.1.6
You Asked
Tom:
    Comparing two dates versus two numbers, which one is faster and why?

Thx
Reji
and we said...
dates = 7 byte binary compare.
numbers = 1 to 22 byte binary compare.

on average, they are about the same  -- it is rare for a number to be much
bigger then a date.
Review & Followup
Rating: 5
April 10, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

April 11, 2001 -- Thanks for the question regarding "Two databases on one machine", version 8.1.5
You Asked
Hi,
 This happened on a test server. The previous DBA had created two databases -
global and test - on this machine. On starting the server manager, it connects
to the test database. And to connect to global database I had to use ' connect
internal@global ', from the server manager prompt. I have the following
questions.

- Where does server manager utility look for which database to reference in the
above case? (I know that it looks for the internal pwd in the password file
'pwdsid.ora'.)

- I dropped the test db. And on starting the server manager I started getting
the error 'Ora-12560 TNS protocol adapter error', however I could use 'connect
internal@global' at the server manager prompt to startup my database. Why did I
get 'Ora-12560 TNS protocol adapter error'?

- With reference to the above question, if I try to connect from sqlplus (on the
server) using 'user/pwd' (without connect string), it gives 'Ora-12560 TNS
protocol adapter error'. Why?? How can I resolve this?

Thanks,

N
and we said...
it looks for GLOBAL in the $ORACLE_HOME/network/admin/tnsnames.ora file or if
the environment variable TNS_ADMIN was set, it'll look for it in
$TNS_ADMIN/tnsnames.ora

because the ORACLE_SID was set to test.  svrmgrl tries to start a session
immediately with the default database.  Set your ORACLE_SID to the SID for
global and it'll not do this (nor will you have to connect internal@global)

Same reason as svrmgrl giving the error -- the database specified in the
ORACLE_SID environment variable no longer exists.  Change your ORACLE_SID and it
won't do this.
Review & Followup
Rating: 5
April 12, 2001
Reviewer: Nitin from India

Rating: 5
April 12, 2001
Reviewer: TinTin from Denver
I found the ORACLE_SID environment variable in the registry. And observed that
when I had dropped my first database using the Database Configuration Assistant,
it did not modify the ORACLE_SID value. On modifying this value to my existing
db SID the TNS protocol adapter error has been resolved. The information was
very helpful. Thanks.

April 11, 2001 Sanjay -- Thanks for the question regarding "Is there anything other then DBMS_SQL", version 8.1.7
You Asked
Hi Tom,

May I know which are other methods to use dynamic sql through Pl/sql
in Oracle besides DBMS_SQL package ?

Regards,
--Sanjay.
and we said...
In Oracle8i there is Native Dynamic SQL which is much easier to code with then
DBMS_SQL.

See
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a77069/10_dynam.htm#4376
for details.
April 11, 2001 Sunder -- Thanks for the question regarding "Conversion of data from an ORACLE database into indexed-PDF documents", version ORACLE 8
You Asked
Tom,
     We have a situation where there is a large amount of textual data in an
ORACLE database pertaining to insurance policy holders. We want to be able to
retrieve policy data selectively and generate PDF files that can be sent to
individual policy holders. Each PDF file will have data pertaining to one
holder.

How can we do that ?

Would appreciate an early response.

Thanks,
Sunder
and we said...
Oracle Reports is capable of generating PDF files.
http://www.oracle.com/ip/deploy/ias/bus_intel_2/index.html?reports.html
...
Review & Followup
Rating: 3
April 12, 2001
Reviewer: A reader

April 11, 2001 Rick -- Thanks for the question regarding "Calling Java methods from PL/SQL", version 8i
You Asked
Where can I find some code samples of how to call methods in a
Java program or class from PL/SQL.  I need to pass VARCHAR2
variables to Java as strings or String objects.

Thanks
RC
and we said...
Examples:
http://asktom.oracle.com/pls/ask/f?p=4950:7:::::F4950_P7_SEARCH_CRITERIA:create+replace+java+source+named

but for the full documentation
http://technet.oracle.com/doc/oracle8i_816/java.816/a81358/03_pub.htm#16482
...
April 11, 2001 Richard -- Thanks for the question regarding "Long Data Type", version 8.1.7
You Asked
I would like to select the text from the user_views table, the column is a long
type, how do I get the text ? I tried to write a store procedure but didn't
print out the text using dbms_output.put_line,

here is the code:

 create or replace procedure rdm is
 x varchar2(32000);
 begin
 select text into x from all_views where view_name = 'V_OLD_ADVERTISEMENTS';
 dbms_output.put_line(x);
 end;

error code :

begin
*
FEHLER in Zeile 1:
ORA-06502: PL/SQL: numerisch oder Wertefehler
ORA-06512: in "SYS.DBMS_OUTPUT", Zeile 43
ORA-06512: in "HOMEGATE.RDM", Zeile 5
ORA-06512: in Zeile 2

Thanks

Richard

p.s. Can I replace the tabs,space to make the output more readable ??
and we said...
Well, I would just:

SQL> set long 50000
SQL> select text from all_views where view_name = 'V_OLD_ADVERTISEMENTS';

dbms_output has a line length limit of 255 bytes per line, you are exceeding
that limit apparently.  You can write a wrapper routine to dbms_output like I
have below:

ops$tkyte@ORA8I.WORLD> set serveroutput on format wrapped
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create or replace procedure rdm
  2  as
  3          x long;
  4
  5          procedure p ( p_str in varchar2 )
  6          is
  7                  l_str   long := p_str || chr(10);
  8                  n       number;
  9          begin
 10                  while (l_str is NOT NULL )
 11                  loop
 12                          n := instr( l_str, chr(10) );
 13                  dbms_output.put_line( substr( l_str, 1, n-1 ) );
 14                  l_str := substr( l_str, n+1 );
 15                  end loop;
 16          end;
 17  begin
 18
 19          select text into x from all_views where view_name =
'ALL_TAB_COLUMNS';
 20
 21          p(x);
 22  end;
 23  /

Procedure created.

ops$tkyte@ORA8I.WORLD> exec rdm
select u.name, o.name,
       c.name,
.....

Yes, you can replace the tabs using REPLACE( x, chr(9), '    ' )
Review & Followup
Rating: 5
very helpful December 12, 2001
Reviewer: A reader

April 11, 2001 Vipul -- Thanks for the question regarding "Does object with $ in their name are treated differently by Oracle?", version 8.1.6
You Asked
Hi,

I have a small question.

Normally, '$' in object names is common for internal object and objects owned by
SYS/SYSTEM.

However, If as a user I create a table with $ in it's name, Does Oracle will
treat that table in some different fashion?

Thanks.
and we said...
nope, it is just a table to us.  nothing special about it.
April 11, 2001 James -- Thanks for the question regarding "sql loader", version 816
You Asked
I want to input data from a file using sql loader.I have read through the
available samples on the site but my file seems quite a challenging one
The data is in this fomart order

A,HJ00034,Thu Dec  7 17:39:18 2000,,,,,,,,,
B,john,smith,admin@mywebsite.com,1 beacon House,Staltan
Street,London,(null),~GB,SE5 0XS,,
P,Credit,CyberCash,Visa,4.11E+15,Jan-00,,,,,,
X,message,Hello Hello, this is a message for you,mailchoice,Yes,,,,,,
S,Express delivery shipping,My other name,My second name,123 House Number,IN a
City,(null),~DZ,SE4 9TY,,,
I,J5409,1,£8.79,£8.79,,,,,,,
I,J5400,1,£33.89,£33.89,,,,,,,
T,£42.68,,,,,£42.68,,,,,

A,B,P,X,S,I,I,T are column identifiers.and are not required in the destined
tables.
The A record contains the invoice number and the date of the order.
The B record contains customer name and bill to address information.
The P record contains payment information. There are actually two types of P
records
depending on whether the customer used a check or credit card as a payment
method
The X record contains any comments.
The S record contains customer name and ship to address information.
The I record contains information about the product(s) being ordered. There will
be
as many I records as there are items ordered for each order.
The T record contains information about the order’s total monetary value.

The begining of every 'A' will indicate the begining of the  transaction and
likewise 'T' will indicate the end of this same unique transaction. I will need
to
put the results in tables as follows
A - customers Table(HJ00034 -will act as primary key) and order Table (HJ00034
will be foreign key in table)
B - customer Table
P - Payments table
x - Payments table
S - Shipping Table
I - Invoice Table
T - Invoice Table
I have tried using positions but this wouldnt workable as I will need to skip
and go to the next row. A Pointer in the right direction will be appreciated

James
and we said...
You won't be able to do that as a transaction in sqlldr.  SQLLdr can load this
file but the A...T records will NOT be considered "together".  It might insert
an A record, commit and then insert the B, P, fail on the X, succeed on the S,
I, I and T records and then commit -- placing the X record into a BAD file.

If transactional integrity is meaningful to you across these records, you'll NOT
be using SQLLDR.

Suggest you create a table like:

create table temp_load
( SEQ  int primary key,
  record_type char(1),
  c1 varchar2(4000),
  c2 varchar2(4000),
  ....
  cN varchar2(4000)
)
organization index
/

and use a ctl file like:

LOAD DATA
INFILE *
into table temp_load
replace
fields terminated by ","
trailing NULLCOLS
( seq RECNUM,
  record_type,
  c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,
  c11,c12,c13,c14,c15,c16,c17,c18,c19,c20
  )
begindata
A,HJ00034,Thu Dec  7 17:39:18 2000,,,,,,,,,
B,john,smith,admin@mywebsite.com,1 beacon House,Staltan Street,London,
....

  and then post process the loaded data using a plsql loop:

begin
   for x in ( select * from temp_load order by SEQ )
   loop
      if ( x.record_type = 'A' ) then commit; end; -- new transaction;
      if ( x.record_type = 'A' )
      then
          insert into table_a values ( x.c1, x.c2, .... x.c? );
      elsif ( x.record_type = 'B' )
      then
          insert into table_b values ( x.c1, x.c2, ... x.c? );
      .....
      end if;
   end loop;
   commit;  -- the last transaction
end;
April 12, 2001 Sitansh -- Thanks for the question regarding "Stored Procedure Compilation Error -- ", version 8
You Asked
I am trying to compile my Stored Procedure but get an error . The error is
because in am use a dba_ table in the procedure.
If I use the same procedure a anonymous block from SQL Plus it executes is it
but does not store it as a Stored Procedure. I can select from all dba_ tables .
and we said...
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
has the answer.
April 12, 2001
      gaurang -- Thanks for the question
      regarding "sqlldr", version 8.1.6

      You Asked
hi tom

my datafile looks like

 number      date     time   const.
5000004000|20010409|14365340|0
5000004000|20010409|14365340|0
5000004000|20010409|14365340|0
5000008200|20010411|8042063|0
5000008200|20010411|8052319|0
5000008200|20010411|8042063|0

i have to load in date field  above date and time column as single field

SQL>  desc t
 Name                    Null?    Type
 ----------------------- -------- ----------------
 CUST_NO                          NUMBER
 CREATED                          DATE <------(load both date & time)
 CONST                            NUMBER

can u help me.

Thanks

      and we said...
Not in a straigt forward way -- we can do this but it'll require a bit of SQL.

LOAD DATA
INFILE *
into table t
replace
(
    cust_no position(1:100) "substr(:cust_no,1,nvl(instr(:cust_no,'|'),0)-1)",
    created position(1:100) "to_date( substr(:cust_no,instr(:cust_no,'|')+1,
instr(:cust_no,'|',1,3)-instr(:cust_no,'|')-1 ),'yyyymmdd\"|\"hham')",
    const   position(1:100) "substr(:cust_no,instr(:cust_no,'|',1,3)+1)"
)
begindata
5000004000|20010409|2am|0
5000004000|20010409|3am|0
5000004000|20010409|4am|0
5000008200|20010411|5am|0
5000008200|20010411|6am|0
5000008200|20010411|7am|0

a bit of good old fashioned parsing with substr and instr and we can do it.

Note: i had no idea how the number 14365340 could be a "time" component so I
used something I knew was a time.  You can apply the above concept in turn to
your data.

April 12, 2001 -- Thanks for the question regarding "Dynamic
      where clause in PL/SQL", version oracle 8i

      You Asked
If I have a package with a cursor and a select statement, but the where clause
of the select statement will change every time depending on what the user
enters.  I want to be able to set the value of the select statement in the
package body(procedure). How can this be coded. An example:

CURSOR <cursor_name> IS
    SELECT *
     FROM <table_name>
     WHERE (different everytime).

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
for the solution.
April 12,
      2001 -- Thanks for the question
      regarding "Reparsing SQL ", version 7.3.4

      You Asked
I saw this SQL in the v$sqleara with
invalidation=0
parcsed_calls=1380578
executions=1380578
This SQL is being re-parsed ( No.parsed calls = No. of executions) for each
execution,
 right?
But it is using host variables. So, I wonder why ? This is 7.3.4 on Solaris
2.5.1.

INSERT INTO  "TOM"."CUSTOMERS"
("ID","FIRSTNAME","LASTNAME","ADDRESS1","ADDRESS2")
VALUES (:C1 ,:C2 ,:C3 ,:C4 ,:C5 )

Thanks.

      and we said...
There are two types of parses

1) HARD parses.  This is the first time the query is being parsed. This takes a
long time.  Using bind variables avoids HARD parses.  You have avoided the worse
of the two parses.

2) SOFT parses.  When you submit the query, we hash it and try to find it in the
shared pool.  After we find it, we must verify it is in fact a query we can use
(same tables, set privs, etc).  This is a modest amount of work but still should
be avoided whenever possible.

If you have code that looks like:

   loop
       prepare the insert
       bind the insert
       execute the insert
       close the insert
   end loop

you need to change that into:

   prepare the insert
   loop
      bind the insert
      execute the insert
   end loop
   close the insert

Actually, if you have a subroutine or something it would be good to code:

  if ( first time called )
     prepare the insert
     first time = true
  end if

  bind
  execute

and just keep the insert cursor open for the duration of the program.
April 12, 2001 Zsolt -- Thanks for the question regarding "Which
      one is faster?", version 8.1.6

      You Asked
Hi Tom,

Which one is faster, dynamic native Sql or standard e.g. :

1.
  EXECUTE IMMEDIATE
  'Begin select egyszeru_ertek,egyszeru_dimenzio,Torzs_Megnevezes_Magyar1 '||
                  'Bulk collect into
Internet.EgyszeruTomb.Ertek,Internet.EgyszeruTomb.Mertekegyseg,Internet.EgyszeruT
omb.Megnevezes ' ||
                  ' from Egyszeru,Torzs '||
                  ' Where '||
                  ' egyszeru_cnr  = :1 And egyszeru_azonosito1 = :2 And '||
                  'egyszeru_azonosito1=torzs_azonosito1 and
egyszeru_azonosito2=torzs_azonosito2  ;'||
                  '  End; ' Using Azonosito,Tipus1;

2.

Begin
select egyszeru_ertek,egyszeru_dimenzio,Torzs_Megnevezes_Magyar1
                  Bulk collect into
Internet.EgyszeruTomb.Ertek,Internet.EgyszeruTomb.Mertekegyseg,Internet.EgyszeruT
omb.Megnevezes
                   from Egyszeru,Torzs
                   Where
                   egyszeru_cnr  = Azonosito And egyszeru_azonosito1 = Tipus1
And
                  egyszeru_azonosito1=torzs_azonosito1 and
egyszeru_azonosito2=torzs_azonosito2  ;
                    End;

Thank you

      and we said...
STATIC sql, in addition to be infinitely easier to code, will almost certainly
be faster then dynamic sql in all cases.

In the above case, it is 100% sure that STATIC sql is the way to go.  Do NOT use
dynamic sql unless you HAVE to in plsql.
Review &
      Followup

      Rating: 4
Which one is
      faster?  April 13, 2001
Reviewer:  Zsolt
      Csillag

      Rating:
      5
  April 13, 2001
Reviewer:  Dusan
      Valasek  from MA USA

      Rating:
      3
  July 20, 2001
Reviewer:  Pichaimani
      Balasubramanian  from San Jose, CA USA

April 12, 2001 Suresh -- Thanks for the question regarding "SQL
      plus - optimization", version 8i

      You Asked
Tom,
  I have an insert statement as shown below.

insert into calc_account_level(account_key,account_level)
   (select DISTINCT parent_account_key, 2 from sum_acc_p_child
      where child_account_key IN
   (select account_key from calc_account_level)
      and parent_account_key NOT IN
   (select account_key from calc_account_level)
and parent_account_key NOT IN
   (select parent_account_key from sum_acc_p_child  where
child_account_key NOT IN (select account_key from
                           calc_account_level));

The above statement does not use the index as there is 'NOT IN' being used. Is
there any way I could optimize the query and make it use an index as the above
statement is taking too much time now to execute.
Thanks a lot.

      and we said...
Well, at the bottom, I've given you two alternatives.  Before we get to them
however, lets look at the basic issue.  You should also look at

http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/optimops.htm#36687
Since you say it is not using an index, I have to assume one (or both) of two
things

o you are not using the COST BASED OPTIMIZER
o calc_account_level.account_key is NULLABLE

If either is true, the index will not be used.  The first case is easy to fix,
use the CBO and Oracle will see that it can use the index.  If the second case
is true -- then we can exclude NULLS in the subquery, use the CBO and it'll
work.

Bear in mind that the answers will be DIFFERENT if you exclude NULLS.  Consider
this case:

ops$tkyte@ORA8I.WORLD> create table t1 ( x int );
Table created.

ops$tkyte@ORA8I.WORLD> create table t2 ( y int );
Table created.

ops$tkyte@ORA8I.WORLD> create index t2_idx on t2(y);
Index created.

ops$tkyte@ORA8I.WORLD> insert /*+ APPEND */ into t1 select object_id from
all_objects where rownum < 1000;

999 rows created.

ops$tkyte@ORA8I.WORLD> insert /*+ APPEND */ into t2 select object_id from
all_objects where rownum < 0999;

998 rows created.

ops$tkyte@ORA8I.WORLD> commit;
Commit complete.

ops$tkyte@ORA8I.WORLD> insert into t2 values ( NULL );
1 row created.

ops$tkyte@ORA8I.WORLD> analyze table t1 compute statistics for table;
Table analyzed.

ops$tkyte@ORA8I.WORLD> analyze table t2 compute statistics
  2  for table
  3  for all indexed columns
  4  for all indexes;
Table analyzed.

ops$tkyte@ORA8I.WORLD> set autotrace on

ops$tkyte@ORA8I.WORLD> select *
  2    from t1
  3   where x not in ( select y
  4                      from t2  )
  5  /

no rows selected

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=50 Bytes=400)
   1    0   FILTER
   2    1     TABLE ACCESS (FULL) OF 'T1' (Cost=1 Card=50 Bytes=400)
   3    1     TABLE ACCESS (FULL) OF 'T2' (Cost=1 Card=50 Bytes=400)

Statistics
----------------------------------------------------------
          0  recursive calls
       4008  db block gets
       1344  consistent gets
          0  physical reads
          0  redo size
        209  bytes sent via SQL*Net to client
        314  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

Note: no rows found.  we KNOW there is at least one row isn't there?  No, in
fact there is not.  Not given the semantics of a NOT IN anyway.  The NULL throws
off the result set.  As soon as the subquery returns NULL, no rows are "not in"
the set -- it is UNKNOWN of X is NOT IN ( null ) -- so no rows are returned.

Adding a IS NOT NULL to the subquery results in:

ops$tkyte@ORA8I.WORLD> select *
  2    from t1
  3   where x not in ( select y
  4                      from t2
  5                     where y is not null    )
  6  /

         X
----------
    100561

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=50 Bytes=400)
   1    0   FILTER
   2    1     TABLE ACCESS (FULL) OF 'T1' (Cost=1 Card=50 Bytes=400)
   3    1     INDEX (FULL SCAN) OF 'T2_IDX' (NON-UNIQUE) (Cost=3 Card=
          50 Bytes=400)

Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
       2504  consistent gets
          0  physical reads
          0  redo size
        362  bytes sent via SQL*Net to client
        425  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

Notice now a row IS returned (different answer).  Now the index can be used...
Depending on the circumstances, not exists might go better (might -- it depends,
try both)

ops$tkyte@ORA8I.WORLD> select *
  2    from t1
  3   where NOT EXISTS ( select null
  4                        from t2
  5                       where t2.y = t1.x )
  6  /

         X
----------
    100561

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=50 Bytes=400)
   1    0   FILTER
   2    1     TABLE ACCESS (FULL) OF 'T1' (Cost=1 Card=50 Bytes=400)
   3    1     INDEX (RANGE SCAN) OF 'T2_IDX' (NON-UNIQUE) (Cost=1 Card
          =2 Bytes=16)

Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
       2004  consistent gets
          0  physical reads
          0  redo size
        362  bytes sent via SQL*Net to client
        425  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

So, here are two alternatives to your query:

insert into calc_account_level(account_key,account_level)
(select DISTINCT parent_account_key, 2
   from sum_acc_p_child
  where child_account_key IN (select account_key
                                from calc_account_level)
    and parent_account_key NOT IN (select account_key
                                     from calc_account_level
                                    where account_key is not null )
    and parent_account_key NOT IN
            (select parent_account_key
               from sum_acc_p_child
              where parent_account_key IS NOT NULL
                and child_account_key NOT IN (select account_key
                                                from calc_account_level
                                               where account_key IS NOT NULL
                                              )
             );

insert into calc_account_level(account_key,account_level)
(select DISTINCT parent_account_key, 2
   from sum_acc_p_child t1
  where child_account_key IN (select account_key
                                from calc_account_level)
    and NOT EXISTS (select account_key
                      from calc_account_level t2
                     where t2.account_key = t1.parent_account_key )
    and NOT EXISTS (select parent_account_key
                      from sum_acc_p_child  t3
                     where t3.parent_account_key = t1.parent_account_key
                       and NOT EXISTS (select account_key
                                         from calc_account_level t4
                                        where t4.account_key =
                                                      t1.child_account_key
                                      )
                    );

April 12, 2001 Patibandla -- Thanks for the question regarding
      "Control File - Reg.", version 8.1.6.0

      You Asked
Why do u require 3 control files.
How do u find which control file(s) is being used .

Regards
Koshal

      and we said...
we do not require, we SUGGEST that you use 3.  1 is the minimum.

Redundancy is good for recoverability.  for the same reason we suggest
multi-plexing your redo log files, we suggest multi-plexing your control files.

select * from v$controlfile;

shows you the controlfiles in use.

April 12, 2001 Patibandla -- Thanks for the question regarding
      "Cursor Life - Reg", version 8.1.6.0

      You Asked
Can we make the cursor active throughout the session,
if so, how.

I mean like the state of variables in package and it is not
allowing to define cursor variable in the package. How do we go about
it

Regards
Koshal

      and we said...
Cursor VARIABLES cannot be global.  Cursors can be.

create package my_pkg
as
  cursor c1 is select * from emp;
end;
/

is valid.  Cursor variables however must be local to a procedure, they can be
returned to a client (who can keep them open as long as they like) but not in
PLSQL.  In PLSQL, once they are opened -- you must either fetch from them and
close or return them to a client.  That is the way they work.

If you need to keep a dynamically opened query open across calls to the
database, you must use DBMS_SQL and its cursor type instead.

April 12, 2001 Ranjan -- Thanks for the question regarding
      "Using Savepoints", version 8.1.x

      You Asked
In a distributed transaction can it calls an api which uses 'SAVEPOINTS'.
Procedure p1 over database link needs to calls procedure p2
Procedure p2 in turns calls a series of api and some of the api uses
'SAVEPOINTS' . So I get the error which says that can not set savepoint in a
distributed transactions. So is there any way I can accomplish this task. I
tried calling p2 and making p2 an autonomous transaction but it didn't help. So
is there any other way?

Thanks
Ranjan

      and we said...
No, you cannot do TRANSACTION control statements in a remotely executed
procedure.

What if procedure p1 calls p2.  P2 issues a savepoint.  You return to P1, P1
calls P3 on another machine.  P3 finishes and P1 calles P2 again.  P2 now does a
"rollback to savepoint".  Well, P2 has no clue about P3 -- cannot do anything
about it.

ALL transaction control statment, ALL of them, must originate from the original
initiating database.  It is the ONLY database that understands all of the
participants in the global transaction.
April 13, 2001 Patibandla -- Thanks for the question regarding
      "Execution Processs of Sql Statement - Reg.", version 8.1.6.0

      You Asked
I have sql statement like this

 SELECT
    FIND_PRODUCT(A.SM_PSC_ID,A.SM_PSC_TYPE) ,
    FIND_BARCODE(A.SM_PSC_ID,A.SM_PSC_TYPE) ,
    A.SM_PRODSRLNO,
    FIND_SKU(A.SM_PSC_ID,A.SM_PSC_TYPE) ,
    A.SM_ACTIVITY,
    A.SM_FULFILL_STATUS,
    SM_FULFILL_DESC,
    A.SM_OBJECTID
    FROM SM_PRODMOVEMENT A
    WHERE A.SM_OBJECTTYPE='WORK ORDER'
    AND A.SM_STATUS_TYPE='RECEIVE'
    AND A.SM_ISCURREC(+)='Y'

the function is something like this

FUNCTION Find_Product(
M_PSC_ID       IN NUMBER,
M_PSC_TYPE     IN VARCHAR2)
RETURN VARCHAR2
IS
M_PROD_NAME        VARCHAR2(200):=' ';
MPSC_TYPE           VARCHAR2(50);
BEGIN
     MPSC_TYPE:=UPPER(M_PSC_TYPE);
     IF MPSC_TYPE='PRODUCTS' OR M_PSC_TYPE='PRODUCT' THEN
           SELECT SM_PROD_NAME INTO M_PROD_NAME FROM SM_PRODUCTS WHERE
SM_PRODSRLID=M_PSC_ID AND ROWNUM<2;
     ELSIF MPSC_TYPE='SPARES' OR M_PSC_TYPE='SPARE' THEN
             SELECT SM_SPARENAME INTO M_PROD_NAME FROM SM_SPAREPARTS WHERE
SM_SPARESRLID=M_PSC_ID AND ROWNUM<2;
     ELSIF MPSC_TYPE='SPARE PART UNIT' THEN
             SELECT SM_SPARENAME INTO M_PROD_NAME FROM SM_SPAREPARTS WHERE
SM_SPARESRLID=M_PSC_ID AND ROWNUM<2;
     ELSIF MPSC_TYPE='CUSTOMER UNIT' OR M_PSC_TYPE='VENDOR UNIT' THEN
             SELECT SM_SPARE_NAME INTO M_PROD_NAME FROM SM_CUSTPARTS WHERE
SM_PSC_ID=M_PSC_ID AND ROWNUM<2;
     ELSIF MPSC_TYPE='CSP' THEN
             SELECT SM_CSP_TITLE INTO M_PROD_NAME FROM SM_CSP WHERE
SM_CSPID=M_PSC_ID AND ROWNUM<2;
     END IF;
     RETURN TRIM(M_PROD_NAME);
EXCEPTION
      WHEN NO_DATA_FOUND THEN
           LOG_ERROR;
              RETURN TRIM(M_PROD_NAME);

      WHEN OTHERS THEN
           LOG_ERROR;
              RETURN TRIM(M_PROD_NAME);

END Find_Product;

The functions find_barcode and find_sku are also
same as find_product except for change in the column.

i.e. based on the type and id they get the data from
the same table same row (no duplicate rows).

In such a scenario

Are 3 functions individually evaluated
u hit the table thrice for each of the function.

or  3 functions combined evaluated.

Regards

Koshal

      and we said...
All three functions are individually evaluated, they have to be -- different
inputs, different functions, different results.

You hit the table three times.

You could improve this by returning an object type from a SINGLE function.  That
would avoid the overhead of 2 of the function calls and if you make the single
function as efficient as possible, doubling up the work where possible -- it'll
run faster over all.

consider:

Here are the three types we want to return, a number, date and string:

ops$tkyte@ORA8I.WORLD> create or replace type my_data as object
  2  ( a int, b date, c varchar2(25) )
  3  /

Type created.

now we create a function that returns that type -- its just a demo, your logic
would have to be put into it of course

ops$tkyte@ORA8I.WORLD> create or replace function f( p_x in number, p_y in
number ) return my_data
  2  as
  3  begin
  4          -- your logic here to collect together
  5          -- the necessary data
  6          return my_data( 1, sysdate, 'hello' );
  7  end;
  8  /

Function created.

we can now fetch it in SQL

ops$tkyte@ORA8I.WORLD> select dummy, f( 1, 2 ) my_data
  2    from dual
  3  /

D
-
MY_DATA(A, B, C)
---------------------------------------------------------------------------------
-------------------
X
MY_DATA(1, '13-APR-01', 'hello')

and if your client cannot deal with OBJECTS, we can turn them into scalars
easy enough using an inline view:

ops$tkyte@ORA8I.WORLD> select dummy, a.my_data.a, a.my_data.b, a.my_data.c
  2    from ( select dummy, f( 1, 2 ) my_data
  3             from dual ) A
  4  /

D  MY_DATA.A MY_DATA.B MY_DATA.C
- ---------- --------- -------------------------
X          1 13-APR-01 hello

April 13, 2001 DERMOT -- Thanks for the question regarding
      "CALLING FUNCTIONS FROM VB", version 8.1.5

      You Asked
Tom, not sure if this the right area to ask you this!
Trying to call a function from VB (6.0 SP4) to return values using ado.

Any ideas or sample code would be helpful

Thanks.

      and we said...
Instead of returning a value as an OUT or an IN/OUT parameter, this sample uses
a Stored Function to return a numeric value. The key is the use of the
adParamReturnValue parameter. (Last test Aug 2000 using VB 6 SP3 and ODBC
version 8.1.6.1.0)

--------------------------------------------------------------------------------

--****************************Start PL/SQL****************************
CREATE OR REPLACE PACKAGE Calc AS
   Function Add5 (num in number) RETURN NUMBER;
END Calc;
/

CREATE OR REPLACE PACKAGE BODY Calc AS
   Function Add5 (num in number) RETURN NUMBER IS
      Begin
      Return (num + 5);
   End Add5;
END Calc;
/
--****************************End PL/SQL****************************

'****************************Start VB Code****************************
   Dim con As New ADODB.Connection
   Dim cmd As New ADODB.Command
   Dim InputParam As New ADODB.Parameter
   Dim ReturnParam As New ADODB.Parameter

   con.ConnectionString = "DSN=ODBC8; UID=scott; PWD=tiger;"
   con.Open

   cmd.ActiveConnection = con
   cmd.CommandText = "Calc.Add5"
   cmd.CommandType = adCmdStoredProc
   Set InputParam = cmd.CreateParameter("Prm1", adSmallInt, adParamInput, , 30)
   'Using adParamOutPut instead of adParamReturnValue will result in the
   'following error:
   'ORA-24334 - no descriptor for this position
   'Set Prm2 = cmd.CreateParameter("Prm2", adSmallInt, adParamOutput)
   Set ReturnParam = cmd.CreateParameter("Prm2", adSmallInt, adParamReturnValue)

   'You will also get the ORA-24334 error if you don't Append the parameters
   'in the correct order. Make sure to bind the Returning parameter first.
   cmd.Parameters.Append ReturnParam
   cmd.Parameters.Append InputParam

   cmd.Execute
   MsgBox "Input Value = " & cmd.Parameters(1)
   MsgBox "Return Value = " & cmd.Parameters(0)
'****************************End VB Code****************************

Review &
      Followup

      Rating: 2
Error even when
      no parameter is passed  October 04, 2001
Reviewer:
      Pranav  from CT, USA
I have a function that goes like:
create or replace function TestRecordset
return types.cursorType
AS
  l_cursor  types.cursorType;
begin
  open l_cursor for select * from table1 where rownum <= 5;
  return l_cursor;
end;

The type is created earlier in this manner:
create or replace package types
as
    type cursorType is ref cursor;
end;

I am trying to use ADO To return the recordset but I get the

[Oracle][ODBC][Ora]ORA-24334: no descriptor for this position

error.

the way the code is executed on the asp side is like
Get the connection(objConn) and now set the Command.

Set cmdStoredProc = Server.CreateObject ("ADODB.Command")
Set cmdStoredProc.ActiveConnection = objConn
cmdStoredProc.CommandText = "TESTRECORDSET"
cmdStoredProc.CommandType = adCmdStoredProc

Set rs1 = cmdStoredProc.Execute

I get the error on cmdStoredProc.Execute
Can you explain why??

      Rating: 5
ADODB and Ref
      Cursor parameters: the last piece in the puzzle  June 30,
      2003
Reviewer:  Nigel Heffernan  from London, England

I've been trying, for far too long, to get ref cursors back from Oracle and into
a VBA client. You can do it using the Oracle InProc server, but that does't
support asynchronous fetching. You can try doing it using ADO, but I suspect
that most developers give up. Here's why:

The ADODB .CreateParameter method only allows a very limited set of return
types, making it almost impossible to get a cursor back into the client
application.

.CreateParameter("myCursor", adVarChar, adParamOutput)

Try it - even if the parameter creation method succeeds, you'll get an 'invalid
SQL' error when the ADO Fetch is completed.

The last piece in the puzzle was the 'adParamReturnValue' constant in this
example.

.CreateParameter("myCursor", adNumeric, adParamReturnValue)

Every other code sample I've seen uses adParamOutput and I have yet to see a
working example. You'll still have to play with the type - adVarChar doesn't
work everywhere - but at least it compiles, runs, and returns data on an 8.06
client.

Here's a sample (not the full listing, which is full of statistical stuff) which
gives a simple example:

/*PL SQL FRAGMENT **************/

CREATE OR REPLACE PACKAGE HISTVOLSTATS AS

TYPE Recordset IS REF CURSOR;

PROCEDURE GetRecordset
(
    StartDate    IN NUMBER,
    EndDate      IN NUMBER,
    lngStockID   IN NUMBER,
    myRecordset IN OUT Recordset
);

END HistVolStats;

CREATE OR REPLACE PACKAGE BODY HISTVOLSTATS AS

PROCEDURE GetRecordset
(
    StartDate   IN NUMBER,
    EndDate     IN NUMBER,
    lngStockID  IN NUMBER,
    myRecordset IN OUT Recordset
)
IS
   BEGIN

   OPEN myRecordset FOR
        SELECT
            tblPrice.*
        FROM
            tblPrice
        WHERE
            tblPrice.TradingDay  > StartDate
        AND tblPrice.TradingDay <= EndDate
        AND tblPrice.StockID     = lngStockID

        ORDER BY
            tblPrice.TradingDay DESC;

    END;

END HistVolStats;

'VBA Fragment *******************

lngStart = CLng(StartDate)
lngEnd = CLng(EndDate)
lngStockID = LookupStockID(Ticker)

Set rst = New ADODB.Recordset
Set cmd = New ADODB.Command

With cmd

    .ActiveConnection = connLocal

    .CommandText = "HistVolStats.GetRecordset"
    .Prepared = False

    .CommandType = adCmdStoredProc

    .Parameters.Append .CreateParameter( _
                            "StartDate", _
                             adInteger, _
                             adParamInput _
                             , , lngStart)

    .Parameters.Append .CreateParameter( _
                            "EndDate", _
                             adInteger, _
                             adParamInput _
                             , , lngEnd)

    .Parameters.Append .CreateParameter( _
                            "lngStockID", _
                             adInteger, _
                             adParamInput _
                             , , lngStockID)

    .Parameters.Append .CreateParameter( _
                            "myRecordset", _
                             adNumeric, _
                             adParamReturnValue)

    Set rst = .Execute(, , adAsyncFetchNonBlocking)

End With 'cmd

Set cmd = Nothing

April 13, 2001 Sridhar -- Thanks for the question regarding
      "Getting back a table from a procedure", version 8i

      You Asked
Hi,
I have a procedure which takes in 5 parameters.
This procedure executes a cursor and stores the values in a PL/SQL table which
has 4 columns. I want to return the values that I have stored in the PL/SQL
table to the calling procedure.
I would like to know how I can accomplish this.

Scenario:
Procedure aa calling procedure bb with 5 parameters
Procedure bb should return a table with the values that it gets back to
procedure aa.

Thanks for your help.
Sridhar

      and we said...
You should use a ref cursor and not tables for this type of work.  See

http://osi.oracle.com/~tkyte/ResultSets/index.html
for examples.

Otherwise, just pass the tables back and forth as parameters:

ops$tkyte@ORA8I.WORLD> create or replace package types
  2  as
  3          type array is table of number index by binary_integer;
  4  end;
  5  /

Package created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create or replace procedure bb( x in out types.array )
  2  as
  3  begin
  4          for i in 1 .. 5 loop
  5                  x(i) := i;
  6          end loop;
  7  end;
  8  /

Procedure created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> set serveroutput on
ops$tkyte@ORA8I.WORLD> create or replace procedure aa
  2  as
  3          l_data types.array;
  4  begin
  5          bb(l_data);
  6
  7          for i in 1 .. l_data.count loop
  8                  dbms_output.put_line( l_data(i) );
  9          end loop;
 10  end;
 11  /

Procedure created.

ops$tkyte@ORA8I.WORLD> exec aa
1
2
3
4
5

PL/SQL procedure successfully completed.
Review &
      Followup

      Rating: 4
Getting back a
      table from a procedure  April 16, 2001
Reviewer:
      Sridhar Kaliyur  from Boston, MA
Thank you very much. This solved my problem and I found it very very useful.

April 13, 2001 Rajesh -- Thanks for the question regarding
      "Union of CLOB datatype -> ORA-00932: inconsistent datatypes", version
      8.1.6

      You Asked
I have table T1 ( id number, content CLOB ) and table T2 ( id number, content
CLOB ) where T2 is snapshot of remote table. Both of them have identical
structure. I want to select all the records from T1 and T2, thus I am trying,
"select id, content from T1 UNION select id , content from T2 ;"

 This returns ORA-00932: inconsistent datatypes

Is it not allowed to have union of clob ?
How do I get all the records using a single Query ?

Thanks,
Rajesh

      and we said...
Use a union ALL

ops$tkyte@ORA8I.WORLD> create table t1 ( x int, y clob );

Table created.

ops$tkyte@ORA8I.WORLD> create table t2 ( x int, y clob );

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select * from t1
  2  union
  3  select * from t2;
select * from t1
       *
ERROR at line 1:
ORA-00932: inconsistent datatypes

ops$tkyte@ORA8I.WORLD> select * from t1
  2  union all
  3  select * from t2;

no rows selected

A union of "a" and "b" is really:

SORT DISTINCT ( "a" + "b" )

A union ALL of "a" and "b" is

"a" + "b"

the sort distinct cannot be done on the clob type.
Review &
      Followup

      Rating: 5
Union of CLOB
      datatype -> ORA-00932: inconsistent datatypes  April 13,
      2001
Reviewer:  Rajesh Jadhav  from Columbus

Thanks,
Rajesh

April 13, 2001 Harsh -- Thanks for the question regarding "Table
      to datafile mapping and some misc. questions.", version 8.1.6

      You Asked
Environment:

Windows NT server 4.0
Oracle 8.1.6 Enterprise edition

1. How do we know Table to datafile mapping ?
i.e. a perticular table is stored in which datafile of a tablespace.

2. How to we know the space allocation i.e. space consumed and free, datafile
wise.

3. How to change the sqlprompt automatically again, after we connect to some
different user and instance in sql+ using connect command.

4. We know that there are so many "set" configurations but when we use show all
it doesn't displays all the "set" settings.
e.g. as a sample example scan setting is not displayed.

Why some settings are missed ?

5. How can we use multiple languages in Sql+ e.g. English and Greek ?

6. Where can i get the LONG LONG journey of Oracle ?

Thanks in advance.
- Harsh

      and we said...
select tablespace_name from user_tables where table_name= 'T';

select file_name from dba_data_files where tablespace_name = (select
tablespace_name from user_tables where table_name= 'T');

2)

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
3)

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1418603973488
4) scan is obsoleted.  still there but obsolete.  same with buffer, closecursor,
document, maxdata, space, truncate, and label.

See appendix F of your sqlplus guide.

5) set your NLS_LANG or use the corresponding alter session.

alter session set nls_language = 'Greek';

6) I do not understand that question.

Review &
      Followup

      Rating:
      3
  April 14, 2001
Reviewer:  Harsh
       from US

April 13, 2001 Ai -- Thanks for the question regarding "rollup
      average", version Oracle 7.3 and 8.0

      You Asked
Hi,

I have two tables.

"Ticket" table contains the following fields:
ticket_no,
resolved_person_id,
resolved_date

and "Analyst" table contains:
analyst_id,
last_name,
first_name,
supervisor

I want to create a report that shows total tickets resolved by an analyst per
month.  The supervisor of the analyst should have total tickets resolved by
analysts who works under her.

Can I do that and how?

Thanks,

Ai

      and we said...
select analyst_id, trunc(resolved_date,'mm'), count(*)
  from analyst, ticket
 where analyst.analyst_id = ticket.resolved_person_id
 group by analyst_id, trunc(resolved_date,'mm')

gives you the first set of data.

select supervisor, trunc(resolved_date,'mm'), count(*)
  from analyst, ticket
 where analyst.analyst_id = ticket.resolved_person_id
 group by supervisor, trunc(resolved_date,'mm')

gives you the second set of data.  You could of course UNION ALL the two queries
together.

April 13, 2001 -- Thanks for the question regarding "Query Vs.
      Transaction", version 8.1.7

      You Asked
Hi,

can U please give me an example for a "QUERY", "TRANSACTION" & a "STATEMENT"
ie...when the query begins and transaction begins etc.

Thankx

      and we said...
A query begins when you OPEN the cursor.

declare
   c1 cursor for select * from dual;
begin
   open c1; <<== query begins

A transaction beings upon execution of the first statement that modifies data in
the database.

SQL> update t set x = 5;  <<<== transaction begins

both are examples of statements.

April 13, 2001 Sanjay -- Thanks for the question regarding
      "Better emailing method UTL_SMTP/UTL_TCP/Enqueing", version 8.1.7

      You Asked
Hi Tom,

I have a situation where I have to send a bulk emails with different
contents for every one in a job scheduled buy DBMS_JOB.

The no. of recipients may be in thousands.

Kindly tell me which one of the above (UTL_SMTP/UTL_TCP/Enqueing)
is best suited and why.  Or is there something better way available ?

Thanks in advance,
--Sanjay.

      and we said...
UTL_SMTP would be superior to UTL_TCP as UTL_SMTP is simply a layer on top of
UTL_TCP that you would have to build if you used that.

AQ would require you to set up a process outside of the database and have it
running.  DBMS_JOB will just run the jobs for you.

I myself use UTL_SMTP to send email from the database -- about 5,000 every day
during the week.

I would recommend it.

April 14, 2001 Harsh -- Thanks for the question regarding
      "Oracle Journey", version 8.1.6

      You Asked
http://asktom.oracle.com/pls/ask/f?p=4950:8:55377::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:498364911663,
Hi Tom,

The above string is for the reference 'coz the question is from the answer of
the questions.

Question No. 3 ( SQL Prompt )

I was trying the same thing with DB trigger on logon.
Is it the right approach ?
But i am unable to use set commands in this, why ?

Pl. let me know how do i change the prompt with connect also.
I understand the solution at the link i.e. using connect.sql but how can we do
it with DBT.

Questions No. 6

This is a bit historical question. I want to know about when Oracle started with
the First version and the journey till Oracle 9i.

In a manner [ Oracle Version      Date launched ]

I hope the question is clear this time.

Thanks in advance.
- Harsh

      and we said...
You cannot set the sqlplus prompt with a database logon trigger.  The database
has no idea that SQLPlus is the tool you are using and (more importantly) the
database cannot issue SQLPlus commands -- only sqlplus can do that.  This would
be like trying to use a database logon trigger to put a message box up on the
screen of the end user -- it doesn't make sense.  The database cannot tell the
client application what to do - the client application tells the database what
to do.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1209036002099
for links to the history of Oracle.

Review &
      Followup

      Rating: 5
Damn Good
      !!!  April 15, 2001
Reviewer:  Harsh
       from US
I got real good answer as usual.

April 14, 2001 Harsh -- Thanks for the question regarding
      "Developing WEB based application - Update and questions on Priviledges",
      version 8.1.6

      You Asked
These are the questions based on ur answer at following link.

http://asktom.oracle.com/pls/ask/f?p=4950:9:::NO::F4950_P9_ORIG,F4950_P9_DISPLAYID:Y,432025751107
Environment Details:

O/S      : Windows NT 4
Database : Oracle 8.1.6 Enterprise Edition

Question - 1
============
Currenly I have Installed Oracle database 8.1.6 and it is working.

From ur answer I found that  for a Hardcore Oracle Guy ( +Oracle and -Java ),
the best ( for me ) suitable is using PL/SQL and OWA Toolkit.
Now the questions:
1. Is OWA Toolkit is part of Oracle 8i, In fact I couldn't found it.
2. I Installed the Oracle WEB Server Version 2.1.
   a) While Installing it founds that ORACLE is already there so I
      renamed the ORACLE node in registry and Installed it.
   b) Now WebServer is installed but Oracle Database is not present.
3. Now My questions are
   a) Am I doing the right thing i.e. Oracle database and Webserver on same
machine. Though both are not running together. Pl. let me know HOW TO USE ORACLE
8.1.6 and ORACLE WEB SERVER 2.1 ON SAME MACHINE i.e. WINDOWS NT 4 SERVER.
   b) Is there any other way to use OWA Toolkit.
4. Infact I went thru Oracle WEB Server Installation Manual also but I am afraid
there is not enough explaination.

In one line MY AIM IS TO DEVELOP A WEB BASED APPLICATION USING ORACLE 8.1.6 ON
WINDOWS NT SERVER 4 THAT TOO USING PL/SQL AND OWA TOOLKIT.

Pl. let me know if u need some more details.

Question - 2
============
------------------------------------------------------------------
In my previous mail one of the question is unanswered, I will again explain it.
If we go thru the Oracle Concepts - Chapter 1 it briefly explains all about
Oracle DB.
I am looking for any similar document/book which BRIEFS all about the complete
ORACLE.

Question - 3
============

In Unix to see Oracle error we use the shell oerr, How to see the similar error
explaination in Windows NT.

Thanks in advance.
- Harsh

      and we said...
1) it is with 8.1.7 -- with 8.1.6 you need oas or ias (ias is better).  In 8.1.7
-- the database itself is the only thing you need -- there is a webserver inside
of it.

2) use the oracle home selector tool from the start menu to set your default
oracle home to the database oracle home.  they are both there.

3) it works, i've used that configuration.  you need to use net8 from ows2.1 to
the database (set up the listener and all) and they should be installed into
separate oracle homes.

Question 2)

that is the concepts manual -- unless by "complete oracle" you mean the
applications, the tools, the system management stuff, and the database -- if so,
there is no single document.

Question 3)

there is no oerr but you can get part of the error text like this:

tkyte@TKYTE816> set serveroutput on
tkyte@TKYTE816> exec dbms_output.put_line( sqlerrm(-1) );
ORA-00001: unique constraint (.) violated

that shows the error message for ORA-00001, unique constraint violated.

Review &
      Followup

      Rating: 5
Simply the Best
      !!!  April 15, 2001
Reviewer:  Harsh
       from US
The answers are really useful and helpful for me.

Thanks,
- Harsh

April 14, 2001 -- Thanks for the question regarding "Porting
      Forms/Reports Applications from NT to SUN Solaris 2.8", version ias1.0.1

      You Asked
Hi,

We have developed Forms and Reports applications on NT 4.0 and successfully
deployed them over web using ias 1.0.2 on NT 4.0. Now our requirements have
changed and we would like to port these applications on to web on Solaris 2.8
platform.
We have never done this before, can you guide us with the optimal way of doing
this. Is a .fmb file portable between platforms or not?

Thanks.
Irshad.

      and we said...
I asked around and this is what I've found:

...
Yes, the fmb is portable across platforms.  The fmx is not  They would have
to recompile the fmb into an fmx.  Also, any pll that may optionally have
been compiled to plx must be recompiled.  And for reports, any rep file must
be recompiled from the rdf.   Note that reports can run from either the
uncompiled rdf or from the compiled version rep.

I would recommend just moving, compiling and testing.  If things don't work
as expected, then I recommend reviewing the following reference manual for
some answers.

Chapter 5 - Designing Portable Applications in the Oracle Forms and Reports
Developer, Guidelines to Building Applications.

http://technet.oracle.com/doc.pdf/forms/A73073_01.pdf
.....

Review &
      Followup

      Rating:
      2
  April 23, 2001
Reviewer:  Phanikumar
      Bhogaraju  from Chicago, IL USA

      Rating: 2
My experiences
      porting Forms and Reports to Solaris/Web  April 23, 2001

Reviewer:  Phanikumar Bhogaraju  from Chicago, IL USA

We had lot of problem porting our Forms from NT to Solaris. There are some very
good articles at OTN, especially on how to map Fonts etc. We have an Oracle
Report which sends the output directly to a Fax server and our DBA had a hard
time configuring this on Unix. He made lot of calls to Oracle Tech Support. Of
course, they were helpful. But it took lot of time, effort and patience to
achieve what we wanted.
Another important point to note is that on the web, the display is completely
different from what we see using Forms Runtime (on Solaris).

April 14, 2001 Ahmer -- Thanks for the question regarding "Data
      types of Functions", version Oracle lite

      You Asked
I appreciate ur effort for answering each and every single question. It is
really a great service.

I have studied in the oracle student book of PL/SQL program units student guide
that the while writing the functions the return data type should be only basic
data type like number,date and character.
The other special data types can not be used like Boolean. And in the same book
return type of many functions is Boolean. Why this contradiction. Please
explain. I will be very thankful to u.

Ahmer

      and we said...
PLSQL functions can return ANY type -- any type at all.

Only SQL types can be returned if you intend to call the function from SQL
however, perhaps that is the distinction they made.  For example:

tkyte@TKYTE816> create function foo return boolean
  2  as
  3  begin
  4    return true;
  5  end;
  6  /

Function created.

tkyte@TKYTE816> begin
  2    if ( foo ) then
  3       dbms_output.put_line( 'Yes' );
  4    end if;
  5  end;
  6  /
Yes

PL/SQL procedure successfully completed.

that shows you can, now:

tkyte@TKYTE816> select foo from dual;
select foo from dual
       *
ERROR at line 1:
ORA-06552: PL/SQL: Statement ignored
ORA-06553: PLS-382: expression is of wrong type

that won't work.  I can call foo from sql if I recode it:

tkyte@TKYTE816> create or replace function foo return number
  2  as
  3  begin
  4     return 1;
  5  end;
  6  /

Function created.

tkyte@TKYTE816> select foo from dual;

       FOO
----------
         1

Now, you are NOT limited to simple datatypes in returns from plsql functions
called from sql.  You can return ANY sql type which includes OBJECT types and
collections.  I can return arrays (collection) types, and complex object types
as well.  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:496671211259
for an example involving an object type.

April 15, 2001 Murali -- Thanks for the question regarding
      "PL/SQL Procedure", version 8.0

      You Asked
.  I have to take a 10 digit number and have it stored in a SQL*Plus variable,
pass it into a PL/SQL stored procedure, format that number so that it looks like
a phone number with area code and then put it back into that SQL*Plus variable.
For example, the number you might have stored in the SQL*Plus variable may be
2129981212. You will then pass that number the procedure which will make it look
like this: (212)998-1212 and then pass it back to the SQL*Plus variable. Once
you have done this,  I have to print the value in the SQL*Plus variable out in
SQL*Plus. Could you  Show me the steps you do to accomplish this.

Thanks for your time,

Murali

      and we said...
scott@ORA8I.WORLD> create or replace procedure format_num( n in out varchar2 )
  2  as
  3  begin
  4          n := '('||substr(n,1,3)||')-'||substr(n,4,3)||'-'||substr(n,7);
  5  end;
  6  /

Procedure created.

scott@ORA8I.WORLD>
scott@ORA8I.WORLD> variable n varchar2(20)
scott@ORA8I.WORLD> exec :n := 1234567890

PL/SQL procedure successfully completed.

scott@ORA8I.WORLD>
scott@ORA8I.WORLD> exec format_num(:n)

PL/SQL procedure successfully completed.

scott@ORA8I.WORLD>
scott@ORA8I.WORLD> print :n

N
--------------------------------
(123)-456-7890

scott@ORA8I.WORLD>
Review & Followup

      Rating:
      4
Good  April 16, 2001
Reviewer:
      Murali  from NY-USA
I will be testing the Procedure shortly as my database is not functioning
properly.
Thanks for your response.

April 15, 2001 Prasanna -- Thanks for the question regarding
      "Query for finding out the %age output", version SQL*Plus Release
3.3.4.0.0

      You Asked
Assume a table having two columns ,say dept_code and salary.I want to know if it
is possible to retrieve in a single SQL*Plus query the
following three things
   1                2                       3
Dept_code  Sum(sal)-(dept wise)   %age salary(sum(sal)/total sal)

I was able to retrieve dept wise sum of salary but not the percentage

      and we said...
  1  select deptno, sum(sal), round( sum(sal)/tot_sal*100, 2 ) || ' %'
  2    from emp, ( select sum(sal) tot_sal from emp )
  3*  group by deptno, tot_sal
scott@ORA8I.WORLD> /

    DEPTNO   SUM(SAL) ROUND(SUM(SAL)/TOT_SAL*100,2)||'%'
---------- ---------- ------------------------------------------
        10       8750 30.15 %
        20      10875 37.47 %
        30       9400 32.39 %

Review &
      Followup

      Rating: 5
It Was
      Great  April 16, 2001
Reviewer:  Ganesh
       from Chennai, India

April 15, 2001 Igor -- Thanks for the question regarding "Whats
      different during a HOT backup", version 8.0.5

      You Asked
Could you please explain what changes are made in internal ORACLE behavior when
issuing command ALTER TABLESPACE '?' BEGIN BACKUP ?
Thanks in advance.

Igor.

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:271815712711
...
Review
      & Followup

      Rating:
      4
  April 15, 2001
Reviewer:  Igor

April 15, 2001 Harshan -- Thanks for the question regarding
      "Procedural dependencies.", version 7.3

      You Asked
Hi Tom,
I have no working experience with Oracle, however I have been going thru books
while preparing for my certification exam.

One thing which has me confused is procedural dependency. If procedure A calls
procedure B (both procedures are in the same database) and for some reason
procedure B was changed and then compiled successfully. What will happen the
next time procedure A is executed.
1.  procedure A will not execute as it is INVALID.

2.  Procedure A will compile automatically and then execute successfully.
My confusion is due to the fact that since A is dependent on B, then
date/timestamp of compilation A should be greater than B. Hence if B is
recompiled then do we recompile A manually or does it get compiled automatically
the next time it is executed.

I would highly appreciate your answer on this.

Thanks
Harshan

      and we said...
2) is what happens.  the procedure gets compiled automagically the next time you
execute it.  It all happens for you.

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:286816015990
for further discussion.

Review &
      Followup

      Rating:
      5
  April 16, 2001
Reviewer:  Harshan
      K.M  from Cincinnati, OH, USA
Very informative and Thanks for clearing the clouds of confusion.

April 15, 2001 pauline -- Thanks for the question regarding
      "PL/SQL book", version 8.1.5

      You Asked
Tom,
Could you recommend some good PL/SQL book which includes Oracle new stuff in
PL/SQL?
Thanks.

Pauline

      and we said...
Not really -- I've been so busy writing mine (due out in June) that I really
haven't read anyone elses.

I've always found the Oracle documentation to be pretty well written myself
actually.  Have you given the

o PLSQL programmers guide

http://technet.oracle.com/doc/oracle8i_816/appdev.816/a77069/toc.htm
o Supplied Packages guide

http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/toc.htm
o Application developer guide

http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76939/toc.htm
read throughs?  I don't think you'll find a better reference anywhere.  Of
couse, the

o Server Concepts manual

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/toc.htm
should be mandatory reading for all.
Review &
      Followup

      Rating:
      4
  April 16, 2001
Reviewer:  Pauline
       from U.S.A.


Subject | Article | Last Updated (East coast time)
Attachment with the e-mail using utl_smtp | article only | Apr 16, 2001 08:52 am
SQL Loader | article only | Apr 16, 2001 08:59 am
different kind of recoveries | article only | Apr 16, 2001 10:15 am
SQL Query | article only | Apr 16, 2001 10:52 am
Dynamic SQL | article only | Apr 16, 2001 04:47 pm
exiting from .sql file to next file in script | article only | Apr 16, 2001 04:48 pm
Oracle SID | article only | Apr 16, 2001 04:52 pm
Installation of Oracle 8 and Higher version on Sun Solaris ! | article only | Apr 17, 2001 07:28 am
M-commerce | article only | Apr 17, 2001 08:25 am
Concatenation of CLOB field | article only | Apr 17, 2001 08:39 am
Resouce Cost | article only | Apr 17, 2001 12:57 pm
Can i assign htp.formsubmit() function in PL/SQL cartridge progamming to a gif. | article only | Apr 20, 2001 08:35 am
set TRansaction Isolation Level Serializanble/ read commit | article only | Apr 20, 2001 08:38 am
Sending Email through Oracle | article only | Apr 20, 2001 08:53 am
dbms_lock.request() with release_on_commit = TRUE | article only | Apr 20, 2001 02:16 pm
Associate Statistics | article only | Apr 20, 2001 02:25 pm
recover | article only | Apr 20, 2001 02:28 pm
Adding more cols | article only | Apr 20, 2001 02:37 pm
Multiple Blocks In A Form | article only | Apr 20, 2001 05:05 pm
remote admin... | article only | Apr 20, 2001 05:25 pm
Problem with Moving PL/SQL rercords from PL/SQL table to a cursor | article only | Apr 20, 2001 09:49 pm
OPEN_FORM built-in | article only | Apr 20, 2001 10:35 pm
Cursor | article only | Apr 21, 2001 12:14 am
Problem with application context....... | article only | Apr 21, 2001 12:37 am
About Dynamic PL/SQL when transferring Db from SQL Server to Oracle 8i | article only | Apr 21, 2001 12:40 am
Detailed information about a user request | article only | Apr 21, 2001 12:18 pm
Strange Behaviour of Index Creation. | article only | Apr 21, 2001 12:40 pm
Backuping temporary tablespace | article only | Apr 21, 2001 07:01 pm
Determining if an index has ever been used. | article only | Apr 21, 2001 07:22 pm
Random Page Breaks | article only | Apr 22, 2001 10:06 am
DBMS_PIPE ,LOGON TRIGGER & DBMS_AQ | article only | Apr 22, 2001 10:41 am
row(s) 1 - 31 of 31
April 16, 2001 Rajashekar H.S -- Thanks for the question regarding "Attachment with the e-mail using utl_smtp", version 8.1.7
You Asked
Hi,

I am using utl_smtp for sending mail in my function now i want to attach the
text file with every mail along with the message.

I have following problem i am able to get only message(i.e.body of email) /
attachment but not both.

i have forwarded the code please suggest me how do i do that using the utl_smtp.

Regards
Raj
The code is as follows,

    FUNCTION deliver (
        in_from IN VARCHAR2 DEFAULT NULL,
        in_to IN VARCHAR2 DEFAULT NULL,
        in_subject IN VARCHAR2 DEFAULT NULL,
        in_content IN VARCHAR2 DEFAULT NULL
        ) RETURN VARCHAR2
    IS
        mailhost    VARCHAR2(30) := 'cob353.dn.net';
        -- mailhost    VARCHAR2(30) := 'mail.finhost.fi';
        mail_conn   utl_smtp.connection;
        response    utl_smtp.reply;
        status      VARCHAR2(2000):='MAIL ID FORMAT ERROR';

        mesg        varchar2(4000);
        attach1        varchar2(4000);
        crlf         VARCHAR2( 2 ):= CHR( 13 ) || CHR( 10 );
    BEGIN

    IF instr(in_to,'@',1,1) > 0 AND instr(in_from,'@',1,1) > 0 THEN
        status := 'OK';
        mail_conn := utl_smtp.open_connection(mailhost, 25);

        response:=utl_smtp.helo(mail_conn, mailhost);
        IF response.code<>250 AND response.code<>221  THEN
            status:='error';
        END IF;

        response:=utl_smtp.mail(mail_conn, in_from);
        IF response.code<>250 AND response.code<>221  THEN
            status:='error';
        END IF;

           response:=utl_smtp.rcpt(mail_conn,in_to);
        IF response.code<>250 AND response.code<>221 AND response.code<>421 THEN
            status:='error';
        END IF;

        if v_filename is null then
        response:=utl_smtp.data(mail_conn, 'Subject:
'||in_subject||chr(10)||in_content);
        IF response.code<>250 AND response.code<>221  THEN
            status:='error';
        END IF;
        else

        --filehandle:=UTL_FILE.FOPEN(v_path,v_filename,'r');
        attach1:='Client Name|Address|Product|Campaign Name|Publication
Date|Insertion Order No|Media Name|Size/Color of Ad|List Price|Discount|Net
Price|Fee';
        mesg:= 'Subject: '|| in_subject || ': Completed ' ||in_content|| crlf ||
        'Your query has been completed. The output can be viewed below.
'||crlf||''||crlf||
        'MIME-Version: 1.0'||crlf||
        'Content-Type: text/plain'||crlf||
        'Content-Transfer-Encoding: 7bit'||crlf||
        'Content-Disposition: attachment; filename=output.log'||crlf||''|| crlf
||
        'Your query results have exc
        eeded the maximum output size. The first block is below. The entire
output can b
        e viewed here.'||
        attach1; -- Data to appear in attachment.

        response:=utl_smtp.data(mail_conn,mesg);
        IF response.code<>250 AND response.code<>221  THEN
            status:='error';
        END IF;
        end if;

        response:=utl_smtp.quit(mail_conn);
        IF response.code<>250 AND response.code<>221  THEN
            status:='error';
        END IF;
    END IF;

    RETURN status;

    EXCEPTION
        WHEN OTHERS THEN
            -- Handle cookie exceptions
            IF SQLCODE=-20101 OR SQLCODE=-20102 THEN

com360.err_msg.print(in_address=>'login.main_index',in_errmsg=>'User sessio
error, please login ('||SQLCODE||')');
            ELSE

com360engine.logs.error_log(in_sqlcode=>SQLCODE,in_errm=>SQLERRM);
            END IF;
    END;
and we said...
In order to use UTL_SMTP, you would have to fully understand the format of the
MIME email you must send and encode the entire thing.

I am not a MIME expert -- won't be able to help you out with this one.

I can suggest (this is the way I send attachments) the use of the Java MAIL api
instead.  Example that allows for sending attachments is at:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:255615160805
it currently supports a BLOB but it is easy enough to change to clob type.
Review & Followup
Rating: 4
UTL_SMTP June 04, 2001
Reviewer: Seetharaman from Chennai, TamilNadu India
Its really good and clarifies many a doubts within me on this package

Rating: 3
but... October 01, 2001
Reviewer: Ricardo from Santiago, Chile
Where (in wish directory) must be the file to realy be attached??

Thanks.

April 16, 2001 Sudhir -- Thanks for the question regarding "SQL Loader", version 8.0
You Asked
Respected Sir,
I am trying to upload a file(Data file) from a stored procedure. I can easily
upload a Data file from SQL Loader from Command Line(DOS prompt. Now, i am
trying to prepare the string and then pass that string to the Command prompt, so
that Data is invisible to the User. can you please tell me any command or
package name which I can execute any DOS command from SQL prompt or PL/SQL
package.
Thanking in anticipation,
Regards..sudhir
and we said...
From the SQL Prompt -- sure,

SQL> host sqlldr .......

will do it.  From PLSQL -- you would have to write an EXTPROC in C in version 8
to accomplish this (see chapter 10 of the v8 PLSQL manual for more info)

Alternatively, if the file is on the database servers file system -- you can
write a procedure using UTL_FILE to load the data

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:464420312302
for an example.
April 16, 2001 parker -- Thanks for the question regarding "different kind of recoveries", version 8.1.7
You Asked
Tom

What is the difference between  database recovery, tablespace recovery, and
datafile recovery?

Further, I know about Media failure, instance falure, or there any other kinds
of failures, which necessitate media recovery?
and we said...
database recovery -- typically means you restore the entire set of database
files, all of them, and recover.

tablespace recovery -- typically means you restore the set of files of a given
tablespace and recover it.  you can do a tablespace point in time recovery as
well, recovering a tablespace to a different point in time from the rest of the
database.

datafile recovery -- you are recovering an individual file belonging to a
tablespace in a database.

media failure is the only thing the necessitates a media recovery.  There are
other reasons you might do it however (such as recovering that dropped table).
April 16, 2001 Parag -- Thanks for the question regarding "SQL Query", version Oracle 8i
You Asked
Hi Tom:

        There is one table say EmpMst which two field . Empno & Ename.
There are some record which we have deleted.

        So , is it possible to find out Missing Record without using any
Sequences.

       Table Lik

       Empno        Eanme

        1           aaa
        2           bbb
        7           ccc
        4           ddd
        6           eee
        10          fff

      So , how to findout Missing Employee falls between Min(Empno) and
Max(Empno).

      I am waiting for ur reply.

Bye
- Parag
and we said...
Assuming your all_objects view has enough rows (typically 10-30k rows in there)
this will work:

tkyte@TKYTE816> select * from t;

     EMPNO      ENAME
---------- ----------
         1          1
         2          2
         4          4
         6          6
         7          7
        10         10

6 rows selected.

tkyte@TKYTE816>
tkyte@TKYTE816> select missing_empno
  2    from t,
  3         ( select rownum+min_empno-1 missing_empno
  4             from all_objects, (select max(empno) max_empno,
  5                                       min(empno) min_empno
  6                                  from t )
  7           where rownum <= (select max(empno)-min(empno)+1 from t)
  8         )
  9   where missing_empno = empno(+)
 10     and empno is null
 11  /

MISSING_EMPNO
-------------
            3
            5
            8
            9

you just need as many rows in that table as the difference between min and max
empno.
Review & Followup
Rating: 5
April 17, 2001
Reviewer: Xm from New Jersey, USA
It works perfectly. I use this exmple code to report all the missed sequence ID
in the table.

April 16, 2001 Ai -- Thanks for the question regarding "Dynamic SQL", version Oracle 7.3/8.0
You Asked
Hi Tom,

I have the following query:

select     resolved_by,
            sum(decode(resolved_date,to_date('2/1/2001','mm/dd/yyyy'), cases))
"2/1",
        sum(decode(resolved_date,to_date('2/2/2001','mm/dd/yyyy'), cases))
"2/2",
        sum(decode(resolved_date,to_date('2/3/2001','mm/dd/yyyy'), cases))
"2/3",
        sum(decode(resolved_date,to_date('2/4/2001','mm/dd/yyyy'), cases))
"2/4",
        sum(decode(resolved_date,to_date('2/5/2001','mm/dd/yyyy'), cases))
"2/5",
        sum(decode(resolved_date,to_date('2/6/2001','mm/dd/yyyy'), cases))
"2/6",
        sum(decode(resolved_date,to_date('2/7/2001','mm/dd/yyyy'), cases))
"2/7",
        sum(decode(resolved_date,to_date('2/8/2001','mm/dd/yyyy'), cases))
"2/8",
        sum(decode(resolved_date,to_date('2/9/2001','mm/dd/yyyy'), cases))
"2/9",
        sum(decode(resolved_date,to_date('2/10/2001','mm/dd/yyyy'), cases))
"2/10",
        sum(decode(resolved_date,to_date('2/11/2001','mm/dd/yyyy'), cases))
"2/11",
        sum(decode(resolved_date,to_date('2/12/2001','mm/dd/yyyy'), cases))
"2/12",
        sum(decode(resolved_date,to_date('2/13/2001','mm/dd/yyyy'), cases))
"2/13",
        sum(decode(resolved_date,to_date('2/14/2001','mm/dd/yyyy'), cases))
"2/14",
        sum(decode(resolved_date,to_date('2/15/2001','mm/dd/yyyy'), cases))
"2/15",
        sum(decode(resolved_date,to_date('2/16/2001','mm/dd/yyyy'), cases))
"2/16",
        sum(decode(resolved_date,to_date('2/17/2001','mm/dd/yyyy'), cases))
"2/17",
        sum(decode(resolved_date,to_date('2/18/2001','mm/dd/yyyy'), cases))
"2/18",
        sum(decode(resolved_date,to_date('2/19/2001','mm/dd/yyyy'), cases))
"2/19",
        sum(decode(resolved_date,to_date('2/20/2001','mm/dd/yyyy'), cases))
"2/20",
        sum(decode(resolved_date,to_date('2/21/2001','mm/dd/yyyy'), cases))
"2/21",
        sum(decode(resolved_date,to_date('2/22/2001','mm/dd/yyyy'), cases))
"2/22",
        sum(decode(resolved_date,to_date('2/23/2001','mm/dd/yyyy'), cases))
"2/23",
        sum(decode(resolved_date,to_date('2/24/2001','mm/dd/yyyy'), cases))
"2/24",
        sum(decode(resolved_date,to_date('2/25/2001','mm/dd/yyyy'), cases))
"2/25",
        sum(decode(resolved_date,to_date('2/26/2001','mm/dd/yyyy'), cases))
"2/26",
        sum(decode(resolved_date,to_date('2/27/2001','mm/dd/yyyy'), cases))
"2/27",
        sum(decode(resolved_date,to_date('2/28/2001','mm/dd/yyyy'), cases))
"2/28",
        sum(cases) total,
        round(avg(cases),2) ticket_avg
from
        (
        select    resolved_by,
                resolved_date,
                count(*) cases
        from    itcs_helpdesk_ticket
        where    period_key  = '02012001'
        group by resolved_by,
                   resolved_date
        )
group by resolved_by

The result looks like this:
resolved_by  2/1  2/2 2/3  2/4... 2/28  total ticket_avg
asanchez     4    6   8     10    15     125   5.0
...

I would like to convert this query into dynamic SQL to have the number of decode
statements change dependent on the number of days there are in a particular
month.  I don't want to hardcode the decode statement for number of days in each
month.

Is it possible to do that?

Thanks for you help.

Ai
and we said...
Well, yes we can -- however -- I would probably just do this:

select resolved_by,
       sum(decode(to_char(resolved_date,'dd'), 1, cases)) "1",
       sum(decode(to_char(resolved_date,'dd'), 2, cases)) "2",
       ....
       sum(decode(to_char(resolved_date,'dd'), 31, cases)) "31",
       sum(cases) total,
       round(avg(cases),2) ticket_avg
  from ( select resolved_by, resolved_date, count(*) cases
           from itcs_helpdesk_ticket
          where period_key  = :bind_variable
          group by resolved_by, resolved_date
        )
group by resolved_by
/

and have the client that fetches ignore any trailing NULL columns...  But to do
this dynamically (i'll use the best language for the job -- plsql) we would do
this:

ops$tkyte@ORA8I.WORLD> create or replace package my_pkg
  2  as
  3      type rc is ref cursor;
  4
  5      procedure do_query( p_period_key in varchar2, p_cursor in out rc );
  6  end;
  7  /

Package created.

ops$tkyte@ORA8I.WORLD> create or replace package body my_pkg
  2  as
  3
  4  procedure do_query( p_period_key in varchar2, p_cursor in out rc )
  5  is
  6      l_query long;
  7      l_days_in_month number default
  8            last_day( to_date(p_period_key,
                      'mmddyyyy') ) - to_date(p_period_key,'mmddyyyy')+1;
  9      l_month         varchar2(3) default substr( p_period_key, 1, 2 )||'/';
 10  begin
 11
 12      l_query := 'select resolved_by';
 13
 14      for i in 1 .. l_days_in_month
 15      loop
 16          l_query := l_query ||
                        ', sum(decode(to_char(resolved_date,''dd''),' ||
 17                                    i || ', cases)) "'||l_month||i||'"';
 18      end loop;
 19
 20      l_query := l_query ||
                     ', sum(cases) total, round(avg(cases),2) ticket_avg
 21                    from ( select resolved_by, resolved_date, count(*) cases
 22                             from itcs_helpdesk_ticket
 23                            where period_key  = :bv
 24                            group by resolved_by, resolved_date
 25                         )
 26                   group by resolved_by';
 27
 28
 29      open p_cursor for l_query using p_period_key;
 30  end;
 31
 32  end;
 33  /

Package body created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> drop table itcs_helpdesk_ticket;

Table dropped.

ops$tkyte@ORA8I.WORLD> create table itcs_helpdesk_ticket
  2  ( resolved_by      varchar2(30),
  3    resolved_date date,
  4    period_key       varchar2(8)
  5  )
  6  /

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into itcs_helpdesk_ticket
  2  select 'user_' || mod(rownum,10),
  3         trunc(to_date('01012001','mmddyyyy'),'mm')+mod(rownum,100),
  4           to_char( trunc(to_date('01012001','mmddyyyy')+
                                     mod(rownum,100),'mm'), 'mmddyyyy')
  5    from all_objects
  6   where rownum <= 1000
  7  /

1000 rows created.

ops$tkyte@ORA8I.WORLD> variable x refcursor
ops$tkyte@ORA8I.WORLD> exec my_pkg.do_query( '01012001', :x )

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> print x

RESOLVED_BY                          01/1       01/2       01/3       01/4
01/5       01/6
------------------------------ ---------- ---------- ---------- ----------
---------- ----------
      01/7       01/8       01/9      01/10      01/11      01/12      01/13
 01/14      01/15
---------- ---------- ---------- ---------- ---------- ---------- ----------
---------- ----------
     01/16      01/17      01/18      01/19      01/20      01/21      01/22
 01/23      01/24
---------- ---------- ---------- ---------- ---------- ---------- ----------
---------- ----------
     01/25      01/26      01/27      01/28      01/29      01/30      01/31
 TOTAL TICKET_AVG
---------- ---------- ---------- ---------- ---------- ---------- ----------
---------- ----------
...

10 rows selected.

ops$tkyte@ORA8I.WORLD> exec my_pkg.do_query( '02012001', :x )

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> print x

RESOLVED_BY                          02/1       02/2       02/3       02/4
02/5       02/6
------------------------------ ---------- ---------- ---------- ----------
---------- ----------
      02/7       02/8       02/9      02/10      02/11      02/12      02/13
 02/14      02/15
---------- ---------- ---------- ---------- ---------- ---------- ----------
---------- ----------
     02/16      02/17      02/18      02/19      02/20      02/21      02/22
 02/23      02/24
---------- ---------- ---------- ---------- ---------- ---------- ----------
---------- ----------
     02/25      02/26      02/27      02/28      TOTAL TICKET_AVG
---------- ---------- ---------- ---------- ---------- ----------
....
10 rows selected.

ops$tkyte@ORA8I.WORLD> exec my_pkg.do_query( '03012001', :x )

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> print x

RESOLVED_BY                          03/1       03/2       03/3       03/4
03/5       03/6
------------------------------ ---------- ---------- ---------- ----------
---------- ----------
      03/7       03/8       03/9      03/10      03/11      03/12      03/13
 03/14      03/15
---------- ---------- ---------- ---------- ---------- ---------- ----------
---------- ----------
     03/16      03/17      03/18      03/19      03/20      03/21      03/22
 03/23      03/24
---------- ---------- ---------- ---------- ---------- ---------- ----------
---------- ----------
     03/25      03/26      03/27      03/28      03/29      03/30      03/31
 TOTAL TICKET_AVG
---------- ---------- ---------- ---------- ---------- ---------- ----------
---------- ----------

....

10 rows selected.

ops$tkyte@ORA8I.WORLD>
Review & Followup
Rating: 4
Dynamic SQL or not April 17, 2001
Reviewer: Ai Tran from Houston, TX
Your suggestion to modify the query works perfectly.  I decided to use that
instead of using the dynamic SQL example, although I think it works just as
well.

Thank you.

April 16, 2001 Stanley -- Thanks for the question regarding "exiting from .sql file to next file in script", version 8.1.6
You Asked
hi tom,
i have a master .sql file which calls other files.

master.sql
----------
spool master
@table1copy.sql;
@table2copy.sql
@creindx.sql;
...
...
spool off
exit;

Each slave .sql file is like:

table1copy.sql
---------------

spool table1copy
-- 1. create dummy table with new structure
-- 2. copy data from old table into dummy table using "copy" command
-- 3. drop old table
-- 4. rename dummy table to old table name
-- 5. create indexes on renamed dummy table

My problem is suppose i have an error in one of the slave files
while copying i should be able to skip step 3 so that my old table
is safe with the data, and then continue to the next slave file.

I tried to use "whenever sqlerror exit" but that will exit out of
the whole sqlplus session.

I want to exit out of the *slave* file alone and continue with the next *slave*
file ie table2copy.sql

Could you pls suggest me if i have an option to do this?

thnx
stan
and we said...
what we do in this case (i actually do this) is

o Use the sqlplus copy command to create the dummy table.  Set copycommit OFF
(inserts generate a trivial amount of rollback, there is no issue with regards
to generating too much rollback during an insert -- you do not need to commit
every n records).  so this is steps 1 and 2 in 1 step

o do 3, 4, and 5 as a plsql block like this:

declare
  l_cnt number;
begin
  -- if the select fails because of no such table, the copy failed
  -- if the select returns 0 rows, the create part of copy worked
  -- but it failed in the middle
  select count(*) into l_cnt from NEW_TABLE where rownum = 1;

  if ( l_cnt = 1 )
  then
     execute immediate 'create index ....';
     execute immediate 'drop old_table';
     execute immediate 'rename new to old';
  end if;
end;
/
Review & Followup
Rating: 3
exiting from .sql file to next file in script April 17, 2001
Reviewer: Stanley from MD US
good, gave me a different approach to handle my prob.
i envy tom kyte's job, it a really cool one.

April 16, 2001 Wayne -- Thanks for the question regarding "Oracle SID", version 8i
You Asked
Tom,

  While helping someone set up an oracle server, I noticed that the "SID" was
ORCL.  Since this name was different from the naming convention for the rest of
the machine (instance_name, db_name, etc), I began to ask myself, "mmm ... If I
didn't know the name for the SID, which v$ would I use to find the name of the
actual SID (or, service name) on the server?

Thanks

Wayne
and we said...
select instance from v$thread;
Review & Followup
Rating: 3
April 17, 2001
Reviewer: A reader from Indianapolis, IN
Hi tom,
  How do i find out of name of database i am connected to if am not given
privilege to access oracle views or select any table?

I guess my question is being a programmer with connect,resource role , how do
find out which database i am connected to, My dba has created  service name
which i use as host string to connect to database, which i am sure is not the
name of database.

Reg,
Ramesh

Rating: 3
April 17, 2001
Reviewer: A reader from Indianapolis, IN
Hi tom,
  How do i find out of name of database i am connected to if am not given
privilege to access oracle views or select any table?

I guess my question is being a programmer with connect,resource role , how do
find out which database i am connected to, My dba has created  service name
which i use as host string to connect to database, which i am sure is not the
name of database.

Reg,
Ramesh

April 17, 2001 OP -- Thanks for the question regarding "Installation of Oracle 8 and Higher version on Sun Solaris !", version 8.1.6
You Asked
Dear Tom,

I have to Install Oracle 8i on Sun Solaris platform.

I know Unix (Sco Open Server) but I will be working
on Solaris for the very first time.

I understand the Basic concepts like Mount and have
some concept of administration also on Unix and
Linux.

If you can send me the steps for the Installation of
Oracle on Sun Solaris ,that surely will be of immense
help for me.

Thanks and Regards
OP Lalwani
and we said...
See
http://technet.oracle.com/docs/products/oracle8i/doc_index.htm
the install guides are there.

If you've installed on SCO and Linux, it is the same on Solaris.  Insert CD, run
the runInstaller and answer the questions.  No difference really.  See the admin
guide for the necessary OS setup you must make (the /etc/system changes you need)
Review & Followup
Rating: 3
Oracle 8i installation on 8i April 19, 2001
Reviewer: Ghulam Moinuddin from Pakistan
I have successfully install the Oracle 8i on Solaris Intel 2.7 but the same CD
is not working on Intel 2.8. Is there any possibility to do so.

April 17, 2001 Derek -- Thanks for the question regarding "M-commerce", version 8i
You Asked
What is Oracle's M-commerce Solution ????
and we said...
http://www.oracle.com/mobile/index.html?content.html
details our approach.
April 17,
      2001 Sasa -- Thanks for the question
      regarding "Concatenation of CLOB field", version 8.1.5

      You Asked
Hi Tom,

I have a table with CLOB field and try to do next:

select 'Try to concatanate with CLOB field'||Clob_Field  from XX;

Is it possible to make a such concatenation?

Regards

Sasa

      and we said...
You cannot concatenate lobs like that, no.

you could, if the lob is small enough, concatenate the dbms_lob.substr()'s of
the lob with the string but you cannot concatenate to the lob itself.

If the clob_field is less then about 4000 bytes, the following will work:

select 'try to concatenate with clob field' ||
dbms_lob.substr(clob_field,3900,1) from xx;
Review &
      Followup

      Rating:
      4
  April 18, 2001
Reviewer:  Sasa
      Petkovic  from Belgrade,Yugoslavia

      Rating:
      5
  April 18, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

      Rating:
      5
  April 18, 2001
Reviewer:
      A reader

April 17, 2001 Randy -- Thanks for the question regarding
      "Resouce Cost", version 8.1.6

      You Asked
I am trying to determine the resource cost of each session for a particular user
and I need some guideline to estimate it. We are running database in a single
CPU Sun 3500 machine with 1GB of ram. The user is supposed to fetch some data,
update, insert new records and will make some remote procedure call using db
link. It wont be a very CPU intensive operation but will use the cpu only as
much as needed for the above operations. At this point I cannt come up to any
appropriate value for cpu_per_session, logical_read or physical_read. Please
tell me if these information are good enough to estimate. Can you provide me any
outline how to assume an appropriate value for the above parameters like
cpu_per_session etc. ?

I am planning to calculate the resouce cost every time the user logs off from
the database may be by writing a trigger on logoff. But I am again at loss to
find out any appropriate data dictionary view which could give me some idea how
much resource the user has consumed so far in the current session.

Appreciate your help.

Randy

      and we said...
If you

select name from v$statname

you'll see all of the stats we can keep for you.  You can join v$statname with
v$mystat to get the value for any of those statistics.  v$mystat shows only the
stats for the current session.  Anything that is in there, you can use - one of
the stats is named "CPU used by this session" for example.  Others are "session
logical reads" and "physical reads".

follow to comment

Are you sure about the user rollback issue?  I cannot reproduce --

tkyte@TKYTE816> select a.name, b.value
  2  from v$statname a, v$mystat b
  3  where a.statistic# = b.statistic#
  4  and lower(a.name) like '%' || lower('&1')||'%'
  5  /
old   4: and lower(a.name) like '%' || lower('&1')||'%'
new   4: and lower(a.name) like '%' || lower('user')||'%'

NAME                                VALUE
------------------------------ ----------
user commits                            0
user rollbacks                          0
user calls                             50

tkyte@TKYTE816> rollback
  2  /

Rollback complete.

tkyte@TKYTE816> @mystat user
tkyte@TKYTE816> select a.name, b.value
  2  from v$statname a, v$mystat b
  3  where a.statistic# = b.statistic#
  4  and lower(a.name) like '%' || lower('&1')||'%'
  5  /
old   4: and lower(a.name) like '%' || lower('&1')||'%'
new   4: and lower(a.name) like '%' || lower('user')||'%'

NAME                                VALUE
------------------------------ ----------
user commits                            0
user rollbacks                          1
user calls                             61

(actually, you seem to have the numbers backwards:

tkyte@TKYTE816> select name, statistic# from v$statname where name like 'user%';

NAME                           STATISTIC#
------------------------------ ----------
user commits                            4
user rollbacks                          5
user calls                              6
)

As for #2, you need to as sys:

GRANT SELECT on V_$MYSTAT to YOUR_ACCOUNT;

(v$mystat is a synonym to the view v_$mystat owned by sys)

See

http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for why this is so.

Review &
      Followup

      Rating: 3
Resource
      Cost  April 18, 2001
Reviewer:  Randy
       from Chicago
Seems helpful to me, but facing couple of problems.
1. The value of "user rollback" using "select value from v$mystat where
statistic#=4" always returns 0 whereas statistic#=5 which is "user commit"
returns valid value. Why ? Is it reliable to use v$mystat ?

2. BIG PROBLEM. I cannt use any select statement using v$mystat in before logoff
trigger. I always get the error "PLS-00201: entifier 'SYS.V_$MYSTAT' must be
declared".  Why ? What could be other way to gather the statistics ?

April 20, 2001 Sushil -- Thanks for the question regarding "Can
      i assign htp.formsubmit() function in PL/SQL cartridge progamming to a
      gif.", version Oracle 8.0.5 / oas302

      You Asked
Dear Tom,

I am a programmer in PL/SQL cartridge and using oas302.
I would like to know if i can use a gif in my procedure which when
clicked executes formsubmit function.

IF not then any other means by which i want a specific action to be
performed on click over a gif.

thanks & regds,
Sushil.

      and we said...
Yes, you can use a GIF.  Your procedure would take an IN parameter of
owa_image.point.  when the user clicks on the image -- you will get the X and Y
co-ords they clicked on in this variable.

create or replace
procedure p( p_button1 in owa_image.point default owa_image.NULL_POINT,
             p_button2 in owa_image.point default owa_image.NULL_POINT )
is
begin
    ....

April 20, 2001 Umesh -- Thanks for the question regarding "set
      TRansaction Isolation Level Serializanble/ read commit", version 8.1.6.0

      You Asked
Hi Tom
How are you?

Some questions

Which are the tables or v$views to be queried  for the following....

1. How do I know that asynchronous i/o is supported?

2.How do I know that my stand by database is running on my system?

3.How can I arrive at a correct block size?

4.How can I arrive at a correct extent size?

5.How can I arrive at a correct Tablespace size?

6.While creation of the tablespace USER_DATA I forget to specify next extent
  and my db_block_size =2k ..What is the next extent Oracle allocates in this
  Tablespace?

7. How Dynamic allocation of extents degrade Performanc?
     Vice versa
   How manual allocation of extents will overcome that?

8. Steps to change the data block size

9. What is "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE" and
"SET TRANSACTION ISOLATION LEVEL READ COMMIT"

   Please give a example..

 I am unable to test these things out as I dont know the steps

Thanks in advance

Best Regards

Umesh S. Kasturi

      and we said...
1)

ops$tkyte@ORA8I.WORLD> show parameter async

NAME                                 TYPE    VALUE
------------------------------------ ------- ------------------------------
disk_asynch_io                       boolean TRUE
tape_asynch_io                       boolean TRUE

(v$paramter)

2) depends on OS.  On solaris I might:

$ ps -aef | grep ora_pmon_$ORACLE_SID

3) see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:329017235004
for pointers

4) use LOCALLY MANAGED TABLESPACES with uniform extent sizes (so the
init/next/pctincrease on a CREATE TABLE is totally ignored).  Create tablespaces
to hold data that grows at various rates and is of various sizes.  for example
if I had a table that was 100meg in size and grew at 5meg/year -- I might use a
tablespace with 1meg extents.  I would have tablespaces with 1, 5, 10, whatever
sized extents I needed to support the size and growth rate of the object.  You
don't want an object with thousands of extents -- but hundreds of extents is in
general great (there are no performance gains to be had by having 1 extent for
an object)

5) depends on what you put into it, doesn't it.  that will drive that one.

6) depends on the TYPE of tablespace.  Query dba_tablespaces

7) use LOCALLY MANAGED tablespaces and never worry about these things again.

8) recreate database -- there currently in 8i and below is no way to do that.

9) to fully understand these PLEASE read the server concepts manual from start
to finish.

to see them at work

a) log in as scott/tiger
   set transaction to serializable;
   select * from emp;

NOW - in ANOTHER session -- leaving the above session open

   delete from emp;
   commit;

Now back to the first session -- do this:

   select * from emp;
   commit;
   select * from emp;

-- now, restore emp (run demodrop and demoblk from $ORACLE_HOME/sqlplus/demo)
and do it again with read committed.  You'll see the big difference.

Review &
      Followup

      Rating: 5
transaction
      isolation level  April 20, 2001
Reviewer:  ted
      chyn(tedchyn@yahoo.com)  from usa
thomas, can you elaborate more on your answer to question 9 ?

      Rating: 3
multiple
      questions  April 26, 2001
Reviewer:
      A reader
helpfull

April 20, 2001 Parag -- Thanks for the question regarding
      "Sending Email through Oracle", version 8.1.6

      You Asked
Hi Tom :

   How are u ? Tom ... we are storing all Customer Id's , Customer Name , Email
Address , Mobile Number into Customer_Master.

   We wanat to send all Email to bulk Customers , daily at Evening
6.00(Evening).

   We wanted to achive this output through Oralce only.

   I know that Scheduling .. we can done through DBMS_JOB Package & E-mail we
can send through DBMS_SMTP  OR UTL_TCP Package.

1]   Can u please tell me that , For DBMS_JOB .. is we have to change any
Parameter of initorcl.ora File.

2]   Can u please send the Procedure Code with use of DBMS_JOB Package .. which
will get invoked daily at 6.00 (eve)

3]   Also can u please send the Oralce Procedure Code .. which will send Email.
Becasue we don't wanna to use Java Mail API.

4]   Last question that .. who do we create Index on CLOB ?

Tom :  Thanks a lot in advance.

I know that u are hepling many people.

Please send me the Code ASAP.

Thanks
- Parag

      and we said...
1) job_queue_processes and job_queue_interval.  See the supplied packages guide,
it as all of the details on dbms_job setup.

2) declare
     l_job number;
   begin
      dbms_job.submit( l_job, 'procedure;',
                        trunc(sysdate)+18/24, 'trunc(sysdate)+18/24' );
   end;

will run procedure every day at 6pm (18 hours into the day)

3) well, you need to use UTL_SMTP and UTL_SMTP is built on top of UTL_TCP and
UTL_TCP is written in -- Java, so long as you understand that you need java
anyway.

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1242800235280
it points to an example

4) You can create interMedia TEXT indexes on a clob.  You cannot create b*tree
or bitmap indexes on them.  See

http://technet.oracle.com/doc/oracle8i_816/inter.816/index.htm

followup to comment one below

for those that cannot be bothered to read the documentation -- here is the link
right to the example

http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/utl_smt6.htm
although I typically find it advisable to read the documentation before jumping
right to the example -- that is what I pointed to, the utl_smtp documentation.
the documentation for the utl_smtp package contains (surprise) an example!

Review &
      Followup

      Rating: 1
This link does
      not point to an example.  May 11, 2001
Reviewer:
      Gururaj  from GA USA
This link will point to another answer and that answer will
point to a page. That page does contain an example.

Obviously this is not helpful. Try to provide an example.

Gururaj

      Rating:
      5
cvbcxb  May 25, 2001
Reviewer:
      cvxbcxvb  from cvbcxvbvcx
bvcbcxvb

April 20, 2001 José -- Thanks for the question regarding
      "dbms_lock.request() with release_on_commit = TRUE", version 8.1.6

      You Asked
Hi Tom

I use Store Procedure dbms_lock.request() with parameter release_on_commit =
TRUE to release the lock when a commit or rollback occurs.

Example of my PL/SQL:

...
savepoint foo;
dbms_lock.request(.., TRUE); -- begin my lock
...
rollback to foo; -- now my lock end, but not!!!

So, there is something that I miss?
The parameter release_on_commit = TRUE only release when the transaction ends
with rollback and not with part off (rollback to)? If so don't make sense...
My code depends on that.

Thanks Tom

      and we said...
Sorry, but in looking in the problem database, it is supposed to work this way
(as above).  Only a COMMIT or ROLLBACK will release DBMS_LOCK locks.

You can manually release a lock using RELEASE -- perhaps you can use that in
conjunction with rollback to foo; to release the lock manually;

April 20, 2001 -- Thanks for the question regarding "Associate
      Statistics ", version 8.1.7

      You Asked
Can you explain what 'associate statistics and disassociate statistics' does ?
Can you give an example/situation how it can be used ?

Thanks.

      and we said...
it allows you to put statistics on a table/index manually.  You might do this in
a test system to see what the effects of having 1,000,000 rows in a table versus
1,000 would have on the generated query plans.  It lets you test the behavior of
the optimizer under various different data conditions.
April 20, 2001 --
      Thanks for the question regarding "recover", version 8.1.6

      You Asked
tom:

time t:
whole backup + controlfile backup ct1

time t+1
add a datafile

time t+2
drop a tablespace

time t+3
add a tablespace

time 4
crash

can i use controlfile backup ct1 to recover to time t+3?
somebody tell me that i can, somebody tell me i can't

      and we said...
Sure you can

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/recoscen.htm#14480
describes what happens.
April 20,
      2001 C -- Thanks for the question
      regarding "Adding more cols", version 8i

      You Asked
Hi Tom,

I have just been asked to add 2 more columns to an already existing table that
has been in use for 8 months.
What is the script to do that and are there any consequences to doing this.
Thanks.

      and we said...
alter table T add cname datatype;

the consequences are that -- you sized the table and set pctfree/pctused based
on how you used the data.  When you did this, these columns did not exist.  If
the addition of these columns -- and their subsequent UPDATES cause the rows to
get too big to fit on the block, these rows will migrate (chain).  It will take
more work to retrieve these rows.

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:358341515662
for further details.

Review &
      Followup

      Rating:
      5
  April 20, 2001
Reviewer:  C Faria
       from New York, NY, USA

April 20, 2001 Tom -- Thanks for the question regarding
      "Multiple Blocks In A Form", version 6.0i

      You Asked
I am just starting to use forms and I have run into a problem.  I want to create
a search form, with the top section in a block not tied to a datasource.  The
top will have search fields.  The bottom will be based on a block with a data
source, that retrieves the results of the search.  I have created the bottom
block, but I don't know how to create the top block and add it.  Is there any
documentation on "inserting" a second block.

Thanks,
Tom Deseamus

      and we said...
In the navigator click on the "data blocks" and then the ADD button (green plus)

Choose "build a block manually"

You'll have your block.  Since this is a control block, not a database block,
you'll want to pull up the property sheet and set:

- database data block = NO

Now you can add items to the block....

April 20, 2001 Senthil -- Thanks for the question regarding
      "remote admin...", version 8.1.5

      You Asked
Hi Thomas,

i was trying to enable remote admin, i succeeded in logging in and do
administration tasks, even shutting down the database, but it failed when i
restarte the database. here are the steps i tried,

1. assigned "exclusive" to remote_login_passwordfile parameter
2. set and assigned value to ORA_PWFILE and ORA_t1721_PWFILE environment
variables.
3. logged into oracle from other unix box
4. i was able to do administrative tasks, like creating tablespace, adding
logfiles etc...
5. i was able to shutdown the database, using shutdown command.
6. when i try to restart the database, i got these messages...
SQL> startup
LRM-00109: could not open parameter file '?/dbs/init@.ora'
ORA-01078: failure in processing system parameters
SQL>

is it not possible to startup oracle database from the remote machine...ofcourse
its different filesystem, and different location. But any workaround...

thanks...

      and we said...
Unless you have access to the parameter file on the remote machine ( a copy of
it will do ) no -- not really , not with SQLPlus.

OEM can do this -- it uses svrmgrl/sqlplus on the target machine with the agent.

see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76956/start.htm#6492
"The Location of the Initialization Parameter File in Distributed Environments"

Review &
      Followup

      Rating: 4
my name is
      hema  April 21, 2001
Reviewer:  hema2001
       from egypt
please, i cann't connect to the client although i build
client/server net with nt server 4 ?
please send me how i can develop adistributed database
please......

April 20, 2001 Trang -- Thanks for the question regarding
      "Problem with Moving PL/SQL rercords from PL/SQL table to a cursor",
      version 8.1.6

      You Asked
Hi Tom

     I have a table and a package :
           table : emp(empno,empname,deptno);
                   create table emp
                        (
                          empno number not null,
                          empname varchar2(50),
                          deptno number
                         );

            package : CREATE OR REPLACE PACKAGE "UPA_RECORDSET1"  is

                       type t_cursor  IS REF CURSOR ;

                       Function func(v_empno in int ,
                                     v_columnname in varchar2 )
                             return t_cursor ;

                       end ;
            Package body :

CREATE OR REPLACE PACKAGE BODY "UPA_RECORDSET1"       IS
    Function func(v_empno in int ,v_columnname in varchar2 ) return t_cursor IS

         type t_tab IS TABLE OF emp%ROWTYPE;
--               INDEX BY BINARY_INTEGER;

    v_temp t_cursor;
      v_cursorID    int;
      v_Sel_stat    varchar2(400);
      v_tabtemp        t_tab;
      v_empname        emp.empname%type;
      v_deptno        emp.deptno%type;
      v_Dummy     int;
      v_i          int := 0;
  Begin
        V_cursorID := DBMS_SQL.OPEN_CURSOR;
        V_Sel_stat := 'Select '||v_columnname||' From emp Where empno =
'||to_char(v_empno);
        DBMS_SQL.PARSE(v_CursorID,v_Sel_stat,DBMS_SQL.V7);
      If upper(v_columnname)='EMPNAME' then
         DBMS_SQL.DEFINE_COLUMN(v_CursorID,1,v_empname,20);
         v_Dummy := DBMS_SQL.EXECUTE(v_CursorID);
         LOOP

               IF DBMS_SQL.FETCH_ROWs(v_CursorID)=0 THEN
                    Exit;
               END IF;
               DBMS_SQL.COLUMN_VALUE(v_CursorID,1,v_empname);
               --INSERT INTO v_tabtemp(empname) values (v_empname);
               v_i := v_i+1;
               v_tabtemp(v_i).empname := v_empname;

         END LOOP;
         DBMS_SQL.CLOSE_CURSOR(v_CursorID);
         OPEN v_temp FOR
                Select empname from table cast(v_tabtemp as t_tab);
     Else DBMS_SQL.DEFINE_COLUMN(v_CursorID,1,v_deptno,20);
        V_Dummy := DBMS_SQL.EXECUTE(v_CursorID);
        LOOP
              IF DBMS_SQL.FETCH_ROWs(v_CursorID)=0 THEN
                   Exit;
              END IF;
              DBMS_SQL.COLUMN_VALUE(v_CursorID,1,v_deptno);
                      v_i := v_i+1;
                  v_tabtemp(v_i).empname := v_empname;

        END LOOP;
        DBMS_SQL.CLOSE_CURSOR(v_CursorID);
        OPEN v_temp FOR
                Select empname from table v_tabtemp ;
     End if;
     Return v_temp;

  EXCEPTION
        WHEN OTHERS THEN
            DBMS_SQL.CLOSE_CURSOR(v_CursorID);
            RAISE;
END func;

end UPA_RECORDSET1;
-------------------------------------------------------------------
My problem : When I compile, Error comes :-

Line # = 35 Column # = 37 Error Text = PLS-00103: Encountered the symbol "CAST"
when expecting one of the following:

   (
The symbol "(" was substituted for "CAST" to continue.

Line # = 35 Column # = 61 Error Text = PLS-00103: Encountered the symbol ";"
when expecting one of the following:

   . ( ) * % & - + / at mod rem <an exponent (**)> ||
The symbol ")" was substituted for ";" to continue.

Line # = 49 Column # = 37 Error Text = PLS-00103: Encountered the symbol
"V_TABTEMP" when expecting one of the following:

   (
Please help me
Thanks

      and we said...
You are making this a WHOLE lot harder then it should be.

First, read

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:528893984337
for why using bind variables is the single most important thing you can do as an
Oracle developer.

Second, just use native dynamic sql and skip all of the procedural processing
you are doing above, the routine you want is really very simple.  It is just
this:

ops$tkyte@ORA8I.WORLD> create table emp
  2  (
  3  empno number not null,
  4  empname varchar2(50),
  5  deptno number
  6  );

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into emp select empno, ename, deptno from
scott.emp;

14 rows created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> CREATE OR REPLACE PACKAGE UPA_RECORDSET1
  2  as
  3      type t_cursor  IS REF CURSOR ;
  4
  5      Function func(v_empno in int ,
  6                    v_columnname in varchar2 ) return t_cursor ;
  7
  8  end;
  9  /

Package created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> CREATE OR REPLACE PACKAGE BODY UPA_RECORDSET1
  2  as
  3
  4  Function func(v_empno in int ,v_columnname in varchar2 ) return t_cursor
  5  IS
  6      v_temp t_cursor;
  7  begin
  8      if ( upper(v_columnName) = 'EMPNAME' )
  9      then
 10          open v_temp for
 11          select empname from emp where empno = v_empno;
 12      else
 13          open v_temp for
 14          'select to_char(' || v_columnName || ') empname
                from emp where empno = :x'
 15          USING v_empno;
 16      end if;
 17
 18      return v_temp;
 19  end;
 20
 21  end;
 22  /

Package body created.

ops$tkyte@ORA8I.WORLD> variable x refcursor
ops$tkyte@ORA8I.WORLD> set autoprint on

ops$tkyte@ORA8I.WORLD> exec :x := upa_recordset1.func( 7566, 'empname' );

PL/SQL procedure successfully completed.

EMPNAME
--------------------------------------------------
JONES

ops$tkyte@ORA8I.WORLD> exec :x := upa_recordset1.func( 7566, 'empno' );

PL/SQL procedure successfully completed.

EMPNAME
----------------------------------------
7566

ops$tkyte@ORA8I.WORLD> exec :x := upa_recordset1.func( 7566, 'deptno' );

PL/SQL procedure successfully completed.

EMPNAME
----------------------------------------
20

Thats it.

Third -- in order to SELECT from a PLSQL variable -- you MUST use a SQL type,
not a PLSQL type -- you must use "create or replace type" at the sql level, not
type .... is .... in PLSQL.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:110612348061
for a short example.

Review &
      Followup

      Rating: 5
Thanks for your
      help  April 22, 2001
Reviewer:  Huynh Thi Thu
      Trang  from 627/15A Ba Dinh, P9, Q8, TpHCm, Viet Nam

April 20, 2001 Wenqi -- Thanks for the question regarding
      "OPEN_FORM built-in", version Developer 2000

      You Asked
Hi Tom,

I am doing the self test for LZO-121, the following is the question:
1. After calling a form from another form, you want the control the remain in
the calling form. which parameter of the OPEN_FORM built-in will you use to
accomplish this?
The answer is activate_mode.
I don't think so, I think the answer should be no_activate_mode.

Could you tell me what it is correct? because I will take the certification .

Thank you.

Wenqi

      and we said...
It is a trick question.

The question is "which PARAMETER", not "what value would you set some parameter
to".

The PARAMETER NAME is "activate_mode".

The PARAMETER VALUE is NO_ACTIVATE (but they didn't ask for that).

Review &
      Followup

      Rating: 4
useful for
      Oracle development  April 21, 2001
Reviewer:
      Wenqi Yang  from USA

April 21, 2001 Murali -- Thanks for the question regarding
      "Cursor", version 8.0

      You Asked
Hi Tom,
I had a couple of questions regarding PL/SQL & cursors.
I will appreciate if you could answer them.

a)In your PL/SQL block you performed a delete on the emp table. You want to be
sure some rows were deleted. If there were no records deleted you want to stop
the application and give the user a message that 'the delete didn't find any
records.' Write the complete statement you would put directly after the delete
statement that would test to determine if there were any records deleted and
then give the above message if there weren't any rows deleted.

b)Can you base a %TYPE definition on a cursor as follows? YES or NO?
DECLARE
CURSOR emp_cursor IS
SELECT *
FROM emp;
v_emprow emp_cursor%ROWTYPE;

Thanks...!

Murali

      and we said...
This sounds more like test questions then anything else but...

a)

   begin
     delete from emp where ...;
     if ( sql%rowcount = 0 ) then -- no rows deleted
        raise_application_error( -20001, 'No rows deleted...' );
     end if;
   end;

b) the easiest way to answer those questions is to try them:

ops$tkyte@ORA8I.WORLD> DECLARE
  2  CURSOR emp_cursor IS
SELECT *
FROM emp;
  3    4    5  v_emprow emp_cursor%ROWTYPE;
  6  begin
  7  null;
  8  end;
  9  /

PL/SQL procedure successfully completed.

the answer is YES, you can.

Review &
      Followup

      Rating:
      4
Cursors  April 21, 2001
Reviewer:
      Murali  from Ny
Hi Tom,
Glad to know that you could answer in such a short time.
These were some prepatory questions . As my Nt Box is down, I couldn't do.
Thanks once gain for your Promptness.

April 21, 2001 Nikhil -- Thanks for the question regarding
      "Problem with application context.......", version 6

      You Asked
Sir,
I was so worried that you are not there when i am in lot of problems and thanks
heven u are back.
I dont know what would have happened to all of us if u were not there.
Thanx a tons for being with us.
Sir,
I am using application context for my program that thing is working fine with
sql prompt but when the same thing is tried with the forms its showing error
that i dont have necessary previliges but the users at sql and forms are same
without doubt.
The two statements i used in forms are
FORMS_DDL('CREATE CONTEXT MY_CTX USING MY_PROCEDURE');-- to create the context.
and
DBMS_SESSION.Set_Context('My_Ctx','XYZ',TempName);-- the place which is giving
the error.
Please help me out.
Nikhil
i am using oracle 8i release 2 and there is no web server or any thing else.
Please help me.

      and we said...
See

http://osi.oracle.com/~tkyte/article2/index.html#Ex2

Why would you be creating the context in forms in the first place?  the context
should ALREADY exist-- and even if you do create it in forms -- only the
DATABASE stored procedure MY_PROCEDURE can modify it (dbms_session.set_context
MUST be called from MY_PROCEDURE -- and my_procedure ONLY).

April 21, 2001 Ngo Thuc -- Thanks for the question regarding
      "About Dynamic PL/SQL when transferring Db from SQL Server to Oracle 8i",
      version 8i

      You Asked
Hi all, I am facing a seriuos problem while transferring DB from SQL Server to
Oracle 8i:
 In SQL Server I have a store procedure such as :(very simple in SQL Server)
CREATE PROCEDURE [usp_get_Announcements]
    (@AnnouncementID    int,
     @Columns    nvarchar(200))
AS

Declare @SQL nvarchar(500)

Set @SQL = 'SELECT ' + @Columns + ' FROM Announcements WHERE AnnouncementID = '
+ STR(@AnnouncementID)

Exec (@SQL)

Return @@RowCount

I want to transfer it to Oracle  8i, but I cann't execute Dynamic PL/SQL because
@Columns is an any column in table that I want SELECT.
Addition,In Oracle I want to RETURN a cursor that is a recordset such as SQL
Server.Please help me.
Thanks and Regards

      and we said...
create or replace package my_pkg
as
   type rc is ref cursor;
   procedure usp_get_announements( p_announcement_id in int,
                                   p_columns in varchar2,
                                   p_cursor in out rc );
end;
/

create or replace package body my_pkg
as

procedure usp_get_announements( p_announcement_id in int,
                                p_columns in varchar2,
                                p_cursor in out rc )
as
begin
   open p_cursor for
   'select ' || p_columns || from announcements where announcementid = :x'
    using p_announcements;
end;

end;
/

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:528893984337
for why bind variables are crucial.

See

http://osi.oracle.com/~tkyte/ResultSets/index.html
for full examples of ref cursors (how to return a result set in Oracle)

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:286816015990
for why you want to never use a stored procedure/function but always want to use
packages.
April 21, 2001 Reji -- Thanks for the question regarding
      "Detailed information about a user request", version 8.1.6

      You Asked
Tom:
    We have several processes, some of them are Java with JDBC and
some of them are C++ with OCI.  How can I findout all the connections/requests
from each every processes those who are connected to the DB and their current
status?

Ex:  Process A ( Java with JDBC ) opened a connection and send a request for
"select something from a table for update" - this request
locked set of rows and it may take some time to release this lock.  Mean time
another process is trying to do some other operation to the same table and we
want to just run a tool or script and findout what's really happening.

We really want to point to the appropriate application who made the request and
locked the table.

Thx
Reji

      and we said...
in $ORACLE_HOME/rdbms/admin there is a script catblock.sql.  It'll add some
views to the database.  Run that when connected as SYS or INTERNAL using
svrmgrl.

Then, when the blocking issue occurs, run utllockt.sql found in the same
directory when connected as SYS or INTERNAL in SVRMGRL.  It'll print out a
blockers/waiters chart for you showing you what session is block what other
sessions.

You can use my showsql.sql script (search for showsql on my site) to see WHAT
sql the blockee is trying to execute to find out what they are waiting on.
April 21, 2001 M.
      -- Thanks for the question regarding "Strange Behaviour of Index
      Creation.", version 8.1.5

      You Asked
Hi,

This is kinda unbelievable, but happened to me many times. I have a table of
about 750000 records. I have a column Seq_No that needs to be populated with a
Number Depending on the Entered_on_date .. I have a table created from the other
table by ordering Entered_on_Date to Update the table throuh Procedure. As soon
as I create a Index to speed up the Process of update, it Shuffles the records.
Please have a Look closely on Entered_on_date Colm.

SQL> select media_id, seq_no, entered_on_date from  medloc
  2  where media_id = 100;

  MEDIA_ID     SEQ_NO ENTERED_O
---------- ---------- ---------
       100            26-SEP-95
       100            27-SEP-95
       100            27-SEP-95
       100            25-FEB-98
       100            21-APR-99

5 rows selected.

SQL>  create index idx on medloc(media_id);

Index created.

SQL> select media_id, seq_no, entered_on_date from  medloc
  2  where media_id = 100;

  MEDIA_ID     SEQ_NO ENTERED_O
---------- ---------- ---------
       100            25-FEB-98
       100            21-APR-99
       100            26-SEP-95
       100            27-SEP-95
       100            27-SEP-95

5 rows selected.

SQL>  drop index idx;

Index dropped.

SQL>  select media_id, seq_no, entered_on_date from  medloc
  2   where media_id = 100;

  MEDIA_ID     SEQ_NO ENTERED_O
---------- ---------- ---------
       100            26-SEP-95
       100            27-SEP-95
       100            27-SEP-95
       100            25-FEB-98
       100            21-APR-99

5 rows selected.

You see the date Column is not ordered as I create the Index on Media_Id.. Why
is this Behaviour. Like Every medi_id will have seq_no as from 1.. Number of
entries for that media depending on the Entry date... But it changes the Entries
WHY?

2-- Can you please give me a Reference (Doc Site) for Sys_Context Function..
Like what are the attributes and how to Use.

3-- Can you please give any example of Passing IN and OUT parameter as PL/SQL
table or Arrays to a Procedure and How we Execute that.. PL/SQL table must have
at least three Different Data Types.

Thanks in advance.

      and we said...
#1 -- the order of data returned by a query is indeterminate UNLESS you have an
order by.  If you are counting on the rows to be returned in some predicable
order WITHOUT having an order by -- you are counting on something that is very
unreliable.

Data is not returned in the order it was inserted or anything like that.  If you
need the data in some ORDER, please use an ORDER BY.  That is the ONLY way to
get data in some predicable order.  Everything else is "random".

#2 -- the SQL reference manual documents all functions:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/functi94.htm#88362

#3 -- see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:79812348058
...
April 21, 2001 Igor -- Thanks for the question regarding
      "Backuping temporary tablespace", version 8.0.5

      You Asked
Could you please answer whether a backup of temporary tablespace should be made
or it can be just recreated during recovery procedure?
Thanks.

      and we said...
If it is a TRUE temporary tablespace with TEMPFILES (not datafiles) there is no
point in backing it up, you cannot restore them, rather we just recreate them
during recovery.

If it is a regular tablespace being used as temporary (with datafiles, not
tempfiles), you can back it up -- it'll be up to you.  It is easy enough to
recreate them at recovery time.  Just make sure they hold only temporary objects
-- no tables or anything by accident.
Review &
      Followup

      Rating:
      5
  April 22, 2001
Reviewer:
      A reader

April 21, 2001 Casey -- Thanks for the question regarding
      "Determining if an index has ever been used.", version 8.1.7

      You Asked
Ive inherited a schema with (at first glance) an excessive number of indexes.
Ive reviewed and EXPLAINed many of the common production queries to find that
there are indexes defined not yet utilized.  Im hoping there is a quick way to
find indexes 'never used'.

Thanks in advance!

      and we said...
It is almost impossible to do this 100% in Oracle8i (will be easy in 9i
however).

The best you can do is place each index in its own tablespace.  We track IO by
tablespace.  If the reads are about the same as writes (a little more reading
then writing) we are probably only reading the index in order to update it.  If
the reads are alot more then the writes, we are probably using it to answer
queries.
April 22, 2001 Sridevi -- Thanks for the question regarding
      "Random Page Breaks", version Developer 6, Reports 6

      You Asked
Hi Tom,

How can a manul page break be inserted in a report?

In Reports 6, I have a report containing 8 frames.
I want to introduce a page break after each of the frames. But when I set the
"page break after" property for the repeating frames, the output behaves funny.
After each frame is printed, IT SKIPS 7-8 pages!!!!!

Can i give a manual page break(by introducing control characters) in the report?
How to do this?

To put it differently....
I want the first page to break after line 66
second page to break after line 72 in second page
third page to break after line 56 in third page...
and so on
HERE I KNOW WHICH EXACT LINE NUMBER IN EACH PAGE WHERE THE BREAK SHOULD OCCUR.

I am using a TVS dot Matrix Printer.
the Report is in character mode.

Please Help!

      and we said...
I had to ask around for help on this (reports is simply not my cup of tea)

Bob Bunting of Oracle tells me:

As you probably know, there is not simply a command to issue a page
break on demand for a specific row in a report.  However, within a
repeating frame, you may have an object with a page break before
property set to Yes that is suppressed with a format trigger except for
the condition on which you want the page break.

As I understand your problem, you want to have a series of frames and
repeating frames each with a page break before the frame or repeating
frame.   I started with 2 queries.  Then I created a repeating frame for
query one, followed by a frame with some boiler plate text, followed by
a repeating frame for query 2.  I then successfully put page breaks
before the desired frames and things worked as expected.     The example
is attached based on emp and dept that I think could be similar to what
you are trying to accomplish is attached.  You may want to check
Metalink for some notes which might help you track down specifically
what may be going on in your case.

I am assuming that you are seeing the same results in the previewer as
you are on the printed page.  If not, I would not rule out the printer
not responding as intended to the driver.

You can send specific codes to the printer before and/or after an
object; however, I don't recommend it for page breaks, since reports
should be controlling when the page breaks occur based on the report
content.  Printer codes sent directly is only going to make things more
difficult.
Review & Followup

      Rating:
      5
  April 25, 2001
Reviewer:
      A reader

      Rating: 2
can you set up
      link or display the example code  January 10, 2002

Reviewer:  Reader  from NJ

April 22, 2001 Andrea -- Thanks for the question regarding
      "DBMS_PIPE ,LOGON TRIGGER & DBMS_AQ", version 8.1.7

      You Asked
dear Tom,

I implement LOGON (and LOGOFF) TRIGGER along with DBMS_PIPE. The scenario is
something like this,

1. LOGON Trigger will send a message to daemon using DBMS_PIPE 'A' Then DAEMON
will do some proccess and return a value to the LOGON Trigger using DBMS_PIPE
'B'. LOGON Trigger will do some proccess and then send value again to DAEMON
using DBMS_PIPE 'C'. And again DAEMON will do some proccess and return value to
trigger using DBMS_PIPE 'D'.

2. LOGOFF Trigger will send a message to DAEMON using DBMS_PIPE 'C'. And DAEMON
will do what is the message without give return to LOGOFF Trigger.

When the daemon run for the first time, it will remove all pipe content, also
when LOGON Trigger finished the proccess, it will remove 'B' & 'D' pipe (pipe
sent by DAEMON), while DAEMON will remove 'A' & 'C' pipe (pipe sent by Trigger)
at the end of every proccess.

While user try to connect is one by one, all works fine. But if a proccess is
still running and another user try to connect or two application try to connect
at the same time, most likely the second will looks like hung, and when I cancel
the proccess it said that DBMS_PIPE is empty.
I need to make some proccess either in LOGON Trigger or DAEMON, and I could not
simplify it.
Can you give me an advise about that phenomenon ?

If I use DBMS_AQ instead of DBMS_PIPE, will this help ?
I try to use DBMS_AQ, in the create_table function, the 'queue_[ayload_type' ask
for row or object type. Because the message I want to send is in varchar, I
create a type which is contain only 1 column in varchar. When I retrieve the
message, I could not manipulate message sent, because it is in type object not
in varchar. How to manipulate the value sent through DBMS_AQ ? Any example will
be better.

Thanks in advance Tom

      and we said...
Use extprocs -- they are infinitely better suited for this. Chapter 10,
application developers guide.

In general, pipes can do what you describe above, I've done it.  You have to do
it differently though.  The requests to the pipe daemon can go down a common
pipe BUT the responses must be returned on pipe names unique to the client --
else If you have two sessions and both write down pipe A and read pipe B --
session 1 might get BOTH respsonses, session 2 might get both responses or
session 1 might see session 2's response and vice versa.

In order to setup the daemon, it should READ from pipe A and part of the message
on pipe A should be the name of a unique response pipe that only the client
making the request knows of.


Subject | Article | Last Updated (East coast time)
switch | article only | Apr 23, 2001 09:16 pm
Shutdown the Application Server | article only | Apr 23, 2001 09:21 pm
tkprof - elapsed time | article only | Apr 23, 2001 09:21 pm
Extent Stategy | article only | Apr 23, 2001 09:24 pm
Sending Email | article only | Apr 23, 2001 09:51 pm
row migration when updating a row | article only | Apr 24, 2001 10:35 am
alter table? | article only | Apr 24, 2001 02:50 pm
Committed data lost at recovery | article only | Apr 24, 2001 02:58 pm
dynamic sql | article only | Apr 24, 2001 09:27 pm
Passing parameters from HTML to web form fails | article only | Apr 24, 2001 09:40 pm
defining types w/i package | article only | Apr 24, 2001 09:50 pm
Upgrade from Oracle 7.3.3 to Oracle 8.1.6 on AIX 4.3.3 | article only | Apr 24, 2001 10:01 pm
Size of SQL | article only | Apr 25, 2001 08:38 am
V$session | article only | Apr 25, 2001 08:52 am
Restrict update access to certain rows while able to read all rows | article only | Apr 25, 2001 12:58 pm
create procedure | article only | Apr 25, 2001 01:33 pm
Regarding Table space ! | article only | Apr 27, 2001 09:16 am
About MaxExtents ! | article only | Apr 27, 2001 09:22 am
Host name and sequences | article only | Apr 27, 2001 11:09 am
create sql script file from an export.dmp file | article only | Apr 27, 2001 11:14 am
Reset Redo Logs | article only | Apr 27, 2001 06:14 pm
How to Tune the SQL and get the best result | article only | Apr 27, 2001 07:12 pm
compile procedure causes ora-1555? | article only | Apr 27, 2001 09:06 pm
Dynamic ref cursors and 8.0.4 | article only | Apr 27, 2001 09:51 pm
Sqlplus or Oracle Reports | article only | Apr 27, 2001 10:23 pm
Table Storage Parameter | article only | Apr 28, 2001 11:24 am
Parallel scan of index | article only | Apr 28, 2001 01:23 pm
Changing the error message of violated constraint | article only | Apr 28, 2001 03:32 pm
row(s) 1 - 28 of 28
April 23, 2001 -- Thanks for the question regarding "switch", version 8.1.6
You Asked
Tom:

i have a question as following.

create table a ( a int, b int unique);
insert into a values (1,1);
insert into a values (2,2);
what's the best way to switch the values of column b
by using jdbc call?
so the result would be
(1,2)
(2,1)

first disable the constraints and then switch and then reenable it?
and we said...
No, just use a single SQL statement, here are two -- the second is more "general
purpose"

ops$tkyte@ORA8I.WORLD> create table a ( a int, b int unique);
Table created.

ops$tkyte@ORA8I.WORLD> insert into a values (1,1);
1 row created.

ops$tkyte@ORA8I.WORLD> insert into a values (2,2);
1 row created.

ops$tkyte@ORA8I.WORLD> insert into a values (3,4);
1 row created.

ops$tkyte@ORA8I.WORLD> commit;
Commit complete.

ops$tkyte@ORA8I.WORLD> select * from a;

         A          B
---------- ----------
         1          1
         2          2
         3          4

ops$tkyte@ORA8I.WORLD> update a
  2     set b = decode( b, 1, 2, 2, 1 )
  3   where a in ( 1, 2 )
  4  /

2 rows updated.

ops$tkyte@ORA8I.WORLD> select * from a;

         A          B
---------- ----------
         1          2
         2          1
         3          4

ops$tkyte@ORA8I.WORLD> rollback;
Rollback complete.

ops$tkyte@ORA8I.WORLD> variable a1 number
ops$tkyte@ORA8I.WORLD> variable a2 number
ops$tkyte@ORA8I.WORLD> exec :a1 := 1; :a2 := 2;

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> update a
  2     set b = ( select a2.b
  3                 from a a2
  4                where a2.a in ( :a1, :a2 )
  5                  and a2.a <> a.a )
  6   where a in ( :a1, :a2 )
  7  /

2 rows updated.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select * from a;

         A          B
---------- ----------
         1          2
         2          1
         3          4
Review & Followup
Rating: 5
Switch unique column values August 06, 2001
Reviewer: Janne Thorshag from Sweden
I was most surprised and happy when I found exactly what I was looking for just
by searching on "switch values".

April 23, 2001 Kelvin -- Thanks for the question regarding "Shutdown the Application Server", version 4.0.7
You Asked
Dear Tom,

For Application Server in NT, except using the Browser Interface to shutdown the
Application Server, can I use the command line (e.g. Batch File) to shutdown the
application server?

In addition, can I custom the Browser Interface to build up a WEB Page that only
with Shutdown function for operation use?

Thanks
and we said...
owsctl can be used to start/stop the app server from the command line.

Additionally, these things are started and stopped via services. you can also
use the net stop <servicename> command to stop it as well.

You probably could build a web page if you wanted but I've not done so myself
and don't have the software installed to play with (so I cannot tell you exactly
how to do this).  You could definitely setup a cgi-bin script (.cmd file) on
your server that does the net stop <servicename> to stop it via your own custom
page.
April 23, 2001 Vimal -- Thanks for the question regarding "tkprof - elapsed time", version 8i
You Asked
HI Tom ,

I am involved in an apps upgrade (107 to 11i) project , involving changing RBO
to CBO.

Follwoing is extract from trace files of a sql stmt run at different times ,
execution plans was similar only thing different is disk reads and CPU times

FIRST RUN

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.02       0.53          0          0          0           0
Execute      1      0.01       0.00          0          0          0           0
Fetch        1     32.08     281.88      90788     539029        124           8
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4     32.11     282.41      90788     539029        124           8

SECOND RUN
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.04       0.05          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1     26.26      31.07      77790     539052        124           8
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4     26.30      31.12      77790     539052        124           8

My questions are

1. Can the difference in elapsed time be attributed to decrease in disk reads
from 90788 to 77790.

2. Can we force SQL stmt to use maximum disk I/o so that we have know maximum
time SQL takes to run (during testing- taking worst case )

3. Can we determine the value of elapsed time had there been 539052 disk reads,
if if have above data with us

Thanks
Vimal
and we said...
1) absolutely.

2) no -- and it wouldn't give you the maximum time anyway.  If you look at the
above, the time increased almost an order of magnitude but the amount of reads
increased only 20% or so.  There was excessive contention when you ran the first
run (lots of users were probably reading the disk at the same time).  You might
run the query again -- get 90788 physical IOs and find the elapsed time to be
less then 31 seconds!  It is all about shared resources and contention for these
resources.  it is not purely a function of the number of physical ios, it is a
function of how long those io's take to service AT THAT point in time.  When you
ran the first query -- it took a long tie.

3) no, and it would not be meaningful anyway.  Just becase there was 540k query
blocks does not mean that the query could EVER result in 540k physical reads!
Heck, there might not even be 540k blocks in the database.  If I read data via
an index, I'll tend to read and re-read the same block many times in a given
query.  I can show you a query against a 1,000 block table that does over 20,000
query blocks.  the query reads and re-reads these blocks over and over -- they
will be cached after the first read, there would never be 20,000 physical io's
for that query (unless the buffer cache was WAY too small and all of the blocks
get flushed almost immediately after their first read)
April 23, 2001 Jason -- Thanks for the question regarding "Extent Stategy", version 7.3.4.5
You Asked
Hi,

I was after some general guidelines on values to set initial and next extent to
on a dictionary controlled dbms.

One specific question is should the nitial extent be the same size as the
initial size of the object and next be the same size or a percentage chunk of
the initial extent size based on a average growing object.

thanks in advance, Jason
and we said...
initial should be set equal to next.  pctincrease should be equal to 0.  All
objects in a tablespace should use the SAME exact initial and next (or at the
very least nice multiples of eachother).

It is OK, normal, and not at all bad to have objects with hundreds of extents.
do not try to squeeze the object into a single initial extent.  Organize objects
by their sizes -- have a tablespace where you have 1meg extents, another with
5meg extents and so on.

You'll be simulating the implementation of a locally managed tablespace with
uniform extent sizes in your 7.3 database.
Review & Followup
Rating: 4
Extent strategy April 25, 2001
Reviewer: Jason Bunyard from Australia
tom answered my question well in that he clearly said keep your initial and next
extents the same and told me not to try and fit an entire object into the
initial extent. he also explained the idea of the grouping of similar sized
objects into common tablespaces.

thanks for your help tom.

April 23, 2001 Sankarakailasam -- Thanks for the question regarding "Sending Email", version 7.3
You Asked
My Client has Database Version 7.3 and APPS version 10.7.  They want to send
emails to all their employees and vendors through an automated process.

What is the best way to handle this?  Will DBMS_PIPE be an ideal solution, given
the situation OR is there any better method to handle this?

Any ideas/insights would be highly appreciated.

Thanks,

Kailasam
and we said...
If they are using APPS, look at the Oracle ALERT mechanism as part of apps -- it
does this for you.
April 24, 2001 Jonathan -- Thanks for the question regarding "row migration when updating a row", version 8.1.5
You Asked
When I update a row so that it becomes too long to be stored in the data block
it was.
It is then moved into another data block.

What are the steps for this operation :

update of the row
delete of the row from initial block
insert in new block??
and we said...
When a row is migrated like that, we leave a forwarding address behind on the
original block.  So, when you update -- we move the row to a new block and
change the block that USED to have the row to now have the address of the new
location.  The rowid of the row does not change (indexes that point to this row
do not have to be updated)...
April 24, 2001 -- Thanks for the question regarding "alter table?", version 8.1.6
You Asked
Tom:

SQL> insert into b values(1,1);
insert into b values(1,1)
*
ERROR at line 1:
ORA-02291: integrity constraint (JIM.SYS_C002551) violated - parent key not
found

SQL> alter table b constraint JIM.SYS_C002551 deferrable;
alter table b constraint JIM.SYS_C002551 deferrable
              *
ERROR at line 1:
ORA-01735: invalid ALTER TABLE option
and we said...
constraints must be created deferrable.  For example, in the above, the primary
key would have generated a UNIQUE index initially since it was not deferrable.
That index now needs to be dropped and created as a NON-UNIQUE index in order to
support the deferrable option.

drop and recreate the primary key.
Review & Followup
Rating: 4
Where can I post my question? September 10, 2001
Reviewer: Rakesh Soni from India
Excellent.

April 24, 2001 Lindsay -- Thanks for the question regarding "Committed data lost at recovery", version 8.1.7
You Asked
Is committed data in the redo logs lost when a full recovery is done from a hot
backup?  My understanding is that the datafiles are restored from the backup set
and then archived logs are applied via a recover database command.  If there was
committed data in the online redo logs that was not archived (with a logswitch)
before the failure, that required a recovery, is that data lost?
and we said...
NO, NO, NO.

When you restore a datafile, you will apply the archived redo logs AND the
online redo logs to it (this is why you NEVER ever backup the online redo logs
-- you never want to restore over them).

We'll just keep rolling forward through all of the logs -- archived and online.
April 24, 2001 -- Thanks for the question regarding "dynamic sql", version 8.0.5
You Asked
I would like to know how I can create procedure or function that could generate
another procedure or function dynamically. I know dbms_sql can generate sql
statement dynmically. But I can't find the example that can create a procedure
or function dynamically from another procedure or function.

Thank you very much

Tin
and we said...
Just dynamically execute the create or replace procedure command.

ops$tkyte@8.0> create or replace procedure execute_immediate( p_sql in varchar2
)
  2  is
  3      cursor_name     pls_integer default dbms_sql.open_cursor;
  4      ignore          pls_integer;
  5  BEGIN
  6      dbms_sql.parse(cursor_name, p_sql, dbms_sql.native);
  7      ignore := dbms_sql.execute(cursor_name);
  8      dbms_sql.close_cursor(cursor_name);
  9  END;
 10  /

Procedure created.

ops$tkyte@8.0> desc  p
ERROR:
ORA-04043: object p does not exist

ops$tkyte@8.0> begin
  2     execute_immediate('create or replace procedure p as begin null; end;' );
  3  end;
  4  /
begin
*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "SYS.DBMS_SYS_SQL", line 491
ORA-06512: at "SYS.DBMS_SQL", line 32
ORA-06512: at "OPS$TKYTE.EXECUTE_IMMEDIATE", line 6
ORA-06512: at line 2

ops$tkyte@8.0> grant create procedure to ops$tkyte;

Grant succeeded.

See
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for why I got that error and why the grant is needed

ops$tkyte@8.0> begin
  2  execute_immediate('create or replace procedure p as begin null; end;' );
  3  end;
  4  /

PL/SQL procedure successfully completed.

ops$tkyte@8.0> desc p
PROCEDURE p
Review & Followup
Rating: 5
Useful for similar error (While creating table through DBMS_SQL) February 04, 2002
Reviewer: Vikas Shirdhankar from INDIA
Thanks Tom,

It was of great help to me.

I had just created a procedure run_ddl(p_sql varchar2). I created this procedure
with the login of our application user. This user owns the whole application
schema & we always create tables with this user.

So I was really surprised when
execute run_ddl('CREATE TABLE AA(A NUMBER(1))');

gave insufficient privileges error.

After struggling for two hours I gave a try on this site && got this question
about creating procedure. I just explicitly gave CREATE TABLE to the user. And
guess what, it started working.

So I guess even CREATE TABLE privilege is required directly & not through the
role.

The above PLSQL was working okay when ran as anonymous block.

Thank you ver much,

Vikas, India.

Rating: 5
December 03, 2002
Reviewer: Selidan

April 24, 2001 -- Thanks for the question regarding "Passing parameters from HTML to web form fails", version 6i
You Asked
Hi Tom,

Another question.
I'm aware that you are able to pass parameters between forms using
CALL_FORM (using parameter list).

Is it possible to pass parameters to a form from the webpage?

To elaborate,
This is what I put on the HTML :
<a href="
Test">http://inetdev01/dev60cgi/ifcgi60.exe?form=main_wolog.fmx&ps_n=12345">Test
Form</a>
And I created a Parameter PS_N in the form main_wolog.fmx

However, the web-form was not able to "receive" the value. Does this mean I have
to amend something on the base.htm?

Thanks a heap
and we said...
ABSTRACT:
---------
Passing runtime parameters in webforms.

DESCRIPTION:
------------
Create user defined parameters in Forms and pass values at runtime (from
the html file) when deploying forms on the web. You can pass parameter
values in all the three implementation methods: static, cartridge, and
CGI.

Static Implementation:
In the static html file modify the argument as below
  serverArgs="module=<form> userid=<user/pass@dbstring> p_deptno=15
              p_dname=Testing"

Cartridge Implementation:
The parameters are passed at the URL at follows:
http:///?module=&userid=
       &p_deptno=15&p_dname=Testing

CGI (Common Gateway Interface) Implementation:
In the Formsweb.cfg (Forms web configuration) file, atleast three
runtime arguments can be passed at startup during the deployment
process. The three default runtime arguments are 'form', 'userid', and
'otherparams'. These parameters are assigned in 'basejini.htm' and
'base.htm' files as:

In the Netscape section.....
  serverArgs="module=%form% userid=%userid% %otherparams%"  and

In the Internet Explorer section.....
  <PARAM NAME = "serverArgs"
                VALUE = "module=%form% userid=%userid% %otherparams%" >

The runtime arguments would look similar to this statment:
http:///dev60cgi/ifcgi60.exe?form=
       &userid=<user/pass@dbstring>
       &otherparams=p_deptno=15 p_dname=Testing
       &useSDI=yes
       &config=HTTP_JINIT
       &lookAndFeel=oracle
       &colorScheme=teal

NOTE:
Here, 'p_deptno' and 'p_dname' are user defined parameters in forms that
are assigned values at runtime and are being passed from the html file
in a static implementation and from the URL in cartridge and CGI
implementations.
<domain> is like 'www.abc.com:8979'
<frmweb> is the virtual directory mapping to the physical location on
         the middle tier where html files, forms, reports...... reside.
<form> is the name of the form that is being deployed
<user/pass@dbstring> is like 'scott/tiger@testdb'
More importantly notice the difference in the way the arguments are passed.
In the absence of '&' as in static implementation use a space.
April 24, 2001 susan -- Thanks for the question regarding "defining types w/i package", version 8.1.6
You Asked
By following the example of 'returning a pl/sql into a ref cursor' example, it
works fine w/ me.
for myscalartype, and mytabletype, both were created as independent objects
outside the package in the example code giving.

If I tried to define mytabletype inside the package, then it is
able to be compiled but during the
execuation, it will throw internal error.

Basically, I have a procedure w/ 4 output parameters and want to assign the
values to a record type as to have a ref cursor returned.  so, it will return a
result set in stead of 4 individual output parameters.
But I don't want to create additional types at the schema level.  I only want to
do it inside the package.  Because in a multiuser development, without
specifying clearly the schema_name, the type object is not recognized.

Thanks a lot for your help
and we said...
I suggest that when using Oracle Types -- you create a schema called "my_types"
or something and put ALL types into that.  Similar in concept to what Oracle
does with CTXSYS, ORDSYS, MDSYS and so on.  In that fashion, your types are
always MY_TYPES.TYPENAME.

The bottom line is -- in order to return a type using SQL, you MUST use a SQL
type -- not a PLSQL type.  The ONLY way to have a SQL type is to use the "CREATE
TYPE" command outside of PLSQL.  When you create the type in PLSQL -- only PLSQL
can "see" that type -- SQL is NOT aware of it.

What might be more applicable to you, if you do not like the MY_TYPES approach,
would be to use a global temporary table and a ref cursor opened on that
instead.

Search for

global temporary

on my site for info on that.
Review & Followup
Rating: 4
April 27, 2001
Reviewer: A reader from in U.S.A
Thanks for the information.

April 24, 2001 Killivalavan -- Thanks for the question regarding "Upgrade from Oracle 7.3.3 to Oracle 8.1.6 on AIX 4.3.3", version Oracle 7.3.3
You Asked
Hi,

Currently we are using Oracle 7.3.3 on AIX 4.2.1. We are going to
upgrade the newer version Oracle 8.1.6 on AIX 4.3.3.

I would like to know the impacts on the database objects and what are
all the changes to be done while upgrading the newer version. Hope
to hear from you very soon.

Thanks and Regards,
Dhanasekaran K
and we said...
http://technet.oracle.com/doc/oracle8i_816/server.816/a76957/toc.htm
that document lists all of the necessary steps and procedures you must be ready
to do, what preparatory work needs be performed, and so on.
April 25, 2001 Murali -- Thanks for the question regarding "Size
      of SQL", version 8.1.6

      You Asked
Hi Tom,

Can please tell me that what is the maximum size of an sql statement can be.

Thanks,

Murali

      and we said...
It is dependent on the environment.  In general, there is no fixed limit but
various TOOLS may impose their own.  Most accepts AT LEAST 32k
April 25, 2001 Howie -- Thanks for the question regarding
      "V$session", version 8.0.5

      You Asked
TOM

I had a thinking that INACTIVE sessions goes off after some time from V$session.
But now I am surprised that few INACTIVE sessions stay for a long , I am not
sure why.

  1  select osuser,username,status,machine from v$session
  2* where status='INACTIVE'
SQL>/

OSUSER                         USERNAME                       STATUS
------------------------------ ------------------------------ --------
MACHINE
----------------------------------------------------------------
oracle                         SYSPROD                        INACTIVE
jdbcclient

oracle                         SYSPROD                        INACTIVE
jdbcclient

oracle                         SYSPROD                        INACTIVE
jdbcclient

oracle                         SYSPROD                        INACTIVE
jdbcclient

oracle                         SYSPROD                        INACTIVE
jdbcclient

oracle                         SYSPROD                        INACTIVE
jdbcclient

Could you explain why these sessions stay there for long in v$session

Thanks
Howie

      and we said...
inactive sessions are just sessions that haven't submitted any sql to the
database for a while.

Open up sqlplus.  Now goto another window and open another sqlplus.  query
v$session.  Your first sqlplus session will be INACTIVE -- and it will stay that
way until you EXIT or do something.

You apparently have some jdbcclients that connect to the database, do not log
off, and don't do anything for some period of time.
April 25, 2001 Bruce -- Thanks for the question regarding
      "Restrict update access to certain rows while able to read all rows",
      version 6.0.8.10.3

      You Asked
What would be the best way to allow users to read an entire table, but restrict
inserts, updates, and deletes to only certain rows within the table using a
single form?  The rows users are allowed to modify or insert would have to have
certain column values for one of the columns.

The application has a table of values for various lists and has the following
type of structure:

ColType     ColCode    ColDesc
ABC           D1       Great condition
ABC           E1       Good condition
ABC           F2       Lousy shape
DEF           ADMH     Admission - hospital
DEF           ADMN     Admission - none
XYZ           GND      Ground based
XYZ           ATM      Atmospheric
. . .

I need to allow user JOE to read, add, and update the ABC list, update (and not
insert or delete) values for the DEF list, but only read the XYZ list.  Another
table contains usernames and the privileges they have for a lists (except for
read - everyone is allowed to do that on all lists).  For example:

UserName   ListName  Ins Upd Del
JOE        ABC       Y   Y   N
JOE        DEF       N   Y   N

Is this better done using application contexts or some other mechanism (e.g.
forms code to handle the rules)?  I am not sure how to know what operation is
being done in using a security policy and an application context.  I am using
Oracle 8.1.6.1.2 on NT.

Thank-you for your response.
Bruce

      and we said...
Fine Grained access control sounds like the way to go to me.

See

http://osi.oracle.com/~tkyte/article2/index.html
for an overview of using this technology.
April 25, 2001 --
      Thanks for the question regarding "create procedure", version 8.1.6

      You Asked
Tom:

how should i do something like this:
since table a is not created yet, it gives me error.

create or replace procedure testing as
  2  begin
  3  execute_immediate('create table a ( a int)');
  4  insert into a values (11);
  5* end;

      and we said...
You should not do something like that!!!

DDL is terribly expensive, any procedure that does DDL as a matter of fact
should be carefully considered.

Static sql in plsql is sent through the plsql parser at compile time - since the
table A does not exist the plsql engine cannot

o do the security check (can you access table A)
o set up the dependency (so if A is dropped the procedure is invalidated and so
  on)
o figure out the datatypes and how to bind to the statement.

and so on.

I hesitate to tell you HOW to do this -- since you SHOULD NOT do this but... it
is easy enough to figure out.  You have to do it dynamically.  dynamically
insert just as you dynamically created.

BUT -- don't do it!

Followup to first comment

Read the answer above -- I did tell you exactly how to do it.

"You have to do it dynamically.  dynamically insert just as you dynamically
created."

Review &
      Followup

      Rating: 2
Tell us
      More...  April 26, 2001
Reviewer:  Misbah
       from Markham, Canada
But you could tell us even if we are not supposed to use it...

      Rating:
      5
  April 28, 2001
Reviewer:  Harrison
      Picot  from Haymarket, VA USA

      Rating: 4
Hey Figure out
      the Rest of it Ur Self  May 04, 2001
Reviewer:
      Usama Munir Dar  from Islamabad, Pakistan
I mean  if u can't figure out from it what to do..then u shouldn't know anyway.

April 27, 2001 OP -- Thanks for the question regarding
      "Regarding Table space !", version 8.1.6.0

      You Asked
Hi Tom,

How are you Doing !

Nice to see you back.

I have a Question related with Tablespace

Suppose there is a database NIIT with Tablespace T1 and T2.

T1 Tablespace has a user  USER1
T2 Tablespace has a user  USER2

Q1) I want to transfer all objects of USER1 from T1 Tablespace
to USER2 in T2 Tablespace.

How should I go about this.

Q2) Now if T2 Tablespace is a part of another database
name [DB2] ,

then how will I transfer the Records from T1 from NIIT
to T2 in DB2.

Q3) Oracle 8i has a feature Transport Tablespace.

Can I solve the above problem by making use of this
feature in Oracle 8i.

Thanks and Regards
OP Lalwani

      and we said...
q1)

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:47812348053
q2) transportable tablespaces.
    exp/imp.
    sqlplus COPY command
    create table as select <from a dblink>

are all viable options for you.

q3) yes.
April 27, 2001 OP -- Thanks for the question regarding "About
      MaxExtents !", version 8.1.6.0

      You Asked
Hi Tom,

Actually I had gone for an Interview and there was a Question
related with MAXEXTENTS.

Q1) What is MAXEXTENTS and when it is generally used.

Q2) Is it possible to reduce or compress the value initialzed
for MAXEXTENTS.

Lets say for a table it's value is 4.Can we compress it
and make it 2.

iF YES,how it can be compressed.

Thanks and Regards
OP Lalwani

      and we said...
q1) that seems obvious to me -- it is the maximum number of extents that object
MIGHT be allowed to allocate given sufficient free space.  If maxextents is 4,
the object will fail if it tries to allocate extent #5

q2) you can lower maxexents to a value that is greater then or equal to the
current NUMBER of extents allocated (or you can free NEVER used extents as
well).  So, if the table has maxextents 4 and 2 extents allocated -- yes, you
can make it two.  If the table has maxextents 4 and 4 extents allocated and 2
extents have NEVER been used, you can release those two and set max extents
down.

What I think they were asking was "if the table is in 4 extents and had used all
4 extents, can we compress it down to 2 extents".  The correct answer for that
is "i have better things to worry about then a table in 4 extents, that is
nothing to worry about but -- if you really wanted to, it would depend on the
tabletype --

if it was an IOT (index org. table) I would do an online rebuild of the index
using new storage parameters.  that would release the space.

if it was a heap table -- I would use the procedures outlined in

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:47812348053
to rebuild the table.

April 27, 2001 Nick -- Thanks for the question regarding "Host
      name and sequences", version 8.1.7

      You Asked
Is there a better way than querying v$instance to determine the host name where
the database is runnung?

We will be using advanced replication, and appending the host name to an Oracle
sequence number seems to be the easiest way to prevent conflicts. Is there
another approach that you recommend to accomplish this?

      and we said...
I cannot imagine an easier way to get the hostname -- however -- that would not
be a good way to do what you want.

Much much easier just to:

o guess at the max number of sites you'll ever have (say 10) in the replication
environment.

o multiply by 10 (100 now)

at site 1, create sequence myseq start with 1 increment by 100;
   site 2, create sequence myseq start with 2 increment by 100;
   ...
   site N, create sequence myseq start with N increment by 100;

now, each site just uses the sequence -- no muss, no fuss and a simple MOD can
tell you the site that created the row in the first place.

Review &
      Followup

      Rating:
      5
  May 17, 2001
Reviewer:  Nuno Souto
       from Sydney, Australia
Very useful bit of info.  Didn't know it was possible to use this as the manual
seems to indicate a "hostname" would be needed.  Definitely going to use it.

April 27, 2001 Patricia -- Thanks for the question regarding
      "create sql script file from an export.dmp file", version 8.1.6

      You Asked
I am required to provide a script file that will recreate an entire database
including schema,users,objects,privileges.  All of this is contained in my full
export.  Is it possible to create a sql script file that provides the same
results as a full import from the .dmp file.

      and we said...
I'd really ask the recipient of this file why a DMP file wouldn't satisfy the
requirement.

However,

you can get this, albeit with some work, via:

imp userid=.... full=y show=y

and redirecting the output (it'll not actually IMPORT it just show you what it
would do).  It'll require lots of reformatting to actually be a script you could
run.

Toad and other tools like that have abilities in this area as well (but the dmp
file is the best option in my opinion).

April 27, 2001 M -- Thanks for the question regarding "Reset
      Redo Logs", version 8.1.7

      You Asked
Based on the manual ORACLE8i Backup and Recovery Guide Rel 8.15 Feb 1999 (pages
1-4, 1-20, 1-23, 14-33), we know that whenever we perform an incomplete
recovery, we must reset the redo logs. Our question is :

When we perform an tablespace point-in-time recovery (TSPITR), do we have to
reset the redo logs as TSPITR seems to be a incomplete recovery if it is not
recovered to the current time point ? If we do not need to do resetting the redo
logs, how does Oracle maintain the redo logs? Does Oracle removes/clears all the
change logs happened on that tablespace from the recovered time point to the
current time point in the redo log files?

We would also like to know if we have to shutdown and reopen the database in
order to reset the redo logs.

Another question is: Is the redo logs a database level or instance level? For
example, for the parallel server, does each node/instance have its own redo
logs, or the parallel server has only one redo logs that covers all nodes?

Thanks very much for your help.

      and we said...
TSPITR is "magic" performed by rman.  It in effect:

o restored system+rbs+affected tablespace to a mini-instance
o PIT recovered that mini-instance
o transported the tablespace out of this mini-instance
o destroyed the mini-instance
o destroyed the tablespace in the real instance
o transported in the PIT recovered tablespace from the other instance.

so in effect, it does a reset logs ONLY to the mini-instance that you never see.

Yes, you have to shutdown since resetlogs is part of the alter database OPEN
statement.

Each instance has its own redo threads that are available to all other
instances.  if a node in the cluster fails, another node will pick up that redo
and rollforward/back -- recovering the failed instance's transactions for us.
April 27, 2001 Ranjan -- Thanks for the question regarding "How
      to Tune the SQL and get the best result", version 8.1.x

      You Asked
Hi

We are having a table say table1

Table 1 has the following fields
Group_id
Message_id,
key1
value1

It is expected that table 1 can contain millions of records at any time. And it
will have insert/delete/select operation concurrently.
We are required to fetch number of records for a set of group_id.
Like
select count(*) from table1 where
key1 is null and group_id in (G1,G2,G3)

So what are the precautions I should take to handle such kind of operations on a
large table and provide high degree of performance (specifically the select on
this table) and also avoid dataconcurrency problem.This table can be accessed by
500 user simultaneously.

Thanks
Ranjan

      and we said...
Oracle will take care of the concurrency issues.  READERS never block WRITERS
and WRITERS never block READERS.  A writer can block another writer but thats
it.

I would probably put a conventional B*Tree index on (GROUP_ID,KEY1) in order to
answer that question efficiently.  Do NOT use a bitmap index which would make
the query go very fast but would KILL the performance of multi-user
insert/update/delete.
Review & Followup

      Rating:
      4
  April 30, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

      Rating:
      3
  July 20, 2001
Reviewer:  Pichaimani
      Balasubramanian  from San Jose, CA USA

April 27, 2001 zhu -- Thanks for the question regarding "compile
      procedure causes ora-1555?", version 7.3.4

      You Asked
hi,tom:
  ask u a second question:
  our applicion is running on oracle734 database,and have a lot of
procedures,some of which are most low level,called by others.
  and when i compile those low level procedures in sql*navigator(using auto
recompile dependent procedure option), oracle always give out ora-1555 error.
leaving some of them uncompiled,still invalid.
  and i think compile procedure is a ddl job(though i find some dml statement to
system table),why would this happen?
  and i checked it myself, hard to find which rollback segment is used by the
compile procedure.all the rollback segment is in good state(none of them exceed
max extetents).
  how shall i avoid that occuring again? thanks tom.
append information:
the the ops env, the instance i was compiling has 6 rollback segment,one
system,6 ordinary with initial 1m next 1m minextents 4.and one large rollback
segment with initial 4m next 4m optimal 20m.
and the compiling procedures is not simple compile. do u use sql*navigator? it
has an option that if u compile a low level procedure, it will automatically
recompile the dependent procedures. and i choose this option. about 30
procedures are recompiled when i compile that low level procedure.
  and nearly every time i recompile the procedure, ora-1555 appears.
  it troubles me so much, thanks for u help.

      and we said...
You might want to search for 1555 on my site.  1555 is caused by rollback
segments being too small to provide a consistent read -- not by being too small
to handle a transaction.  the 1555 is generated on a READ, not on a write of
data.  A transaction that generates no rollback is subject to a 1555.

I do not use sql*navigator no.  I actually do not worry about invalid procedures
in my database as they will NATURALLY recompile themselves when need be.

I've NEVER seen a compile raise a 1555 although it is possible (must be, you are
getting it).

You have 6 rollback segments of 4m each.  I myself prefer to run with 10-20
rollback segments of 25 meg each.  I hate the approach of  "a big rollback
segment" -- they should all be the same size.  The odds of a 1555 are in direct
proportion to your SMALLEST rollback segment.  That large rollback segment might
help some big transaction -- but the small ones kill the long running queries
(you are hitting that with the 1555).  I would recommend going with 10
equi-sized rollback segments that were a lot bigger then you currently have.

1555 is caused by not configuring enought RBS for your QUERIES to co-exist with
your transactions.  I suspect sql*navigator is doing something like:

  for x in ( select * from data_dictionary where status = invalid )
  loop
     alter procedure compile
  end loop

The problem is that alter is DDL, ddl commits -- they are committing in a cursor
loop and the cursor is querying the table they are modifying (the data
dictionary is being modified by the alter).  Bamm -- classic 1555 error
conditions.  You need bigger rollback segments.

please see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:275215756923
If you have so many procedures invalid -- you might have a bigger problem
though.  You are probably using STAND ALONE procedures, you should be using
PACKAGES.  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:286816015990
for why this is so.  they will break the dependency chain and you will not have
so many things to compile when you make a minor change (NOT that you need to
compile them in the first place!)

April 27, 2001 K -- Thanks for the question regarding "Dynamic
      ref cursors and 8.0.4", version Oracle 8.0.4

      You Asked
Tom:

I am moving our code from 8.1.5 to 8.0.4, I had the following kinds of errors.

1) All ref cursors using dynamic queries failed:

   A simplified example that used to work in 8i quite well is shown here:
     vQry := 'SELECT name FROM T ' || ' WHERE id = :1 ';
     open rc for vQry using in_id;

   To make this run on 8.0.4, the solution I have in mind (I know it's not a
great one) is:

   I have a small pl/sql procedure that executes queries dynamically using the
dbms_sql package called exeQuery (a simplified, execute immediate of 8i)

Then I will have a code snippet like this:
I have created a table specifically to get the below code working called tmp_T
(couldn't create global temporary table in 8.0.4 for some reason).

   vQry := 'SELECT name FROM T ' || ' WHERE id = ' || in_id;
   vQry := 'insert into tmp_T ' || vQry;
   exeQuery(vQry);
   open rc for SELECT name from tmp_T;
   delete rc;
   commit;
   return rc;

My question is
1) Is there a way to avoid another session coming along and corrupting this
scheme?

2) Is there a better way to do this in 8.0.4 at all?

3) Can I avoid inserting into a table at all?
I found it very hard to convert the dynamic queries to static ones, because the
queries are built based on many input parameters.

4) Is there a transaction based or a session based temporary table in Oracle
8.0.4?

Any help will be appreciated,

Thanks

      and we said...
1) another session cannot CORRUPT this data.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:848827203811
for an example that does exactly this.

DO NOT COMMIT (unless you want to get ora-1555 all over the place).  It is not
necessary - no one else can see the data.  the commit would be a bug.  The
delete is necessary, the commit is not.

2) in 8.0.4, there is not.  I would URGE you to use BIND VARIABLES!!!!!  My
example is simplistic like yours but you should BIND id into the query -- NOT
concatenate it in (if you want to scale above 1 or 2 users anyway).

3) Using object types, you could create a procedure that fetches into a nested
table collection and then opens a ref cursor on that collection variable.  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:246014735810
this works ONLY if you have the objects option in 8.0 (it didn't come with the
database in 8.0, it was an option)

4) No, they were new with 8i.  The insert/open cursor/delete trick works in 8.0
without any concurrency related issues whatsoever.  You'll generate more
rollback/redo then you would like but that'll be unavoidable in that release.

IT IS CRUCIAL FOR YOU TO SUPPORT BIND VARIABLES.  I cannot overstate that fact.

Review &
      Followup

      Rating: 4
As always, very
      informative  April 28, 2001
Reviewer:  K
       from Ellicott City, MD

      Rating:
      5
  April 30, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

April 27, 2001 Eduardo -- Thanks for the question regarding
      "Sqlplus or Oracle Reports", version 6i

      You Asked
Hi Tom.

I have next doubt :

We are developing an application, we have a centralized database in the city A
(corporation), and others 12 branches offices in the country.
( The RDBMS is Oracle 8i 8.1.7)
The applications will be run in every branch office using oracle forms.
the application make remote connections to corporation to retrieve data from the
database for each user.
But the end users sometimes must execute reports in differents times in a day.

Is there some overhead in the performance whether we create the same  reports
using oracle reports instead of create them in sqlplus using the same code in
both cases.?

Can you explain to me the best choice between Oracle Reports and SQlplus that do
not affect the database performance ?

Thanx in advance

      and we said...
Whether you use reports or sqlplus will not materially affect the database
performance -- they both just submit SQL and the database doesn't really care
WHO submits the sql -- it'll do the same amount of work either way.

The difference is in the output.  sqlplus will give you simple character mode
reports -- period.  Reports will give you pdf, html, character mode, etc etc
etc.  sqlplus gives you no layout control really -- reports does.  Reports is a
full fledged report tool, plus is not.
April 28, 2001 Parag -- Thanks for the question regarding "Table
      Storage Parameter", version 8.1.6

      You Asked
Hi Tom :

   Again i came with different question. Can u please guide me book ot any Link
where i can find some good stuff on Sizing for an Database(Tablespace , Segment
, Extent , Table , Index e.t.c.). Because I am working on Oracle from last soo
many year .. but still i am not that much clear on Sizing part. Which all the
factors should be take in to consideration while sizing for Table or Index.

    Tom : we have one table name Customer_Master which going to contain 1,00,000
records initially. After that daily 2000 Fresh Insertion & 2000 Upation is going
to take place.CAn u please suggest me that what storage clause i need to pass ,
when i create such tables. Do i need to do Indexing , Partitioning e.t.c.

   Please , send me good tips on Sizing for the database.

   Secondly , How to convert nunmber (50,000.45) into word like (Fifty Thousand
& Fourty Five paise only)

   Please help me & give me reply ASAP.

Thanks
- Parag

      and we said...
search for

sizing

on my site.  I have some discussions on this.  Basically to SIZE the table, i
recommend loading and indexing a small representative sample of the table,
analyze it and multiply.  That is the only accurate method.

The inserts will add to the growth -- the updates are something you need to
think about -- setting pctfree and pctused.  Search for

pctfree pctused

to see some discussions on that.  It'll be a function of HOW you update the rows
as to how these should be set.

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1407603857650
to spell a number -- use the TO_DATE if your numbers are small enough, else use
the plsql.

April 28, 2001 Steven -- Thanks for the question regarding
      "Parallel scan of index", version 8.1.6

      You Asked
Under what circumstances will an index be scanned in parallel
for a query (range scan, full scan, etc)?

I know that an index on a partitioned table can be scanned in
parallel - but is that true of global or local indexes or both?

What about for non-partitioned tables?

Can a bitmap index ever be read in parallel for a query?

Thanks for your help.

      and we said...
Parallel index FAST FULL SCANS can be done in parallel. Parallel FAST FULL SCANS
can be done on non-partitioned indexes.

Parallel index RANGE SCANS can be done in parallel if the index is partitioned
(matters not if it is global or local - only matters that the INDEX is itself
partitioned).

The partitioning of the underlying table is not relevant here.  Only the
partitioning of the index is relevant.

Partitioned bitmap indexes can be queried in parallel.

April 28, 2001 Man Tik -- Thanks for the question regarding
      "Changing the error message of violated constraint", version 8.1.6i

      You Asked
Dear Tom,

  Can I change the error message of violated constraint?

  I have created a table called USERFUNC with the following format :

 Name                                      Type
 ----------------------------------------- ------------------
 PARTY_ID                                  NUMBER(10)
 PARTYTYPE_TX                              CHAR(1)
 FUNC_ID                                   NUMBER(10)
 READ_YN                                   CHAR(1)
 INSERT_YN                                 CHAR(1)
 UPDATE_YN                                 CHAR(1)
 DELETE_YN                                 CHAR(1)

  I have also created a constraint called UFUN_READ_YN_CHK, which check the
value of field READ_YN must be either in 'Y' (Yes) or 'N' (No). If this
constraint is violated, the following error message is shown :
-  "ORA-02290: check constraint (DEVELOPER.UFUN_READ_YN_CHK) violated"

  Can I change the error message into a much more meaningful sentence like
"READ_YN must be in either (Y)es or (N)o." ?

Yours,
Dick

      and we said...
To a degree yes.  You can name the constraint with up to 30 characters of
whatever you want:

tkyte@TKYTE816> create table t
  2  ( x char(1), constraint
  3  "READ_YN must be Y(es) or N(o)" check ( x in ('Y','N') ) )
  4  /

Table created.

tkyte@TKYTE816> insert into t values ( 'A' );
insert into t values ( 'A' )
*
ERROR at line 1:
ORA-02290: check constraint (TKYTE.READ_YN must be Y(es) or N(o)) violated

But that is the extent of it.

Review &
      Followup

      Rating: 2
You can, at a
      higher level  May 03, 2001
Reviewer:  Jack
       from Netherlands
While it's true that working in SQL*Plus you only have the name of the
constraint to give you a clue of what happened, most users use a more
sofisticated tool to insert data, an application for instance. Changing the
error-message into somehing a bit clearer would be the responsibility of the
application. Using Forms builder you could use the ON-ERROR trigger for that.


Subject | Article | Last Updated (East coast time)
To get the definition of a view | article only | May 02, 2001 08:30 am
who created tables | article only | May 02, 2001 08:30 am
Question Regarding HASH JOIN ! | article only | May 02, 2001 08:40 am
parsing of sql statements -- oo4o | article only | May 02, 2001 08:42 am
How to Access OPS | article only | May 02, 2001 01:21 pm
Acquiring OS blocks on a datafile extension (or new extent) | article only | May 02, 2001 01:26 pm
Result Through Union All | article only | May 02, 2001 11:46 pm
USING SUM FUNCTION WITH A BASIC SELECT STATEMENT WHILE CREATING TABLES/VIEWS | article only | May 03, 2001 12:53 pm
Passing BULK BINd Variable to a query in a procedure | article only | May 03, 2001 01:20 pm
cross - session pl/sql tables | article only | May 03, 2001 04:16 pm
Shared memory and SGA | article only | May 03, 2001 04:19 pm
Oracle Training Administrator Module | article only | May 03, 2001 04:44 pm
Arithmetic on DATE fields - how to add / subract minutes. | article only | May 04, 2001 09:40 am
Raw filesystems and DBA overheads | article only | May 04, 2001 10:16 am
System 'ALL_' tables not workingas expected | article only | May 04, 2001 08:18 pm
Stored Procedure as Data Source | article only | May 04, 2001 08:27 pm
To open the text file from Database Server from forms 6i | article only | May 04, 2001 09:35 pm
DB & Instance | article only | May 04, 2001 11:04 pm
I/O Bandwidth, Rollback segment's available space. | article only | May 06, 2001 12:09 pm
database cloning, standby database, replicated database | article only | May 06, 2001 06:02 pm
9ias question | article only | May 06, 2001 06:16 pm
How to access .DBF files using 'shared' Win/NT network drives | article only | May 06, 2001 10:28 pm
How to set up custon authentication from scratch | article only | May 06, 2001 11:31 pm
row(s) 1 - 23 of 23
May 02, 2001 -- Thanks for the question regarding "To get the definition of a view", version 8.1.5.0.0
You Asked
Dear Tom,

I have created a view earlier. Now I would like to get the definition of the
view. Can I retrive the details like which are the base tables, what kind of
joins are used,etc from the database?  or the DESC command is the only way?

with regards

Kishore
and we said...
The data dictionary has all of this.  To get the view text, I use the scripts
at:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:683824732911
that'll show you have to get the original view definition.  DESC will show you
what is IN the view.

USER/ALL_DEPENDENCIES will show you want base tables are referenced by the view
(hence showing you what is joined together in the view itself)
May 02, 2001 -- Thanks for the question regarding "who created tables", version 8.0.5
You Asked
Hi Tom,
 I am able to find out the database-owner and created_time of created tables
with "select * from *_objects" but i'd like to know who as 'OSUSER', on unix
workstaion created these tables.

Thanks a lot, Nick
and we said...
That information is not recorded anywhere by default.

In Oracle8i, release 8.1.5 and up, you can use a database event trigger on the
CREATE event to capture this yourself,

In any release (including 8.0.5 as you have) -- you could enable AUDITING at the
database level to capture this information as well.
Review & Followup
Rating: 3
May 03, 2001
Reviewer: A reader

May 02, 2001 OP -- Thanks for the question regarding "Question Regarding HASH JOIN !", version 8.1.6.0
You Asked
Hi Tom,

I have read in the book that whenever we are dealing with
a small table for Eg DEPT and a large Table EMP ,then
to improve the pewrformance HASH join can be implemented,
where the small table can be kept in memory and can be
used in the Join with the large table (EMP in this case).

Q1) Can you please tell me the syntax to apply HASH JOIN.

Q2) Is there any THUMP RULE that the HASH JOIN should be
applied to tables with some specific number of Records.

Thanks and Regards
OP Lalwani
and we said...
There is no "syntax" -- the optimizer does this for you.  You can use a HINT
(see the designing and tuning for performance guide for all of the hints) to
make the optimizer "want" to use a hash join if you like but in general, if you
use the CBO and analyze your tables -- it'll do it for you.  That is how to
apply a hash join (you don't, the optimizer does)

There are no rules of thumb - the optimizer will look at many things, table
size, estimated cardinality, existing indexes, optimizer goal, hash area size,
etc, etc, etc to determine when and if a hash join is appropriate.
May 02, 2001 -- Thanks for the question regarding "parsing of sql statements -- oo4o", version 8.1.7
You Asked
Hi Tom,

I am using oo4o (Oracle Objects for OLE) 8.1.7 version against Oracle 8.1.7 EE
on Solaris. I found that though I am using bind variables, the statement is
getting parsed and executed every time. I also found, that sometimes the
statement is issued twice to Oracle by oo4o dynaset, one the statement I wrote
and the other oo4o is appending rowid (internalrowid) column to the select
statement. If I refresh the Dynaset, oo4o is using the second statement. I also
found that SQL statements in stored procedures/packages executed as part of
Oracle Jobs are parsed again and again though the stored program units are
pinned in SGA. My DBA wants the parse to execution ratio down to atleast 0.5. I
gladly appreciate your help me in resolving this issue.

Thanks.

Sudhakar.
and we said...
The use of bind variables does NOT mean that you won't be parsing -- it only
means that instead of doing a HARD parse, we will do a SOFT parse.

In order to achieve a low parse/execute ratio, your programs must reuse the same
statement over and over and over and over again.  If your program executes a sql
statment ONCE per program -- your parse/execute will be 1 and there will be NO
way to decrease that (you have to parse AT LEAST once and if you execut it once
-- there you go, 1:1).

I am not an OO4O programmer (never touched it myself).  I asked around though
and found:

The AskTom reader is correct, in that prior to performing an
actual update of data (in OO4O language, this would be Dynaset.Edit
and Dynaset.Update), a SELECT is issued, getting back the actual
rowid itself.  And then actually prior to issuing the update itself,
a SELECT FOR UPDATE is performed and then the UPDATE.

But this user is incorrect about the parsing.  I properly used
OraParameters as my bind variables, and you can see that in the
attached trace.  This user must be seeing soft parses.

If the user wishes to trace this at all, they can include the
following statements to generate a trace:

    OraDatabase.ExecuteSQL("ALTER SESSION SET SQL_TRACE=TRUE")
    OraDatabase.ExecuteSQL("ALTER SESSION SET TIMED_STATISTICS=TRUE")

and when complete, issue:

    OraDatabase.ExecuteSQL("ALTER SESSION SET SQL_TRACE=FALSE")
    OraDatabase.ExecuteSQL("ALTER SESSION SET TIMED_STATISTICS=FALSE")

They should use the Refresh method on their objects whenever possible:

Forces an immediate update of the dynaset by re-executing the SQL statement in
the SQL statement object.

Usage

oradynaset.Refresh
oradynaset.DbRefresh
orasqlstmt.Refresh
orasqlstmt.DbRefresh

Remarks

This method cancels all edit operations (Edit and AddNew), executes the current
contents of the SQL statement buffer, and moves to the first row of the
resulting dynaset. Any dynaset objects created before issuing the Refresh
method, including bookmarks, record counts, and field collections, are
considered invalid. The OraConnection and OraSession objects associated with the
previous dynaset remain unchanged.

Performing a refresh operation with this method can be more efficient than
refreshing with a data control. This method also lets you execute a modified SQL
statement without creating a new dynaset or sqlstmt object.

Using oradynaset.Refresh or orasqlstmt.Refresh is the preferred refresh method
when changing parameter values, because required database operations are
minimized (SQL parsing, binding, etc.). This can improve performance when only
parameter values have changed.

Here is a full example demonstrating how to avoid the parse with every execute:

Sub EmpData()

'Declare variables as objects
Dim OraSession As Object
Dim OraDatabase As Object
Dim EmpDynaset As Object

Dim flds() As Object
Dim fldcount As Integer

 Set OraSession = CreateObject("OracleInProcServer.XOraSession")
 Set OraDatabase = OraSession.OpenDatabase("ORCL", "scott/tiger", 0&)
 OraDatabase.ExecuteSQL ("ALTER SESSION SET SQL_TRACE=TRUE")
 OraDatabase.ExecuteSQL ("ALTER SESSION SET TIMED_STATISTICS=TRUE")
 OraDatabase.Parameters.Add "EMPNO", 7800, 1

 Set EmpDynaset = OraDatabase.CreateDynaset("select empno, ename, comm from emp
where empno > :EMPNO", 0&)
 EmpDynaset.Refresh
 EmpDynaset.Refresh
 EmpDynaset.Refresh
 EmpDynaset.Refresh
 EmpDynaset.Refresh
 EmpDynaset.Refresh
 EmpDynaset.Refresh

 Range("A1:H15").Select
 Selection.ClearContents

  'Declare and create an object for each column.
  'This will reduce objects references and speed
  'up your application.
 fldcount = EmpDynaset.Fields.Count
 ReDim flds(0 To fldcount - 1)
 For Colnum = 0 To fldcount - 1
  Set flds(Colnum) = EmpDynaset.Fields(Colnum)
 Next

 'Insert Column Headings
 For Colnum = 0 To EmpDynaset.Fields.Count - 1
  ActiveSheet.Cells(1, Colnum + 1) = flds(Colnum).Name
 Next

 'Display Data
 For Rownum = 2 To EmpDynaset.RecordCount + 1
  For Colnum = 0 To fldcount - 1
   ActiveSheet.Cells(Rownum, Colnum + 1) = flds(Colnum).Value
  Next
  EmpDynaset.DbMoveNext
 Next

 OraSession.BeginTrans
 EmpDynaset.MoveFirst
 EmpDynaset.Edit
 EmpDynaset.Fields("COMM").Value = 999
 EmpDynaset.Update
 OraSession.CommitTrans

 OraDatabase.ExecuteSQL ("ALTER SESSION SET SQL_TRACE=FALSE")
 OraDatabase.ExecuteSQL ("ALTER SESSION SET TIMED_STATISTICS=FALSE")

Range("A1:A1").Select

End Sub

Sub ClearData()
 Range("A1:H15").Select
 Selection.ClearContents
 Range("A1:A1").Select
End Sub
May 02, 2001 M -- Thanks for the question regarding "How to Access OPS", version 8.1.7
You Asked
Hi there,

I have some questions related to the parallel server.

1. How to access the OPS connection? Based on the OPS document, OPS distributes
the client connections across the cluster, that is, directs the client request
to the least loaded node to process the database connection. How does this work?
Is there a MASTER node existing, so I need to specify this MASTER node to
connect to first, then the MASTER node direct to the least loaded node? For
example, if I use JDBC to connect to the server, I may use the code like:

  Connection conn =
DriverManager.getConnection("jdbc:oracle:thin@<host>:<port>:<sid>", "user",
"pass");

  Which node should I use as <host>:<port>:<sid> ?

2. As long as a user makes a connection to Node_A, does that mean this user
session always stay with Node_A and later on OPS won't reconnect to another less
loaded node unless the user disconnect and reconnect again?

3. Can we specify a particular node to connect to no matter if it is the least
loaded node?

4. Oracle tools such as Database Configuration Assistant, Enterprise Manager,
Recovery Manager and Universal Installer are installed on all nodes, OR just
installed on one node and which one?

5. In the document of Oracle8i Parallel Server(An Oracle Technical White Paper
Jan 20, 2000), the Example of Connection Load Balancing shows the Node A with
one dispatcher and Node B with 2 dispatchers. I don't quite understant what the
dispatcher mean. What is the
difference between one dispatcher and two dispatchers? Is it better to
configurate the node with more than one dispatcher? OR the more dispachers, the
better?

Thanks very much for any help.
and we said...
1) you can connect to ops in different ways. NONE of them look any different to
the client-- you just connect to a listener and it takes it from there.  One
option is to use load balancing as you described.  It is not the only way.   I
can use a connection directly to a specific instance.  I can use connect time
failover -- specifying that I would like to connect to instance 1 and if that is
not up, then instance 2 and so on.

You set this all up at the net8 layer. See
http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/toc.htm
for details on configuration.  The client will just connect "as normal"

2) if you are using load balancing, that is correct.  you connect for a session
-- your session will stay on that instance (you have a rather large state being
maintained)

3) you can either use load balancing, in which case the software will decide or
you can connect to a specific node -- it is up to you.

4) dbca -- all
   oem -- server/agent part all,
          middle tier -- one
   rman -- the rman utility on all, the recovery catalog -- one
   OUI -- none, one, all -- upto you.

5) dispatchers are used with MTS.  See the server concepts for a discussion of
that.  It is not a case of the more the better -- it depends on how you use the
system.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c07procs.htm#18572
for details on MTS
Review & Followup
Rating: 5
May 03, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

May 02, 2001 Randy -- Thanks for the question regarding "Acquiring OS blocks on a datafile extension (or new extent)", version 8.1.7
You Asked
In the event a datafile autoextends, what happens while it's acquiring the extra
space?  I'm trying to determine a NEXT size in the autoextend clause.  Will
transactions have to wait until the ENTIRE extension is finished or can it
resume while it's finishing the autoextension?  This would of course only be an
issue if the NEXT is large, maybe 100M.

Also, is the behavior similar when acquiring a new extent?

Thanks.
and we said...
You wait -- you need the space and you must wait.

Acquiring an extent in a LOCALLY MANAGED TABLESPACE with UNIFORM EXTENTS is a
trivial operation and happens so rapidly, you won't event notice.  That is the
only type of tablespace I use.

In a dictionary managed tablespace -- it can add overhead if you tend to grab
new extents lots.  It is a whole recursive sql operation.
May 02, 2001 Anand -- Thanks for the question regarding "Result Through Union All", version Oracle 8i
You Asked
Hi Tom

I have a table like this named VOUCHER
--------------------------------
ID  TYPE  DATE           AMOUNT
--------------------------------
01  EXP   01-APR-2000   1100.00
02  EXP   05-APR-2000   1200.00
03  EXP   15-APR-2000   1500.00
05  EXP   05-MAY-2000   9000.00
01  OTH   16-JUN-2000    110.00
02  OTH   25-JUL-2000    120.00
03  OTH   18-AUG-2000    150.00
04  OTH   23-SEP-2000    115.00

I need output like this.
-----------------------------------------------------------
ID  TYPE  DATE         AMOUNT  TYPE1  DATE1       AMOUNT1
-----------------------------------------------------------
01  EXP   01-APR-2000 1100.00  OTH    16-JUN-2000 110.00
02  EXP   05-APR-2000 1200.00  OTH    25-JUL-2000 120.00
03  EXP   15-APR-2000 1500.00  OTH    18-AUG-2000 150.00
04                             OTH    23-SEP-2000 115.00
05  EXP   05-MAY-2000 9000.00
-----------------------------------------------------------

I have written a SQL Statement :

select id,type,date,amount,type1,date1,amount1 from(
(select id,type,date,amount,to_char(null) as type1,to_date(null) as date1,0 as
amount1 from voucher where type='EXP')
union all
(select id,to_char(null) as type,to_date(null) as date,0 as amount,type as
type1,date as date1,amount as amount1 from voucher where type='OTH'));

But by this statement, I get two rows for a same ID. If I use GROUP function,
that also not gives me the required result.

Please help me for the required result.

Thanks

Anand
and we said...
ops$tkyte@ORA8I.WORLD> select id,
  2         max(decode(type,'EXP',type,null)) typ1,
  3         max(decode(type,'EXP',dt,null)) dt1,
  4         max(decode(type,'EXP',amt,null)) amt1,
  5         max(decode(type,'OTH',type,null)) typ2,
  6         max(decode(type,'OTH',dt,null)) dt2,
  7         max(decode(type,'OTH',amt,null)) amt2
  8    from t
  9   group by id
 10  /

ID TYP DT1             AMT1 TYP DT2             AMT2
-- --- --------- ---------- --- --------- ----------
01 EXP 01-APR-00       1100 OTH 16-JUN-00        110
02 EXP 05-APR-00       1200 OTH 25-JUL-00        120
03 EXP 15-APR-00       1500 OTH 18-AUG-00        150
04                          OTH 23-SEP-00        115
05 EXP 05-MAY-00       9000

does it..
May 03, 2001 Hassan -- Thanks for the question regarding "USING SUM FUNCTION WITH A BASIC SELECT STATEMENT WHILE CREATING TABLES/VIEWS", version Personal Oracle 8 and Developer 6.0
You Asked
    I am trying to create a view/table, which is fecthing records from five
different tables, and I need to calculate the sum of these fields in such a way
that two tables have more than one value to add and I'm using SUM function to
add their values. The SELECT statement looks something like that:

create table total_dues
as select
a.name,a.membership_no,(b.due+sum(c.due)+d.due+e.regn_cg_due+sum(f.surcharge_due)
)"Total Dues"
from member a,land_cost b, dev_charges c,fee d, regn e,surcharge f
where a.membership_no=b.membership_no
and
a.membership_no=c.membership_no
and
a.membership_no=d.membership_no
and
a.membership_no=e.membership_no
and
a.membership_no=f.membership_no
group by a.name,a.membership_no,b.due,d.due,e.regn_cg_due
/

The strange thing, which I have observed is that whenever SUM function is used
more than once in the SELECT statement (as in the present case), the result is
not correct i.e., the calculated sum of the fetched fields is always greater
than the actual amount and when I skip one SUM function from the statement, the
result is correct. This happens both in the case of creation of table and view.
Why is that? Is something wrong with the syntax?
        Another interesting thing is observed in the following simple SELECT
statements used on the Oracle supplied sample tables:
select sum(sal),sum(dept.deptno)
        from emp,dept
            where emp.deptno=dept.deptno
 In this particular case, the column sum(sal)gives the correct figure, while the
column sum(dept.deptno) alwas gives the sum of deptno from emp table, even when
I have used the dot notation to reference the dept table.
    Should I rely on the Report Builder to design a report, because in this
particular case we are calculating the sum of fields fetched from five different
tables. The summary column in Report Builder only sums the fields from one
individual table. Could you please guide me in the repect.
 The table looks like :
membership_no          installment_no     due     paid
22                         1               4000    2000
22                         2               6000     3000

Thanks
Hassan Ayub
and we said...
You have a misunderstanding of how joins and group by work -- a report generator
won't help you here.  The database is giving you the dead on right answer

Lets look at:

select sum(sal),sum(dept.deptno)
  from emp,dept
 where emp.deptno=dept.deptno
/

That returns:

scott@ORA806.WORLD> select sum(sal),sum(dept.deptno)
  2    from emp,dept
  3   where emp.deptno=dept.deptno
  4  /

  SUM(SAL) SUM(DEPT.DEPTNO)
---------- ----------------
     29025              310

what I think you were expecting based on the above "when I have two sums it
doesn't work" was:

scott@ORA806.WORLD> select sum(sal) from emp;

  SUM(SAL)
----------
     29025

scott@ORA806.WORLD> select sum(deptno) from dept;

SUM(DEPTNO)
-----------
        100

You have to understand that AGGREGATES are applied last, after everything
else (but before a sort).  So, your query is really the same as:

scott@ORA806.WORLD> select sum(sal),sum(deptno)
  2    from ( select emp.sal, dept.deptno
  3             from emp,dept
  4            where emp.deptno=dept.deptno )
  5  /

  SUM(SAL) SUM(DEPTNO)
---------- -----------
     29025         310

which, once you see the results of that inner query:

scott@ORA806.WORLD> select emp.sal, dept.deptno
  2    from emp,dept
  3   where emp.deptno=dept.deptno
  4  /

       SAL     DEPTNO
---------- ----------
      2450         10
      5000         10
      1300         10
       800         20
      1100         20
      3000         20
      3000         20
      2975         20
      1600         30
      2850         30
      1250         30
       950         30
      1500         30
      1250         30

14 rows selected.

Might make more sense -- it sums up the DEPTNO after joining to emp.  So
each deptno record is "multiplied" by the number of EMP records it was joined
to.

Now, in your case, given the query:

create table total_dues
as select a.name,a.membership_no,
        (b.due+sum(c.due)+d.due+e.regn_cg_due+sum(f.surcharge_due))"Total Dues"
from member a,land_cost b, dev_charges c,fee d, regn e,surcharge f
where a.membership_no=b.membership_no
  and a.membership_no=c.membership_no
  and a.membership_no=d.membership_no
  and a.membership_no=e.membership_no
  and a.membership_no=f.membership_no
group by a.name,a.membership_no,b.due,d.due,e.regn_cg_due
/

I'm guessing the A, B, D, E have a one to one relationship (for each record in
A, there is ONE in b, one in D and one in E).

A has a one to many with C
A has a one to many with F

What happens when you query both C and F with A is that if for a given A record
there were 2 C records and 3 F records -- you would end up with 6 records after
the jion (each C record is joined to EACH of the F records -- this is a
cartesian product and is what happens in the abscence of other join conditions).

So, how can we fix it?  One is to use an inline view and make it so that A and F
have a one to one and A to C is one to one, for example:

create table total_dues
as select a.name,a.membership_no,
        (b.due+c.due+d.due+e.regn_cg_due+f.surcharge_due)"Total Dues"
from member a,land_cost b,
     (select sum(due) due, membership_no
        from dev_charges
       group by membership_no ) c,
     fee d, regn e,
     (select sum(surcharge_due) surcharge_due, membership_no
        from surcharge
       group by membership_no ) f
where a.membership_no=b.membership_no
  and a.membership_no=c.membership_no
  and a.membership_no=d.membership_no
  and a.membership_no=e.membership_no
  and a.membership_no=f.membership_no
/

That'll aggregate the DUE and SURCHARGE_DUE independently by membership_no and
then join -- which is what I believe you are after..
Review & Followup
Rating: 4
May 04, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

Rating: 5
USING SUM FUNCTION May 04, 2001
Reviewer: Hassan Ayub from Islamabad, PAKISTAN
Thanks a lot Tom. As usual your response was excellent and to the point and I
realized my overlooking of the problem. I tested the script and gives me the
right answer. I want to add some additional code to the exsiting script like in
the previous script I was adding up all the dues for a particular person in one
column, now in the same table I want to add another column which will be adding
all the paid amount for the employess. Do i have to use the same nested SELECT
statement separately for the paid columns, cause I did that but couple of errors
arise..do I need to change the script or what?

Thanks a lot

Hassan
hassan_ayub@yahoo.com

May 03, 2001 Ranjan -- Thanks for the question regarding "Passing BULK BINd Variable to a query in a procedure", version 8.1.6
You Asked
Hi Tom,

I have a Table

TEST

(ID        number,
Type_val number,
Group_id number,
Creation_date    date)

I will pass a pl/sql table of numbers (This pl/sql table might contain 1000
numbers which are corresponds to the Group_id of TEST
Table)
and want to retrieve the following

A> Total no of records group by ID,Type_val where group_id in (set of numbers in
the PL/SQL table)

B> Get a Single Record having lowest creation date where group_id in (set of
numbers in the PL/SQL table)

TEST may contains millions of records and will be accessed by 1000 users
simultaneously. Also this involve other concurrent DML
operations like INSERT/DELETE apart from the above SELECT operation.

SELECT operation should have a high degree of performance.

I can have the traditional approach like opening the pl/sql input table and
going through each entry and issuing a select statement
against TEST to retrieve the data. But in this case this will kill the
performance. So is there any other alternatives (e.g passing the
whole pl/sql table and getting the result set in one shot).

Thanks.

Ranjan
and we said...
do not use a PLSQL table -- use a SQL Nested Table and you can select from it:

tkyte@TKYTE816> create type myTableType as table of number
  2  /

Type created.

tkyte@TKYTE816>
tkyte@TKYTE816> create or replace procedure p( p_tbl in myTabletype )
  2  as
  3  begin
  4          for x in ( select count(*) cnt from all_users where user_id in
  5                        (select * from TABLE( cast(p_tbl as myTabletype) )) )
  6          loop
  7                  dbms_output.put_line( x.cnt );
  8          end loop;
  9  end;
 10  /

Procedure created.

tkyte@TKYTE816>
tkyte@TKYTE816> exec p( myTableType( 0, 5, 16, 24, 25, 26, 27, 30, 36, 37, 38,
39 ) );
12

PL/SQL procedure successfully completed.
May 03, 2001 John -- Thanks for the question regarding "cross - session pl/sql tables", version 6.0
You Asked
Hi,

Nice site.

 We have 1000+ forms with a menu structure of 500+ .
We need to track form calls and other misc data across
Open_Form(??,activate, session) calls.

Is there a way to pass a pl/sql table between sessions?
Something we're not thinking of?

Any help will be greatly appreciated.
and we said...
You would use a real database table for this.  PLSQL tables, like data
structures in any language, are private to a session -- a session sees its data
and no one elses.

You just need to use a "real" table.
May 03, 2001 Murali -- Thanks for the question regarding "Shared memory and SGA", version 8.1.6
You Asked
Hi Tom

I am using oracle versions starting from 8 to 8i on Sun Solaris 2.6, 2.7 and 2.8

1. The first question I would like to ask is regarding SGA and shared memory

    When should I relocate SGA…and why..?

After changing the shared memory parameters/ semaphores in Unix Kernel..?

2. In Solaris how will I lock SGA in memory?

Please help

Thanks & Best Regards

Murali
and we said...
1) only when the SGA exceeds a size that prohibits it from existing where it
normally wants to reside.  (eg: rarely, and only when you must - if it starts up
as it is, you do not need to)

2) lock_sga = true in the init.ora
May 03, 2001 Joni -- Thanks for the question regarding "Oracle Training Administrator Module", version 11i
You Asked
We are an Oracle Educational Reseller - We have a client inquiring about the
Oracle Training Administration Module.  What is it and how does it relate to the
Oracle Family?
and we said...
It is part of Oracle HR
http://www.oracle.com/appsnet/products/hr/collateral/ds_train.html
for more info.

If you goto
http://www.oracle.com/
and search for

Training Administration

you'll get lots of hits.
May 04, 2001 Greg -- Thanks for the question regarding "Arithmetic on DATE fields - how to add / subract minutes.", version 8.1.6 SE
You Asked
Tom,

I had a user come to me recently and ask for an ad hoc report that details
transactions open for a certain duration.  When contructing the SQL, I realised
that I did not know how to tell Oracle to add a certain number of minutes to the
Start_Time field.

I ended up dividing 1 (day) by 24, then by 60, to get the value of a minute.
Then I multiplied that value by the number of minutes that I wanted, so that my
code eventually looked like...

SELECT ...
  FROM ...
 WHERE ((ticket.end_time >= ticket.start_time + 0.005555)
   AND  (ticket.end_time <= ticket.start_time + 0.010416))

...to cover transactions open between 8 and 15 minutes.

It worked, but I'm sure you'll agree that it wasn't the most elegant of
solutions.

How would you have coded this statement?

Where in the Oracle documentation library can I look for tips on how to work
with DATE fields?
and we said...
Think of a date just like a number -- what you did is perfectly valid.  I would
have coded:

select
  from
 where ticket_end_time between ticket.start_time+8/24/60
                           and ticket.start_time+15/24/60;

it is more readable and just the same as far as speed goes.

See
http://osi.oracle.com/~tkyte/Misc/DateDiff.html
but once you just start to think of a date as a number -- it is easy from there.
 add 1 to get tomorrow, 1/24 to add an hour, 1/24/60 to add a minute, 1/24/60/60
to add a second.
Review & Followup
Rating: 5
May 05, 2001
Reviewer: riaz

May 04, 2001 -- Thanks for the question regarding "Raw filesystems and DBA overheads", version 8.1.7
You Asked
What are the downsides in using raw filesystems (on Solaris) to host database
files in terms of
DBA admin. overheads  ?
What do we need to know as DBAs  on raw filesystems ?
Can we just treat it as cooked file systems (e.g. copy, move, tar , un/compress,
vi)?

Can datafiles be RESIZEd ?
Can datafiles be RENAMEd using ALTER ?

thanks.
and we said...
there are no DBA admin overheads that I am aware of.  If they can deal with raw
and have an understanding of it that is.  If they don't the overhead is
enourmous.

Everything about raw file systems, how to manage partitions and deal with them.
It is not hard, just something you need to know about.

Raw is raw, you do not have "files" on them.  hence there is nothing to copy,
move, tar, compress or vi.  they are raw disks -- just bytes of data, no files
whatsoever.

You create partitions of Xbytes in size.  You give that to oracle.  If you want
that to be bigger (or smaller) you have to repartition the disk which usually
involves destroying the existing data so.... resizing on raw is not really
feasible (although you can give Oracle a 5gig raw partition and tell us it is
only 1gig and we can autoextent out to 5gig on it but it is self defeating --
nothing else can use that 4gig or anything).

Yes, datafiles (raw or otherwise) can be renamed via the alter database command.
May 04, 2001 Casey -- Thanks for the question regarding "System 'ALL_' tables not workingas expected", version 8.1.7.0.0.
You Asked
I recently have found that I'm not seeing information in system tables that I
expected.  Below is a step-by-step example (hope it's not too confusing):

As always, thanks in advance!

===================================

User_X has as privileges: CREATE ANY SYNONYM and DROP ANY SYNONYM (among others)

--Table is created
User_X>create table FOO (bar number);

Table created.

--Grants are made
User_X>grant all on FOO to User_Y;

Grant succeeded.

-- Synonym for User_Y is created
User_X>create the synonym for user_Y for foo;
create synonym User_Y.FOO for foo;

Synonym created.

== As User_Y, I can see now see FOO
User_Y>desc FOO
 Name                                      Null?    Type
 ----------------------------------------- -------- ---------
 BAR                                                NUMBER

-- As User_X, I can see the created synonym in ALL_SYNONYMS but _not_ in
ALL_OBJECTS (I would have thought FOO synonym would be there)

User_X>select * From all_objects
  2  where object_name = 'FOO'
  3  and object_type = 'SYNONYM'
  4  /

no rows selected

User_X>select * from all_synonyms
  2  where synonym_name = 'FOO'
  3  and owner = 'USER_Y'
  4  /

OWNER                          SYNONYM_NAME
------------------------------ ----------------------
TABLE_OWNER                    TABLE_NAME
------------------------------ ----------------------
DB_LINK
-----------------------------------------------------
USER_Y                         FOO
USER_X                         FOO

-- As User_X, I drop table FOO and look at ALL_SYNONYMS - I do not find the
synonym FOO
User_X>drop table FOO
  2  /

Table dropped.

User_X>select * from all_synonyms
  2   where synonym_name = 'FOO'
  3   and owner = 'USER_Y'
  4  /

no rows selected

== As User_Y, I look in ALL_SYNONYMS for FOO (after I have dropped FOO as UserX)
User_Y>select * from all_synonyms
  2  where synonym_name = 'FOO'
  3  and owner = 'USER_Y'
  4  /

OWNER                          SYNONYM_NAME
------------------------------ ---------------
TABLE_OWNER                    TABLE_NAME
------------------------------ ---------------
DB_LINK
----------------------------------------------
USER_Y                         FOO
USER_X                         FOO

-- As User_X, I now drop the synonym FOO
User_X>drop synonym User_Y.FOO;
Synonym dropped.

== Back as User_Y, I no longer can find synonym FOO
User_Y>select * from all_synonyms
  2  where synonym_name = 'FOO'
  3  and owner = 'USER_Y';

no rows selected

=========================================

Why does synonym FOO not show up in queries against ALL_OBJECTS?
Why does dropping table FOO remove entry from ALL_SYNONYMS for User_X?

Thanks again!
and we said...
in sqlplus if you:

SQL> set long 50000
SQL> select text from all_views where view_name = 'ALL_OBJECTS';

you'll find the defintion for this view.  In there, you'll see:

....
 o.owner# in (userenv('SCHEMAID'), 1 /* PUBLIC */)
....

we can see anything we own and anything granted to public

....

    or
    (
       o.type# in (1, 2, 4, 5, 19, 20) /* index, table, view, synonym */
       and
       exists (select null from v$enabledprivs
               where priv_number in (-45 /* LOCK ANY TABLE */,
                                     -47 /* SELECT ANY TABLE */,
                                     -48 /* INSERT ANY TABLE */,
                                     -49 /* UPDATE ANY TABLE */,
                                     -50 /* DELETE ANY TABLE */)
               )
    )
........

and we can see indexes/tables/views/synonyms if we have one of those privs.  Now
the view all_synonyms, since it deals ONLY with synonyms, is a little more
sophisticated, it has

  and (
       o.owner# in (USERENV('SCHEMAID'), 1 /* PUBLIC */)  /* user's private, any
 public */
       or /* user has any privs on base object */
        exists
        (select null from sys.objauth$ ba, sys.obj$ bo, sys.user$ bu
         where bu.name = s.owner
           and bo.name = s.name
           and bu.user# = bo.owner#
           and ba.obj# = bo.obj#
           and ba.grantee# in (select kzsrorol from x$kzsro))
        or /* user has system privileges */
         exists (select null from v$enabledprivs
                 where priv_number in (-45 /* LOCK ANY TABLE */,
                                       -47 /* SELECT ANY TABLE */,
                                       -48 /* INSERT ANY TABLE */,
                                       -49 /* UPDATE ANY TABLE */,
                                       -50 /* DELETE ANY TABLE */)
                 )
       )

so it checks to see if you can "see" the thing the synonym points to or if you
have the other privs.

I refer to ALL_OBJECTS as "ALMOST_ALL_OBJECTS" sometimes as there are special
cases like this where they do not show up.

This also explains why it drops out of all_synonyms when you drop the table. You
do not have the ANY TABLE privs and the table is no longer there so the where
exists fails as well -- you cannot see the synonym.

That *technically* explains why you see what you see -- it was programmed that
way.
Review & Followup
Rating: 4
May 07, 2001
Reviewer: A reader
Great look into area of 'ALL_*' tables.  I knew the basic 'ALL_* shows anything
you own or is public', but how this is resolved was very interesting.

May 04, 2001 Rizwan -- Thanks for the question regarding "Stored Procedure as Data Source", version 8
You Asked
Hi

Please help me in passing arguments in stored procedure as data source.

Rizwan
and we said...
Simply create a procedure that takes arguments and after you build a block on
that stored procedure goto the properties for that block and setup the property:

Query data source arguments

here will be a list of all of the possible parameters to this procedure -- you
can then bind a block item to each input)
May 04, 2001 Masilamani -- Thanks for the question regarding "To open the text file from Database Server from forms 6i", version 8.1.6
You Asked
Hai Tom,
        We have oracle 8.1.6 database , the database sit in unix server,In the
database server we have one folder /interface/data ,
that contains lot of text file , i wants to open that file from
form 6i , i can see the file sit in the local drive(client)  using the HOST
command , But i wants to see the files from database server. Advance thanks for
u to the valuable solution.

  1. File on the server

Thanks
With Regards
Selva
and we said...
You will use UTL_FILE to do this.

Your DBA will set up the utl_file_dir init.ora parameter to allow you to access
the /interface/data directory.  You can then write a stored procedure or call
utl_file directly from forms.  UTL_FILE is much like TEXT_IO only it operates on
the server.

see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/utl_file.htm#998101
for details.
Review & Followup
Rating: 3
To open the database file from server May 08, 2001
Reviewer: Selva

May 04, 2001 Keith -- Thanks for the question regarding "DB & Instance", version 8.1.6
You Asked
What is the different between a DB & instance ?
Should I create one more DB or an instance on a unix box for Testing env. ?
How can I switch to another DB on same machine (By SID ??)

Thanks
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:533422350794
for testing, you will create both a new database and instance.

You can switch between them either by:

o using sqlnet so you login with scott/tiger@DATABASENAME

o changing your oracle_sid environment variable.
May 06, 2001 John -- Thanks for the question regarding "I/O Bandwidth, Rollback segment's available space.", version 8.1.5
You Asked
Hi,

  1. How do I find the available [ empty space] space in all
     rollback segments?

  2. What is I/O Bandwidth ?

Thanks in advance.

John.
and we said...
I can tell you how to find out how much of the ALLOCATED rollback segment space
is in use -- you can substract that from how much rollback you have allocated:

ops$tkyte@ORA8I.WORLD> select segment_name, used, blocks
  2  from dba_segments,
  3       ( select b.name, sum(a.used_ublk) used
  4           from v$transaction a, v$rollname b
  5          where a.xidusn = b.usn
  6          group by b.name ) v
  7   where v.name(+) = dba_segments.segment_name
  8     and dba_segments.owner = 'SYS'
  9     and dba_segments.segment_type = 'ROLLBACK'
 10  /

SEGMENT_NAME                         USED     BLOCKS
------------------------------ ---------- ----------
RBS_01                                          3200
RBS_02                                          3200
RBS_03                                          3200
RBS_04                                          3200
RBS_05                                  3       3200
RBS_06                                          3200
....

that shows that RBS_05 is using 3 of its blocks (out of 3200 allocated)
currently.  When that transaction commits -- those three blocks will "go away".

I/O bandwidth is a measure of the speed with which you can get data from disk
into memory.  Like network bandwidth only for disks.
Review & Followup
Rating: 4
May 06, 2001
Reviewer: Harrison from HockeyTown, VA USA

May 06, 2001 parker -- Thanks for the question regarding "database cloning, standby database, replicated database", version 8.1.7
You Asked
Hi Tom

I want to know the different between  a cloned database, a standby database and
a replicated database.

Kindly , give the specifics of each kind of database mentioned above.

I also want to know the degree of importance of each one of them in the real
time world.

Further...

How would you define a small, medium and large database..

if terms of tables, in terms of recovery time

Thank you

Parker
and we said...
cloned database -- a point in time copy of one database to another location.  I
might backup my production database and restore it onto my test machine (clone
it onto my test machine).

standby database -- a warm failover.  There in case the primary database gets
blown up or burnt down.  It is a hot spare.

replicated database -- two databases keeping eachother in sync constantly (but
asynchronously).

they are all relevant in their own space.  cloning is great for making a copy to
test with or demo with.  standby is great for failover.  replication is not a
failover, it is more of a availability (want fast access over the lan to local
data, not remote data) thing.  They serve different purposes.

Sorry - but i won't even touch that last one ;)  It totally depends on the
hardware, the people, the application.  The number of tables isn't relevant --
the amount of disk is.  What is small to me might be large to someone else.  I
hate rules of thumb like that (they'll be obsolete next year anyway)....
Review & Followup
Rating: 3
The answer too short but useful May 13, 2001
Reviewer: Mr. Z
If you can describe the answer more detail ,this answer more than useful

Rating: 5
Excellent December 09, 2002
Reviewer: Sikandar Hayat Awan from Pindi Bhattian - Pakistan
It is not a short answer as it is covering all aspects.

May 06, 2001 parker -- Thanks for the question regarding "9ias question", version 9ias
You Asked
Hi Tom

I have recently done migration from oas4 to 9ias 1.0.2.0.
Everything is fine except the custom authentication.

Previously, under oas4 the access to our website was set up through custom
authentication. I have recently taken over the maintainance of our web site, and
did the migration to 9ias.

Can you tell me how is custon authentication set up in 9ias.

parker
and we said...
Here is a support note on this

Article-ID:         <Note:132780.1>
Circulation:        ARCHIVED (EXTERNAL)
Folder:             internet.Applicationserver.HTTPserver
Topic:              PL/SQL gateway (mod_plsql)
Title:              Differences in custom authentication between modplsql and
                    OAS PL/SQL cartridge
Document-Type:      BULLETIN
Impact:             MEDIUM
Skill-Level:        CASUAL
Updated-Date:       23-APR-2001 07:41:46
References:
Attachments:        NONE
Content-Type:       TEXT/PLAIN
Keywords:           CUSTOM; MODPLSQL; OAS; OWA_SEC; PER_PACKAGE; AUTHENTICATION;

Products:           1042/LISTENER;  96/APACHEGW;
Platforms:          GENERIC;

*************************************************************
This article is being delivered in Draft form and may contain
errors.  Please use the MetaLink "Feedback" button to advise
Oracle of any issues related to this article.
*************************************************************

PURPOSE
-------

Explain some differences between custom authentication in OAS
PL/SQL cartridge and in modplsql.

SCOPE & APPLICATION
-------------------

This Note is intended for people who migrate PLSQL based web
applications that make use of custom authentication from OAS to
9iAS.

QUICK OVERVIEW
--------------

Custom authentication is a mechanism to programmatically control which
users are allowed to access a PL/SQL web application. The PL/SQL web
gateway (either OAS PL/SQL cartridge or mod_plsql) calls a boolean
function prior to executing the real procedure and will execute the real
procedure only when the authorize function has returned TRUE.

Custom authentication is also needed to make owa_sec functions work,
because these functions will always return NULL values otherwise.

DECLARATION OF CUSTOM AUTHENTICATION
------------------------------------

In OAS You need to change owa_custom's package body to enable custom
authentication. You will replace the line

    owa_sec.set_authorization(OWA_SEC.NO_CHECK);

with one of

    owa_sec.set_authorization(OWA_SEC.GLOBAL);
    owa_sec.set_authorization(OWA_SEC.CUSTOM);
    owa_sec.set_authorization(OWA_SEC.PER_PACKAGE);

In IAS 1.0.0 and 1.0.1 You basically do this the same way, but because
of some hardcoded schema and procedure names in mod_plsql You have to
fiddle with this a little. Better upgrade to 9iAS 1.0.2.

9iAS 1.0.2 does not use the same way to declare custom authorization. You
do not have to change owa_custom's package body any more; actually this will
have no effect. Instead You change your DAD's "Authentication Mode" to
"Global OWA", "Custom OWA" or "Per Package", and mod_plsql will use the
corresponding custom authentication scheme for this DAD.

DUMMY AUTHORIZE FUNCTIONS
-------------------------

Dummy authorize functions look like this:

   function authorize return boolean is
   begin
      return TRUE;
   end authorize;

They just enable anybody to log in without specifying username and password.
They may be needed to enable owa_sec functions, as indicated above, or to
allow access to specific public packages when using per-package authentication.

These authorize functions work in OAS, but do not work in 9iAS 1.0.2. When
such a function is used this error message will be printed to the HTML page:

  Custom Authentication Failure. [testauth.authorize] oerr = 1405
  ORA-01405: fetched column value is NULL

To make the authorize function work again in mod_plsql change it to look like
this:

   function authorize return boolean is
   begin
      owa_sec.set_protection_realm ('Dummy Realm');
      return TRUE;
   end authorize;

This means that You must specify a realm name in Your authorize functions
for mod_plsql while You didn't have to when using OAS.

At the time of writing this bulletin it is not clear whether the realm
will also have to be set in future 9iAS versions or whether this behaviour
is specific to version 1.0.2.
May 06, 2001 ken -- Thanks for the question regarding "How to access .DBF files using 'shared' Win/NT network drives", version 8.1.6.0.0
You Asked
Q: How to access .DBF files using 'shared' Win/NT network drives ?...

What steps do I need to take to have Oracle recognize and use
.DBF files located on a separate Win/NT network drive?

 I'd like to run an instance on \\KEN with the datafiles on a Win/nt
networked CompaqProliant box called \\RAND .

The background:
I have two Win/NT Server's in my network connected via a switched
router. TCP/IP is the protocol for both machines. A Trusted Relationship
exists between both machine domains. Each machine is a NT Server Primary
Domain Controller.

'\\RAND is the Compac Proliant1500 server where I'd like store and
access my oracle database files eg:System01.dbf,Control01.ctl,..User
data files...   on it's multiple fast separate drives.

'\\Ken' is the Toshiba PP200 server where the OracleServiceTEST, ie: the
oracle executables eg:installation software(oracle.exe..)
are located.

Yes I can bring up a 'normal' system from \KEN where all database files
are installed onto one drive. I dont have multiple drives on \Ken.

I'd like to run an instance on \\KEN with the datafiles on \\RAND.

Drive 'F:' is a network drive from \\RAND.

After a startup mount. I used the OS to copy a .dbf from \\KEN to
\\RAND. I verfied the new file on \RAND - file shows was created by
\\KEN administrator properly.

====================================================================
Here is the output:

SQL> alter database rename file 'D:oracle\oradata\oem_rep.dbf' to
'F:\bkp\oem_rep.dbf'

alter database rename file 'D:oracle\oradata\oem_rep.dbf' to
'F:\bkp\oem_rep.dbf'
*
ERROR at line 1:
ORA-01511: error in renaming log/data files
ORA-01141: error renaming data file 8 - new file 'F:\bkp\oem_rep.dbf'
not found
ORA-01110: data file 8: 'D:ORACLE\ORADATA\OEM_REP.DBF'
ORA-27041: unable to open file
OSD-04002: unable to open file
O/S-Error: (OS 5) Access is denied.
====================================================================

What do I do now?

Ken60610@yahoo.com
and we said...
Seriously baaaaddddd idea.   Do not use network drives for datafiles -- We must
perform "safe" IO to disks (if you value your data even a tiny bit).  We must
get confirmation that the data did (or did not) make it to disk.  Not only will
this be dog slow on a network as compared to a local machine, it is unreliable.
Your "fast drives" will behave like the slowest disks in the world.

I can tell you how to make network drives available to Oracle but YOU SHOULD NOT
DO THIS.  it will fail at some point and is definitely not a support
configuration.

See chapter 6 of the Oracle8i admin guide for more warnings on this approach.
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:370418132791
talks more about this and has a link to a page that shows how to make the
network drive available to Oracle.
May 06, 2001 parker -- Thanks for the question regarding "How to set up custon authentication from scratch", version 9ias
You Asked
Tom

Thanks for the response on the 9ias question.

But , I want to know, as to what are the steps involved in setting up custom
authentication from scratch.

And

How do give my users the ability to sign off?

Do I have to install some new packages and make changes to them.

Parker
and we said...
this
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:596269493096
tells you how to set it up.  its a selection on the DAD setup page in 1.0.2.
Thats it -- you put the auth routines into the database then.

See
http://technet.oracle.com/docs/products/ias/doc_library/1021doc_otn/comm.102/a87562/toc.htm
and specifically:
http://technet.oracle.com/docs/products/ias/doc_library/1021doc_otn/comm.102/a87562/secure.htm#1015917
for details.


Subject | Article | Last Updated (East coast time)
Adding Minutes toTime | article only | May 07, 2001 08:34 am
How do i implement page wise concept for complex queries using web | article only | May 07, 2001 09:00 am
statement reparsed for every execution in a Oracle Job | article only | May 07, 2001 09:02 am
Trees | article only | May 07, 2001 09:03 am
Reading binary data with the UTL_FILE package | article only | May 07, 2001 09:04 am
Generating Unique Sequence Number(Parent Table) in SQL Loader and Use the same value while inserting into Detail Table | article only | May 07, 2001 12:15 pm
Converting a non-partioned table to partitioned table. | article only | May 07, 2001 12:49 pm
BFILE Export/Import | article only | May 07, 2001 04:19 pm
MANAGING LOBS | article only | May 07, 2001 04:22 pm
DBMS_JOB | article only | May 07, 2001 04:32 pm
Drop & re-create a Table to avoid fragmentation ... | article only | May 07, 2001 04:36 pm
SQL*Plus cut-paste buffering for Windows | article only | May 07, 2001 05:19 pm
SAME SESSION ID USING ORACLE 8iAS | article only | May 07, 2001 05:57 pm
Deletion of the records from table which is having RI | article only | May 07, 2001 06:03 pm
HI TOM | article only | May 08, 2001 08:05 am
password file | article only | May 08, 2001 09:18 am
Oracle 8.1.6 support for Solaris 8 | article only | May 08, 2001 09:18 am
difference between exclusive lock and shared lock | article only | May 08, 2001 09:20 am
Indexes on Foreign Keys | article only | May 08, 2001 09:36 am
Messaging between Oracle Forms and Oracle Database | article only | May 08, 2001 05:46 pm
pl/sql | article only | May 08, 2001 06:01 pm
Is there way/hints to improve performance of Minus operator? | article only | May 09, 2001 09:12 am
Stored Procedures and Functions | article only | May 09, 2001 09:23 am
status bar | article only | May 09, 2001 09:28 am
alter table partition move | article only | May 09, 2001 02:09 pm
Table Locks | article only | May 09, 2001 02:46 pm
Label Security | article only | May 10, 2001 09:47 am
Scripts for installation | article only | May 10, 2001 09:51 am
Selective Delete. | article only | May 10, 2001 07:46 pm
unix for a dba | article only | May 12, 2001 11:48 am
basic backup and recovery scenarios | article only | May 12, 2001 11:50 am
listener.ora,config.ora,tnsnames.ora,sqlnet.ora | article only | May 12, 2001 11:59 am
restrict_references,order of tables in from clause and bulk copy 'forall' | article only | May 12, 2001 03:00 pm
Memory ipcs / tstshm out put | article only | May 12, 2001 03:23 pm
union and union all | article only | May 12, 2001 03:27 pm
Pimary key in Foxpro / Load Data from Foxpro tables | article only | May 12, 2001 04:25 pm
help with a query ! | article only | May 13, 2001 12:28 pm
enforcing refential integrity with a remote database | article only | May 13, 2001 01:09 pm
check option in views | article only | May 13, 2001 01:12 pm
users,roles,privileges | article only | May 13, 2001 01:17 pm
instead of triggers | article only | May 13, 2001 04:56 pm
forms item triggers | article only | May 13, 2001 05:02 pm
Question on UTLBSTAT and UTLESTAT ! | article only | May 13, 2001 11:35 pm
Database state | article only | May 13, 2001 11:36 pm
row(s) 1 - 44 of 44
May 07, 2001 Naren -- Thanks for the question regarding "Adding Minutes toTime", version 8i
You Asked
I am working on Attendance system and time is main factor for my system. The
problem is I want to check if person is late by not more than 45 minutes from
standard office time then he should not be marked as late. Now in such situation
I don't know how to find new time by adding 45 minutes to standard time.
and we said...
See
http://osi.oracle.com/~tkyte/Misc/DateDiff.html
basically -- you'll say:

  if ( (clock_in_time - supposed_to_be_in_time) > 45/24/60 )
  then
     they were more then 45 minutes late
  end if;

when you subtract two dates -- you get the difference in days.  1 is one day.
1/24 is one hour. 1/24/60 is one minute (hence 45/24/60 is 45 minutes)....
May 07, 2001 Shiva -- Thanks for the question regarding "How do i implement page wise concept for complex queries using web", version 8.1.5
You Asked
Please help me to build the page wise concept or limiting oracle rows for
complex queries using group by clauses and distinct clauses. I want to implement
this concept for web based applications.
thanks in advance for helping me out..
shiva
and we said...
Well, you have somewhat of a problem there.  Using group bys and distinct almost
always means that Oracle has to find the LAST row before it'll return the first
row to you.  These queries are expensive to execute to get the first row.  they
are not good "pagination in a stateless environment queries".

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:76812348057
for some methods.
May 07, 2001 -- Thanks for the question regarding "statement reparsed for every execution in a Oracle Job", version 8.1.7
You Asked
Hi Tom,

I have an Oracle Package Unit, which has a procedure, opening an cursor against
a table with a condition, looping through the cursor and call another procedure
accordingly. The Oracle Package Unit is running as a job for every second. The
package Unit will get executed with 200 to 400 milliseconds. The package is
pinned to the SGA. But I found to my surprise, that Oracle is reparsing the sql
statement for every execution of Job. I also found that the logon time in the
user sessions is changing for every session which is connected to the Oracle Job
Process. I appreciate if you let me know how to reduce the parse execution ratio
on SQL statements executed by Oracle Jobs.

Thanks.

Sudhakar.
and we said...
Cursors are reusable only in a session.  A job is a session.  It starts (gets a
session), runs and exits (closing the session).  All resources are freed.

The parses you see are SOFT parses (not hard).  They are not as expensive.  The
only way to avoid the soft parse is to keep the session around.  Consider doing
this:

begin
   loop
       your_procedure;
       dbms_lock.sleep(1);
   end loop;
end;
/

And just running that from startup to shutdown -- not via the job queue -- just
as a session you have running forever - like a daemon.  In that case, you have 1
session, the cursors will remain open and reusable forever.

Soft parses are normal, to be expected.  You would hope that in a given SESSION
you would parse only once -- but you have to expect that for every SESSION you
will parse AT LEAST once.  It is unavoidable.
May 07, 2001 Omar -- Thanks for the question regarding "Trees", version 6.0.8
You Asked
Hi Tom,
  I have the following situation.
  I have an account table
  (acc_no, acc_name, db_init_balance,...,acc_level)
sample data
acc_no                 acc_level
-------               ------------
1                          1
11                         2
111                        3
1111                       4
111100001                  5

acc_no 1 is the parent of acc_no 11 and the last is the parent of 111, and so
on.
  when populating the charts of accounts as a tree item I used this query.

 select 1, level,acc_name, null,to_char(acc_no)
 from account
 start with acc_level = 1
 connect by prior acc_no  = substr(acc_no,1,acc_level-1);

and I have 2500 record in the table, I noticed it is very slow, How could I
speed this query.

* another thing I need to know if you have any notices on designing this table.
which is better to design the accounts chart, in one table like the previous one
or use 5 different tables for the levels of the
accounts and make foreign keys between them

thanks very much in advance
and we said...
store the data as

ACC_NO PARENT_ACC_NO .....

so you have:

ACC_NO    PARENT_ACC_NO
1
11        1
111       11
1111      111
111100001 1111

then, you can

select *
 from account
 where with parent_acc_no is null
 connect by prior acc_no = parent_acc_no
/

and index parent_acc_no -- it'll be fast.

If you must persist with your current structure AND you have 8i enterprise
edition, you may be able to create an index on substr(acc_no,1,acc_level-1) in
order to speed this up as well.  See
http://osi.oracle.com/~tkyte/article1/index.html
for details on that approach.
May 07, 2001 Tamas -- Thanks for the question regarding "Reading binary data with the UTL_FILE package", version 8.1.6.
You Asked
Dear Tom,

I would like to read a binary data file with the UTL_FILE package. The out
parameter (called buffer) of the procedure GET_LINE is of vachar2 type. Does
this mean that I can not read binary data into a table through UTL_FILE?

Thank you for you help in advance.

Regards,

Tamas Szecsy
and we said...
You cannot read or write binary files with UTL_FILE.

You can use a BFILE and the DBMS_LOB packge to accomplish this.

create or replace directory my_files as '/export/home/tkyte/public_html';

declare
    l_bfile    bfile;
    l_buffer   raw(2000);
    l_vc_buffer varchar2(2000);
begin
    -- Next, we open the BFILE (binary file) we will load
    -- from.

    l_bfile := bfilename( 'MY_FILES', 'x.dat' );
    dbms_lob.fileopen( l_bfile );

    dbms_lob.read( l_bfile, 2000, 1, l_buffer );

    -- if it is really TEXT data you can convert it:
    l_vc_buffer := utl_raw.cast_to_varchar2(l_buffer);

    dbms_lob.fileclose( l_bfile );
end;
/
May 07, 2001 Karthikeyan -- Thanks for the question regarding "Generating Unique Sequence Number(Parent Table) in SQL Loader and Use the same value while inserting into Detail Table", version 8.0.6.1
You Asked
Control File

LOAD DATA
INFILE *
INTO TABLE T1 WHEN (1) = 'H'
(Seq_No      " ",
 Cust_id   Position(03:10) char,
 Header    Position(12:30)
INTO TABLE T2 WHEN (1) = 'D'
(Seq_No      " ",
 Cust_id   Position(03:10) char,
 Detail    Position(12:30)
BEGINDATA
H abc123   Feed Road Ma
D abc123   sdfdfsdfsdf
D abc123   dfgdfgdfdfdf
D abc123   dvliggjgjjgj
H fvf555   gdfgdfgdfgdf
D fvf555   opifjnffmnfi
D fvf555   dfgdflokdfklf
H xxx111   fkofkfkfkkfkkf
D xxx111   fllfllflflfll
H xyz999   jfihfihjnfijjf
D xyz999   dfgdfgfgdfgdfg
D xyz999   fdgdgf
D xyz999   dfgdgdgdfdf
D xyz999   fddgdg
D xyz999   osooskskklslsll

I like to generate a Sequence Number for the Column Seq_no while inserting into
T1 table
 and use the same sequence value for remaining Detail Records and so on.

After loading,Records should of this format(value)

Table T1
Seq_No       Customer_id           Header

 1            abc123               Feed Road Ma
 2            fvf555           gdfgdfgdfgdf
 3            xxx111               fkofkfkfkkfkkf
 4            xyz999               jfihfihjnfijjf

Table T2
Seq_No       Customer_id           Detail
 1            abc123               sdfdfsdfsdf
 1            abc123               dfgdfgdfdfdf
 1            abc123               dvliggjgjjgj
 2            fvf555               opifjnffmnfi
 2            fvf555               dfgdflokdfklf
 3            xxx111               fllfllflflfll
 4            xyz999               dfgdfgfgdfgdfg
 4            xyz999               fdgdgf
 4            xyz999               dfgdgdgdfdf
 4            xyz999               fddgdg
 4            xyz999               osooskskklslsll

Can u help me in this regard, having a control file to achieve this.

Note;
   Solution: 1;
    By using Normal Sequence object (Sequence_name.Nextval in Header and
Sequence_Name.Currval in Detail)
and Rows=1 I am able to achieve the result. Since i am Loading few thousand
records for every 5 minutes, i am
worried about the performance of the database, especially Rollback Segment
(Loading few thousand row and commiting for each row - is not a bon program)

There is no (Foreign Key) relationship between T1 and T2

regards
karthik
and we said...
using sqlldr -- you are doing it the only way I know how.

it'll generate extra redo, committing each row, but if you want to use sqlldr,
that'll be the way.  you could use UTL_FILE and PLSQL to process this data
easily as well.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:464420312302
for a simple example that demonstrates this concept.

follow up to comment

As I said - sqlldr won't be able to do this without rows=1.  I cannot make
things do what they cannot do. The solution would be either:

o leave it "as is".
o write it in plsql (my first choice).
o write it in C or Java...

follow up to comment #2

Sure -- PLSQL can do that -- even EASIER then delimited data.

  loop
      utl_file.get_line( f, buffer );
      f1 := rtrim(substr( buffer, 1, 20 ));
      f2 := rtrim(substr( buffer, 21, 25 ));
      ......

just substr the fields.....  rtrim if you do not want trailing blanks.
Review & Followup
Rating: 2
Sequence May 07, 2001
Reviewer: Karthik from Houston, TX USA
Response time is Quick, but i like to get any other alternative to this program

Rating: 3
PL/SQL May 08, 2001
Reviewer: Karthik from Houston,TX, USA
Just Confirmation, thanks.Pl/sql can be
used for delimited file. will it work for
fixed format file

Rating: 5
PL/SQL May 08, 2001
Reviewer: Karthik from Houston, TX, USA
Thanks a lot, I will try to implement it following your suggestion

May 07, 2001 Robert -- Thanks for the question regarding "Converting a non-partioned table to partitioned table.", version 8.0.4
You Asked
I want to convert a non-partitioned table into a partitioned table. I can do
this by re-creating the table and dumping the data back. But how can I find all
the constraints details that were in the original table, so that I can re-create
the table with all the constraints. I don't have the table creation scripts.
and we said...
this is what I would do:

exp userid=u/p tables=THAT_TABLE rows=n
imp userid=u/p full=y indexfile=THAT_TABLE.SQL

THAT_TABLE.SQL will have all of your ddl -- constraints and all.  Just modify
that and you'll be good to go.  In fact, you could:

exp userid=u/p tables=TABLE_TABLE rows=Y
imp userid=u/p full=y indexfile=THAT_TABLE.SQL
edit that_table.sql
drop that_table
run the modified that_table.sql (just the create table part)
imp userid=u/p full=y ignore=y

there you go.
Review & Followup
Rating: 5
May 07, 2001
Reviewer: A reader

May 07, 2001 Reji -- Thanks for the question regarding "BFILE Export/Import", version 8.1.7
You Asked
Tom:
    I have a DB with BFILES.  I want to export the bfile information
and import into another db.  Do I have to do any special steps here?

Thx
Reji
and we said...
Well, the DIRECTORY entries most likely won't be exported (unless you do a full
database export) since they are owned "globally" -- not by users.  You will most
likely have to create the directory entries on the other data.

Obviously, the files themselves will not travel with the export either -- it'll
be upto you to make them available on the other database somewhere.

Other then that -- it should go OK -- the bfile type stores the platform
indepedent directory name (from the create directory command) and the file name
(which should be fairly portable)
May 07, 2001 eli -- Thanks for the question regarding "MANAGING LOBS", version 8.1.7
You Asked
is there a utility in 8i that can get a jpg or a gif file from
the PC windows system and enter it to an Oracle 8i database
to a given BLOB column in a given table ?
and we said...
there are lots of ways to do it.

search for:

load lob

on my site and you'll find many ways.  there is dbms_lob.loadfromfile, sqlldr,
and of course any 3gl.
May 07, 2001 Venkat -- Thanks for the question regarding "DBMS_JOB", version 8.1.7
You Asked
Hi Tom,

I have a batch file ( exp.bat ) to export a user schema.

exp test/test file=c:/tmp/test_exp.dmp FULL=N OWNER=test COMPRESS=Y TRIGGERS=Y
GRANTS=Y INDEXES=Y ROWS=Y CONSTRAINTS=Y CONSISTENT=N log=c:/tmp/test_exp.log

Can I use dbms_job.submit and schedule exp.bat everyday 10 p.m?

Thanks,
Venkat
and we said...
Yes and no.

EXP is a command line program -- it runs at the prompt.  PLSQL is normally
capable of running database commands only.

If you set up a java stored procedure that can run host commands (see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:952229840241
for an example of this) or create a C external routine that can run this -- then
yes, you can schedule a job to run every night at 10pm.

Otherwise, you would be looking to use the NT "at" command if you are on windows
nt.
Review & Followup
Rating: 4
May 08, 2001
Reviewer: Venkat from USA
This is exactly what I was looking for.

May 07, 2001 Fernando -- Thanks for the question regarding "Drop & re-create a Table to avoid fragmentation ...", version 8.x
You Asked
Dear Tom,

I want to drop and re-create a table (whose number of extents is > 5)after
changing its storage parameters.

Do you have a script (or do you know a site that has created a script) that
creates the DDL for a table (that exists in the database), including all the
indexes, synonyms, foreign keys, primary key, etc.

Thanks ...
and we said...
why -- why -- why.

Maybe if you said "whose number of extents is greater then 5,000" i would be
with you on this one.

5 extents, 50 extents, 500 extents -- so what?  It is not a bad thing.

You are only wasting your time and resources by worrying about such a thing.  5
extents is *nothing*.

having objects in a single extent is no faster then 100 or 1000.

Look at how you access a table.  Hopefully, most of the accesses are indexed
reads.  In that case -- if you had an extent per block it would not matter -- we
read a block here -- a block there -- the extent doesn't come into play.

If you full scan it - as long as your extent size is a nice multiple of your
multi-block read count -- it won't matter anyway.  We'll read 64k, then another
64k, and so on.  In a multi-user system, the heads on your disk drive are going
to move between reads -- having things in a single "extent" won't make ANYTHING
faster.  Not that an extent is even contigous on disk -- disks get "fragmented"
-- the blocks in an extent might be miles apart from eachother.

Please, I urge you, forget about this.  It is not worth your time, energy or
computing resources.

and, sigh, if you persist as many people do for whatever reason, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:47812348053
the command you are looking for is simply "alter table T move tablespace X
storage (whatever)" and then "alter index iname rebuild".
Review & Followup
Rating: 4
May 08, 2001
Reviewer: shawish_sababa

Rating: 4
fragmentation May 08, 2001
Reviewer: andrew lapides from calgary, alberta, canada
I completely agree with this reply.
However there is one thing missing. By dropping and recreating the tables the
fragmenatation of tablespace does get created. The free space get fragmented.
After table was dropped the chunk of free memory is created. If the next table
uses different storage parameters, then it can't use this free chunk. To avoid
this make sure that INITIAL=NEXT for every table in the same tablespace (similar
to rollback and temporary tablespaces)

May 07, 2001 rob -- Thanks for the question regarding "SQL*Plus cut-paste buffering for Windows", version 8i
You Asked
Hi Tom,

I've noticed that there seems to be insufficient buffer for some cut-and-pastes
into a Windows 2000 client SQL*Plus session from an application such as NOTEPAD.
 The last time I encountered this, I
ftp'd the file to Unix to do a word count, and saw that the limit is somewhere
around 3620 bytes.

What happens is that the paste stops in mid-stream.  This is unaffected by
SQL*Plus environment settings like ARRAYSIZE and MAXDATA, but I know that
cut-and-pastes between other Windows apps can deal with much greater chunks than
this.

Are you familiar with this problem?

Thanks
~Rob S.
and we said...
seems the number is 3625.  it is an undocumented limit on the "gui" sqlplus.
been there since version 7.0

I personally use the "dos" mode sqlplus (gives you the UP arrow key!! to recall
commands as a bonus) myself.  It does not suffer from this (i've never quite
liked that gui version myself).
May 07, 2001 Alan -- Thanks for the question regarding "SAME SESSION ID USING ORACLE 8iAS", version 1.0
You Asked
  Hi Tom,

    We are developing a dynamic web site that is 100% generated by PL/SQL
packages using PL/SQL Web Toolkit and Oracle 8iAS 1.0 with
Oracle EE 8.1.6 as database server.
    But in our tests with the site we detected a problem. When I execute a login
on the site with the same database user on different hosts or on different
browser windows the Oracle generates only one database session for all users. So
the site don´t works fine because
Oracle is sharing the application data with all users. I don´t know why Oracle
is not creating a different session for each connection request because it is
using the same session id for each new connection request that I make. What´s
wrong ?

                                                   Thanks
                                                       Alan
and we said...
By default, the mod_plsql cartridge will cache sessions and reuse them over and
over.  If possible -- if you need a "sessionid" -- you should consider using
your own sequence:

create sequence my_session_id;

and assigning my_session_id.nextval INSTEAD OF userenv('sessionid').  This will
be much more scalable then getting a new session for each connection.

You can get a new session by telling mod_plsql to not cache the connections.  If
you look in

$ORACLE_HOME/Apache/modplsql/cfg/wdbsvr.app

You'll find entries like:

[DAD_flowspublic]
connect_string   =  cheese
password   =  public_user
username   =  public_user
default_page   =
document_table   = flows.wwv_flow_file_objects$
document_path   = docs
document_proc   =  flows.wwv_flow_file_mgr.process_download
upload_as_long_raw   =
upload_as_blob   =  *
name_prefix   =
always_describe   =
after_proc   =
before_proc   =
reuse   =  Yes
connmax   =  5
pathalias   =
pathaliasproc   =
enablesso   =  No
custom_auth   =

change reuse to No and it'll not reuse connections (but it'll run slower....)
May 07, 2001 Venku Reddy -- Thanks for the question regarding "Deletion of the records from table which is having RI", version 8.0.5
You Asked
I came across a weird situation because of an oversight. I am deleting records
from a parent table. Though the table has a referential constraint to a child
table, the child table doesn't have any rows at all for the rows I am trying to
delete. My oversight was that the child table didn't have an index on the
foreign key. Therefore, it is understandable that the deletion would take a
longer time than necessary forcing Oracle to check each row of the child table
using a full table scan. However, what is weird is that while this deletion is
going on, other process(es) are trying to insert rows into the parent & child
tables. What I am seeing in such a situation is that both the deletion AND the
inert processes are just waiting indefinitely! The v$lock shows a row exclusive
lock on both parent and child tables by the deletion process and all the insert
processes waiting for their release.

What I don't understand is that if Oracle has row level locking, why are
insertions waiting for locks? Surely, the inserted rows and the rows to be
deleted are entirely different (deletion is based on a date field). Also, why is
a row lock in the child table when there isn't a row at all to be deleted?

I've tested the deletion running it exclusively when no insertions are
happening. In such a case, the deletion takes about 3 minutes. Of course, once I
created the index on the foreign key, the deletion is done in sub-second. The
question is more academic since I always thought Oracle has true row level
locking.

Thanks in advance for your answer.

Venku
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:292016138754
a delete of a parent record, or an update to the primary key of the parent
record forces a FULL scan of the child and a table level lock on the child table
as well (we cannot LOCK what is NOT there - we need prevent the inserts into
child -- else they would still see the parent record. with an index, we can do
this much better).
May 08, 2001 BASHYAM -- Thanks for the question regarding "HI TOM", version 8.0.1.3
You Asked
HI TOM,

I HAVE TWO QUESTIONS, CAN U HELP ME.

1. HOW TO READ THE WINDOWS REGEDIT ENV VARIABLES FROM FORMS45 DEVELOPER,ie i
want CALL MICROSOFT EXCEL FROM FORMS,I WANT TO KNOW THE EXECUTABLE DIRCTORY, ie
IS IN SOME PC IT IS IN C OR D DRIVE AND PATH ALSO DIFFERENT.

2. IN MY TABLE I HAVE TWO FIELDS,ie
ARR_TIME FORMAT HH24:MI
DEP_TIME FORMAT HH24:MI
I WANT TO FIND THE RECORDS
NVL(DEP_TIME,ARR_TIME) BETWEEN '22:31' AND '07:30'(NEXT DAY MORNING)- NIGHT
SHIFT.
NVL(DEP_TIME,ARR_TIME) BETWEEN '07:31' AND '15:30'(NEXT DAY MORNING)- MORNING
SHIFT.
NVL(DEP_TIME,ARR_TIME) BETWEEN '15:31' AND '22:30'(NEXT DAY MORNING)- EVENING
SHIFT.
CAN U HELP ME?

THANKS

BASHYAM RAJA
BAHRAIN AIPORT SERVICES
and we said...
IT IS HARD TO READ UPPERCASE ONLY TEXT and it makes it seem like you are
shouting at me.

1)

Article-ID:         <Note:50678.1>
Folder:             client.Dev2000.Forms.V4
Topic:              Oracle Forms Hints - General Hints
Title:              WIN:Reading Registry from 32-bit Forms
Document-Type:      FAQ
Impact:             LOW
Skill-Level:        CASUAL
Updated-Date:       11-MAY-2000 18:11:14
References:
Attachments:        NONE
Content-Type:       TEXT/PLAIN
Products:           0;
Platforms:          GENERIC;

                    Reading Registry from Forms
                    ------------------------------
Introduction
------------
On P.Cs with 32 bit Operating Systems such as WIN95 or WIN NT 4.0
the Registry holds information on how your computer runs.
This note shows step-by-step, how information in a WIN95 Registry can be
accessed from an application developed in Forms4.5. It uses the example of
accessing the IP Address of a p.c but can be easily adapted to get any Registry
information.

Follow these steps:
1.Create new form with on-logon trigger and set it to null as no database
  connection is required.
2.Attach library D2kwutil.pll part of D2kwutil utility. (see below)
3.Create Program Unit with this code:

DECLARE
 v_msg varchar2(20);
 v_path varchar2(100);
BEGIN

  --specify registry entry which holds IP Adress info
  v_path := 'HKEY_LOCAL_MACHINE\System\CurrentControlSet
              \Services\Class\NetTrans\0003';

  --use d2kwutil package function
  v_msg := win_api_environment.read_registry(v_path,'IPAddress',true);

  --display IP Address to screen
  message(v_msg);

END;

(Replace v_path
with 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Srv' for NT4.0)

4.Create button on a non-base table block.
5.Create a WHEN-BUTTON-PRESSED trigger which calls the program unit.
6.Run form, press button and you should see the machine's IP address
  displayed.

The Registry Editor (Regedit.exe) provided on 32-bit Windows can be used to
find the exact location of a particular key that holds information that
you need. Once the exact path is found, it can be passed along with
the name of the key, to the D2kwutil function 'read_registry' in the D2kwutil
package win_api_environment.

NOTE:
D2kwutil consists of a PL/SQL library (D2kwutil.pll) and a windows DLL
(D2kwutil32.dll). This DLL is only available as a 32-bit utility for
Developer/2000 running on Windows 95 and WindowsNT. It comes with an extensive
Acrobat document listing all the available packages.
Contact Oracle Technical Support for the latest version of this utility.

---------------------------------------------------------------------------
                                         Oracle WorldWide Customer Support

2)

where to_char(nvl(dep_time,arr_time),'hh24mi') >= 2231
   or to_char(nvl(dep_time,arr_time),'hh24mi') <=  730

where to_char(nlv(dep_tim,arr_time),'hh24mi') between 731 and 1530

where to_char(nlv(dep_tim,arr_time),'hh24mi') between 1531 and 2230
May 08, 2001 parker -- Thanks for the question regarding "password file", version 8.1.7
You Asked
Tom

While creating a database manually, at what stage should the password file be
created, using the orapwd utility.

Parker
and we said...
Whenever you want, before or after -- it is optional (you never need it).

the most likely answer would be "after" -- to allow for remote SYSDBA/SYSOPER
connections.
May 08, 2001 Madhusudhana Rao -- Thanks for the question regarding "Oracle 8.1.6 support for Solaris 8", version Oracle 8.1.6
You Asked
Hi Tom,

Our project is going to be on Solaris 8 and Oracle 8.1.6 but
in Oracle site they not mention anywhere it will support but
they say Solaris 8 supports Oracle 8.1.7 in installation guide and
release note.

Can you pls let me know wheater Solaris 8 supports Oracle 8.1.6
if yes, do we need to apply any OS patches and if there is any known
bugs are there in this combination.

Regards.
Madhusudhana Rao.P
and we said...
Oracle8i release 2 version 8.1.6 is supported and cerfitied on Solaris

2.6
2.7 (aka 7)
2.8 (aka 8)

there are no mandatory patches.
May 08, 2001 parker -- Thanks for the question regarding "difference between exclusive lock and shared lock", version 8.1.7
You Asked
Tom

Can you explain the difference between exclusive lock, sharedlock, and row lock
in simple terms.
Further,
When does oracle obtain table locks?

Parker
and we said...
an exclusive lock generally means "i have it and you cannot have it".  If I have
an exclusive lock, no one else can have that lock.

a shared lock means generally "i have it and you can share it with me but if you
try to get it exclusively, i won't let you".  So, two people can share that lock
but if a third comes along and tries to get that lock in exclusive mode -- they
will fail (or wait).

Oracle generally does not obtain table locks.  A glaring exception and pretty
much the only one I'm aware of, is in the case of an unindexed foreign key.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:292016138754
Now, Oracle will take DDL locks on tables -- meaning that while my query is
processing you cannot ALTER the table i am using.  these prevent DDL but not DML
on the table.
Review & Followup
Rating: 5
well explained May 09, 2001
Reviewer: Uzma from Karachi,Pakistan
i really liked the way u made the explination on the topics!!!!

Rating: 5
It is quite useful. May 09, 2001
Reviewer: A reader from Islamabad

May 08, 2001 -- Thanks for the question regarding "Indexes on Foreign Keys", version 8.1.6
You Asked
I recently discovered that our third party software provider does not have any
indexes on the foreign keys within their schema. I have noticed that throughout
the day, "lock waits" account for somewhere in the range of 10-15% of all waits.
My question is, how important is having these indexes on the foreign keys.
Everything I have read so far indicates that without them, we could be locking
parent tables throughout the day. Given that we are in a OLTP environment with
anywhere from 40-150 users(tellers) running the same banking application.

My second question has to deal with your thoughts of some of the new "Quest"
software--"Live Re-Org", "iWatch" etc.. Have you heard any pros or cons
concerning them.

Thank you as always in advance for any input that you may have.
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:292016138754
it'll not be locking the PARENT -- it locks the CHILD table on

o an update to the PARENT primary key (hopefully they do not do this, you can
query v$sql to find update statements against parent tables and see if the
primary key is included in the update)

o a delete to the parent (again, they might not delete from the parent.  a query
query against v$sql will confirm/deny this)

If they never do that and don't need the indexes for queries -- then it is OK.

I've never used any of the Quest tools, sorry.  I'll have to refer you to the
newsgroups for opinions on those.
May 08, 2001 Tom -- Thanks for the question regarding "Messaging between Oracle Forms and Oracle Database", version 6.0
You Asked
Tom:

We have a situation where we would like to have a data extract performed via a
database package.  As the package rips its way through the data, it's desirable
to have a progress bar updated on a form.  (This will give the user a sense of
security as the extract will take several minutes.)

Is there a way to easily communicate with a procedure within the database
package so that the percentage complete may be determined by the form?

Thanks!
and we said...
When forms makes a stored procedure call, it must wait until the stored
procedure call completes before it can do anything else.  What you will have to
do is break your one routine into probably three routines:

init
do_some_work( pct_complete out )
finish

and your forms app will:

   pkg.init;
   loop
       do_some_work( pct_complete );
       exit when (pct_complete = 100);
       update_process;
   end loop;
   pkg.finish;
May 08, 2001 ahmad -- Thanks for the question regarding "pl/sql", version 8
You Asked
how i can get spool out in pl/sql
and we said...
spool is a client side, sqlplus command.

PL/SQL runs in the server, spool is not a concept known to PL/SQL.

If your goal is to spool and capture PLSQL output then:

set serveroutput on
spool somefile
exec some_procedure
spool off

and if some_procedure calls the dbms_output package, its output will be captured
to a file.

if your goal is to have PLSQL create a file on the server, you want to look at
UTL_FILE.  Search my site for UTL_FILE for lots of examples.
May 09, 2001 Vipul -- Thanks for the question regarding "Is there way/hints to improve performance of Minus operator?", version 8.1.6
You Asked
Hi Tom,

I have 2 tables with identical structures (each have same 30 columns) and col_1
is PK in both. Let's call these tables as new and old. I am required to update
the old table if there is any change in any column for a given row (matching on
PK) or insert into old table if it's a new PK column value.

Now each of these table have approx. 6 Mil. rows.

I thought that, it would be easy if I open a cursor like
select * from new
minus
select * from old;

And then go on carrying update/insert operation. In this case, I may be only
hadling 20% rows which are either changed or are new.

But, in case of minus, I noticed that:

1. It makes full table scan on both the tables
2. it goes on using temp table space for sorting

My question is : is there any Hint/other way to make this operation faster with
usage of fewer resources?

Thanks.
VJ
and we said...
update ( select old.c1 old_c1, ... old.c30 old_c30,
                new.c1 new_c1, ... new.c30 new_c30
           from old, new
          where old.pk = new.pk
            and ( nvl(old.c1,'x') <> nvl(new.c1,'x')
                  OR ...
                  OR nvl(old.c30,'x') <> nvl(new.c30,'x')
                )
       )
  set old_c1 = new_c1, ...., old_c30 = new_c30
/

that'll update all changed rows.  It will MOST LIKELY full scan OLD (has to full
scan something) and index access every row in NEW (that'll take SOME amount of
time!) and compare the values and update the rows that don't match.

In place of 'x', you should pick a VALUE that the column cannot assume naturally
(use numbers and dates where appropriate of course).  You can skip the NVL() on
all non-null columns.

insert into old
select new.*
  from new, old
 where new.pk = old.pk(+)
   and old.pk is null
/

that'll insert all of the NEW records.  It'll full scan NEW, index read old and
insert any records that are in NEW but not OLD.

Another alternative might be:

for x in (
select decode( old.pk, null, 'INSERT', 'UPDATE' ) what, new.*
  from new, old
 where new.pk = old.pk(+)
   and ( old.pk is null
         or
         ( old.pk is NOT NULL
           and ( nvl(old.c1,-1) <> nvl(new.c1,-1)
                 or nvl(old.c30,-1) <> nvl(new.c30,-1)
               )
         )
       )
)loop
   if ( x.what = 'INSERT' ) then do the insert
   else do the update
end loop
/

one FULL scan on new, index read into every row of OLD.  Might be faster, you
might want to do some bulk fetches (array processing) as well.
Review & Followup
Rating: 5
Nice options May 09, 2001
Reviewer: VJ from Boston, MA USA
Thanks a lot.

Rating: 3
May 10, 2001
Reviewer: Asif Momen from Riyadh
Hi Tom,

  Your suggestion is quite fantastic when we have to perform the operation on
existing records.

But, its easy and fast to create a database trigger on the new table on every
insert, delete or update.
Then keep modifying the table old table from the triggers.

Regards,

May 09, 2001 Howie -- Thanks for the question regarding "Stored Procedures and Functions", version 8.0.5
You Asked
Hi Tom

I want to get definition of Stored Procedures/Functions from the database . How
can I achieve that? I mean to say that which dictionary view can be used like to
find a view definiton I use DBA_Views

Thanks in Advance

Howie
and we said...
*_SOURCE has that.  (* = all, user, dba)

see also
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:743825617527
...
May 09, 2001 -- Thanks for the question regarding "status bar", version 8.1.6
You Asked
Hi, Tom,

How to simulate a status bar in ORACLE FORM(process bar), this bar can be filled
with color to indicate how far we already go or how many time left? I tried by
creating text items, but the reslt is not very immpresing, especially for
multiple records(each key corresponding to one status bar). Could you recommend
some ways or code to make it fancy?

Thanks
and we said...
don't use text itemS, use a text item.  for example, create a default block on
DEPT, add a text item called status, a button with this in the trigger:

for i in 1 .. 20
loop
     set_item_property( 'dept.status', ITEM_SIZE, i*10, 10 );
     synchronize;
     dbms_lock.sleep(1);
end loop;

and run the form (might need execute on dbms_lock).

followup to second comment

You yourself has to know how long it is going to take in order to do that.  Look
at the "file copy" status -- it is almost always wrong in the beginning and gets
"smarter" as it goes along.  copy a really big directory with it and see what
happens.  It gets halfway across fast and stops advancing until reality catches
up with it.

You would have to break your long running processing into "chunks" or steps so
that it can report back to forms how far along in the process it is.

Something similar to
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:608987592477
...
Review & Followup
Rating: 4
Very Good May 09, 2001
Reviewer: Reader from usa
It is very useful, thanks

Rating: 4
Further Question May 09, 2001
Reviewer: Question from USA
Hi,

Based on what you provided, how can i synchronized this status bar with the
process running on the background? For example: with the start of a process, the
status bar started, and it is stopped(reach the end of status bar at the same
time) as soon as the background process stops(finished). It is somthing like the
pop up window when we doing copy files under the WINDOWS system(it is more
better to tell the end user how many minutes still left).

Thanks

Rating: 3
Clearance May 10, 2001
Reviewer: A reader
Hi, Tom,

Could you please make it more clear for me or give me an example? Because my
main package is loading the data(from flat file) and validate the data, stored
them into table and finally make some tansctions. The flat file is located in
client side and called the package(in server side) from form. The package itself
is fire complicated, and i don't know if i can breake them into some pieces.

Another: could we use animate pictures such as "folder and coping route" while
copying files in Window system? If, it is true, how? example please.

Thanks

May 09, 2001 -- Thanks for the question regarding "alter table partition move", version 8.1.7.1
You Asked
Hi Tom,

I know you object to reorganizing table/index if there are more than 1 or 2
extents, but I have a question where I want to reorganize a table because of
different reasons.

First let me make sure I understand something...

I want to find out how much space a table is actually using.  I can do this by
selecting the sum of the blocks from dba_tables for a particular table??  I then
want to compare that to the initial extent.  I want to find out how much space
is being wasted on tables.

So, I have a table that has an initial extent of say 50M and the sum of the
blocks for that table is only 1024K.  Does that tell me that I'm wasting 49M on
that table?  If so, can I use the alter table move to rebuild the table??  What
if it's a partion table?  Can the same thing be done?

If this all can be done, will I have any fragmentation in the tablespace,
assuming that I keep the tables in the same tablespace during the move?

Sorry if this is too confusing, I'm starting to confuse myself :)

Roland
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
for getting the size used by a table.  It'll show you allocated and used blocks
(the diff being the "wastage" -- wastage being of course a relative term, if you
are going to use it soon enough, its best to leave it there).

You can use the alter table move to rebuild it with new storage parameters.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:47812348053
for the process.

you can move individual partitions in this manner as well.

You'll have fragmentation in the tablespace if you are using a dictionary
managed tablespace and have extents of various sizes, yes.  you'll leave lots of
holes that others may or may not be able to use later.
May 09, 2001 Venku Reddy -- Thanks for the question regarding "Table Locks", version 8.0.5
You Asked
In what are the situations oracle is going to impose table locks? This reference
to my earlier question subject is "deletion of records from parent table with RI"
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:292016138754
an unindexed fkey is the only time it'll happen.  if you DELETE from the parent
or update the parents primary key -- any child table with an unindexed foreign
key will be locked.
May 10, 2001 Parag -- Thanks for the question regarding "Label Security", version 8.1.6
You Asked
Hi Tom :

   Can u please tell me the Pratical USE with some basic example of Oracle Label
Security which availabel in Oracle 8.1.7.

   Tom . Please Don't give me the Link address .. which is available on Oracle
Site. Please give me some Realistic example of Oracle Label Security.

   Can u please guide me some more updates with Oracel Vertual Private Database.
How to use it e.t.c.

Thanks
- Parag
and we said...
It is designed as the replacement for trusted Oracle which was a B1 multilevel
secure implementation of Oracle that ran on B1 operating systems.  In such a
system, a user logs in with a hierarchical level (eg: unclassified, secret,
top-secret) and potentially a compartment within that level (eg: "department 1",
"department 2", .... ).

You can see information at your level or below (secret can read secret and
unclassified but not top-secret).  You can only see data in those levels that is
in your compartment (or has not compartment).  So, i might be able to see secret
"department 1" and "departement 3" but not "department 2".

All data you create will be automatically created with your level and
compartment.  You cannot declassify things -- you can only make them go up a
level or more.

So, who would use this -- the same people that might use VPD in the first place.
 Your application logs you in at a level ( like a role clerk, admin, super user
perhaps) and a division (or department or company).  You can only see the data
you are allowed to see at your level and compartment.

See
http://osi.oracle.com/~tkyte/article2/index.html
for a howto on VPD
Review & Followup
Rating: 3
Label Security October 30, 2001
Reviewer: ville from Australia
I thought your response was adequate to the level of the question that was
asked. But I find it difficult to find any really indepth information on label
security for oracle 8.1.7 and 9.0.1. Sure the documents from oracle are useful
for setting it up and all as I have. It all works fine and all but when I try
and do something innovative like automate user security labels with LDAP, I have
a real bugger of a problem I will try and ask you sometime when I am permitted.
As I cannot find a solution so far with forums either.

ville.

May 10, 2001 Anderson -- Thanks for the question regarding "Scripts for installation", version Oracle 8i
You Asked
Is there another way for run a script ( to create my views, procedures... )
whithout use sqlplus.exe?
Imagine a situation that a machine has an Oracle db with minimum installation.
and we said...
svrmgrl is there.

in 9i, sqlplus will always be there as it is the replacement for svrmgrl.
May 10, 2001 Venkatesan -- Thanks for the question regarding "Selective Delete.", version 8.1.6
You Asked
Hi Tom,

I have a table with the following data.

My Table

Col1          col2
1              Y
1              Y
1              Y
2              Y
2              Y
2              N
3              N
3              N

I would like to delete all the records in the table for col1 corresponding col2
has only 'Y'.i.e after the delete data should be
as follows.

Col1          col2
2              Y
2              Y
2              N
3              N
3              N

Your help will be higly appreciated.

Thanks,
Venky
and we said...
delete from my_table
 where not exists ( select null
                      from my_table b
                     where b.col1 = my_table.col1
                       and b.col2 <> 'Y' )
/
Review & Followup
Rating: 5
It's excellent May 11, 2001
Reviewer: venkatesan govindarasan from USA
Thanks for your immediate reply.
Venkatesh

May 12, 2001 parker -- Thanks for the question regarding "unix for a dba", version 8.1.7
You Asked
Tom

I want to know what is the minimum of Unix an oracle dba should know.
Is there a document  which gives the frequently used Unix commands by a dba.

Thanks
and we said...
A DBA should know their operating system very well and be comfortable with ALL
of the commands.  You cannot hope to successfully backup, restore, or tune a
database server and database instance otherwise.  You need all commands, much
more information than I can present here.
May 12, 2001 parker -- Thanks for the question regarding "basic backup and recovery scenarios", version 8.1.7
You Asked
Tom

Iam a developer aspiring to become a dba. I have done a lot of reading on backup
and recovery.But Iam not satisfied. I want to know what the minimum backup and
recovery scenarios which a dba should know.

Thanks
and we said...
All of them.

This document covers many of the cases you might hit:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/toc.htm

you need to be able to recover from media failure, from loss of a single
datafile forever, from loss of all online redo logs, from loss of all control
files, etc etc etc.  There are sections on various scenarios in that document.
May 12, 2001 parker -- Thanks for the question regarding "listener.ora,config.ora,tnsnames.ora,sqlnet.ora", version 8.1.7
You Asked
Tom

I want to know if there are any other net8 files apart from
listener.ora,config.ora,tnsnames.ora,sqlnet.ora( which I think are byfar the
most crucial) which are very important to know for trouble shooting network
problems.

Can you explain in brief to me , about sqlnet.ora and config.ora?

Further

Does windows registry come into picture any time while troubleshooting network
problems?

Parker
and we said...
these are fully documented in the network guide.
http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/params.htm#421916

the windows registry typically does not come into play, i've never had to access
it to trouble shoot network stuff.

The config.ora isn't related to networking at all.  Some databases use both an
"init.ora" and a "config.ora" when setting up the paramater files.  But some are
not quite clear as to why and what the recomendation is for using the two
diferent files.

The "init.ora" is the main parameter file that is looked for by Oracle when a
instance is started.  The "init.ora" can contain all of the parameter files
needed for your instance.  Then why have a file called the "config.ora"?

When using both an "init.ora" and a "config.ora", the "init.ora" is used to
hold parameters that set limits and variable information. This is data such as:
the name of private rollback segments, how much memory to use for memory
structures in the SGA, and starting automatic archiving and archive log formats.
 Basically, the "init.ora" holds information that might be changed on a
relatively frequent basis.

The "config.ora" on the other hand can be used to hold parameters that name
things.  These parameters stay relatively static as compared to the parameters
set in the "init.ora". The parameters you might set here are things as: the
name of the database,  the names and location of the control files, your
archive log destination,  and process dump directories. Usually, the files in
the "config.ora" will not be used for tuning or changing how the database uses
resources.  Even though it is not required to use both parameter files, it can
reduce the chances of static parameters of being accidentally changed.
May 12, 2001 Nagaraju -- Thanks for the question regarding "restrict_references,order of tables in from clause and bulk copy 'forall'", version 8.1.6
You Asked
tom,

1.can you tell me why do we need to give restrict_references in a package for a
function.
what benefit we get out of it?

2.order of the table names in the from clause of a join query make difference
in performance of the query?

3. I have used Oracle8i bulk copy command in one of my pl/sql procedure in the
following matter
   i am just listing out the steps:

   i want to read from a table, process all the rows do some calculation and
then insert those rows
   into another table.the source table is of 30,000 to 40,000 rows.to avoid the
overhead on
   rollback segment, i want to commit the rows for every say 1000 rows.

   so, basically what did was:(Process #1)
   1.declared pl/sql tables for each column in the destination table.
   2.opened a cursor for the source table
   3.looping  for each record in source table
   4.doing the calculation and writing to a pl/sql table
   5.checking the record count reached 1000 then
   6.using forall copy everything to destination table
   7.delete all the rows from pl/sql tables using '.delete'
   8.commiting,
   9.resetting the record counter to 0

   after the end of the loop
   repeating the steps 6,8 to copy the remaining records if any.

   i have to do the above process from three different source tables move the
data to a same
   destination table.

   i used a ref cursor to open a different cursor for step2 in a loop on top of
the above process.

   the above process takes more time than when do everthing in a normal way
like:
   (Process #2)
   1. declare the simular variables for the columns of destination table
   2.open the cursor(normal cursor, not ref cursor) for the source table
   3.looping  for each record in source table
   4.doing the calculation and writing to the variables
   5.checking the record count reached 1000 then
   6.commiting.
   9.resetting the record counter to 0

i repeated the same above code in three different blocks for the three tables.
this process runs in less than half time over the first approach.

i really don't understand where is my fault? i think it could be

  a.due to ref cursor
  b.bulk copy
  c.due to the usage of '.delete'
  d. all of the above.

i thought of declaring some empty pl/sql tables(simular types of destination
tables) and assign
these things to the values in step7 of process #1 instead of '.delete'
but again i have to declare so many pl/sql table vairables.

Can you tell me in what exact context the bulk copy forall be used?
how exactely oracle copies the rows from pl/sql tables
(like whether it frames that many insert statements or anything else)
is it a good way to use pl/sql tables?

it looks like the process #2 is better than process #1, because by declaring
pl/sql tables
don't we occupying the more space in user global area?

help in this really appreciated.

thanks
nagaraju
and we said...
1) in Oracle8i, release 1 and up (8.1.5) and up -- it is not relevant -- not
necessary -- anymore.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:503221940653
for a discussion of what it was used for.

2) Maybe -- when using the rule based optimizer (RBO) it can affect it very
much.  Using the cost based optimizer (CBO), no -- it will not affect it (unless
of course you use the ORDERED hint).

The RBO would look at the tables as listed from RIGHT to LEFT and pick a driving
table for the query based on that.  Predicates and indexes (or lack thereof)
could change this but in general tables were processed right to left.

The CBO doesn't look at the order of tables in the from clause, it is not
relevant.

3) change your processing.  NEVER NEVER artifically constrain the size of your
transaction due to concerns about the rollback segment!  Never.  Firstly, an
insert requires the least amount of rbs space - it just needs to remember what
rowids to delete in the event of a rollback.  Only if you have mega indexes,
tons of indexes, would the rollback be large.  40k rows is *nothing*  -- it is
tiny.  Maybe if you were talking about 4million rows we might want to look at an
alternative (maybe).  What if halfway through your system fails (power outage).
You'll have to figure out how to figure out what rows have been processed, which
have not.  You'll spend more time coding logic to recover from every possible
error then the simple logic that runs from start to finish will take to run.
It'll be error prone and a waste of time.  Just do it in one transaction.  The
book I have coming out in June spends a great deal of time looking at this "we
need to commit frequently" MYTH -- why it is error prone, why it wastes more
resources then it saves (it saves nothing but generates more redo, more
rollback, eats more cpu, wastes precious programming time, etc -- there is no
UPSIDE to this approach).

Without seeing your code, I cannot tell you why -- i can guess.  First, I would
seriously look at doing all of this logic as:

  insert into t select ...... from source;

doing ALL of the functions and calculations right in SQL -- not in PLSQL.  If
you can do it in SQL, it'll almost always be MUCH faster then PLSQL.  If you
cannot do it in sql -- then do it in plsql.

What might be happening here is that your log devices are very slow.  when you:

  for x in select * from t
  loop
      insert into t2 .....
      if mod(rowcount,1000) = 0 then commit;
  end if

you are slowly filling up the redo log buffer and lgwr is flushing it to disk
every 3 seconds, when the buffer is 1/3 full, whenever someone else commits.

when you do the logic as:

   for x in select * from t
   loop
      array(i) := values
      if ( mod ) then
         forall insert ....
         commit;
      end if
   end loop

you are flooding the redo log buffer at the end of a process instead of
trickling it in with each row.  The commit has to wait until the log buffer is
totally flushed and the log buffer is potentially 1,000 times bigger with the
tables then with the single rows (which were being trickled out to disk)

Try this -- TAKE the commit OUT of the bulk processing and see what happens.
Now you'll be trickleing 1,000 rows at a time into the log buffer and lgwr will
flush that out in the background.  only the last commit will wait.

The bottom line is -- COMMITTING frequently is a very very very large resource
overhead.  You are not conserving anything, in fact you are using MORE of
everything.
May 12, 2001 Murali -- Thanks for the question regarding "Memory ipcs / tstshm out put ", version 8.1.6
You Asked
Hi Tom

Just a quick note thanks for your answer and I need some more help/clarification
from you .(
http://asktom.oracle.com/pls/ask/f?p=4950:9:::NO::F4950_P9_ORIG,F4950_P9_DISPLAYID:Y,587552870073
I was going through the answer and with some other references I got from web. I
know this is bit difficult to answer in one word but I am requested to do this
for a project.

What the following out put means…and how will I find out whether the SGA in
contiguous or not? (this is the out put from my sun box)
Can you please refer some good books or web sites regarding this

Best Regards

Murali

IPCS OUTPUT

IPC status from <running system> as of Sun May 13 00:40:19 GMT 2001
T         ID      KEY        MODE        OWNER    GROUP
Message Queues:
q          0   0xacea0207 -Rrw-rw-rw-     root      365
Shared Memory:
m          0   0xacec9521 --rw-rw-rw-     root     root
m          5   0          --rw-r-----   oracle oinstall
m          6   0x64ad5ad8 --rw-r-----   oracle oinstall
m        107   0x74d1b1e4 --rw-r-----   oracle oinstall
Semaphores:
s     196608   0x5507616  --ra-r-----   oracle oinstall
s          1   0x5507617  --ra-r-----   oracle oinstall
s          2   0x5507618  --ra-r-----   oracle oinstall
s          3   0x5507619  --ra-r-----   oracle oinstall
s          4   0x550761a  --ra-r-----   oracle oinstall
s          5   0x550761b  --ra-r-----   oracle oinstall
s     458758   0x7073fc6  --ra-r-----   oracle oinstall
s      65543   0x7073fc7  --ra-r-----   oracle oinstall
s      65544   0x7073fc8  --ra-r-----   oracle oinstall
s      65545   0x7073fc9  --ra-r-----   oracle oinstall
s      65546   0x7073fca  --ra-r-----   oracle oinstall
s      65547   0x7073fcb  --ra-r-----   oracle oinstall

TSTSHM OUTPUT

/tstshm
Number of segments gotten by shmget() = 50
Number of segments attached by shmat() = 12
Segments attach at lower addresses
Maximum size segments are not attached contiguously!
  Segment separation = 4292345856 bytes
Default shared memory address = 0xfe800000
Lowest shared memory address  = 0xfff80000
Highest shared memory address = 0xfe800000
Total shared memory range     = 4272422912
Total shared memory attached  = 25165824
Largest single segment size   =  2097152
Segment boundaries (SHMLBA)   =     8192 (0x2000)
and we said...
set the environmemt variable SHMMAX to your SHMMAX setting:

$ setenv SHMMAX 4294967295

and then use tstshm with the value of the size of your SGA:

$ tstshm -t193073136
totsize = 193073136
Succeeded in attaching 1 segments with total shm of 193073136

that shows I have 1 segment for my sga.
May 12, 2001 Nagaraju -- Thanks for the question regarding "union and union all", version 8.1.6
You Asked
hi tom,

even union all also sort all the rows as union does?
and we said...
No.

A union all B =  A + B

A union B = DISTINCT( SORT( A+B ) )

only use union when you NEED to.
May 12, 2001 TARIQ NOOR -- Thanks for the question regarding "Pimary key in Foxpro / Load Data from Foxpro tables", version 6/6i
You Asked
I designd a new payroll application in oracle 8.1.5 with developer 6/6i, But my
personal (HRM) system is running under Visual Foxpro version 6. I have following
questions.

1. Is it possible to define /reference the primary key of Oracle table to
non-oracle database or flat file.

2. Is is posible to populate my Database Block, List-item with the foxpro date
(with out punning the data into oracle)

3. How i can execute an SQL statement from developer that reference foxpro
table.

4. How I can populate my Oracle Table with the Foxpro flat file table from
developer (i.e. i don't want to create the control file and then run the
sqlloader to populate the data) I just want to automate the peocedure through
developer.

What you suggest to integrate my payroll application with existing Visual Foxpro
tables.

I have send therse questuion to our TSS team but not receied any answer.

You will not mind this long question list.
Hopefully
and we said...
1) no, not really.  you could use a trigger and code your own logic with a
gateway but it would be about the worst idea in the entire world.

2) yes, developer fully supports ODBC. see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:218213305850
3) see #2

4) see #2, you can also use the sqlplus copy command
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1139834557335
...
May 13, 2001 -- Thanks for the question regarding "help with a query !", version 8.1.7
You Asked
Hai Tom,

1)
I had a structure

cust_id
type (DEBIT/CREDIT)
amount

I have to display like...

cust_id  debit_amount  Credit_amount
1001     10,000.00         -
1002        -             500.00
....
....

please can u tell me how this can be achieved in a sql query !

2)  We are using oracle 8.1.7 on linux.   How many physical hard disks one
server should have(recommended).

thanks

best regs
mubeen
and we said...
1)

select cust_id, sum( decode(type,'DEBIT',amount,0) ) debit_amt,
                sum( decode(type,'CREDIT',amount,0)) credit_amt
  from t
 group by cust_id
/

2) at least one.  no one but you can answer this question.  no one but you
understands how much data you have, what your througput requirements are,
whether you need raid or not. and so on.....
Review & Followup
Rating: 5
May 14, 2001
Reviewer: A reader

Rating: 5
May 14, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

May 13, 2001 Reddi -- Thanks for the question regarding "enforcing refential integrity with a remote database", version 8.1.7
You Asked
Hi Tom

How can I enforce referential integrity with a table in a remote database, for
my table in the local database?

Thanks
and we said...
You do not, you do not want to.  It would be among the top 10 worst things you
could think about doing.

You would be making your database dependent on the other database -- if it was
not up or available, your database would become "read only".  Your application
belongs in the OTHER database in that case.

You could use triggers to do it yourself, there is no built in functionality.
It would be a terribly bad idea.
May 13, 2001 Reddi -- Thanks for the question regarding "check option in views", version 8.1.7
You Asked
Tom

I dont see the need for a check option with views. I work in forms, if I give my
user only the columns which he needs to see from a view, how can he update
columns which are not provided by the view.

Thanks
and we said...
You are missing the point of the check option. It prevents you from updating a
row to become a value that is not in view anymore.  Consider:

tkyte@TKYTE816> create table t ( x int );

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> create or replace view v1
  2  as
  3  select * from t where x > 0
  4  /

View created.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> create or replace view v2
  2  as
  3  select * from t where x > 0
  4  with check option
  5  /

View created.

tkyte@TKYTE816>
tkyte@TKYTE816> insert into v1 values ( -1 );

1 row created.

tkyte@TKYTE816> insert into v2 values ( -1 );
insert into v2 values ( -1 )
            *
ERROR at line 1:
ORA-01402: view WITH CHECK OPTION where-clause violation

it makes sure you only create data that matches the definition of the view, its
another type of integrity constraint.
Review & Followup
Rating: 5
Thanks very much December 03, 2002
Reviewer: Bong99 from Hong Kong
It is what I want know, thanks

May 13, 2001 Reddi -- Thanks for the question regarding "users,roles,privileges", version 8.1.7
You Asked
Hi
I want to see all the privileges assigned to each role grouped by roles, what is
the view I have to query? Iam querying user_role_privs , but that is not giving
the expected results.

I also want to see which user has access to what tables, through what assigned
roles. What views should I hit ?

Should the dba have all the 8 system privileges?

Thanks
and we said...
You want to look at DBA_TAB_PRIVS and DBA_SYS_PRIVS

tkyte@TKYTE816> select privilege || ' on ' || owner ||'.' ||table_name from
dba_tab_privs
  2  where grantee = 'CONNECT'
  3  union all
  4  select privilege from dba_sys_privs
  5  where grantee = 'CONNECT'
  6  /

PRIVILEGE||'ON'||OWNER||'.'||TABLE_NAME
----------------------------------------------------------
SELECT on TKYTE.T
ALTER SESSION
CREATE CLUSTER
CREATE DATABASE LINK
CREATE SEQUENCE
CREATE SESSION
CREATE SYNONYM
CREATE TABLE
CREATE VIEW

9 rows selected.

the second part is harder.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:853427230099
for part of an answer.  It shows how to see all of the privs granted to a USER
either directly or via any of the roles they have.  It is backwards from what
you want -- with it, you can find all of the privs an individual has and thus
find all of the tables they can access.  You want to find all of the users that
can access a given table -- to do that, you would have to find

- all users with direct grants
- all roles that have this grant
- all roles that have been granted a role that has this grant (and so on and so
on).

that second link shows you how to get started, you'll need to rewrite the
queries differently.

It is upto you and your security as to whether the dba should have the set of
privs.  many sites create their OWN dba role with their specific set of grants.
That is not a bad idea.
Review & Followup
Rating: 5
Nag October 22, 2001
Reviewer: Nag
Tom

My dba cloned a table t to schema YYY  for me in dev.
I see that the table exists in schema YYY , but Iam not able to access it from
my schema.

1.What can be the reason, if no synonym is created I should at least be able to
access it by schema.object notation.
yyy.table  should describe the table for me.

It is not happening Iam getting the error
ORA-04043: object t does not exist( but I can see it under the YYY schema)

2.How can I list all the objects I have access to , and the privileges I have
over them.

May 13, 2001 Reddi -- Thanks for the question regarding "instead of triggers", version 8.1.7
You Asked
Tom

1.I have coded all kinds of database triggers except instead of triggers. Never
got an oppurtunity. What can be a good example of instead of  triggers..

2.Untill 7.3 we had a maximum possible 12 number of triggers on a table, with
the addition of instead of in 8 it became 14. Now with the addition of 8 more in
8i , there are totally 22 database triggers, Iam I right ?

3.I have been asked this question a lot of times by my team members..
from which version has oracle 8i started, is it 8.0.6 or 8.1.5.

Thanks
and we said...
1) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:686424821718
2) well, that really was "12 TYPEs of triggers" -- you could have as many
TRIGGERs as you wanted -- you could have 10 "before insert" triggers

instead of triggers are on VIEWS, not tables -- so the number of types of
triggers on TABLES stayed the same, the number of types of triggers on VIEWS
however went from 0 to 6.

The event triggers to which I think you are referring (like "after logon",
"before drop" and so on) are placed either on the DATABASE or on a particular
SCHEMA -- they don't get associated with tables either.

3) Oracle8i release 1 was version 8.1.5.  Oracle8 covers the 8.0.x versions.
May 13, 2001 Reddi -- Thanks for the question regarding "forms item triggers", version 8.1.7
You Asked
Hi Tom

Thanks a lot for clarifying all these doubts and questions, which were lying
there in my log book from a long time. I owe my improvement in the last one week
to you.

An item has the following triggers

pre text item
when new item instance
key next item

post change

when validate item

post text item

in what order will these triggers fire?

I have never used the post change , Iam not quite sure when it would fire?

Further, how can give my user the functionality to select multiple values from a
combo box. Is there a document issued by oracle regarding this ?

Thanks
and we said...
navigate into the field
  1) pre-text
  2) when next item instance

check the field and hit tab:
  1) key-next-item
  2) post-change
  3) when-validate
  4) post-text

assuming all triggers are on the ITEM
May 13, 2001 OP -- Thanks for the question regarding "Question on UTLBSTAT and UTLESTAT !", version 8.1.6.0
You Asked
Hi Tom,

Thanks for providing useful tips always.

Today my Question is

1) UTLBSTAT and UTLESTAT utilities are used to gather
what kind of Information.

2) Is there any way to provide a PERIOD that is from
a specific period of time for which the data
needs to be gathered.

3) Is there any specific priviolege required to Run these
utilities.

4) What are the Related files where we can see the OUTPUT
generated by these Scripts.

5) Is there any disadvantage of these utilities or in other
words what are the things for which the Information
cannot be provided by these utilities.

6) Is there any new Utility available in ORACLE 9i for
carrying out the same task.

Thanks and Regards
OP Lalwani
and we said...
1) they are obsolete with 8i. statspack is much better.  see
http://technet.oracle.com/deploy/performance/listing.htm
and look for statspack

2) see #1

3) see #1

4) see #1

5) stats package imposes no performance penalty other then timed_statistics
=true.  this is so minimal that you should ignore it.

6) don't even have to wait, see #1
Review & Followup
Rating: 5
Performance Utilities ! May 14, 2001
Reviewer: OP Lalwani from INDIA
As usual very useful precise answer.

May 13, 2001 -- Thanks for the question regarding "Database state", version 8i
You Asked
Hi,
 Which V$ view will provide me with the information regarding status of the
database i.e. nomount, mount or open? Does any view give this information? If
not then is there any method for getting the state of the database. Now, if the
junior dba opens the server manager and issues startup mount and closes the
server manager window. How can I know what state the db is in? (The OEM does
show this info but I wanted to know from where does OEM retrieve this info.)

Thanx,

Nitin
and we said...
If the database is started but not mounted:

tkyte@TKYTE816> select * from v$database;
select * from v$database
              *
ERROR at line 1:
ORA-01507: database not mounted

if the database is started and mounted by not open:

tkyte@TKYTE816> select open_mode from v$database;

OPEN_MODE
----------
MOUNTED

if the database is started, mounted and open:

tkyte@TKYTE816> select open_mode from v$database;

OPEN_MODE
----------
READ WRITE
Review & Followup
Rating: 4
Nice Info May 14, 2001
Reviewer: VJ from Boston, MA USA

Rating: 5
May 14, 2001
Reviewer: Nitin
Exactly what I was looking for. Thanx.


Subject | Article | Last Updated (East coast time)
Execution Plan - Reg | article only | May 14, 2001 12:54 am
OS_Roles set default path for init.ora | article only | May 14, 2001 01:16 am
Collectors | article only | May 14, 2001 09:31 am
How to reference a host array or a mutidimension array in a PL/SQl block which USES PACKAGES. | article only | May 14, 2001 09:41 am
JAVA source code | article only | May 14, 2001 09:45 am
a question about sql query | article only | May 14, 2001 09:48 am
PIN, Chained rows.. | article only | May 14, 2001 09:58 am
Testing for blanks | article only | May 14, 2001 11:12 am
archivelog mode in not on during instance startup | article only | May 14, 2001 11:14 am
Unable to change the mode of tablespace.. | article only | May 14, 2001 01:24 pm
Package Error | article only | May 14, 2001 03:05 pm
Using PL/SQL to perform statistical operations found in SAS | article only | May 14, 2001 03:59 pm
intermedia | article only | May 14, 2001 04:02 pm
A few iAS Questions | article only | May 14, 2001 08:55 pm
how to return result set from stored procedure. | article only | May 15, 2001 07:03 pm
foreign key declaration | article only | May 15, 2001 07:13 pm
in, out, in out | article only | May 15, 2001 07:16 pm
password file | article only | May 15, 2001 07:20 pm
unique between two table. | article only | May 15, 2001 07:45 pm
loading java classes | article only | May 15, 2001 09:32 pm
Cold backup | article only | May 15, 2001 09:37 pm
How to extract a value from a buffer delimited by %? | article only | May 15, 2001 09:40 pm
Wrapping Utility | article only | May 15, 2001 11:13 pm
How can I user the same lov for 2 items | article only | May 15, 2001 11:27 pm
How to dynamically update a remote table using 'where current of l_cursor'? | article only | May 15, 2001 11:28 pm
disable constraint cascade | article only | May 16, 2001 11:30 am
Assign More Space To a Table | article only | May 16, 2001 11:46 am
Calling API from stored procedure | article only | May 16, 2001 12:03 pm
Log Switch Waits | article only | May 16, 2001 12:19 pm
any datatype to store milli seconds | article only | May 17, 2001 10:40 am
How to remove the archive files automatically | article only | May 17, 2001 01:41 pm
Select statements in a Declare | article only | May 17, 2001 01:57 pm
Adding a tablespace | article only | May 17, 2001 02:05 pm
Problem to create a system trigger | article only | May 17, 2001 07:01 pm
Totals in Hierarchy | article only | May 17, 2001 08:55 pm
OCM and pool | article only | May 17, 2001 08:56 pm
Default NUMBER precision | article only | May 17, 2001 09:01 pm
Explain Plan | article only | May 18, 2001 11:03 am
Passing a Unknown # of Arguments to a Procedure | article only | May 18, 2001 11:20 am
To Select the columns on the fly having not null data...... | article only | May 18, 2001 11:23 am
Executing oracle procedure from C | article only | May 18, 2001 11:25 am
Locking records... | article only | May 18, 2001 12:03 pm
savepoints with select for update clause | article only | May 18, 2001 03:27 pm
16 bit or 32 bit or 64 bit | article only | May 18, 2001 03:49 pm
trigger | article only | May 18, 2001 03:57 pm
Q: related to table reorganization(move/import) | article only | May 18, 2001 11:48 pm
tools tablespace | article only | May 19, 2001 05:29 pm
procedure and function | article only | May 19, 2001 05:32 pm
immediate and deferred constraints | article only | May 19, 2001 06:53 pm
Special Characters | article only | May 19, 2001 11:42 pm
renaming a table | article only | May 20, 2001 12:38 pm
Function index not used without hint. | article only | May 20, 2001 12:49 pm
row(s) 1 - 52 of 52
May 14, 2001 -- Thanks for the question regarding "Execution Plan - Reg", version 8.1.7.0.0
You Asked
Hi Tom

I would like to know how the results are to be intepreted pertaining to
execution plan

1. Recursive Calls.

   Tells about whether the execution plan for query exists in the library cache
or not?
   is it right?

2.  DB Block gets

    No of data block processed/searched to get the output? Is it right?
    Why it changes some time for the same query without any changes done to the
    table?

3.  Consistent gets

    I dont know about this paramater and how to interpret/analyse  it?

4.  Physical Reads.

    No of data blocks read from the disk not from the cache? Is it right?

5   bytes sent via SQL*Net to client
6   bytes received via SQL*Net from client

    Can we optimise 5& 6 paramters in any way. for a give query if so how?

7.  Sorts Memory
8.  Sorts Disks

     Can u pl explain what these parameters mean and how to analyse these
parameters

9. Rows Processed

   No of rows generated as output? is it right?
   Nothing to optimise in it?

Regards
and we said...
1) recursive calls may be generated by things other then parsing.  space
management might be recursive calls.  Triggers might have some.  It does not
indicate that the query was or was not in the shared pool already.

2) db block gets are blocks gotten in current mode.  inserts/updates/deletes get
their blocks in current (non-read consistent) mode in order to modify them.  A
full tablescan will read current mode blocks from the data dictionary/segment
headers to determine what blocks need to be scanned.

3) consistent gets -- this is logical IOs to perform your query.  How many
blocks were processed to perform your query in a read consistent mode.

4) correct

5) obvious
6) obvious

as for optimizing them -- use stored procedures to process multiple statements
-- never return the data to the client -- make one round trip instead of
hundreds.  do the work in the database, not over the network.

7 & 8) again -- these seem obvious.  They are the counts of sorts you performed
broken out by whether they fit in the sort_area_size number of bytes (sorts
memory) or not (sorts disk).  If you have a small sort_area_size and lots of
(sorts disk) consider increasing the sort_area_size (you can alter session to
play with it)

9) correct.
May 14, 2001 Umesh -- Thanks for the question regarding "OS_Roles set default path for init.ora", version 8.1.6.0
You Asked
Hi Tom,
How are you?

Some small Questions for you..

Platform : Windows NT 4.0 Service pack 4

1. I have my init.ora file in a directory other than ORACLE_HOME\database.

when I startup i need to specify the
 Pfile = < Complete path of the init.ora> file

But I want to change that ORACLE_HOME\database setting to my own directory where
my init.ora file exists ..So that Oracle looks up to this new directory other
than ORACLE_HOME\database  How doI do that??

2. I read thru' the documentation for OS_ROLES = true
 Here it says the OS is going to authenticate and grant the user the roles
created at OS levels instead of at the Database level

Can I get the steps for executing the same in Windows NT?

For this I created a <user> identified externally;
I created a          <role> identified externally..

How do I proceed?

Thanks in advance

Umesh Kasturi
and we said...
You cannot change the default place it will look (thats the purpose of the
default).  You can simply put a file in \oracle\database named
init$ORACLE_SID.ora that contains:

IFILE='C:\oracle\admin\tkyte816\pfile\init.ora'

that points to the "real" one.  8.1.6 does this by default actually.

See
http://technet.oracle.com/doc/oracle8i_816/nt.816/a73008/ch7.htm#1036322
for "Authenticating Database Users with Windows" part of the Oracle8i
Administrator's Guide Release 2 (8.1.6) for Windows NT
Review & Followup
Rating: 4
os_roles May 18, 2001
Reviewer: Umesh Kasturi from Bangalore ,India
Its been og good use.. I need not go on asking everybody as Tom always help me
out quickily

May 14, 2001 X -- Thanks for the question regarding "Collectors", version 8.1.5
You Asked
Hi Tom:
I use 8i version to create Oracle Web application. I created a object type as
table in the first web page procedure. How can I pass this ojbect to the second
page (I want second page to reference this table data).

Thank you
and we said...
You use PLSQL Table types for this.  Typically, the "state" is stored in a web
page using hidden fields.

for example:

create or replace package demo_pkg
as
    type array is table of varchar2(4000) index by binary_integer;

    procedure p1;

    procedure p2( p_data in array );
end;
/

create or replace package body demo_pkg
as

procedure p1
is
begin
    htp.p( '<form action=demo_pkg.p2 method=post>' );
    for i in 1 .. 10
    loop
        htp.p( '<input type=hidden name=p_data value='||i||'>' );
    end loop;
    htp.p( '<input type=submit>' );
    htp.p( '</form>' );
end;

procedure p2( p_data in array )
is
begin
    for i in 1..p_data.count
    loop
        htp.p( 'p_data('||i||') = ' || p_data(i) || '<br>' );
    end loop;
end;

end;
/

procedure p1 generates a page, that page will call p2.  p2 will recieve the
array p1 produced.

followup to comment

The mod_plsql module/cartridge only binds to tables of strings.  Since HTML is
all about TEXT anyway, this is not an issue -- it must be stored as a string in
the HTML page anyway.  Converting to any other datatype is trivial (just assign
to a number or date or whatever you have).

There is no need to use anything other then strings -- all things must be
converted to strings for transmission over HTTP anyway.
Review & Followup
Rating: 3
May 14, 2001
Reviewer: A reader from NJ
This example works for 'type array is table of varchar2(4000) index by
binary_integer'. How about the itms in the table is record not varchar2(4000)?

Rating: 5
May 14, 2001
Reviewer: A reader from NJ
Thank you for your followup comment.

May 14, 2001 Anwar -- Thanks for the question regarding "How to reference a host array or a mutidimension array in a PL/SQl block which USES PACKAGES.", version oracle8.i
You Asked
Thanks in Advance.
How to reference a host array or a mutidimension array in a
PL/SQl block which USES PACKAGES.
here is my query
Also please suggest me any way where i can do Bulk inserts from Pro*C.

the initial code is as follows::
it uses host arrays to insert large chunks of data

**************************************************************
                The current way the code is written
**************************************************************
INSERT_ARRAY_SIZE = 500;

int Somefunc(SomeStruct *someRecord)
{
/* Begin SQL Declaration section */
EXEC SQL BEGIN DECLARE SECTION;

/* Declare the host variables */

static char i_oid [INSERT_ARRAY_SIZE][17];
static char i_part_oid [INSERT_ARRAY_SIZE][17];
static int rows_to_insert=0;

/* End of SQL Declaration section */
EXEC SQL END DECLARE SECTION;

if (someRecord == NULL)
{

if (rows_to_insert != 0)
{
EXEC SQL FOR :rows_to_insert
INSERT INTO SOMETABLE
(VERSION_OID, PART_OID)
VALUES (:i_oid, :ipart_oid);

rows_to_insert = 0;
}

return (0);
}
return (0);

}
**************************************************************

        the way i am trying to implement...
**************************************************************

Now this is how i implement the PACKAGE (Supposedly )
i have a package called SOMEPACKAGE which has a member InsertRows.
The insertRows has the query (insert ) which is running on the database.

here is how i implement it and
it seems like i am having problems

int Somefunc(SomeStruct *someRecord)
{
/* Begin SQL Declaration section */
EXEC SQL BEGIN DECLARE SECTION;

static char i_oid [INSERT_ARRAY_SIZE][17];
static char i_part_oid [INSERT_ARRAY_SIZE][17];
static int rows_to_insert=0;
varchar h_error_msg[255];
int     h_error_code = 0;
short ind1,ind2;

/* End of SQL Declaration section */
EXEC SQL END DECLARE SECTION;

if (someRecord == NULL)
{

if (rows_to_insert != 0)
{

                EXEC SQL  EXECUTE
                BEGIN

                SOMEPACKAGE.InsertRows(:i_oid,
                                        :i_part_oid,
                                        :rows_to_insert,
                                        :h_error_code:ind1,
                                        :h_error_msg:ind2);

                END;
                END-EXEC;

                        if(h_error_code)
                        {
                                oracode= h_error_code;
                                strcpy(ErrorMessage, h_error_msg.arr);
                                return (h_error_code);
                        }

}
}
}

This not the whole code but it might give u an idea about what is happening i
guess the place where i know i am getting problems is
the  (SOMEPACKAGE.InsertRows(:i_oid,
                                        :i_part_oid,
                                        :rows_to_insert,
                                        :h_error_code:ind1,
                                        :h_error_msg:ind2);)

i do not know how to pass the i_part_oid and the i_oid ...?????
I am open to any suggestions how to implement this and improve the fastness.
???Not necessarily the way i think i am doing it...Please help

the below is the error i get...

/**********************Error**************/

/* Declare the host variables */ 254 ...1
254 PLS-S-00306, wrong number or types of arguments in call 'INSERTROWS'
254 ...1
254 PLS-S-00000, Statement ignored
/**********************Error**************/

And i checked out the package in by using the package through anonymous block in
Oracle it runs fine ....!!!

Please can anyone help????

thanks for the cooperation

Anwar MOhammad
and we said...
If you have a schema like this (always helps to have the PLSQL code as well as
the non-functioning proc code!)

create table oid( oid char(17) );
create table part_oid( part_oid char(17) );

create or replace package somePackage
as
    type array is table of char(17) index by binary_integer;

    procedure insertRows( p_oid        in array,
                          p_part_oid   in array,
                          p_error_code OUT number,
                          p_error_msg  OUT varchar2 );
end;
/

create or replace package body somePackage
as
    procedure insertRows( p_oid        in array,
                          p_part_oid   in array,
                          p_error_code OUT number,
                          p_error_msg  OUT varchar2 )
    is
    begin
        p_error_code := 0;
        p_error_msg := 'Recieved '  || p_oid.count ||
                       ' oids and ' || p_part_oid.count || ' part_oids';

        forall i in 1 .. p_oid.count
            insert into oid values ( p_oid(i) );

        forall i in 1 .. p_part_oid.count
            insert into part_oid values ( p_part_oid(i) );
    end;
end;
/

Your subroutine can look like this:

static void process()
{

#define INSERT_ARRAY_SIZE 500

exec sql begin declare section;
char    i_oid[INSERT_ARRAY_SIZE][17];
int     i_oid_length;
EXEC SQL ARRAYLEN i_oid(i_oid_length);

char    i_part_oid[INSERT_ARRAY_SIZE][17];
int     i_part_oid_length;
EXEC SQL ARRAYLEN i_part_oid(i_part_oid_length);

varchar h_error_msg[255];
short   h_error_msg_i;
int     h_error_code;
short   h_error_code_i;
exec sql end declare section;

    for( i_oid_length = 0;
         i_oid_length < 25;
         i_oid_length++ )
            sprintf( i_oid[i_oid_length], "oid %d", i_oid_length );

    for( i_part_oid_length = 0;
         i_part_oid_length < 30;
         i_part_oid_length++ )
            sprintf( i_part_oid[i_part_oid_length], "part oid %d",
                                i_part_oid_length );

    EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();
    exec sql execute
    begin
        somepackage.InsertRows( :i_oid, :i_part_oid,
                                :h_error_code:h_error_code_i,
                                :h_error_msg:h_error_msg_i );
    end; end-exec;

    printf( "%d, %.*s\n", h_error_code, h_error_msg.len, h_error_msg.arr );

}

Suggest you use the ARRAYLEN, it will avoid sending over the entire array when
you are not using the entire array.  it will send only the relevant components.

without seeing your plsql code, I cannot comment further on why you are getting
the message you are.  I can only assume the plsql table types on the server are
incompatible with your C type (eg: the plsql table type was a varchar2 not a
CHAR type for example)
Review & Followup
Rating: 5
Referencing host arrays in PL/SQl blocks using packages May 14, 2001
Reviewer: Anwar Mohammad from Peoria,IL
Hi Tom,
Thanks for the prompt reply and I am going to implement the code right now I
hope it works. You response is very fast .
Thanks for the response.

Rating: 3
referencing host arrays in packages. July 05, 2001
Reviewer: navdeep from India
Its a brilliant answer really helpful in learning.But it would have been better
to give information about passing arrays back to pro C.

May 14, 2001 -- Thanks for the question regarding "JAVA source code", version 8.1.6
You Asked
Hi,

How do i get the java source code which was loaded as a class in SQLPLUS or
other ENV. How many methods we have and examples please.

Thanks
and we said...
did you load the class into the database or the source.

If you load the class -- we obviously don't have the source.  If you load the
source and let us compile it -- we will (and it'll be there in user_source as
normal)
May 14, 2001 Senthil -- Thanks for the question regarding "a question about sql query", version 8.1.5
You Asked
Hi thomas,

i have a table called 'test' with one column, name. here are the rows i have in
that table.

SQL> select name from test;

NAME
----------
1
0
2
2
12.27
nest
,
90
hello1nest

9 rows selected.

now, i want to select rows that has only numbers, ie, it should look like...

NAME
----------
1
0
2
2
12.27
90

6 rows selected.

is there any function, that we can eliminate characters and select only numbers.

thanks for your help.

Senthil.
and we said...
ops$tkyte@DEV816> select x
  2    from t
  3  /

X
--------------------
1
0
2
2
12.27
nest
,
90
hello1nest
12.27.22

10 rows selected.

ops$tkyte@DEV816> select x
  2    from t
  3   where replace( translate( x, '0123456789.', '...........' ), '.', '' )
                                                    is null
  4     and instr( x, '.', 1, 2 ) = 0
  5  /

X
--------------------
1
0
2
2
12.27
90

6 rows selected.

should work in most cases.  the translate turns all digits into dots.  the
replace nulls out all dots.  if the result is null -- we have a string of digits
and dots.  the instr verifies there is only one dot at most and gets rid of
NULLs as well.
Review & Followup
Rating: 3
May 14, 2001
Reviewer: A reader
it was excellent...thanks

May 14, 2001 Suresh -- Thanks for the question regarding "PIN, Chained rows..", version 8.1.7
You Asked
Hi Tom,
  1. I created an emp table with pctfree as 10. Then I updated all the 10000
rows in the table with the maximum value for the empname column. I analysed the
table for chained rows and did  find them. Then I recreated the same table with
pctfree as 50, did the same procedure again and still there were chained rows.
Now, how do I get rid of the chained rows? Is increasing the pctfree only way to
get rid of those? Also, does the presence of chained rows affect the performance
of the system badly?

 2. When should I PIN the packages? Do I have to PIN the packages that are most
frequently used or is there any other reason as to when should I pin it?

3. What is the difference between pctfree and pctincrease?

4. While going through the ORACLE DBA handbook  I came across two options,
PARALLEL = TRUE and REENABLE DISABLED_CONSTRAINTS that could be used in the
control file. Could you please let me know how to use the two above mentioned
commands and also explain in details when to use PARALLEL = TRUE option.

As always, thanks a lot in advance for your help.
and we said...
1) first -- make sure you can eliminate the chained rows.  If the maximum row
size exceeds your block size, you might not be able to.  for example:

create table t ( x varchar2(4000) );

insert into t values ( rpad('*',4000,'*') );

i can assure you that on a database with a 2k block size -- that row is chained.

if the rows can fit on a block, you would have to REMOVE them from the table and
put them back in.

o analyze table T list chained rows into <some table>
  to get the rowids

o create table temp as select * from T where rowid in ( select head_rowid from
<some table>
  to copy them

o delete from t where rowid in ( select head_rowid from <some table> )
  to remove them

o insert into t select * from temp
  to put them back.

pctfree is the knob you have to reduce the number of times a row is chained (in
this case they are technically MIGRATED.  a truely CHAINED row is one that
cannot fit on a single block and you cannot fix those)

2) i never pin packages unless i'm triaging a system that does not use bind
variables.  The need to pin indicates poor application implementation.  If you
need to pin a procedure, it is because your developers are trashing the shared
pool.  hopefully you are not in this case.  You would know if you were.

3) pctfree reserves x% of a block for updates.  If you set pctfree to 10%, 10%
of a block would be set aside for updates.  an insert will NOT use that space.

pctincrease is a terrible, obsolete parameter that causes free space
fragmentation in tablespaces.  If you use locally managed tablespaces (thats the
ONLY kind to use in 8i), this parameter is meaningless.

pctincrease causes extents to "grow"  if you have:

initial= 1m, next = 1m, pctincrease = 50, your extents would be:

1m
1m
(1.5)*1m
(1.5)*(1.5)*1m

and so on.  they grow larger and larger.  I recommend pctincrease be set to ZERO
in all cases and you always use the same exact initial=next for all objects in a
tablespace.

4) in the control file???  i don't think so.  do you mean the sqlldr ctl file?
they are options there.  Please see the sqlldr chapter in the Server Utilities
guide for details.
Review & Followup
Rating: 5
Very educational May 15, 2001
Reviewer: Chuck from Atlanta, GA
I visit your site just to learn about problems and solutions I have not thoouth
of.

May 14, 2001 Greg -- Thanks for the question regarding "Testing for blanks", version 8.1.6 SE
You Asked
Tom,

I have a table that is meant to keep track of comment text.  The application
that populates this table, which is a black box to me, is screwing up and
inserting multiple blank rows for every meaningful entry.

Now, I've been given the task of mining this table for reports.  The problem is
that my query gives me a deluge of output, most of it blank.  So it occurred to
me to use an IF statement to test and see if a row is blank before outputing it.

The field is question is a CHAR(70) field.  And the "blank" rows appear to be
sometimes null, sometimes ' ', and sometimes multiple spaces (e.g. '    ').

How would you code an if statement to filter out all these bogus entries?
and we said...
If it is a CHAR(70) then it is EITHER null or 70 blanks.  CHAR's are always
stored at their full length with trailing blanks.

ops$tkyte@ORA8I.WORLD> create table t ( x int, msg char(70) );
Table created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1, 'hello' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 2, '    ' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 3, '          ' );
1 row created.

ops$tkyte@ORA8I.WORLD> select x, length(msg) from t;

         X LENGTH(MSG)
---------- -----------
         1          70
         2          70
         3          70

see, they are all 70 characters long.... to get ones that have data:

ops$tkyte@ORA8I.WORLD> select x from t where trim(msg) is not null;

         X
----------
         1

ops$tkyte@ORA8I.WORLD>
Review & Followup
Rating: 3
Tom tells how to test for empty character fields. May 14, 2001
Reviewer: Greg Kliewer from Toronto, Ontario, Canada
It works.  Thanks again, Tom.

May 14, 2001 Debabrata -- Thanks for the question regarding "archivelog mode in not on during instance startup", version 7.3.4
You Asked
Hi Tom,

 I am Debabrata from Calcutta once again. Sorry for disturbing Once again. I
have been benefitted by you previously for a no. of times.
Currently I am facing one problem.I have set log_archive_start as "TRUE" ,
log_archive_dest as "/oracle/oracle/hms/deba" (hms is the directory name and
deba is starting characters of log files) and also log_archive_format as
"arch%s.ora". Now instance starts properly.One process whose name is
o_arch_EXAM(EXAM is the instance identifier) is created. But the database
,possibly,is not running in archivelog mode.Because if  I write the following
code

declare
   dummy char(1);
begin
   select 'x'
   into dummy
   from v$database
   where log_mode = 'ARCHIVELOG';
exception
   when no_data_found then
      raise_application_error(-20000, 'Database not in ARCHIVELOG mode !');
end;

then it is directly going to the exception part. Naturally, I hope so, it
implies that it is not running in archivelog mode.Now what is to do ? How to run
in archivelog mode? At the time of startup it is not giving any error message. I
need your valuable advice. I hope you will help me once agian as you have
already done.

The OS is SCO UNIX 5.0.5 and ORACLE is 7.3.4

Thanks and regards

Debabrata
and we said...
That does not enable archivelog mode, you've only made it so that if a database
was IN archivelog mode -- it would employ automatic archiving.

see
http://technet.oracle.com/doc/server73x/SAD73/ch22.htm#toc176
for how to turn archiving on and off
May 14, 2001 -- Thanks for the question regarding "Unable to change the mode of tablespace..", version 8.1.6.3
You Asked
Dear Tom,
I am unable to change the mode of tablespace to read only.The system is getting
hanged.This happened when I tried to do it for exporting it(Transportable
tablespaces).I am having few doubts regarding that
1)Is it necessary that there should not be any active transactions in the entire
database???
According to one document it states that there should not be any active
transactions in the corresponding rollback segment as well as database.
If that is the case is there any workaround for that because it is not possible
to take outage if it is a production database and there will be always some
active transactions in it.The purpose of transportable tablespace feature is
ineffective in this case.
Thanks,
Geeta
and we said...
For a brief instant in time, yes.

In order to change the tablespace from read write to read only, we must suspend
transactions.  When you issue the:

alter tablespace i1 read only;

new transactions will be prevented from starting.  As the last of the old
transactions finish, the alter tablespace will complete and everything will
become unblocked.

This should not take longer then your longest running transaction.  You need to
do this during a period of time when you are running "short" transactions, not
long running batch jobs.
May 14, 2001 Raj -- Thanks for the question regarding "Package Error", version 8.1.5
You Asked
SCOTT.UTILITIES_PKG.FILE_OPEN@DBLINK_NYC( p_UtlFileDir, --UTLpath
                                          p_Logfile,    --logfile name
                                          'w',          --Mode
                                          2000,         --line size
                                p_logfilehandle,   --file handle (OUT)
                             v_utility_error );  --Error (OUT),if any

Hi Tom,

I am getting the following error below when I try to execute the package
above.It works fine if I execute it in it's instance but gives an error when I
execute it using DBLink. I'm calling it exactly the way it's defined.Could you
please help me find the what the error is ? I checked every possible thing the
manual says like I checked spelling,datatypes etc.
I checked the privileges also and it has the execute privileges.
Please help!!!

Error: (1):PLS-00306: Wrong number or types of arguments in call
                      to 'FILE_OPEN'.
       (2):Statement ignored

Thanks in advance.

--------------------------------------------------------------------
Hi Tom,
Here's the code you've asked me to provide for file_open-

PROCEDURE File_Open( p_UtlFileDir     IN   VARCHAR2,
                     p_FileName       IN   VARCHAR2,
                     p_Mode           IN   VARCHAR2,
                     p_Max_LineSize   IN   BINARY_INTEGER,
                     p_FileHandle     OUT  UTL_FILE.FILE_TYPE,
                     p_UtilityError   OUT  VARCHAR2) IS
BEGIN
  p_UtilityError := NULL;
  p_FileHandle := UTL_FILE.FOPEN (p_UtlFileDir, p_FileName, p_Mode,
p_Max_Linesize);
EXCEPTION
WHEN UTL_FILE.INVALID_PATH THEN
  p_UtilityError := 'invalid_path';
WHEN UTL_FILE.INVALID_MODE THEN
  p_UtilityError := 'invalid_mode';
WHEN UTL_FILE.INVALID_FILEHANDLE THEN
  p_UtilityError := 'invalid_filehandle';
WHEN UTL_FILE.INVALID_OPERATION THEN
  p_UtilityError := 'invalid_operation';
WHEN UTL_FILE.READ_ERROR THEN
  p_UtilityError := 'read_error';
WHEN UTL_FILE.WRITE_ERROR THEN
  p_UtilityError := 'write_error';
WHEN UTL_FILE.INTERNAL_ERROR THEN
  p_UtilityError := 'internal_error';
WHEN OTHERS THEN
  p_UtilityError := SQLCODE||'-'||SQLERRM;
END File_Open;

FYI, This procedure is in Oracle version 8.1.7 but I'm calling it from another
Oracle instance version 8.1.5.

Thanks in advance.
Raj-
and we said...
Ok, the variable:

p_logfilehandle

is defined using the UTL_FILE package in the 8.1.5 instance.  It is calling a
package that requires a UTL_FILE record from the 8.1.7 instance -- that is the
cause of the mismatch.

Consider (p is a procedure on ora8i.world that has an out parameter of
utl_file.file_type)

tkyte@TKYTE816> declare
  2          x       utl_file.file_type;
  3  begin
  4          p@ora8i.world( x );
  5  end;
  6  /
declare
*
ERROR at line 1:
ORA-06550: line 4, column 2:
PLS-00306: wrong number or types of arguments in call to 'P'
ORA-06550: line 4, column 2:
PL/SQL: Statement ignored

tkyte@TKYTE816> create synonym utl_file_remote for utl_file@ora8i.world;
Synonym created.

tkyte@TKYTE816> declare
  2          x       utl_file_remote.file_type;
  3  begin
  4          p@ora8i.world( x );
  5  end;
  6  /

PL/SQL procedure successfully completed.

Now you'll get the file type back.  You can only use this with utl_file_remote.
the local UTL_FILE will not operate on that file.
Review & Followup
Rating: 5
Great Solution May 15, 2001
Reviewer: Raj
It really works now. Thank you very much Tom.

May 14, 2001 Paul -- Thanks for the question regarding "Using PL/SQL to perform statistical operations found in SAS", version 8.1.6
You Asked
Tom
Our Oracle database is used heavily by statisticians who use SAS and simple SQL.
 In my programmer role I am being asked to take over many of the statisticians
processes that were done in SAS and use PL/SQL stored procedures to do so.

Last week I encountered a procedure that from SAS that I have found difficulty
replicating with a PL/SQL solution.  It is a statistical scoring procedure that
our users use in SAS heavily called PROC SCORE.

The example is this:  I have Table A with 350,000 rows, 6 primary key columns,
and 75 numeric raw data columns.  I have Table B with 360 rows (each one
representing a statistical model), a primary key column (model_name), and 75
numeric coefficient data columns.  The 75 data columns in each table have the
same exact set of names.  I need to produce Table C with 350,000 rows, primary
key columns (same PK as Table A), and 360 data columns (one for each of the rows
from table B).

The observation value for a given model score column in Table C is achieved with
the following function:
((A.data_col1*B.data_col1)...+ (A.data_col75*B.data_col75) ) for a given model.

PROC Score in SAS allows the statisticians to do such a thing in just a handful
of lines of code. How can I best perform this in Oracle using SQL and PL/SQL?  I
don't know how to use VARRAY, nested tables, but I'm not afraid to learn if they
can factor into a good solution for this problem I have.

Thanks,
Paul Sieczkowski
and we said...
Yes, in general, the table you want is:

create table results as
select  PK1, PK2, PK3,
        sum(decode( b.r,1,((a.C1*b.C1)+(a.C2*b.C2)+
                         (a.C3*b.C3)+(a.C4*b.C4)),0)) "MODEL1",
        sum(decode( b.r,2,((a.C1*b.C1)+(a.C2*b.C2)+
                         (a.C3*b.C3)+(a.C4*b.C4)),0)) "MODEL2",
        sum(decode( b.r, 3,((a.C1*b.C1)+(a.C2*b.C2)+
                         (a.C3*b.C3)+(a.C4*b.C4)),0)) "MODEL3",
        sum(decode( b.r,4,((a.C1*b.C1)+(a.C2*b.C2)+
                         (a.C3*b.C3)+(a.C4*b.C4)),0)) "MODEL4",
        sum(decode( b.r,5,((a.C1*b.C1)+(a.C2*b.C2)+
                         (a.C3*b.C3)+(a.C4*b.C4)),0)) "MODEL5"
   from a a, ( select rownum r, b.* from b b ) b
  group by  PK1, PK2, PK3
/

where I did a test with 3 primary key columns and 4 data points.  I went a
little further and wrote a plsql routine to generate this query -- in the event
the table names change and so on.  Basicaly, all you need is the above query but
you might be interested in the following routine:

tkyte@TKYTE816> create table a
  2  ( pk1 int, pk2 int, pk3 int,
  3    c1 number, c2 number, c3 number, c4 number,
  4    primary key(pk1,pk2,pk3)
  5  )
  6  /

Table created.

tkyte@TKYTE816> begin
  2      for i in 1 .. 10
  3      loop
  4          insert into a values ( i, i, i, i, i, i, i );
  5      end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> create table b
  2  ( model varchar2(10) primary key,
  3    c1 number, c2 number, c3 number, c4 number
  4  )
  5  /

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> begin
  2      for i in 1 .. 5
  3      loop
  4          insert into b values ( 'model' || i, i, i, i, i );
  5      end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> create or replace
  2  procedure proc_score( p_atab in varchar2,
  3                        p_btab in varchar2,
  4                        p_result_tab in varchar2 )
  5  is
  6      type rc is ref cursor;
  7
  8      l_cursor    rc;
  9      l_cnt        number := 0;
 10      l_cname     varchar2(30);
 11
 12      l_columns   long;
 13      l_multiply  long;
 14      l_sep       char(1) default '(';
 15      l_pks       long;
 16      l_query     long;
 17  begin
 18
 19      open l_cursor
 20       for 'select upper(substr(model,1,30)) from ' || p_btab;
 21
 22      loop
 23          fetch l_cursor into l_cname;
 24          exit when l_cursor%notfound;
 25          l_cnt := l_cnt + 1;
 26          l_columns := l_columns ||
 27                         ', sum(decode( b.r, '||l_cnt||
 28                               ',$F,0)) "' || l_cname || '"';
 29      end loop;
 30      close l_cursor;
 31
 32      for x in ( select a.column_name acname,
 33                        b.column_name bcname
 34                   from user_tab_columns a,
 35                        user_tab_columns b
 36                  where a.table_name = upper(p_atab)
 37                    and b.table_name (+) = upper(p_btab)
 38                    and a.column_name = b.column_name(+)
 39                  order by a.column_id )
 40      loop
 41          if ( x.acname = x.bcname )
 42          then
 43              l_multiply  := l_multiply || l_sep
                                  || '(a.'||x.acname||'*b.'||x.acname||')';
 44              l_sep := '+';
 45          else
 46              l_pks := l_pks || ', ' || x.acname;
 47          end if;
 48      end loop;
 49      l_multiply := l_multiply || ')';
 50      l_pks      := ltrim(l_pks,',' );
 51
 52      l_query :=
 53         'create table ' || p_result_tab || ' as
 54                select ' || l_pks || replace( l_columns, '$F', l_multiply )
|| '
 55                  from ' || p_atab || ' a, ( select rownum r, b.* from ' ||
                                                           p_btab || ' b ) b
 56                 group by ' || l_pks;
 57
 58
 59      execute immediate l_query;
 60  end;
 61  /

Procedure created.

tkyte@TKYTE816>
tkyte@TKYTE816> drop table results;

Table dropped.

tkyte@TKYTE816> exec proc_score( 'a', 'b', 'results' );
PL/SQL procedure successfully completed.

tkyte@TKYTE816> select * from a;

PK1 PK2 PK3         C1         C2         C3         C4
--- --- --- ---------- ---------- ---------- ----------
  1   1   1          1          1          1          1
  2   2   2          2          2          2          2
  3   3   3          3          3          3          3
  4   4   4          4          4          4          4
  5   5   5          5          5          5          5
  6   6   6          6          6          6          6
  7   7   7          7          7          7          7
  8   8   8          8          8          8          8
  9   9   9          9          9          9          9
 10  10  10         10         10         10         10

10 rows selected.

tkyte@TKYTE816> select * from b;

MODEL              C1         C2         C3         C4
---------- ---------- ---------- ---------- ----------
model1              1          1          1          1
model2              2          2          2          2
model3              3          3          3          3
model4              4          4          4          4
model5              5          5          5          5

tkyte@TKYTE816> select * from results;

PK1 PK2 PK3     MODEL1     MODEL2     MODEL3     MODEL4     MODEL5
--- --- --- ---------- ---------- ---------- ---------- ----------
  1   1   1          4          8         12         16         20
  2   2   2          8         16         24         32         40
  3   3   3         12         24         36         48         60
  4   4   4         16         32         48         64         80
  5   5   5         20         40         60         80        100
  6   6   6         24         48         72         96        120
  7   7   7         28         56         84        112        140
  8   8   8         32         64         96        128        160
  9   9   9         36         72        108        144        180
 10  10  10         40         80        120        160        200

10 rows selected.
Review & Followup
Rating: 5
May 15, 2001
Reviewer: Paul Sieczkowski from Arlington, VA

Rating: 4
what is sas January 11, 2002
Reviewer: A reader
Tom

I recently got a job enquiry and they asked me about sas.

Can you tell us something about sas, as to what it is.

And why would one convert an application from SAS to pl/sql.

what are the advantages

May 14, 2001 Alex -- Thanks for the question regarding "intermedia", version 8i
You Asked
Do you know if I can use oracle intermedia with allaire cold fusion?
and we said...
yes, anything that can connect to Oracle can use intermedia.  You interface to
it via plain old SQL.
May 14, 2001 Bhavesh -- Thanks for the question regarding "A few iAS Questions", version 1.0.2.0
You Asked
Hi Tom,
    Is there any direct way where by we can remove special characters from a
string which user gives to search the database. What I mean is that the string
may contain some special characters which may not be recognized by intermedia
and it gives some intermedia text errors. I have tried to use your urlencode
which converts all the so called bad characters into their ascii equivalent but
then the database can not search for %20 (blank etc). I have tried to remove the
trailing, leading and in between white spaces but then sometimes a few
characters cause problem. Can you suggest some solution for this.
Another problem what I am facing is while uploading a bfile. I do not know what
type of file user is going to upload. It can be a pdf, doc, xls, txt. You in one
of your solution have shown how to download the file using bfile but there we
need to specify the type of file. Is there any way where by we can find
extension of the file and then process it accordingly.
Thanks a lot in advance.
Regards

Bhavesh

------------------------Updated Info
Hi Tom,
    Thanks a lot for answering my first question. The program is working
exceptionally well, though it will take me some time to understand the wonderful
code.
I am sorry for not been able to explain the second question properly. Well the
scenerio is that one of the user who prepares the data to be shown on web needs
to upload external file (viz. pdf, xls, doc etc) into blob column of database
using Oracle Forms. Once uploaded the file can be viewed by end users on the
web. Right now I am using your following procedure to download the file.
----------------------------------------------
procedure pdf( p_id in demo.id%type )
is
    l_lob    blob;
    l_amt    number default 30;
    l_off   number default 1;
    l_raw   raw(4096);
    mimetyp  varchar2(256) ; ---:= 'application/pdf';
begin
    select mime_type, theBlob into onevar, l_lob
        from demo
         where id = p_id;

      owa_util.mime_header( mimetyp );
        begin
           loop
              dbms_lob.read( l_lob, l_amt, l_off, l_raw );

              htp.prn( utl_raw.cast_to_varchar2( l_raw ) );
              l_off := l_off+l_amt;
              l_amt := 4096;
           end loop;
        exception
           when no_data_found then
              NULL;
        end;
end;
-----------------------------------
my worry is that how can I determine the mime type of the file while it is
uploaded because if I know the mime type then only I can download the file
properly. Also if I use bfile data type instead of blob what changes will be
required to make things work ?
Your guidence in this regard will be of immense help.
Thanks a lot in advance.
Regards

Bhavesh
and we said...
urlencode is for URLENCODING.  intermedia is not url encoding!

What i use on asktom for intermedia is the following routine:

for i in 1 .. 100 loop
    exit when delimited.word( p_search_str, i, '"', ' ' ) is NULL;
    l_search_str := l_search_str || l_sep ||
                 delimited.word( p_search_str, i, '"', ' ' );
    l_sep := ' and ';
end loop;

where delimited is the package:

create or replace package delimited
as
    function word( p_str            in varchar2,
                   p_n              in varchar2,
                   p_enclosed_by    in varchar2 default '''',
                   p_separated_by   in varchar2 default ',' )
    return varchar2;

    pragma restrict_references( word, WNDS, RNDS );
end;
/

create or replace package body delimited

as
    type vcArray is table of varchar2(2000) index by binary_integer;

    g_words         vcArray;
    g_empty         vcArray;
    g_last_string   varchar2(4096);

    function de_quote( p_str in varchar2, p_enc_by in varchar2 ) return varchar2
    is
    begin
        return replace( ltrim( rtrim( p_str, p_enc_by ), p_enc_by ),
                            p_enc_by||p_enc_by, p_enc_by );
    end de_quote;

    procedure parse( p_str   in varchar2,
                     p_delim in varchar2,
                     p_sep   in varchar2 )
    is
        l_n         number  default 1;
        l_in_quote  boolean default FALSE;
        l_ch        char(1);
        l_len       number default nvl(length( p_str ),0);
        l_words     vcarray;
    begin
        if ( l_len = 0 ) then
            return;
        end if;

        l_words := g_empty;
        l_words(1) := NULL;

        for i in 1 .. l_len loop
            l_ch := substr( p_str, i, 1 );
            if ( l_ch = p_delim ) then
                l_in_quote := NOT l_in_quote;
            end if;
            if ( l_ch = p_sep AND NOT l_in_quote ) then
                l_n := l_n + 1;
                l_words(l_n) := NULL;
            else
                l_words(l_n) := l_words(l_n)||l_ch;
            end if;
        end loop;

        for i in 1 .. l_n loop
            l_words(i) := upper(replace( de_quote( l_words(i),
                                                     p_delim ), '_', '\_' ));
            l_words(i) := replace( l_words(i), '*', '\*' );
        end loop;

        for i in 1 .. l_n loop
            if ( l_words(i) not in
                          ( 'AND', 'OR', 'NOT', 'IN', 'THE', 'AS', 'IS' ) )
            then
                g_words(g_words.count+1) := '{' || l_words(i) || '}';
            end if;
        end loop;
    end parse;

    function word( p_str            in varchar2,
                   p_n              in varchar2,
                   p_enclosed_by    in varchar2 default '''',
                   p_separated_by   in varchar2 default ',' ) return varchar2
    is
    begin
        if ( g_last_string is NULL or p_str <> g_last_string ) then
            g_last_string := p_str;
            parse( p_str, p_enclosed_by, p_separated_by );
        end if;
        return g_words( p_n );
    exception
        when no_data_found then return NULL;
    end;

end delimited;
/
set define on

That will turn the input search string:
How is this going to work and why
into:
{How} and {is} and {this} and {going} and {to} and {work} and {why}

2) you would look at the file extension (.pdf, .gif, .jpg, .doc, whatever) and
keep a database table with:

extension -> mime_type

With a bfile, you must provide a directory and a filename, simply:

  select mime_type from mapping_table where extension =
                substr( filename, instr(filename,'.',-1)+1 )

that'll give you the mime type by file extension.

That is the way webservers do it -- you set up a configuration file with
extensions to mime_types and they looked at the requested file to decide what
mime type to use.
Review & Followup
Rating: 5
Just Superb May 17, 2001
Reviewer: Bhavesh from Singapore
Thanks a lot Tom. This is precisely what I was looking for.

May 15, 2001 Prakash -- Thanks for the question regarding "how to return result set from stored procedure.", version 8i
You Asked
We are developing an intranet application using Asp IIS and oracle 8i. I want to
return a resultset from oracle stored procedure to Asp page. How do I do it?
Like in sybase you say

create procedure test (parameters) resultset (col1,col2 )

Like wise what is there in Oracle to return a resultset from a procedure to an
environment outside oracle.

Thanks
Prakash
and we said...
see
http://osi.oracle.com/~tkyte/ResultSets/index.html
...
Review & Followup
Rating: 4
Return resultset from procedure. May 16, 2001
Reviewer: Prakash S. Ranade from Irvine CA USA
The information given is very elaborate and useful. It solved my problem.

Thanks

May 15, 2001 parker -- Thanks for the question regarding "foreign key declaration", version 8.1.7
You Asked
While creating a table

I delcare the foreign key as
column name   foreign key references <table> <columnname>

I have observed that even if I just say
column name  references <table> <columnname>... it establishes a relationship.

what is the difference between the two.

Further,

in one of the articles I have read that purity levels have been relaxed starting
with 8.1.7, can you expand on that.

Thanks
and we said...
If you do not use an explicit column list, Oracle will only consider the primary
key on the referenced table and will assume that is what you meant.  The one
without the column list will ALWAYS goto the primary key and not any other
unique constraint.

see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76962/ch2.htm#140922
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76939/adg10pck.htm#6048
with regards to purity rules.

May 15, 2001 parker -- Thanks for the question regarding "in,
      out, in out", version 8.1.7

      You Asked
I have been using these parameter modes for long.
But if some one asks me how does these parameters behave inside the procedure or
a function, I kind of stuck up.

Can you kindly explain me... with simple examples.

What is the copy option with the context of parmeter modes ?

Thanks

      and we said...
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:325417134618
for in / out / in out

COPY -- normally an OUT or IN OUT parameter is COPIED into a temporary buffer,
passed to the procedure, used, and then if the procedure returns without an
exception -- the temporary buffer is copied back into the original variable (so
the original variable is modified IF and ONLY IF the called procedure succeeds)

NOCOPY -- a pointer to the variable is passed.  Now, if the procedure fails with
an exception, the OUT parameters contents are sort of unstable -- the calling
procedure may or may not have modified it.

use NOCOPY if you can, much faster.
May 15, 2001 --
      Thanks for the question regarding "password file", version 8.1.7

      You Asked
I find that when we create database the password file is created in the
directory $ORACLE_HOME/dbs directory.

What is the syntax to create it manually, and what should I name it.
Is it instancename+pwd?

If the parameter remote_login_password=exclusive is uncommented, should I create
the password file , before I give the create database command?(as it is giving
me errors as I have not created the password file)

What do the two exclusive and shared mean for the parameter
remote_login_password?

Can I login from a remote client if I comment this parameter out?

Thanks

      and we said...
the name and location of this file is OS dependent.  See the OS Admin guide for
details. In general, on unix:

location = $ORACLE_HOME/dbs
name = ora$ORACLE_SID

on windows:

location = %ORACLE_HOME%\database
name = pwd%ORACLE_SID%.ora

Yes, if the remote_login_password is set, you should have created this file with
orapwd.

shared vs exclusive, see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1207835945571
You can login from a remote client without this.  this allows remote SYSDBA
connections over the network (connect internal type of connections)

May 15, 2001 -- Thanks for the question regarding "unique
      between two table.", version 8.1.6

      You Asked
tom:

I have an situation like the one below:

for example:let's say we have table
dept (deptname primary key, loc varchar2);
emp( empname primary key, address varchar2);

i know this sound silly, but we have such requirement that
deptname can't be same as emp name.

how to use trigger to enforce it?

      and we said...
create table emp_dept_unique( name varchar2 primay key ) ORGANIZATION INDEX;

create triggr dept_trigger
after insert or update or delete on dept
begin
   if (  updating or deleting ) then
      delete from emp_dept_unique where name = :old.deptname;
   end if;
   if ( updating or inserting ) then
       insert into emp_dept_unique values ( :new.deptname );
   end if;
end;
/

create triggr emp_trigger
after insert or update or delete on emp
begin
   if (  updating or deleting ) then
      delete from emp_dept_unique where name = :old.empname;
   end if;
   if ( updating or inserting ) then
       insert into emp_dept_unique values ( :new.empname );
   end if;
end;
/

that will in effect create a unique index that spans both tables.

May 15, 2001 -- Thanks for the question regarding "loading
      java classes", version 8.1.7

      You Asked
You just don't see ConnectionEvent because I sent
only a part of the error messages.
Actualy it already has been loaded.

Ivaylo

"Can you verify.  for example I see the error message:

ORA-29534: referenced object TEST.com/ibm/mq/resource/spi/ConnectionEvent

but in the list i only see:

creating : com/ibm/mq/MQObjectRecord
loading  : com/ibm/mq/resource/spi/LocalTransactionException
creating : com/ibm/mq/resource/spi/LocalTransactionException
loading  : com/ibm/mq/resource/spi/IllegalStateException
creating : com/ibm/mq/resource/spi/IllegalStateException
loading  : com/ibm/mq/MQS390PackedDecimalSupport

LocalTransactionException and IllegaStateException getting loaded? Is
ConnectionEvent in fact getting loaded and I just don't see it?
"

Hi Tom,

Thank you for your quck answer. Please find
the additional information, bellow.

First I will describe the project in a few
words.
We are trying to integrate Oracle based application
with IBM MQSeries, using Java and JMS provider for
MQSeries. The goal is to have updates to tables
immediately propagated to MQSeries as appropriate
messages. Of course one of possible solutions
is to use Java application server and EJB
to update both MQSeries and Oracle in one
transaction. But at the moment as we are
at the early stages on our EAI project we
decided to speed up the solution and use
JMS straith from a Java stored procedure in
the database. In order this to happen we
have to load the following jars:
jms.jar (it is already loaded in SYS
shema as a part of javax.*), com.ibm.mq.jar,
and com.ibm.mqjms.jar. They can be obtained
from www.ibm.com/software/ts/mqseries.
The problem arise when we try to load the last
two jars. The loadjava utility can't resolve
references to the classes in these packages,
which is very strange as they are already there.
We use Oracle 8.1.7.

Following are the command lines:

loadjava -u test/test -f -r -v com.ibm.mq.jar

or

loadjava -u sys/change_on_install -f -r -v com.ibm.mq.jar

(it doesn't matter what is the user, the result is
the same)

And this is the part of error messages:

loading  : com/ibm/mq/MQDistributionList
creating : com/ibm/mq/MQDistributionList
loading  : com/ibm/mq/MQSimpleConnectionManager$1
creating : com/ibm/mq/MQSimpleConnectionManager$1
loading  : com/ibm/mq/MQObjectRecord
creating : com/ibm/mq/MQObjectRecord
loading  : com/ibm/mq/resource/spi/LocalTransactionException
creating : com/ibm/mq/resource/spi/LocalTransactionException
loading  : com/ibm/mq/resource/spi/IllegalStateException
creating : com/ibm/mq/resource/spi/IllegalStateException
loading  : com/ibm/mq/MQS390PackedDecimalSupport
creating : com/ibm/mq/MQS390PackedDecimalSupport
loading  : com/ibm/mq/MQResponseRecord
creating : com/ibm/mq/MQResponseRecord
loading  : com/ibm/mq/MQBindingsManagedConnectionFactoryJ11
creating : com/ibm/mq/MQBindingsManagedConnectionFactoryJ11
loading  : META-INF/MANIFEST.MF
creating : META-INF/MANIFEST.MF
resolver :
resolving: com/ibm/mq/resource/spi/ConnectionEventListener
errors   :  com/ibm/mq/resource/spi/ConnectionEventListener
    ORA-29534: referenced object TEST.com/ibm/mq/resource/spi/ConnectionEvent
could not be resolved
resolving: com/ibm/mq/StoredManagedConnection
errors   :  com/ibm/mq/StoredManagedConnection
    ORA-29534: referenced object TEST.com/ibm/mq/MQSESSION could not be resolved
resolving: com/ibm/mq/MQEnvironment
errors   :  com/ibm/mq/MQEnvironment
    ORA-29534: referenced object TEST.com/ibm/mq/MQSESSION could not be resolved
resolving: com/ibm/mq/ManagedConnectionStore
errors   :  com/ibm/mq/ManagedConnectionStore
    ORA-29534: referenced object TEST.com/ibm/mq/StoredManagedConnection could
not be resolved
resolving: com/ibm/mq/MQSESSIONClient

Please note that the classes from com/ibm/mq are already
there but the references to them can't be resolved ?????

Thank you once again for your quick answer
and I hope to hear from you soon.

Ivaylo Evtimov

System Architect
Unicredito Group

I am trying to load JMS provider from IBM.
The name of the file is com.ibm.mq.jar and
every time I receive error messages that some
of the classes can't be resolved. But they
are in this jar file, I already checked this.

Regards,

Ivaylo

      and we said...
I found that some of the IBM MQ Series code (from

http://www-4.ibm.com/software/ts/mqseries/txppacs/ma88.html
 needs a few
things. I tried to load the com.ibm.mq.jar file into an 8.1.7.1 database
running on Solaris 8. Here is my output:

  > loadjava -u scott/tiger -o -r com.ibm.mq.jar
      ORA-29534: referenced object
SCOTT.com/ibm/mq/resource/spi/ConnectionEvent could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/StoredManagedConnection
could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQQueueManager could not
be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQQueueManager could not
be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQManagedConnectionJ11
could not be resolved
      ORA-29534: referenced object
SCOTT.com/ibm/mq/MQManagedConnectionFactory could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQQueueManager could not
be resolved
      ORA-29534: referenced object
SCOTT.com/ibm/mq/resource/spi/ManagedConnection could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/server/MQSESSION could
not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/server/MQSESSION could
not be resolved
      ORA-29534: referenced object
SCOTT.com/ibm/mq/resource/spi/ManagedConnectionFactory could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQEnvironment could not
be resolved
      ORA-29534: referenced object
SCOTT.com/ibm/mq/MQBindingsManagedConnectionFactory could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQQueueManager could not
be resolved
      ORA-29521: referenced name javax/security/auth/Subject could not be
found
      ORA-29521: referenced name javax/security/auth/Subject could not be
found
      ORA-29534: referenced object SCOTT.com/ibm/mq/ManagedConnectionStore
could not be resolved
      ORA-29534: referenced object
SCOTT.com/ibm/mq/MQSimpleConnectionManager could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQEnvironment could not
be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQEnvironment could not
be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQQueueManager could not
be resolved
      ORA-29534: referenced object
SCOTT.com/ibm/mq/resource/spi/ManagedConnectionFactory could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQManagedConnectionJ11
could not be resolved
      ORA-29521: referenced name javax/security/auth/Subject could not be
found
      ORA-29521: referenced name javax/security/auth/Subject could not be
found
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQQueueManager could not
be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQEnvironment could not
be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29521: referenced name javax/security/auth/Subject could not be
found
      ORA-29521: referenced name javax/security/auth/Subject could not be
found
      ORA-29534: referenced object SCOTT.com/ibm/mq/StoredManagedConnection
could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQManagedConnection
could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQManagedConnection
could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQManagedConnectionJ11
could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQEnvironment could not
be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQOD could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQQueueManager could not
be resolved
      ORA-29534: referenced object
SCOTT.com/ibm/mq/MQSimpleConnectionManager could not be resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
      ORA-29534: referenced object SCOTT.com/ibm/mq/MQManagedConnection
could not be resolved
  loadjava: 49 errors

Here is the same list with all duplicated removed:

    ORA-29534: referenced object SCOTT.com/ibm/mq/StoredManagedConnection
could not be resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/server/MQSESSION could not
be resolved
    ORA-29534: referenced object
SCOTT.com/ibm/mq/resource/spi/ManagedConnectionFactory could not be resolved
    ORA-29534: referenced object
SCOTT.com/ibm/mq/resource/spi/ManagedConnection could not be resolved
    ORA-29534: referenced object
SCOTT.com/ibm/mq/resource/spi/ConnectionEvent could not be resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/MQSimpleConnectionManager
could not be resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/MQSESSION could not be
resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/MQQueueManager could not
be resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/MQOD could not be resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/MQManagedConnectionJ11
could not be resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/MQManagedConnectionFactory
could not be resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/MQManagedConnection could
not be resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/MQEnvironment could not be
resolved
    ORA-29534: referenced object
SCOTT.com/ibm/mq/MQBindingsManagedConnectionFactory could not be resolved
    ORA-29534: referenced object SCOTT.com/ibm/mq/ManagedConnectionStore
could not be resolved
    ORA-29521: referenced name javax/security/auth/Subject could not be
found

It looks similar to yours. One of the classes you are having trouble with is
com/ibm/mq/resource/spi/ConnectionEvent. Incidentally, you can list all
classes that need resolving by running:

    select dbms_java.longname(object_name)
    from   user_objects
    where  object_type = 'JAVA CLASS'
    and    status = 'INVALID';

I attempted to manually resolve the class by running something like this:

  SQL> alter java class "com/ibm/mq/resource/spi/ConnectionEvent" resolve;

  Warning: Java altered with compilation errors.

  SQL> show errors
  Errors for JAVA CLASS /4c02fb7e_ConnectionEvent:

  LINE/COL ERROR
  -------- -----------------------------------------------------------------
-------------------------------------------------------
  0/0      ORA-29534: referenced object
SCOTT.com/ibm/mq/resource/spi/ManagedConnection could not be resolved
  SQL> alter java class "com/ibm/mq/resource/spi/ManagedConnection" resolve;

  Warning: Java altered with compilation errors.

  SQL> show errors
  Errors for JAVA CLASS /d6739f5a_ManagedConnection:

  LINE/COL ERROR
  -------- -----------------------------------------------------------------
-------------------------------------------------------
  0/0      ORA-29534: referenced object SCOTT.javax/security/auth/Subject
could not be resolved
  SQL> alter java class "javax/security/auth/Subject" resolve;

  Warning: Java altered with compilation errors.

  SQL> alter java class "javax/security/auth/Subject" resolve;

  Warning: Java altered with compilation errors.

  SQL> show errors
  Errors for JAVA CLASS javax/security/auth/Subject:

  LINE/COL ERROR
  -------- -----------------------------------------------------------------
-------------------------------------------------------
  0/0      ORA-29534: referenced object SCOTT.javax/security/auth/Subject$3
could not be resolved
  SQL> alter java class "javax/security/auth/Subject$3" resolve;

  Warning: Java altered with compilation errors.

  SQL> show errors
  Errors for JAVA CLASS javax/security/auth/Subject$3:

  LINE/COL ERROR
  -------- -----------------------------------------------------------------
-------------------------------------------------------
  0/0      ORA-29521: referenced name java/security/DomainCombiner could not
be found
  SQL>

Notice that when I was chasing this down, I needed a package named
javax.security.auth. Where did I get that? How come you won't see it in your
Oracle database? It's because it's part of Sun's "Java Authentication and
Authorization Service (JAAS) 1.0". It's located at

http://java.sun.com/products/jaas/
Next, I loaded the JAAS.JAR file. I
didn't get far since it also required a few things. One of the required
classes is java.security.DomainCombiner but, unfortunately, this is only
available in JDK 1.3. I looked in the SYS schema (where all the JDK classes
reside) of my database and there is no DomainCombiner class. If interested,
check out the following references on the security API in JDK 1.2 and 1.3:

http://java.sun.com/products/jdk/1.2/docs/api/java/security/package-summary
html

http://java.sun.com/j2se/1.3/docs/api/java/security/package-summary.html

You might be saying, "I never saw anything in the IBM MQ Series
'requirements' section of the documentation that said I needed J2EE or JDK
1.3". I said that too. It seemed to only talk about JDK 1.2 stuff. I had to
read the document titled "Using Java" from
ftp://ftp.software.ibm.com/software/ts/mqseries/library/books/csqzaw06.pdf.
It was a link from the first IBM MQ Series web page listed above. Chapter 3
has this to say about connection-related stuff:

    Under Java 2 v1.3, with JAAS 1.0 installed, applications and middleware
providers
    can provide alternative implementations of connection pools. MQ base Java
    provides a partial implementation of the J2EE Connector Architecture.
    Implementations of javax.resource.spi.ConnectionManager can either be used
as
    the default Connection Manager or be specified on the MQQueueManager
    constructor.

    MQ base Java complies with the Connection Management contract of the J2EE
    Connector Architecture. Please read this section in conjunction with the
Connection
    Management contract of the J2EE Connector Architecture (refer to Sun’s Web
site at

http://java.sun.com/
.

This was all I did to fix the first un-resolvable IBM MQ Series class. I'm
sure there will be a lot more dependencies going forward. However, some will
go away since they depend on that ConnectionEvent class. I'm not saying that
it cannot be done but I think it could be time consuming since it **might**
amount to replacing or "overriding" some (or all) of the Oracle-provided JDK
classes. From the IBM documents, it sounds like their connection manager is
optional. Maybe you can just ignore those classes that do not resolve?
Probably not.

Review &
      Followup

      Rating:
      5
  November 25, 2003
Reviewer:
      Randall  from STL
Tom,  Thanks for the help.  We are also trying to do this.  I am working through
the resolve and came across something that I cannot figure out.  Some of the
required classes are under java/security/*.  We created a jar file with this
branch and tried to load under our application schema.  But got the error like
below for anything under java/security:

loading  : java/security/Permission
creating : java/security/Permission
Error while creating class java/security/Permission
    ORA-29545: badly formed class: User has attempted to load a class
(java.security.Permission) into a restricted package. Permission can be granted
using  dbms_java.grant_permission(<user>, LoadClassInPackage...

It also could not resolve items that existed under sys like the following

resolving: java/security/GuardedObject
Error while resolving class java/security/GuardedObject
    ORA-04043: object java/security/GuardedObject does not exist

So two questions,

1.  Can I load java/security/*  classes under my app schema to use those instead
of the system ones?  And if so what permissions do I need to grant the user?  It
currently has CONNECT, RESOURCE.

2.  Should the jars I load under my schema be able to resolve if they have
references to classes not in my schema but under sys?  And if so, do you need to
grant any right to use reference them.

Thanks for your time

May 15, 2001 Murali -- Thanks for the question regarding "Cold
      backup", version 8.1.6.0.0

      You Asked
I am scheduling backups, preferably the cold one on a WinNtserver4.0(sp6) .
Before backing the imp.files(dbf,ctl,log)I have to shut the database in a clean
state.
I am doing this thru svrmgrl by using connect internal/oracle.
I am getting the error as follows: Insufficient Privellige.
 I would also like to know if the whole volume(D for eg) where Oracle is
installed is to be backed up on a daily(nightly) bais.

Thanks for your time.

      and we said...
Well, i would recommend a hot backup, it is really not any harder to restore
with or to accomplish and the performance of your database will be better (you
won't start out cold everytime you backup)..

Anyway, the connect internal issue is purely a privelege issue at the OS level,
your OS account is not allowed to connect internal.  What you could do is
either:

o use an account that is privileged enough to do this (eg the account that runs
the database in the first place)

o grant SYSDBA to some other user and use that account.  Make sure you have
setup a password file using ORAPWD in the proper location with the correct name
and have set the remote_login_passwordfile init.ora parameter.  See your OS
admin guide for details.  then, loging using "username/password AS SYSDBA"

Backup volume D as you see fit.  I cannot tell you if you need to back it up or
not.  If you make configuration changes to the init.ora and such, yes, you
should back it up.
Review & Followup

      Rating: 3
Some
      comment  May 17, 2001
Reviewer:  Tamas
      Szecsy  from Hungary
With some versions of server manager you get this message also if your misstyped
your password.

      Rating:
      4
Coldbackup  May 18, 2001
Reviewer:
      Murali
Thanks so much for your timely reply.

May 15, 2001 -- Thanks for the question regarding "How to
      extract a value from a buffer delimited by %?", version 8i

      You Asked
Hi Tom,
I would like to extract the value 123, ABCDEF, US Dollar etc from a buffer
delimited by %:

  123%ABCDEF%US Dollar%.....

Is there any functions I can use to do this other than substr()?

Thank you.
Jesse

      and we said...
There is nothing builtin besides instr and substr.  What I do is use Object
types (a nested table collection specifically).  the nice thing about this is
that I can either tokenize the string into PLSQL variable and use it like an
array OR i can use it in a SQL statement and "select * from the_string" as if it
were a table (nice for subqueries and other things).

Here is an example:

tkyte@TKYTE816> create or replace type myScalarType
  2  as object
  3  ( idx number, word varchar2(4000) )
  4  /
Type created.

tkyte@TKYTE816> create or replace type myArrayType
  2  as table of myScalarType
  3  /
Type created.

tkyte@TKYTE816> create or replace
  2  function tokenize( p_str in varchar2,
  3                     p_sep in varchar2 default '%' )
  4  return myArrayType
  5  as
  6      l_data myArrayType := myArrayType();
  7      l_str  long := rtrim(p_str,p_sep) || p_sep;
  8      l_piece varchar2(4000);
  9  begin
 10      loop
 11          exit when l_str IS NULL;
 12          l_data.extend();
 13
 14          l_piece := substr( l_str,1,instr(l_str,p_sep)-1 );
 15          l_str   := substr( l_str,instr(l_str,p_sep)+1 );
 16
 17          l_data(l_data.count) := myScalarType(l_data.count,l_piece);
 18      end loop;
 19      return l_data;
 20  end;
 21  /
Function created.

tkyte@TKYTE816> variable str varchar2(250)
tkyte@TKYTE816> exec :str := '123%ABCDEF%US Dollar';
PL/SQL procedure successfully completed.

tkyte@TKYTE816> declare
  2      l_words  myArrayType;
  3  begin
  4      l_words := tokenize( :str );
  5
  6      for i in 1 .. l_words.count
  7      loop
  8          dbms_output.put_line( 'word('||i||') = ' || l_words(i).word );
  9      end loop;
 10  end;
 11  /
word(1) = 123
word(2) = ABCDEF
word(3) = US Dollar

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816> select *
  2    from TABLE( cast( tokenize( :str ) as myArrayType ) )
  3  /

       IDX WORD
---------- --------------------
         1 123
         2 ABCDEF
         3 US Dollar

tkyte@TKYTE816>
Review & Followup

      Rating: 5
Nice
      Stuff  May 16, 2001
Reviewer:  VJ  from
      Boston, MA USA

      Rating: 4
very
      useful  May 17, 2001
Reviewer:  ashraf
       from kuwait
very useful title

May 15, 2001 Shanmugam -- Thanks for the question regarding
      "Wrapping Utility", version 8.1.6.2

      You Asked
How to Wrap a set of Packages using Wrapping Utility.

For E.g,

        Suppose I am Having 50 Packages. In each i am having more than one
procedures and functions. I want to wrap this 50 Packages using Wrapping
Utility.

Please explain Detail.

Thanks,

With Regards,
Shanmugam

      and we said...
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a77069/c_wrap.htm#1859
explains this utility in detail.
May
      15, 2001 reddi -- Thanks for the
      question regarding "How can I user the same lov for 2 items", version
      forms 6i

      You Asked
Tom

I have been told that we can use use the same lov for 2 items in a form? How can
we do that?

Kindly explain?

Thanks

      and we said...
Just assign the LOV to the same item.  It is that easy if you are using the LOV
to validate the item.

If you want the value returned to a field, you would set up a control block
(non-database block) with some item say lov_text on it.  Then, have the LOV
return its value there.  On each item that should "share" this lov, code
something like:

:control.lov_text := null;
list_values;
if ( :control.lov_text is not null ) then
    :dept.deptno := :control.lov_text;
end if;

in a key-listval trigger.
Review & Followup

      Rating: 5
Reusing a
      LOV  May 16, 2001
Reviewer:  Robert
       from San Diego
I also return LOV values to global variables.

      Rating: 4
Global
      Variables  May 17, 2001
Reviewer:  Asif
      Momen  from Riyadh
Hi Tom,

  We can as well use Global Variables.

      Rating: 3
Form Item is
      better  May 17, 2001
Reviewer:  Pichaimani
      Balasubramanian  from San Jose, CA, USA
Hi Tom,
   I agree with you as using Global variables has limited scope.
   1) It occupies more memory.
   2) You can store explicitly only 255 characters
   3) With a Form Item you can store more as well as it occupies less memory.
   Go for the Global variable only if you have to share the value between
multiple forms.

May 15, 2001 -- Thanks for the question regarding "How to
      dynamically update a remote table using 'where current of l_cursor'?",
      version 8i

      You Asked
Hi Tom,

My objectives are:
1. select * from remotetable@dblink for update (parse & open a cursor l_cursor)
2. update remotetable@dblink set flag='Y' where current of :l_cursor

I try to use dbms_sql.bind_variable (l_cursor2, ':l_cursor', l_cursor);

but it doesn't work. How can I resolve this problem?

Thank you.

Regards,
Jesse

      and we said...
It won't work that way.  the for update where current of works with static SQL
in PLSQL only.  There is no concept of "binding" a cursor with either native
dynamic sql or dbms_sql.

You should code:

  'select rowid rid, a.* from remotetable@dblink a for update'

and later:

  'update remotetable@dblink set .... where rowid = :rid'

and bind the rowid in.
May 16,
      2001 parker -- Thanks for the question
      regarding "disable constraint cascade", version 8.1.7

      You Asked
Tom

When I do a alter table <name> disable primary  cascade on a table , it will
disable all the primary key , as also all the refercing columns from other
table. I have tried this successfully.

Now when I enable the same primary key, will the referencing key constraints in
other tables , get enabled automatically, or should I enable those keys
manually.

Thanks

      and we said...
you have to re-enable the child constraints manually:

tkyte@TKYTE816> create table p ( x int constraint p_pk primary key );

Table created.

tkyte@TKYTE816> create table c ( x constraint c_fk_to_p references p );

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> alter table p disable constraint p_pk cascade;

Table altered.

tkyte@TKYTE816>
tkyte@TKYTE816> select constraint_name, status from user_constraints;

CONSTRAINT_NAME                STATUS
------------------------------ --------
C_FK_TO_P                      DISABLED
P_PK                           DISABLED

tkyte@TKYTE816>
tkyte@TKYTE816> alter table p enable constraint p_pk ;

Table altered.

tkyte@TKYTE816> select constraint_name, status from user_constraints;

CONSTRAINT_NAME                STATUS
------------------------------ --------
C_FK_TO_P                      DISABLED
P_PK                           ENABLED

May 16, 2001 Luis -- Thanks for the question regarding "Assign
      More Space To a Table", version oracle 8i

      You Asked
    Hi, i need to know how to assign more space to a table that is full now.  Im
not really a DBA but the database is under my responsability now.  The OS is
Windows NT server 4.0 and the database is oracle 8i.
    When i tried to make an insert i got the following message:

SQLException: ORA-01653: unable to extend table CLORAS.COMPRAS by 92169 in
tablespace DATA

      and we said...
You need to add space to a file in that tablespace.

Here is what you do.  first query:

tkyte@DEV2.THINK.COM> select file_name, trunc(bytes/1024/1024)
  2  from dba_data_files
  3  where tablespace_name = 'DATA';

FILE_NAME                         TRUNC(BYTES/1024/1024)
------------------------------    ----------------------
/d02/oradata/DEV2/DEV2_misc01.dbf                     68

there may be more then one file listed there, thats OK, just pick one and then:

tkyte@DEV2.THINK.COM> alter database
  2  datafile '/d02/oradata/DEV2/DEV2_misc01.dbf'
  3  resize 70m;

Database altered.

resize it bigger, now you should see:

tkyte@DEV2.THINK.COM> select file_name, trunc(bytes/1024/1024)
  2  from dba_data_files
  3  where tablespace_name = 'DATA';

FILE_NAME                           TRUNC(BYTES/1024/1024)
------------------------------     ----------------------
/d02/oradata/DEV2/DEV2_misc01.dbf                      70

Review &
      Followup

      Rating: 5
Resizing a
      Tablespace  May 16, 2001
Reviewer:  Robert
       from San Diego
Great!
I used to just add datafiles.

      Rating:
      5
sorry  May 16, 2001
Reviewer:  Luis
      Eduardo  from Chile
    I made a mistake  when following your instructions,but i saw it, and after,
voilà.  Im not good with the english, your answer was really useful, thanks you
very much

      Rating:
      5
  May 17, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

      Rating: 4
Resizing a
      Tablespace   December 14, 2001
Reviewer:
      MELODY  from CA
THANK YOU FOR ANSWERING THIS QUESTION SO WELL.

May 16, 2001 Gregory -- Thanks for the question regarding
      "Calling API from stored procedure", version oracle 8

      You Asked
How do I call an API from a stored procedure?  The oracle data base instance is
on a UNIX platform.  We need to call an API that will bridge to a Bull mainframe
and do data base retrieval against the Bull data base.  That part is working.
What I need to know is how to invoke the call to the API from an Oracle
procedure.  Thank you.

The API is written in C.
The Oracle Data Base is version 8.0.5.1.0

      and we said...
External procedures:

http://technet.oracle.com/doc/server.804/a58236/10_procs.htm#433731
....
May 16, 2001 -- Thanks for the question regarding "Log Switch
      Waits", version 8.1.6

      You Asked
I am in the process of diagnosing a problem with our OLTP system and have a
question regarding the actual process of switching redo logs. My question is,
does LGWR continue on writing to the next redo log group after the switch
occurs? Or does LGWR wait until the CKPT process finishes writing out the dirty
buffers from the database buffer cache? Or does LGWR wait until both, the CKPT
and ARCH, processes finish doing their job before moving on to the next redo log
group?

I have noticed that "log switch wait time" has become an issue and am wondering
how the actual process of log switching occurs. Let me thank you ahead of time,
as usual, for any information you may have concerning this issue.

      and we said...
lgwr keeps on going.  a log switch is one of the many times that a checkpoint is
initiated but a log switch does NOT wait for a checkpoint to complete.

What will wait for a checkpoint to complete is a log switch into a redo log file
whose checkpoint has not completed.

If you have lots of

"checkpoint not complete, cannot allocate new log"
"archival not complete, cannot allocate new log"

messages in your init.ora file -- you have not configured sufficient online redo
log and need to add more.

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:69012348056
for details.

Review &
      Followup

      Rating: 4
Nice discussion
      of what goes on around log switch/checkpoint  June 13, 2001

Reviewer:  Peter Hitchmough  from Macclesfield UK

      Rating: 1
Log
      Swiching  October 04, 2001
Reviewer:  Daniel
       from India
In any of the description, you are not mentioning the solution, just saying
adjust parameter, we need a example kind of description, like for 20-100GB
database this could
be the problem.  For fast import what is the criteria, I am
serching for fast import. which is not available related ot
redo logs.

May 17, 2001 Nagaraju -- Thanks for the question regarding
      "any datatype to store milli seconds", version 8.1.6

      You Asked
tom,
1.i asked a question about adding a milli second to a date.
  and got the answer, we cannot as it stores only till seconds.
  is there any other data type that stores milliseconds as well.

2.can you please tell me the significance of
  set verify off/on
  set termout off/on
  set define off/on

3.i asked you how to write the source code of various procedures,packages to
  a file name, you gave me a link, there i got the necessary files
  i.e. getcode, getallcode. in getcode.sql  i don't fully understand following
query in that

   select decode( type||'-'||to_char(line,'fm99999'),
                  'PACKAGE BODY-1', '/'||chr(10),
                   null) ||
          decode(line,1,'create or replace ', '' ) ||
          text text
     from user_source
    where name = upper('&&1')
    order by type, line;

   everything is fine, why is that first decode and the functions inside
that.can you explain it

nagaraju

      and we said...
1) besides a STRING or a NUMBER -- populated by a callout to a java stored
procedure or C, no.  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:341817437103
for both.

2)

ops$tkyte@ORA8I.WORLD> set verify on
ops$tkyte@ORA8I.WORLD> define x=foo
ops$tkyte@ORA8I.WORLD> select '&x' from dual;
old   1: select '&x' from dual
new   1: select 'foo' from dual

'FO
---
foo

ops$tkyte@ORA8I.WORLD> set verify off
ops$tkyte@ORA8I.WORLD> select '&x' from dual;

'FO
---
foo

ops$tkyte@ORA8I.WORLD> set define OFF
ops$tkyte@ORA8I.WORLD> select '&x' from dual;

'&
--
&x

ops$tkyte@ORA8I.WORLD>

set termout off makes it so sqlplus doesn't display anything on screen when
spooling to a file.

3) the
decode( type||'-'||to_char(line,'fm99999'),
                  'PACKAGE BODY-1', '/'||chr(10),
                   null) ||
          decode(line,1,'create or replace ', '' )

is the same as:

   if ( type||'-'||to_char(line,'fm99999') = 'PACKAGE BODY-1' )
   then
       output /
   end if;
   if ( line = 1 )
   then
       output "create or replace"
   end if;

That makes it so the first line of code starts with CREATE OR REPLACE and if it
is the first line of the package body -- output the / to run the specification
we just spooled out before we put out the create or replace

May 17, 2001 Ravindra -- Thanks for the question regarding
      "How to remove the archive files automatically ", version 8i R8.1.7

      You Asked
How I can remove the archive files automatically in WinNT. I am taking backup
everynight of all the archive files.Next morning I need to remove them
manully??? If you have any tip to automate this Process please do share with me.

Here is the other information:

Datebase: Oracle8i R8.1.7
OS: WinNT
Database Size : 50GB(Approx)
Archive Log: True

      and we said...
Well, I would want to make it part of the BACKUP process.  What happens if the
backup fails and you "automatically" erase them?

You can use the NT at/cron facility to automatically do it -- but -- it would
best be incorporated into the backup scripts themselves.
Review &
      Followup

      Rating:
      3
  May 18, 2001
Reviewer:  Ravindra
       from Detroit,MI(USA)

May 17, 2001 Vinnie -- Thanks for the question regarding
      "Select statements in a Declare", version 8.1.5

      You Asked
How can I assign a variable a default value using a SELECT?

Example:

var1   VARCHAR2(20) default SELECT xxx from temp where xxx = 1;

      and we said...
tkyte@TKYTE816> variable x varchar2(20);

tkyte@TKYTE816> begin select 1 into :x from dual; end;
  2  /

PL/SQL procedure successfully completed.

tkyte@TKYTE816> print x

X
--------------------------------
1

is the way to do accomplish that.
May
      17, 2001 Amanullah -- Thanks for the
      question regarding "Adding a tablespace", version 8.0.3.0.0

      You Asked
hi,
   Tom,
       I have a tablespace with four datafile as a backup
of database1. My database1 is now no longer exist.
I have created another database2 and now I would like to
add tablespace with four datafile(previous database file)
into the new database.Is this is possible in Version 8.0.3.0.0?

      and we said...
You cannot take the datafiles from one database and put them onto another
database.

In Oracle8i release 8.1 and up, we did add transportable tablespaces which
permits this IF and only IF you exported the datafiles properly.

In 8.0, you cannot do this.
May 17,
      2001 M -- Thanks for the question
      regarding "Problem to create a system trigger", version 8.1.7

      You Asked
Hi there,

I had trouble to create a system trigger. The following shows how it happened.

Connected with USER1

SQL> create or replace trigger CREATE_TABLE
 2 after create on USER1.schema
 3 declare
 4 sql_stmt varchar2(100);
 5 begin
 6 if ora_dict_obj_type = 'TABLE' then
 7 sql_stmt := 'grant select on ' || ora_dict_obj_name || ' to USER2';
 8 execute immediate sql_stmt;
 9 end if;
10 end;
11 /

Trigger created.

SQL> create table test (a varchar2(10));
create table test (a varchar2(10))
*
ERROR at line1:
ORA-00604: error occurred at recursive SQL level 1
ORA-30511: invalid DDL operation in system triggers
ORA-06512: at line 6

Thanks for any help

      and we said...
Grant is DDL.
Triggers cannot commit.
DDL commits.

You cannot do that.  Even if you coded that as an AUTONOMOUS transaction (see

http://osi.oracle.com/~tkyte/autonomous/index.html
it would not work since when the trigger fires -- the object does not really
truly exist yet -- the autonomous transaction would have nothing to grant on.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:646423863863
for my suggested method of doing this.
May 17, 2001 Sreenu -- Thanks for the question regarding
      "Totals in Hierarchy", version 7.3

      You Asked
In the following question U have given a query for
finding the totals for each level of the hierarchy.

I suppose, that will work only in latest versions of oracle.

http://asktom.oracle.com/pls/ask/f?p=4950:8:98430::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:598170615803,
Can U please advise how to do the same in the earlier versions
in which sub-queries are not allowed in the columns.

Thanks in Advance

      and we said...
You would use a PLSQL function called from SQL such as this:

create or replace function get_data(  p_sub in varchar2 ) return number
as
    l_amt number;
begin
     select sum(amount) into l_amt
       from test  t2
      where t2.main = p_sub
         or t2.main in ( select nvl(t3.sub ,'xx')
                           from test t3
                          where t3.main = nvl(p_sub,test.main)
                            and t3.sub is not null);
    return l_amt;
end;
/

select decode( level, 1, get_data( test.sub ), amount ) amt
  from ....
Review & Followup

      Rating: 2
Please read
      on...  May 19, 2001
Reviewer:  Sreenu
       from singapore
So, the answer makes me guess it can't be done in sql straightly. Actually, I
also wrote a function something like that. But, what made me concern over is
that it was executing very slow. Thats why I wanted something in straight SQL.
Sometimes I feel like hardcoding the heirarchy into tables.

Thanks

May 17, 2001 -- Thanks for the question regarding "OCM and
      pool", version 8.1.6

      You Asked
what's relationship between oracle connection manager and connection pool? is it
the same thing ? or different thing but for the same purpose.

when should use which?

      and we said...
Oracle Connection Manager is a router through which a client connection request
may be sent either to its next hop or directly to the database server. Clients
who route their connection requests through a Connection Manager can then take
advantage of the connection concentration, Net8 access control, or
multi-protocol support features configured on that Connection Manager.

Connection pooling is a resource utilization and user scalability feature of MTS
that enables you to maximize the number of network sessions over a limited
number of connections to a dispatcher. This is achieved by sharing or pooling a
set of connections.

they are very different.  See

http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/toc.htm
for details.

May 17, 2001 James -- Thanks for the question regarding
      "Default NUMBER precision", version 8.1.6

      You Asked
When NUMBER column is created using DBA Studio, there is no precision.  It comes
out finally with NUMBER(38) when I double check.

I think this is not a good practice.  A NUMBER column with precision 38 will
consume more system resource during processing than a column with precision 5.
Am I right?  By the way, is there any way to limit the default precision in DBA
Studio or database?

Rgds
James

      and we said...
No, a number(38) will not consume any more storage then a number(5) UNLESS You
put a number in it that will not FIT in the number(5).

Numbers are stored as varying length, OS independent numbers.  A number takes
between 0 and 22 bytes to store.  the precision and scale are simply EDITS on
the number, the number(5) cannot store the number 123456 whereas the number(38)
can.

It will not consume any more or less storage.

I do not know of anyway to change the default precision.
Review &
      Followup

      Rating: 4
Review :
      Default NUMBER precision  May 18, 2001
Reviewer:
      A reader  from HK

May 18, 2001 Carlos -- Thanks for the question regarding
      "Explain Plan", version oracle 8i

      You Asked
 I need to know like placing the instruction " Explain plan " in a stored
procedure, so that this it does not accept it.
Thank you very much

      and we said...
  1  begin
  2     execute immediate
  3     'explain plan set statement_id = ''x'' into plan_table for
  4      select * from emp';
  5* end;
ops$tkyte@ORA8I.WORLD> /

PL/SQL procedure successfully completed.

if you are trying to TUNE your sql in plsql, a better method would be to use
tkprof

http://asktom.oracle.com/~tkyte/tkprof.html
May 18, 2001 -- Thanks for the question regarding "Passing a
      Unknown # of Arguments to a Procedure ", version 8i

      You Asked
In PL/SQL can you pass a unknown number of arguments to a procedure?

      and we said...
You would use a collection type -- either a VARRAY, NESTED TABLE or even a PLSQL
Table type.  For example:

ops$tkyte@ORA8I.WORLD> create type myArgType as table of varchar2(4000)
  2  /

Type created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create or replace procedure flexible( x in myArgType )
  2  as
  3  begin
  4          for i in 1 .. x.count loop
  5                  dbms_output.put_line( x(i) );
  6          end loop;
  7  end;
  8  /

Procedure created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> exec flexible( myArgType( 'a', 'b', 'c' ) );
a
b
c

PL/SQL procedure successfully completed.

May 18, 2001 Sandip -- Thanks for the question regarding "To
      Select the columns on the fly having not null data......", version 8.1.6

      You Asked
Hi! Tom,
    We have a problem of modifying our "Create table as Select * from
table_name" syntax used to load data from tables.
    I know that I have some columns in the table which does not have any data at
all. Can I write a Select which will intelligently select only those columns
which have data and eliminate those which have all null data in that column,
without me explicitly naming the columns. The reason is a lot of table with a
lot of columns need to be done and I don't want to find out by looking at the
data that a particular column in a table has all null data.
       Please suggest if it can be done by any way.
Would appreciate quick response.

 thanks in advance,
    Sandip

      and we said...
That would be a neat trick -- "create table as select <all columns that contain
data> from another_table".  If you don't know what columns are all null -- how
could we?  We would both need to read the table first....

If you analyze the table, we can tell you the columns that contain data:

ops$tkyte@ORA8I.WORLD> create table t ( a int, b int, c int );

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into t values ( 1, 1, null );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1, null, null );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1, null, null );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1, null, null );

1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( null, null, null );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> analyze table t compute statistics;

Table analyzed.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select column_name
  2    from user_tab_columns
  3   where table_name = 'T'
  4     and ( low_value is not null or high_value is not null )
  5  /

COLUMN_NAME
------------------------------
A
B

you would use that output to generate you CREATE TABLE.
Review &
      Followup

      Rating: 4
Neat Trick
      ...  May 18, 2001
Reviewer:  Sandip
       from Cincinnati, OH
That was good and easy. It helped me to construct the SQL on the fly for not
null columns.

      Rating:
      4
Excellent  May 20, 2001
Reviewer:
      Pichaimani Balasubramanian  from San Jose, CA

      Rating:
      4
Excellent  May 20, 2001
Reviewer:
      Pichaimani Balasubramanian  from San Jose, CA

May 18, 2001 Azman -- Thanks for the question regarding
      "Executing oracle procedure from C", version 8.1.6

      You Asked
Hi Tom,
Currently I've a third party software that need to interface with Oracle rdbms.
Th eproblem is that this software could only issued a limited sql statement such
update, delect, insert. It cannot issued a 'execute' command. We now have a
requirement for this systems to execute a stored procedure. What do you this is
the best method of doing it given its limitations.

The software can also activate a external C program. Is it possible to write a C
program that could connect to Oracle a activate the stored procedure?

Your response is much appreciated.

      and we said...
EXECUTE is a sqlplus'ism -- its not really a sql command.

EXEC p

is just shorthand for:

begin p; end;

so you might try having your environment execute that "begin p; end;" and see
what it does.

If it cannot, then lets say you have a procedure:

ops$tkyte@ORA8I.WORLD> create or replace
  2  procedure p( arg1 in number,
  3               arg2 in out date,
  4               arg3 out varchar2 )
  5  as
  6  begin
  7          arg2 := arg2+arg1;
  8          arg3 := to_char( arg2, 'dd-mon-yyyy hh24:mi:ss' );
  9  end;
 10  /
Procedure created.

that you want to call... you can create an interface table:

ops$tkyte@ORA8I.WORLD> create global temporary table p_arguments
  2  ( arg1 number,
  3    arg2 date,
  4    arg3 varchar2(20)
  5  )
  6  on commit delete rows
  7  /
Table created.

With a trigger on it:

ops$tkyte@ORA8I.WORLD> create or replace trigger p_trigger
  2  before insert on p_arguments
  3  for each row
  4  begin
  5          p( :new.arg1, :new.arg2, :new.arg3 );
  6  end;
  7  /

Trigger created.

so that the act of inserting into this table does this:

ops$tkyte@ORA8I.WORLD> insert into p_arguments values ( 1, sysdate, null );
1 row created.

ops$tkyte@ORA8I.WORLD> select * from p_arguments;

      ARG1 ARG2      ARG3
---------- --------- --------------------
         1 19-MAY-01 19-may-2001 13:40:41

May 18, 2001 Andy -- Thanks for the question regarding
      "Locking records...", version 8i

      You Asked
Hi Tom,

  I have the following question:

    In PL/SQL, when I issue a select statement to lock some records (i.e: select
* from table_A where column_A is null for update nowait;), the records are
locked until the next commit or rollback statement.

  However, if I have two sessions opened, session A issue the following
statement: (select * from emp where emp_id = 1234 for update nowait;), then
session B issue the statement: (update emp set emp_name = 'JOHN' where emp_id =
1234;), session B will execute the update statement by the time session A issues
a commit or rollback.

  My question is: Assuming session B is waiting for the record, is there a way
for session A to continue locking the record even after a commit or rollback
statement is issued?  That is, not giving the chance for session B to lock the
record.

Thanks in advance!!!

Andy Woo.

      and we said...
No, end of transaction implies end of transaction.  Locks are gone, given up.
Enqueues are given on a first come first serve basis -- so there is no way for
your session to get in front of the UPDATE that is waiting.
Review &
      Followup

      Rating:
      4
  May 19, 2001
Reviewer:  Andy
       from Hong Kong

May 18, 2001 Stalin Kumar -- Thanks for the question regarding
      "savepoints with select for update clause", version 8.1.6 Standard Edition

      You Asked
I find a strange behaviour with rollback and rollback to savepoint statements.
Do i miss anything or is this normal ?

Problem explanation

In Session 1,

sql> savepoint session_a;

sql> select column1 from table_a where column2 = 'x' for update;
Now i acquire a row share locks on the rows the above select returns which is 2
rows.

Open another Session 2,

sql> savepoint session_a;

Issue the same select as in Session 1
sql> select column1 from table_a where column2 = 'x' for update;

Now this select hangs bcoz the rows are being locked by Session 1, which is
normal.

but on issuing rollback on Session 1, am able to get 2 rows returned on Session
2 whereas if i issue rollback to session_a on Session 1, still the locks arent
released and the select hangs in Session 2.

As far as the oracle docs says..whether i give rollback or rollback to
savepoints, oracle releases any locks that got acquired within the transaction
or the savepoints.

So what i see here is totally different from what oracle says...

Any thoughts..

-Stalin

      and we said...
It does in fact release the locks.  the problem is the manner in which you coded
your test.  Do this, open 3 windows.  Then do the following:

time     session 1                session   2             session 3
t1       savepoint sa;

t2       select *
         from emp
         where ename = 'KING'
         FOR UPDATE;

t3                               select *
                                 from emp
                                 where ename = 'KING'
                                 FOR UPDATE;
                                 This blocks!

t4       rollback to sa;         This is still blocked

t5                                                        select *
                                                          from emp
                                                          where ename = 'KING'
                                                          FOR UPDATE;
                                                          This is NOT
blocked!

You see -- the second session is blocked on the transaction in the first session
-- not a row of that transaction but the transaction itself.  The 3rd session is
able to get the row since that row is in fact not locked and it never got
blocked on session 1 in the first place.  Session 2 will become blocked by
session 3 if session 1 commits -- else session 2 will remain blocked waiting for
session 1 to commit or rollback fully(and end the transaction)

So, session 2 is enqueued on the TRANSACTION -- the rows are in fact not locked.
May 18, 2001 Tim
      -- Thanks for the question regarding "16 bit or 32 bit or 64 bit", version
      8.1.5

      You Asked
Tom:

I want to know what do you mean by "Oracle 8.1.6 for solaris 64 bit"? I have
seen so many places mentined 16 bit Oracle or 32 bit Oracle or 64 bit Oracle.
Now I found Oracle 8.1.6 for solaris 64 bit and I hoping definately it should be
for 32 bit and 16 bit solaris also. Same thing for NT 64 bit or 32 bit or 16
bit.

Basically what I want to know weather Oracle itself in differ from 64 bit to 32
bit or 32 bit to 16 bit.
or
It's operating system specific, I mean Oracle for 64 bit solaris or Oracle for
32 bit/16 bit solaris (also for NT OS).

Thanks

Tim

      and we said...
There is no such thing as 16 bit solaris.

Oracle (the database) operates much the same regardless of the "bits" on the
system.  We are very portable that way.

A 64bit OS would allow us to address much more memory then a 32bit one.  On a
32bit system (a system where pointers are 32bits) we can address 4gig or less of
RAM.  That limits the size of an SGA.  On a 64bit system -- we can address an
incredibly large SGA.

16, 32, 64 all speak to the native word size of the underlying hardware.  We
have versions of Oracle for 32 bit platforms and 64 bit platforms.  Windows used
to be a 16 bit application (DOS) and the tools that ran on it were 16 bit. We
windows 3.x came out -- things could be "win32" or 16 bit -- hence the large
number of "16 bit" or "32 bit" tools you saw.

Review &
      Followup

      Rating: 4
16 bit or 32
      bit or 64 bit  May 21, 2001
Reviewer:
      Sanjeev
Good One!!!

May 18, 2001 -- Thanks for the question regarding "trigger",
      version 8i

      You Asked
I need to design a trigger that takes the new.row and inserts into another
table, but, I only want rows with a certain condition.

I tried this

SQL> CREATE or REPLACE trigger prod_attr_ai
  2  after insert on prod_attr
  3  for each row
  4  when (new.attr_cd IN (select attr_cd from meta_attribute where searchable_p
= 't'))
  5  begin
  6  insert into search
  7    values (seq_search_id.nextval, :new.prod_id, :new_attr_val);
  8  end;
  9  /
when (new.attr_cd IN (select attr_cd from meta_attribute where searchable_p =
't'))
                      *

ERROR at line 4:
ORA-02251: subquery not allowed here

thanks for your help

      and we said...
you can only have simple things in the "when"

begin
  for x in ( select *
               from dual
              where :new.attr_cd in
                (select attr_cd from meta_attribute where searchable_p = 't')
           )
  loop
       insert into search ...
  end loop;
end;

will do it.  the body of the loop will execute once if the subquery is
satisfied, zero times otherwise.

Review & Followup

      Rating:
      5
Excellent!  May 18, 2001
Reviewer:
      Susan McCarthy  from Newton, MA USA
this was most helpful - seemed like a pretty basic thing to do but I couldn't
find any documentation re: suggested method.  Thanks!

      Rating:
      5
  May 21, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

May 18, 2001 ted -- Thanks for the question regarding "Q:
      related to table reorganization(move/import)", version 8.1.6

      You Asked
Thomas, table t

SQL> desc t
 Name                            Null?    Type
 ------------------------------- -------- ----
 X                               NOT NULL NUMBER(38)
 Y                                        CHAR(2000)
1.primary key X. notice the gap between block and x=51,52,53(inserted
later) have block# before x=50
2.after move block gap disappeared but x=51,52,53 still have block
ahead of x=50.
3.  export t , drop t and import t the x=51,52,53 still have block
ahead of x=50.

Questions:
1. Is there a way to get block into primary key sequence ?

2. I noticed when inserting new records rowno = 1 instead of zero
   which disappeared (turn into 0) after move or import. why  oracle
   is  smart enough to know the available block is no longer have
   a record in it ?

Unrelated question.
3. in pivot sql why max is necessary to be there ?

select job,
  2         max( decode( deptno, 10, cnt, null ) ) dept_10,
  3         max( decode( deptno, 20, cnt, null ) ) dept_20,
  4         max( decode( deptno, 30, cnt, null ) ) dept_30,
  5         max( decode( deptno, 40, cnt, null ) ) dept_40
  6    from ( select job, deptno, count(*) cnt
  7             from emp
  8            group by job, deptno )
  9   group by job

thnx a lot
ted chyn
===============================================================

block and row before move.
    BLOCK        ROW          X
---------- ---------- ----------
     24223          0          2
     24225          0          4
     24227          0          6
     24229          0          8
     24231          0         10
     24233          0         12
     24235          0         14
     24237          0         16
     24239          0         18
     24241          0         20
     24243          0         22
     24245          0         24
     24247          0         26
     24249          0         28
     24251          0         30
     24253          0         32
     24255          0         34
     24257          0         36
     24259          0         38
     24261          0         40
     24263          0         42
     24265          0         44
     24266          1         53
     24267          0         46
     24268          1         52
     24269          0         48
     24270          1         51
     24271          0         50
alter table move t;

        BLOCK        ROW          X
---------- ---------- ----------
     24742          0          2
     24743          0          4
     24744          0          6
     24745          0          8
     24746          0         10
     24747          0         12
     24748          0         14
     24749          0         16
     24750          0         18
     24751          0         20
     24752          0         22
     24753          0         24
     24754          0         26
     24755          0         28
     24756          0         30
     24757          0         32
     24758          0         34
     24759          0         36
     24760          0         38
     24761          0         40
     24762          0         42
     24763          0         44
     24764          0         53 *
     24765          0         46
     24766          0         52 *
     24767          0         48
     24768          0         51 *
     24769          0         50

      and we said...
1)
create table new_table
as
select * from old_table
order by X;

or use an index organized table if order is always important to you.  Why the
heck do you care if the data is physically stored in "order".  You know, extent
1 for a table might be blocks 100, 101, 102, ... 150.  Extent #2 for a table
might be in the same file -- but could be blocks 51, 52, ... 99.  Extent #3
could be blocks 1..50.  Put the data in order and it'll still be "block
backwards".  Who cares????

2) I do not understand this question.  It you are asking "why before the move
did I sometimes have 2 rows per block and after I do not"  - the answer will be
"when first inserted the rows fit nicely on the block -- after an update, one or
both grew.  when we reinsert these rows -- the exceed the pctfree so we don't
put them on the same block"

3) do it without the max and group by and you'll see why.  You get a sparse
matrix. the group by squashes the rows together and the max gets rid of the
nulls.

Review &
      Followup

      Rating:
      4
  May 20, 2001
Reviewer:  ted cjum
       from tx usa
clarification on question 2:
block 24270        row=  1       x=  51
was inserted later after original record had been deleted.
the question is
why oracle is smart enough to know row=0 in block 24270 had
already been deleted ?

May 19, 2001 parker -- Thanks for the question regarding
      "tools tablespace ", version 8.1.7

      You Asked
Tom

1.When I look into my tablespaces I find  tablespaces tools and drsys
what are they related to, can I go ahead and delete them?

2.are packages dbms_aq and dbms_job similar to each other, can you briefly
explain the difference between both of them?

Thanks

      and we said...
1) tools are for various tools.  forms, demos, and other things might install
their stuff in there.  feel free to drop it.

drsys is part of intermedia text.  if you are using that, don't drop it.  if you
do not have it installed and the tablespace is empty, feel free to drop it.

2) dbms_job is like CRON in unix or AT in windows.  It runs stored procedures on
a one time or recurring basis.

AQ is messaging software builtin to the database.  It is for building loosely
coupled, message based, asynchronous systems.  A client would put a message in a
queue.  Another process you write ( a daemon of sorts ) would dequeue the
message and do something about it.  It happens in real time.

jobs are just like a time, run this job every hours.

queues are messages -- when a new message comes in, someone dequeues it and does
something about it.
May 19, 2001
      parker -- Thanks for the question regarding
      "procedure and function", version 8.1.7

      You Asked
Tom

Usually the difference between a procedure and a function is said to be that, a
function returns a value where as a procedure doesnt. But even the procedure can
be made to return a value with a out or a in out parameter.

Can you please explain.

Further , can you give me simple examples for a procedure using an out parameter
and a procedure using in out parameter.

Thanks

      and we said...
Its a matter of the way you call them.  A function F and a Procedure P are
called differently:

declare
   x number;
begin
   x := f;
   p(x);
end;

A function can also be called from sql:

select f from dual;

whereas a procedure cannot. A function is simply a procedure that can return a
value.  functions and procedures can both MODIFY their inputs given that the
inputs are OUT or IN OUT.

A procedure using an OUT and IN OUT might be:

tkyte@TKYTE816> create or replace procedure p( arg1 out number, arg2 in out
number )
  2  as
  3  begin
  4    arg1 := abs(arg2);
  5    arg2 := arg2*arg2;
  6  end;
  7  /

Procedure created.

tkyte@TKYTE816> variable a number
tkyte@TKYTE816> variable b number
tkyte@TKYTE816> set autoprint on
tkyte@TKYTE816> exec :b := -5;

PL/SQL procedure successfully completed.

         B
----------
        -5

tkyte@TKYTE816> exec p(:a,:b)

PL/SQL procedure successfully completed.

         B
----------
        25

         A
----------
         5

May 19, 2001 parker -- Thanks for the question regarding
      "immediate and deferred constraints", version 8.1.7

      You Asked
Tom

What is the needs to make a constraint deferred?
Can you also give the mail difference between a immediate and a deferred
constraint.

Is there a special syntax to make a constraint immediate or deferred?
what is the default?

Thanks

      and we said...
The deferrable constraint was introduces for a process that makes a bunch of
updates to a lot of tables that temporarily makes the tables "inconsistent" but
by the time its done -- every thing will be OK.

Lets say you were writing a batch process.  It would process input files that
told it to INSERT/UPDATE/DELETE employee and dept records.  It is going to do
this work in some order (maybe process ALL emp changes and then ALL dept changes
for example).  During the processing it is told to:

DELETE employee 1 (who is the manager of employee 2)
UPDATE employee 2 setting the manager to employee 3, department to 50
INSERT employee 3 into deptartment 50

INSERT department 50
DELETE department 10 (employee 1 and 2 were the only ones in dept 10)

At the END of the process -- all of the tables are OK.  Individually however --
each statement would leave the database in an inconsistent state.  If you delete
employee 1 -- you have an orphaned foreign key in the employee table UNTIL you
create employee 3 but employee 3 is in dept 50 which doesn't exist until you
create it.

So, during this process the database is inconsistent -- at the end it is OK.  A
common use of this might be to do an update cascade.  Say you wanted to change
dept = 10 to dept = 11.  If you update the DEPT table first -- it would normally
fail since the emp table has employees in dept 10.  If you tried the emp table
first, it would fail since dept = 11 doesn't exist.  deferrable constraints
permit this to take place naturally.  the constraints are validates upon COMMIT.

the main difference between an immediate and deferred constraint is quite
simple:  an immediate constraint is validated after each statement, a deferred
constraint is validated upon commit (or upon setting all constraints to
immediate).

Search for deferrable on my site to see examples.  immediate is the default, you
have to define constraints as deferrable in the CREATE or ALTER statement.

Review &
      Followup

      Rating:
      4
  May 23, 2001
Reviewer:  PURUSH
       from Germany
Baisc funda but very useful

May 19, 2001 -- Thanks for the question regarding "Special
      Characters", version 8.1.6

      You Asked
Hi,

I have a form which has a field. This field must be alphanumberic(only
letters&numbers permitted). I permit the end user to input the other "special
characters", but internally i want to strip them out  first and keep only the
leftover as my clean data key which will be based on to continue process the
transaction.

E.g.: sk6789er$2%%&6(before)  ====> sk6789er26(after)

I doubt we have the same function "IS_ALPHA_NUNERIC()" function in C or C++
language, so what function or procedure we can use and how?

Thanks for you kindness.

      and we said...
tkyte@TKYTE816> create table t ( x varchar2(25) );

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> set define off
tkyte@TKYTE816> insert into t values ( '*sk6789er$2*%%&6' );

1 row created.

tkyte@TKYTE816>
tkyte@TKYTE816> select replace(translate( x,
  2         translate( x,
             'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
  3                        rpad( '*', 62, '*' ) ), ' ' ), ' ', '')
  4  from t
  5  /

REPLACE(TRANSLATE(X,TRANS
-------------------------
sk6789er26

the inner translate turns all "good" characters into '*'.  so, we end up with
(for this string):

*********$*%%&*

so, the outer translate is now:

   translate( '*sk6789er$2*%%&6', '*********$**%%&*', ' ' )

that returns:

' sk6789er2 6'

now we use replace to get rid of the blanks and are left with what we want.

follow up to third comment below:

the 62 is the length of ABC...Zabc....z01....9  -- NOT the length of the string
X.  the rpad('*',62,'*') makes a translation table that is the length of the
input translation table.

Review &
      Followup

      Rating:
      5
  May 20, 2001
Reviewer:  Reader
       from U.S.A

      Rating:
      5
  May 21, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

      Rating: 5
Replace 62 by
      Length Function  May 21, 2001
Reviewer:  Asif
      Momen  from Riyadh
Hi Tom,

The SQL is wonderful. But, why to hardcode the statement by '62', instead of
that we can read the length of the column eg. Length(x).

select replace(translate( x, translate( x,
 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rpad( '*',
Length(x), '*' ) ), ' ' ), ' ', '')
  from t
  /

Regards,

Momen.

      Rating: 5
Special
      Characters  December 18, 2002
Reviewer:  Mark
      M  from Phoenix, AZ

      Rating: 4
Space between
      characters in a string  August 21, 2003
Reviewer:
      Ratan  from Singapore
Hi,
Need help to write query to get the following.

my input:  "Testing"
how to get this Output : " T e s t i n g"
i.e. each character follwed by sapce except last character.

Thanks in advance.
Ratan

May 20, 2001 -- Thanks for the question regarding "renaming a
      table", version 8.1.6.3

      You Asked
is renaming a table dangerous while user are hitting that table
because i just did it and my entire database went crawling
so i renamed it back to its original name and no luck

      and we said...
dangerous -- if it is a highly accessed table with lots of procedures and such
-- yes.

you would have invalidated all dependent procedures and views (any stored,
compiled object that was dependent on it).  you would have invalidated the
cursor cache for all objects that reference it.

You most likely made your database recompile TONS of stuff.  renaming it back
would only prolong the agony as that would do the whole invalidation thing over
again.

DDL like that is something you do not want to do on a production system.
Review &
      Followup

      Rating:
      4
  August 13, 2001
Reviewer:
      A reader

May 20, 2001 -- Thanks for the question regarding "Function
      index not used without hint.", version 8.1.7

      You Asked
Hi,

I have a question about function indexes. I have observed that I have to use a
hint in order to force the optimizer to use a function index on a table.  like:

select /*+ index(emp) */ empno,ename,sal from emp
   where upper(ename) like 'S%';

Here I have a function index on emp(ename).

Does it happen for all function indexes on tables of small and larger size? How
can the optimizer user the function index without the user of a hint? Mant
thanks.

Irshad.

      and we said...
see

http://osi.oracle.com/~tkyte/article1/index.html

most likely, you have not analyzed the EMP table.  you need to use the cost base
optimizer to use FBI's.

if you have analyzed the EMP table and the emp table is 14 rows big -- the CBO
will not tend to use an index (slower then using one) and that could be the case
as well.


Subject | Article | Last Updated (East coast time)
Invoice Tracking | article only | May 21, 2001 10:37 pm
Binary Conversion to float | article only | May 22, 2001 10:43 am
Comparison of Oracle to other database servers | article only | May 22, 2001 10:54 am
initaqjms.sql under 8.1.6 vz 8.1.7 | article only | May 22, 2001 05:05 pm
default optimizer in oracle 8 and 8i | article only | May 22, 2001 05:55 pm
regarding arrays in forms | article only | May 22, 2001 11:50 pm
To assign a Sequence value to a table inside the trigger | article only | May 23, 2001 11:05 am
long to Clob | article only | May 23, 2001 11:08 am
Join tables, Order of predicate evaluation | article only | May 23, 2001 11:16 am
source code profile | article only | May 23, 2001 11:44 am
kill inactive sessions | article only | May 23, 2001 11:47 am
pl/sql tuning .. sql tuning | article only | May 23, 2001 11:48 am
"Log File Switch" waits | article only | May 23, 2001 04:22 pm
PL/SQL - 3GL? | article only | May 24, 2001 08:23 am
java call | article only | May 24, 2001 08:24 am
dbms_java, where are the privileges stored | article only | May 24, 2001 08:35 am
Partionining - Reg. | article only | May 24, 2001 08:42 am
Which is faster ---- continue | article only | May 24, 2001 08:54 am
random number generator | article only | May 24, 2001 10:16 am
re-writing query with outer view | article only | May 24, 2001 11:13 am
Orakill utility | article only | May 24, 2001 01:40 pm
Optimizor | article only | May 24, 2001 01:46 pm
Selecting primary key columns with not null constraints | article only | May 24, 2001 08:54 pm
Query for converting row to column | article only | May 24, 2001 09:03 pm
How to Determine size of a bfile | article only | May 25, 2001 08:23 am
dbms_obfuscation_toolkit.DESEncrypt - ORA-06508: PL/SQL: could not find program unit being called | article only | May 25, 2001 08:42 am
Disconnecting from a current user and then connecting back to the same user | article only | May 25, 2001 08:53 am
DBMS_OBFUSCATION_TOOLKIT | article only | May 25, 2001 09:26 am
Can i pass "C" structures to Oracle | article only | May 25, 2001 11:35 am
Display result of 2 queries side by side | article only | May 25, 2001 11:38 am
query and current in tkprof output | article only | May 25, 2001 12:28 pm
how to disply 2 result sets side by side | article only | May 25, 2001 12:37 pm
delete on cascade or trigger to maintain referential integrity? | article only | May 25, 2001 01:38 pm
Oracle and Active Directory | article only | May 25, 2001 01:47 pm
About using Arrays | article only | May 25, 2001 04:30 pm
no redo log for inserting/updating a table | article only | May 25, 2001 04:38 pm
How to related the oracle process created at database from an htp request at oas server | article only | May 25, 2001 04:40 pm
memory | article only | May 26, 2001 06:01 pm
cbo and table size | article only | May 26, 2001 07:26 pm
archive | article only | May 26, 2001 07:28 pm
5 levels of application tuning | article only | May 26, 2001 07:30 pm
v$session_wait | article only | May 26, 2001 07:35 pm
bind variables | article only | May 26, 2001 07:40 pm
indexes on foreign key | article only | May 27, 2001 06:59 pm
row(s) 1 - 44 of 44
May 21, 2001 dedy -- Thanks for the question regarding "Invoice Tracking", version 2.5.5.2.7
You Asked
hi tom..
I have two tables listed below :
  Table A : ORDER_NUMBER varchar2(9) primary key
  Table B : ORDER_NUMBER varchar2(9)primary key
            INVOICE_NUMBER varchar2(9)
  ORDER_NUMBER          ORDER_NUMBER  INVOICE_NUMBER
  ------------          ------------  --------------
  001                   001           1A
  002                   003           1b
  003                   004           1c
  004
  005

1. How do I know the status for order number which one is already has invoiced
or not yet ?
2. If it has invoiced should be return INVOICE_NUMBER
   else "NO_INVOICES EXIST FOR THIS ORDER"
   end if.

thank for your time to help me.
and we said...
select tablea.*,
       decode( tableb.order_number, NULL, 'NO INVOICES', tableb.invoice_number )
  from tablea, tableb
 where tablea.order_number = tableb.order_number (+)
/

should do it for you.  an outer join takes care of this
Review & Followup
Rating: 5
Invoice Tracking May 22, 2001
Reviewer: DEDY RINALDY from INDONESIA
substr(a.order_number,1,9)=substr(b.order_number,1,9)(+) before you give me the
answer.
Thank you very much.

May 22, 2001 Kjell -- Thanks for the question regarding "Binary Conversion to float ", version 8.1.6
You Asked
I’m passing binary data in to a PL/SQL procedure (PL/SQL long raw datatype).
The procedure clip out 4 or 8 bytes with UTL_RAW.SUBSTRING.

The binary representation is accordance with IEEE 754 float.

I want to convert 4 bytes to float and 8 bytes to double float.
The float shall be returned in Oracle number datatype.

Can this be done in PL/SQL?
If I want to use Java stored procedures to solve this,
how do I write the Java procedure?

Mor details:
The machine the server is running on use IEEE 754 float.

The spec for the storage of the IEE 754 float is found here:
http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
As you see I’m not familiar with Java or C programming.

I want to pass the binary representation of the float which in pl/sql is stored
in raw(4)or raw(8).

Which data types shall be used when passing and returning data?

Here is sketch of what I try to do with Java stored procedures:

Create or replace JAVA SOURCE NAMED ‘’BinToFloat’’ AS
Public class BinToFLOAT{
Public static ???? BinToFloat( ){
?
?
?
Return ????;

}
};
/

--wrapper function

create or replace function BinToFloat(?? in ??) Return NUMBER
as LANGUAGE JAVA NAME ‘bintofloat’()return number’;
/

Thanks for any help
and we said...
(Thanks to Mark Piermarini for the Java bit here....)

Ok, here we go.  first I generated a test set of data in C:

#include "stdio.h"

void main()
{
float x = 1.123;
double y = 12121;
FILE * output;

    output = fopen( "test.dat", "wb" );
    fwrite( &x, 1, sizeof(x), output );
    fwrite( &y, 1, sizeof(y), output );
    fclose(output );
}

then, i loaded that up in the database:

create or replace directory my_files as '/export/home/tkyte'
/

drop table t;

create table t ( x blob );

declare
    l_bfile bfile;
    l_blob blob;
begin
    l_bfile := bfilename( 'MY_FILES', 'test.dat' );
    dbms_lob.fileopen( l_bfile );

    insert into t values ( empty_blob() ) returning x into l_blob;

    dbms_lob.loadfromfile( l_blob, l_bfile, dbms_lob.getlength(l_bfile) );
    dbms_lob.fileclose( l_bfile );
end;
/

and then:

ops$tkyte@DEV816> create or replace and compile java source
  2  named "RawIEEE" as
  3  import oracle.sql.*;
  4
  5  public class RawIEEE {
  6    static public NUMBER rawFloatToNUMBER(RAW r) throws Exception {
  7      return new NUMBER(
  8                    Float.intBitsToFloat(
  9                          Integer.parseInt(r.stringValue(), 16)
 10                                        )
 11                       );
 12    }
 13
 14    static public NUMBER rawDoubleToNUMBER(RAW r) throws Exception {
 15      return new NUMBER(
 16                    Double.longBitsToDouble(
 17                        Long.parseLong(r.stringValue(), 16)
 18                                           )
 19                       );
 20    }
 21  }
 22  /

Java created.

ops$tkyte@DEV816> show errors
No errors.
ops$tkyte@DEV816>
ops$tkyte@DEV816> create or replace function
  2  RAW_FLOAT_TO_NUMBER(p_raw in RAW) return NUMBER
  3  as language java
  4  name 'RawIEEE.rawFloatToNUMBER(oracle.sql.RAW) return
  5        oracle.sql.NUMBER';
  6  /

Function created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> create or replace function
  2  RAW_DOUBLE_TO_NUMBER(p_raw in RAW) return NUMBER
  3  as language java
  4  name 'RawIEEE.rawDoubleToNUMBER(oracle.sql.RAW) return
  5        oracle.sql.NUMBER';
  6  /

Function created.

And now I can simply:

ops$tkyte@DEV816> column rfloat format a8
ops$tkyte@DEV816> column rdouble format a16
ops$tkyte@DEV816>
ops$tkyte@DEV816> select dbms_lob.substr( x, 4, 1 ) rfloat,
  2         RAW_FLOAT_TO_NUMBER(dbms_lob.substr( x, 4 , 1)) xfloat,
  3         dbms_lob.substr( x, 8, 5 ) rdouble,
  4         RAW_DOUBLE_TO_NUMBER(dbms_lob.substr( x, 8, 5)) xdouble
  5    from t
  6  /

RFLOAT       XFLOAT RDOUBLE             XDOUBLE
-------- ---------- ---------------- ----------
3F8FBE77      1.123 40C7AC8000000000      12121
Review & Followup
Rating: 5
RAW_FLOAT_TO_NUMBER June 01, 2001
Reviewer: Kjell Lie from Norway -Karm?y
This is exactly what I was looking for.
The Java part is implemented and tested with success.

(The Raw input to Oracle is coming from Programmable Logical Controller’s via a
OPC client.)

Thanks very much
 Kjell Lie

May 22, 2001 Ms Jay Milam -- Thanks for the question regarding "Comparison of Oracle to other database servers", version Oracle 8I
You Asked
I am in the process of writing a proposal for a new project.  I need to sell
them on a centralized data base using Oracle.  I need to re-assure them of data
secutiy issues due to sensitive and confidential nature of data....like only the
right people have the access and ablity to view and update files and no one else
will have access if not authorized....Do you have any write up on this and how
Oracle compares to other databases.

Thanx for your input ...in Advance...Looking forward to receiving
information....

Regards,
Ms Jay Milam
and we said...
see
http://www.oracle.com/ip/solve/security/index.html?content.html
lots of info there.
Review & Followup
Rating: 5
How Oracle compares with other datatbase technologies May 23, 2001
Reviewer: Jay Milam from Ft. Lauderdale FL USA
Excellent input ....EXACTLY what I needed....prompt response....

Can not say enough ...Thanx very much!!!!

May 22, 2001 Reji -- Thanks for the question regarding "initaqjms.sql under 8.1.6 vz 8.1.7", version 8.1.7
You Asked
In 8.1.6 there is a sql script "initaqjms.sql". It is under dbms/admin
directory, but I can't find it in
our 8.1.7 tree. What are the new scripts that we will be using
to get the same functionality.

Thanks
Reji
and we said...
It is simply initjms.sql in 8.1.7
May 22, 2001 redi -- Thanks for the question regarding "default optimizer in oracle 8 and 8i", version 8.1.7
You Asked
Tom

I know that the default optimizer in oracle  7 was rule based. What is the
default optimizer in oracle 8 and oracle 8i.

I want to use dbms_profiles on one of my procedures, can explain to me how I
should do it.

Further,
Is the statspack used only by the dba's, is it also useful to the developers in
any way?

Redi
and we said...
The default optimizer depends on your init.ora parameter setting.

If left to the default, the optimizer goal will be CHOOSE.  If ANY object your
query references is analyzed -- we will use the cost based optimizer.  If no
object is analyze -- we will use rbo.

it is exactly as it was in Oracle7, no changes there (just many more reasons to
use CBO)

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:458240723799
for a quick overview of dbms_profiler.

Statspack is useful to the developer -- definitely.  There is a wealth of
information in there -- too much to go into here (but I can say that I have a
chapter in it in my book that does go into detail on the contents of that
report)..
Review & Followup
Rating: 4
May 23, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

May 22, 2001 shamim -- Thanks for the question regarding "regarding arrays in forms", version form6
You Asked
Dear sir
is there is any concept of ARRAYS in forms  as  in c/c++
if yes
ps tell me in detail with an example how to use
else
any alternative to arrys
ps reply apropriatly
thanx with regars
shamim
and we said...
There are PLSQL table types:

create package foo
as
  type myArray is table of number;

  x myArray;
end;
/

There are record groups which act alot like a 2 dimensional array with NAMED
columns and rows (like a result set)

If you have that package defined in your form, you can write a trigger that has:

declare
   data myArray;
begin
   for i in 1 .. 10 loop
      data(i) := i;
   end loop;
end;
/

for example.
May 23, 2001 -- Thanks for the question regarding "To assign a Sequence value to a table inside the trigger", version 8.1.6
You Asked
I created following trigger, and i want's to assign a sequence value to the same
table before insert. Explain in detail and correct the following statement.

CREATE or REPLACE TRIGGER DMY_ADDRESS_BEFORE_I_TRIG
BEFORE INSERT ON DMY_ADDRESS
FOR EACH ROW
DECLARE
v_seq_id number;
BEGIN
SELECT dmy_no.nextval INTO :v_seq_id FROM dual;
INSERT INTO DMY_ADDRESS (id_num) VALUES(:v_seq_id);
END;

After executing this i'm getting Trigger cretaed with compilation error

Thanks in Advance

Partha
and we said...
You cannot insert into the table that fires the trigger like that.

It should simply be:

CREATE or REPLACE TRIGGER DMY_ADDRESS_BEFORE_I_TRIG
BEFORE INSERT ON DMY_ADDRESS
FOR EACH ROW
BEGIN
    SELECT dmy_no.nextval INTO :new.id_num FROM dual;
END;

just modify the :new.column values.
Review & Followup
Rating: 5
May 23, 2001
Reviewer: A reader from usa
Thnak you verymuch, it worked fine.

May 23, 2001 Mohamad -- Thanks for the question regarding "long to Clob", version 8.1.6
You Asked
I am developping using Coldfudion . All what i could pass to a stored procedure
is a ( CF_SQL_LONGVARCHAR ) which corresponds to a Long in the oracle Database.
i need to convert it to a Clob in order to be able to insert it in the
corresponding feild in the table.
and we said...
that long varchar is really just a varchar2(32767) -- it is a plsql variable,
not a long type.  Your procedure will look like:

create proceudre p ( p_id in number, p_string in varchar2 )
as
   l_clob clob;
begin

   insert into t ( id, text ) values ( p_id, empty_clob() )
    returning text into l_clob;

   dbms_lob.writeappend( l_clob, length(p_string), p_string );
end;
Review & Followup
Rating: 4
long to clob March 15, 2002
Reviewer: A reader

May 23, 2001 X -- Thanks for the question regarding "Join tables, Order of predicate evaluation", version 8.1.5
You Asked
Good morning Tom:
Thank you for your previous help!!!

When I join two tables such as:

Select field names from emp, dept
where emp.dept_num = dept.num and
    emp.name Like 'S%' and dept.name = 'IT';

In this query, which part of where clause is performanced first by oracle
optimizer. Either emp.dept_num = dept.num or emp.name Like 'S%' and dept.name =
'IT'.

Thank you

from New Jersey
and we said...
Well, it'll totally depend.  The optimizer will decide based on existing
indexes, statistics and session/init.ora parameters.

Say you have an index on DEPT(name) and EMP(dept_num).  The optimizer sees that
DEPT(name) is almost unique.  It would probably:

1) use the index on dept(name) to find the dept rows
  2) use the index on emp(dept_num) to find the matching emp rows (this is the
     join emp.dept_num = dept.num )
    3) filter on emp.ename like 'S%'

now, lets say that there is no index on dept_num, no index on dept.name, indexes
are on EMP(name) and DEPT(num).  Now it *might*

1) use the index on EMP(name) to find the emps with S's
  2) use the index on dept(num) to find the matches
    3) filter the result on dept.name = 'IT'

Basically -- the order of evaluation of the predicate is NOT defined, not
assured, can and will change over time / version to version and is decided by
the optimizer.  Do NOT assume anything happens in a certain order.  Consider:

ops$tkyte@ORA8I.WORLD> create table t ( x varchar2(1), y varchar2(1) );
Table created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 'a', '1' );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 'b', 'x' );
1 row created.

ops$tkyte@ORA8I.WORLD> alter session set optimizer_goal = choose;
Session altered.

ops$tkyte@ORA8I.WORLD> select * from t where x = 'a' and y = 1;
ERROR:
ORA-01722: invalid number

no rows selected

that shows that in this case, Oracle evaluated the y=1 FIRST  and when it hit
the row where y = 'x', it could not convert 'x' into a number (obviously) and
fails... however:

ops$tkyte@ORA8I.WORLD> alter session set optimizer_goal = all_rows;
Session altered.

ops$tkyte@ORA8I.WORLD> select * from t where x = 'a' and y = 1;

X Y
- -
a 1

ops$tkyte@ORA8I.WORLD>

Use a different optimizer mode and wah-lah -- it works!  why?  because the
optimizer said "hey, its faster to check x='a'  then to do y=1 since y=1
includes a conversion of y from a string to a number, we'll skip that step and
do x='a' first and then y=1"
Review & Followup
Rating: 5
May 23, 2001
Reviewer: A reader
Thank you very much

Rating: 5
It is really suprising. May 23, 2001
Reviewer: KP from India
The example is excellent

Rating: 5
Driving table January 17, 2002
Reviewer: Thanga Aruna from India
Good explanation with excellant example. Thanx.

May 23, 2001 redi -- Thanks for the question regarding "source code profile", version 8.1.7
You Asked
Hi

What do you mean by a source code profiler.
What is the need for dbms_profiles.

Further

can you briefly explain in a few sentences as to how statspack is useful to a
developer  and to a dba?

Apart from optimizer hints, explain plan and tkprof, dbms_profiles and
statspack, what are theother tunining utilities in oracle?

Thank you
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:424938726712
for an example using the source code profiler.  it helps you identify where in
the code you spent your time.  you can implement an algorithm two or three
different ways and see which is BETTER.

stats pack shows you the top sql across all applications.  statspack shows you
the major wait events in the system -- typically it takes application level
changes to reduce major wait events, especially enqueues (locks) and latch.
statspack shows you your soft parse ratio (which had better be darn close to
100%).  if it isn't -- only application level changes can fix it.  it shows you
your parse/execute ratio, which should approach zero.  again, something only an
application level fix can correct.... and so on.

how about

o materialized views
o analytic functions
o external procedures
o OEM performance packs
o dbms_application_info (knowing WHERE you are slow is important, heavily
  instruemented code helps you find those spots)
o statistics
o optimizer plan stability
o dynamic performance views (V$ tables)
o cursor_sharing
o Oracle trace
o resource management
o profiles

and the list goes on (index organized tables, bitmap indexes, clusters, etc etc
etc)
May 23, 2001 Alfredo -- Thanks for the question regarding "kill inactive sessions", version 8i
You Asked
With the instance manager I see that i have several sessions inactive and I want
to killed them.

I remeber having seen a script to kill inactive sessions in an oracle magazine
but i can not find it anymore.

Do you have any scritps to kill sessions ?
and we said...
alter system kill session 'sid,serial#'

where the sid and serial# are as reported from v$session

HOWEVER -- did you know that as soon as you run a query and get the results back
in sqlplus -- you are "inactive".  most sessions are MOSTLY inactive!

I think you might want to look at PROFILES.  There you can set an IDLE time
limit.  That will kill sessions that have been IDLE for "x" minutes.  Just
killing inactive sessions would *not* be a good idea.
May 23, 2001 redi -- Thanks for the question regarding "pl/sql tuning .. sql tuning", version 8.1.7
You Asked
Tom

Can briefly discuss the differences between  pl/sql tuning .. sql tuning. How do
they compliment each other.

Can you give me an example, where a well tuned query does not perform well due
to badly written pl/sql, and vice versa.

Thank you
and we said...
tuning SQL is tuning SQL.  SQL is a non-procedural language.  You are going to
be tuning a SINGLE statement.

PLSQL is a 3gl -- like C, Java, VB, etc....  Tuning it is like tuning a program
(because -- it is a program).

they are just totally different.

A well tuned query will perform well regardless of the environment.  It will NOT
perform poorly due to poorly written code.
Review & Followup
Rating: 5
Lov Display Problem May 24, 2001
Reviewer: Venkat from Muscat Oman
Hi
 Lov Columns usually display in Horizontal order. But I want to display in
vertical order. Is it possible in Forms 4.5.

Thanks
By
venkat

May 23, 2001 -- Thanks for the question regarding ""Log File Switch" waits", version 8.1.6
You Asked
In a previous "Ask Tom", I posed a question regarding "log switch waits". In
that forum I basically asked what LGWR does after a log switch--does LGWR wait
for the CKPT or ARCH processes to finish doing their job before moving on and
writing to the next redo log? Your answer to that question was simply put "LGWR
keeps on going". Which brings me to my next question. If LGWR does not wait for
any process to finish, then what causes the "log file switch" wait event?

As usual, thank you for any input you may have regarding this subject.
and we said...
The question you refer to is:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:654384749266
there i said "lgwr keeps going" however I also said:

What will wait for a checkpoint to complete is a log switch into a redo log file
whose checkpoint has not completed.

That is when you'll get this "log file switch" wait.  when LGWR attempts to
REUSE a redo log file that either

o DBWR has not checkpointed all the blocks protected by this redo log file
(checkpoint not complete message in the alert log)

o ARCH has not completed copying this redo log file (archival required message
in the alert log)
May 24, 2001 Dusan -- Thanks for the question regarding "PL/SQL - 3GL?", version 8.1.6
You Asked
Hi Tom

As mentioned :
http://asktom.oracle.com/pls/ask/f?p=4950:8:108016::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:689074041658,
I am bit surprised, is PL/SQL really considered as 3GL?

rgds,

Dusan
and we said...
Taking the definition of 1-4gl from:
http://www.npac.syr.edu/users/gcf/cps616rdbms1/foilsephtmldir/041HTML.html
which is as good as any others - a 3gl is
"high level programming language, structural, modular and usually procedural"

I would definitely classify PL/SQL as a 3gl.  It has packages (modular), it is
defintely a structured language, it is procedural by nature, it is very
Ada/Pascal like.

Yes, I would definitely classify it as a 3gl.
May 24, 2001 -- Thanks for the question regarding "java call", version 8.1.6
You Asked
Tom:

after loadjava,
can i only call static function or it doesn't matter?
and we said...
At some level, you need to have a static member to call.  This static member can
then invoke any other non-static member.  The interface from the SQL layer to
the java layer must be via a static member however since there is no java
"instance" at the SQL layer (no "this" instance to be accessed).  Hence the need
for at least one static member function.
May 24, 2001 -- Thanks for the question regarding "dbms_java, where are the privileges stored", version 8.1.6
You Asked
Tom:

after I run dbms_java.grant_permission,
by which table can i tell what permission have been granted?
and we said...
See
DBA_JAVA_POLICY
USER_JAVA_POLICY

...
Review & Followup
Rating: 5
very useful, as always February 01, 2002
Reviewer: Eric Grancher from CERN, Switzerland

May 24, 2001 -- Thanks for the question regarding "Partionining - Reg.", version 8.1.7.0.0
You Asked
What is the difference between range partionining and hash partitioning. I have
gone through the document but it is not
clear.  Where we go for range partioning/hash partioning.

If i had date as partition column.  and if i had 365 differnt
dates.  r 365 partitions created by the system when new dates r inserted . Or we
have to specify
partition for each and every date while creating the table.

An example would really help me a lot.

Regards

Koshal
and we said...
Range partitioning means YOU have told US where to put the data.  You have said
"all data with x < 5 goes into this partition.  all data with x >= 5 and x < 10
goes into this partition.  all data with x >= 10 and x < 15 goes here" and so
on.

YOU tell US where the data goes.

Hash partitioning means you told us how many partitions you would like US to
automatically spread the data across.  We hash a column(s) and that tells us
what partition to put the data in.  You yourself cannot look at a row and
determine what partition it might end up in, only after inserting the data can
you tell what partition it might be in.

You have to create each and every partition, Oracle will never create a
partition on the fly.  You can ALTER the table to add/split/merge/delete and so
on partitions over time, it does not HAVE to be done during table creation.

search for:

partition

on my website for lots of little examples.
Review & Followup
Rating: 5
Excellent May 25, 2001
Reviewer: KP from India
This sort of explanation is missing in documentation.
U tell it in such a way that it is very easy to understand.

Yr replies have been of great help

May 24, 2001 -- Thanks for the question regarding "Which is faster ---- continue", version 8.1.6
You Asked
Hi, tom,

Small question:

Within a larg loop, if we want to commit every 1000 records(million or billion
records), which is more faster(efficient), mod()-- then commit or setup a
counter like: counter := counter + 1, if count ... then commit; counter := 0;

eg:
1).
  ....
  START LOOP
    ....
    cnt := cnt + 1;
    IF ( cnt%1000 ) = 0 THEN  <======== using mod() function
      commit;
    END IF;
    ....
  END LOOP;
  ....

2).
  ....
  START LOOP
    ....
    cnt := cnt + 1;
    IF cnt = 1000 THEN        <======== no mod() function
      commit;
      cnt := 0;
    END IF;
    ....
  END LOOP;
  ....
1) & 2) which way is more fater? or same efficient?
Give pros and cons p.l.

Hope i'm clear this time

Thanks
and we said...
The fastest is to bite the bullet, configure sufficient rollback and do the
update in a single update statement.

The second fastest is to bit the bullet, configure sufficient rollback and do
the transaction in a single loop without commits.

The commit is what will slow you down.  You'll have to consider how you will
restart this process as well.  Watch out for the ora-01555 which will inevitably
get you if you are updating the table you are reading as well.

As for the code above, we can use the source code profiler provided in the 8i
database to analyze this.  I created the following procedures and ran them:

create or replace procedure do_mod
as
    cnt number := 0;
begin
    dbms_profiler.start_profiler( 'mod' );
    for i in 1 .. 500000
    loop
        cnt := cnt + 1;
        if ( mod(cnt,1000) = 0 )
        then
            commit;
        end if;
    end loop;
    dbms_profiler.stop_profiler;
end;
/

create or replace procedure no_mod
as
    cnt number := 0;
begin
    dbms_profiler.start_profiler( 'no mod' );
    for i in 1 .. 500000
    loop
        cnt := cnt + 1;
        if ( cnt = 1000 )
        then
            commit;
            cnt := 0;
        end if;
    end loop;
    dbms_profiler.stop_profiler;
end;
/

exec do_mod
exec no_mod

Now, after running the profiler reports I find:

=
=
====================
Total time

GRAND_TOTAL
-----------
      11.41

=
=
====================
Total time spent on each run

RUNID RUN_COMMENT    SECS
----- ----------- -------
    1 mod            8.18
    2 no mod         3.23

=
=
====================
Percentage of time in each module, for each run separately

RUNID RUN_COMMENT UNIT_OWNER  UNIT_NAME         SECS PERCEN
----- ----------- ----------- -------------- ------- ------
    1 mod         OPS$TKYTE   DO_MOD            8.18  100.0
    2 no mod      OPS$TKYTE   NO_MOD            3.23  100.0

=
=
====================
Percentage of time in each module, summarized across runs

UNIT_OWNER  UNIT_NAME       SECS PERCENTAG
----------- -------------- ----- ---------
OPS$TKYTE   DO_MOD          8.18     71.67
OPS$TKYTE   NO_MOD          3.23     28.32
SYS         DBMS_PROFILER    .00       .00

So already, this shows that the MOD function takes longer.  Just to prove that
it is MOD

=
=
====================
Lines taking more than 1% of the total time, each run separate

RUNID     HSECS    PCT OWNER       UNIT_NAME       LINE# TEXT
----- --------- ------ ----------- -------------- ------ ---------------------
    1    550.06   48.2 OPS$TKYTE   DO_MOD              9 if ( mod(cnt,1000) =
                                                         0 )

    1    135.22   11.9 OPS$TKYTE   DO_MOD              8 cnt := cnt + 1;
    2    107.71    9.4 OPS$TKYTE   NO_MOD              8 cnt := cnt + 1;
    2    104.34    9.1 OPS$TKYTE   NO_MOD              9 if ( cnt = 1000 )
    1     67.95    6.0 OPS$TKYTE   DO_MOD              6 for i in 1 .. 500000
    2     64.66    5.7 OPS$TKYTE   NO_MOD             12 cnt := 0;
    1     64.64    5.7 OPS$TKYTE   DO_MOD             11 commit;
    2     44.99    3.9 OPS$TKYTE   NO_MOD              6 for i in 1 .. 500000

8 rows selected.

that clinches it -- using MOD took about 5.5 seconds, doing if ( cnt=1000 )
took 1 second PLUS the time to do cnt := 0 gives a grant total of about 1.5
seconds.

5.5 for mod
1.5 for cnt=1000; cnt:=0;

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1405003844201
for more info on the profiler....

follow up to somewhat silly comment below

hmmm, a more accurate answer.  lets see

question was: what is faster a MOD or a counter that is reset.....
answer was:   mod takes 5.5, counter takes 1.5

Well, that seems pretty darn "accurate" to me.... it seems clear that the way to
do it would be to use a counter that is reset.

followup to second comment

See $ORACLE_HOME/plsql/demo/profsum.sql  -- it is a standard report, all of the
sql you want is in there.
Review & Followup
Rating: 2
March 28, 2001
Reviewer: Want more accurate answer from USA

Rating: 5
From Singapore May 24, 2001
Reviewer: Ch Srinivasa Ra0 from Singapore
Hi Tom
   The example and the output is very informative. Can u give the SQL how u
calculated HSECS,PCT. I created the package and respective tables and able to
see output from plsql_profiler_data and i understood u have linked ur query with
user_source. Can u put ur query in this site.

May 24, 2001 Huannu -- Thanks for the question regarding "random number generator", version Oracle8i
You Asked
Hi Tom,

Could you please tell me the best way of writing a random number generator,
which can generate random numbers that greater than 0 and less than 1? (using
DBMS_RANDOM.RANDOM?)

Thanks!!
and we said...
In Oracle8i release 2 and up there is a function

DBMS_RANDOM.VALUE

that returns a random 38-digit precision number, 0.0 <= value < 1.0

see

select text from all_source where name = 'DBMS_RANDOM'
and type = 'PACKAGE' order by line;

for documentation
Review & Followup
Rating: 5
May 24, 2001
Reviewer: Bai Huannu from Ireland

May 24, 2001 Sean -- Thanks for the question regarding "re-writing query with outer view ", version 8.0.6
You Asked
Hi Tom,

I have a query to tune:

it is simplified as:

select g.allotment_code
, farv.amsco_code
, farv.fund_type_code
from fund_acct_reg_view farv
, general_ledger_detail
where g.fund_acct_no = farv.fund_acct_no(+)
and g.fns_code = '09038'

fund_acct_reg_view is a view and simplified as:

select fa.fund_acct_no
, fa.amsco_code
, mfa.master_fund_acct_no
, fr.fund_type_code
from funding_account fa
, funding_register fr
, master_funding_account mfa
where fa.master_fund_acct_no=mfa.master_fund_acct_no
and mfa.fund_reg_no=fr.fund_reg_no

If I change the query with substituting the base tables:

select g.allotment_code
, fa.amsco_code
, fr.fund_type_code
from funding_account fa
, funding_register fr
, master_funding_account mfa
, general_ledger_detail
where g.fund_acct_no = fa.fund_acct_no(+)
and g.fns_code = '09038'
and fa.master_fund_acct_no=mfa.master_fund_acct_no
and mfa.fund_reg_no=fr.fund_reg_no

The new one should be identical with the old one, but old one returns three rows
more the the
new one. I could not figure out the reasons.

Additional info, The explain shown the old one has the no-mergeable view, and
FST on the MASTER_FUNDING_ACCOUNT. and the rewritten one shows using the index
on MASTER_FUNDING_ACCOUNT.
and we said...
those are two very different queries.  you are loosing rows on the query against
the base tables because you aren't outer joining to mfa and fr.

the first query says:

  I will get every row in G such that G.fns_code = '09038'.  IF that row has a
  match in FARV, i'll get it otherwise we'll supply NULL for the FARV columns

So, if G has N rows with 09038, you'll get N rows as output.

The second query says:

   Get every row in G such that G.fns_code = '09038'.  If that row has
   a match in FA, I'll get it otherwise we'll supply NULL for the FA
   columns.  Now JOIN that row to MFA by a column in FA --- here is where
   the logic breaks down.  FA columns are NULL with a row doesn't exist in
   FA.  That row now DROPS OUT OF THE RESULT set.  Whenever the row in FA
   is "made up" by the outer join -- the predicate
          "fa.master_fund_acct_no=mfa.master_fund_acct_no"
   ensures it will get dropped -- fa.master_fund_acct_no is NULL and
   that predicate will always be "unknown" -- the row is rejected.
Review & Followup
Rating: 4
May 24, 2001
Reviewer: Sean from Atlanta

Rating: 4
May 24, 2001
Reviewer: Sean from Atlanta
So I need to write as :

and fa.master_fund_acct_no=mfa.master_fund_acct_no(+)
and mfa.fund_reg_no=fr.fund_reg_no(+)

May 24, 2001 Sundar -- Thanks for the question regarding "Orakill utility", version 8.1.6
You Asked
Hi,

I tried to use Orakill to kill a thread. But I am getting an error message
"Orakill unable to attach to the instance err=2"

OS is Windows 2000
Oracle Database Version is 8.1.6

I have used this tool to kill a thread on NT 4.0 server without any problem.

Is there anything special that has to be done on Windows 2000?

Sometime we run into a deadlock issue and Kill session would help us to release
the resources. I have used Orakill and it was helpful. Unfortunately, I can't
use this on the Windows 2000 / 8.1.6 server. Any help on this would be highly
appreciated.

thanks,

Sundar.
and we said...
sounds like you typed in the SID name wrong.  I'm using 8.1.6 on windows 2k and
have not had this issue.

check that the spelling of the sid is correct.

C:\Documents and Settings\Thomas Kyte\Desktop>orakill TKYTE816 1256
Kill of thread id 1256 in instance TKYTE816 successfully signalled.

C:\Documents and Settings\Thomas Kyte\Desktop>orakill TKYTE816x 1256
Could not attach to Oracle instance TKYTE816x: err = 2

when the sid is wrong -- it does not work.
Review & Followup
Rating: 3
Please include the syntax also if possible to help others July 20, 2001
Reviewer: Pichaimani Balasubramanian from San Jose, CA USA

Rating: 4
that works from the console April 25, 2003
Reviewer: eric givler from harrisburg, pa
Orakill works from the server, but not through a terminal services session.  The
error reported here matches the same error we got when running the client.

May 24, 2001 Bhaskara -- Thanks for the question regarding "Optimizor", version 815
You Asked
Hi Tom,

     What are advantages and disadvantages of Rule based optimizor over Cost
based optimizor ?

     Thanks you very much in advance.
Regards,
Bhaskara
and we said...
Any new application should use CBO -- period.

Any legacy application, they can test with CBO and see how it goes -- else just
stick with RBO.

Most all new features (function based indexes, descending indexes, materialized
views, partitioned tables, bitmap indexes, etc etc etc) function ONLY when using
the CBO.
Review & Followup
Rating: 3
May 25, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

May 24, 2001 -- Thanks for the question regarding "Selecting primary key columns with not null constraints", version 8.1.5
You Asked
Currently we have columns in our database that are defined as primary keys as
well as defined with a not null constraint in them. Since the not null
constraint is unnecessary, we would like to drop it. How do I select all columns
with NOT NULL constraints that are also either a primary key or part of a
primary key?
and we said...
Here is a query to get you going -- haven't fully tested it on every possible
condition....

tkyte@TKYTE816> create table t ( x int not null primary key );
Table created.

tkyte@TKYTE816> select a.constraint_name, b.column_name, a.search_condition
  2    from user_constraints a, user_cons_columns b
  3   where a.constraint_name = b.constraint_name
  4     and a.constraint_type = 'C'
  5     and exists ( select null
  6                    from user_constraints c, user_cons_columns d
  7                   where c.table_name = a.table_name
  8                     and c.constraint_type = 'P'
  9                     and d.column_name = b.column_name )
 10  /

CONSTRAINT_NAME
------------------------------
COLUMN_NAME
-----------------------------------------------------------------------------

SEARCH_CONDITION
-----------------------------------------------------------------------------
SYS_C004959
X
"X" IS NOT NULL

tkyte@TKYTE816> alter table t modify x null;
Table altered.

Note that X is still "not null" -- the P constraint does that for us

tkyte@TKYTE816> select a.constraint_name, b.column_name, a.search_condition
  2    from user_constraints a, user_cons_columns b
  3   where a.constraint_name = b.constraint_name
  4     and a.constraint_type = 'C'
  5     and exists ( select null
  6                    from user_constraints c, user_cons_columns d
  7                   where c.table_name = a.table_name
  8                     and c.constraint_type = 'P'
  9                     and d.column_name = b.column_name )
 10  /

no rows selected
May 24, 2001 Kiran -- Thanks for the question regarding "Query for converting row to column", version Oracle 8.1.5
You Asked
Hi Tom,
My question is as follows

Structure of table:
Barcode varchar2(30)
defect_id varchar2(15

Data in table
Barcode        id1      id2     id3      id4    empid1   empid2
-------        ------------------------------   -----    ------
B2034          L03X                             1024
B2034                   L01S                              1034
B2034                            L0D
B2034                                     AS01
Z01b34                  24AZ
Z01b34                                     df89

I want the data to shown as :
Barcode     id1    id2    id3   id4    empid1       empid2
-------     ---    ---    ---   ---    ------       ------
B2034       L03X   L01S   L0D   AS01   1024          1034
Z01b34             24AZ         df89

Please let me know how this can be solved

Thanks.

Kiran
and we said...
in that particular case --

select barcode, max(id1), max(id2), ... max(empid1), max(empid2)
  from t
 group by barcode
/

will get you that result set, however if you have data like:

Data in table
Barcode        id1      id2     id3      id4    empid1   empid2
-------        ------------------------------   -----    ------
B2034          L03X                             1024
B2034                   L01S                              1034
B2034                            L0D            1234
B2034                                     AS01            5678
Z01b34                  24AZ
Z01b34                                     df89

you'll "miss" some of the empid1's and empid's -- only the max within a barcode
will come out.
May 25, 2001 Bhavesh -- Thanks for the question regarding "How to Determine size of a bfile", version 1.0.2.0.0
You Asked
Hi Tom,
    Is there any way by which we can determine the size of bfile which is in
bfile column of the table.

Say I have a table as:
sno       number(3) not null primary key,
ext_lob   bfile

and i load the data as
insert into lob_table VALUES (21, BFILENAME('my_files', 'back.gif'));

What I need to know is the size of this file named back.gif. Is there any way to
find this ?
Regards

Bhavesh
and we said...
ops$tkyte@ORA8I.WORLD> create or replace directory my_files
                               as '/export/home/tkyte'
  2  /
Directory created.

ops$tkyte@ORA8I.WORLD> drop table t;
Table dropped.

ops$tkyte@ORA8I.WORLD> create table t ( x int, y bfile );
Table created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1, bfilename( 'MY_FILES',
'test.sql' ) );

1 row created.

ops$tkyte@ORA8I.WORLD> select dbms_lob.getlength(y) from t;

DBMS_LOB.GETLENGTH(Y)
---------------------
                  253

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> !ls -l /export/home/tkyte/test.sql
-rw-r--r--   1 tkyte         253 May 25 08:25 /export/home/tkyte/test.sql
Review & Followup
Rating: 5
Very Good May 25, 2001
Reviewer: Bhavesh
Exactly that is what I was looking for. Thanks a lot.

May 25, 2001 Prashanth -- Thanks for the question regarding "dbms_obfuscation_toolkit.DESEncrypt - ORA-06508: PL/SQL: could not find program unit being called", version 8.1.6.0.0
You Asked
Hi,

i want to encrypt a few fields in a table. so i am trying to use
dbms_obfuscation_toolkit.DESEncrypt in Oracle 8.1.6.0.0
i have writen a small test package to test out the
dbms_obfuscation_toolkit.DESEncrypt

i have managed to complie my pacakage successfully. but when i try to exceute my
package the excution aborts while trying to call
dbms_obfuscation_toolkit.DESEncrypt.

I have excute grant on the dbms_obfuscation_toolkit package and also the public
synonym is created.

I even tried executing my test package using the 'SYS' ID of oracle but the same
result.

Can any one help me out as to why i am not able to access the
dbms_obfuscation_toolkit.DESEncrypt procedure.

i get the error ORA-06508: PL/SQL: could not find program unit being called.

i have attached the out put below.
in my PL/SQL code i have added hint lines "just before calling
dbms_obfuscation_toolkit.DESEncrypt" and "just after calling
dbms_obfuscation_toolkit.DESEncrypt". when the exception is raised it shows the
hint as "just before calling dbms_obfuscation_toolkit.DESEncrypt". This means
that the program is aborting at the call to dbms_obfuscation_toolkit.DESEncrypt.

i am able to do  "desc dbms_obfuscation_toolkit"  as well as
select * from all_objects where object name = 'DBMS_OBFUSCATION_TOOLKIT' using
my userid (as well as sys id).

SQL> @test.sql
Package created.
No errors.
Package body created.
No errors.

SQL> set  serveroutput on
SQL> exec   pcpf_test_enc.pcpf_enc
> ====== BEGIN TEST =======
> Input String             prashanth
BEGIN pcpf_test_enc.pcpf_enc; END;
*
ERROR at line 1:
ORA-20001: pcpf_test_enc ORA-06508: PL/SQL: could not find program unit being
called hint = before opening the dbms_obfuscation_toolkit.DESEncrypt
ORA-06512: at "SYS.PCPF_TEST_ENC", line 46
ORA-06512: at line 1

SQL> show user
USER is "SYS"

The PL/SQL procedure is as follows.:

--start of test.sql
--=================

set define off;
set serveroutput on;
CREATE OR REPLACE PACKAGE pcpf_test_enc AS
    PROCEDURE pcpf_enc;
END pcpf_test_enc;
/
show errors;

CREATE OR REPLACE PACKAGE BODY pcpf_test_enc AS

    PROCEDURE pcpf_enc IS
        input_string VARCHAR2(16) := 'prashanth';
        key_string VARCHAR2(8) := 'kumar';
        encrypted_String  VARCHAR2(2048);
        decrypted_String  VARCHAR2(2048);
        raw_key VARCHAR2(100);
        hint VARCHAR2(100);

        error_in_input_buffer_length EXCEPTION;

        BEGIN
            null;
            dbms_output.put_line('> ====== BEGIN TEST =======');
            dbms_output.put_line('> Input String             '|| input_string);
                hint := 'before opening the
dbms_obfuscation_toolkit.DESEncrypt';
                dbms_obfuscation_toolkit.DESENCRYPT(input_String =>
input_string,
                                                     key_string   => key_string,
                                                     encrypted_string =>
encrypted_string);
                hint := 'after opening the dbms_obfuscation_toolkit.DESEncrypt';

                dbms_output.put_line('> encrypted_string     '||
encrypted_string);

                hint := 'before opening the
dbms_obfuscation_toolkit.DESDecrypt';
                dbms_obfuscation_toolkit.DESDECRYPT(input_string =>
encrypted_string,
                                                    key_string => raw_key,
                                                    decrypted_string =>
decrypted_string);
                hint := 'after opening the dbms_obfuscation_toolkit.DESDecrypt';
                dbms_output.put_line('> decrypted_string     '||
decrypted_string);
                dbms_output.put_line('> ');
                IF input_string = decrypted_string THEN
                    dbms_output.put_line('> DES Encryption and Decryption
successful');
                END IF;
        EXCEPTION
                WHEN OTHERS THEN
                           RAISE_APPLICATION_ERROR(-20001,'pcpf_test_enc
'||sqlerrm||' hint = '||hint);
        END pcpf_enc;
END pcpf_test_enc;
/
show errors

--================
--End of test.sql
--================

Here is the output of the select query.

SQL> desc dbms_obfuscation_toolkit
PROCEDURE DESDECRYPT
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 INPUT                          RAW                     IN
 KEY                            RAW                     IN
 DECRYPTED_DATA                 RAW                     OUT
PROCEDURE DESDECRYPT
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 INPUT_STRING                   VARCHAR2                IN
 KEY_STRING                     VARCHAR2                IN
 DECRYPTED_STRING               VARCHAR2                OUT
PROCEDURE DESENCRYPT
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 INPUT                          RAW                     IN
 KEY                            RAW                     IN
 ENCRYPTED_DATA                 RAW                     OUT
PROCEDURE DESENCRYPT
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 INPUT_STRING                   VARCHAR2                IN
 KEY_STRING                     VARCHAR2                IN
 ENCRYPTED_STRING               VARCHAR2                OUT

SQL>
SQL>
SQL>
SQL> select * from all_objects where object_name = 'DBMS_OBFUSCATION_TOOLKIT';

OWNER                          OBJECT_NAME
------------------------------ ------------------------------
SUBOBJECT_NAME                  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE
------------------------------ ---------- -------------- ------------------
CREATED   LAST_DDL_ TIMESTAMP           STATUS  T G S
--------- --------- ------------------- ------- - - -
SYS                            DBMS_OBFUSCATION_TOOLKIT
                                    18495                PACKAGE
22-MAY-01 22-MAY-01 2001-05-22:17:49:44 VALID   N N N

PUBLIC                         DBMS_OBFUSCATION_TOOLKIT
                                    18476                SYNONYM
22-MAY-01 22-MAY-01 2001-05-22:17:49:44 VALID   N N N

OWNER                          OBJECT_NAME
------------------------------ ------------------------------
SUBOBJECT_NAME                  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE
------------------------------ ---------- -------------- ------------------
CREATED   LAST_DDL_ TIMESTAMP           STATUS  T G S
--------- --------- ------------------- ------- - - -

SYSTEM                         DBMS_OBFUSCATION_TOOLKIT
                                    18493                PACKAGE
22-MAY-01 22-MAY-01 2001-05-22:15:56:14 VALID   N N N
SQL>
SQL>

Thanx  in advance
Prashanth
and we said...
somebody installed the package into SYSTEM.  It belongs only in SYS.

Log in as system and drop that package.

also, someone has only installed the SPEC of dbms_obfuscation_toolkit -- the
package body is missing.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:899028482141
for the proper method to install this tool
Review & Followup
Rating: 4
SYS.DBMS_OBFUSCATION_TOOLKIT is working - thanx asktom June 01, 2001
Reviewer: Prashanth Kumar from Singapore
Thank you very much. I managed to get the package working.
i reinstalled using catobtk.sql and it started to work.
Thanx again.

May 25, 2001 Rajesh -- Thanks for the question regarding "Disconnecting from a current user and then connecting back to the same user", version 8i
You Asked
Hi Tom,

I do have a peculiar problem that I am facing. Here's the scenario:-

I have a created a schema(user) say 'SCOTT' in my database that does not have a
DBA rights, I want to write a stored procedure that will internally connect as
'SYSTEM/MANAGER' and then create a user 'RAJESH' with all the grant options and
then connect back as 'SCOTT'. I have tried using DBMS_SQL package for that but
am facing errors.

Kindly suggest me something to solve this problem. looking forward for your
answer ASAP.

Thanx and Regards,
Rajesh Ballal.
and we said...
You have missed the point of procedures.

Procedures, by default, run with the base set of priveleges of the OWNER of the
procedure.

Here is what you do:

o CREATE a schema (do not put your code in SYS or SYSTEM or any other oracle
supplied account).

o GRANT create session, create procedure, create user to this schema.  Grant any
roles you want this schema to be able to grant to other users with the ADMIN
option.

o create a procedure in this schema "create_user" that creates the user

o grant execute on this procedure to the people you want to have execute on it.

Here is a full example demonstrating the steps:

ops$tkyte@DEV816> create user create_user_schema identified by x;
User created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> grant create session, create procedure, create user
  2  to create_user_schema;
Grant succeeded.

ops$tkyte@DEV816> grant connect to create_user_schema with admin option;
Grant succeeded.

ops$tkyte@DEV816> @connect create_user_schema/x

create_user_schema@DEV816> create procedure create_user( p_uname in varchar2 )
  2  as
  3  begin
  4          execute immediate
  5          'create user ' || p_uname || ' identified by ' ||
  6                                            p_uname;
  7
  8          execute immediate
  9          'grant connect to ' || p_uname;
 10
 11  end;
 12  /
Procedure created.

create_user_schema@DEV816> grant execute on create_user to scott
  2  /
Grant succeeded.

create_user_schema@DEV816> @connect scott/tiger

scott@DEV816> select * from all_users where username ='TEST_USER';
no rows selected

 user does not exist...

scott@DEV816> create user test_user identified by test_user;
create user test_user identified by test_user
                                    *
ERROR at line 1:
ORA-01031: insufficient privileges

and scott is not allowed to create users...

scott@DEV816> exec create_user_schema.create_user( 'test_user' )

PL/SQL procedure successfully completed.

scott@DEV816> select * from all_users where username ='TEST_USER';

USERNAME                          USER_ID CREATED
------------------------------ ---------- ---------
TEST_USER                             494 25-MAY-01

but the CREATE_USER_SCHEMA user is and its procedure can -- procedures execute
with the set of privs of the OWNER of the procedure by default.
Review & Followup
Rating: 5
scott/tiger schema November 14, 2002
Reviewer: mo
Tom:

I am setting sql*plus environment per your book in a development instance I use.

1.  How can I check if scott/tiger schema is already installed? What is the host
string you type when you do
connect scott/tiger@???.

2. Do I need a system/manager priviledge to run some examples?

Thank you,

May 25, 2001 LOUIS -- Thanks for the question regarding "DBMS_OBFUSCATION_TOOLKIT", version 8.1.7
You Asked
Hi tom,

I am in the process of testing a web application. However
I am trying to use your example about DBMS_OBFUSCATION_TOOLKIT but
you used bind variables. So, I am running into a problem. I need to incrypt and
most important descrypt  the credit card field. So, I guess I need to use the
DBMS_OBFUSCATION_TOOLKIT in a procedure or function. Can you help me please or
tell me the best way to do this?? I will appreciate it so much, without a doubt
I will take to you lunch when you are in new york....

Louis Lugo
DBA
and we said...
Here is the same example from
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:791026226790
written as procedures.  Bind variables are simply replaced with formal
parameters (thats the only change I've made)...

Here it is:

ops$tkyte@DEV816> variable x varchar2(25)

ops$tkyte@DEV816> exec :x := 'How Now Brown Cow';
PL/SQL procedure successfully completed.

X
--------------------------------
How Now Brown Cow

ops$tkyte@DEV816> create or replace procedure crypt( p_str in out varchar2 )
  2  as
  3      l_data  varchar2(255);
  4  begin
  5      l_data := rpad( p_str, (trunc(length(p_str)/8)+1)*8, chr(0) );
  6
  7      dbms_obfuscation_toolkit.DESEncrypt
  8          ( input_string => l_data,
  9        key_string   => 'MagicKey',
 10        encrypted_string=> p_str );
 11  end;
 12  /
Procedure created.

ops$tkyte@DEV816> create or replace procedure decrypt( p_str in out varchar2 )
  2  as
  3      l_data  varchar2(255);
  4  begin
  5      dbms_obfuscation_toolkit.DESDecrypt
  6          ( input_string => p_str,
  7        key_string   => 'MagicKey',
  8        decrypted_string=> l_data );
  9
 10      p_str := rtrim( l_data, chr(0) );
 11  end;
 12  /
Procedure created.

ops$tkyte@DEV816> set autoprint on
ops$tkyte@DEV816> exec crypt( :x )

PL/SQL procedure successfully completed.

X
--------------------------------
Rr=p]w]pSWq:]PtJ?T,

ops$tkyte@DEV816> exec decrypt( :x )

PL/SQL procedure successfully completed.

X
--------------------------------
How Now Brown Cow

follow up to comment one.

Well, I guess I would write a FUNCTION then.  Something like this:

  2  function crypt( p_str in varchar2 ) return varchar2
  3  as
  4      l_data  varchar2(255);
  5  begin
  6      l_data := rpad( p_str, (trunc(length(p_str)/8)+1)*8, chr(0) );
  7
  8      dbms_obfuscation_toolkit.DESEncrypt
  9          ( input_string => l_data,
 10            key_string   => 'MagicKey',
 11            encrypted_string=> l_data );
 12
 13      return l_data;
 14  end;
 15  /

Function created.

scott@DEV816>
scott@DEV816> create or replace
  2  function decrypt( p_str in varchar2 ) return varchar2
  3  as
  4      l_data  varchar2(255);
  5  begin
  6      dbms_obfuscation_toolkit.DESDecrypt
  7          ( input_string => p_str,
  8            key_string   => 'MagicKey',
  9            decrypted_string=> l_data );
 10
 11      return rtrim( l_data, chr(0) );
 12  end;
 13  /
Function created.

scott@DEV816> column decrypt format a30
scott@DEV816> drop table t;

Table dropped.

scott@DEV816> create table t ( data varchar2(32) );
Table created.

scott@DEV816> insert into t values ( crypt( 'Hello World' ) );
1 row created.

scott@DEV816> select data, decrypt(data) decrypt from t;

DATA                             DECRYPT
-------------------------------- ------------------------------
7??-,?P I{CK??!                  Hello World

scott@DEV816>
Review & Followup
Rating: 3
"DBMS_OBFUSCATION_TOOLKIT", version 8.1.7 May 25, 2001
Reviewer: Louis Lugo from new york
Thanks tom for your prompt response. However, how am I going  to use this
example with let's say encrypting
a table field?

Rating: 5
Excellent - how to hide the key though? November 16, 2001
Reviewer: Doug Cowles from CT, USA
Very useful.  How do we hide the key though.   A bind variable will help with
tkprof, but it will have to be defined in the code somewhere which will allow it
to be seen in all_source.  Other ideas?

May 25, 2001 Uday -- Thanks for the question regarding "Can i pass "C" structures to Oracle", version 8i
You Asked
Hi Tom,
I want to pass a "C" structure as a parameter to Oracle procedure/function.
Is this possible or should i have to pass each variable by variable if i cant
pass a C structure.
  This requirement came up because our PRO*C programs gets the structures and
does the DML operations by passing variable by variable which consumes time.
So instead if i can pass the struncture as it is i can do the rest of the
operations in the procedure/function which i write in the database which will
improve my performacne.

Hope i made the question clear.Let  me know if you require any clarification on
the question.

Thanks & Regards
Uday.
++++++++++++++++++++++++++++++++++++++++++++++++++
Additional information:

Ex:I am giving a prototype of the code:

typedef struct
{ int x;
  int y;
  Struct st1;
} my_rec;

typedef st1
{
   int xx;
   int yy;
   int zz;
}

suppose i have a procedure in oracle:
Create procedure Test(Integer one,???????)
{
}

Can ??????? be a "C" structure.

Thanks & Regards
Uday.
and we said...
It can be a C structure if called from SQL.  Consider:

create or replace function p(p_x in number, p_y in number )
return number
as
begin
   return p_x+p_y;
end;
/

static void process()
{
exec sql begin declare section;

typedef struct
{ int x;
  int y;
} my_rec;

my_rec data;
int    x;
exec sql end declare section;

    data.x = 1;
    data.y = 2;

    EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();
    exec sql select p(:data) into :x from dual;

    printf( "return value= %d\n", x );
}

that works.  Note that it must be a FUNCTION.  Also, it cannot have any OUT
parameters.  Lastly, if it modifies the database, it MUST be an autonomous
transaction.

Another method would be:

scott@DEV816> create or replace function p(p_x in OUT number, p_y in OUT number
)
  2  return number
  3  as
  4          l_tmp number := p_y;
  5  begin
  6          p_y := p_x;
  7          p_x := l_tmp;
  8     return p_x+p_y;
  9  end;
 10  /

Function created.

scott@DEV816> create global temporary table p_interface_table
  2  ( x int, y int, return_code number )
  3  on commit delete rows
  4  /

Table created.

scott@DEV816> create or replace trigger p_interface_table_trigger
  2  BEFORE insert on p_interface_table for each row
  3  begin
  4          :new.return_code := p(:new.x, :new.y);
  5  end;
  6  /

Trigger created.

static void process()
{
exec sql begin declare section;

typedef struct
{ int x;
  int y;
  int return_code;
} my_rec;

my_rec data;
int    x;
exec sql end declare section;

    data.x = 1;
    data.y = 2;

    EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();
    exec sql insert into p_interface_table values ( :data );

    exec sql select * into :data from p_interface_table;

    printf( "x, y, return value= %d, %d, %d\n",
             data.x, data.y, data.return_code );
}

That lets you do in out variables and does not make you use an autonomous
transaction if the procedure/function (you can use either here of course)
modifies the database as well.
May 25, 2001 Parames -- Thanks for the question regarding "Display result of 2 queries side by side", version 8.1.7
You Asked
Hi tom

I am having a table called a where i have 10 columns col1.... col10.

In this col1 and col2 is primary key.  Possible values for col2 is 1 and 2 only.

Whenever a row is inserted with value '1','1' in col1,col2 respectively,
definitely it will have one more row with value '1','2' in col1 and col2
respectively.  Hence the table will have rows only in multiples of 2.  But the
values in the cols col3..col10 would differ.  My requirement is:

I need to get a result set in the following fashion:

1,1,col3,col4,col5,col6,col7,col8,col9,col10,1,2,col3,col4,col5,col6,col7,col8,co
l9,col10

2,1,col3,col4,col5,col6,col7,col8,col9,col10,2,2,col3,col4,col5,col6,col7,col8,co
l9,col10

3,1,col3,col4,col5,col6,col7,col8,col9,col10,3,2,col3,col4,col5,col6,col7,col8,co
l9,col10

I need to display the values side by side for all the rows that have same value
in the col1.

Thanks in advance

sathish
and we said...
select col1,
       max( decode( col2, '1', col3, null ) ) col3_1,
       max( decode( col2, '1', col4, null ) ) col4_1,
       ....
       max( decode( col2, '1', col10, null ) ) col10_1,
       max( decode( col2, '2', col3, null ) ) col3_2,
       max( decode( col2, '2', col4, null ) ) col4_2,
       ....
       max( decode( col2, '2', col10, null ) ) col10_2
  from t
 group by col1
/
May 25, 2001 sam -- Thanks for the question regarding "query and current in tkprof output", version 8.1.7
You Asked
call     count       cpu    elapsed       disk      query    current        rows
------- ------ -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.01          1          3          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.01       0.02          1          3          0           1

Above is the tkprof output ..

1.From the above output it shows that, the sql statement has been parsed once.
Iam I right.
Is a sql statement parsed more than one time, is it good or bad, what does it
signigy i.e. what does it tell. Why will a sql statement get parsed twice.
Should we make any change in the sql statement so that it is parsed only once.

If for a session there are totally 100 sql statements and the parse count is 10,
what does this signify?

2.In the above example there are 1 disk reads, and 3 logical reads.
Logical reads = current+query;
By logical reads do we mean that the data is being read from the data buffers.
What do current and query mean within the context of logical reads.

Which one is better more disk reads or more buffer reads and why?

If disk reads are much much more than the logical reads , what should be done to
increase the buffer reads? Are there any changes we need to make in the query?

3.For example if the execute and fetch count for a sql statement is 100 and the
rows returned is 70 , what does this tell. What are the changes suggested in the
sql statements.
What is going wrong?

Tom, Iam immersed in the world of tkprof as of now, so you can expect a few more
questions like this from me. But be assured that with each passing hour , the
clarity in my questions will increase.

Thank you
and we said...
1) yes, parsed once.
   if you have it parsed more then once in the same program execution, you have
just wasted resources.  You should strive for a parse count of 1.  In your case,
you only EXECUTED it once so this is a trivial example.  You would like to see a
parse followed by many executes.

You will get a parse count > 1 by explicitly coding something like:

   loop
      open cursor
      parse statment
      bind values
      execute cursor
      close cursor
   end loop

in this case, you should code:

   open cursor
   parse statment

   loop
      bind values
      execute cursor
   end loop
   close cursor

how you achieve this exactly varies by the language you program in and the API
you us.

if you have 100 sql statments and only 10 parses -- you have done something
magical.  You have executed 90 statements without even parsing them.

I think what you mean is "if a SINGLE statement was parsed ten times and
executed 100 times -- what does this signify".  It signifies you parsed it 9
times more then you should have.

2) logical ios are buffer reads, yes.

o QUERY – How many blocks we processed in 'consistent read' mode. This will
include counts of blocks read from the rollback segment in order to 'rollback' a
block.

o CURRENT – How many blocks were read in 'current' mode. Current mode blocks are
retrieved as they exist right now, not in a consistent read fashion. Normally,
blocks retrieve for a query are gotten as they existed when the query began.
Current mode blocks are gotten as they exist right now, not from a previous
point in time.  During a SELECT, we might see current mode retrievals due to
reading the data dictionary to find the extent information for a table to do a
full scan (we need the 'right now' information on that, not the consistent
read). During a modification, we will access the blocks in current mode in order
to write to them.

doing a physical IO takes longer then a buffered read, you should strive to do
buffered reads in most cases.

3) if you execute a query 100 times and fetch from it 100 time and get 30 rows
-- that indicates 30 times it returned no data.

Consider:

create table t as select rownum x from all_objects where rownum <= 70;

begin
   for i in 1..100
   loop
       begin
          select x into l_x from t where x = i;
       exception
           when no_data_found then l_x := null;
       end;
       .....
   end loop;

that'll execute the query 100 times -- find only 70 rows.  thats what that
means.  It is not an error, it is what it is ;)

My book, coming out in June, has a big chapter on this stuff with lots more
detail.
May 25, 2001 Parames -- Thanks for the question regarding "how to disply 2 result sets side by side", version 8.0
You Asked
Hi tom

This is regarding my previous question 'how to disply 2 result sets side by
side'.  I want a workable solution in ver 8.0

Thanks
sathish
and we said...
did you even try it?

that is what I gave to you.  that'll work in any oracle version.

Here it is in 7.1.6:

scott@ORA716.WORLD> create table t ( col1 int, col2 int, col3 int, col4 int );

Table created.

scott@ORA716.WORLD>
scott@ORA716.WORLD> insert into t values ( 1, 1, 3, 4 );

1 row created.

scott@ORA716.WORLD> insert into t values ( 1, 2, 13,14 );

1 row created.

scott@ORA716.WORLD>
scott@ORA716.WORLD> insert into t values ( 2, 1, 23, 24 );

1 row created.

scott@ORA716.WORLD> insert into t values ( 2, 2, 33, 34 );

1 row created.

scott@ORA716.WORLD>
scott@ORA716.WORLD> select col1,
  2         max( decode( col2, '1', col3, null ) ) col3_1,
  3         max( decode( col2, '1', col4, null ) ) col4_1,
  4         max( decode( col2, '2', col3, null ) ) col3_2,
  5         max( decode( col2, '2', col4, null ) ) col4_2
  6    from t
  7   group by col1
  8  /

      COL1     COL3_1     COL4_1     COL3_2     COL4_2
---------- ---------- ---------- ---------- ----------
         1          3          4         13         14
         2         23         24         33         34

scott@ORA716.WORLD>
Review & Followup
Rating: 5
Thankx May 26, 2001
Reviewer: Riaz Shahid from Pakistan
It was really very useful to me....

May 25, 2001 Susan -- Thanks for the question regarding "delete on cascade or trigger to maintain referential integrity?", version 8i
You Asked
Hello,

What are the advantages or disadvantages of using triggers on parent tables to
delete from child tables versus on delete cascade foreign key constraint?

Thanks.

Susan McCarthy
and we said...
Triggers are intrepreted code.  they run slower then declaritive operations.

Triggers are code, you have to write them and maintain them.  Declaritive
operations are just that -- declare it and it'll be done.

Declaritive operations are documented in the data dictionary.  It becomes more
meta-data about your system.  Triggers are code, you have to read them to
understand them.

never do something in a trigger that you can do in a declaritive fashion.
Review & Followup
Rating: 3
July 12, 2001
Reviewer: A reader

May 25, 2001 Greg -- Thanks for the question regarding "Oracle and Active Directory", version 8i
You Asked
My company has select MS Active Directory for the enterprise directory services.
 We would like to integrate our Oracle networking with AD, in lieu of TNSNAMES
or Oracle Names, for database connection resolution.  However, we are having a
hard time finding any resources (white papers, articles, books, etc) that can
help with our understanding of the architecture and implementation of Oracle and
Active Directory.  Do you have any suggestions?
and we said...
Article-ID:         <Note:111424.1>
Circulation:        PUBLISHED (EXTERNAL)
Folder:             server.DBA.Security
Title:              How to Install Oracle 8.1.6 with Integration for Windows
                    2000 Active Directory
Document-Type:      BULLETIN
Impact:             LOW
Skill-Level:        NOVICE
Server-Version:     08.01.06
Updated-Date:       04-APR-2001 09:16:51
References:
Shared-Refs:
Attachments:        NONE
Content-Type:       TEXT/PLAIN
Keywords:           8.1.6; ACTIVE; DATABASE; DIRECTORY; INSTALL; REGISTER;
Products:           5/RDBMS;
Platforms:          100;

PURPOSE
-------

To Install Oracle 8.1.6 With Integration for
Microsoft Windows 2000 Active Directory

SCOPE & APPLICATION
-------------------

Intended Audience: DBA
Use: Help for installing 8.1.6 with Active Directory

How to Install Oracle 8.1.6 with Integration for
Microsoft Windows 2000 Active Directory
------------------------------------------------

I.    Introduction
A.    This document introduces the procedures for performing a Typical
install of the Oracle 8.1.6.0.0 EE database on a Windows 2000 server domain
controller.  The operating system on this server is installed with one 6 GB
partition, formatted as NTFS with the default permission settings.  The fully
qualified domain name of the server is rocky.mountain.com, with a downlevel
NetBIOS name of Rocky (the domain controller for the Mountain domain).

B.    It should be noted that although this procedure has been performed
on the only domain controller in the Active Directory forest, the steps are
very similar if they are performed on a member server in an Active Directory
domain.  Moreover, this domain controller will be left in mixed mode (an Active
Directory status which allows interaction with downlevel Windows NT domain
controllers).

II.    Requirements
A.    It is vital that the person performing this procedure has the proper
administrative control, both in the Active Directory forest, as well as on the
local member server (if this procedure is performed on a member server), or
domain controller.  Integrating the Oracle database with Active Directory will
cause a modification of the Active Directory Schema and will also create new
services.  Since these processes will run with the credentials of the logged on
user, it is required that the person logged on has the necessary credentials
for performing these tasks.

B.    The person who is installing the Oracle 8.1.6 database must be a member
of the Schema Admins group in order to make changes to the Active Directory
Schema.  By default, this group has only one member: the Administrator account
of the first domain in the forest.  If the installer is not using this account,
the installer must be manually added to Schema Admins prior to installing the
database.  Keep in mind that when a user is added to this group, that user must
log off and log back on in order to have the new membership reflected in the
access token of the user (i.e., to have this new membership take effect).  This
person should also be a member of Domain Admins and this group should be a
member of the local Administrators group.  The Administrator account in the
first domain created in the forest is a member of all of these groups by
default, as well as being a default member of Enterprise Admins (a forest
level group).  If possible, the installer should log on as Administrator, the
administrative account in the first domain in the forest and check to make sure
that this account has the proper forest wide control.  If it is not possible to
log on with this account, the installer must at the very least be a member of
the local Administrators group and a member of the forest wide Schema Admins
group.

C.    DNS should be properly installed somewhere in the Active Directory
forest, and the installer should verify that the service is available and
correctly resolving the machine names involved in the installation of the
database.  This is especially important if the database is being installed
on a machine which is remote from the domain controller where the Schema
resides (by default, the first domain controller in the first domain in the
Active Directory forest is the Schema Operations Master).

III.    Procedures
A.    Create or open a Microsoft Management Console which contains snap-ins
for Active Directory Domains and Trusts, Active Directory Sites and Services,
Active Directory Users and Computers, and Computer Management.  This mmc is
necessary to enable writing to the Schema and perform troubleshooting as
necessary.  To create the mmc, Click Start, Run, and type mmc.  When the window
opens, click the Console menu and click Add/Remove Snap-in.  When that window
opens, click Add.  When the Add Standalone Snap-in window opens, highlight the
above snap-ins one at a time and click add.  When all are added, click close,
then OK, and then save the console by clicking on the Console menu, click Save
As and choose a location and name for the new console.  Leave the console open.

B.    In order to install a snap-in for the Active Directory Schema, you must
first register a .dll file to make the tool visible.  Click Start, Run, and
type regsvr32 schmmgmt.dll.  You should see a confirmation window stating:
“DllRegisterServer in schmmgmt.dll succeeded”.  Click OK.

C.    On the Console menu of your new console, click Add/Remove Snap-in.
When the Add/Remove Snap-in Window opens, click Add.  When the Add Standalone
Snap-in window opens, you should see a new snap-in listed second from the top
called Active Directory Schema.  Highlight it and click Add.  Click Close and
then OK.  Your console should now show Active Directory Schema at the bottom
of the console tree.  Click the Console menu, and click Save.

D.    Right-click Active Directory Schema and click Operations Master.  Click
the check box next to “The Schema may be modified on this Domain Controller”.
Note the name of the operations master on which the schema resides.  Click OK
to close the box.

E.    Ensure that you have sufficient free space to install the database.
A typical install requires 1001 MB, but expansion of the installation files may
require up to 2 GB for the install to succeed.  Place the Oracle 8.1.6 EE
CD-ROM into the CD-ROM drive and when the auto-run brings up the Install
window, click Install/Deinstall Products.

F.    At the Welcome Screen, Click Next.

G.    Modify or accept the name and location for the Destination options and
click Next.

H.    Ensure that Oracle8i Enterprise Edition 8.1.6.0.0 is selected and click
Next.

I.    Ensure that Typical is selected and click Next.

J.    Type in orcl.world at the Global Database Name window.  Orcl should now
appear in the SID window.  Click Next.

K.    At the Summary window, click Install

L.    At the end of the install, click Exit and Yes to confirm the exit.

M.    At this point, you must configure the naming methods and Directory
Service Access.

N.    Click Start, Programs, Oracle- OraHome81, Network Administration, Net8
Configuration Assistant.

O.    Select Directory Service Access configuration.

P.    Select Perform directory access configuration for a server.

Q.    Pull down the Directory Type select box and choose Microsoft Active
Directory and click Next.

R.    At the Hostname window, type in the fully qualified domain name of the
domain controller on which the schema resides.  For this example, the fully
qualified domain name of my server is rocky.mountain.com.  Click Next.

S.    Ensure that “Yes, I want to add the required Oracle Schema” is selected
and click Next only ONCE.  This process may take up to a minute.  You will
receive a warning which appears to be an error that states that the NET8
Configuration Assistant is unable to create or update the schema.  The process
has actually succeeded.  Click OK only ONCE to close the window.

T.    You may see another window with a Red alarm bell.  Select “I want to
verify the directory service information and try again” and click OK

U.    Ensure that Directory Service Access configuration is selected and
click Next.

V.    Select Perform directory access configuration for a server and click
Next.

W.    Ensure that Directory Type is selected for Microsoft Active Directory
and click Next.

X.    Type in the fully qualified domain name of your schema operations
master and click next.

Y.    Note that this screen has now changed from the option in step S to
“Yes, I want to create a new Oracle Context”.  Click Next only ONCE and you
should receive a message that Directory Server Access configuration is complete.

Click Next and select Naming Methods configuration and click Next.

Z.    Select “Directory” from the left window and click the right arrow.  You
may choose to remove Oracle Names and Host Name from the list, but ensure that
you have at least Directory and local in the right window and then click Next
and Next again.  You will receive a message that Naming methods configuration
is complete.  Click Next and then Finish.

AA.    Open your mmc console, expand the Active Directory Schema and highlight
Classes.  In the right pane, scroll down and you should note several classes
which begin with orcl.  The Schema has now been updated to reflect Oracle
objects.

BB.    Expand the Active Directory Users and Computers and Expand the domain
name and expand the Oracle Context.  If any of the icons are not fully formed,
log off and log back on.  This is caused by the addition of your account to
groups created by the Active Directory configuration.  Logging back on will
update your access token.

CC.    Close the mmc console.  Leaving it open at this point may cause the
next procedure to fail.

DD.    To register the database with Active Directory, Click Start, Programs,
Oracle-OraHome81, Database Administration, Database Configuration Assistant.

EE.    When the application opens, select Change database configuration.

FF.Ensure that the servicesid for your database is selected
and click Next.

GG.    Select Dedicated Server mode and click Next. Click Next again.

HH.    Ensure that Yes, register the database is selected and click Finish.

II.     You will be prompted to confirm the location of the init.ora file
for your database. Confirm it and click OK.  You will be prompted to confirm
the changing of the init.ora.  Click OK.

JJ.    Open the mmc console, expand Active Directory Users and Computers and
Expand the domain name and expand the Oracle Context.  You should now notice
that the sid name of your database appears under Oracle Context.
The Oracle Database is now registered with Active Directory with a service
name which is identical to your sid name.

IV.    Optional Procedures
A.    If you choose, you may add the snap in for the Oracle Managed Products
and complete the OS authentication procedures or create users in the database.

B.    Click the Console Menu and click Add/Remove Snap-in.

C.    Click Add, scroll down, and highlight Oracle Primary MMC Snap-in and
click Add and then click close.

D.    Click OK, then Click the console menu and click Save.

E.    Expand the Oracle Managed Objects Snap-in, Expand Computers, Expand
your computer name, and expand databases.  You should now see your sid name.
Right click the sid name and click connect database.  You should connect
immediately since your Administrator account is a member by default in the
newly created Ora_Dba group.  You may right click External OS Users and OS
database Administrators and create users in the database.

F.  Client machines can be set up and configured by installing the Oracle
client from the CD-ROM, running the Net8 Configuration Assistant, choosing
Directory Service Access Configuration, and choosing directory access
configuration for a client.
May 25, 2001 Andrew -- Thanks for the question regarding "About using Arrays", version 8.1.6i on NT4(SP5)
You Asked
Hi, Tom !
I have tested the following code:

create type MyType is table of integer;
/
grant execute on MyType to public;

create table Test (A integer,B varchar2(100));
insert into Test(A)
select a.column_value from
the(select cast(MyType(1,2,3) as MyType) from dual) a;
It works.
So I've a questions.
1.Where can I find a description of keywords column_value and THE?

2.Can I insert into table from two arrays the same time.
I wrote the additional code:
Create type MyCharArr is table of varchar2(100);
/
grant execute on MyCharArr to public;
delete from Test;
insert into Test
select a.column_value,b.column_value from
the(select cast(MyType(1,2,3) as MyType) from dual) a,
the(select cast(MyCharArr('a1','a2','a3') as MyCharArr) from dual) b;
My table has 9 records after this statement:
1 a1
1 a2
1 a3
2 a1
2 a2
2 a3
3 a1
3 a2
3 a3
But I want to have only 3 records:
1 a1
2 a2
3 a3
Of course,I can do INSERT with using loop in procedure and everything
will be OK.
But I want to insert both columns together using
arrays(By the way - is it a kind of so called "bulk insert" ???)
and only using one INSERT INTO ... SELECT clause.
Is it possible?

Any help would be very appreciate.
Andrew.
and we said...
1) column_value is not a keyword -- it is the default name assigned to the
single collection in a collection type created on a scalar.

the "THE" keyword (deprecated in 8i actually) is documented in the SQL Ref
manual.  It is better and easier to use table:

tkyte@TKYTE816> insert into Test(A)
  2  select a.column_value from
  3  TABLE (cast(MyType(1,2,3) as MyType) ) a;

3 rows created.

2) You would use a COLLECTION of objects for that:

tkyte@TKYTE816> create type myScalarType as object
  2  ( x int, y varchar2(100) )
  3  /

Type created.

tkyte@TKYTE816> create type myArrayType as table of MyScalarType
  2  /
Type created.

tkyte@TKYTE816> insert into test
  2  select *
  3    from TABLE( cast( myArrayType( myScalarType( 1, 'a' ),
  4                                   myScalarType( 2, 'b' ),
  5                                   myScalarType( 3, 'c' ) ) as
                                                            myArrayType ) )
  6  /

3 rows created.

very similar to a table of records....

If I was in PLSQL -- I could simply:

   forall i in 1 .. variable_name.count
      insert into test values ( variable_name(i), variable_name_two(i) );

where variable_name and variable_name_two were PLSQL variables of the collection
types.
Review & Followup
Rating: 4
Good answer on serious question May 28, 2001
Reviewer: Andrew from Russia
Thanks, Tom for deep analysis of situation!

May 25, 2001 Jin -- Thanks for the question regarding "no redo log for inserting/updating a table", version 8.1.5
You Asked
With the latest Oracle database, is it possible at all to make
inserting/updating a particular table (using insert/update command) NOT
generating any redo log? Thanks.
and we said...
No, quite impossible.  Won't happen.
Review & Followup
Rating: 3
May 25, 2001
Reviewer: Arup Nanda from Norwalk, CT, USA

May 25, 2001 sushil -- Thanks for the question regarding "How to related the oracle process created at database from an htp request at oas server", version 3.0.2
You Asked
Hi tom,

I am using oas302 and oracle805 on two different servers.
Am using htp & htf packages.

Whenever a http request is made my oas initiates one process with
LOCAL=NO at database server.
In some cases the process stays active for no of days, untill the
same is either killed or database/ listener restarted.

I would like to know why does these processes stay alive and
how do i trace the procedure which was called by the http request.
and we said...
Its ok -- its normal -- its supposed to work that way.  OAS creates a physical
connection to the database and keeps it open.  The slowest part of the web page
generation is the connect -- the plsql cartridge connects 1 and then
authenticates itself for each page.  It is many times faster this way.

This is just like a connection pool. It works like this by design.
May 26, 2001 don parker -- Thanks for the question regarding "memory", version 8.1.7
You Asked
Tom

The following might be a stupid question.

Data is stored in the datafiles and is measured in bytes.
But all the memory components which we declare in the init.ora file, like
shared_pool_area are also declared in bytes, and data buffers ,redo log buffers
exist in memory.

Where do these buffers actually exist, are they stored temporarily in on the
physical files.

When memory is not enough for any query we say that it will take the sort area.
Where does this sort area exist, what is it. How is it measured. Is it an area
on any physical file?

How come datafiles and memory buffers both of them are measured in bytes.

Thanks
and we said...
There is this thing called an SGA -- it is a large memory data structure.  the
shared pool, block buffers, redo log buffers -- they are all in there.  You
should give the Oracle8i server concepts manual a cover to cover read, it'll be
very enlightening.  I don't mean that sarcastically -- I mean it.  I read that
document myself with each release and always find something new.
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/toc.htm

These buffers exist in memory.  The OS is free to "page them out" but basically
they are RAM based structures, they are not on disk.

The sort area is taken from the PGA (process global area), it is malloc()'ed
memory by a process (dedicated server or shared server).

Why bytes?  because bits would be too hard to figure out.  A byte is the unit of
measure of storage -- that is all.
May 26, 2001 don parker -- Thanks for the question regarding "cbo and table size", version 8.1.7
You Asked
Tom

1.The cost based optimizer will used indexes if the table size is small.
How does it decide that a table is small sized, medium sized or large sized.

Is there any criteria which is applied.

2.Further , can you give me an example when exists is better than in , and when
in is better than exists. What does an in and exists actually do?

3.what are non mergable views, and how can we merge a view in our select
statement. Can you give me an example.

Thanks
and we said...
1) the CBO will use an index if it can determine that a small percentage of the
table will be accessed via the index -- it is not the SIZE of the table, it is
the CBO's estimate of how many rows will be accessed.  If a small percentage of
the rows will be accessed, the CBO will use the index.  The CBO uses the
statistics on the table/indexes to see if it will use them.

3) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:953229842074
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:442029737684
3) a mergeable view is such that the predicates against the view can be "pushed
down" into the view itself.

For example:

create view v as select * from emp where ename like '%A%';

select * from v where sal = 500;

That query against V can be merged into V itself.  Oracle will rewrite that
query as:

select * from emp where ename like '%A%' and sal = 500;

However, if the view was;

create view v as select deptno, sum(sal) sal from dept;

that query "select * from v where sal = 500" cannot be merged into the view
since:

select deptno, sum(sal) sal from dept where sal = 500;

if VERY different from:

select * from ( select deptnp, sum(sal) sal from dept ) where sal = 500;

You do not merge a view in your select statement -- Oracle does.

May 26, 2001 -- Thanks for the question regarding "archive",
      version 8.1.6

      You Asked
my system runing well, but all a sudden it seems stoped.
then i check
v$sesson_wait, found that:

      11 log file sequential read
        45 log file switch (archiving needed)

mpstat 10 10
CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
  0    0   0    0     0    0   35    0    0    0    0    41    0   0 100   0
  1    0   0    0     0    0   16    0    0    0    0    37    0   0 100   0
  4    0   0   28   229   29   25    0    0    0    0    38    0   0 100   0
  5    0   0    0    23   23   22    0    0    0    0   128    0   0 100   0
  8    0   0    0     0    0   21    0    0    0    0   159    0   0   0 100
  9    0   0    0     0    0   28    0    1    0    0    33    0   0   0 100
 12    0   0   21     1    1   40    0    0    0    0    76    0   0   1  99
 13    0   0    0     0    0   37    0    0    0    0    66    0   0   0 100

how to solve it?

      and we said...
you are in archive log mode and either:

o you have not enabled automatic archiving -- enable it (init.ora parameter) in
the meanwhile "alter system archive log all" manually.

o you have run out of space in your archive destination, make more space
available.
May 26, 2001 don parker -- Thanks for the question regarding
      "5 levels of application tuning", version 8.1.7

      You Asked
Tom

The following came to my mind when I wanted to think as to what all is necessary
for a well tuned application.

1.good data model

2.efficient handling of memory parameters in the init.ora file

3.having enough disk space, and spreading the files properly over different
disks.

4.Proper sizing of sort area parameters and temporary segments.

5.Optimized sql

6.ptimized pl/sql

Iam I right with my assessments. Your comments please

Thanks

      and we said...
1, 5, 6 are the most important (2, 3, 4 is for the DBA and is "instance tuning,
not application tuning).

1, 5, and 6 are all one step in my three step program ;)

step 1; get the application running as fast as possible in isolation.  that is,
make it go as fast as you can in "single user mode"

step 2; test to scale -- many choke points only show themselves with 2 or more
users.  make sure you test to scale (most people seem to skip this step).  this
is as important, if not MORE SO, than step 1.

step 3; tune the instance.  no need to move files and such until now.  if you
try to do this step before 1 or 2, you'll just end up doing it again because 1
and 2 will change your execution profile as you tune them.

Review &
      Followup

      Rating:
      4
  July 20, 2001
Reviewer:  Pichaimani
      Balasubramanian  from San Jose, CA USA

May 26, 2001 -- Thanks for the question regarding
      "v$session_wait", version 8.1.6

      You Asked
if i find a lot of following information from v$session_wait,
how to improve it?

3 log file parallel write
18 log buffer space
2 db file parallel write
5 smon timer

Regards,

      and we said...
Fact: I just waited at 50 red lights on my last car trip.

Question: is that good, bad or indifferent?

You cannot tell.

What if my trip was from New York City to San Fransico (about 2,500 miles).
That would be awesome -- something to strive for.

What if my trip was from 1st Avenue to 48'th Avenue in New York -- that would be
pretty bad.

What if I waited 2 minutes at those red lights and my trip took 8 hours.  So
what if I waited, it was "noise".

What if i waited 2 minutes at those red lights and my trip took 5minutes.  That
red light wait event was pretty damaging.

You need to accompany wait events with TIME WAITED and overall time measured.

(log buffer space waits can be alleviated by 1) generated less redo, 2) making
the redo log buffer larger, 3) speeding up lgwr)

May 26, 2001 don parker -- Thanks for the question regarding
      "bind variables", version 8.1.7

      You Asked
1.What will happen if my application is using a lot of hardcoded values in its
select statements.
2.How can I see if there are any hardcoded sql statements in the library cache.

3.Once we find out that the application is slowing down because of the excessive
use of hardcoded values in the select statements, what should we do?
4.Do we need to flush the shared pool area regularly, or do we weed to go back
to our code and remove all the hard coded values with bind variables.

5.How can I see these hardcoded values in the library cache. Is there any way in
which I can trace the whole contents of the library cache.

6.What should be the methodology once we discover that the library cache is
being filled up with hard coded sql statements.

Thanks

      and we said...
1) your application will out and out fail.  It will not scale beyond 1 user (if
that).  It will spend 90% of its time parsing queries, 10% of its time executing
them.  If you try to do this in a multi-user system, your scalability will be
SEVERLY DIMINISHED.

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:528893984337
I spend a great deal of time on this topic in my book as well (i beat it to
death actually).  see
http://asktom.oracle.com/
for a clickthru to the book.

2) see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1163635055580
3) step 1: fire or retrain the developer who wrote it.
   step 2: make them recode it to use bind variables.

4) flushing the shared pool is the worst thing you can do to us. you can use it
as a temporary bandage, a crutch, while you fix the problem.  It would be like
erasing the .EXE's of your application and making your end users recompile them
all every time you flush the shared pool.

5) see #2

6) see #3

May 27, 2001 -- Thanks for the question regarding "indexes on
      foreign key", version 8.1.5

      You Asked
Tom

Is it advisable to have indexes on foreign key, why and why not?
In what circumstances will creating an index on foreign key help?

When I have indexes on one of my join columns, then a nested loop join is
choses, other wise a sort merge join is chosesn. What will happen if I have
indexes on both my join columns.

What is the difference between a hash join and a sort merge join?

What are the most often used optimizer hints?

Why is explain plan not reliable when compared to tkprof?

Bye

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:292016138754
for the foreign key issue.

If you have indexes on both sets of join columns -- the optimizer will pick one
table to be the driving table and do an indexed read (nested loops) into the
other - just like it happens with indexes on one (except the choice of a driving
table is made by the fact that one table isn't indexed).

a hash join uses a hash table to organize data.  data is found by hashing the
key -- that hash value tells us where the data is.

a sort merge sorts the data and then merges it.  a hash does not sort, it hashes
a sort does not hash, it sorts.  two totally different concepts.

There is no "most used" hint that I am aware of.

The explain tell tells you what would happen if you ran the query right now, in
your environment.  the TKPROF shows *what actually happend* when the query was
run.


Subject | Article | Last Updated (East coast time)
Storing email content into database | article only | May 28, 2001 01:04 pm
SQL | article only | May 28, 2001 01:21 pm
Updation to 6 tables | article only | May 28, 2001 02:07 pm
IOT,indexes and global temporary tables | article only | May 28, 2001 02:19 pm
dbms_job and cron job | article only | May 28, 2001 02:23 pm
sql trace and tkprof -- one more | article only | May 28, 2001 02:28 pm
use of bind variables | article only | May 29, 2001 08:40 am
exists and in summarized | article only | May 29, 2001 08:49 am
space utilization | article only | May 29, 2001 09:03 am
resize datafiles and logs, rename an index. | article only | May 29, 2001 11:10 am
quotation mark | article only | May 29, 2001 12:58 pm
date and number | article only | May 29, 2001 01:01 pm
Using index with DECODE function | article only | May 29, 2001 02:17 pm
Not in clause causes query to be very slow | article only | May 29, 2001 08:29 pm
Partition key | article only | May 29, 2001 08:43 pm
CLOB Questions with forms | article only | May 30, 2001 07:50 am
How Oracle search encrypted data in the database ? | article only | May 30, 2001 08:05 am
exists and in ..continued | article only | May 30, 2001 08:14 am
Export files or backup all DB files for customer data validation? | article only | May 30, 2001 10:17 am
Enumerated Constants | article only | May 30, 2001 10:41 am
Adding Custom keywords to intermedia | article only | May 30, 2001 01:46 pm
How do I use the host commands from Stored Procedures | article only | May 30, 2001 02:34 pm
on NT what percentage of RAM should i use for SGA | article only | May 30, 2001 02:38 pm
TWO_TASK environment variable on windows. | article only | May 30, 2001 02:42 pm
Need a performance tuning hint... | article only | May 30, 2001 03:51 pm
hash | article only | May 30, 2001 05:03 pm
Recover through adding logfile | article only | May 31, 2001 08:18 am
Oracle datafiles | article only | May 31, 2001 08:21 am
Primary-Foreign Key | article only | May 31, 2001 10:37 am
The :old and :New in Triggers | article only | May 31, 2001 10:52 am
How to get metadata? | article only | May 31, 2001 10:54 am
For Cursor and Open & Fetch | article only | May 31, 2001 11:15 am
Filtering SQL*Plus errors when trying to shutdown | article only | May 31, 2001 01:01 pm
CURSOR%ROWTYPE variable | article only | May 31, 2001 03:48 pm
Using Intermedia: Multiple Paths for file_datastore on NT | article only | May 31, 2001 09:01 pm
SQL Query | article only | Jun 01, 2001 09:30 am
Unknown record type fetch from the cursor. | article only | Jun 01, 2001 09:33 am
Procedure | article only | Jun 01, 2001 10:03 am
sequences during replication | article only | Jun 01, 2001 10:24 am
query -- decoding and getting a pct of total | article only | Jun 01, 2001 11:11 am
pl/sql tables | article only | Jun 01, 2001 12:34 pm
Truncate Command | article only | Jun 01, 2001 01:27 pm
checkpoint - Reg | article only | Jun 01, 2001 01:39 pm
mutating table on update trigger | article only | Jun 01, 2001 01:52 pm
Difference between Transaction READ-ONLY and TRANSACTION ISOLATION LEVEL SERIALIZABLE | article only | Jun 01, 2001 03:53 pm
isolation levels - what are the different levels and what do they mean | article only | Jun 01, 2001 04:31 pm
unique constraint | article only | Jun 01, 2001 06:56 pm
Who controls extent management in locally managed TS's ? | article only | Jun 02, 2001 07:28 pm
Internal numeric format | article only | Jun 02, 2001 07:30 pm
Simple Pl/Sql question on Procedure | article only | Jun 02, 2001 07:36 pm
Interval parameter for dbms_Job | article only | Jun 03, 2001 01:20 pm
IOT's | article only | Jun 03, 2001 01:28 pm
row(s) 1 - 52 of 52
May 28, 2001 Valsaraj -- Thanks for the question regarding "Storing email content into database", version 8.x
You Asked
hi tom

We have an application which records user complaint and IT support handles the
issue.We have Oracle 8.1.7 databse running on Windows NT.
For mailing we use outlook 98/2000 version on Exchange server 5.5.

Tom, we have two aspects.
First one is, user send support request email to the address of itsupport say,
"x". We want to store all mails coming to address "x" in our oracle database.

Second one is, user send support request email to the address of itsupport say,
"x". The person who monitors this address will forward the mail to helpdesk
address say "y", if this is a support request call. We want to store all mails
coming to address "y" in our oracle database.

How is it possible to fetch address of sender, date and time, subject and mail
content, so that we can store them in a table.

Please provide a solution for this. Incase more details required please mail me.

thanks in advance !

Tom,

i am adding more information as you have asked.

we have

Oracle8i Enterprise Edition Release 8.1.7.0.0
JServer Release 8.1.7.0.0

Sorry, an addition to the question... In second case we require to capture the
detail of user only. Not the detail of email address 'x'.
To be more clear, i am 'v' sending a request call to 'x'. x forwards to 'y'. we
need to capture the detail of 'v' and the content.

thanks again Tom...
and we said...
What you want to do is load up the JavaMAIL api (free from sun) into the
database.
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:255615160805
shows how to do that (it has an example of SENDING mail -- you'll need to read
about the javaMail api to write your procedures to READ mail).

Once you can read mail, just set up a job using DBMS_JOB to check for new mail
every N minutes and pump it into the database.
May 28, 2001 sujata -- Thanks for the question regarding "SQL", version 8.1.6
You Asked
Hi Tom,

I have 3 tables with the following strucutres and their contents:

Dept:
    Dept_Id
    Dept_Desc

Dept_Id        Description
-------        -----------
1          ADMIN
2          SALES
3          PRODUCTION

Designation:
    Desig_Id
    Desig_Desc

DESG_ID     DESG_DESCRIPTION
-------          ---------------------
1             CHAIRMAN
2             MANAGING DIRECTOR
3             GENERAL MANAGER
4             REGIONAL MANAGER
5             AREA MANAGER
6             SALES OFFICER
7             FIELD ASSISTANT
8             PLANT INCHARGE
9            PRODUCTION MANAGER
10            PRODUCTION SUPERVISOR
11            ADMIN

Hiercs:
    Desig_Id
    Superior_Id
    Dept_Id

Desig_Id    Superior_Id    Dept_Id
1                         1
2               1            1
3               2                   2
4               3            2
5               4            2
6               5            2
7               6            2

I wanted to view the respective descriptions for the above numerical values as
following using above 3 tables:

Desig_Id        Superior_Id        Dept_Id
----------        -----------        -------
Chairman                    Admin
Managing Director    Chairman        Admin
General Manager            Managing Director    Sales
Regional Manager    General Manager            Sales
Area Manager        Regional Manager    Sales

Please help me in writing sql statement to get above output using  dept, desig,
hiercs tables?

Sujata
and we said...
it is a straightforward join:

select d1.desg_description, d2.desg_description, dept.dept_desc
  from designation d1, designation d2, dept, hiercs h
 where h.desig_id = d1.desg_id
   and h.superior_id = d2.desg_id(+)
   and h.dept_id = dept.dept_id
/
May 28, 2001 chandra -- Thanks for the question regarding "Updation to 6 tables", version 7.3
You Asked
Hi Tom
The question is i have 6 tables wherein one column has to be updated.
Suppose a Debtor code DMP001 is there, i want to update the values
of these columns present in these 6 tables, where in datatype and length are
same.
Example is
DB_code                  new_code
DMP001                   PDS001
XDB001                   RDS001
XDS001                   SDS001
VDS001                   VFS001

DMP001 SHOULD BE REPLACED WITH PDS001 ie first 3 chrs are diff and next 3 chrs
are same.For all these tables the column names are different.could u help me out
with Different methods of updation ie
using PL/SQL and dynamic sql.

Thanks
Regards
GCS
and we said...
tkyte@ORA734.US.ORACLE.COM> create or replace procedure execute_immediate( p_sql
in varchar2 )
  2  is
  3      cursor_name     pls_integer default dbms_sql.open_cursor;
  4      ignore          pls_integer;
  5  BEGIN
  6      dbms_sql.parse(cursor_name, p_sql, dbms_sql.native);
  7      ignore := dbms_sql.execute(cursor_name);
  8      dbms_sql.close_cursor(cursor_name);
  9  END;
 10  /

Procedure created.

tkyte@ORA734.US.ORACLE.COM>
tkyte@ORA734.US.ORACLE.COM> create or replace procedure p( p_tname in varchar2,
p_cname in varchar2 )
  2  as
  3  begin
  4      execute_immediate(
  5      'update ' || p_tname ||
  6        ' set ' || p_cname || ' = decode( substr( ' || p_cname || ', 1, 3 ),
  7                ''DMP'', ''PDS'',
  8                ''XDB'', ''RDS'',
  9                ''XDS'', ''SDS'',
 10                ''VDS'', ''VFS'' ) || substr( '||p_cname ||',4)
 11        where ' || p_cname || ' like ''DMP%''
 12           or ' || p_cname || ' like ''XDB%''
 13           or ' || p_cname || ' like ''XDS%''
 14           or ' || p_cname || ' like ''VDS%''' );
 15  end;
 16  /

Procedure created.

tkyte@ORA734.US.ORACLE.COM>
tkyte@ORA734.US.ORACLE.COM>
tkyte@ORA734.US.ORACLE.COM>
tkyte@ORA734.US.ORACLE.COM> select * from t;

C
----------
DMP001
XDB001
XDS001
VDS001
ABC001

tkyte@ORA734.US.ORACLE.COM> exec p ( 'T', 'C' );

PL/SQL procedure successfully completed.

tkyte@ORA734.US.ORACLE.COM> select * from t;

C
----------
PDS001
RDS001
SDS001
VFS001
ABC001
May 28, 2001 -- Thanks for the question regarding "IOT,indexes and global temporary tables", version 8.1.7
You Asked

1.what is the difference between a reverse index and a regular index?

2.I know that a reverse key index stores a value of 1007 as 7001, and this helps
in better balancing the branches of the

index( is this right?).

3.Under what situations are reverse key indexes ideal?

4.While dealing with IOT's , we come across logical rowid's? what is a logical
rowid, how is it differenct from a regular rowid?

Under what sitiations are IOT's used?

In one of the examples you have given , answering a question of the use of IOT,
taking the example of stock price table which will have stock prices for orcl
inserted into it every day, you have explained that in a regular table the rows
get inserted at the end of the table, where as in an index organized table when
they are inserted, they exist in group where previous records for orcl stock
exist. Can you expand on it further?

5.Will there be any performance improvement using global temporary tables? can
you give an example where using a global temporary tables improves performance?

6.It is recommended that there should be indexes on nested tables. Will it help?
Can you give an example where creating an index on a nested helps it boosting
the performance? Can you please give an example?

7.Can you give an example where a partioned table is a much better option than a
regular table?

8.Can we use function based indexes on pl/sql functions i.e. user created
functions?

9.Should there be any difference of approach while optimizing a regular query,
and a query used to create a view?

10.What is the differenct between

CREATE TYPE location (
  building_no NUMBER,
  city        VARCHAR2(40) );

create type location as object

11.While creating an index we can specify ordered or unordered, what difference
does it make when an index is ordered and when it is unordered?

12.Tom, can you specify or give the link to a source where I can get the top 5
or top 'n' dont do's when writing sql statements?

Thank you Tom
and we said...
I think you'll really like my book that comes out in June -- I pretty much cover
all of this and more in there... anyway...

1) a reverse key index stores the bytes for each index key reversed.  ABC is
stored as CBA.

2) The goal of the reverse key index is to spread the insertion of new values
across the index structure.  If you have an index on a column maintained by a
sequence, that will insert the values 1, 2, 3, 4, 5, ...... and so on.  they
will all go to one side of the index.  reverse the bytes and they are not stored
right next to eachother.  that is the goal.  It is useful in OPS (parallel
server) where concurrent modifications of the same blocks by different instances
should be avoided when possible.

3) see #2.  I would not use them unless I was in that environment (at least I
haven't found a cause to yet)

4) a regular rowid is a physical address, file, block and slot on a block.
Since a row in an IOT will move as the index splits and reorgs itself -- we
cannot key a real rowid (the row won't be there tomorrow!).  A logical rowid is
enough information to range scan the IOT efficiently to find that row again.

5) depends on what you are doing.  I don't use them for "intermediate" result
sets myself as many people are brain washed into doing from experiences with
SQLServer and the like.  I do the work in a single query.  When I use a global
temporary table, it is to use it to cache some session specific data, data to be
processed for example or something like that.

6) If you do not index the nested_table_id (a hidden magic column on a nested
table) Oracle will have to full scan the child table whenever you access the
nested table rows. Lets say the parent object has 1,000,000 rows and each of the
parent rows has 10 children.

Would you want to full scan the nested table or do 10 indexed reads?

I would vote for #2 myself.....  In 8i, a nested table should almost ALWAYS be
an IOT using index key compression.

7) I have a 100 gig table.  I need to analyze it in parallel.  I need administer
it (back it up, load it, rebuild parts of it) and so on.  There you go.

I have to keep history online for 3years.  Every month, I must delete the oldest
month and add the newest month.  With a partitioned table, this should be 2 DDL
statments to get rid of the old data and add in the new data.  Without
partitions, this would be 2 DML statments that might take a very very long time.

thats the tip of it.

8) yes.  see
http://osi.oracle.com/~tkyte/article1/index.html
9) Nope.  they are both just queries after all

10) one is valid SQL and the other is not:

ops$tkyte@ORA8I.WORLD> l
  1  CREATE TYPE location (
  2    building_no NUMBER,
  3    city        VARCHAR2(40) );
  4*
ops$tkyte@ORA8I.WORLD> /

Warning: Type created with compilation errors.

ops$tkyte@ORA8I.WORLD> show err
Errors for TYPE LOCATION:

LINE/COL ERROR
-------- -----------------------------------------------------------------
1/15     PLS-00103: Encountered the symbol "(" when expecting one of the
         following:
         ; is authid as compress compiled wrapped

5/0      PLS-00103: Encountered the symbol "end-of-file" when expecting
         one of the following:
         pragma

  1  CREATE TYPE location as object (
  2    building_no NUMBER,
  3*   city        VARCHAR2(40) );
  4  /

Type created.

11) if the data is loaded sorted and you say "ordered", the index will create
faster since Oracle doesn't have to sort that which is already sorted.

12) nope, don't know of any such magic as that.
Review & Followup
Rating: 5
answers: 1,2,3,7 May 29, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

Rating: 3
May 29, 2001
Reviewer: Purushotham from Germany

May 28, 2001 -- Thanks for the question regarding "dbms_job and cron job", version 8.1.7
You Asked
If you have to choose between, unix cron job, and the database specific dbms_job
, to execute a procedure at regular intervals, what would youchoose and why.

A couple of weeks back I attended interview, and when I told them that Iused
dbms_job package, they asked me why I did not use cron job for the same , when
the operating system was unix.

Can you please explain
and we said...
DBMS_JOB.

Cron runs -- even when the database isn't up.  Jobs run -- when the database is
up only.

Any errors from cron goto a log file somewhere or email.  Errors from Jobs go
into the alert log, someplace I'm already looking.

Cron -- unix.  Jobs -- everywhere.

My question to them would be -- why would I do it at the OS when I can do it in
the database?  Less moving parts.  I can run a QUERY to see how my job is doing
-- try that with cron ;)
May 28, 2001 NK -- Thanks for the question regarding "sql trace and tkprof -- one more", version 8.1.6
You Asked
hi,

i asked using 'set autotrace on' and explain plan i get a result of
statistics and execution plan of the query. how can i tune the query by looking
at the statistics of generated by 'set autotrace on' and explain plan. if you
explain with an example it will be good.

thanks a lot.
and we said...
depends on the type of query.  I generally look at the consistent gets and try
to get that number down... I use the query plan to see WHAT it is doing and do
something to make it do something else.

consider:

ops$tkyte@ORA8I.WORLD> create table t as select * from all_objects;
Table created.

ops$tkyte@ORA8I.WORLD> set autotrace on
ops$tkyte@ORA8I.WORLD> select object_name from t where object_id = 55;

OBJECT_NAME
------------------------------
I_UGROUP1

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (FULL) OF 'T'

Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
        420  consistent gets   <<<<==== thats too many for this query
        415  physical reads
          0  redo size
        377  bytes sent via SQL*Net to client
        425  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

I see I'm full scanning but getting a single row, so I'll add the index

ops$tkyte@ORA8I.WORLD> create index t_idx on t(object_id);
Index created.

ops$tkyte@ORA8I.WORLD> select object_name from t where object_id = 55;

OBJECT_NAME
------------------------------
I_UGROUP1

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T'
   2    1     INDEX (RANGE SCAN) OF 'T_IDX' (NON-UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          4  consistent gets   <<<== ahhh, much better.
          2  physical reads
          0  redo size
        377  bytes sent via SQL*Net to client
        425  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

ops$tkyte@ORA8I.WORLD> set autotrace off
Review & Followup
Rating: 5
May 29, 2001
Reviewer: Andre from Brazil

Rating: 4
May 29, 2001
Reviewer: C.S.Venkata Subramanian from India
Good query to explain the basics of query tuning.

Rating: 5
May 29, 2001
Reviewer: Shashi Gupta from USA

Rating: 5
consistent gets June 05, 2001
Reviewer: A Reader
Very Useful

May 29, 2001 korada -- Thanks for the question regarding "use of bind variables", version 8.1.6
You Asked
i read in one of your answers that we should not use hard coded values ,instead
we should use bind variables. I am not clear with that see
for example:

i wrote a code of:

begin

  insert into emp(empno,name,sal,hiredate)
  values('1111','jjjj',10000,'28-may-2001');

end;

do you mean the above should be replaced with

declare

v_empno number;
v_sal number;
v_name varchar2(20);
v_date date;

begin

  insert into emp(empno,name,sal,hiredate)
  values(v_empno,v_sal,v_name,v_date);

end;

am i right, if yes could please explain me why?
and we said...
Yes, that is correct.

If you really want to know all of the reasons why -- my book coming out next
month beats this topic virtually to death.

If you code:

   insert into t values ( 1 );
   insert into t values ( 2 );
   ....

Oracle must parse, compile, optimize, security check, etc etc etc each query.
That is called a hard parse.  It is a lot of work.  Typically, you'll find that
in single user mode 90%  OR MORE of your execution time is spent PARSING queries
if each query is a hard parse.  90% or MORE.  In multi-user mode, it is even
WORSE as this causes lots of latching in the library cache (a latch is a
serialization device) so you start getting lots of people waiting on each other
to parse a query.

Additionally, there is a data structure called a shared pool in Oracle.  This is
where we stuff parsed queries.  If every query coming into the system is unique
-- the shared pools is defeated.  We are caching query plans that will never be
reused.  We did a lot of work to cache/manage them for nothing.

If you would like to write really slow, non-scalable applications -- just don't
use bind variables.  It is that simple.

I cannot overstate their importance.
Review & Followup
Rating: 5
Bind Variables - How the CBO uses histograms/data distribution information? May 29, 2001
Reviewer: Moorthy Rekapalli from Atlanta GA USA
Tom,

Please explain how the CBO uses histograms/data distribution information with
bind variables?  I agree that parsing overhead will be minimal with bind
variables.  But, how the optimizer knows which value will be used in run time
and how to get the best exeuction path?

If I use bind variables, my query will be
select * from t where state = :b1;

In run time, it can be either
select * from t where state = 'GA';
or
select * from t where state = 'AL';

My assumption is that 90% of the rows have state as GA and rest of the rows have
AL.

Thanks again for your help.

May 29, 2001 -- Thanks for the question regarding "exists and in summarized", version 8.1.7
You Asked
Tom

1.Let me generalize all your explanations on the use of exists and in..

IN should be used when the query in 'IN' is bound to return less number of
values, else exists should be used.

For example

select ename from emp
where deptno in (select deptno from dept;)

If select deptno from dept; returns only 4 rows them 'IN' should be used, where
as if it is going to return  1000 rows then the query should be

select ename from emp
where exists (select deptno from dept;)

is this right?

2.
I have a query

select ename
from emp
where emp.deptno=dept.deptno
and ename like '%c%'
and deptno < 30
and sal >2000;

In what order will the conditions in the predicate will be read( when using rbo
and when using cbo , can I use the ordered hint here, to force it to read from
bottom to top or top to bottom);

Thank you
and we said...
1) no, not neccesarily (but usually).

in your example, the optimizer would see that DEPT(DEPTNO) is unique and would
be able to do a very efficient join.  If dept has a billion records -- it would
not matter in this case.

If the in was doing a column such as DNAME which the optimizer does not
understand is unique -- but dname is indexed, an exists would probably be
better.  On the other hand, if dname is NOT indexed -- the IN would be more
efficient.

2) it is indeterminate.  the ordered hint is to hint the order of the TABLES
(which table will DRIVE the query).

You cannot order the evaluation of predicates.
May 29, 2001 ted -- Thanks for the question regarding "space utilization", version 8.1.6
You Asked
thomas,

1. Is it true, when there are free block in the freelist chain, the new extents
will not be allocated because oracle look for freeblock first before extending ?
If this is true why am I finding new extents were allocated even there are many
free blocks exsits for a table.

2. which parameters - pct used of pct free  is used in determining the free
block ? oracle manual - pct free and some literature say pct used(I always
thought it is pct used).

3. when sequence number is used as primary key, this index tend to skewed  in
one direction producing an unbalanced binary tree. can you give me insight how
this occurs (related to leave branch split)?

4. what is the correct course of action, after finding out a table or index
associated with sequential read contention(wait) ?

5. can you give me an example to test outputing  an plsql table using
sqlplus ?

6. Is it possible to create a regular table with global partition index. If so,
under what circumstance this design is appropriate ?

7. under what condition a random sequence number can be appropriate used ?

thnx in advance
ted chyn
and we said...
1) new extents will be allocated for many reasons.

If you have multiple freelists on a table for example, a session will only
inspect ONE of them.  when that list runs out, we'll grab more space.

If you insert /*+ APPEND */ or direct path load, we do that into new extents.

It could be that each block on the freelist does not have sufficient space for
the newly inserted row (indicates your pctused is set wrong -- blocks are
getting on the freelist that do not have sufficient space for new rows).

2) pctfree dictates when the block comes OFF of the freelist.
   pctused tells us when to put it back ON

3) it won't necessary be unbalanced.  it is skewed in that all inserts go after
the same block (hot spot) but it won't be unbalanced.  most of that happens with
massive deletes.

4) need more information. give me a scenario and the wait event exactly (are you
waiting on IO or buffers -- what is the wait event)

5)

  1  declare
  2  type array is table of number index by binary_integer;
  3  data array;
  4  begin
  5     for i in 1 ..5 loop data(i) := i;
  6     end loop;
  7     for i in 1 .. data.count loop dbms_output.put_line( data(i) );
  8     end loop;
  9* end;
ops$tkyte@ORA8I.WORLD> /
1
2
3
4
5
ops$tkyte@ORA8I.WORL

6) yes it is.  I don't know why you would want to do it.

7) i don't know what a random sequence number is. random and sequence used
together is an oxymoron.
May 29, 2001 NARESH -- Thanks for the question regarding "resize datafiles and logs, rename an index.", version 7.3.4
You Asked
1. It is possible to resize a datafile. Can log group memebers also be resized
or only dropping and recreating the only option.

2. Table can be renamed. How to rename the indexes.

regards

Naresh
and we said...
1) datafiles = yes.  alter database datafile 'filename' resize 100m
   log files = no.  create new ones and drop the old.

2)
scott@8.0> alter index IMAGE_PK rename to xxx;

Index altered.

in 8.0 and UP (not available in 7.3)
May 29, 2001 renee -- Thanks for the question regarding "quotation mark", version 8i
You Asked
Hi, Tom!

I have searched a lot of books regarding inserting string with quotation mark.
I understand that in order to do that, one should use '' to achieve the goal.
But what if I have no control on where my user will put the quote on the field
that I am saving?  Examples are comments and name (O'Connor) fields?  How do I
solve this?

Thank you so much for your help.
and we said...
You MUST be using bind variables in any real application.  The only time you
need to double up the quotes is when you are running a sqlplus script.

Any real application will be using BIND VARIABLES:

   insert into t values ( :x );

Never, never code:

   insert into t values ( 'O''connor' );

so, unless you are using SQLPlus as your "user interface", use bind variables.
There you need no quotes anywhere.
May 29, 2001 Suresh -- Thanks for the question regarding "date and number", version 8.1.7
You Asked
Hi Tom,
   I have a table with a date column in it. This table could have more than 2
million records when goes into production. The "dd" part in the date column will
always be 01 and also the date in that column could be duplicated. Since I am
interested only in "yyyy/mm" part of the date column, is it advantageous to
store the above mentioned date as a number (eg 200001 in a NUMBER(6) datatype).
Will this(storing date as a number) make the queries against this table run
efficiently or is it going to be the same? As always , thank you so much for
your help.
and we said...
A date is a 7 byte fixed length field.

A number 6 will consume 4 bytes.

It may be marginally faster as a number HOWEVER, there will be not stopping
someone from putting in 999999 -- you'll lose the fact that the column is in
fact a DATE.

I would stick with the date as it comes with the server enforced santity check
on the values contained in the column.
May 29, 2001 Erika -- Thanks for the question regarding "Using index with DECODE function", version Oracle8i
You Asked
Hello,

I have the following select

  select * from my_table
    where decode(&x, null, 1, id) = decode(&x, null, 1, &x) ;

Could I force somehow (by creating an index) not to do a full scan on the table
my_table? For the moment there is a unique index on the primary key id.

Thanks you for your answer,

Erika

More info: &x is a parameter. Here is an example of a procedure:

create or replace procedure my_proc(x IN integer DEFAULT NULL) as
cursor c_name(x integer) is
  select * from my_table
    where decode(x, null, 1, id) = decode(x, null, 1, x);
begin

FOR c_name_rec IN c_name(x) LOOP
  dbms_output.put_line(c_name_rec.name);
END LOOP;

end;
/

A goal I would like to achieve is:
- if the parameter x is entered, than select one row from table my_table (id is
the primary key)
- if the parameter x is null, than select all rows

Thanks again for help,

Erika
and we said...
Oh, you should really code that using a ref cursor.  By your own definition, a
single query plan would be a really bad idea (sometimes 1 row, sometimes all
rows.  one should use an index, one should NOT)

Ok, if your problem is as simple as above, just code:

create or replace procedure my_proc( p_x in integer default null )
as
  type rc is ref cursor;

  l_cursor rc;
  l_rec    my_table%rowtype;
begin
  if ( p_x is not null )
  then
     open l_cursor for select * from my_table where id = p_x;
  else
     open l_cursor for select * from my_table;
  end if;

  loop
      fetch l_cursor into l_rec;
      exit when l_cursor%notfound;
      ....
  end loop;
  close l_cursor;
end;

if you really have a complex series of predicates to build or not build on the
fly, see:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
for a general purpose solution.
May 29, 2001 Manikandan -- Thanks for the question regarding "Not in clause causes query to be very slow", version 8.1.7
You Asked
Hi Tom,

I really appreciate all your efforts taken in making this forum very intersting
and informative.

I have a problem that worries me for sure.
I have a table called testing
SQL> desc testing
 ID                                                 NUMBER(1)
 SETVERSION_ID                                      NUMBER(10)
 SDATE                                              DATE
 NAME                                               VARCHAR2(10)

SQL> select * from testing;

        ID SETVERSION_ID SDATE     NAME
---------- ------------- --------- ---------
         1            33 01-JAN-01 mani
         2            33 01-JAN-01 balaji
         3            34 01-JAN-01 karthik
         4            33 01-FEB-01 jana
         1            33 01-FEB-01 mani

my requirement is to find out the uniquepersons whose sdate is feb-2001.ie the
persons joining for the first time.(they should not have joined previously as
the the username 'mani' having id=1.,
the query written is

SQL> SELECT   *  FROM    testing  ci_tid_01
  2  where  (    ( ci_tid_01.sdate = TO_DATE('01-02-2001', 'DD-MM-YYYY')
  3  and ci_tid_01.id not in (select testing.id from testing
  4  where testing.sdate < TO_DATE('01-02-2001', 'DD-MM-YYYY') )  )    );

        ID SETVERSION_ID SDATE     NAME
---------- ------------- --------- ----------
         4            33 01-FEB-01 jana

however, as the number of rows increases , the not in clause is taking lots of
time to execute.. for even 50000 rows it is taking more than 30 minutes to
execute.

the execution path is

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   FILTER
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'TESTING'
   3    2       INDEX (RANGE SCAN) OF 'TESTSDATE' (NON-UNIQUE)
   4    1     TABLE ACCESS (BY INDEX ROWID) OF 'TESTING'
   5    4       INDEX (RANGE SCAN) OF 'TESTSDATE' (NON-UNIQUE)

I want to rewrite this query to fetch the results faster.

Any help in this regards will be really appreciated...

expecting your reply
thanks
Mani
and we said...
well, how about just:

select *
  from testing
 where sdate = to_date( '01-02-2001', 'dd-mm-yyyy' )
   and not exists ( select null
                      from testing t2
                     where t2.id = testing.id
                       and t2.sdate < to_date( '01-02-2001' )
                  )
/

that should be pretty OK if sdate has an index on it as does (id,sdate) or just
(id)

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:442029737684
for the reason why the not in is slow in your case.  ID is NULLABLE, it cannot
use an index on ID (since NULLS are not indexed) and it changes the meaning of
the query if you ignore NULLS.  You might find that if ID is NOT NULL it works
pretty good as a NOT IN query.
Review & Followup
Rating: 4
May 29, 2001
Reviewer: manikandan srinivasan from San Jose, CA USA
the resonse is very good!!

May 29, 2001 Gunjeet -- Thanks for the question regarding "Partition key", version v8.1.6
You Asked
Hi Tom,

I want to design a partitioned table where the partitions are based
on the week of the year (52 partitions). The data in this table
needs to be retained for a max of 1 year, after that I can start purging the
oldest week's data on a routine basis [exchange partition
with empty table, drop table].

I already have a date column in my table structure as each data point
has a date against it. Now, do I need to introduce another column
called "week_of_year" and populate that for each record and use
that as the partition key ?

If yes, most of the selects against this table will include the
date column in the where clause (not the week_of_year column). Will
Oracle optimizer be able to do partition elimination while running
such a query or do I need to always include the column that is
part of the partition key in the where clause to enable partition
elimination while executing the query ?

I'm sure this is a common scenario where data has a date column but
you don't want to partition on absolute dates as that design is not
easily extensible, so you would rather partition by month, by week
of the year etc.

Please advise.

Thanks,

Gunjeet
and we said...
You would be using RANGE partitioning here with

PARTITION part_1 VALUES LESS THAN(to_date('01-jan-1997','dd-mon-yyyy')),
PARTITION part_2 VALUES LESS THAN(to_date('08-jan-1997','dd-mon-yyyy')),
.....

if you introduced another column "week of year", you would have to have just as
many "compares":

PARTITION part_1 VALUES LESS THAN(2),
PARTITION part_1 VALUES LESS THAN(3),
...

and yes, you would have to use the derived column in ALL queries since the
optimizer would have no clue that the partition with 50 in it had dates X
through Y.

Just keep an EMPTY partition at the end of the table (less then maxvalue).
Every week, you'll split this empty partition into a new partition that is less
then the end of the current week and the other is less then maxvalue.  Switch
this new empty partition with the real data and you have just slid in the new
data.  Drop the oldest partition and you are good to go.

Don't use the derived column.
May 30, 2001 Bhavesh -- Thanks for the question regarding "CLOB Questions with forms", version 1.0.2.0
You Asked
Hi Tom,
   Hope you must be fine. I have following 2 questions for you.
1. I Want to insert a CLOB Data into 8i (8.1.7) database using front end as
Oracle Forms (6.0.8.8.0). Since there is no CLOB data type in the property
palette so I am taking Long. Is this the only data type we should take when
dealing with CLOB data and if yes then what should be the Maximum size of the
same ?

2. Another even bigger problem what I am facing is that once i insert this data
into the database and then later when I view this data using internet browser,
all the data comes in a straight line i.e carriage return is missing from the
data. Say I entered data as follows :

This is the first line.
This is the second line.

Now when I view this through browser it appears as :

This is the first line. This is the second line.

Although when I view the data in SQL*Plus it seems fine.

To view the data I am using following code in PL/SQL unit.
htp.tableRowOpen (cattribues => 'valign = "top"');
   l_clob = cursor_record.lob_data;
   countdown = dbms_lob.getlength(l_clob);
   htp.p(dbms_lob.substr(l_clob, countdown, 1));
htp.tableRowClose;

I will be thankful if you please let me know how can i view the data in proper
format at the earliest.
Regards

Bhavesh
and we said...
1) forms datatype = long, length = whatever you need it to be.

2) are you wrapping the text with:

<pre>
This is the first line.
This is the second line.
</pre>

otherwise, in HTML -- whitespace like blank, tab, newline, etc are IGNORED and
everything is word wrapped.

you could also code:

htp.tableRowOpen (cattribues => 'valign = "top"');
   l_clob = cursor_record.lob_data;
   countdown = dbms_lob.getlength(l_clob);
   htp.p( REPLACE( dbms_lob.substr(l_clob, countdown, 1), CHR(10), '<BR>' ) );
htp.tableRowClose;

to replace linefeeds (chr(10))  with <BR> tags.
Review & Followup
Rating: 5
Thanks a lot. May 30, 2001
Reviewer: A reader
Thanks a lot Tom for this useful tip.

May 30, 2001 YW -- Thanks for the question regarding "How Oracle search encrypted data in the database ?", version 8.0.5
You Asked
I know there isn't any encrypted methodology for data in the database until
Oracle 8i Release 2.   What if we are adopting this function using
DBMS_OBFUSCATION_TOOLKIT, could someone explain how to oracle search or match
the encrypted data ?  Will it use index ? Is it a bit / bytes matching ?

Thanks a lot.
and we said...
You cannot search encrypted data -- it is encrypted.  It doesn't even make sense
to thing about "searching" it.

In any case, if you do "search" this data, you'll have to supply encrypted
inputs and even then only exact equality would work.
May 30, 2001 -- Thanks for the question regarding "exists and in ..continued", version 8.1.7
You Asked
From your earlier answer..

"If the in was doing a column such as DNAME which the optimizer does not
understand is unique -- but dname is indexed, an exists would probably be
better.  On the other hand, if dname is NOT indexed -- the IN would be more
efficient."

Can you kindly explin why?

Why does the optimizer understand that dname is unique, if we can have a unique
index on it.

Thanks
and we said...
you should put URL references in the query -- i get lots of questions (for every
1 you see published there are 3 or 4 more that are not).  A short fragment like
that out of context makes me search for the original question.

So, this is in reference to
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:711323290500
An IN such as:

select ename from emp
where deptno in (select deptno from dept)

is processed much like:

select ename
  from emp, ( select DISTINCT deptno from dept ) dept
 where emp.deptno = dept.deptno

-- that is as a JOIN.  Since the optimizer knows DEPTNO is unique (assuming you
have a primary key on it) the DISTINCT step could be skipped.  If you queried:

select ename from emp
where dname in (select dname from dept)

here -- dname is not unique (i'm assuming that) so the optimizer would in fact
DISTINCT dname and if the DEPT table was LARGE -- that could take a bit of time
(if dname was indexed there are some optimizations to be had there speeding up
that process)
May 30, 2001 Amy -- Thanks for the question regarding "Export files or backup all DB files for customer data validation?", version 8.16
You Asked
Dear Tom,

Our customer sent backup database which is on SQL server to us for data
validation frequently. Now we are moving to Oracle and Unix.
Could you tell me which is best way for them sending us the backup DB
or export DB in order to validate their data? I think export file is enough. Is
that right?

Thanks,Amy
and we said...
An export is cross platform (can exp from solaris and imp on HP) where as a
backup is not -- if that matters.

Either would work if you are on the same platform.  As they should already be
doing regular backups, that might be the easiest for them (and you actually).
Doing the export and import just adds extra steps, a dump and load process, that
is no necessary.
Review & Followup
Rating: 2
June 18, 2001
Reviewer: alok from Pune,India

Rating: 2
back up July 12, 2001
Reviewer: v.r.karthikeyan from noida,india
i'm a just beginner of oracle dba.
so i need clear idea about backup&how to do(both in nt&unix platfrom)
my mail id is vr_karthi123@rediffmail.com

May 30, 2001 Rahul -- Thanks for the question regarding "Enumerated Constants", version 8.1.7
You Asked
Hi Tom

1. Is is possible to create Enumerated Constants in ORACLE, as we normally do in
VC++, VB etc.  If no is there any work around to achieve this.

2. Is there any function available to Add Time (i.e. adding 10 secs/Mins/Hours
to the Time like add_months..  If no is there any work around to achieve this.

Thnx in advance

Rahul
and we said...
1) plsql does not have an enumeration type, no.

you would have to code:

create package mypkg
as
   var1   constant number := 1;
   var2   constant number := 2;
   var3   constant number := 3;
   ....

2) to add 1 day to a date, add 1   (sysdate+1)
   to add 1 hour to a date, add 1/24  (sysdate+1/24)
   to add 1 minute to a date, add 1/24/60  ( sysdate+1/24/60)
   to add 1 second to a date, add 1/26/60/60  (sysdate+1/24/60/60)

to add any number of days|hours|minutes|seconds to a date, just multiply, eg:

   sysdate+5*1/24

adds 5 hours.

There is no need of a specialized function to add time to a date like there is
for adding a month.  To add a month requires complex logic (what happens when
you add 1 month to 28-feb-2000 vs 28-feb-2001 for example) whereas adding time
to a date is simple addition.
May 30, 2001 Raj -- Thanks for the question regarding "Adding Custom keywords to intermedia", version 8.1.7
You Asked
Hi Tom!
   We have created this keyword table in our schema in which the user enters his
keywords assosiated with the article that is created. We are going to using
oracle intermedia as our search tool. Is there anyway we can have intermedia use
these keywords.
and we said...
Assuming that "have intermedia use these keywords" means you want
queries that are issued against the articles to also be issued
against the keyword table, then the answer is yes, you can
exploit this using interMedia Text.  The simplest way to "include"
these keywords in your search is via an additional query.

As an example, let's say your articles were contained in
ARTICLES.THETEXT.  And let's also assume that the keywords associated
with these articles are stored in ARTICLES.KEYWORDS.  Then if you
had an interMedia Text index created on each of these, you could
issue a query similar to:

    SELECT id
      FROM ARTICLES
     WHERE CONTAINS( thetext,'searchterm' ) > 0
        OR CONTAINS( keywords, 'searchterm' ) > 0;

another option is to index a function and have the function return the text and
the keywords "glued together" in a clob.  see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:440419921146
for an example

follow up to comment

index a function.  Have the function return a temporary clob that has the
original text AND the keywords.  I answered that.

see
http://technet.oracle.com/doc/oracle8i_816/inter.816/a77063/cexec3.htm#9186
for ctxload documentation.
Review & Followup
Rating: 2
May 30, 2001
Reviewer: A reader
Hi Tom!
    I needed Intermedia to consider those keywords PART OF a document! Also do
you have any links to explain the ctxload package!

May 30, 2001 Nagarajan -- Thanks for the question regarding "How do I use the host commands from Stored Procedures", version 8.1.6
You Asked
Hi
   I would like to use a stored procedure, which in turn runs some of the
operating system commands like compress, ftp etc.
    Can you help me in developing this procedure to run the os commands from the
database.
     Is it not possible to do it without the use of java.
     Is there any standard oracle package to accomplish this

Thanks
Badrinath
and we said...
The easiest way to do this is Java.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:952229840241
for that method.

An alternative is to use C based extprocs -- see
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76939/adg11rtn.htm#1656
for the background on that.

Another method is to "publish" the commands you want to be able to run from
PLSQL as CGI-BIN scripts running under a webserver on that machine.  Have the
webserver run on ip address 127.0.0.1 (local loopback link, this webserver is
accesible ONLY from the server itself).  Then, you can use

result := utl_http.request
                 ( '
http://127.0.0.1/cgi-bin/ftp.sh?server=foo&file=bar'
);

to run a command.
May 30, 2001 balraj -- Thanks for the question regarding "on NT what percentage of RAM should i use for SGA", version 8.1.6.3
You Asked
My database is on WINDOWS NT,The server has 1GB RAM.

What size of SGA Can i define for the database.
and we said...
I assume you mean "what size SHOULD i use" -- you could use 2gig but that would
not perform well ;)

Impossible to answer.  If you are using MTS (multi-threaded server) the answer
would be about 900m probably.

If you are using dedicated server, the answer might be 100meg.

If you are a data warehouse with 1 one, any configuration -- it might be 900meg.

Then there is the breakdown of the SGA itself -- large pool, java pool,
db_block_buffers, log_buffers, shared_pool, etc.  Thats more important (and
equally impossible to answer) then the aggregate size in many respects.

Sorry I cannot be more clear but without lots of details -- this cannot be
answered.
May 30, 2001 Senthil -- Thanks for the question regarding "TWO_TASK environment variable on windows.", version 8.1.5
You Asked
Hi thomas,

Is it possible to connect remote database without giving service name.

i tried by setting TOW_TASK environment variable. i am able to connect any
remote database from Unix client, if i
-set TWO_TASK environment and
-not giving the service name while entering username and password

but i am *not* able to do the same in windows-NT.

Here is an example.

First Instance, NTORCL, on windows-NT
Second Instance, UNORAC, on Sun-solarais

1. Login into unix client
2. add entry in tnsnames.ora, to the instance NTORCL
3. set TWO_TASK environment variable(assign the NTORCL service name)
4. sqlplus username/password

works fine...

now...
1. Login into windows client
2. add entry in tnsnames.ora, to the instance UNORAC
3. set TWO_TASK environment variable(assign the UNORAC service name)
4. sqlplus username/password
gives invalid username/password...

but it works if i give 'sqlplus username/password@service_name'

am i doing anything wrong or is it not possible.

please advice me.

thanks.

senthil.
and we said...
the environment variable name is LOCAL on windows NT.

set LOCAL=service_name
May 30, 2001 Periasamy -- Thanks for the question regarding "Need a performance tuning hint...", version 8.1.6
You Asked
hi,

in a query i am having some columns and one calculated value , i want to filter
the result based on the calculated value. how can i do this?

say example

select name, city, salary+bonus+epf as total from emp

suppose if i want to filter the result for total > 10000 then how can i include
this condition? in the having class, i can not use the alias name of the field.
my query is too complicated, i badly want to filter the result in a single query
based on the calculated value.

thanks

Periasamy
and we said...
create index total_index on emp(salary+bonus+epf);

See
http://osi.oracle.com/~tkyte/article1/index.html
for details on the Oracle8i feature "function based indexes", available with
Oracle8i EE.

followup to comment one below

do you mean:

select *
 from ( select name, city, salary+bonus+epf as total from emp )
where total > 1000;

use an inline view.
Review & Followup
Rating: 3
Performance issue.... May 31, 2001
Reviewer: Periasamy Subramaniyan from Bulgaria
once if i use the inline view, i am facing the performance impact, my actual
query with out this where condition takes just 350 milli seconds, but once if i
included the filter condition through where clause, it takes 25 SECONDS for just
4000 records, and actually the return result is empty.

(say example i filtered with status = 0, but no such record having the status =
0. according to my situation always the result will be less than 5% of records.

May 30, 2001 -- Thanks for the question regarding "hash", version 8.1.7
You Asked
Tom

 can you tell me in simple terms as to what actually 'hash' means.

and how does a hash join work?

Further

I have read that index join, takes data from the indexes if all the columns in
the predicate are indexed. Is it true, how is it possible?

Further

Can I create a synonym on a partition in a table? What are the data dictionary
tables which give partition specific information.

Further

Discussion IOT's you gave the example of orcl stock records inserted every day
into the stock table. But I dont think your example is appropriate, as iot's are
best suited to static look up tables like product codes etc which doest change
very frequently.

Kindly discuss

Thank you
and we said...
In a hash join, the data to be joined to is stored in a hash table by join
condition.  for example, given:

   select * from emp, dept where emp.deptno = dept.deptno;

the optimizer might hash join emp to dept.  It would full scan DEPT, store it in
a hash table ( a table such that a function applied to the DEPTNO column would
return the index/slot in the table where that row of DEPT could be found).  So,
now when it full scans EMP, it will apply that function to each deptno to find
the DEPT row that goes with it.

In an index join -- if all of the data needed to satisfy the join is in the
index -- Oracle will use the indexes as if they were the table.  Given the query
"select deptno, count(*) from emp, dept where emp.deptno = dept.deptno" -- if
both emp and dept had an index on DEPTNO -- Oracle could choose to "join the
indexes" to get the answer.  No need to ever goto the table -- it has no data we
need in this case.

No, you cannot create a synonym for a partition however you can create a VIEW
that selects from a single partition.

No one ever said IOTs are best suited to static look up tables.  IOTs have many
uses.  The example I gave was actually a text book, classic example of when an
IOT would absolutely be the best choice.

Look at it this way -- you could have a table with TICKER, DATE, PRICE and an
index on that table with TICKER, DATE.  To what end?  You still have to maintain
the index on TICKER,DATE (no savings there) PLUS you have to duplicate
TICKER,DATE (the biggest chunk of data) in the table and the index!  Not only
that but since (as my example had us doing) we load this table every night -- a
heap table would tend to have all of the data for a single ticker on separate
blocks.  The entire point of using an IOT in this case was to get the data
physically colocated -- so that queries (which i do thousands of) hit as little
data as possible.

IOTs are not for static read only data - not in any sense.
May 31, 2001 Tho -- Thanks for the question regarding "Recover through adding logfile", version 8.1.5
You Asked
Hi Tom,
I've read the Oracle doc and know how to recover through adding datafile using
backup controlfile.
But I wonder if i can recover through adding logfile.
Thank you very much.
and we said...
yes, that won't change anything in the recovery process, it'll just be an
archived redo log file to us with a thread # like all other archived redo logs
are.
May 31, 2001 Gayathri -- Thanks for the question regarding "Oracle datafiles", version 8i
You Asked
Where does Oracle store data?
Which of these would be an appropriate answer -  TABLES or DATAFILES, and Why??
and we said...
The data is physically stored in datafiles.  A table is a logical structure that
organizes the data but a table is a "logical entity".  I would vote for datafile
(although you could argue either side of the story here, its not a very relevant
question in my opinion)

We store data in structures in the datafiles, one of those structures is a
table, other structures are indexes, clusters, hash clusters, and so on.
Review & Followup
Rating: 4
May 31, 2001
Reviewer: Gayathri. R from Tamil Nadu, India
The response was very useful and clear and precise.

Thanks for the immediate assistance

May 31, 2001 Kiran -- Thanks for the question regarding "Primary-Foreign Key", version Oracle 8i
You Asked
Hi Tom,

Here is a structure of 2 tables

Table A                Table B
empid (PK) not null---------empid_head (FK) not null
deptid (FK) not null--------deptid     (PK) not null

If I try to insert a row any in one table it gives a primary-foreign violation
due to
the realtionship. So can you please tell me how can I insert a row or  do I have
to change
the design

Thanks
and we said...
Well, it is probably a bad design -- I wouldn't want to work with it -- but it
is doable.  In this case, since the columns are NOT NULL -- you need to use
deferrable constraints.  If the foreign keys were nullable, this would be easy.

Anyway, it could go like this:

ops$tkyte@ORA8I.WORLD> create schema authorization ops$tkyte
  2  create table
  3  a ( empid int primary key,
  4          deptid int not null references b deferrable )
  5  create table
  6  b ( empid_head int not null references a deferrable,
  7          deptid     int primary key )
  8  /

Schema created.

ops$tkyte@ORA8I.WORLD> set constraints all deferred;
Constraint set.

ops$tkyte@ORA8I.WORLD> insert into a values ( 1, 10 );
1 row created.

ops$tkyte@ORA8I.WORLD> insert into b values ( 1, 10 );
1 row created.

ops$tkyte@ORA8I.WORLD> set constraints all immediate;
Constraint set.

ops$tkyte@ORA8I.WORLD> commit;
Commit complete.
May 31, 2001 Vipul -- Thanks for the question regarding "The :old and :New in Triggers", version 8.1.6
You Asked
Hi Tom,

The :old and :new identifiers in Triggers are nothing but record types based on
underlying table structure.

Now, I am looking for capturing before images of a row in a history table before
updating a table. The structure of history table and transaction table will be
identical. This is for Audit purpose and will be done for couple of tables.

For further simplicity, let's say that we will follow a naming convention like
DEPT for transaction table and DEPT_HIS for change History table. Can I write
some kind of generalised routine where irrespective of knowing which columns are
there in the :old record or which table I am updaing, simply say something like
insert into <?>_HIS  values (:old);

And call the same routine from after update trigger on various tables?

I would appreciate if you can suggest any other method you feel would be better.

Thanks.
and we said...
The :NEW and :OLD are bind variables -- not really records at all.  You cannot
write a generic routine (or even specific routine) and pass them as a record.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:59412348055
for a method to do this.  You will write a generic routine to write a specific
trigger, instead of having a generic trigger.
Review & Followup
Rating: 5
Thanks for suggesting different way to achieve the goal. May 31, 2001
Reviewer: VJ from Boston, MA USA

May 31, 2001 Vipul -- Thanks for the question regarding "How to get metadata?", version 8.1.6
You Asked
Hi Tom,

I have declared a generic cursor type in one of the package (say common package)
like below:

create or replace package common_pkg as
  type generic_cur is ref cursor;
end common_pkg;

Now all other packages/procedures are using this type for their parameters or
local variables.

Is their any way (preferably in PL/SQL - not in Java), by which a procedure
whose in parameter is of this generic_cur type can get metadata of each column
(Column name, data type, size etc) it is receiving in the cursor?

Thanks.
and we said...
No, and it would not matter if it did.

PLSQL does have a "get" method to apply to a cursor like java does the result
set.  PLSQL must know at COMPILE time the number of columns and types of columns
-- else you cannot fetch from the cursor or do anything with it.

If you need to dynamically access some unknown number of columns with differeing
types -- you need to use DBMS_SQL.
Review & Followup
Rating: 4
Thanks for Clarifying the issue. May 31, 2001
Reviewer: VJ from Boston, MA USA

Rating: 4
Extremely useful..Thnx Tom June 27, 2001
Reviewer: Girish Hulikantimath from Karnataka, India

Rating: 3
x June 27, 2001
Reviewer: Ed Dice from Pensacola FL
Good to know.

Rating: 3
Good to know. June 27, 2001
Reviewer: Ed Dice from Pensacola FL
Good to know.

Rating: 4
Its very useful June 29, 2001
Reviewer: Sunitha N from Karnataka India

Rating: 4
June 29, 2001
Reviewer: Raj from A.P.India
It's really helpful

Rating: 4
Are there any Data Dictionary Views to know Dirty Blocks, Locked Rows, Locked by whome July 01, 2001
Reviewer: Satyam Polusani from A.P.India
Hi
 Could u send the response to my doubt.
 Daily I am getting complaints from my users and developers
 that they are not accessing some records at particular time, because of they
are already locked by other users.
 so i am expecting answer from u
 that knowing the info of dirty buffres,
 Rows which are locked , Blocks which are locked,
 and locked by whome
please
 send as early as posiible
bye
satyam

Rating: 4
Very important July 03, 2001
Reviewer: Mohamed MOatamed from Cairo , Egypt

Rating: 3
Useful info, July 09, 2001
Reviewer: sarbjit from Toronto
Thanks for the Info.

Rating: 4
Good to Know July 11, 2001
Reviewer: Anthony D. Noriega from NJ, USA
Outstanding, Tom.  You did clarify the issue.

Rating: 4
September 13, 2001
Reviewer: Ranganthan.C from Delhi,India
Very Useful

Rating: 5
Mangement server September 22, 2001
Reviewer: venki from chennai,India
Sorry to ask questions, but I need this to be solved in urgent.
Dear sirs,
After creating repositary I could able log in to the Management Server, but when
I try to log in again, I receive the following Error Message
VTK -1000; unable to connect to the management server .pleae verify that you
have entered the correct host name and the status of the Oracle Management
Server.

Out of this my host name is correct, and when I try to start my service  I
receive the following

C:\>oemctrl start oms
OEMCTRL for Windows NT: Version 2.1.0.1.0
Copyright (c) 1998, 1999 Oracle Corporation.  All rights reserved.
Starting the Oracle Management Server...VXA-3008 : Starting OMS Services, Wait.

oracle.sysman.vdb.VdbSQLException
       at oracle.sysman.vdb.VdbStatement.processError(VdbStatement.java:340)
       at oracle.sysman.vdb.VdbStatement.executeDML(VdbStatement.java:943)
       at
oracle.sysman.vdb.VdbReadWriteTransaction.executeDML(VdbReadWriteTransaction.java
:92)
       at
oracle.sysman.vdf.VdfMASFailOverService.performInitialization(VdfMASFailOverServi
ce.java:
307)
       at
oracle.sysman.vdf.VdfMASFailOverService.startService(VdfMASFailOverService.java:1
46)
       at oracle.sysman.vxa.VxaAppServer.startServices(VxaAppServer.java:1317)
       at oracle.sysman.vxa.VxaAppServer.main(VxaAppServer.java:2213)
[main][2001-9-22:11:15:13:39] VD-2251 : A system error has occurred inside
[FailOver Service]:
 %s
[main][2001-9-22:11:15:13:49] Vxa -- Service 'vdf' failed to start
oracle.sysman.vxn.VxnBootstrapException: VXA-2019 : Error encountered starting
up service: vdf
       at oracle.sysman.vxa.VxaAppServer.startServices(VxaAppServer.java:1319)
       at oracle.sysman.vxa.VxaAppServer.main(VxaAppServer.java:2213)
[main][2001-9-22:11:15:13:49] VXA-2021 :
OMS Service startup failed!
[main][2001-9-22:11:15:13:49]
Error starting Oracle Management Server.
oracle.sysman.vxn.VxnBootstrapException: VXA-2019 : Error e
ncountered starting up service: vdf

May 31, 2001 Mohammed Asif -- Thanks for the question regarding "For Cursor and Open & Fetch", version 8.0.5.0.0
You Asked
Hi Tom,
  The answers you give are too good. I have some questions below, please do a
favor by providing the answers.

** 1) While working on a Pl/sql block I had a strange experience related to
cursors. My block is as follows:
Declare
  Cursor emp_cur is Select emp_no from emp;
Emp_rec emp_cur%rowtype;

  Cursor tran_cur is Select sal, month from emp_tran
    Where emp_no = emp_rec.emp_no;

Begin
  For emp_rec in emp_cur loop
    For tran_rec in tran_cur loop
      -- some processing.
    End Loop;
  End Loop;
End;
/
It does not open the inner cursor, when I replace the For Cursor Loop by Open &
Fetch statements and read the emp_no into temporary variable and assign this
temp. variable to the second cursor, things are fine.

  Could you please explain the strange behaviour.

** 2) I’m working in an environment where my team is afraid of using accumulated
fields as they had a bad experience before. But I’m insisting on the usage of
accumulated fields. Our queries are performing bad as they have to go through
full table to read the amounts. I think maintaining the accumulated fields in
the database trigger would be a good solution. What do you suggest?

** 3) When using Group By clause, do we have to include Order By clause to order
the result or is it ordered automatically?

** 4) We are using Reports 6 and have the following requirement..

  Based on some conditions I have to add a line of text in between my records.
The text differs for different conditions.

eg. Voucher_Details

Item_No   Item_Desc Item_Type    Credit     Debit   Line_Desc
-------   --------- ---------    ------     -----   ---------
3302       A/c 3302     A           784          0     XXX
3102       A/c 3102     A           95           0     XXX
0254       Item 0254    B           651          0     XXX
0110       Item 0110    B            0        1340     XXX
0310       Item 0310    B            0          41     Line 1
0415       Item 0415    B            0          74     XXX
0310       Item 0310    B            0          75     Line 2
3401       A/c 3401     A            0         124     XXX

  We have two types of Item_Types A(Account) & B(Budget Item)

The Rules are
* Start from debit side(i.e. debit > 0)
* Sort by Budget Item and then Account.
* If both A and B are present in debit side then print a line
   "From Both A/c Types". Otherwise, concatenate "From " in the text field with
Item_Desc for all entries in debit side.
 &#61623; If an Item exists only once then print the debit amount in Total_Debit
field.
 &#61623; If exists more than once then print the Item_Desc and on the following
lines print the line desc with amount in the debit column. Lastly, print the sum
in the total_debit side with text field containing Item_Desc concatenated with
“Total of “.
 &#61623; Repeat the above rules for credit sides also, instead of “From” make
it “To”.

My output should be like this
----------------------------------------------------------------
Tot_Credit    Credit            Text          Debit  Total_Debit
----------------------------------------------------------------
                        From Both A/c Types
                             Item 0110          0        1340
                             Item 0301
                               Line 1           41          0
                               Line 2           75          0
                         Total of Item 0301               116
                             Item 0415           0         74

                        From Both A/c Types
    651           0          Item 0254
     95           0          A/c 3102
    784           0          A/c 3302
----------------------------------------------------------------
  1530             One Thousand and Thirty Only            1530
----------------------------------------------------------------

  We are currently using a temporary table to produce the report. But it is a
hectic job, we need to maintain the temp table from multiple users. It would
have been easy if we could have used Stored Procedures or something similar,
even Ref Cursors are helpless.

  Could you suggest a way out.

  Thanks in advance.

Regards,
and we said...
1) you have coded:

Declare
  Cursor emp_cur is Select emp_no from emp;
  Emp_rec emp_cur%rowtype;

  Cursor tran_cur is Select sal, month from emp_tran
    Where emp_no = emp_rec.emp_no;

Begin
  For emp_rec in emp_cur loop
    For tran_rec in tran_cur loop
      -- some processing.
    End Loop;
  End Loop;
End;
/

Those EMP_REC's are not the same EMP_REC.  Notice how you did not define a
TRAN_REC -- you never need to define a loop variable, they are implicit.  When
you entered the loop "for emp_rec in emp_cur" -- the other emp_rec was in a
different scope.  The TRAN_CUR referers to the EMP_REC in the DECLARE block
--but that emp_rec is alway NULL -- its never been assigned to.  Hence -- no
data.

Suggest you blow off the explicit cursors anyway, do this instead:

Begin
  For emp_rec in ( select emp_no
                     from emp )
  loop
    For tran_rec in ( select sal, month
                        from emp_tran
                       where emp_no = emp_rec.emp_no )
    loop
      -- some processing.
    End Loop;
  End Loop;
End;
/

In my opinion, not only is that infinitely more readable -- it is less error
prone (and its faster)

2) with proper tuning, derived fields should not be neccessary unless you are in
a data warehouse.  I do not use "accumulated" fields either.  If I had to keep
the SUM of SALARY by departement for example -- that would imply each
insert/update/delete to/from a department would have to update the DEPT record
as well -- introducing a massive point of contention.  Instead of locking rows
at the EMP level, you would lock them at a much higher level -- the DEPT level.

In a data warehouse -- aggregate away.
In an OLTP system -- don't do it.

3) you MUST include an order by.  group by does not have to sort.

4) true temporary tables are available in Oracle8i, release 8.1.  In prior
releases, you can do this:

ops$tkyte@ORA8I.WORLD> create table temp ( x int, y date, z varchar2(25) );

Table created.

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

Package created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create or replace package body demo_pkg
  2  as
  3
  4  procedure p( p_cursor in out rc )
  5  is
  6  begin
  7
  8          -- populate temp table however
  9          -- you see fit
 10          for i in 1 .. 5
 11          loop
 12                  insert into temp values ( i, sysdate+i, 'row ' || i );
 13          end loop;
 14
 15          open p_cursor for select * from temp;
 16
 17          delete from temp;
 18  exception
 19          when others then
 20                  delete from temp;
 21  end;
 22
 23  end;
 24  /

Package body created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> variable x refcursor
ops$tkyte@ORA8I.WORLD> set autoprint on
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> exec demo_pkg.p( :x )

PL/SQL procedure successfully completed.

         X Y         Z
---------- --------- -------------------------
         1 31-MAY-01 row 1
         2 01-JUN-01 row 2
         3 02-JUN-01 row 3
         4 03-JUN-01 row 4
         5 04-JUN-01 row 5

ops$tkyte@ORA8I.WORLD> select * from temp;

no rows selected

ops$tkyte@ORA8I.WORLD>

due to our multi-versioning model, the cursor you open in the stored procedure
will ALWAYS see the data even though no data ever exists.

Multiple users can use this temp table wihtout ever bumping into eachother.

followup to comment one

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1544606261686
shows

  select .... into ...
   from ....

is faster then the explicit:

   open c;
   fetch c into x;
   close c;

(which is sort of funny cause for some reason everyone thinks the opposite is
true)

Another example is:

tkyte@TKYTE816> declare
  2          l_start number default dbms_utility.get_time;
  3
  4          cursor c is select * from dual;
  5          l_dummy dual.dummy%type;
  6  begin
  7       for i in 1 .. 10000
  8       loop
  9               open c;
 10               loop
 11                       fetch c into l_dummy;
 12                       exit when c%notfound;
 13               end loop;
 14               close c;
 15       end loop;
 16       dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
 17  end;
 18  /
135 hsecs

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816> declare
  2          l_start number default dbms_utility.get_time;
  3  begin
  4       for i in 1 .. 10000
  5       loop
  6               for x in ( select * from dual )
  7               loop
  8                       null;
  9               end loop;
 10       end loop;
 11       dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
 12  end;
 13  /
120 hsecs

PL/SQL procedure successfully completed.

my guidelines as to when explicit cursors are appropriate -- only when you use
a ref cursor.  Otherwise I never use them.  Implicit cursors RULE
Review & Followup
Rating: 5
Explicit Cursors..when to use?? May 31, 2001
Reviewer: Nilan from Norfolk, VA USA
Tom,

Let me first say that you provide a very valuable service.
I have picked up many USEFUL tips here that I practice everyday.  However, I was
suprised to see your answer to the first question above.

"Suggest you blow off the explicit cursors anyway, do this
instead...<snip>....In my opinion, not only is that infinitely more readable --
it is less error prone (and its faster)".

Do you have a set of guidelines that you use to identify when explicit cursors
are appropriate and when they are not? Also, can you clarify what you said about
cursors being slower than doing a regular for statement?

Rating: 5
Helpful? May 31, 2001
Reviewer: Jim Kennedy from Hillsboro, OR
You bet its helpful!  I come to this site everyday just to read and see if I can
learn anything new.  I learn something new , new method, better style, better
practice  every day.  Tom, you are worth your weight in gold to the Oracle
community.  I can't wait until the book is out, I have it on order. And the
spell checker is cool.  You guys should market that.

May 31, 2001 David -- Thanks for the question regarding "Filtering SQL*Plus errors when trying to shutdown", version 8.1.6
You Asked
I have the following as part of a Korn shell script :-

(
$ORACLE_HOME/bin/sqlplus -s /nolog <<-!END_SQL >>$LOG 2>&1

WHENEVER SQLERROR EXIT SQL.SQLCODE
WHENEVER OSERROR EXIT SQL.OSCODE

SET PAGESIZE 0 LINESIZE 132

SET SERVEROUTPUT ON;
SET FEEDBACK ON;

CONNECT / AS SYSDBA

SHUTDOWN IMMEDIATE

EXIT SQL.SQLCODE
!END_SQL
)

ERR=$?

#Check for errors other than d/b not mounted or open

[[ $ERR != 0 ]] &&\
[[ $ERR != 227 ]] &&\
[[ $ERR != 85 ]] &&\
error $ERR "returned from SQL*Plus, see $LOG"

My problem is that although under normal circumstances this is fine, traps
errors etc. Sometimes the dataabse may not be open e.g a standby database. When
a database is not open it returns either ORA-01507 or ORA-01109, depending on
wether or not it is mounted. So as you can see I filter for these two (they are
returned to the ksh script as either 85 or 227). However the WHENEVER SQLERROR
statement causes immediate exit and the database hangs in the state of "shutdown
pending". So how do I prevent the hang or is there a better way of filtering
SQL*Plus errors?

TIA
and we said...
why don't you check to see if the database is open and mounted?

WHENEVER SQLERROR EXIT SQL.SQLCODE

declare
    l_open_mode varchar2(25);
begin
    select open_mode into l_open_mode
      from v$database
     where open_mode = 'READ WRITE';
end;
/

then you'll get

ORA-01507: database not mounted
when the database is not mounted

and
ORA-01403: no data found
when the database is mounted by not opened.
May 31, 2001 Rahul -- Thanks for the question regarding "CURSOR%ROWTYPE variable", version 8.1.7
You Asked
Hi tom,

I have a following program:

  CREATE OR REPLACE PROCEDURE A() AS
  BEGIN
     DECLARE CURSOR C1 IS SELECT A.COL1, A.COL2, B.COL1, B.COL2 FROM A, B WHERE
A.COL3 = B.COL3;

   C1_rec%ROWTYPE;

    For C1_Rec IN c1 LOOP
         insert into c values (c1_rec.a.col1, c1_rec.a.col2, c1_rec.b.col1,
c1.b.col2);
        end loop

But the above insert statement is not working it gives an error PLS-00302:
component 'a' must be declared;

How to resolve this problem

Thx
and we said...
it is just c1_rec.col1.  The correlation name is not part of the column name.

You need to remove the ambiguity using column aliases.  I would suggest not
using explicit cursors either -- harder, more error prone and slower then the
easy way:

...
begin
   for x in ( select a.col1 a_c1, a.col2 a_c2, b.col1 b_c1, b.col2 b_c2
                from a, b
               where a.col3 = b.col3 )
   loop
         inset into c (c1,c2,c3,c4) values ( x.a_c1, .... );
   end loop;

and I hope your logic is much harder then the above, otherwise the proper method
is:

   insert into c (c1,c2,c3,c4)
   select a.col1, a.col2, b.col1, b.col2 from a, b where a.col3 = b.col3;

(hint -- always use an explicit list (c1,c2,c3,c4) in a real insert in a real
program, less error prone, less buggy)
Review & Followup
Rating: 4
Usefull June 01, 2001
Reviewer: Anand Singh from Ghaziabad(U.P.)-India
Tom
For...Loop...End Loop function is very usefull.
In this less declaration,less codding is required instead of using cursors.

May 31, 2001 Scott -- Thanks for the question regarding "Using Intermedia: Multiple Paths for file_datastore on NT", version 8.1.6
You Asked
In your March/April 2001 article, "Tips on Automation, Cleanup, and Database
Maint." you enumerated a few examples on how to create and automate full text
indexes.

I am looking for a way to create a preference (method 2 in your article) that
has multiple paths for a single datastore (c:\temp and c:\temp\dir1 and
c:\temp\dir2).

The online documentation listed here (see below) for the path attribute of
preferences indicates that you can use colons to separate multiple paths.
However, this does not work on NT.  Is there a viable delimeter that works on
NT?

Documentation link:
http://technet.oracle.com/doc/oracle8i_816/inter.816/a77063/cdatadi3.htm#41613

Thanks -
and we said...
Joel Kallman, resident interMedia guru says....

This is clearly not documented in an evident fashion.  On Windows NT
and Windows 2000, the directory separator character for the PATH
attribute of the FILE_DATASTORE preference is a semicolon ';' instead of
a colon ':'.

This is documented in note 113326.1 on MetaLink at:
http://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&p_id=113326.1
...
Review & Followup
Rating: 5
Thanks Tom. November 09, 2003
Reviewer: Saminathan Seerangan from Jersey City,NJ,USA
This example is from AskTom column(Oracle Magazine). CTX_DDL.SET_ATTRIBUTE has
been modified to work with multiple directories (Windows NT OS).

CREATE TABLE mydocs( id NUMBER PRIMARY KEY,title VARCHAR2(255), thefile
VARCHAR2(255) );

INSERT INTO mydocs( id, title, thefile ) VALUES( 1, 'Document1', 'WordDoc1.doc'
);
INSERT INTO mydocs( id, title, thefile ) VALUES( 2, 'Document2', 'WordDoc2.doc'
);
INSERT INTO mydocs( id, title, thefile ) VALUES( 3, 'Document3', 'WordDoc3.doc'
);
COMMIT;

BEGIN
CTX_DDL.drop_PREFERENCE('my_datastore_prefs');
END;
/

/*
WordDoc1.doc is stored in D:\share\oracle
WordDoc2.doc is stored in D:\share\oracle\work
WordDoc3.doc is stored in D:\share\oracle\XML
*/

BEGIN
CTX_DDL.CREATE_PREFERENCE( 'my_datastore_prefs', 'FILE_DATASTORE' );
CTX_DDL.SET_ATTRIBUTE( 'my_datastore_prefs', 'path',
'D:\share\oracle;D:\share\oracle\work;D:\share\oracle\XML');
END;
/

drop index mydocs_text_index;

CREATE INDEX mydocs_text_index ON
mydocs(thefile) INDEXTYPE IS ctxsys.context
    PARAMETERS('datastore my_datastore_prefs');

SELECT title  FROM mydocs WHERE contains( thefile, 'PMON' ) > 0;

June 01, 2001 Bhavesh -- Thanks for the question regarding "SQL Query", version 8.1.7.0.0
You Asked
Hi Tom,
1.   I have got stuck with a query and will be thankful if you please help me
out of this. Ok following is the structure of the table for your perusal.

DETAIL TABLE :(I am removing the details column for easy reference)

TOPIC_ID                                 VARCHAR2(30)
SERIAL_NO                       NOT NULL NUMBER(3)
TOPIC_HEADER                             VARCHAR2(512)
USER_CREATED                             VARCHAR2(30)
DATE_CREATED                             DATE

The primary key here is topic_id and serial_no and serial number starts from
one. I want to have a query where I can have the topic_id, value of user_created
field for that topicid and serial no = 1 (i.e first record of that topic id) and
maximum of date created for that topic id i.e.
say if I have 11 records as follows :

14761170770000116            1 Hello  user A                        01-MAY-01
14761170770000116            2 Hello  user A                        04-MAY-01
14761170770000116            3 Hello  user B                        08-MAY-01
14761170770000116            4 Hello  user A                        10-MAY-01
14761170770000116            5 Hello  user B                        14-MAY-01
14761170770000116            6 Hello  user A                        17-MAY-01
14761170770000116            7 Hello  user B                        18-MAY-01
14761170770000116            8 Hello  user B                        22-MAY-01
14761170770000116            9 Hello  user A                        26-MAY-01
14761170770000116            10 Hello user B                        29-MAY-01
14761170770000116            11 Hello user A                        31-MAY-01

The query should return me

14761170770000116, user A, 31-MAY-01 i.e. topic_id, first user who created the
topic and last date on which this was updated.

2. I am doing following query to create a PL/SQL server generated page.
   select trunc(nvl(total_amount, 0)*1, 2) from invoice ;
   The above query returns me something say 567, 756.32, 235.79, 563, 90.22
   that means I am loosing the format for those number which are in whole
numbers. I thought it should have displayed something 567.00, 756.32, 235.79,
563.00, 90.22. I could have converted it into to_char and formatted the query
but I am using dynamic query to generate the page and the table name, column
name and value is not known to me until it is printed (just one of the excellent
solution I found on your site). How can i get the numbers as 567.00 instead of
567.

   Thanks a lot in advance.
   Best Regards

   Bhavesh
and we said...
1)

Here is one way:

ops$tkyte@DEV816> select topic_id,
  2             max( decode( serial_no, 1, user_created, NULL ) ) user_created,
  3             max( date_created ) date_created
  4    from t
  5   group by topic_id
  6  /

TOPIC_ID                       USER_CREATED                   DATE_CREA
------------------------------ ------------------------------ ---------
14761170770000116              user A                         31-MAY-01

2)

  can you

  select to_char( trunc(nlv(total_amount,0)*1, 2 ), '999,999,999.99' )
    from invoice

If you cannot do that, you can use a procedure such as:

procedure format_cell( columnValue in varchar2, fmt in varchar2 )
is
    dummy    number;
begin
    dummy := to_number( columnValue );
    htp.tableData( ltrim(to_char(dummy,fmt)), 'right' );
exception
    when others then
        htp.tableData( nvl(columnValue,'(null)') );
end format_cell;

That'll print out the numbers (if they are a number) using whatever fmt you
supply -- else it'll just print out the string.
Review & Followup
Rating: 5
Thanks a Lot June 01, 2001
Reviewer: A reader
Thank you very much Tom. I was looking for this only. Thanks once again.

June 01, 2001 -- Thanks for the question regarding "Unknown record type fetch from the cursor.", version Oracle 8i
You Asked
Hi Tom,

I would like to write a modular procedure which will take in parameters and
construct a sql stmt like this:

procedure get_record(p_tname varchar2,
p_dbname varchar2) as
type cur_type is ref cur;
c cur_type;
stmt varchar2(101);
begin
stmt := 'select * from :tname@:dbname';
open c for stmt using p_tname, p_dbname;
loop
fetch c into C_REC;
exit when c%notfound;
.... -- do something
end loop;
....
....
end;

The objective is to make C_REC to be the type of whatever the ref cursor c
holds. I don't know in advance the type of columns to retrieve. (It can be done
if I use "for C_REC in c loop", but the I need to construct the dynamic sql).

Other than dbms_sql, can I use native dynamic sql to solve this? Any other
suggestions, please?

Is there any site or documents about tutorial on dynamic sql you can recommend?

Thanks.
and we said...
You cannot do that using NDS.  The record type must be fixed at compile time
(think about it -- the record is referenced via C_REC.NAME - if you don't know
the names -- you couldn't even reference the record at runtime if you could do
this)

DBMS_SQL is the 100% correct approach in the above as it allows you to reference
the N'th column.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:235814350980
for an example using DBMS_SQL that takes any query and dumps it to a delimited
file.
June 01, 2001 ahmad -- Thanks for the question regarding "Procedure", version 8.1.5
You Asked
Hi Tom;
1.The question I asked before about triggers and displaying a message to the
user after his logon Is it completly Impossible in oracle?
2.In trigger we can have after update or insert on emp,
can't we have a statement like after select on emp

3.I have an application in vb accessing oracle.
tables are :
STUDENTINFO
STUDENTID
The table Studentinfo contains detail information about students like
,name,id,address,phone,ect..
The table studentid contains two columns student name and student id.
a student can have multiple records in studentinfo table as for each month.
the problem is that I want to identify those student who have not paid fees as
there is more than 1 month difference between PAIDDATE and SYSDATE I can't do
this because there are multiple records for same student with different months
for there fees payments:
I tried it this way:
select * from studentinfo
where months_between(sysdate,admdate)>1;
it works fine but there are multiple records of a student it checks for all
student and returns all students records even for last months:
Studentname                  stid                       paiddate
-------------------               -------                       -----------
Smith            1        01-feb-2001
smith             1        01-mar-2001
smith            1        01-apr-2001

Now this query returns all the rows:
select * from studentinfo
where months_between(sysdate,piaddate)>1;

tanx;
and we said...
1) impossible unless the APPLICATION connecting to Oracle gives the message.

Think about it -- Oracle is a server, it can do no IO with the end user.  There
is always a program between the end user and Oracle.

This program is responsible for doing interaction with the end user.  SQLPlus
has no "message of the day" facility.  Any application YOU develop can have a
message of the day.  SQLPlus would allow you to use a login.sql or glogin.sql to
put something like:

select * from motd;

in it.  that would have sqlplus run that query everything you start it.  you
would put the message of the day

2) because we don't have an "after select" type of trigger.  The overhead would
be totally overwhelming.

We allow you to "select * from function()" -- you can procedually process
whatever you like there.  We also provide for fine grained access control, a
query rewrite facility -- see
http://osi.oracle.com/~tkyte/article2/index.html

3)
select stid, max(admdate)
  from studentinfo
 group by stid
having months_between( sysdate, max(amdate) ) > 1
/
June 01, 2001 -- Thanks for the question regarding "sequences during replication", version 8.1.7
You Asked
hi
i have a table with a column taking values from a sequence. i am setting up
multi master replication which involves 3 sites..one master definition site and
2 other master sites. the replication involves this table also..how can we avoid
the sequence number clash between all the 3 sites.
i donot want to reserve the numbers because they might be exhausted after some
time..(like 1 to 10000 for one site and 10000 to 20000 for another and so on)
i think there is  a leap frog/window sequence generator which the oracle
databases internally divide and manage the sequences.. can you throw more light
on how to allocate the sequences to each site in this case and how to manage
this.
thanks
and we said...
create sequence my_seq start with 1 increment by 100;  -- at site 1....
create sequence my_seq start with 2 increment by 100;  -- at site 2....
create sequence my_seq start with 3 increment by 100;  -- at site 3....

that way each site generates its own stream of numbers that cannot conflict with
eachother.
Review & Followup
Rating: 4
June 01, 2001
Reviewer: A reader from Frankfurt

Rating: 5
Very nice, elegant solution July 09, 2001
Reviewer: Mark J. Bobak from Ann Arbor, MI
Thanks Tom!  We have been struggling w/ this very
problem, and exploring different possibilities, including
things as kludgy as public synonyms that point to seqeunces
in another database across a db link.  That was not a very
optimal solution.

I like this one.  It's simple, and it doesn't add any
overhead to the sequence process.

Thanks,

-Mark

June 01, 2001 Anil -- Thanks for the question regarding "query -- decoding and getting a pct of total", version 8.1.5
You Asked
Hi tom,
  Here is My question
select branchcode,gscname,count(*) as totalno,'07 days'"days"
from test where (diffdays between 1 and 7)
group by branchcode,gscname
union
select branchcode,gscname,count(*) as totalno,'14 days'"days"
from test where (diffdays between 8 and 14)
group by branchcode,gscname
union
select branchcode,gscname,count(*) as totalno,'21 days'"days"
from test where (diffdays between 15 and 21)
group by branchcode,gscname
union
select branchcode,gscname,count(*) as totalno,'above 21 days'"days"
from test where diffdays > 21
group by branchcode,gscname
order by branchcode,"days"

I get answer as follows
   branchcode   gscname   totalno  days
   101001       p         64       7
   101001       p         21       14
   101001       p         6        21
   101002       j         10       7
   101002       j          1       14
   101002       j          1       21
    -  -        -          -        -
i want another colomn which should give me the percentage as follows
1) for first row totalno 64 is how much percent of 64+21+6
2) for second row totalno 21 is how much percent of 64+21+6
3) for third row   totalno 6 is how much percent of 64+21+6
4) for fourth row totalno 10 is how much percent of 10+1+1
5) for fifth row totalno 1 is how much percent of 10+1+1
5) for sixth row totalno 1 is how much percent of 10+1+1
and so on for next row

Just notice i want according to gscname column,first time gscname is
p,second time gscname is j.and third time it might be something else.

can You help me on This.

thanks,

Regards
  ak
and we said...
Well, in 8.1.6 -- using the analytic functions, this will be a breeze and will
perform much better then in 8.1.5 without them.  I'll show you both methods.

I can say that using a union to do the above is rather inefficient (whenever you
have mutually exclusive sets - use a UNION ALL.  A union B = distinct ( sort (
A+B ) ).   A union all B = (A+B).

But, we don't even need the union, just a little decode action:

ops$tkyte@DEV816> select branchcode, gscname, days, count(*) totalno
  2    from (select branchcode, gscname,
  3                 decode( sign(diffdays-7.1), -1, '07 days',
  4                   decode( sign(diffdays-14.1), -1, '14 days',
  5                      decode( sign(diffdays-21.1), -1, '21 days',
  6                             'above 21'
  7                            )
  8                         )
  9                       ) days
 10            from test
 11          )
 12   group by branchcode, gscname, days
 13   order by 1, 3
 14  /

BRANCHCODE G DAYS        TOTALNO
---------- - -------- ----------
    101001 p 07 days          64
    101001 p 14 days          21
    101001 p 21 days           6
    101002 j 07 days          10
    101002 j 14 days           1
    101002 j 21 days           1

6 rows selected.

Now, to get the pct's in 8.1.5 and before, we'll use an inline view to
aggregate the counts at two different levels and join them together:

ops$tkyte@DEV816> select branchcode, gscname, totalno, days,
                              round(100*totalno/tot_days,2) days_pct
  2    from ( select branchcode, gscname, days, count(*) totalno
  3             from (select branchcode, gscname,
  4                          decode( sign(diffdays-7.1), -1, '07 days',
  5                             decode( sign(diffdays-14.1), -1, '14 days',
  6                                 decode( sign(diffdays-21.1), -1, '21 days',
  7                                         'above 21'
  8                                       )
  9                                   )
 10                                ) days
 11                     from test
 12                  )
 13            group by branchcode, gscname, days
 14         ),
 15         ( select branchcode t2_branchcode, gscname t2_gscname,
                                                         count(*) tot_days
 16             from test
 17            group by branchcode, gscname ) t2
 18   where t2_branchcode = branchcode
 19     and t2_gscname = gscname
 20  order by 1, 4
 21  /

BRANCHCODE G    TOTALNO DAYS       DAYS_PCT
---------- - ---------- -------- ----------
    101001 p         64 07 days       70.33
    101001 p         21 14 days       23.08
    101001 p          6 21 days        6.59
    101002 j         10 07 days       83.33
    101002 j          1 14 days        8.33
    101002 j          1 21 days        8.33

6 rows selected.

In Oracle8i release 2 and up (8.1.6) the analytic functions remove the need
for us to materialize the aggregates at two different levels -- the
ratio_to_report built in does what you want in one step.  also notice how the
use of CASE (new in 8.1.6 as well) makes the decoding easier to
code/read/understand:

ops$tkyte@DEV816> select branchcode, gscname, totalno, days,
  2         round( (ratio_to_report(totalno) over
  3                     ( partition by branchcode, gscname ))*100, 2 ) days_pct
  4   from  ( select branchcode, gscname, days, count(*) as totalno
  5             from ( select branchcode, gscname,
  6                        case when diffdays between 1 and 7 then '07 days'
  7                             when diffdays between 8 and 14 then '14 days'
  8                             when diffdays between 15 and 21 then '21 days'
  9                             else 'Above 21 days'
 10                        end AS days
 11                      from t )
 12             group by branchcode, gscname, days
 13         )
 14  order by 1, 4
 15  /

BRANCHCODE G    TOTALNO DAYS            DAYS_PCT
---------- - ---------- ------------- ----------
    101001 p         64 07 days            70.33
    101001 p         21 14 days            23.08
    101001 p          6 21 days             6.59
    101002 j         10 07 days            83.33
    101002 j          1 14 days             8.33
    101002 j          1 21 days             8.33

6 rows selected.
Review & Followup
Rating: 4
Too good ... June 01, 2001
Reviewer: Sanjay from Denver, CO USA
Answer is exceptionally good, provides with comparative study of different sql
techniques. Thanks very much for this brain storming answers.

Rating: 5
June 01, 2001
Reviewer: VJ from Boston, MA USA

Rating: 5
Best Solution June 08, 2001
Reviewer: A reader from USA
Tom is the best!!!

June 01, 2001 -- Thanks for the question regarding "pl/sql tables", version 8.1.7
You Asked
Suppose , I have a huge look up table. But only need couple of columns from that
table, for my procedure.

Is it efficient to select those two columns into a pl/sql table in my procedure
, instead of looking up to the table every time.

Example

Say dept is a huge table.

I need to look into deptno many time in my procedure.
I will select all the deptno's into my pl/sql table and use it as my look up
table , instead of the dept table itself.

Is this more efficient.

Thank you.
and we said...
I seriously doubt it.

select a,b,c into l_a,l_b,l_c from dept where deptno = :x;

will be faster then you code code a similar binary search or linear search in
plsql.

The size of a table, on an indexed read, is not really relevant.

The size of a plsql table is -- the bigger -- the longer to search, the more ram
it consumes.

the database was built to do SQL, it does it rather efficiently.  Rather then
doing a procedural lookup like this:

   for x in ( select * from t )
   loop
       select a,b,c into l_a,l_b,l_c from dept where deptno = t.deptno;
       ......

you should just JOIN - let the database do the work for you.  Thats what it is
there for.

Never do procedurally what you can do in one query.
Review & Followup
Rating: 4
plsql tables July 02, 2001
Reviewer: Prasanna satish from Mumbai,India
I had this doubt that plsql tables depend on the RAM. My plsql blocks ran much
faster when I replaced the plsql tables with cursors. Thanks.

June 01, 2001 senthilkumar -- Thanks for the question regarding "Truncate Command", version 8.1.6
You Asked
Hi Tom,

I have created a Table say table-A and created a synonym TableAX.

When I say Truncate table table-A it is truncating without any problem. But if I
give Truncate table TableAX (Synonym) it says table or view doesn't exist. I was
surprised by this (I never used synonym before in Truncate statement, but this
time I need to use synonym in Truncate). When we use synonym in all other place,
why not Oracle doesn't allows us to use synonym in Truncate Statement ?

Is it done purposely not to use Synonym in Truncate or is it a bug?

Thanks,

Senthil.
and we said...
A synonym can only be used with some commands. See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/ch4g8.htm#3702
For DDL, this is specifically:

AUDIT
NOAUDIT
GRANT
REVOKE
COMMENT

so, truncate does not stand alone:

tkyte@TKYTE816> create procedure p as begin null; end;
  2  /

Procedure created.

tkyte@TKYTE816> create synonym p_syn for p;

Synonym created.

tkyte@TKYTE816> alter procedure p compile;

Procedure altered.

tkyte@TKYTE816> alter procedure p_syn compile;
alter procedure p_syn compile
*
ERROR at line 1:
ORA-04043: object P_SYN does not exist

tkyte@TKYTE816> exec p;

PL/SQL procedure successfully completed.

tkyte@TKYTE816> exec p_syn;

PL/SQL procedure successfully completed.

is another example....
Review & Followup
Rating: 4
June 01, 2001
Reviewer: Senthil from USA

Rating: 3
June 01, 2001
Reviewer: A reader

Rating: 4
June 01, 2001
Reviewer: mani from ca,usa

June 01, 2001 -- Thanks for the question regarding "checkpoint - Reg ", version 8.1.7.0.0
You Asked
Hi Tom

I think checkpoint is made to maintain the integrity of
datafiles/logfile.

When does cchekpoint occurs. what does the default value of checkpoint 10000
represents.

Whenever there is a commit the transaction is handled by new scn.
why do u require checkpoint.

pl explain in detail i have gone through the documentation it is not clear. More
often yr replies r much more easily understood  that the documentation.

Regards
and we said...
correct.

a checkpoint occurs on every log switch, may be caused by time passing or number
of blocks dirtied.  see log_checkpoint_interval, log_checkpoint_timeout.  It may
be caused by the buffer cache being too full.

A checkpoint gets blocks that are protected by redo log entries onto disk so we
can reuse a redo log file.  Lets say you modify blocks 1, 100, 1000, 10000 --
that generates redo.  when you commit, the redo is saved to the online redo log
files.  The blocks remain in the cache.  If we crash, we have the modifications
saved in the redo log file and can redo them upon startup.  However, eventually
that log file fills up and we must reuse it.  Before we can -- those dirty
blocks MUST be flushed to disk.  Once they are we can reuse the redo log.

In my book coming out in three weeks -- I go into this in some detail with
pictures and everything ;)  I follow various scenarios "what if we crash right
now" sort of things.
June 01, 2001 Susan -- Thanks for the question regarding "mutating table on update trigger", version 8i
You Asked
What I want to do seems relatively simple -

pseudo code
on user_listing.update
                if :old.exchg_id = 6 and :new.email is notnull then
                    set user_listing.user_nm = :new.email where
user_listing.user_id = :old.user_id

Here's what I set up to avoid a mutating table

create or replace package user_nm_pkg as
   type  array is table of user_listing%rowtype index by binary_integer;
   updvals array;
   empty array;
end;
/

create or replace trigger user_listing_bu
before update on user_listing
begin
   user_nm_pkg.updvals := user_nm_pkg.empty;
end;
/

create or replace trigger user_listing_bufer
before update on user_listing
for each row
declare
  i number default user_nm_pkg.updvals.count+1;

begin

user_nm_pkg.updvals(i).user_id := :old.user_id;
user_nm_pkg.updvals(i).exchg_id := :old.exchg_id;
user_nm_pkg.updvals(i).email := :new.email;
end;
/

CREATE OR REPLACE TRIGGER USER_LISTING_AU
AFTER UPDATE
ON XR1_TEST.USER_LISTING
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
begin

 for i in 1 .. user_nm_pkg.updvals.count loop
  update user_listing
  set user_nm = user_nm_pkg.updvals(i).email
  where user_id = user_nm_pkg.updvals(i).user_id;
end loop;
end;

But when I perform an update on user_listing - I still get a mutating table
error.  What am I doing wrong and do I really need all this for such a simple
requirement (my boss who is a Java developer can't believe all this is
necessary)

UPDATE:

is that going to UPDATE the same row that is being updated?
  yes

we allow users to change their email, but for this particular site email and
user_nm are the same value, so if a user changes their email we want to
automatically change their user_nm as well.  User_id is a primary key on the
user_listing table.

Thanks for your help.
and we said...
Then the trigger is simply:

before update on T for each row
begin
  if ( :old.exchg_id = 6 and :new.email is NOT NULL )
  then
       :new.user_nm := :new.email;
  end if;
end;
/

the BEFORE triggers can simply write into the :new record -- you might use this
in a BEFORE INSERT trigger for example to populate a primary key:

create trigger ...
before insert on T for each row
begin
   select my_seq.nextval into :new.primary_key from dual;
end;
/

Don't try to update the table again -- just modify the :NEW data.
Review & Followup
Rating: 5
June 02, 2001
Reviewer: A reader

June 01, 2001 Logo -- Thanks for the question regarding " Difference between Transaction READ-ONLY and TRANSACTION ISOLATION LEVEL SERIALIZABLE", version 8,1.6
You Asked
Tom,

What is the difference between SET TRANSACTION READ ONLY and SET TRANSACTION
ISOLATION LEVEL SERIALIZABLE? As for as my understanding goes, both of them
don't see any committed changes from other sessions during the duration of the
transaction.

Thanks,
Logo Palanisamy
and we said...
one can update.

the other cannot.

set transaction read only predates serializable by a couple of years -- if they
had come out at the same time, we probably would not have read only as
serializable is a superset of read only.
Review & Followup
Rating: 5
Transaction Read only and isolation level serializable June 01, 2001
Reviewer: Logo Palanisamy from Santa Clara, CA
Well said.

June 01, 2001 -- Thanks for the question regarding "isolation levels - what are the different levels and what do they mean", version 8.1.7
You Asked
Tom

What are the different levels in oracle, and what do they mean? Kindly provide
me the link to the concerned material, Iam not able to find any.

Thank you
and we said...
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c23cnsis.htm#2434
and specifically

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c23cnsis.htm#2641

Oracle8i server concepts manual.

June 01, 2001 Susan -- Thanks for the question regarding
      "unique constraint", version 8i

      You Asked
Can I have a composite unique constraint where one of the columns allows nulls?
By way of example, let's say I've put a unique constraint on the combination of
a and b columns but I allow nulls for b.

Insert into table(a,b)
values ('X',null)
insert into table(a,b)
values ('Y', 'Z')
insert into table(a,b)
values ('X',null)

will that last row violate the unique constraint?

Thanks for the help.

      and we said...
SQL> create table t ( a int, b int, unique(a,b) );
Table created.

SQL> insert into t values (1,null);
1 row created.

SQL> insert into t values (1,null);
insert into t values (1,null)
*
ERROR at line 1:
ORA-00001: unique constraint (TKYTE.SYS_C005075) violated

as long as ONE of the columns in the unique constraint is NOT NULL -- it'll be
entered into the index and NULL will be consider equal to NULL for uniqueness.
So, the two rows (1,null) and (1,null) are considered the same.

HOWEVER, if all of the columns can be null, be careful.  NULLS are not indexed
in conventional b*tree indexes (and bitmaps, which do index nulls, cannot be
unique):

SQL> insert into t values (null,null);
1 row created.

SQL> insert into t values (null,null);
1 row created.

Review &
      Followup

      Rating: 5
How let this
      columns auto.... ?  June 01, 2001
Reviewer:
      kent  from shenzhen china.
Tom:

Now I have this table.
temp(col1   number,  col2   varchar2(10))

I want use fllowing pl/sql .

insert into temp(col2) values ('values01');
insert into temp(col2) values ('values02');
insert into temp(col2) values ('values03');
insert into temp(col2) values ('values04');
insert into temp(col2) values ('values05');
insert into temp(col2) values ('values06');
...

Then the col1's values will be:
1
2
3
4
5
6
....

I wan't use the pl/sql:
insert into temp(col1,col2) values(x,'values');
How can i do?
Thank you?

      Rating:
      4
  June 02, 2001
Reviewer:
      A reader

June 02, 2001 Andre -- Thanks for the question regarding "Who
      controls extent management in locally managed TS's ?", version 8.1.6

      You Asked
Hi Tom !

I've had this question a long time, maybe you can answer it.

Performance improvements in LMTS's are due to decentralizing access to extent
management information. Dictionary managed TS's are controlled by recursive
operations carried out by background processes, I assume. It seems to me extent
management in LMTS's are performed by server processes instead. Is that correct
?

Thanks for your help !

Andre W Nasser

      and we said...
see also

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:733126913855
part of the improvment is due to de-serializing a serial process, the other part
is that finding a free extent is so much less expensive in an LMT as well.

Extent management in a dictionary managed tablespace is done by the server
process as well -- it is the process that does the recursive sql.  extent
management has always be the "done" by the server process.

Recursive sql is done by your dedicated/shared server.

June 02, 2001 Andre -- Thanks for the question regarding
      "Internal numeric format", version 8.1.6

      You Asked
Hi again !

I was wondering how Oracle maintains internal numeric information like the
NUMBER datatype. Is it represented in traditional binary formatting like in
little/big endian notation or some other way like binary encoded decimal (two
digits in each byte ) ?

Thanks,

Andre W Nasser

      and we said...
see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c10datyp.htm#784
it is like a BCD.  It is never in "native" format.
June 02, 2001 --
      Thanks for the question regarding "Simple Pl/Sql question on Procedure",
      version 8.0.5

      You Asked
Im new to Pl/sql . How do I call a procedure to whom I pass an In & Out
variable.
For example:
my_procedure(ssn in, name out)

How would I execute such a procedure in Pl/SQL so that I can get the value of
name(above) out. Any help is greatly appreciated.

Thanks
Tans

      and we said...
declare
   l_name varchar2(100);
begin
   my_procedure( 123456789, l_name );
end;

will do it.  If you are actually asking "how do I test this in sqlplus" it would
be:

variable name varchar2(100)
set autoprint on
exec my_procedure( 123456789, :name );

Review &
      Followup

      Rating: 5
Report Call
      from Menu  June 03, 2001
Reviewer:  Manik Miah
      (manikmiah@yahoo.com)  from Bangladesh
Hi Tam

I could not call report from menu.
Please help me by giving some code.

Thank
manik

      Rating: 3
How can I write
      to new table  June 04, 2001
Reviewer:
      Nuray_u@hotmail.com  from Turkey
Hi Tom,
I have a table that is IKY_DIL_V. It is structure like so,
LOC_ID    EMP_NUM    SEGMENT1
21    8    ENG
21    8    FRAN
21    8    GER
21    2    ENG
21    2    GER
21    1    ARA
20    5    ENG
20    5    RAN
20    7    ENG
20    7    GER

I WANT TO ARRANGE  IT LIKE SO ( I want to write all knowledge to another table
that must be
like so)
IKY_TEMP -> Table name

LOC_ID    EMP_NUM    LANG1    LANG2    LANG3
21    8    ENG    FRAN    GER
21    2    ENG    GER
21    1    ARA
20    7    ENG    GER
20    5    FRAN    GER

Would you please explain me, how can I do.
I hope it is understandable what I mean
Thanks a lot
Nuray

      Rating:
      4
Thx  June 04, 2001
Reviewer:
      A reader
Thanks a lot.It really helped.

June 03, 2001 -- Thanks for the question regarding "Interval
      parameter for dbms_Job", version 8i

      You Asked
Hi Tom,

I need to run a bunch of reports using dbms_job pkg. These reports could be
asked by the user to be run every day at a certain time, or weekly , or yearly.
So the interval is not known.I will have to create a function to take care fo
this,....I am totally lost!!
Also the result set of the report has to be emailed to the user.How do I take
care of that too...Can you help me, Please...????

Thanks
Amy

      and we said...
If the job is to be run ONCE -- interval should be NULL.

If the job is to run weekly, say on MONDAYS, the interval could be:

    next_day( sysdate, 'MON' )

If the job is to run yearly, the interval could be

   add_months( sysdate, 12 )

You need to create a list of options for them, let them pick one and you have an
associated function that you really use.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:255615160805
for one method for sending email from the database.

This is a feature of Oracle Reports as well -- it has a scheduling facility as
as well email builtin, you'll get much much fancier reports from it.

June 03, 2001 ahmad -- Thanks for the question regarding
      "IOT's", version 8.1.5

      You Asked
Hi Tom;
When Should I use IOT:
1.when the data is less updated,and usually queried.
2.When Rows Are not too large.
3.When table is reasonable in size ,not too large.
If the third point is true then we have option to partition IOT and we usually
partition large tables, Am I right?
---
The Password of Sysdba is stored in the password file.
and any body who can loggin to operating system e.g Windows NT
can user orawpwd utility and change the password, Right?
If Yes any Solutions.
---

      and we said...
1) no, it is perfectly OK to have an active IOT.  You have indexes on tables you
modify lots don't you?  IOT's can be modified.  An IOT that has "keyword"
"document_id" "position" in it would be a perfect example.  Here the entire row
is the primary key.  Upon insert, you would have a trigger scan the document
looking for certain key words.  You would insert into the IOT all of the data.
If you used a "regular" table -- it would have the table PLUS an index that is
the same as the IOT. Here, the table would slow you down.

2) It is OK for the rows to be large - that is what the overflow is all about.

3) table size is not relevant.

The owapwd file is a file -- it should be protected like any other file.  Lets
put it this way.  If they can login and overwrite your password file -- they can
probably already CONNECT INTERNAL without a password -- they are using a
privileged account.  Now, if you let the permissions on that file be such that a
non-privileged user can overwrite it - thats upto you.

If they can log in as an account that can overwrite the orapwd file -- they
could just as easily steal all of your database files, restore them to another
machine and do whatever they like with it.

Protect your file system!


Subject | Article | Last Updated (East coast time)
nested table -- can it have more then one column? | article only | Jun 04, 2001 08:00 am
Find the Length of the Field | article only | Jun 04, 2001 08:15 am
Splitting an existing tablespace to more tablespaces across more disks | article only | Jun 04, 2001 08:19 am
Latches - what are they | article only | Jun 04, 2001 01:03 pm
Relation Of Database Time and Server Time | article only | Jun 04, 2001 01:16 pm
about local managed tablespace | article only | Jun 05, 2001 09:18 am
Refreshing data from one database to another | article only | Jun 05, 2001 12:28 pm
max_enabled_roles | article only | Jun 05, 2001 12:32 pm
system written data uppercase always? all_tab_columns.owner | article only | Jun 06, 2001 07:10 am
controlfile & logfile - recovery questions. | article only | Jun 06, 2001 09:14 am
indexes - del_fl_rows, multiblock IO, clustering factor questions | article only | Jun 06, 2001 09:48 am
8.1.5 Vs. 8.1.7 | article only | Jun 06, 2001 09:57 am
Stored Procedure accessing remote objects | article only | Jun 06, 2001 01:00 pm
pro*c --- tuning it. | article only | Jun 06, 2001 01:37 pm
using bind variables in the query | article only | Jun 06, 2001 09:47 pm
Compare 2 records | article only | Jun 07, 2001 09:41 pm
Oracle optimizer chooses a more expensive plan | article only | Jun 07, 2001 09:49 pm
Oracle Application Server Release 4.0.8.1.0 | article only | Jun 08, 2001 10:52 am
how can we pass multiple parameter in forms | article only | Jun 08, 2001 01:21 pm
TABLES CONTAINING BFILE | article only | Jun 09, 2001 11:17 am
row(s) 1 - 20 of 20
June 04, 2001 -- Thanks for the question regarding "nested table -- can it have more then one column?", version 8.1.7
You Asked
HI
Iam confused about a nested table.. can it contain only one column or can it
contain multiple columns.

Can you give a very simple example for a varray and  a nested table?

Thanks
and we said...
varray's and nested tables my either be simple scalar types (number, date,
string) or user defined object types.  The following example shows how to create
a nested table and or varray with more then one column:

tkyte@TKYTE816> create or replace type mySCALARtype
  2  as object
  3  ( x int,
  4    y date,
  5    z varchar2(20)
  6  )
  7  /
Type created.

tkyte@TKYTE816> create or replace type myTABLEtype
  2  as table of mySCALARtype
  3  /
Type created.

tkyte@TKYTE816> create or replace type myVARRAYtype
  2  as varray(20) of mySCALARtype
  3  /
Type created.

tkyte@TKYTE816> create table t ( a int, b myTABLEtype, c myVARRAYtype )
  2  nested table b store as b_tab
  3  /
Table created.
June 04, 2001 Periasamy -- Thanks for the question regarding "Find the Length of the Field", version 8.1.6
You Asked
Hi,

I want to get the maximum length of the varchar2, number fields.

i found in some documentations they asked me to use vsize to find the actual
length. but i tried, its return the same value of the command length returned.

thanks

Periasamy
and we said...
If it is a column in a database table -- you would select that information from
USER_TAB_COLUMNS.

If it is a variable in a PLSQL routine, there really isn't an effective way to
discover this at runtime other then to stuff various sized pieces of data in
there until you get a numeric/value error.
June 04, 2001 Dusan -- Thanks for the question regarding "Splitting an existing tablespace to more tablespaces across more disks", version 8.1.6
You Asked
Hi Tom,

While monitoring our production database, system operator found out that some
disks are pretty 'hot', i.e. a lot of i/o operations are performed on some disks
(u05, u09, see below). I got the following results:

select
substr(a.TABLESPACE_NAME,1,10) tblsp
,substr(a.FILE_NAME,1,35) file_name
,b.PHYRDS
,b.PHYWRTS
,b.MAXIORTM
,b.MAXIOWTM
from dba_data_files a,v$filestat b
where a.FILE_ID = b.FILE#
/
TBLSP      FILE_NAME                              PHYRDS   PHYWRTS  MAXIORTM
MAXIOWTM
---------- ----------------------------------- --------- --------- ---------
---------
...

D2_MP_DAT  /u05/oradata/D2/D2_MP_DAT_01.dbf       898664    184294       526
  121
D2_MP_DAT  /u05/oradata/D2/D2_MP_DAT_02.dbf      1127888    226937       538
  128
D2_MP_IDX  /u09/oradata/D2/D2_MP_IDX_02.dbf       168315    121755       134
   22
D2_MP_IDX  /u09/oradata/D2/D2_MP_IDX_01.dbf       143277     97921       183
   23
D2_REF_DAT /u04/oradata/D2/D2_REF_DAT_01.dbf        1709      5174       106
   97
D2_REF_IDX /u08/oradata/D2/D2_REF_IDX_01.dbf         996       949        16
  229

In tablespaces D2_MP_DAT, D2_MP_IDX (Locally managed, with uniform sizes!) we
hold the biggiest tables and their indexes.
The questions are:
1) If we create another tablespaces with db files on another disks, and move
some of our big 'busy' tables into this new tablespaces, will it help
(performance)?
2) Is there any possibility to find out (in some similar way as in the query
above) how 'busy' tables itself are?

Thanks a lot,

Dusan
and we said...
1) possibly, it is hard to say.  Are you measuring IO over a period of weeks,
hours, or days above.  Is that 1.1 million reads over a month (probably no
change in performance) or an hour (good chance of increased performance).

2) IO is tracked by file.  Since that tablespace (D2_MP_DAT) has 2 files, you
might be able to remove some tables from consideration (find the tables with NO
extents in D2_MP_DAT_02.dbf for example).

since it is pretty easy to move objects  via ALTER TABLE t MOVE and ALTER INDEX
i REBUILD, you have nothing to lose by trying.  Consider using a couple of
tablespaces in order to allow more fine grain analysis of object access in the
future.
Review & Followup
Rating: 3
Unless you are using a disk array June 04, 2001
Reviewer: Just Anothervoice from MI, USA
This is all fine and good unless the data is stored on some big (or not so big)
disk array.  Then things get quite complicated.  For example, if you had 96 48GB
disks mirrored they would yield about 2TB of available storage. Now if the disk
array presents those 2TB as 42 mount points -- 18 32GB, 12 48GB, and 12 96GB,
and we add in striping of say 16 KB, on which disk does your data reside.   You
can't tell for sure.  And with the read/write cache of the disk array does it
matter all that much?  Perhaps if the i/o were extremely heavily skewed it
might, otherwise???

Rating: 3
Regarding the comment ... June 05, 2001
Reviewer: JJ from South Africa
The whole idea behind using a disk array is that the striping and/or mirroring
will take care of spreading the I/O load across the disks. You would typically
expose the disk set as one mount point and at the file level, just put
everything on this one mount point. Let the hardware (or logical volume
software) do the load spreading for you.

Rating: 4
Regarding the "stripe and the world will be ok" comment June 05, 2001
Reviewer: Connor from UK
Blindly striping across all of the disks in the universe may give the appearance
of solving IO problems (and in some cases it does), but it still does not
guarantee to protect you from disk hotspots, and does not give great separation
from the different types of IO activity within Oracle.

June 04, 2001 Rajwinder -- Thanks for the question regarding "Latches - what are they", version 8.1.6.3
You Asked
Hi Tom

I Tried my Best but could not understand the concept of Latch.

Could u please explain me with few examples

What is a Latch
How is it created
What are its types
What sre its functions

And all the things Related to it....

Pl. try to give it with more of the examples.

Thanks/regards
Rajwinder
and we said...
A latch is a serialization mechanism.  In order to gain access to a shared data
structure, you must "latch" that structure.  that will prevent others from
modifying it while you are looking at it or modifying it your self.  It is a
programming tool.

A latch is a permanent thing in Oracle -- when the Oracle developers ship the
data, the entire universe of latches is known.  It is compiled into the
database.  The number of some latches vary - the types of latches are fixed into
the code itself.

There is one type of latch -- they are just a serialization device.  Many things
are PROTECTED by latches -- the library cache, the buffer cache, and so on.

Steve Adams (
http://www.ixora.com.au/home.htm
 has published a small book on this subject:
http://www.amazon.com/exec/obidos/ASIN/156592598X/qid=991674200/sr=1-1/ref=sc_b_1/002-1072204-1998410
if you are really curious, this will go further then you probably really want
to.
June 04, 2001 pudhp -- Thanks for the question regarding "Relation Of Database Time and Server Time", version 8.1.6.3
You Asked
Hi Tom

Pl.explain that what does the database time means.Is it picked everytime from
the server clock or does oracle runs it internally

In a scenerio Say

I have a database running on a server

  I shutdown the database
  Change the clock time of the server
  And start the database again

How will it effect the database (if it at all does.....)

Thanks/Regards
Pushp
and we said...
The database server uses an internal clock called the SCN (system change
number).  It does not rely on the system wall clock.

However.... if you try to do a time based point in time to 11am and 11am is one
of those overlapping times -- you'll recover to the FIRST 11am it finds.  You
would have to do a changed based (SCN based) recovery to go beyond the first
11am.

However.... If your application uses SYSDATE anywhere -- your application might
be logically messed up.  If you order by some timestamp, the results will be
affected by the set back -- just like they are during daylight savings in the
fall.
Review & Followup
Rating: 5
June 05, 2001
Reviewer: A reader
thanks so much for such a nice answer

June 05, 2001 Vincent -- Thanks for the question regarding "about local managed tablespace", version 8.1.5.
You Asked
Hi Tom,

I'd like to create a tablespace with NO FREE SPACE FRAGMENTATION.

1.
CREATE TABLESPACE "TABLESPACE_LOCAL"
    LOGGING
    DATAFILE 'data.ora'  SIZE 50M
    EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1024K

or

2.
CREATE TABLESPACE "TABLESPACE_DICT"
    LOGGING
    DATAFILE 'data.ora' SIZE 50M REUSE AUTOEXTEND ON
    NEXT  1024K MAXSIZE UNLIMITED DEFAULT
    STORAGE ( INITIAL 1024K NEXT 1024K MINEXTENTS 1 MAXEXTENTS
    UNLIMITED PCTINCREASE 0 )

A. So, what's the better solution (in OLTP AND DSS) , what's the faster?
B. IN case 1, is it interesting to have a big value for the "UNIFORM SIZE" ?
C. In case 1, is it a good solution to create a locally managed tablespace for
TEMP TABLESPACE ?
D. in case 1, if there are many writings into the tablespace => there are many
updates of bitmap index too,
        is there a risk of i/O contention ?

Thanks a lot

Vincent
and we said...
A) in 8i, i would strongly encourage the use of Locally managed tablespaces --
period.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:733126913855
btw: using case 2 I can still fragment your tablespace.  MY object storage
parameters override YOUR tablespace storage parameters.

B) It depends.  You might have a tablespace for

small objects (64k extents)

medium objects (1meg extents) -- good for objects upto a couple of hundred
megabytes (yes, it is OK to have HUNDREDS of extents)

large objects (Xmeg extents, based on your need)

really large objects (you decide)

C) they EXCELL as temporary tablespaces -- see link in A)

D) see link in A).  The bitmaps REDUCE contention for space management request
by de-serializing a serial operation AND making that operation blindingly fast.
Review & Followup
Rating: 5
June 05, 2001
Reviewer: Vincent

June 05, 2001 Sriram -- Thanks for the question regarding "Refreshing data from one database to another", version 8i
You Asked
Tom,

  We have a requirement to create a new database from the production database
for reporting purposes. The reporting database will contain subsets of
production data and needs to be refreshed on a daily basis.

We have two options.

Create materialized views in the reporting database using dblink and set them to
be refreshed automatically

Create a shell script with Export (using where clause) and import commands and
have it executed through cron periodically.

Is there any advantage/drawback to either of the approaches.

Thanks
and we said...
materialized views = less maintenance, only happens when database is up, errors
logged to the alert log and database tables.

exp/imp = you have to script it, you have to monitor it, it'll run whether or
not the database happens to be available, etc.

if you can do it in the database, do it in the database.
Review & Followup
Rating: 3
July 20, 2001
Reviewer: A reader

Rating: 3
July 20, 2001
Reviewer: Pichaimani Balasubramanian from San Jose, CA USA

June 05, 2001 -- Thanks for the question regarding "max_enabled_roles", version 8.0.5
You Asked
Hi Tom,

first my congratulation to your new book, I'll buy it as soon as possible.

Now I have two problems:

1- What is the default size of enabled_roles and when do I need to set    a
default role to a person or group?

2- Can I use "commit" in a trigger, if not how can I insert to many rows say
ca.500000 into a table without getting the error "snapshot too old" ?

Thanks a lot,
   Nick
and we said...
1) max_enabled_roles defaults to 20.

   as for when you NEED to set a default role to a person/group -- you never
NEED to, it is a matter of wanting to.

2) thats sort of funny in a way.

if you do "commit" in a trigger (you cannot commit the initiating transaction)
you would CAUSE the ora-1555.  The major CAUSE of 1555 is committing in a cursor
for loop as you would like to do.

You need to size your rollback appropriately or, since you are doing an INSERT,
use a direct load insert (coordinate with your DBA -- they'll need to backup
your tablespace right after this to protect it from media failure).
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c21dlins.htm#365
Review &
      Followup

      Rating: 5
Please do not
      use this to ask a question.  June 07, 2001

Reviewer:  Please do not use this to ask a question.

Please do not use this to ask a question.

June 06, 2001 Jeff -- Thanks for the question regarding "system
      written data uppercase always? all_tab_columns.owner", version 7.34,8.x

      You Asked
Greetings.

I was wondering, is the all_tab_columns.owner always upper case?
I had an application which had demonstrated some weird behavior that I tracked
down to it not finding a lower case owner. Of course I can change the compare to
ignore case, but I was wondering is it always upper case?

Is this generally true for system written data? All releases of Oracle?

Thanks
Jeff

      and we said...
All object names/identifiers are folded to UPPERCASE -- UNLESS they are quoted:

create table "t" ( x int );
create table t ( x int );

will create two tables -- t and T.

I would discourage the use of quoted identifiers.  they only lead to heartburn
and confusion.

followup to comment two

you would have to provide some context (like a link to an example).

I can imagine doing it to show someone how they could make a mixed case view of
a table that was in uppercase, to support an application that needed it -- but
not as a "standard operating procedure" sort of thing.

Review &
      Followup

      Rating: 5
thanks. This is
      useful.  June 05, 2001
Reviewer:  Jeff Kish
       from Grand Rapids, Michigan USA
Thanks.
 The recommendation is also appreciated.

      Rating: 5
Use of
      identifiers in Lower case  June 06, 2001
Reviewer:
      Your Fan  from Riyadh
Hi tom,
  Once you have used lowercase column names in creating a view and now you
discourage the use. Could you please explain in detail ?

The view is contained in the following question :

Question Id : 396618940119
Title       : Forms Matrix Style Form

Regards,

June 06, 2001 Anil -- Thanks for the question regarding
      "controlfile & logfile - recovery questions.", version 8.1.5

      You Asked
Hi tom,
   Here is the question for you ..

  My database is in ARCHIVELOG MODE

1)I have mirrored my controlfile to Two diff. location.If My control file is
Getting corrupted(both the file) how do I recover from this situation.Anything
which i have to do before itself,so that when it crases i can use that.Please
suggest some way.Database is in ARCHIVELOG MODE.

2)I HAVE THREE lOG GROUP,If My logfile is Getting Corrupted(assume all three)
when database was running and so many user connected to it.
what will happen to My archive file.I hope those files will also be
corrupted One ?? Now how do i Get My all three log file back ?? And
if those archive files were corrupted ,if I apply those archivefiles
in cash of crash,what will happen ??(because i will not be knowing which one is
correct archive & which one is corrupted One).
Can you Please explain above two points.

Regards
 Ak

      and we said...
suggest you read:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/toc.htm
from cover to cover.

for #1 specifically:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/recoscen.htm#11872
is the section entitled:
"Losing All Copies of the Current Control File"

for number two -- you really want to have 3 groups with at least 2 members each
to avoid this (multi-plex your REDO !!!).

if all of your online redo log files are lost for some reason, you will have
lost some of the work they contain.

Again,

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/recoscen.htm#15799
Recovering After the Loss of All Members of an Online Redo Log Group

covers the steps.

Review &
      Followup

      Rating: 3
Yes, I think it
      too necessary to read oracle document first  November 12,
      2002
Reviewer:  From East  from Beijing, China

June 06, 2001 -- Thanks for the question regarding "indexes -
      del_fl_rows, multiblock IO, clustering factor questions", version 8.1.7

      You Asked
1.Reading about when to drop indexes, I happened to read the following passage..

'You can run the 'ANALYZE INDEX VALIDATE STRUCTURE' command on the affected
indexes - each invocation of this command creates a single row in the
INDEX_STATS view. This row is overwritten by the next ANALYZE INDEX command, so
copy the contents of the view into a local table after each ANALYZE. The
'badness' of the index can then be judged by the ratio of 'DEL_LF_ROWS' to
'LF_ROWS'. '

Can you please discuss the basics relating to ' the ratio of del_lf_row to
lf_rows'.

2.How does an higher or lower value for DB_FILE_MULTIBLOCK_READ_COUNT  effect a
query performance. How would a query read multiple block with a single read.
What if I set it to a very high figure , so that all the blocks required by a
query are read in one read

3.
'USER_INDEXES.CLUSTERING_FACTOR - This defines how ordered the rows are in the
index. If CLUSTERING_FACTOR approaches the number of blocks in the table, the
rows are ordered. If it approaches the number of rows in the table, the rows are
randomly ordered. In such a case, it is unlikely that index entries in the same
leaf block will point to rows in the same data blocks. '

What does clustering factor mean?
what is the difference between the clustering factor approach the number of
blocks  in the table , and  number of rows in a table.

4.Can you name the v$views which are a must know, to do application tuning.. I
can think of one ..v$sqlarea what are the others

Thank you

      and we said...
1) if a high pct of the rows in the index are marked as deleted, it might be
time to rebuild.  This will happen for example if you create an index on a
column that gets its value from a sequence and you delete every other entry.
half of the index will be deleted entries that will never be reused (since a
sequence will never generate a number that will reuse these deleted slots)

2) that parameter affects only full table scans.  If you do indexed reads, it
does not come into play.  It is limited in size by various operating systems so
you might set it really high but we'll cap it at some value anyway.

again -- full table scans only benefit from this.

3) the clustering factor is a measure of how well the order of entries in the
index predicts the order of the data in the table.  Consider a table like this:

tkyte@TKYTE816> create table t ( x int, y int );
Table created.

tkyte@TKYTE816> insert into t
  2  select rownum, dbms_random.random
  3    from all_objects
  4   where rownum <= 5000
  5  /
5000 rows created.

tkyte@TKYTE816> exec show_space('T')
Free Blocks.............................4
Total Blocks............................64
Total Bytes.............................524288
Unused Blocks...........................48    <<<--- hence table has 15 blocks
Unused Bytes............................393216
Last Used Ext FileId....................6
Last Used Ext BlockId...................73
Last Used Block.........................16

PL/SQL procedure successfully completed.

tkyte@TKYTE816> create index t_idx1 on t(x);
Index created.

tkyte@TKYTE816> create index t_idx2 on t(y);
Index created.

tkyte@TKYTE816> analyze index t_idx1 compute statistics;
Index analyzed.

tkyte@TKYTE816> analyze index t_idx2 compute statistics;
Index analyzed.

tkyte@TKYTE816> select index_name, clustering_factor
  2    from user_indexes
  3   where index_name like 'T\_IDX%' escape '\'
  4  /

INDEX_NAME                     CLUSTERING_FACTOR
------------------------------ -----------------
T_IDX1                                        12
T_IDX2                                      4532

Now, since the table data is physically in order of X (rownum = 1, 2, 3, 4.... )
the first index on X has a clustering factor near the number of blocks in the
table.  That means if I do an index range scan on T_IDX1 and access say 10 rows
of the table via that index -- there is a VERY good chance that those ten rows
are on the same block (or on two adjacent blocks).

On the other hand, T_IDX2 which is on the random number, has a clustering factor
near the number of rows in the table.  If I do that same range scan for 10 rows
-- I will probably need to access 10 blocks, the index entries that are next to
eachother in the index all point to different blocks.

That means the optimizer will be more likely to use T_IDX1 in more cases for
larger index range scans then it would for T_IDX2.

5) there are about 17 of them I use on a frequent basis.  I actually spend time
documenting them and their usage in my book...

event_name, filestat/tempstat, lock, mystat, open_cursor, parameter, session,
session_event, session_longops, session_wait, sesstat, sess_io, sql, sqlarea,
statname, sysstat, system_event

are their names

June 06, 2001 Hemant -- Thanks for the question regarding
      "8.1.5 Vs. 8.1.7", version 8.1.5

      You Asked
Hi Tom,
I have a problem in executing an Oracle query.
My Oracle configuration is:
Oracle 8.1.7 on Windows 2000 Server.
My Query is:
DELETE FROM TB_TMP_QUEUE WHERE HOST = H AND KEYWORD = KEYWD AND TEMPID IN
(SELECT TEMPID FROM(SELECT TEMPID, CAMPID, KEYWORD, PRIORITY FROM TB_TMP_QUEUE
WHERE PRIORITY IN (SELECT MIN(PRIORITY) FROM TB_TMP_QUEUE) ORDER BY CAMPID)
WHERE ROWNUM <=1) ;

which is working fine.

The same query I want to run on
Oracle 8.1.5 on HP Unix Server.
When I run the query it gives me following error:

LINE/COL ERROR
-------- -----------------------------------------------------------------
107/302  PLS-00103: Encountered the symbol "ORDER" when expecting one of
         the following:
         ) with and or group having intersect minus start union where
         connect
         The symbol "group was inserted before "ORDER" to continue.

Is that a version problem or something wrong with installation on Unix?
Please Advise.

Hemant.

      and we said...
Oh, I see -- its in PLSQL.  PLSQL is the problem here.

Do this instead:

   execute immediate
       'DELETE FROM TB_TMP_QUEUE
         WHERE HOST = :h
           AND KEYWORD = :keyword
           AND TEMPID IN (SELECT TEMPID
                            FROM (SELECT TEMPID, CAMPID, KEYWORD, PRIORITY
                                    FROM TB_TMP_QUEUE
                                    WHERE PRIORITY IN
                                       (SELECT MIN(PRIORITY) FROM TB_TMP_QUEUE)
                                    ORDER BY CAMPID)
                            WHERE ROWNUM <=1)'
    using H, KEYWRD;

and that'll fix it right up.  The PLSQL parser did not understand the order by
in a subquery syntax in 8.1.5.  Using dynamic sql will avoid that issue.

Review &
      Followup

      Rating: 5
You Saved Me
      !!!  June 06, 2001
Reviewer:  Hemant
       from Dublin, Irelan
Dear Tom,
It would help me very much. I am very thankful to you for all these help.
Thanks very much.

June 06, 2001 Robert "Dale" -- Thanks for the question
      regarding "Stored Procedure accessing remote objects", version 8.1.6.0.0

      You Asked
Tom,

This expands on the authid question I asked of you a couple of days ago.

We have a Stored Procedure on instance A that was created using the default
authid=definer.  This procedure updates data in our datamart by pulling from our
data warehouse atomic layer on instance B and from our POS system in instance C.
 Instance A is version 8.1.6.0.0, instance B is version 8.0.6.1.0 and instance C
is version 8.0.6.2.0 if that matters.

We were hoping to provide access by granting privileges only to the owner of the
stored procedure on all 3 instances.  Is this possible?

      and we said...
depends on how the database link was created.

If the owner of the procedure creates a PRIVATE database link that includes its
username and password used to access instance A -- and the procedure references
this private database link, then YES -- the privs would goto the user associated
with the database link.  this is known as a proxy database link, when you use
it, it will use a consistent username/password.

If you create a database link and leave off the authentication credentials, then
the CURRENT USERS credentials are used (they are the only ones we have at that
time).
Review
      & Followup

      Rating:
      5
  June 06, 2001
Reviewer:  Dale Ware
       from St. Louis Mo.

June 06, 2001 -- Thanks for the question regarding "pro*c ---
      tuning it.", version 8.1.7

      You Asked
Tom

My manager has asked me if I can tune an application written in pro*c.

I have not written any pro*c code untill now.

But I understand that tuning the specific pro*c application will not include any
pro*c coding, I just need to look into the sql in the code.

I need to trace the sessions using this application and gather the performance
statistics for the sql.

Iam I right , the way Iam understanding it. Kindly advise.

I want to be careful before I accept the assignment.

Thank you

      and we said...
Well, one can write really bad C code.  If the performance problem is in the C
code (poor algorithms), you need to learn C.

If the performance problems lie in the SQL -- sql_trace,tkprof, timed_statistics
are all you need.

If the Pro*C program does lots of queries and does not use ARRAY fetches -- make
sure to check out the prefetch=NN precompile option!! It can dramatically speed
up pro*c code that does not array fetch programatically in 8i and up.
Review &
      Followup

      Rating:
      1
  June 07, 2001
Reviewer:  J.F.
      Guyard  from Switzerland

      Rating: 5
A very good
      idea I was not aware of...  September 15, 2001

Reviewer:  Harrison Picot  from Haymarket, VA USA
      "Hay capital of P.W. county"
I was surprised that anyone would rate this answer with one star; the question
is slight, and the answer is important, if you have heard of prefetch (as I had)
and are not aware of what it does (me again), this answer will point you in the
correct direction, and help you create high performance applications.  It is
hard to see how the answer could have been better, considering the limits of the
question. Anway, it has been a great help to me.

June 06, 2001 korada -- Thanks for the question regarding
      "using bind variables in the query", version 8.1.6

      You Asked
i read from lot of your answers, we must use
bind variables in the query instead of hard coding them, esp. in a loop.

even in a loop, if we hard code the same values also it runs slow,
consider the following ex:

for i in mycursor
loop
select * into rec from days
where day_type = '001'
and curr_date = i.date
end loop;

      and we said...
No, that is not a problem.  It is if you did something like:

for i in mycursor
loop
   execute immediate
   'select * from days where day_type = ''001''
    and curr_date = ''' || i.date || '''' into c1, c2, c3, ...;
end loop;

that would generate a unique sql statment for each iteration.

If you always use static SQL in plsql (your example) you will use bind variables
- plsql does it for you.  in your case, '001' would be a literal but the VARIANT
part of your query, i.date, will be a bind variable.

It is only with dynamic sql in plsql that you must concern yourself with
binding.  if you don't do dynamic sql and you only use plsql -- you will ALWAYS
be using bind variables as a matter of fact.

June 07, 2001 -- Thanks for the question regarding "Compare 2
      records", version 5.0

      You Asked
Is there anyway that I can compare 2 records in the same table or in different
tables of the same structure,
without a field by field compare. All I need is a boolean value back.

      and we said...
lets say you have the two primary keys in variables l_pk1 and l_pk2, you can
then:

   select count(*) into l_cnt
     from dual
    where exists ( select * from T1 where pk = l_pk1
                   intersect
                   select * from T2 where pk = l_pk2 );

if l_cnt = 1, you have a match, else you do not.

Assumes that T1 and T2 have the same columns in the SAME order.

followup to first comment below

that does not answer the persons question though.  That will simply tell you if
a table has dups.

they asked "how to compare 2 records in the same or different tables".

I only answer what is asked...

Review &
      Followup

      Rating:
      2
  June 07, 2001
Reviewer:
      A reader
But how to do if u want to find it in the same table.

I know some method but that takes in account the fields.
Like Let there be a table A with f1,f2 columns. Than this query will tell me if
there are records in the table which are same.
select count(*) from dual
where exists
(
select f1,f2,count(*) from A
group by f1,f2
having count(*) > 1
)

June 07, 2001 Pramod -- Thanks for the question regarding
      "Oracle optimizer chooses a more expensive plan", version 8.1.7.0.0

      You Asked
Tom,

We have a query which when explained chooses the plan with a higher cost.  See
below.  The plan chosen has a cost of 1706, however when we hint the optimizer
to perform a full table scan on a  particular table the cost is 1480.  It was my
understanding that the optimizer would always choose the plan with the least
expensive cost.  Can you please shed any light on why the optimizer would choose
the more expensive plan.  Please let me know if there is any other info
required.

PLAN CHOSEN BY OPTIMIZER
QUERY_PLAN
--------------------------------------------------------------------------------
 SELECT STATEMENT    Cost = 1706
   2.1 NESTED LOOPS
     3.1 NESTED LOOPS
       4.1 NESTED LOOPS
         5.1 HASH JOIN
           6.1 HASH JOIN
             7.1 TABLE ACCESS FULL SPLATE_TEMPLATE
             7.2 TABLE ACCESS FULL ASSAY_POOL
           6.2 TABLE ACCESS FULL SCREEN_RUN
         5.2 TABLE ACCESS BY INDEX ROWID INSTR_RESULT
           6.1 INDEX RANGE SCAN PK_INSTR_RESULT UNIQUE
       4.2 TABLE ACCESS BY INDEX ROWID SCREEN_PLATE
         5.1 INDEX RANGE SCAN XIE1SCREEN_PLATE NON-UNIQUE
     3.2 TABLE ACCESS BY GLOBAL INDEX ROWID SCREEN_WELL
       4.1 INDEX RANGE SCAN XIE1SCREEN_WELL NON-UNIQUE

QUERY_PLAN
--------------------------------------------------------------------------------
 SELECT STATEMENT    Cost = 1480
   2.1 NESTED LOOPS
     3.1 HASH JOIN
       4.1 NESTED LOOPS
         5.1 HASH JOIN
           6.1 HASH JOIN
             7.1 TABLE ACCESS FULL SPLATE_TEMPLATE
             7.2 TABLE ACCESS FULL ASSAY_POOL
           6.2 TABLE ACCESS FULL SCREEN_RUN
         5.2 TABLE ACCESS BY INDEX ROWID INSTR_RESULT
           6.1 INDEX RANGE SCAN PK_INSTR_RESULT UNIQUE
       4.2 TABLE ACCESS FULL SCREEN_PLATE
     3.2 TABLE ACCESS BY GLOBAL INDEX ROWID SCREEN_WELL
       4.1 INDEX RANGE SCAN XIE1SCREEN_WELL NON-UNIQUE

      and we said...
the cost of two queries cannot be compared.

The way the hint works is to artifically lower the cost associated with a step
in the query to make that plan more appealing to the optimizer.  It was the act
of you HINTING the query that artificially lowered the cost of a particular
plan, making that plan more appealing and hence "the plan".

followup to comment two below

Pramod,

your understanding is correct.

you wrote (i added the bolded text):

1)iterating throught the objects in the query

2)try different methods of access.

3)for each iteration calculate a resource cost based on avaiable statistics for
the objects in the catalog.  Hints will affect the costs associated with steps
- this is how hints work.  An INDEX hint will artificially lower the cost of
using that index and artificially inflate the costs of other access methods

4)once it completes all possible iterations(statisitcal permutations)choose the
plan with the lowest cost.

That is correct, thats what happens.  That is also why you cannot compare the
costs across executions.  Everything you do to change a plan influences the
costs associated with different steps.  The value assigned in step 3 is
comparable only to other query plans computed at the same time -- given the same
ENVIRONMENT.

by using hints, you changed the environment -- just like you might when
computing stats, changing the sort_area_size, and so on.

Review &
      Followup

      Rating: 4
Understanding
      how this works is really important  June 06, 2001

Reviewer:  Harrison  from Haymarket, VA USA

Understanding what a tool is doing is a lot better than
just seeing the numbers, as this example points out.
Almost every tool has some limitation, and knowing what
they are for the tools we use is important; knowing a few
tools well would seem to be better than getting tricked
by this kind of stuff.

      Rating: 3
Does the
      Optimizer consider every access option for every object for a Query
      Plan?  June 07, 2001
Reviewer:  Pramod
       from Phila Pa
Okay your point is that by hinting for the optimizer to do a full table scan we
changed the queries cost and the plan.  I have used hints extensively and I have
added hints that push the cost much higher(typically does not make the cost
less) and then run the query which actually runs faster.  In effect when you
give the optimizer a hint you are telling it you know better how to access the
paticular object(Maybe because the statisics collect for the objects are old or
not detailed enough).  I always have assumed that any hint that I give the
optimizer is going to cause the calculated resource cost for the query to be
higher then the resource cost the optimizer calculated for the query with no
hints.  I base my assumptions on how the cost based optimizer finds a plan for a
query which as I understand it is  on the Lowest Total Cost for the query.  I
assumed it calculates the lowest cost by using the following simplified
algorythm :

1)iterating throught the objects in the query
2)try different methods of access.
3)for each iteration calculate a resource cost based on avaiable statistics for
the objects in the catalog
4)once it completes all possible iterations(statisitcal permutations)choose the
plan with the lowest cost.

Is my understanding of how the cost based optimzer makes its choice of a queries
plan incorrect?

      Rating: 5
Thanks for the
      Futher Clarification..   June 08, 2001
Reviewer:
      Pramod
Tom,
Thank you very much for the further clarification on the cost based optimizers
interworkings with hints.. I completly understand your point now...  BTW I will
be purchasing your book from Amazon today... They are still listing at pre-order
status can't wait to get my copy...

June 08, 2001 Nikunj -- Thanks for the question regarding
      "Oracle Application Server Release 4.0.8.1.0", version 4.0.8.1.0

      You Asked
Hi tom,

I have Oracle Application Server Release  4.0.8.1.0 - Enterprise Edition.

I am using basic-Digest Authentication. There are more peoples are connecting at
the same time. How can i get list of people who at present connected.

I want to keep audit i.e. when he logon, when he logout e.t.c.  on user which
connecting through basic-Digest Authentication how can I keep this ?

how can i disble save password in ur password list, when user going to connect
using basic authonthication in internet explorer ?

Tia,
Nikunj.

      and we said...
I think you mean you are using BASIC authentication as DIGEST is a wholly
different method.

Anyway, with OAS -- it is stateless.  You are connected for the split instant
that you make the request and then you are not.  There is no such thing as "a
list of all connected users".  At a split instant in time you can see if there
are 5 cartridges being actively used but the second you look at it -- it is
stale data already.

There is no such thing as "logging out".  If I log in -- I can exit my browser
and an hour later start it backup and log in again.  You cannot tell that I am
logging in again -- the request to the app server looks no different from any
other request to it.  The app server cannot differentiate the first request a
user makes from the second.

You would have to write your own browser or mandate the use of a browser that
does not support that feature.  The browser implements this -- nothing to do
with the app server whatsoever.
Review &
      Followup

      Rating: 2
Use the
      database  June 11, 2001
Reviewer:  internet
      dude  from working
Use the database.  Create cookies that are created when someone signs in, add
that cookie to the database as well to track the user and have a trigger for the
login/logout functions on your website to destroy the cookie as well.

If the user simply "walks" away, setup a timeout on the cookie so the "session"
is lost.  If you integrate cookies within your applications and rdbms you can
query for active sessions based on who's cookie is active and you can also setup
events to make sure that only 1 person is active per ip address. this way if you
run a subscription service and 10 people are active with the same username on
different ip's you know something is wrong.. as some browsers on some os's will
open multiple connections anyhow so 5 sessions for the same ip address are not
uncommon

June 08, 2001 sadiq -- Thanks for the question regarding "how
      can we pass multiple parameter in forms", version forms 4.5

      You Asked
hello sir
i want to create a procedure as below
procedure fp_diable (x in block_name)
for i in 1..x.count loop
   set_block_property(block_name(i),insert_allowed,property_false);
   set_block_property(block_name(i),update_allowed,property_false);
end loop;

in when_button_pressed
i want
as below
fp_disable('control','master_block','detail_block');
and
in another
when_button_pressed
fp_disable('control','master_block','detail_block1','detail_block2');
can you please
give a solution for this

thanks
sadiq.n

      and we said...
does not work that way.

You could use a PLSQL table type

create package mytypes
as
  type array is table of varchar2(30) index by binary_integer;
end;

and then have code like:

declare
   data mytypes.array;
begin
   data(1) := 'control'; data(2) := 'master_block'; data(3) := 'detail_block';
   fp_disable( data );
end;
/

but it would probably be easier to just:

   fp_disable( 'control/master_block/detail_block' );

and code:

procedure fp_disable( x in varchar2 )
as
   l_data long default x || '/';
begin
   loop
      exit when l_data is null;
      set_block_property(substr(l_data,1,instr(l_data,'/')-1,
                                 insert_allowed,property_false);
      l_data := substr( l_data, instr(l_data,'/')+1 );
   end loop;
end;

June 09, 2001 mohammad -- Thanks for the question regarding
      "TABLES CONTAINING BFILE", version 8.1.6.0

      You Asked
I have created a table with a column data type as BFILE.
Now,while inserting values for this column I realised that the syntax of
inserting BFILE data is not known to me.

Would you please,tell me the  details with examples.

      and we said...
ops$tkyte@ORA8I.WORLD> create or replace directory my_files as '/tmp'
  2  /
Directory created.

ops$tkyte@ORA8I.WORLD> create table t ( x int, y bfile );
Table created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1, bfilename( 'MY_FILES', 'zz.sql'
) );

1 row created.

ops$tkyte@ORA8I.WORLD> select x, dbms_lob.getlength(y) from t;

         X DBMS_LOB.GETLENGTH(Y)
---------- ---------------------
         1                   116

ops$tkyte@ORA8I.WORLD>

Make sure to use UPPERCASE directory names in the bfilename() function!  it is
important (if you want it to work anyway)

followup to comment one

1) select * from dba_directories;

2)

  1  declare
  2     l_dir varchar2(255);
  3     l_name varchar2(255);
  4  begin
  5      for c in ( select * from t )
  6     loop
  7        dbms_lob.filegetname( c.y, l_dir, l_name );
  8        dbms_output.put_line( 'directory = ' || l_dir ||
                                             ' name = ' || l_name );
  9        for c2 in (select * from dba_directories where directory_name =
                                                                       l_dir )
 10        loop
 11           dbms_output.put_line( 'physical dir = ' || c2.DIRECTORY_PATH );
 12        end loop;
 13     end loop;
 14* end;
ops$tkyte@ORA8I.WORLD> /
directory = MY_FILES name = zz.sql
physical dir = /tmp

PL/SQL procedure successfully completed.

You could of course create a function to do this as well:

sys@ORA8I.WORLD> grant select on dba_directories to ops$tkyte;
Grant succeeded.

sys@ORA8I.WORLD> connect /

ops$tkyte@ORA8I.WORLD> create or replace function filename( p_bfile in bfile )
return varchar2
  2  as
  3     l_dir  varchar2(255);
  4     l_name varchar2(255);
  5
  6     l_return varchar2(1000);
  7  begin
  8      dbms_lob.filegetname( p_bfile, l_dir, l_name );
  9
 10          select directory_path || '/' || l_name into l_return
 11            from dba_directories
 12           where directory_name = l_dir;
 13
 14          return l_return;
 15  end;
 16  /

Function created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select x, filename( y ) from t;

         X
----------
FILENAME(Y)
---------------------------------------------------------------------------------
--------------------------------------------------
         1
/tmp/zz.sql

Review &
      Followup

      Rating: 3
thanks
        June 08, 2001
Reviewer:  mohammad toaha
       from Dubai,UAE.
I thank you very mucch for this.But I have still some questions whicch I intend
to ask by a separate question.The above gives me size of the field only.Whaat If
I want to know the following:

1.How to query the existing bfile directories in the database?
2.How to know the location of bfile in the operating system  by quering the
database tables?

      Rating: 4
Complete
      satisfaction  June 09, 2001
Reviewer:  mohammad
      toaha  from Dubai,UAE
Now,I have got the complete reply of what I wanted to know.

Thank you very much.

      Rating:
      3
good  July 07, 2001
Reviewer:  sk a
      samad  from hyderabad india
fine explanation


Subject | Article | Last Updated (East coast time)
ORA-01000: maximum open cursors exceeded | article only | Jun 14, 2001 08:12 am
long columns in partitioned tables | article only | Jun 14, 2001 08:14 am
Upgrade and Failover mechanism | article only | Jun 14, 2001 08:22 am
Export, CLOB display and datafile | article only | Jun 14, 2001 08:42 am
Performance when altering the table | article only | Jun 14, 2001 12:35 pm
How to use V$SESSION for validation | article only | Jun 14, 2001 12:46 pm
statspack | article only | Jun 14, 2001 04:16 pm
Turn off table logging + incremental export question | article only | Jun 14, 2001 04:25 pm
Table Sizing Guidelines | article only | Jun 15, 2001 09:29 am
apostophe in database " ' " | article only | Jun 15, 2001 09:35 am
diffrence between primary key and combination of unique and not null | article only | Jun 15, 2001 11:03 am
trapping windows NT login into a database column | article only | Jun 15, 2001 11:09 am
Several doubts | article only | Jun 16, 2001 02:22 pm
Possible arcane question on B*Tree indexes as Oracle sees them | article only | Jun 16, 2001 02:59 pm
regarding dba tables | article only | Jun 16, 2001 05:42 pm
Whether to have logic in java class or PL/SQL stored procedure? | article only | Jun 17, 2001 07:13 pm
row(s) 1 - 16 of 16
June 14, 2001 Azman -- Thanks for the question regarding "ORA-01000: maximum open cursors exceeded ", version 8.1.6
You Asked
Hi Tom,
I running Oracle 8.1.6 under Solaris 2.6.

We are using third-party application server and one common user-id to login to
the server. We currently encountering the above error messages and are having
difficulty in identifying the program that caused this.

Our open_cursors is set to 3000.

We know that the view v$open_cursor is helpful in listing out all the cursors,
however it also includes dynamic cursors PARSED and NOT CLOSED. So it is
difficult for us to track the actual curson that is sill open.

On the other hand v$sysstat where statistic# = 3 only provides the no. of
currently opened cursor.

Is there a script that can be run to determine how many open cursors
exist and which program is causing the open cursors?

Regards
and we said...
use v$sysstat to identify sessions with more then 2,900 open cursors -- then,
since you have that sid, you can goto v$open_cursor and see the cursors.  You
KNOW that 2900 of the 3000 they have in there are OPEN cursors -- the fact that
100 of them might be logically closed in the application isn't relevant anymore
-- you can see the 2900 that are OPENED in the application (that the application
is "leaking")

followup to comment one below

correct -- that was a typo.  should be V$SESSTAT to get the session level counts
of open cursors.  thanks.
Review & Followup
Rating: 2
ORA-01000: maximum open cursors exceeded June 11, 2001
Reviewer: Prince Kumar from CA, USA
Souldn't it be v$sesstat, instead of v$sysstat?

June 14, 2001 -- Thanks for the question regarding "long columns in partitioned tables", version 8.1.7
You Asked
We have two history tables with long columns in it.
I read that we cant convert a table having a long column into a partition table.
Is this true?

If this is true, then how should I convert my history tables into
partitioned tables.

thank you
and we said...
LONGS and LONG RAWS are deprecated types, supported only for backwards
compatibility.

Suggest you take this oportunity to conver the LONGS into CLOBS using the
TO_LOB() SQL function (since you have to rebuild to partition an existing
table).

There are many things you cannot do with longs (this is just one of them).
CLOBS will serve you much better and can be partitioned.

followup to comment one below

using the search tab on this site.  put in clob.  you'll see lots of examples.
Review & Followup
Rating: 2
CLOB June 10, 2001
Reviewer: toaha from Dubai,UAE
Would you please describe in details all about CLOB data type including creating
a table and inserting data into the table by examples.

June 14, 2001 Sulueti -- Thanks for the question regarding "Upgrade and Failover mechanism", version 7.3.2.3
You Asked
First of all I would like to say that your answers have been very informative
and useful - Thank you!

We are trying to plan our upgrade (planned for August - we would like to go up
to 8.1.6 or 8.1.7) process and at the same time, implement a failover mechanism.
Because of money constraints, our best failover option is to make copies of our
PROD environment daily and re-create it in the new machine which will be located
elsewhere. For this to work I'm assuming that both machines should be on the
same Oracle version. Am I correct?

Now our RDBMS (currently) is on 7.3.2.3, Alpha OVMS7.1-2 and running a
client/server and terminal server Forms45 (Dev1.6.1) application. The new
machine will be Alpha OVMS7.2, Oracle RDBMS? (we are trying to decide), Dev1.6.1
(in case we use this machine as development one).

The other option is to export the database and import to a different version of
Oracle.

What would you recommend as the best way to go? and what would be the
implications?

thank you very much for your help
Sulu
and we said...
I would recommend a standby database - most like option #1 above.  yes the
systems have to be homogenous (same hardware types).

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76995/toc.htm
for details.
June 14, 2001 Vladimir -- Thanks for the question regarding "Export, CLOB display and datafile", version 8i (release 8.1.7)
You Asked
Hi Tom,
Thanks one more time for your help, I have some questions:
a) I have a table T1 with A column define like CLOB, I means:
table T1:
text_id number(5)
text_name varchar2(12)
text_narr clob
I would like to know how to display the content of text_narr column using
servlet or jsp and with PL/SQL, it is possible?

b) I've a user U1 defined with default tablespace TB1, and tables T1, T2, T3
(table T1 is describe before with CLOB column), then I make a export without
problem, then I made a import in another database, in another user U2 with
default tablespace TB2 but I get a problem with table T1 (contain CLOB column)
that said does not exist tablespace T1 (ORA-00959), with the others tables T2
and T3 is not a problem to import on user U2(T3 and T2 doesn't have CLOB
columns), if I create a tablespace TB2 a define like a default for user U2 a
then repeat the import in that case I don't have any problems!!, is that the
solutions create a tables TB1 for user U2?, what happens when export tables with
CLOB columns?

c) I have a DB in noarchive log mode, accidently I create a datafile XX.ORA
instead XX.DBF, how I can to rename XX.ORA datafile to XX.DBF when the DB is
mounted? or how I can do it?, I try to rename using OEM but i get this message:
ORA-01511: error in renaming log/data files
ORA-01121: cannot rename database file 10 - file is in use or recovery
ORA-01110: data file 10:'H:\oracle\oradata\dbdev\XX.ora'
In which mode must be DB in open, nomount or mount to rename datafile?
How I can to rename to XX.DBF?

Thanks and regards

Vlad
and we said...
a) with a servlet or jsp -- just fetch the data and print it.  It would be NO
different then showing the end user the TEXT_NAME field.

search for

java clob

on my site if you don't know how to fetch a clob in java.  In PLSQL -- it is
really easy using the mod_plsql module with apach (or the plsql cartridge with
oas)

   select text_narr into l_var from t where text_id = some_parameter;
   l_len := dbms_lob.getlength(l_var);
   l_offset := 1;
   while ( l_offset < l_len )
   loop
      htp.prn( dbms_lob.substr( l_var, 32000, l_offset ) );
      l_offset := l_offset + 32000;
   end loop;

b) This is an issue with multi-tablespace objects like tables with clobs,
partitioned tables, iot's with overflows and so on.

You need to pre-create the object.  What you can do is this:

imp userid=u1/u1 tables=T1 rows=n indexfile=T1.SQL

that'll give you the full SQL to create T1 in the file T1.SQL (it'll NOT import
or do anything in the database -- totally SAFE in that regards).

Edit that file, fix up the tablespaces to be where you want them to be and run
T1.SQL as U2.  Run only the create table (or whatever sql you want)

Do the import with IGNORE=Y enabled.

c) alter tablespace <TABLE SPACE THAT CONTAINS XX.ORA> offline;
   alter database rename file 'xx.ora' to 'xx.dbf';
   alter tablespace <table space....> online;
June 14, 2001 partha -- Thanks for the question regarding "Performance when altering the table", version 8.1.6
You Asked
I have a table with 300,000 Records, when i alter the table it takes more than
three hours, could you please any hint or tip to reduce the time when i alter
the table.

Clues: 1) No concurrent Users, during the time of alteration
2)i'm adding a new column to the table

Thanks in Advance.

Partha
and we said...
are you adding with a DEFAULT clause which would tend to rewrite the entire
table, causing most all rows to migrate to new blocks and generally totally
messing up the existing table?

consider (t has 700k+ rows)

tkyte@TKYTE816> set timing on
tkyte@TKYTE816> alter table t add x date;
Table altered.
Elapsed: 00:00:00.70

tkyte@TKYTE816> alter table t add y date default sysdate;
Table altered.
Elapsed: 00:02:171.57

given that the alter generates redo as well -- I had an "archival required,
cannot allocate new log" due to this process as well.

The alter without the default was fast.

Three hours seems extreme but as each block was rewritten and depending on your
pctfree/used settings -- perhaps each row is now migrated.... I'll bet your
alert log has lots of "checkpoint not complete" messages as well.

Perhaps a better approach would be a CREATE TABLE AS SELECT with the
unrecoverable clause in the future to add a column with a default.
Review & Followup
Rating: 5
Altering Large Table and Performance issue June 14, 2001
Reviewer: Partha from USA
It was really helpful, and it is a very good hint for DBA's

Rating: 5
Excellent August 03, 2001
Reviewer: Gururaj Kulkarni from Norcross,GA USA

June 14, 2001 Gururaj -- Thanks for the question regarding "How to use V$SESSION for validation", version 7.X/8.X
You Asked
Hi Tom,

While answering to the question "do i need to hardcode password inside the
program? " ,you have said as following,

" Well, we'll just have our procedure query v$session for the
program --if the program is not myapp.exe, we'll not turn it on.  Ok,
I'll just copy sqlplus.exe to myapp.exe -- now I'll apear to be your
application. "

I am curious to know how can I use v$session to do this. Could you
give me an example ?

Thanks
Gururaj
and we said...
tkyte@TKYTE816> select program from v$session where sid = ( select sid from
v$mystat where rownum = 1 );

PROGRAM
----------------------------------------------------------------
SQLPLUS.EXE

that shows the name of the program (as the program reports it) for your session.

but as I said - its totally flaky:

tkyte@TKYTE816> host

Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-1999 Microsoft Corp.

C:\Documents and Settings\Thomas Kyte\Desktop>xcopy \oracle\bin\sqlplus.exe
myapp.exe

1 File(s) copied

C:\Documents and Settings\Thomas Kyte\Desktop>.\myapp.exe

SQL*Plus: Release 8.1.6.0.0 - Production on Thu Jun 14 12:49:48 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Enter user-name: tkyte/tkyte

Connected to:
Oracle8i Enterprise Edition Release 8.1.6.0.0 - Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production

tkyte@TKYTE816> select program from v$session where sid = ( select sid from
v$mystat where rownum =
1 );

PROGRAM
----------------------------------------------------------------
myapp.exe

don't use it for security.
Review & Followup
Rating: 3
Quick reply June 15, 2001
Reviewer: Gururaj from GA USA
Thanks for your detailed and quick reply Tom. Yeah I will
not use this for security.

June 14, 2001 -- Thanks for the question regarding "statspack", version 8.1.6.3
You Asked
i am trying to run the stats pack scripts but i am getting an error
create view           X_$KCBFWAIT as select * from  X$KCBFWAIT
                      *
ERROR at line 1:
ORA-00955: name is already used by an existing object

my question is why wouldn't they first create the user so he would
have his own schema and then create tables into his schema

can i just go ahead and take that peace of code (that creates these
views) and paste it after the code that create the user

it wouldn't harm for gathering the snapshots afterwards

thank you
and we said...
You are running the installation for the second time -- you've already run it at
least partially and either forgot you did so (or someone else did) or it aborted
for some reason part way through.

Simply run:

$ORACLE_HOME/rdbms/admin/statsdrp.sql

in 8.1.6 or spdrop.sql in 8.1.7

then you can run the create script again.

the script DOES create the user and create the objects in their schema -- you
have just run it more then once.
June 14, 2001 Alexei -- Thanks for the question regarding "Turn off table logging + incremental export question", version 8i
You Asked
Q1.
My boss is a MS SQL Server guru. But now we're developing Oracle project and
sometimes we've to compare SQL Server vs. Oracle. (again :))
He was really suprised when I've told that Oracle doesn't permit to turn off
logging completely.
He says it is a piece of cake in SQL Server just by truncating database
transaction log on checpoint.
My question is:
For example we have 2 kinds of tables:
1. High activity tables insert/update/delete holding some temporary data
2. Low activity tables holding mostly selected data

Is it possible to reduce log activity for temporary data?
I'd love to use GLOBAL TEMPORARY tables which significantly reduce redo log
activity... in that case users can see thier own rows only but that is not
acceptable.
What is the solution?

Q2.
Does Oracle incrementally export only rows changed since last export or it just
keeps the records on tables which changed since last export?
Will it fully export those changed tables next tim?

Thank you in advance.
and we said...
q1 -- that DOES NOT DISABLE LOGGING IN MICROSOFT.

That setting is 100% equivalent to our NO ARCHIVE LOG MODE -- period.  It simply
"truncates the log" (resets the log).  It never prevented it from being written
to in the first place!!!! (if it did -- why truncate it -- there would be
NOTHING in it would there!)

If the temporary data is temporary based on a SESSION (eg: its for a session)
then yes, use a temporary table.

Else no.  As you stated -- it is no.

But, as I said -- it was happening this way in MS -- believe me.  MS logs just
like we log.  The temporary tables are not logged but then again, changes to our
temporary tables aren't either.

q2 - incremental exports get the TABLES (all of the data) since the last change.
 I believe you want to use RMAN to get incremental backups (and please remember
that exp is NOT a backup tool, not today anyway)
Review & Followup
Rating: 3
Thank you for help :) June 18, 2001
Reviewer: Alexei Inozemtsev from Taganrog, Russia

June 15, 2001 Anirban -- Thanks for the question regarding "Table Sizing Guidelines", version 8.0.5
You Asked
Are there readily available guidelines to size database tables, assuming I know
the growth pattern, updates vs inserts vs deletes etc?
Im am interested particularly in deriving PCTFREE and PCTUSED.
A excel like spreadsheet would be ideal, where I input some of the
known metrics and it computes the rest.

Thanks
and we said...
Really not possible using a spreadsheet or any sort of formula.  Oh, there are
formula's that try but due to the fact that:

o 999999999 takes three times the storage 10000000000000000000000
o indexes can be key compressed
o free space might not be used within a transaction but across transactions it
  would be
o an IOT stores things very differently then a HEAP table.
o (any one of a thousand things)

The only way I know to accurately size a table and related structures is to load
it on your system with data that is REPRESENTATIVE of the actual data you will
be using.  You don't have to load 100% of the data, anywhere from a fraction of
1% to 10% of the data (depending on the table size itself -- the bigger they are
the less you need to sample percentage wise).  Then you analyze the table and
multiply.  That'll give you your initial sizing.

As for pctfree and pctused -- they are a soft function of HOW you use the data
-- there is no spreadsheet possible for them at all, not even a function.  You
set pctfree and pctused based on how the data will be manipulated.  Some very
very generalized rules of thumb might be:

o if you load a table and never update a row and never delete any rows  the
pctfree = 0 pctused = 1.  pctfree = 0 because ROWS NEVER GROW, hence you want to
pack the block all the way up.  do not save any space for update.  pctused = 1
because you really don't care what it is in this case.  You never delete only
add. When the block gets full it will be taken off of the free list (pctfree
hit) and will never go back on (since you never delete)

o if you load a table with lots of rows at a point in time and expect that on
average the rows will DOUBLE in size and you never delete you would set pctfree
at say 55%.  Now 55% of the block will be reserved for those updates.  pctused
is not relevant since once a block is half full, we want to reserve the rest of
the space for updates so set pctused to 1 (block must be 99% empty to be a
candidate for insertion)

o if you have no idea how the rows are going to grow and shrink over time, what
effects deletes will have and so on, you would just leave then default and hope
for the best.

and so on.  Basically, you must take an understand of what pctfree and pctused
do and see how they apply to YOUR data and the way YOU will be using your data.
There are no forumlas for these.

Followup to the comment below regarding "...sometimes cause delays in projects
like ...".

Let me rephrase it this way -- if you cannot come up with a small set of data
that represents some percentage of the entire data set (representative set of
numeric data for a field, varchars that represent how the actual data will be
used and so on) at this point in time -- it does not MATTER what sizing you use,
they will all be meaningless.

If you are going to a customer to tell them to buy such and such an amount of
hardware and you do not know what the data is going to look like, the only thing
you can do is give them the WRONG answer.

If you understand the data (a prerequisite for sizing), all you need is an
Oracle instance somewhere with the appropriate block size you plan on using.
Load it up with sample data and size it.  You do not have to do it on their
hardware, you just need to do it somewhere - and if you cannot do it, you could
not size this with a formula either.  That is because the only reason you could
not do this is due to lack of knowledge of what the data looks like.

followup to comment 4 below

that is exactly the problem -- each DBA has their OWN spreadsheet with different
ways of calculating values based on THEIR installation and their PAST experience
with THEIR applications.

There is no generic solution to this.  If the DBA switched jobs to a different
company with a different set of applications -- they might as well through out
their spreadsheets (they will have to modify them greatly at the very least).
Review & Followup
Rating: 3
March 26, 2001
Reviewer: A reader

Rating: 3
March 28, 2001
Reviewer: Eric Grancher from CERN

Rating: 3
Table Sizing March 30, 2001
Reviewer: Sudip Sarkar from PricewaterHouseCoopers from India
BEfore loading the dat into the database then to determine the sizing sometimes
cause delays in projects like when the clients wants to order the h/w after the
sizing is done.

Rating: 2
June 15, 2001
Reviewer: reader
I believe each of DBA has his own set of formula (either spreadsheet or
programs), even though PCTUSED, PCTFREE are variables.

Rating: 5
From DBA who does not use spreadsheet June 15, 2001
Reviewer: Dusan from MA
I agree that the best way for table sizing is just populating of the table with
sample data.
When using localy managed tablespaces (LMT) with uniform sizes, the whole issue
(after identifying how 'big' the table really is) is simple - take decision to
which tablespace put the table (index). To the 'small', 'medium' or 'big'
tablespace. Thanks procedure show_space and LMT strategy, I calculated very
precisely space needed for tables, indexes and tablespaces, and then rebuilt
production database (saving a lot of GB!). The only inputs were number of rows
and the real size of table or index, investigated by show_space.

Rating: 5
From DBA who does not use spreadsheet June 15, 2001
Reviewer: Dusan from MA
I agree that the best way for table sizing is just populating of the table with
sample data.
When using localy managed tablespaces (LMT) with uniform sizes, the whole issue
(after identifying how 'big' the table really is) is simple - take decision to
which tablespace put the table (index). To the 'small', 'medium' or 'big'
tablespace. Thanks procedure show_space and LMT strategy, I calculated very
precisely space needed for tables, indexes and tablespaces, and then rebuilt
production database (saving a lot of GB!). The only inputs were number of rows
and the real size of table or index, investigated by show_space.

Rating: 4
Table Sizing August 30, 2001
Reviewer: Jim Kirsch from Alexandria, VA USA
Good, clear advice about the importance knowing the data before sizing.

Rating: 5
hi folks December 30, 2002
Reviewer: A reader
Is there any utility or program which will populate sample data, by inspecting
the tables.

Thanks

June 15, 2001 venus -- Thanks for the question regarding "apostophe in database " ' "", version 8.0.5
You Asked
Tom

when i insert (apostophe data )e.g  patty's in the column.
it is inserted as patty?s. I mean to say ' is replaced with ?.
can u clarify this.Hope i have provided enough details.any solution.

Venus
and we said...
if you are writing a program -- you must use bind variables ( for performance
and scalability and to avoid this issue).

you would prepare and execute:

    insert into t values ( :x );

NOT
    insert into t values ( 'some string' );

if you are just in sqlplus doing an occasional insert, you will use two quotes:

   insert into t values ( 'patty''s' );
June 15, 2001 suresh -- Thanks for the question regarding "diffrence between primary key and combination of unique and not null", version 8.0
You Asked
hello sir
I would like to know the
diffrence between primary key and combination of unique and not null
and we said...
Semantics.

A primary key SAYS something -- it says "hey, I'm the primary key".

A unique+not null constraint doesn't say that.

If you have a primary key, you don't need to list the columns (or even specify
the datatypes!) in the create table statement for the child table, for example:

ops$tkyte@ORA8I.WORLD> create table p ( x int primary key );

Table created.

ops$tkyte@ORA8I.WORLD> create table c ( a references p );

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> drop table c;

Table dropped.

ops$tkyte@ORA8I.WORLD> drop table p;

Table dropped.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create table p ( x int unique not null );

Table created.

ops$tkyte@ORA8I.WORLD> create table c ( a references p );
create table c ( a references p )
                              *
ERROR at line 1:
ORA-02268: referenced table does not have a primary key

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create table c ( a INT references p(X) );

Table created.
Review & Followup
Rating: 3
USE FUL June 16, 2001
Reviewer: RAMANA from HYD, INDIA
Way of explanation is very good

Rating: 4
June 17, 2001
Reviewer: Sean from Atlanta
Very insidefull.

June 15, 2001 sadiq -- Thanks for the question regarding "trapping windows NT login into a database column", version 8.0
You Asked
hello sir
how to trapp NT user name in database column
example
when_button_pressed
i want to store the NT username in a textfield and later it has to be stored in
a database column when i save the record
many many thanks

question 2
sir
i want to display a LOV initialy with 2 columns (table 1)
example    part_no,part_desc
later in another textfiedd
i want to use same LOV with 3 columns
example
          item_code,vendor_code,vendor_name (table 2)
thanks
and we said...
1)

select osuser
  from v$session
 where sid = ( select sid from v$mystat where rownum = 1 );

will get that.  you'll need select on SYS.V_$SESSION and SYS.V_$MYSTAT.
Optionally -- your dba can set that query up as a view and grant you select on
that.

2) you use 2 lovs for that.
Review & Followup
Rating: 5
Melvin Mathias June 18, 2001
Reviewer: MELVIN MATHIAS from UK
Tom this query was very useful but I have a small doubt how do I get the I.P
address of the machine in my database.

Rating: 5
Just what I wanted June 25, 2001
Reviewer: SC from Chichester, UK
Been looking for this for ages, couldn't work it out myself.  Worked spot on,
and boosts the capabilities of my auditing triggers tremendously.  Thanks heaps!

June 16, 2001 Guru -- Thanks for the question regarding "Several doubts", version 8i
You Asked
Hai Tom,

   I have several questions for you.

1) If a table is locked is there any way to know whether it is locked or not.
In our application a pro*C program will be inserting rows in a particular table
& we don't want the user to open the form which is based on the same table.

2) I had read in forms help guide that for all base table blocks deletes are
applied first then inserts & then updates.  I think internally it does in this
sequence.  Please explain me or suggest me some documentation where i can get
the information about this.

3) I have a table ex: emp & i want to create another table (emp1) which has the
same structure as emp but emp1 shoud not get populated with the data in the emp.

4) I have a query to retrieve even numbered rows in a table.  But i am not able
to understand how it is working.  I got the query from my friend.  Kindly
explain me.
   The query is
   select * from emp where (rowid, rownum) in (select (rowid, (rownum/2) from
emp b)
   As far as my knowledge goes the rownum gets assigned only after the query is
executed.  But in the above query the rownum is used in the sub query.  I tried
by replacing rowid with empno or ename or any column in emp table.  It does't
work.  Kindly explain how it works.

5) What is the difference between the following 2 statements used in a procedure
or function.
   a) i number default 1;
   b) j number := 1;
   In case of (a) does the function retain the latest value of i if the function
is called recursively in a session.

6) Our application is running on forms server which is installed on Unix.  For
duplication checking i was creating a record group dynamically by calling pl/sql
library function.  Because the coding is little bit difficult for it i have
changed the checking for duplication by populating the values in a pl/sql table.
 Is there any advantage of using record group (because it is a form object) than
using pl/sql table.

   Sorry I think i have asked lot of question.  You were not available for past
some days.  So the questions have i increased.

Thanking You,
Guru Prasad
and we said...
1) well, locks are transient in nature -- lets say we check and the table is not
locked, that does not mean that by the time the form starts the table will STILL
not be locked.

In any case, look in V$LOCK for a type='TM' lock where id1 = the object ID of
the table in question.  The lmode column will tell you if the table is locked
in:

 0, 'None',           /* Mon Lock equivalent */
 1, 'Null',           /* N */
 2, 'Row-S (SS)',     /* L */
 3, 'Row-X (SX)',     /* R */
 4, 'Share',          /* S */
 5, 'S/Row-X (SSX)',  /* C */
 6, 'Exclusive',      /* X */

3 and below will allow inserts by other sessions, 4 and above will not.

2)  create table t ( x int primary key );

create a default block on that.  run that form.  Insert the value 1 and save.

Now

o add a record with a value of 1
o delete the first record

save....  it works.  It MUST have done the delete first else it would have
errored out with duplicate key.

Now

o add a record with a value 2
o add a record with a value 3
o commit
o change record 3 to 2
o delete 2
o commit

it works. It MUST have done the delete first else.....

the documentation you have already tells you the truth.

3) create table emp1 as select * from emp where 1=0;

4) the subquery is run and generates a set of rowids, NUMBERs like:

rowid        rownum/2
--------    ------------
xxxx        .5
yyyy         1
zzzz         1.5
aaaa         2
bbbb         2.5
......

So, since rownum can never be .5, 1.5, 2.5 in any case - just ignore those, we
are left with:

yyyy         1
aaaa         2
......

it'll use that and get the row with rowid yyyy - the rownum for that is ONE so
it succeeds and rownum is incremented.  It gets the row with rowid aaaa -- that
rownum is OK as well so it keeps it.  and so on.

Since there is no such thing as "even or odd" rows -- you would be better off
using the SAMPLE builtin and getting a 50% random sample.  It would be faster as
well

5) the are the same.  := and default are interchangeable.

6) none that I am aware of.  the PLSQL table is a forms object as well -- forms
has a plsql runtime in it, unless the plsql table is in a package compiled into
the database that is.
June 16, 2001 Harrison -- Thanks for the question regarding "Possible arcane question on B*Tree indexes as Oracle sees them", version 8.1.7
You Asked
Hi Tom:

I just got a book on Oracle 8i Application Programming
and it seems to have some odd bits.  In a chapter "Database
Foundations", a B*Tree index is pictured as (I am just doing part):

                   Ivanov
                /          \
               /            \
         Gogi                  Karamazov
         Gorky                 Lemontov
         /                      /  \
        /                      /    \
 Adreev    Bulgakov       Leskov       Rasputin
 Belinsky  Chekhov        Lomonosov    Romanov
 Blok      Dostoevsky     Pushkin      Tchaikovsky

First, what may be a help to anyone else not familiar
with Oracle's B*Trees, it seems apparent that by using
blocks as nodes, there are many data elements (names) in
each node and not just one (as you might expect if you
are familiar with traditional C style B*Tree nodes).

What is still confusing, after you accept that there can be
many data elements in any node, is how Oracle knows which
pointer to follow next; in this example both the left and
right nodes below "Gogi" and "Gorky" have elements which
seem to be to the left of the parent node, and both of
the other two nodes at this level seem to contain data
that apparently would be to the right of their parent
node.

At the third level, does Oracle just do a brute force search,
and if you have a million records, would that not entail a
search of (at the third level) 250,000 records?  It seems
to me that even if many records exist in each node, there still
needs to be two L&R specific records that lead to data which is
greater or lessor than the indicators.

Other than that the concept of using a data block as a node is
interesting as it could return a complete index for a small table
in just a few blocks, so that later queries on different data would
be satisfied from the shared area.

Also, if you had the chance to read this book, what was your
favorite part?  Not that I won't read it all, I just like to
read the best parts first (actually, I might not read all of
any book; I was lying).

Last, your book reviews are valuable, I bought "Oracle8i Internal
Services" by Steve Adams and found it a good read (not everybody
that has a good idea can also write, but Steve can) and the modest
cost was welcome.  It has as much on diagnosis and tuning as it
does on understanding what we are diagnosing, so it is well
worth reading.

Thanks

Harrison
and we said...
They probably should have used a different diagram.  It seems to imply there are
two entries on a branch block -- there are dozens (or more) actually.  That
branch block with (gogol, gorky) would have MANY other entries pointing us to
the right place -- that block may point to andreev/belinsky/blok -- but the
entry on that branch block that did that pointing wasn't depicted.

Here is a tiny extract from my book from the chapter on indexes:

B*Tree, or what I call 'conventional', indexes are the most commonly used type
of indexing structure in the database. They are similar in implementation to a
binary search tree you might have learned about in a computer science course.
Their goal is to minimize the amount of time Oracle spends searching for data.
Loosely speaking, the structure might look like this, if you have an index on a
number column:

                              +---------------+
                              |  50 and less--|--------+
                       +------|--more than 50 |        |
                       |      +---------------+        |
                       |                               |
                       |                               |
                       |                               |
                +---------------+               +---------------+
          +-----|-->= 100       |               |  >40 to 50    |
          |     |  >90 to 100---|---+           |  >30 to 40    |
          |     |  >80 to 90    |   |       +---|-->20 to 30    |
          |     |  >70 to 80    |   |       |   |  >10 to 20----|---+
          |     |  >60 to 70    |   |       |   |  >0  to 10    |   |
          |     |  >50 to 60    |   |       |   |  less than 0  |   |
          |     +---------------+   |       |   +---------------+   |
          |                         |       |                       |
          |                         |       |                       |
          |                         |       |                       |
          |                         |       |                       |
+---------------+   +---------------+   +---------------+   +---------------+
| 101, rowid    |   | 91, rowid     |   | 21, rowid     |   | 11, rowid     |
| 102, rowid    |   | 92, rowid     |   | 22, rowid     |   | 12, rowid     |
| 103, rowid    |<->| 93, rowid     |<->| 23, rowid     |<->| 13, rowid     |
| 104, rowid    |   | 94, rowid     |   | 24, rowid     |   | 14, rowid     |
| ....          |   | ....          |   | ....          |   | ....          |
+---------------+   +---------------+   +---------------+   +---------------+

The lowest level blocks in the tree, called LEAF NODES, contain every indexed
key and a rowid (rid in the picture) that points to the row it is indexing. The
interior blocks, above the leaf nodes, are known as branch blocks. They are used
to navigate through the structure. For example, if we wanted to find the value
'42' in the index, we would start at the top of the tree and go to the right. We
would inspect that block and discover we needed to go to the block in the range
'less than 50 to 40'. This block would be the leaf block and would point us to
the rows that contained the number 42. It is interesting to note that the leaf
nodes of the index are actually a doubly linked list. Once we find out where to
'start' in the leaf nodes – once we have found that first 42 value – doing an
ordered scan (also known as an INDEX RANGE SCAN) of values is very easy. We
don’t have to navigate the structure any more, we just go forward through the
leaf nodes. That makes solving a predicate, such as the following, pretty
simple:

where x between 20 and 30

Oracle finds the first index block that contains 20 and then just walks
horizontally, through the linked list of leaf nodes until it finally hits a
value that is greater than 30.
---------------------------- end of quote ---------------------------------

Hopefully that is more clear.  Each branch block has a whole bunch of ranges on
it.  We navigate from branch to branch finding the right range.  Each range
points to the next block (either yet another branch block or a leaf node).

It is not a simple LEFT/RIGHT -- its an N-Way tree with each branch block
pointing to many other blocks).

I haven't actually read the book from start to finish myself (well, I definitely
did read chapter 16 since I wrote that one and chapter 8 which Sean Dillon who
works with me wrote).

I read it piecemeal as a technical reviewer and only read the first drafts ;)
It has be well recieved so far though

A book I highly recommend -- Practical Oracle8i by Jonathan Lewis.
Review & Followup
Rating: 5
June 18, 2001
Reviewer: Harrison Picot from Haymarket, VA USA

Rating: 5
March 02, 2002
Reviewer: Anantha from USA

Rating: 5
September 16, 2002
Reviewer: A reader

Rating: 5
September 16, 2002
Reviewer: Cvdeepak

Rating: 5
September 16, 2002
Reviewer: Cvdeepak

Rating: 5
B*Tree indexes as Oracle sees them October 28, 2003
Reviewer: Dinesh from Australia
Excellent! This is the best explanantion one can get on Index Structure

June 16, 2001 veerendra -- Thanks for the question regarding "regarding dba tables", version 7.3,8
You Asked
is it possible to view and modify the dba tables?
and we said...
view, sure.

modify -- via insert/update/delete -- no way.
          via create/alter/drop -- sure.

if you want to remove a row from DBA_OBJECTS, drop something.  Add a row, create
something.

the DBA_* views are built on top of the real data dictionary (obj$, uet$, fet$,
etc etc).  they are modified when you do DDL.
June 17, 2001 Anurag -- Thanks for the question regarding "Whether to have logic in java class or PL/SQL stored procedure?", version 8.1.6
You Asked
Hi Tom,

Please help me in this.

I am developing an application, which has a Search Screen. The Search screen has
12 textboxes & each textbox correspond to a column in more than one tables in
the Database. In order to optimize the Search, I have to dynamically build the
SQLs so that there are minimum number of joins.

Now I have two options:

(1)Write this logic for forming dynamic sql in a java class (to be kept on app
server) & then execute this sql.

(2)Pass the values entered by the user in the textboxes to a stored procedure as
parameters to a stored procedure & form the sql dynamically inside it.

Please help me in selecting the better one out of these two.

Thanks & Regards
and we said...
It is totally upto you in this particular case.  Both languages can do this --
in both cases Java will end up with a result set.

I will advise you to use bind variables!  Here Java might be at an advantage.
It'll be easier to bind to your dynamic statement using Java/JDBC then it is
with a ref cursor (since the number of binds is not known until run time).

You can do this in PLSQL as well either by issueing:

alter session set cursor_sharing=force;

before opening the ref cursor (that invokes the "auto binder" feature available
with 8.1.6 and up) or by using application contexts.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
for an example of the second method.


Subject | Article | Last Updated (East coast time)
Problem in Replication (multi-multimaster Configuration) | article only | Jun 18, 2001 07:26 am
Performance related | article only | Jun 18, 2001 12:50 pm
Increasing speed of SELECTs and INSERTS | article only | Jun 19, 2001 07:12 am
Loging Strategy | article only | Jun 19, 2001 08:53 am
Problem while computation on a character type field. | article only | Jun 19, 2001 08:58 am
dbms_job | article only | Jun 19, 2001 09:01 am
user defined push button Oracle Application Server Release 4.0.8.1.0 | article only | Jun 20, 2001 10:13 am
PL/SQL equivalent of unix sleep command. | article only | Jun 21, 2001 09:07 am
How can I create an index on Bfile column (not the content of that file) | article only | Jun 21, 2001 08:34 pm
One Question. | article only | Jun 22, 2001 10:11 am
Primary Key Constraint and Unique Key | article only | Jun 22, 2001 10:15 am
XML data type and VARCHAR2 | article only | Jun 22, 2001 01:39 pm
Want to display "*" for typed password | article only | Jun 22, 2001 01:57 pm
index -- read mostly database | article only | Jun 22, 2001 07:25 pm
Oas in Sun Solaris | article only | Jun 23, 2001 10:35 am
db block gets and consistent get | article only | Jun 23, 2001 10:46 am
Grant database object privileges to a user | article only | Jun 23, 2001 12:37 pm
How to run the OS script Through PL/SQL | article only | Jun 23, 2001 03:53 pm
Temporary Segment | article only | Jun 23, 2001 03:55 pm
Oracle9i | article only | Jun 23, 2001 04:02 pm
getting results with computed column | article only | Jun 23, 2001 04:25 pm
server manager won't run scripts | article only | Jun 24, 2001 09:59 am
using bulk binds | article only | Jun 24, 2001 03:29 pm
Grant Privileges to Users | article only | Jun 24, 2001 03:32 pm
'consistent gets' values of set autotrace on output | article only | Jun 24, 2001 03:37 pm
ROLL FORWARD??? | article only | Jun 24, 2001 03:40 pm
Operating System Script from plsql | article only | Jun 24, 2001 07:22 pm
row(s) 1 - 27 of 27
June 18, 2001 -- Thanks for the question regarding "Problem in Replication (multi-multimaster Configuration)", version 8.1.6
You Asked
hi tom,
i got some problem today,
i am stating the problem here.
i think u can suggest me in this regard.
i have two sites A, B
both the sites contains tables table1,table2
which are multi-master replicated.

in site A i have writen a trigger on table1 on insert to insert a new
row in
table2.

because table1,table2 are multi-multimaster configured sites A, B
should
reprasent same values all the times.

1. when i am inserting a new row in A site table1
trigger is getting fired and new row is getting inserted into table2.
site B is also reprasenting the same values as in
site A.

2 when i am inserting a new row in B site table1 that row is getting
propagated to Site A
and there my trigger is getting fired and inserting a new row in the
site A's
table2 BUT THIS NEW ROW IS NOT GETTING PROPAGATED TO SITE 'B'

pls, let me know what could be the reason.

Thanks in Advance.
and we said...
Easy.

Data that is replicated is not itself replicated.  Otherwise -- the data would
ping back and forth forever.

It is assumed that table2 at site B would make its OWN entry in table2.  Data
that is created during replication is not itself replicated -- in effect
"replication is disabled during a replication update".  Consider what would
happen otherwise.

Table1 at site A would be sent to table1 at site B which would send it back to
site A ......

We cannot tell the difference between a row that is being replicated and a row
that is created as a side effect of a row being replicated.

You should code ALL triggers such that they do not fire during replication -- if
they do, you undoubtably have an error in your logic.
Review & Followup
Rating: 2
not fully satisfied with the answer June 19, 2001
Reviewer: RAMANA from HYD, INDIA
1. "replication is disabled during a replication update".
i didn't understand this can u suggest me some site where i can have information
about this.

2. "You should code ALL triggers such that they do not fire during replication "
how to code triggers in this way can u suggest me some information for this.

3. in my problem i defined statement numbered 2 is my specific requirement who
can i do that.

pls help me in this,
thanks in advance,
ramana

June 18, 2001 Uday -- Thanks for the question regarding "Performance related", version 8i
You Asked
Hi Tom,

Which takes more time either the self join or the same condition being handled
programmatically. Its a master table and has at around 20-30 thousand records.

Thanks
uday.
and we said...
well, I would assume that you would be doing the "self join" query yourself,
once for each records...

It is my experience, time and time again, that if you can do it in a SINGLE sql
statement -- it'll be faster then any procedural code you yourself can write.

do it in one query.
June 19, 2001 Mark -- Thanks for the question regarding "Increasing speed of SELECTs and INSERTS", version 8.0.5
You Asked
Tom, I am an Oracle programmer who is trying to improve the performance of
existing packages and procedures.  One of these procedures uses a great number
of outer joins, and inserts to the database tables are done on a row-by-row
basis (ie. rather slow).

I am using Oracle 8.0.5.  Is there anything you could suggest to help speed up
the SELECT statement, and increase the speed into which the database tables are
filled.  I looked at some new features, however, they are only available with
Oracle 8.1.5.  Can you help with this?

Mark Barnes

P.S. I looked at creating a function that returns a PL/SQL table of values.
Would this work?  Please let me know.
and we said...
Outer joins are not inheritently slow - they can be blazingly fast.  They are
not evil.

You would use tkprof to identify the poor performing queries:
http://asktom.oracle.com/~tkyte/tkprof.html
then, tune them.

As always look at the logic, if you see alot of:

  for x in ( select .... )
  loop
        insert into t values ( x.a, x.b, x.c );
  end loop;

turn that into

  insert into t select ....;

It is almost certainly faster to do in on SQL statement what some people try to
do in procedural code.  It will also obviate the need for "bulk inserts" as it
is one call to the server.

Look at the queries that do outer joins, I find 9 times out of 10 -- they are
not needed.  I see this alot:

    select *
      from t1, t2
     where t1.x = t2.x(+)
       and t2.z > 55;

Well, that "t2.z > 55" means the outer join is not necessary, all you've done
there is preclude the optimizer from considering T2 as the driving table.  This
happens more often then you would think.

Don't return a table of values, return a ref cursor.  See
http://osi.oracle.com/~tkyte/ResultSets/index.html
June 19, 2001 Zahid -- Thanks for the question regarding "Loging Strategy", version 8
You Asked
I am designing Purchase software for our group of industrial companies. I have
to authenticate about 1000 different users. What may be the best strategy to
solve the authentication problem. Weather I must use the Oracle supplied Schema
Users or I must create my own tables to store the users and generate forms to
authenticate the users
> Users will perform Different Activities
> 1. Raise Indents
> 2. Approve , Cancel Indents
> 3. Generate Inquiries
> 4. Feed Rates
> 5. Generate Quotations
> 6. Approve, Cancel the Quotations
> 7. Generate Purchase Orders
>
> --
and we said...
it is a matter of opinion.

I myself prefer database users over "do it yourself" authentication as it

o allows me to use auditing
o "select user from dual" returns something meaningful
o i can use database roles effectively
o i don't have to worry about storing passwords and writing the code to manage
all of that.

others would sing the praises of "do it yourself".  I just disagree with that
approach in general.  It would take hundreds of thousands of users or other
extenuating circumstances before I consider alternative approaches.
Review & Followup
Rating: 5
Include a variety of users you want June 20, 2001
Reviewer: Juan C. from Colombia
In fact this is the better solution because allow create a lot of users and
minimize the administration and development for your application

June 19, 2001 Anand -- Thanks for the question regarding "Problem while computation on a character type field.", version Form 6i
You Asked
In a form in (Form 6i)
I have a text item: Named VALUE, Type CHAR, Width 4

I want to change its value, if the value entered in it less than 100 with its
existing value multiply by 25.4

If I will do it like
   :VALUE := VALUE*25.4;
Or Even
   :VALUE := TO_NUMBER(VALUE)*25.4;
Or Even
   :VALUE := TO_CHAR(TO_NUMBER(VALUE)*25.4,'9999');

It gives me error ORA : 06502 PL/SQL: numeric or value errorstring.

But I think I have assigned values correctly.

I have done it by this way :

DECLARE
  MTMP  NUMBER(4);

BEGIN
  MTMP   := :VALUE*25.4;
  :VALUE := MTMP;
END;

It works very fine.

But I have not yet cleared whats the problem in my above statements.

Thanks

Anand
and we said...
you need a char(5) to hold the number 2514 (which is trunc(99*25.4))

There is a leading space for the sign digit.

tkyte@TKYTE816> l
  1  select TO_CHAR(77*25.4,'9999') ,
  2         length( TO_CHAR(77*25.4,'9999') )
  3*   from dual
tkyte@TKYTE816> /

TO_CH LENGTH(TO_CHAR(77*25.4,'9999'))
----- -------------------------------
 1956                               5
June 19, 2001 Bhagat -- Thanks for the question regarding "dbms_job", version oracle 816
You Asked
Hi Tom,

How r you tom my question is can i run scheduler dbms_job at the time interval
of 1 second if yes then how or is there any limitation on this please tell

Regards
Bhagat Singh
and we said...
yes you can but you probably do not WANT to.

you would set the job queue internal to 1.

You will see it doing more work then you probably want to.

A case of "yes you can, but don't".

If you need something to do something every second, probably better to run a
PERSISTANT job that does;

   dbms_alert.register( 'KILL_JOB' );
   loop
      my_procedure;
      dbms_alert.waitone( 'KILL_JOB', msg, status, 1 );
      exit when status = 0;
   end loop;
   dbms_alert.removeall;

that'll run my_procedure every second until someone issues:

  exec dbms_alert.signal( 'KILL_JOB', '' );

(that lets you shutdown cleanly)
June 20, 2001 Nikunj -- Thanks for the question regarding "user defined push button Oracle Application Server Release 4.0.8.1.0", version 4.0.8.1.0
You Asked
hi tom,

i have Oracle Application Server Release  4.0.8.1.0 - Enterprise Edition.

i write the procedure as below

CREATE OR REPLACE  PROCEDURE CHEQUE_INFO   is
 l_username varchar2(30) default owa_util.get_cgi_env('REMOTE_USER');

 cursor c1 is select modeofpay,to_char(crdate,'DD.MM.YYYY')
crdate,payno,bank,to_char(amount,'9,99,99,999.99')
amount
 from ex2001.party_credit
 where custcode=l_username
 order by crdate desc;

 tcustname varchar2(120);
 tinv_n_code number;
 counter number:=1;
begin

htp.htmlopen;
htp.headopen;
htp.title('Last Payment Received Information');
htp.headclose;

htp.bodyopen(cattributes=>'TEXT="#000000" BGCOLOR="#FFFFFF"
BACKGROUND="/ows-aimg/paws2.gif"');
htp.centeropen;

select initcap(custname) into tcustname from ex2001.custmast where
custcode=l_username;
htp.header(2,tcustname||' Last Payment Received Information');
htp.tableopen('border="4",bordercolor="blue"');

htp.tablerowopen;
htp.tableheader('Mode of Payament');
htp.tableheader('Cheque/DD Date');
htp.tableheader('Cheque/DD No.');
htp.tableheader('Bank');
htp.tableheader('Amount');
htp.tablerowclose;

for i in c1
loop
 htp.tablerowopen;
 htp.tabledata(i.modeofpay);
 htp.tabledata(i.crdate);
 htp.tabledata(i.payno);
 htp.tabledata(i.bank);
 htp.tabledata(i.amount);
 htp.tablerowclose;
 counter:=counter+1;
 if counter>5 then exit; end if;
end loop;

exception when others then
    htp.tabledata('No Payment Information Available .........');

htp.centerclose;
htp.tableclose;
htp.bodyclose;
htp.htmlclose;
end;

now i want to put one push button in procedure. when user click on that button
it will redirect to back. (history.back)

tia,
nikunj.
and we said...
I asked Chris Beck our javascript expert to answer and this is what he had to
say:

Just add the following lines where you want the button to appear.

htp.formOpen( null );
htp.p( '<INPUT type="BUTTON" value="Back" onClick="javascript:history.go(-1);">'
);
htp.formClose;

Hope that helps.
Review & Followup
Rating: 3
June 21, 2001
Reviewer: Gans from Cincinnati, OH USA

June 21, 2001 Rowan -- Thanks for the question regarding "PL/SQL equivalent of unix sleep command.", version 8.0.6
You Asked
Is there any PL/SQL procedure, function etc where you can delay processing for a
nominated time.
and we said...
dbms_lock.sleep( Number_of_seconds );

See
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for why SYS will need to grant you EXECUTE on this package directly (not via a
role) if you want to create a stored procedure that uses it.
Review & Followup
Rating: 4
Delay processing October 25, 2001
Reviewer: Armin Bollmann from Germany
Very helpful like almost the most of your hints and answers.

Thanks a lot
Armin

Rating: 5
Regarding dbms_lock.sleep February 20, 2002
Reviewer: Priti from India
This was most helpful as we were stuck as to how to delay the further processing
after a point. Has saved a lot of efforts.

Thnax a million

Rating: 5
Good for regression test May 02, 2002
Reviewer: David Penington from Melbourne, Australia
I was looking for this for regression testing. Looking up asktom was a lot
quicker than trawling the manuals usually is.

June 21, 2001 Lucy -- Thanks for the question regarding "How can I create an index on Bfile column (not the content of that file)", version 8.1.6
You Asked
Hi, Tom, I like your site, it is really helpful. Thank you.

Here I have a question whether it is possible or not to create an index on a
BFILE column, I know I can use Intermedia to generate index on the content of
that bfile, but if I want to do a search on the filename, how can avoid the full
table scan? I tried to use function based index, but it didn't work.

Thanks.
and we said...
Since you cannot create an index on a bfile, the only way I can think to do it
is to maintain an extra column that contains the name of the file.  You would
index and query that as normal:

tkyte@TKYTE816> create or replace function filename( p_bfile in bfile ) return
varchar2
  2  deterministic
  3  as
  4     l_dir  varchar2(255);
  5     l_name varchar2(255);
  6  begin
  7      dbms_lob.filegetname( p_bfile, l_dir, l_name );
  8
  9      return l_dir || ':' || l_name;
 10  end;
 11  /

Function created.

tkyte@TKYTE816>
tkyte@TKYTE816> create or replace directory my_dir as 'c:\temp'
  2  /

Directory created.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> drop table t;

Table dropped.

tkyte@TKYTE816> create table t ( x int primary key, y bfile, z varchar2(100) );

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> create or replace trigger t_trigger
  2  before insert or update on t
  3  for each row
  4  begin
  5          :new.z := filename( :new.y );
  6  end;
  7  /

Trigger created.

tkyte@TKYTE816>
tkyte@TKYTE816> insert into t(x,y) values ( 1, bfilename( 'MY_DIR', 'foo.txt' )
);

1 row created.

tkyte@TKYTE816> insert into t(x,y) values ( 2, bfilename( 'MY_DIR', 'bar.txt' )
);

1 row created.

tkyte@TKYTE816>
tkyte@TKYTE816> select x, z from t;

         X Z
---------- ----------------------------------------
         1 MY_DIR:foo.txt
         2 MY_DIR:bar.txt
June 22, 2001 Syed -- Thanks for the question regarding "One Question.", version 8.1.6
You Asked
If want to create a new tablespace called APPS for a new application in your
existing database. The Tablespace will be 50 MB and should have a minimum extend
of 20Mb with the next and each subsequent extent being 10MB. Please planning to
execution to create the tablespace.

Yes I am asking how to do this using SQL...
and we said...
I suggest you use a LOCALLY managed tablespace with uniform extent sizes.  You
will not have an initial extent of 20 meg - rather it'll be 10meg (different
sized extents in a tablespace is a bad idea).

create tablespace LMT
datafile '/path/file.dbf' size 51254k  -- added 64k for LMT bitmap header
extent management local uniform size 10m;

followup to comment one below

it is the cause of tablespace fragmentation.  If you use same sized extents --
you are assured that when you drop or rebulid an object, the extents it frees up
can DEFINITELY be used by ANY other object.  If the tablespace says it has
100meg free -- you have 100 meg of usable space for objects.

With different sized extents (especially the wacky ones created by having pctinc
> 0 -- i hate pctinc), those extents may be usable, may not be.  In this
tablespace, if you have 100meg free you very well might still get "unable to
allocate extent" errors -- in fact, you might not have ANY free space in that
tablespace with 100meg free!
Review & Followup
Rating: 4
June 22, 2001
Reviewer: Gururaj from Norcross,GA USA
Tom, why do you say 'different sized extents in a tablespace is a bad idea' ?

June 22, 2001 Alan -- Thanks for the question regarding "Primary Key Constraint and Unique Key", version 8.1.6
You Asked
I just wanted to validate the idea that it is much faster to Create a unique
index with parallel option and then add a primary key constraints using index
(same column as with the unique index) in that way oracle will not build the pk
index but uses the unique index that was build already. Instead of just doing
Alter TAble Add contraints primary key using index in which oracle will build
the pk index without the parallel option (which is much slower). Is that true?
and we said...
Yes, you can build your own unique index using any options and then alter the
table and add the primary key.  We will "kidnap" your existing index and take it
for our own.  Bear in mind that if you drop the primary key -- we'll drop your
index as well.
June 22, 2001 Reji -- Thanks for the question regarding "XML data type and VARCHAR2", version 9i
You Asked
Tom:
    Would you please elaborate on the XML data type in Oracle9i?  Can we do SQL
operations against an XML type columns?

Is there any plan to increase the max size of VARCHAR2 from 4000 to a higher
number?

Thx
Reji
and we said...
The Oracle supplied type, XMLType, can be used to store and query XML data in
the database. XMLType provides member functions to access, extract and query the
XML data using XPath expressions. XPath is another standard developed by the W3C
committee to traverse XML documents. In Oracle9i, XMLType functions only support
a limited subset of the XPath expressions. Oracle9i also provides a set of SQL
functions such as SYS_XMLGEN,SYS_XMLAGG, and other PL/SQL packages (DBMS_XMLGEN)
to create these XMLType values from existing relational or object relational
data.

XMLType, a system defined type, can be used as arguments to functions or as
table or view columns. When you create a XMLType column in a table Oracle
internally uses a CLOB to actually store the XML data associated with this
column. You can create Oracle Text indexing on the XMLType column and other
functional indexes. In Oracle9i, since the XMLType is stored as a CLOB, updates
can only be made to the entire document.

There is no plan that I am aware of.  for data over 4000 bytes -- the correct
and proper datatype is a CLOB.  That is what that is there for.
June 22, 2001 Sandeep -- Thanks for the question regarding "Want to display "*" for typed password", version 8.1.6
You Asked
Hi,

  We are writing a SQL script and in between we are creating some users, roles.
So we want to make this script intractive for passwords. Like whoever is
executing this scripts he has to enter the passwords for new users (which this
script will create) and we want
when that person enter the password it should just display "*" on terminal.

 Let me know If I'm not clear enough

Thanks
Sandeep
and we said...
You can use the HIDE option on the accept verb:

accept x prompt "Enter password " hide

it will NOT display a *, it'll just surpress the output alltogether.
Review & Followup
Rating: 5
cool June 22, 2001
Reviewer: Sandeep from MA
U'r the best man

June 22, 2001 -- Thanks for the question regarding "index -- read mostly database", version 8.1.6
You Asked
Tom:

if my database is mostly used for query only,

build more index won't hurt (based on each query), is that true?
and we said...
Well, having indexes that are never used consume resources, take up space, take
time to be built, and could cause query plans to take longer to get generated
(more options to consider).

All in all, i would expect more indexes in a read mostly database versus a write
mostly database -- yes.
June 23, 2001 Pham Quang -- Thanks for the question regarding "Oas in Sun Solaris", version 4.0
You Asked
Hi Tom!

I am a newbie in Oracle Application Server (Oas). Recently, I must work with
Oas4.0, I was successful with Oas in WinNt but there are some problems with Sun
Solaris 5.7. I was install Oas in sun Solaris and start successfull (when
starting all flag of Oracle Application Server and HTTP Listener is set to blue)
but  I failed when trying
to run the JServlet application (which I ran successfully with WinNt). The
detail is as following:
I run netscape 4.7 in windows 2000 to query to server( When installing Oas I set
host is sol7, domain is foo.com):
- When I edit host file:
    192.168.131.29  sol7
  and query
http://sol7:8888,/
server is run successful but when I call application(
http://sol7/T5COMM/HelloServlet
  there is the error: "The request did not specify a valid virtual host."
- when I edit host file:
        192.168.131.29 sol7.foo.com
  and query
http://sol7.foo.com:8888/
there is the error as above.
It is very helpful if you explain for me the reason.
I am looking forward hearing from you.
Tien,
and we said...
When you installed, you supplied the hostname.  This hostname is in the
configuration file for each HTTP daemon you set up.

For the hostname for the server on port 80  you must not have put in simply sol7
but rather sol7.foo.com.

On 8888 you must have put in simply sol7.

Either edit the http configuration files or using the GUI to update the virtual
host name.

Here is a support note with more info on this issue:

Article-ID:         <Note:2061916.102>
Circulation:        PUBLISHED (EXTERNAL)
Folder:             internet.WebServer
Topic:              Known Problems and Solutions
Title:              CHANGE HOST TO HOST.DOMAIN
Document-Type:      SOLUTION
Impact:             LOW
Skill-Level:        CASUAL
Server-Version:     XX
Updated-Date:       05-MAY-2000 10:30:58
References:
Shared-Refs:
     <Problem:1013131.102> REQUEST DID NOT SPECIFY A VALID VIRTUAL HOST
Attachments:        NONE
Content-Type:       TEXT/PLAIN
Products:           276/LISTENER (XX);
Platforms:          GENERIC;

Solution Description:
=====================

    1.  Go into the listener setup using the node manager and
        click on the Network icon under the problem listener.

    2.  Under hostname change the entry from the hostname
        to the host.domain syntax.

    3.  Restart the listener by clicking on HTTP Listeners selecting the
        modified listener a clicking the reload icon ( |<< ) in the browser
        window.

Now when accessing the listener, use the host.domain syntax and the error
no longer appears.

Solution Explanation:
=====================

The reason for this change is that during install, the Oracle Application Server
automatically selects the host.domain from the NETWORK settings for the
Oracle Application Server machine.  This is assigned to the node manager
listener and remaining default listeners.  Each listener created manually after
this step then only takes the hostname, and drops off the domain.  This is the
point at which the listener needs to be updated with the domain information.
Review & Followup
Rating: 4
Oas in Sun Solaris June 25, 2001
Reviewer: Pham Quang Tien from Viet nam
Hi Tom!

Many thanks for your response. It is very helpful for my work.

Tien,

June 23, 2001 -- Thanks for the question regarding "db block gets and consistent get", version 8.1.6
You Asked
Tom:

I guess my real question is when compare plan.

should i add db block gets and consistent gets and then compare.
so one is more important than the other.

some plan may have more db block gets, some may have more on consistent gets,
which one should we consider better?
and we said...
db block gets is a count of blocks read in CURRENT mode.

On a query, i would expect to see these when we read the data dictionary/extent
map to determine how to FULL SCAN a table.  They are rare in a query.  If you
use a SELECT FOR UPDATE they will not be rare.

A query that has more db block gets is probably full scanning more tables then
the one that is not doing them.  Whether that is GOOD or BAD is IMPOSSIBLE to
say.  It depends -- you cannot use this as a way to ascertain whether a query is
inheritently good or evil.

Too see the difference a simple query like this:

ops$tkyte@ORA8I.WORLD> select rowid from dual;

ROWID
------------------
AAAADCAABAAAAHQAAA

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (FULL) OF 'DUAL'

Statistics
----------------------------------------------------------
          0  recursive calls
          4  db block gets
          1  consistent gets
...

That indicates that we did 4 current mode reads to determine how to FULL SCAN
dual.  Another query is run against dual:

ops$tkyte@ORA8I.WORLD> select * from dual where rowid = 'AAAADCAABAAAAHQAAA';

D
-
X

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY USER ROWID) OF 'DUAL'

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          1  consistent gets
...

and we can see that when we use an index/rowid access plan, we'll not need to
get the layout of dual (no full scan) hence no db block gets.

Whether is is "good" or "bad" -- one cannot say in the generic case.  In this
case, the second query is "better" (although for such a tiny table, its not
totally relevant).

Consider a query like:

select * from T where x > 0;

Assume there is an index on X.
Assume there are 1,000,000 rows in T.
Assume for all X's, the value of X is greater then ZERO.

I would prefer the query with db block gets cause a full scan would be the right
way to go.

Now, change the assumptions.  Assume that for all X's, 5 of them are greater
than ZERO, the rest are less than or equal to zero.

Now, I prefer the query with zero db block gets cause I want to use the index to
read this table -- NOT a full scan.
June 23, 2001 MBL -- Thanks for the question regarding "Grant database object privileges to a user ", version 7
You Asked
I WAS TRY TO Grant database object privileges to a user
FOR EXAMPLE(SELECT ON ....)
BUT IT NOT ACCEPT (ERROR ORA-1031).
IS THERE ANY SYSTEM PRIVILEGES OR ROLE SHOULD GIVE IT FIRST OR WHAT
I WILL THANK TO YOU FOR YOUR ANSWER.....AS SOON AS P.
and we said...
You need to have granted granted that object priv WITH GRANT OPTION.  For
exmaple:

ops$tkyte@ORA8I.WORLD> grant select on scott.emp to connect;
grant select on scott.emp to connect
                      *
ERROR at line 1:
ORA-01031: insufficient privileges

ops$tkyte@ORA8I.WORLD> @connect scott/tiger
scott@ORA8I.WORLD> grant select on emp to ops$tkyte WITH GRANT option;

Grant succeeded.

scott@ORA8I.WORLD> @connect /
ops$tkyte@ORA8I.WORLD> grant select on scott.emp to connect;

Grant succeeded.

ops$tkyte@ORA8I.WORLD>
Review & Followup
Rating: 3
July 05, 2001
Reviewer: Senthil Kumar A from Chennai
It was useful but what do u mean by connect whether it is
a role or a user.Do explain me ? Thanks.

June 23, 2001 Nirmal Kumar -- Thanks for the question regarding "How to run the OS script Through PL/SQL", version 7.3.1
You Asked
Dear Tom,

How are u.

I have an requirement in my appliacation as, to transfer data files from the FTP
server directory to Oracle server directory, and then am processing the data.
This i can able to do it through developer by using HOST command. But i need to
do it at server level.

My question are,

a) How Can I run the OS(Win NT4) script files through PL/SQL?

b) If data are delemited by tab in the datafile, what i can i specifiy in the
control file statmenet 'FIELDS TERMINATED BY ?' to use sql loader for transfer
data into a table.

c) Can you give one small example for, how to define and call an external
procedures(using C) from PL/SQL.

d) Can you give some tips regarding HASH functions?. What it means 'HASH'?. Is't
mean selection a random value from the certain range of data?. I'm not clear
with hash join, hash index, hash cluster, etc. So expecting more on 'HASH' from
you.

Regards,
Nirmal Kumar.
and we said...
a) in 7.3, you cannot really.  There is no facility for doing so in that
release.

b) You could use terminated by X'09' which is the tab character using HEX format
(ASCII 9 is a tab character) or you might use terminated by WHITESPACE. The two
are very different in implementation however as the following shows. Using the
DEPT table from above we’ll load using this control file:

LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY WHITESPACE
(DEPTNO,DNAME,LOC)
BEGINDATA
10      Sales       Virginia

It is not readily visible on the page but there are TWO tabs between each piece
of data in the above – the data line is really:

10\t\tSales\t\tVirginia

Where the \t is the universally recognized “Tab” escape sequence.  When you use
that control file with the TERMINATED BY WHITESPACE clause as above, the
resulting data in the table T is:

tkyte@TKYTE816> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 Sales          Virginia

Terminated by WHITESPACE parses the string by looking for the first occurrence
of whitespace (TAB, BLANK or NEWLINE) and then continues until it finds the next
non-whitespace character. Hence, when it parsed the data, DEPTNO had 10 assigned
to it – the two subsequent tabs were considered whitespace and then Sales was
assigned to DNAME and so on.

On the other hand, if you were to use FIELDS TERMINATED BY X’09’ as the
following control file does:

LOAD DATA
INFILE *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY X'09'
(DEPTNO,DNAME,LOC)
BEGINDATA
10      Sales       Virginia

you would find DEPT loaded with the following data:

tkyte@TKYTE816> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10                Sales

Here, once SQLLDR encountered a TAB it output a value. Hence, 10 is assigned to
DEPTNO and DNAME gets NULL since there is not data between the first tab and the
next occurrence of a tab.  Sales gets assigned to LOC.

This is the intended behavior of TERMINATED BY WHITESPACE and TERMINATED BY
<character>. Which is more appropriate to use will be dictated by the input data
and how you need it to be interpreted.

c) in 7.3, no.  feature did not exist.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:341817437103
for an 8.0 and up example

d) a HASH is a method of taking an infinite set of possible values and "hashing"
them into a finite number of values.    It is used to organize data for quick
retrieval.

see
http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?hash+coding
for a definiteion.

With a hash join, we basically build hash tables of the data to be joined.  Now
we can quickly go from key value to location (without having to use an index).

A hash cluster is a method of storing, in a database table, data in a hash
table.  When you query the data and include the hash column in the predicate
(eg: you have a hash table whose cluster key is EMPNO and you issue:

   select * from emp where empno = 1234
) We can quickly convert the value 1234 (using the hash function) into a
location on disk and go directly to the data without even using an index.
June 23, 2001 balraj -- Thanks for the question regarding "Temporary Segment", version 8.1.6.3
You Asked
Sir

Like a Rollback segment can i manually Allocate a temporary Segement to a
transaction.

Does Oracle do all the Temporary Opearations in Temporary Files or does it take
an area in memory...If yes what part of SGA does it take for temporary
operations like Order by,Sort

Regards/Balraj
and we said...
A temporary segment will be allocated from the temporary tablespace assigned to
a user.  The temporary extents will be allocated from the tablespace that user
has set as their temporary tablespace.

Oracle does operations in memory upto the sort area size.  This memory is
allocated from the PGA which is part of the process memory.  It is allocated
using malloc() in the server process itself, it does not come from the SGA.
June 23, 2001 balraj -- Thanks for the question regarding "Oracle9i", version 8.1.6.3
You Asked
Sir,pl be a bit more explanatory with examples

1.How are the Locally managed tablespaces better than the System
  Managed tablespaces....in real transactions

2.Which part of Memory is provided to the User Processes(PGA) and how
  much is provided to individual.Can we allocate that manually

3.In oracle can we set the user request priorities like we do in
  Print Servers

      FIFO
      LIFO and so on

4.Sir,for the sort operations or order by functions what is stored in
  users PGA and how is Temporary Tablespace utilized

5.One of programmer has to Process his 8 lakh records with 10 column
  of each record...The system give temporary tablespace error

        How do i handle it ?

Regards/Balraj
and we said...
1) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:733126913855
for a general discussion

LMTs:

o avoid fragmentation of the tablespace, the tablespace cannot be fragemented.
o avoid the expensive recursive SQL you would need to do otherwise to allocate
  more space
o avoid the serialization of space management that dictionary managed
  tablepspaces have.
o remove the possibility of someone messing up your allocation scheme, they
  cannot change the initial and next no matter how hard they try.

2) PGA (PROCESS global area) is dynamically allocated memory allocated in a
process.  It is not part of the SGA.

A search for PGA on my site will lead you to about 14 articles (including this
one) that discuss it.

You cannot allocate the pga manually, I cannot imagine a reason for even wanting
to do so.

3) no.

4)
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:849819369119
5) add more temporary tablespace space.
June 23, 2001 kamini -- Thanks for the question regarding "getting results with computed column", version 8.1.7
You Asked
Hi tom

I am having a table called price_tbl.  The columns and values of the table are
as follows

TIMESTAMP    PRICE
---------       -----
16:38:52:688    950000
16:38:58:840    0
16:39:21:704    950000
16:39:56:323    960000
16:40:08:330    960000
16:45:40:856    950000
16:56:39:800    950000
17:00:46:014    950000
17:00:47:263    950000
17:02:18:417    960000
17:02:49:459    950000
17:03:01:168    950000
17:10:52:034    950000
17:14:53:888    950000
17:18:28:221    950000
17:18:28:703    950000
18:10:10:597    0
18:43:23:229    950000
18:45:23:874    900000

From the above dataset I should extract the price movement at each timestamp
based on the following conditions:
1. If the current record's price is greater than previous record's price i
should mark it as 'up'.
2. if the current record's price is lower than previous record's price i should
mark it as 'dn'
3. if the current record's price is equal to previous record's price i should
mark it with previous record's movement sign.

I wrote the following query and tried:

SELECT timestamp, price, tick, (CASE WHEN tick IS NULL THEN lead(tick)
OVER(ORDER BY timestamp desc ) ELSE tick END) as tick1 from
(
SELECT timestamp, price, (CASE WHEN LEAD(price) OVER (order by timestamp desc) <
price THEN 'UP' ELSE  (CASE WHEN LEAD(price) OVER (order by timestamp desc) >
price THEN 'DN' END)END) as TICK
FROM price_tbl
ORDER BY timestamp
) ORDER BY timestamp

The above query yields me following data

TIMESTAMP    PRICE    TICK    TICK1
---------       -----   ----    -----
16:38:52:688    950000
16:38:58:840    0       DN      DN
16:39:21:704    950000  UP      UP
16:39:56:323    960000  UP      UP
16:40:08:330    960000          UP
16:45:40:856    950000  DN      DN
16:56:39:800    950000          DN
17:00:46:014    950000
17:00:47:263    950000
17:02:18:417    960000  UP      UP
17:02:49:459    950000  DN      DN
17:03:01:168    950000            DN
17:10:52:034    950000
17:14:53:888    950000
17:18:28:221    950000
17:18:28:703    950000
18:10:10:597    0       DN      DN
18:43:23:229    950000  UP      UP
18:45:23:874    900000  DN      DN

But I need the data as following

TIMESTAMP    PRICE    TICK    TICK1

16:38:52:688    950000
16:38:58:840    0       DN      DN
16:39:21:704    950000  UP      UP
16:39:56:323    960000  UP      UP
16:40:08:330    960000          UP
16:45:40:856    950000  DN      DN
16:56:39:800    950000          DN
17:00:46:014    950000          DN
17:00:47:263    950000          DN
17:02:18:417    960000  UP      UP
17:02:49:459    950000  DN      DN
17:03:01:168    950000          DN
17:10:52:034    950000          DN
17:14:53:888    950000          DN
17:18:28:221    950000          DN
17:18:28:703    950000          DN
18:10:10:597    0       DN      DN
18:43:23:229    950000  UP      UP
18:45:23:874    900000  DN      DN

Could u please help me.. I need this very badly..   I want to achive this either
in one sing SQL Statement or PL/SQL Block returning the above info as Cursor

Thanks
and we said...
I'll admit -- this one took a moment or two of thought.

Its an interesting problem that lag and lead cannot solve directly.  You want an
analytic function that doesn't exist -- you want the first prior price that is
DIFFERENT from the current price -- you don't want just the lag, you want the
last different value.

It would take some "sql that could recurse" to do that.

what we can do is use lag() whenever possible (when the price of the prior
record is different) and a SELECT of a SELECT to find the prior, different
price, otherwise.

Here is one approach:

ops$tkyte@ORA817.US.ORACLE.COM> select timestamp,
  2          price,
  3          case when movement = 'DN' then 'DN'
  4                 when movement = 'UP' then 'UP'
  5                 else ( case when substr(movement,14) > price then 'DN'
  6                             when substr(movement,14) < price then 'UP'
  7                             else                                  NULL
  8                         end
  9                       )
 10          end
 11  from ( select timestamp,
 12                price,
 13                case when prior_price > price then 'DN'
 14                       when prior_price < price then 'UP'
 15                       else (select max( timestamp || '-' || price )
 16                               from t t2
 17                              where t2.timestamp < t.timestamp
 18                                and t2.price <> t.price )
 19                end movement
 20           from ( select timestamp,
 21                         price,
 22                         lag(price) over ( order by timestamp ) prior_price
 23                    from t
 24                ) t
 25       )
 26  order by timestamp
 27  /

TIMESTAMP                      PRICE CA
------------------------- ---------- --
16:38:52:688                  950000
16:38:58:840                       0 DN
16:39:21:704                  950000 UP
16:39:56:323                  960000 UP
16:40:08:330                  960000 UP
16:45:40:856                  950000 DN
16:56:39:800                  950000 DN
17:00:46:014                  950000 DN
17:00:47:263                  950000 DN
17:02:18:417                  960000 UP
17:02:49:459                  950000 DN
17:03:01:168                  950000 DN
17:10:52:034                  950000 DN
17:14:53:888                  950000 DN
17:18:28:221                  950000 DN
17:18:28:703                  950000 DN
18:10:10:597                       0 DN
18:43:23:229                  950000 UP
18:45:23:874                  900000 DN

19 rows selected.

ops$tkyte@ORA817.US.ORACLE.COM>
June 24, 2001 Jean-Alexandre -- Thanks for the question regarding "server manager won't run scripts", version 8.0.6
You Asked
I just installed Oracle 8.0.6 on HPUX 10.20

I start svrmgrl and connect internal
from there I can without any problem run create database...,
startup, shutdown, but when I try to run a script with @<path><script>
I get an error message <path><script> not a recognise SQL command.

It seems that it does not recognize the @.

THIS IS WHAT I GET-----------------
SVRMGR> @test.sql;
test.sql
*
ORA-00900: invalid SQL statement
------------------------------------------

Even if I run catproc or anything, it does not even open the script.
In my exemple I did not precise a path but it gives the same result.

YES that's what is was, thank you so much!!!!!!!!!!!!!!

 many THANKS.
and we said...
The chracter "@" is not being interpreted correctly.  The "stty"
setting for "kill" is set to "@".  When any SQL script is executed,
the "@" precedes the script name to tell whichever program that is
being used to execute the script.

Try this:

$ stty kill ^U

(ctl-U -- one key) or some other character.

Let me know.  You can verify this by doing

$ stty -a

to see if @ is set to something.
June 24, 2001 Orna -- Thanks for the question regarding "using bulk binds ", version 8.1.7
You Asked
Hi Tom,

Currently  , whenever we need to change the structure of a table ( for example ,
rename a column , or add a column in the middle ) I write a 'conversion script'
that is basically an INSERT ... SELECT to the new table from the old table.
this can take a long time for very large tables

I would like to use the bulk bund option to spid things up for large tables .

So , if for example I have :

SQL> desc  A_OLD
 Name                            Null?    Type
 ------------------------------- -------- ----
 COL1                                     NUMBER(9)
 COL2                                     NUMBER(3)
 COL3                                     NUMBER(9)
 COL4                                     NUMBER(9)
 COL5                                     VARCHAR2(1)

and the new structure is AN ADDITIONAL COL6 IN THE MIDDLE:

SQL> desc  A_OLD
 Name                            Null?    Type
 ------------------------------- -------- ----
 COL1                                     NUMBER(9)
 COL2                                     NUMBER(3)
 COL6                                     VARCHAR2(2)
 COL3                                     NUMBER(9)
 COL4                                     NUMBER(9)
 COL5                                     VARCHAR2(1)

and lets assume a half a million records on A_OLD :

1. Will I benefit from the bulk option instead of INSERT SELECT ?
2. Do I need to first load the A_OLD table into a PL/SQL table ? how can I do it
without specifying each field separately ( 'cause  we have very big tables with
lots of columns )
2. Can you give me a basic script that does it ?

thanks!
Orna
and we said...
To rename a column, you should quite simply use a view.

Same with adding a column in the "middle". Just add it at the "end" and use a
view.

Just rename the table T to T_TABLE, create a view T as select <columns with
aliases in whatever order> from T_TABLE and grant on T_TABLE.

don't re-org 1/2 million rows for something that can be done easier and faster.

(and don't use bulk binds for this -- just a single statement -- it should be a
CREATE TABLE as SELECT with the unrecoverable option).

Again however, I would not even consider rebuilding a table for these
reasons.  Use of a simple view against a single base table will solve all of
your problems.
June 24, 2001 Mohammed -- Thanks for the question regarding "Grant Privileges to Users ", version 8i
You Asked
Dear Mr. Tom,

I have tried to create user as the following steps but I really find an error in
one of the steps below:

SQL> create user x identified by x;

          User created.

SQL> grant Connect to x;

Grant succeeded.

SQL> grant create any table to x;

Grant succeeded.

SQL> conn  x/x;
Connected.

SQL> create table c (x number(2),y varchar2(20));
create table c(x number(2),y varchar2(20))
*
ERROR at line 1:
ORA-01950: no privileges on tablespace 'SYSTEM'

As you see that I have the error above .How can I Solve this problem. However I
tried to create user by using Oracle Navigator for personal oracle version
7.3.2.1.0, and give the user the same privileges, and
No error appeared when I tried to practice the Privilege.
and we said...
alter user X
default tablespace <some tablespace OTHER then system>
quota unlimited on <that tablespace>
temporary tablespace <some tablespace OTHER then system>;

by default you have no quotas on any tablespace -- hence you cannot create your
initial extent.  You do not want these objects in your system tablespace so pick
some other tablespace you have.
Review & Followup
Rating: 5
Try this yuo will not lose any thing just more information July 02, 2001
Reviewer: Mohammed Al-moayed from Yemen Sana'a
I realy thank Mr Tom about all help , I tried this method and it goes Ok .

Rating: 5
User tablespace priv January 22, 2002
Reviewer: Steve Chelstrom from Austin, TX
As a new user of Oracle Tom's website is a great timesaver because of the rapid
access to info on the specific errors.  I altered user priveledges for table
space via DB Studio on NT however it wasn't until I did the update via SQLplus,
stated for this error, that I could create my tables.

June 24, 2001 naga -- Thanks for the question regarding "'consistent gets' values of set autotrace on output", version 8.1.6
You Asked
i am not clear with the significance of this 'consistent hits' of a
set autotrace on output.

ideally it should have more value or how do we decide the performance of the
query using its value.

and also what is 'consistent read' mode?

if you can explain with an example, that will be good.

thanks
and we said...
I think you mean consistent gets, not hits.

These are blocks read in "read consistent mode" -- they were read as they
existed at the point in time your query began (even if the query runs for 5
hours, the last block read is consistent with the first block).

In order to do consistent gets, we may have to "rollback" a block to make it
appear as it did when the query began.  This is also how we avoid writes
blocking reads -- we just rollback their work in our session so we can see the
data as it existed when the query began.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c23cnsis.htm#2611
for the whole scoop on read consistency.  Its all about getting the right answer
in a highly concurrent fasion.
June 24, 2001 naga -- Thanks for the question regarding "ROLL FORWARD???", version 8.1.6
You Asked
HI TOM,

WHAT IS THIS ROLLFORWARD AND HOW DOES IT DIFFER FROM ROLLBACK?
BETTER IF IT IS EXPLAINED WITH EXAMPLES.
and we said...
Rolling forward is the term applied to the activities that take place during a
crash recovery.

Say the system was processing transactions -- there are some committed ones and
some that are in process.  The system fails (power loss).

When the system is brought back up, Oracle will read the redo log files and
apply the REDO found in there to the database.  This will bring the database
back to the exact point in time of the failure.  This is known as rolling
forward.

Now, all of the committed transactions are recovered and the ones that were in
process will begin to rollback.  When thats all done -- the entire database is
consistent again.
Review & Followup
Rating: 4
June 24, 2001
Reviewer: Satya B Mylavarapu from Hayward, CA USA

Rating: 3
more explanation June 25, 2001
Reviewer: A reader
Sir

Would u please make it more clear

how rollback initiates and who initiates it
how rollforward initiates and who initiates it

Do the SMON goto the rollback segments to know that which transactions were not
committed or it know it from redo

regards/Balraj

June 24, 2001 -- Thanks for the question regarding "Operating System Script from plsql", version 8.1.5.0.0
You Asked
I saw your answer saying that you cannot run an NT OS script from pl/sql in
version 7.?.?

How about from pl/sql 8.1.5.0.0?

Thanks for your replies and answers - they are of great help!!

Brgds Mark
and we said...
In 7.x, you can "sort of" run a script, UTL_HTTP lets you execute any URL, that
URL could be a cgi-bin, that cgi-bin can be a script of course.

In 8i, java is easiest:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:952229840241
And you do have the ability to use an extproc as well:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:341817437103
...


Subject | Article | Last Updated (East coast time)
Library cach , iMT questions | article only | Jun 25, 2001 07:10 am
Extent - definition - reg. | article only | Jun 25, 2001 09:22 am
ORA-1555 and indexes | article only | Jun 25, 2001 10:02 am
v$sga mismatch... | article only | Jun 25, 2001 10:05 am
DECODE | article only | Jun 25, 2001 10:20 am
Prohibit to Access server Gateway Settings | article only | Jun 25, 2001 10:53 am
PLS-00222: no function with name 'TO_DATE' exists in this | article only | Jun 25, 2001 03:29 pm
Usage of LOB's | article only | Jun 25, 2001 03:33 pm
1)UTLBSTAT and UTLESTAT 2)WRAP | article only | Jun 26, 2001 10:44 am
SHMMAX of 4G causes excessive swapping AND SGA/RAM relationship | article only | Jun 26, 2001 01:24 pm
Transferring data from more than to servers to One common server | article only | Jun 26, 2001 01:54 pm
Hiding a Password while using DBMS_OBFUSCATION_TOOLKIT | article only | Jun 26, 2001 02:56 pm
Support for Oracle version 8.1.6 on sun solaris server. | article only | Jun 26, 2001 03:53 pm
re: Consistent Reads | article only | Jun 27, 2001 09:27 am
Insert rows in PL/SQL | article only | Jun 27, 2001 09:43 am
Number of extents in LMT | article only | Jun 27, 2001 01:56 pm
Archive Logs backup | article only | Jun 27, 2001 02:02 pm
OLAP services in Oracle9i | article only | Jun 27, 2001 02:56 pm
user_tables | article only | Jun 27, 2001 08:38 pm
PL/SQL Block for inserting data in BLOB type Column ! | article only | Jun 28, 2001 11:04 am
multiple questions | article only | Jun 28, 2001 11:26 am
OPS$ORACLE | article only | Jun 28, 2001 12:47 pm
RMAN Backup and Recovery | article only | Jun 28, 2001 01:55 pm
JDK 1.3 | article only | Jun 28, 2001 02:01 pm
How to use &1, &2 etc.. parameters in a PL/SQL block | article only | Jun 28, 2001 03:45 pm
RE:refresh database | article only | Jun 28, 2001 03:56 pm
Migrating OCI application from 32-bit Oracle to 64-bit Oracle | article only | Jun 28, 2001 07:54 pm
oracle applications pdf files | article only | Jun 29, 2001 09:45 am
How can i load file (into a clob) from my directories and not specially from the directory created like MY_FILES | article only | Jun 29, 2001 09:55 am
Object Caching Service | article only | Jun 29, 2001 01:51 pm
dbms_space | article only | Jun 29, 2001 07:36 pm
efficient way to query count | article only | Jun 29, 2001 07:48 pm
Oracle Application Server | article only | Jun 30, 2001 10:23 am
Latches, Nested Loop and more... | article only | Jun 30, 2001 09:25 pm
Using Bind Variable in a Store Produre | article only | Jun 30, 2001 09:29 pm
Indexes=N | article only | Jun 30, 2001 09:38 pm
PGA | article only | Jul 01, 2001 04:33 pm
Trace performace in Pro*C | article only | Jul 01, 2001 07:47 pm
Autonomous transaction | article only | Jul 01, 2001 08:20 pm
Physical sizing of a VARCHAR2 variable | article only | Jul 01, 2001 09:04 pm
row(s) 1 - 40 of 40
June 25, 2001 Omar -- Thanks for the question regarding "Library cach , iMT questions", version 8.1.6
You Asked
Hi tom,
I need you to help me in the following.
Q1. I have Oracle8i rel2 can I upgrade iMT option only to the version 8.1.7 and
how ?.

Q2.What is the diff between pins vs gets, and pinhitration vs gethitratio.

thanx in advance
and we said...
q1) you either upgrade the entire instance or not.  you cannot upgrade a
specific piece of the database (and not the rest).

q2) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:465420331879
....
June 25, 2001 -- Thanks for the question regarding "Extent - definition - reg.", version 8.1.7.0.0
You Asked
"A free extent in a tablespace is comprised of a collection of contiguous free
blocks."

When at the os itself we dont get the contiguous free space.
What does the above statement means?

Can i call extent as collection of blocks in a datafile.  Is this statement
true?
Or i have to say extent as collection of contiguous blocks in a datafile.

I am not clear why the word  contiguous is used in defining the extent?

Can u elaborate on it?

Regards

Koshal
and we said...
The blocks are logically contigous.

Say you opened the datafile using fopen() (C IO call).

Assume you have a 2k blocksize.

Assume you have an extent that goes from block 100 to 200.

A simple fseek to byte ( (100-1)*2048 ) would get you to block 1 of your extent.
 An fseek to byte ( (101-1)*2048 ) would get you to block 2 of your extent.

block 1 and 2 of your extent might not be physically near eachother on disk due
to file system fragmentation but as far as we are concerned they are right next
to eachother logically.

Call them a collection of contigous blocks that is what they are.  The fact that
physically, at the file system level, they might not be contigous is not
relevant.  As far as any utility, or Oracle itself is concerned, they are
contigous.
June 25, 2001 Steve -- Thanks for the question regarding "ORA-1555 and indexes", version 816
You Asked
I am helping a colleague who is receiving ORA-1555.

On doing some investigtation I find that he is selecting from two tables
approximately 15 and 20GB in size. I have also come to find out that the 20GB
table has 16 indexes on it (another problem unto it self) that collectively are
80GB in size.

I understand problem/resolution for ORA-1555, what I am not clear on is ...does
Oracle include indexes whcn constructing read consistent views? In this case if
we were to drop all the indexes would the chance of receiving ORA-1555 be
significantly less? I am not saying this is the only problem I am just curious
if the indexes are in any way a contributing factor

tks

Steve
and we said...
Absolutely - indexes are covered by the same protection.

Dropping all indexes would be rather drastic.

Using same sized rollback segments -- each of which is big enough so that it
does not cycle around during the longest of long running queries -- that would
fix it.
Review & Followup
Rating: 5
tks again tom June 25, 2001
Reviewer: Steve Montgomerie from Houston
I'll buy you book. Thanks for taking the time to answer questions. In my case
your second option was invaluable.

June 25, 2001 Senthil -- Thanks for the question regarding "v$sga mismatch...", version 8.1.5
You Asked
Hi Thomas,

a question about v$sga and init parameter.

SQL> show sga
Total System Global Area   33234320 bytes
Fixed Size                    64912 bytes
Variable Size              32268288 bytes
Database Buffers             819200 bytes
Redo Buffers                  81920 bytes

SQL> show parameter db_block_size
NAME                                 TYPE    VALUE
------------------------------------ ------- --------------------
db_block_size                        integer 4096

SQL> show parameter db_block_buffers
NAME                                 TYPE    VALUE
------------------------------------ ------- --------------------
db_block_buffers                     integer 200

SQL> show parameter log_buffer
NAME                                 TYPE    VALUE
------------------------------------ ------- --------------------
log_buffer                           integer 12288

SQL> show parameter shared_pool_size
NAME                                 TYPE    VALUE
------------------------------------ ------- --------------------
shared_pool_size                     string  30000000

1. What is fixed size...and where does it gets the value(64k)?
2. What is Variable size?
3. My understanding is...'Redo Buffers' is the value of log_buffer
parameter...but then...why there is a conflict? Correct me if i am wrong.
4. Is there any calculation to get the value for SGA, i once read, it should be
45% of the Physical memory...

Thanks for your reply.

regards,
senthil.
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:365088445659
and
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:972030403607
You should not compute the SGA size based on memory (other then the SGA
shouldn't exceed physical memory).

If you use MTS, 90% might be right (maybe not).
If you are OLTP, 10% might be right (maybe not).
If you are DSS, 50% might be right (maybe not).
Review & Followup
Rating: 4
June 25, 2001
Reviewer: A reader

June 25, 2001 Suresh -- Thanks for the question regarding "DECODE", version 8.1.7
You Asked
Hi Tom,
   My requirement is as follows.

1. SELECT 'Q'|| DECODE
(v_month_start,1,1,2,1,3,1,4,2,5,2,6,2,7,3,8,3,9,3,10,4,11,4,12,4) from dual;

The above statement gives me the output
Q1    -- If v_month_start is >= 1 and <= 3
Q2    -- If v_month_start is >= 4 and <= 6
Q3    -- If v_month_start is >= 7 and <= 9
Q4    -- If v_month_start is >= 10 and <= 12

Can I make the above statement more efficient by, say

select decode(<=3,1,<=6,2....) or something like that.

2. I have an insert statement as below.

Insert into t1(c1,c2) select c6,c7 from t2;

I have a requrement as
Insert into t1(c1,c2,c3)
select c6,c7,
case WHEN v_report_type_id != V_C_EFF_RATE_ID THEN v_period_name_2
     ELSE 'RATE %'
     END, FROM t2;
When I tried the above code in  a procedure it did not let me compile it. Please
let me know what is wrong with the above statement.
and we said...
1) use

   'Q' || trunc(v_month_start/3+.999)

2) PLSQL does not understand the CASE statement (in 9i it does).  Until then,
use this syntax:

  execute immediate
  'insert into t1(c1,c2,c3)
   select c6, c7,
          case when :v_report_id <> :v_c_eff_rate_id then :v_period_name_2
               else ''RATE %''
          end
     from t2' using :v_report_id, :v_c_eff_rate_id, v_period_name_2;
Review & Followup
Rating: 5
Very good June 25, 2001
Reviewer: Suresh from New York

Rating: 3
"DECODE", version 8.1.7 June 25, 2001
Reviewer: Gov from NJ, USA
You could do this 8.1.7, too.

SELECT
( CASE WHEN &&MTH <= 3 then 'Q1' WHEN &&MTH <= 6 THEN 'Q2' WHEN &&MTH <= 9 THEN
'Q3' WHEN &&MTH <=12 THEN 'Q4' END )
from dual
/

Rating: 5
Use CEIL to achieve the same June 26, 2001
Reviewer: Momen from Riyadh
You could as well use this query,

SELECT 'Q'|| ceil(v_month_start/3) from dual;

June 25, 2001 Bhavesh -- Thanks for the question regarding "Prohibit to Access server Gateway Settings", version 1.0.2.0
You Asked
Hi Tom,
    I have created a web site using iAS 1.0.2.0 and oracle 8i (Rel. 8.1.7). It
is having typical three tier configuration. From the web server I have created
gateway which points to firewall and firewall in turn points to the db. Upto
this point everything is fine. Now my concern is that if someone types
http://www.sitename.com/admin/pls/admin_/gateway.htm
the
user can simply get access to plsql gateway settings which is quite dangerous.
Can you please tell me how can I prevent any user except one logging from local
machine from accessing this url.
Best Regards

Bhavesh
and we said...
Article-ID:         <Note:108661.1>
Circulation:        PUBLISHED (EXTERNAL)
Folder:             internet.Applicationserver.HTTPserver
Topic:              PL/SQL Gateway (mod_plsql)
Title:              How to secure the PL/SQL Gateway Admin Pages
Document-Type:      BULLETIN
Impact:             LOW
Skill-Level:        NOVICE
Updated-Date:       08-JUN-2001 13:06:54
References:
Attachments:        NONE
Content-Type:       TEXT/PLAIN
Keywords:           ADMIN; GATEWAY; IAS; PLSQL; SECURE;
Products:           1042/MODPLSQL;  96/APACHEGW;
Platforms:          GENERIC;

PURPOSE
=======

This article will offer two ways to protect the gateway administration
page of mod_plsql for Oracle Internet Application Server (iAS).

SCOPE & APPLICATION
===================

This article is intended for Oracle Internet Application Server administrators.
It is not intended to provide detailed information on security procedures beyond
the protection of the Gateway configuration pages.

How to secure the PL/SQL Gateway Admin Pages
============================================

By default access to the mod_plsql Gateway administration URL,
http://[hostname]:[port]/pls/admin_/gateway.htm
is not protected. To prevent normal users from changing the configuration
some kind of authentication/protection should be set. This can be achieved
in two different ways.

Using the PL/SQL Gateway authentication scheme
==============================================

There is a provision to restrict access to the PL/SQL Gateway configuration
area, e.g.
http://[hostname]:[port]/pls/admin_/gateway.htm
This is done by changing the parameter "administrators" in your [WVGATEWAY]
section of the wdbsvr.app file. This parameter is set to "all" by default, and
can be
set to a list of comma separated values indicating the list of users which
will have access to the gateway.htm page.
For example, setting "administrators=scott,system" allows only users "scott"
and "system" to access gateway.htm.

In order to get prompted for a password the access to the "admin_" pages
must use a DAD with "dynamic authentication" enabled (no username/password
specified).

Notes:

Do not specify users as administrators that are used for a DAD where static
authentication exists (even if its not the default DAD). If this is done, a URL
like,
http://[hostname]:[port]/pls/[DAD_with_admin_user_specified]/admin_/gateway.htm
would allow access to the Gateway configuration page.

Pros:

PLSQL gateway's method of authentication is to use a cookie
(WDB_GATEWAY_LOGOUT) in conjunction with the Basic Authentication info.
This allows de-authenticatoion by running the built-in command "logmeoff"
by using a URL like,
http://[hostname]:[port]/pls/[DADusedforauth]/logmeoff
The DAD must be specified in the URL as a URL like,
http://[hostname]:[port]/pls/logmeoff
would give an error.

Cons:

The specified administrators can not be the same users used in a static DAD
without compromising security.

If the DAD used for authentication is to be the default DAD, the application URL
will need to contain the DAD name if there is a separate DAD for the
application.

Using the Apache authentication features
========================================

Another way to protect the Gateway page is to use the Apache authentication
features. By adding a "LocationMatch" directive in the plsql.conf you can set
the necessary protections for every URI containing "/pls/[...]/admin_".

For example,

<LocationMatch "/pls(.*)admin_">
   AuthType Basic
   AuthName "Restricted Access"
   AuthUserFile /somedir/userfile
   AuthGroupFile /somedir/groupfile
   require group somegroup
</LocationMatch>

In this example basic authentication is used.

The userfile can be generated using the htpasswd utility.

>htpasswd -c userfile alex
     Creates a password file 'username' with 'alex' as the initial ID.
     It will prompt for the password.

>htpasswd userfile scott
     Adds or modifies in password file 'userfile' the username 'scott'.

The groupfile is a simple textfile listing the groups, for example,

somegroup: alex scott admin

For more info on these directives pls check the Apache documentation at,
http://www.apache.org/docs/mod/mod_auth.html

Pros:

It is possible to use other available Apache authentication mechanisms or
modules.

It is independent from the PL/SQL Gateway.

The same Realm can be used to protect other Apache server content that is for
administrators.

Cons:

Realm based so there is no provided de-authentication feature.
Review & Followup
Rating: 5
Thanks June 28, 2001
Reviewer: Bhavesh
This is what I was looking for. Thanks a million.

Rating: 4
September 17, 2001
Reviewer: Tan Mei Li from Singapore
Certainty this is what I was looking for.  The method described in Oracle Mag :
Expert's guide to OAS/9iAS migration was much difficult to understand.
Thanks

Rating: 4
Was looking for this as well - thanks January 05, 2004
Reviewer: David Rydzewski from Lexington, MA

June 25, 2001 BALASUBRAMANIAN -- Thanks for the question regarding "PLS-00222: no function with name 'TO_DATE' exists in this ", version 8.0.6/8.1.5
You Asked
Hi Tom,
 When I am executing a function to_date(date),it is working in the SQL prompt.
But when I am executing the same function inside a stored procedure, it is
giving the error 'PLS-00222: no function with name 'TO_DATE' exists in this
scope'. What could be the reason ? But If I am using TRUNC(date) function it is
working inside as well as outside the procedure. Why?

I will type my full procedure as follows:

QL> Create or Replace Procedure SP_ADDDEL
  2  (from_date in date, to_date in date) IS
  3  Cursor cur_mas is
  4  select distinct empcode,emp_name,emp_grade,add_type
  5  from tadd_del order by empcode,add_type;
  6
  7  Cursor cur_child(e_code varchar2,e_name varchar2,e_grade varchar2,a_type
char)
  8    is select from_date,to_date,days from tadd_del where empcode = e_code and

  9  emp_name = e_name and emp_grade = e_grade  and add_type = a_type;
 10
 11  ls_code char(5);
 12  ls_name varchar2(40);
 13  ls_grade varchar2(50);
 14  ls_rem varchar2(250);
 15  ls_type char(1);
 16  ld_from date;
 17  ld_to date;
 18  li_days integer;
 19  li_tmp integer;
 20  ld_tfrom date;
 21  ld_tto date;
 22  ld_today date;
 23  Begin
 24  select to_date(sysdate) into ld_today from dual;
 25   Open cur_mas;
 26   Loop
 27    Fetch cur_mas into ls_code,ls_name,ls_grade,ls_type;
 28    Exit When cur_mas%notfound;
 29    Open cur_child(ls_code,ls_name,ls_grade,ls_type);
 30    li_days := 0;
 31    ls_rem := '';
 32    Loop
 33     li_tmp :=0;
 34     Fetch cur_child into ld_tfrom,ld_tto,li_tmp;
 35     Exit When cur_child%notfound;
 36     li_days := li_days + li_tmp;
 37     if ld_tfrom = ld_tto then
 38       ls_rem :=  ls_rem ||' '|| to_char(ld_tfrom) || ',';
 39     else
 40      ls_rem :=  ls_rem ||' '|| to_char(ld_tfrom) || ' to '||to_char(ld_tto)
||',';
 41     end if;
 42    End Loop;
 43    Close cur_child;
 44     ls_rem := substr(ls_rem,1,length(ls_rem) -1);
 45    Insert into tadd_del_report values
(ls_code,ls_name,ls_grade,li_days,ld_today,ls_rem,ls_type)
;
 46   End Loop;
 47  Close cur_mas;
 48  Commit;
 49  End;
 50  /

Warning: Procedure created with compilation errors.

SQL> show error;
Errors for PROCEDURE SP_ADDDEL:

LINE/COL ERROR
-------- -----------------------------------------------------------------
24/1     PL/SQL: SQL Statement ignored
24/8     PLS-00222: no function with name 'TO_DATE' exists in this scope
SQL> select to_date(sysdate) from dual;

TO_DATE(S
---------
23-JUN-01

SQL> select trunc(sysdate) from dual;

TRUNC(SYS
---------
23-JUN-01
and we said...
Well, the fact is that:

  to_date(sysdate)

is a sure way to corrupt a date!  In SQL -- it is converting SYSDATE to a STRING
(there is NO to_date function that takes a DATE as an input and SYSDATE is
already a DATE).  So, it converts sysdate into the string '25-JUN-01'.  Now, it
uses the default date mask to convert that into a date.  The problem is the
century is typically GONE by now and you may get different results on different
databases.

Lose the TO_DATE(sysdate) -- if you want a date without a TIME, simply use
TRUNC(sysdate).

PLSQL is not doing this implicit conversion when it type checks the sql
statement -- since there is no to_date that takes a date, it fails.

To make your coding easier, just code:

...
   ld_today date DEFAULT trunc(sysdate);
....

lose the select into.

followup to comment

it won't cause problems but it could be considered a bad idea (sort of confusing
having a column named to_date)

ops$tkyte@ORA8I.WORLD> create table t ( to_date date );

Table created.

ops$tkyte@ORA8I.WORLD> insert into t values ( sysdate );

1 row created.

ops$tkyte@ORA8I.WORLD> begin
  2          for x in ( select to_date from t )
  3          loop
  4                  dbms_output.put_line( x.to_date );
  5          end loop;
  6  end;
  7  /
25-JUN-01

PL/SQL procedure successfully completed.
Review & Followup
Rating: 4
But June 25, 2001
Reviewer: JN from MA US
Wouldn't line 8
ie
8    is select from_date,to_date,days from tadd_del where empcode = e_code and

also cause a problem?

June 25, 2001 aparna -- Thanks for the question regarding "Usage of LOB's ", version oracle 8i
You Asked
I want to store text files in the database. How to implement the
blob/clob datatypes for the same ?

Can I use PL/SQL and DBMS_LOB package for this purpose ?

Also is it possible to store other file types such as an excel sheet
or word document in the database ? If yes, then how to store, retrieve and
update those file s?

Can you please give some simple examples ?

Thanks,
aparna.
and we said...
To "implement" the blob/clob type -- just create a table with columns of CLOBs
and/or BLOBs.  Use clobs for plain textual data (data you would use "vi" or
"notepad" to edit).  Use blobs for spreadsheets, gifs, and other binary objects.

You can use PLSQL and the DBMS_LOB package, you can use Oci, you can use various
APIs.  See
http://technet.oracle.com/doc/oracle8i_816/appdev.816/index.htm
for docs on using lobs in PLSQL, OCI, Pro*c, Cobol, VB, and Java.  Additionally,
a generic "application developers guide" for LOBs is available.

A simple example to load an existing OS file into the database and then query it
back out follows:

drop table demo;

create table demo
( id        int primary key,
  theClob    clob
)
/

create or replace directory
MY_FILES as '/export/home/tkyte/public_html';

create or replace
procedure load_a_file( p_id in number,
                       p_filename in varchar2 )
as
    l_clob    clob;
    l_bfile    bfile;
begin
    insert into demo values ( p_id, empty_clob() )
    returning theClob into l_clob;
    l_bfile := bfilename( 'MY_FILES', p_filename );
    dbms_lob.fileopen( l_bfile );
    dbms_lob.loadfromfile( l_clob, l_bfile,
                           dbms_lob.getlength( l_bfile ) );
    dbms_lob.fileclose( l_bfile );
end;
/

exec load_a_file( 1, 'index.html' );

select * from demo;

follow up to comment one below

Guiraud --

you must use a DIRECTORY object -- not a path.

In my example above I:

create or replace directory
MY_FILES as '/export/home/tkyte/public_html';

MY_FILES (uppercase) is my directory object.  I use that directory object later:

    l_bfile := bfilename( 'MY_FILES', p_filename );

so, create a directory named MY_FILES.
Review & Followup
Rating: 5
Errors during execution June 25, 2001
Reviewer: guiraud pierre from Albi, in FRANCE
When I do that :

procedure load_a_file(identifiant in number,nom in varchar2,fichier in
varchar2,ladate in varchar2)
is
l_clob clob;
l_bfile bfile;
good_date date;
my_files varchar2(100);
begin
good_date := TO_DATE(ladate,'DD/MM/YYYY','NLS_DATE_LANGUAGE=FRENCH');
my_files :='C:\test\packages\deliberations';
insert into test_insert values ( identifiant,nom,empty_clob(),good_date)
returning c_clob into l_clob;
l_bfile := bfilename( 'my_files', fichier );
dbms_lob.fileopen( l_bfile );
dbms_lob.loadfromfile( l_clob, l_bfile,dbms_lob.getlength(l_bfile));
dbms_lob.fileclose(l_bfile);

When I execute, I obtain that :

ORA-22285: repertoire ou fichier inexistant pour l'operation FILEOPEN
ORA-06512: a "SYS.DBMS_LOB", ligne 475

Rating: 5
I can't create directory June 26, 2001
Reviewer: GUIRAUD Pierre from albi, FRANCE
I'm working with the software "TOAD".
When I create my procedure, if I write
"create or replace directory my_files as
'F:/test/packages'".

I have errors, that's why I would like to work with variables.

HOW CAN I DO WITH TOAD ?

June 26, 2001 Gururaj -- Thanks for the question regarding "1)UTLBSTAT and UTLESTAT 2)WRAP", version 8.X
You Asked
Hi Tom,

1)
I am using Oracle 8.1.5.0. I tried to use UTLBSTAT and UTLESTAT.

i)Connected to database from svrmgrl. Used internal.
ii)executed UTLBSTAT.
iii)Did some database operations from other session.
iv)executed UTLESTAT.
v)as it is documented looked for "report*.*" for results.

I didn't find the results, where did I go wrong ?
Could you guide me ?

2)

I was referring to Wrap utility document on
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a77069/c_wrap.htm#1859
In this document the following is mentioned as a advantage,
"normal importing and exporting--the Import/Export utility accepts wrapped
files"

What does this mean ? Could you explain me ?

Thanks
Gururaj
and we said...
1) you probably were in a directory that did not permit you to write to.  It
uses the spool command to write to the current working directory.

2) it means that if you load wrapped code (obscured code, code that cannot be
read by you and me) the server utilities IMPORT and EXPORT will handle it
properly.

followup to comment

simply edit utlEstat.sql and search for spool:

....
Rem *******************************************************************
Rem              Output statistics
Rem *******************************************************************

spool report.txt;
.....

It creates the file report.txt in the current directory you are in.  make sure
you are using SVRMGRL to run this.
Review & Followup
Rating: 2
June 26, 2001
Reviewer: Gururaj from Norcross, GA USA
Tom, 1) I have administrator privilege on machine and I am using windows NT 4.0
(client). I am working on directory where I have all the privilges. Do you see
any other reason ? I have been trying execute UTBSTAT and UTLESTAT,
to figure out but no luck.

2) Thanks for the wrap utility explaination.

Rating: 4
June 26, 2001
Reviewer: Gururaj from Norcross, GA USA
Thank you very much. I got it.

June 26, 2001 raj -- Thanks for the question regarding "SHMMAX of 4G causes excessive swapping AND SGA/RAM relationship", version 8.1.6 EE
You Asked
Hi Tom,

i searched thru asktom archives first but couldn't find a satisfactory asnswer,
so here is my question:

BACKGROUND: We are running 4 identical (in terms of init.ora) oracle 8.1.6
Enterprise instances on the same sun E420 (solaris 2.7) box which has 1G of RAM.
The total SGA of each of these instances is 125M, so that adds up to 500M for
all 4 instances.

Q.1. Could oracle consume more than 500M of memory at any given point in time?

Q.2 Someone said that if the SGA of an oracle isntance is 125, at times,  some
of the ORACLE processes ( SMON, PMON etc) can consume 125M *each* of memory. Is
this true?

Q.3. Our Sun SysAdmins here claim that setting SHMMAX = 4G causes too much
swapping on the disk and are asking to reduce SHMMAX to 1G (the size of the RAM
on the machine). Is this going to hurt oracle performance in anyway? What is the
lowest we can go on SHMMAX without affecting oracle performance - could SHMMAX
be set equal to the size of the SGA of the largest oracle instance?

Thanks for your patience...

Raj
and we said...
q1) sure, you have just sized up the SGA's, the background processes have their
own needs (dbwr, lgwr, shared servers, dedicated servers and so on)

q2) each of those processes will attach the SGA and some tools like "top" and
"ps" will report that as process memory. see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:562479498141
for a discussion of this.

q3) get a new sysadmin.

SHMMAX = The maximum size(in bytes) of a single shared memory
         segment.

it is a MAX.  It is NOT allocated.  It is a hard limit.  If someone tried to
allocate 4gig-- that would cause swapping.  Until then -- have a hard limit of
4gig is harmless.

Feel free to bump it down to appease them (but its pointless).  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:454420165038
....
Review & Followup
Rating: 5
Precise and Informative June 27, 2001
Reviewer: A reader from New Jersey, USA
Just the info I needed. All questions got answered.

June 26, 2001 Arvind -- Thanks for the question regarding "Transferring data from more than to servers to One common server", version 8.1.6
You Asked
In our company we are having Different Novell Severs for different Divisions.
And each one of them is having its own Oracle. Now We are planning to have one
Corporate Unix Based Oracle Server. My Queries are

1)  Will It increases the performance as regards Speed etc.

2)  How can I import complete data of all the servers in one server.
    I have so many users in each Oracle. And by Using Oracle
    Utilities, If I will take user wise backup, Then all the roles
    etc. assigned to it will be lost. Then what is the best method to
    transfer data to one server?

Regards
Arvind
and we said...
1) sort of impossible to say but if I had to guess I would say "physically
impossible for one machine to do the work of N machines faster".  I would say
"no" -- but then again I don't have all of the facts (eg: are you forced to do
distributed queries now that you won't have to.  are you doing replication now
--adding additional workload that you won't have to in the future.  are you
getting a whopping big machine to replace N little tiny machines and so on)

2) I generally write SQL against the data dictionary (dba_tab_privs,
dba_sys_privs) to generate the GRANTS for a user, then do user level
export/imports.

followup to comment

This would be a candidate for Real Application Clusters (what OPS is being
called in 9i) -- yes.
Review & Followup
Rating: 3
What about option of OPS? June 26, 2001
Reviewer: VJ from Boston, MA USA
I think that, this is a good case for going for OPS. Pl. comment.

Rating: 3
June 26, 2001
Reviewer: A reader
This reply is some what useful for me. But it didn't solved my problem fully

June 26, 2001 Michael -- Thanks for the question regarding "Hiding a Password while using DBMS_OBFUSCATION_TOOLKIT", version 8.1.6.2
You Asked
I need to encrypt a field in a database.  I wrote a function that basically
takes in a string and a password, then calls DBMS_OBFUSCATION_TOOLKIT to
encrypt/decrypt.  Here is the problem, If I hard code the passwrod in the PLSQL
code and wrap it, the password variable is till visible in the wrapped code.  It
shows the binding of it or something.  If I Pass in the variable, what is to
stop a DBA from re-writing the function to display the password?  ANy ideas?
How can I keep this password secure?

Michael
and we said...
If you cannot trust the integrity of your code, you are totally hosed.

Even if you hard coded the password in the PLSQL -- what then, the DBA just
executes your PLSQL.  You cannot put the password in the code.

Using a bind variable is the way to go.  It is true that a motivated DBA can get
this (they can set an event to dump all binds, place trojan horses in the
database and so on).

The problem you describe isn't limited to the password -- what if they rewrote
your procedure as it exists now and just captured the RETURNED data (not the
inputs, not the password but the decrypted results??)

What if they replace the DBMS_OBFUSCATION_TOOLKIT with their own code that calls
the real toolkit -- they would not need access to your stuff at all.

I guess if you cannot trust your DBA at that level, that you suspect they will
actively attempt to crack your data, you must use a client side encrypt/decrypt
and never transmit the key anywhere.  You cannot trust the very code in the
database.

Even if I solved your problem at your procedure -- you still have the core
database code to worry about, they can replace any of that
(DBMS_OBFUSCATION_TOOLKIT).

followup to comment

sure, there are dozens of ways to obscure the password in the wrapped code.
I've done this:

is
   l_piece1 varchar2(1) := 'a';
   l_piece2 varchar2(1) := 'b';
   l_piece3 varchar2(1) := 'c';
   ....
   l_piece25 varchar2(1) := 'y';
   l_piece26 varchar2(1) := 'z';
begin

   .... l_piece6||l_piece8|| .... || l_piece10 ....;

for example.

the problem is that this person cannot trust the DBA even a tiny bit.  A
suggestion like this won't solve their issues -- Their only solution is to do
the encrypt/decrypt outside the application (better not do it in a DLL or .so
file tho! an end user could drop their own in that dynamically loads your dll/so
and does the same thing)
Review & Followup
Rating: 3
June 26, 2001
Reviewer: A reader
I agree with tom.

But if you still want one, have a wrapped package which calls the
OBFUSCATION_TOOLKIT.

Define the password as the concatenation of their character's ASCII equivalent
in the package. (You have to wrap this package)

myPassword varchar2(56) := chr(115) || chr(111) || chr( 109) || chr(101) ||
chr(112) || chr(97) || chr(115) || chr( 115) || chr(119) || chr(111) || chr(114)
|| chr( 100);

The more the characters repeated, the hard to decrrypt the password. In this
example our password is "somepassword" and in the encrypted value you can see
only one "115" and only one "111".

Note: I guess the wrap does some kind of compression.

Regards,

June 26, 2001 -- Thanks for the question regarding "Support for Oracle version 8.1.6 on sun solaris server.", version 8.1.6
You Asked
When is Oracle due to stop supporting this version.
I ask this question due to the problems this version has had.Should we move
straight to 8.1.7 from our current platform of 7.3.4 ?
and we said...
817 would be the correct version -- truth be told -- 901 on solaris would be the
better version.  Why put yourself back a rev?

817 will be the terminal 8i release.  Its the only 8i version you should even
consider.
June 27, 2001 Prince -- Thanks for the question regarding "re: Consistent Reads", version 8.1.6
You Asked
I was reading the following thread,
http://asktom.oracle.com/pls/ask/f?p=4950:8:155624::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:865586003021,
But then why there is "42  consistent gets" in the first case and "2  consistent
gets" in the second case?

I assumed that its the logical reads and shouldn't it be same for both the
cases?

I can understand the physical reads being different "0  physical reads" againt
"6  physical reads", becaz the blocks would be in memory during the second time.

Note: I just want to get a complete understanding on this "consistent gets"

Thank you,
Prince.
and we said...
It had:

...
select * from dept;
Statistics
----------------------------------------------------------
        233  recursive calls
          5  db block gets
         42  consistent gets

....

the 233 recursive calls were the side effect of the hard parse being done on
select * from dept.  You are seeing the effect of the SQL Oracle runs to do your
SQL.

Since the second query found the query plan in the shared pool -- we had:

select * from dept
Statistics
----------------------------------------------------------
          0  recursive calls
          4  db block gets
          2  consistent gets

no recursive SQL.
Review & Followup
Rating: 5
Thats what I wanted June 27, 2001
Reviewer: A reader
Tom:

Thank you very much. It is very clear now..

June 27, 2001 Daniel -- Thanks for the question regarding "Insert rows in PL/SQL ", version 8.1.5
You Asked
Hi Tom,
   I want to insert a larg number of rows from one table to another with PL/SQL
stored procedure.The dest table have a PK,and I can't sure the source table has
distinct key ,also the two tables have too many rows. So I often get the
'DUP_VAL_ON_INDEX' exception .Are there solution to skip dup rows?
             Thanks!
and we said...
insert into T2
select *
  from T1
 where rowid = (select MIN(rowid)
                  from T1 t1_a
                 where T1_a.<columns you consider unique> =
                       T1.<columns you consider unique> )

will work best of course if there is at least an INDEX on the columns you
consider unique in T1..

followup to comment

and if T2 might already have the rows simply add:

and NOT exists ( select NULL
                   from T2
                  where T2.<columns you consider unique> = T1.<columns...> )

to the predicate.
Review & Followup
Rating: 3
I'm doubt if T1 and T2 have some same rows June 27, 2001
Reviewer: A reader
OK ! Now T1 have unique rows,but if T1 and T2 have some same rows,it also raise
exception!

June 27, 2001 -- Thanks for the question regarding "Number of extents in LMT", version 8.1.7.1
You Asked
Hi

I wonder if the number of extents of segments in a Locally Maaged Tablespace
(with uniform size) matters? I have to create several tablespaces for an
application, there are 700 tables and 1900 indexes. The size of these segments
sizes from several KB to GB, I am planning to create just two tablespaces, one
for data and the other for index (with 10 datafiles each), if I use 128K extent
size the big GB tables would have tons of extents and the small tables probbaly
just one extent, is this feasible? I understand that the number of extents does
not affect the perfomance of database so I guess this shouldnt matter?

Or I have to used the old space management strategy, create one tablespace for
very big segments, one for big segments, one for mid-size segments, one for
small segments and one for micro-sized segments?

What would happen if one sgement has 10000 extents in a locally managed
tablespace???
and we said...
No, you want to use 6 tablespaces (if you want to segregate indexes and tables)

You want to get in the habit of creating small, medium and large.

Small with 64k extents
Medium with 1m extents
Large with 128m extents

for example.

I wish that was the "old space mgmt" way -- we would not need LMTs if people did
that all of the time ;)

10,000 extents -- probably too many.  hundreds, low thousands -- just fine.
Review & Followup
Rating: 5
Number of Extents July 06, 2001
Reviewer: Dee from Louisiana, USA
Nice succinct answer for those of us who aren't into doing all the math. Thanks!

June 27, 2001 T.S.V.S -- Thanks for the question regarding "Archive Logs backup", version 8.1.5
You Asked
Dear Tom,

We are using Oracle 8i on Solaris v7.0 Os.
Our DataBase is in Archive log mode. The disk slice size is 2GB, which are
storing archive logs is not mirrored. Eevery 10 days the disk slice is go to
full. Pl. give me suggestions for taking Physical backups of DBF files, Control
Files & RBS and Archive Logs.

Suggestion means in sense of when we take physical backup and after that when we
take archive logs backup and how many days we keep it in not overwritting.

Thanks
Kishore
and we said...
you should be backing up to another location your archives ASAP -- don't skimp
on this -- buy another disk and duplex them!

The alternative is that you will lose data someday.  No doubt.

As for the backup strategy -- you should get them onto two tapes nightly and
then you can clear them from disk.  Always have two copies of them.
June 27, 2001 Antony -- Thanks for the question regarding "OLAP services in Oracle9i", version 9.0.1
You Asked
Hi Tom,
1. Is  OLAP services a part of Oracle9i database Enterprise Edition. Or is it an
extra cost option?
2.Is ETL in the Oracle 9i same as Oracle warehouse builder or is it different?
3.Can Discover3i or discoverer4i bought separately?Read somewhere that it is a
part of Oracle 9iAS ?
Thanks ,
Antony Stanislaus
and we said...
1) Oracle OLAP is an option to EE.

If you goto
http://store.oracle.com/
and click on the 9i EE icon, it'll list the options.

2) no, the ETL enhancements are:

o external tables.  Allows you to attach an external flat file to the database
and treat it as a table.  You do not have to sqlldr and then manipulate -- you
can just manipulate the data using SQL right from the get-go

o multi-table inserts

o upserts (update if exists, insert otherwise)

OWB is still there and does what it does -- it takes advantage of these new
features.

3) I am not a licensing expert but as far as I know -- that is correct, it is
all bundled now.  You would be best off talking to your sales rep.
June 27, 2001 Sathish -- Thanks for the question regarding "user_tables ", version 8.1.7
You Asked
CREATE TABLESPACE MID_DATA11
    DATAFILE 'K:\ORACLEDATAFILES\MD03\MID\DATA\DATA11.DBF' SIZE 409600K
AUTOEXTEND OFF
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 5120K     ONLINE    PERMANENT;

So each extent is 5120K and the db block size being 8k , each extent is 640
blocks .

Now i create a table

SQL> create table emp(empno varchar2(10)) tablespace mid_data11 ;

Table created.
SQL> select segment_name , extent_id , blocks , bytes/1024/1024 "MBytes"
  2  from dba_extents
  3  where segment_name='EMP' ;

EMP
         0        640          5

It just created 1 extent of 640 blocks .

I imported a table from 7.3.4 db called "sub_groups" .

SQL> r
  1  select segment_name , extent_id , blocks , bytes/1024/1024 "MBytes"
  2  from dba_extents
  3* where segment_name='SUB_GROUPS'

SUB_GROUPS
         0        640          5

( Truncated to make it shorter )

SUB_GROUPS
        39        640          5

40 rows selected.

SQL> analyze table sub_groups compute statistics ;

Table analyzed.

Elapsed: 00:00:00.61
SQL> select blocks , empty_blocks from user_tables
  2  where table_name='SUB_GROUPS';

        15        25584

My question is why am i seeing so many empty blocks . When i did the import if
the data could fit into 15 blocks then all it would need is one extent .
why did it create 40 extents ? where am i conceptually wrong ?
where else do i have to look ?

Thanks
Sathish .
and we said...
Look at that import -- it'll have an INITIAL extent size for the table.

If you have a locally managed tablespace with 1meg extents and create a table
with an INITIAL of 10meg, it'll oblige you by allocating 10 1meg extents.

You might have used "compress=y" on the export (which is deadly).  You should
use compresss=N so that exp does not add up all of the extents in the table and
puts them as the initial.

followup to comments 1-3 below

It will use the initial, next, minextents, pctincrease and allocate that much
space.  Eg: you have initial=1m, next = 1m, pctincrease = 50, minextents = 5.
You have an LMT with 0.5m extents.

Oracle will compute:

1+1+(1*1.5)+(1*1.5)*1.5+(1*1.5)*1.5*1.5
---------------------------------------
                                  9.125

round it up to 9.5 and allocate that much space for you.  From then on in -- its
0.5 extents.

By "ignore" -- it does not use the initial/next sizes when creating individual
extents.  It will preallocate as much space as you ask for however.

followup to comment 4 below

you inserted 10,000 number pairs into a table.  That will be much less then 5m
of data.

That table is:

ops$tkyte@ORA8I.WORLD> create table t ( x int, y int ) tablespace system storage
( initial 8k next 8k )
  2  /

Table created.

ops$tkyte@ORA8I.WORLD> insert into t select rownum, rownum from all_objects
where rownum <= 10000;

10000 rows created.

ops$tkyte@ORA8I.WORLD> exec show_space('T');
Free Blocks.............................1
Total Blocks............................19
Total Bytes.............................155648
Unused Blocks...........................0
Unused Bytes............................0
Last Used Ext FileId....................1
Last Used Ext BlockId...................38248
Last Used Block.........................1

PL/SQL procedure successfully completed.

(search for showspace on my site for that procedure if you want it)...  It takes
19 8k blocks -- about 152k.

When you exported, export would have either set initial = 152 (if compress=y) or
8 (if compress=n).

Upon import, with a 5m initial extent, you would get 1 extent.  You would have
had to of generated at least 5.00000001m of data to get more extents (or used a
really big MINEXTENTS)

followup to comment 5 below

compress in exp means "should I compress all of your currently allocated extents
into a single intial extent".  When you say compress=y, exp will sum up all of
the currently allocate extents and that will become your INITIAL.  Consider:

ops$tkyte@ORA8I.WORLD> create table t ( x int ) tablespace system storage (
initial 8k next 8k minextents 10 );

Table created.

ops$tkyte@ORA8I.WORLD> !exp userid=/ tables=t

Export: Release 8.1.6.2.0 - Production on Wed Jun 27 20:26:45 2001
...
About to export specified tables via Conventional Path ...
. . exporting table                              T          0 rows exported
Export terminated successfully without warnings.

ops$tkyte@ORA8I.WORLD> !imp userid=/ full=y show=y

Import: Release 8.1.6.2.0 - Production on Wed Jun 27 20:26:58 2001
...
. importing OPS$TKYTE's objects into OPS$TKYTE
 "CREATE TABLE "T" ("X" NUMBER(*,0))  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRA"
 "NS 255 LOGGING STORAGE(INITIAL 90112
  NEXT 8192 MINEXTENTS 10 MAXEXTENTS 505"
 " PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPAC"
 "E "SYSTEM""
. . skipping table "T"

Import terminated successfully without warnings.

ops$tkyte@ORA8I.WORLD> drop table t;

Table dropped.

ops$tkyte@ORA8I.WORLD> create table t ( x int ) tablespace system storage (
initial 8k next 8k );

Table created.

ops$tkyte@ORA8I.WORLD> !exp userid=/ tables=t

Export: Release 8.1.6.2.0 - Production on Wed Jun 27 20:27:27 2001
....
About to export specified tables via Conventional Path ...
. . exporting table                              T          0 rows exported
Export terminated successfully without warnings.

ops$tkyte@ORA8I.WORLD> !imp userid=/ full=y show=y

Import: Release 8.1.6.2.0 - Production on Wed Jun 27 20:27:31 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to: Oracle8i Enterprise Edition Release 8.1.6.2.0 - Production
With the Partitioning option
JServer Release 8.1.6.2.0 - Production

Export file created by EXPORT:V08.01.06 via conventional path
import done in WE8ISO8859P1 character set and US7ASCII NCHAR character set
. importing OPS$TKYTE's objects into OPS$TKYTE
 "CREATE TABLE "T" ("X" NUMBER(*,0))  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRA"
 "NS 255 LOGGING STORAGE(INITIAL 16384
 NEXT 8192 MINEXTENTS 1 MAXEXTENTS 505 "
 "PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE"
 " "SYSTEM""
. . skipping table "T"

Import terminated successfully without warnings.

See the effect on the initial extent when using the compress=y (default) setting
- the minextents of the first table create get added to the initial extent
Review & Followup
Rating: 5
Thanks June 27, 2001
Reviewer: Sathish from Richmond , VA
It was a test Export/Import . I left compress at default .
I will make sure i set compress=N when i do the final
export . I am also happy i noticed it now during test .

Rating: 5
On Second thoughts ...................... June 27, 2001
Reviewer: Sathish from Richmond , VA
1 - My Import log just says the number of rows imported .

2 - When i use compress=N while exporting ,
Suppose the table in 7.3.4 DB was created with an
initial extent of 3M and next extent of 3M ,
Import will still try to create 3 extents of 1M on
the Locally Managed tablespace that i created .

3- I always thought Locally Managed tablespaces ignored
the storage parameters given during create table statement .

Rating: 3
From the manual June 27, 2001
Reviewer: Sathish from Richmond, VA
Storage Parameters in Locally Managed Tablespaces
When you allocate a locally managed tablespace, you cannot specify default
storage parameters or minimum extent size. If AUTOALLOCATE is specified, the
tablespace is system managed with the smallest extent size being 64K. If UNIFORM
SIZE is specified, then the tablespace is managed with uniform size extents of
the specified SIZE. The default SIZE is 1M.

When you allocate segments in a locally managed tablespace, the storage clause
is interpreted differently than for dictionary-managed tablespaces. When an
object is created in a locally managed tablespace, Oracle uses its INITIAL,
NEXT, and MINEXTENTS parameters to calculate the initial size of the object's
segment

So Tom the storage clause is not ignored but interpreted
differently .
Can you tell me how it is interpreted ?

Thanks !
Sathish

Rating: 3
June 27, 2001
Reviewer: A reader
I tested this scenario, but didn't get it.
what i did is at one database, i created a table named create table testme( a
int, b int) storage(initial 8k next 8k);

begin
for i in 1..10000 loop
insert into testme values (i,i);
end loop;
end;
/

export table testme

then at second database, i create tablespace big_data datafile
'f:\whatever\big_data.dbf' size 300000k extent management local uniform size
5120k;

then i import the file.

i only create 1 extent instead of many, what's different between my scenario and
Sathish's?

Rating: 3
June 27, 2001
Reviewer: A reader
this question give us some scenario that set compress incorrectly can cause
disaster, but what i don't know is
when should we set it to true and when shoule we set it to false?

i don't understand why after we set compress=y, it still cause imported table
generate some many extents, based on my understanding, compress means less,
which means when set it to N, it may cause the scenario that Sathish present,
but if we set Compress=y , it should aviod that situation.

June 28, 2001 OP -- Thanks for the question regarding "PL/SQL Block for inserting data in BLOB type Column !", version 8.1.6
You Asked
Dear Tom,

Hi !

I am very Happy to see you back again.Actually stuck with
a procedure written below.

I am trying to load data in A BLOB datatype of a table.The table
name is btab and it contains 2 columns

i number
j BLOB

I am trying to load the contents of f1.doc file which is existing
under d1 directory on C:.Following is the PROCEDURE TEXT.

create or replace procedure load_a_file(p_file_id IN number)
as
l_blob blob;
l_bfile bfile;
begin
insert into btab values(p_file_id,EMPTY_BLOB());
l_bfile:=bfilename('c:\d1','c:\d1\f1.doc');
dbms_lob.fileopen(l_bfile);
dbms_lob.loadfromfile(l_blob,l_bfile,dbms_lob.getlength(l_bfile));
dbms_lob.fileclose(l_bfile);
end;

Ques 1) The procedure compiles successfully but when I Execute it.
It gives 3 Error Messages

ORA-22285: FILEOPEN
ORA-06512: "SYS.DBMS_LOB"
ORA-06512: "SYSTEM.LOAD_A_FILE"

Kindly help to solve this problem and

Ques 2) Please tell me can I use
the same procedure for Loading a .BMP file contents also.

Ques 3) Is it appropriate to make use of the same procedure
to load more than 5MB image files in the table for BLOB type
column.

Ques 4) If you can tell me how to read the contents of BLOB
from the table through PL/SQL code,I will be very greatful to
you.

Thanks & Regards
OP Lalwani
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:232814159006
it has an example of using loadfromfile and reading a blob back out as well.

You must create a directory object to map a physical directory for use with a
BFILE -- you cannot just specify an arbitrary directory.  You need the create
any directory privelege to create one of these directories.

followup to comment one

You must create a directory object for it.  You can do that dynamically if you
like using EXECUTE IMMEDIATE in plsql.
Review & Followup
Rating: 5
Can I insert documents (.doc) from many directories June 28, 2001
Reviewer: Guiraud Pierre from FRANCE
I know how to insert a document which is in my directory 'MY_FILES' but if I
want to insert one document which is in an other directory, how can I do?????

Rating: 4
June 28, 2001
Reviewer: A reader
Vary Help full, but can you explain please
Where we have to
Clob for which kind files i.g   .txt .doc .sql ?
and
Blob for which kind files i.g  .xls .csv .dbf

Rating: 3
Exactly what I want..! July 05, 2001
Reviewer: Praveen Kumar Talla [Pune] from India [Pune]
It helps me to do what i want in the last week when i was at work. Thanx Tom,
you are providing a great support

Rating: 5
It works March 27, 2002
Reviewer: Chidambara Barathi from Bangalore
Hi Tom,

It works fine..thanks a lot..

June 28, 2001 -- Thanks for the question regarding "multiple questions", version 8.0.5
You Asked
Hi Tom,

Q.1- I have 2 servers with each 2 DB's.
     I am able to connect remote such as:
  SQL>sqlplus user/passwd@DB1-server1.world   or
  SQL>sqlplus user/passwd@DB2-server1.world   or
  SQL>sqlplus user/passwd@DB1-server2.world   or
  SQL>sqlplus user/passwd@DB2-server2.world  .
It is just defined so in tnsnames.ora (with minus sign ).
But if I try to compare to DB's like:
  SQL>select table_name from user_tables@DB1-server1.world
      minus
      select table_name from user_tables@DB2-server1.world;
ERROR at line 3:                            *
ORA-00933: SQL command not properly ended
How can I resolve that problem?

Q.2- I created a unique column named "UNI" on several tables.
     What is the select statment to find the max or min of this
     "UNI" ?

Q.3- How can I store other charcter sets like arabic in database?

Thanks a lot, Nick
and we said...
q1) you need to create a database link and db_links will not have a dash in
them.

create database link db1_server.world
using 'DB1-server1.world';

make sure DB1-server1.world is a TNSNAMES entry on the SERVER (not your client
pc).  DBlinks are done on the server.

q2) its not clear but I assume you mean the min/max uni ACROSS all tables?

select max(uni)
from ( select max(uni) uni from t1
       union all
       select max(uni) uni from t2
       .....
       union all
       select max(uni) uni from tN )

q3) you would use a character set that supports it -- most like UTF8.  You
should take a look at the NLS guide for details on choosing a character set.
June 28, 2001 Andre -- Thanks for the question regarding "OPS$ORACLE", version 816
You Asked
Hi.
When i do

sqlplus system

and dont type a password, this happen:

SQL*Plus: Release 8.0.6.0.0 - Production on Thu Jun 21 14:13:37 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Enter password:
ERROR:
ORA-01005: null password given; logon denied

Enter user-name:

Connected to:
Oracle8 Enterprise Edition Release 8.0.6.2.0 - Production
PL/SQL Release 8.0.6.2.0 - Production

SQL> show user
USER is "OPS$ORACLE"
SQL>

What is it USER "OPS$ORACLE" ? What that user can do in his session ?
Oracle Parallel Server user? But why oracle dont prompt to put a password ?

[],
André.
and we said...
OPS$ stands for OPerating System identified user.

You are logged into the OS as oracle.

Do this:

$ sqlplus /

you'll be right in.  Someone created a user ops$oracle identified externally and
granted them connect (or create session, whatever).

Its just a normal user, it doesn't have to supply a password as Oracle trusts
the OS to supply the username.

I use it for scripts run by cron all of the time - don't have to put passwords
into files.

followup to comment 3 below
See
http://technet.oracle.com/doc/oracle8i_816/nt.816/a73008/ch7.htm#1036322
for how to set this up on windows.
Review & Followup
Rating: 3
Need Help June 27, 2001
Reviewer: Govind from India
I need your help. I am able to find any provision made to ask questions on the
page
http://asktom.oracle.com/pls/ask/
Please help me to post question to your desk. I am having lot of questions to
ask. My email id is wegov@yahoo.com. Please give guidance and link to post
question(exactly).

thanking you
Govind

Rating: 3
Need Help June 27, 2001
Reviewer: Govind from India
I need your help. I am not able to find any provision made to ask questions on
the page
http://asktom.oracle.com/pls/ask/
Please help me to post question to your desk. I am having lot of questions to
ask. My email id is wegov@yahoo.com. Please give guidance and link to post
question(exactly).

thanking you
Govind

Rating: 3
June 28, 2001
Reviewer: Gururaj Kulkarni from Norcross GA USA
Hi Tom ,

I tried creating OS user. Could you tell me why it didn't
work and how can make that work.

1)create user guru identified externally;

2)grant connect,resource to guru

3)c:\>sqlplus /

ERROR ORA-01004 default username feature not supported :
logon denied

Enter user-name : guru
Enter password :
ERROR ORA-01017: invalid username/password ; logon denied

The following is banner from v$version

BANNER
----------------------------------------------------------
Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production
PL/SQL Release 8.1.5.0.0 - Production
CORE Version 8.1.5.0.0 - Production
TNS for 32-bit Windows: Version 8.1.5.0.0 - Production
NLSRTL Version 3.4.0.0.0 - Production

June 28, 2001 Subrato -- Thanks for the question regarding "RMAN Backup and Recovery", version 8.1.7
You Asked
1. I have taken a full hot backup of database using RMAN
2. using list command I have
   list the backupset of tablespace user; it is ok

3. I have intentionally dropped the tablespace user from the database
4. Again using list command I have
   list backupset of tablespace user
   now this time its showing some error that there is no such tablespace by this
name exist in the catalog

Please suggest what could be the reason
and we said...
From the syntax of the list command in the recovery manager documentation:

o The list command will not show any records with DELETED status. To see the
records with DELETED status, query the recovery catalog views. See
Chapter 11, "Recovery Catalog Views".

You want to query

RC_TABLESPACE
   This view lists information about all tablespaces registered in the
   recovery catalog, all dropped tablespaces, and tablespaces that
   belong to old database incarnations. It corresponds to the
   V$TABLESPACE dynamic performance view. The current value is shown
   for tablespace attributes.
   COLUMN             DESCRIPTION
   DB_KEY             The primary key for the target database.
   DBINC_KEY          The primary key for the incarnation of the target
                      database.
   DB_NAME            The DB_NAME of the database incarnation this
                      record belongs to.
   TS#                The tablespace identifier in the target database.
   NAME               The tablespace name.
   CREATION_CHANGE#   The creation SCN (from the first datafile).
   CREATION_TIME      The creation time of the tablespace.
   DROP_CHANGE#       The SCN recorded when the tablespace was dropped.
   DROP_TIME          The date when the tablespace was dropped.
June 28, 2001 -- Thanks for the question regarding "JDK 1.3", version 8.1.5
You Asked
Installed SDK 1.3.1 on Window NT database server for necessary JClasses used.
This is the only version that will work for the Java code.  The install was
sucessful.  When we issue loadjava or dropjava command erros occur.  Javva
classes loaded from jar file are invalid.  The initjvm.sql was run.  The Java
stored procedure contains JDBC.  We are compiling on the server side.  The
current classpath setting is:
C:\JDK1.3.1\BIN;C:JDK1.3.1\LIB;C:\JDK1.3.1\JRE\BIN;C:\JDK1.3.1\JRE\LIB;

We are not using oci8 loadjava option.  These Java Stored procedures have never
worked.  The JDK version is SDK 1.3.1.  The errors that are currently in
DBA_ERRORS table are:
ORA-29521: Referenced Name...Could not be found.

We need to know how to make Oracle point to SDK 1.3.1 so that the classes will
compile.
and we said...
Ok, we have a square peg/round hole problem here.

815 has JDK 1.2 burned into it.  the database is not simply a respository that
holds your classes -- it is a full JVM -- a JDK1.2 JVM.  You are attempting to
use JDK 1.3 and apparently are calling out to java classes that exist in 1.3
(but not 1.2).  Thats your name resolution error.

It matters not what you compile the code with -- if the JVM doesn't have that
jdk level, it won't work.  If you stick with JDK1.2 features -- it'll probably
work (i've seen it work) but as soon as you use a JDK1.3 feature -- it'll stop
dead (that code isn't available to the JVM in the database).
June 28, 2001 raj -- Thanks for the question regarding "How to use &1, &2 etc.. parameters in a PL/SQL block", version 8.1.6
You Asked
Hi Tom,
I have a sqlplus script, in which I accept a username/password as  arguments, I
create the user and grant certain privileges to this user. The 'regular' grants
to stored procedures give no problem but the pl/sql block to grant queue
privileges gives error when I try to use &1 parameter. Is it possible to use the
passed in value in the pl/sql block?

Thanks for your time.
Raj

File cr_user.sql
================

create user "&1" identified by "&2";
...
...
grant execute on stores.proc1 to "&1"; -- these two grants work fine
grant execute on stores.proc2 to "&1";
...
...
begin

--use of '&1' or "&1" in the following statement causes an error--
dbms_aqadm.grant_queue_privilege(privilege=>'DEQUEUE',
queue_name=>'MF.STATUS_QUEUE', grantee=>'&1', grant_option=>FALSE);

commit;
end;
/
and we said...
My guess is you are sending lower case usernames and you are actually creating a
user in lower case (bad bad idea).

By double quoting the "&1" and "&2" -- you are causing us to create the user in
mixed case -- that would:

create user "scott" identfied by "tiger"

that means you cannot:

C:\> sqlplus scott/tiger

as that is really sqlplus SCOTT/TIGER

In the call to grant_queue_privilege, you have not quoted the identified.  So,
you created the user "scott" but are trying to grant to SCOTT.

Suggest you REMOVE all "" from this script.
Review & Followup
Rating: 5
Solved my problem. June 29, 2001
Reviewer: A reader from NJ, USA
Learned that double quotes would preserve the case and that creating a user in
lower case is a "bad, bad idea".

June 28, 2001 Pauline -- Thanks for the question regarding "RE:refresh database ", version 8.1.5,8.1.7
You Asked
Tom,
I can refresh test database by copying all production database files there.
These 2 database are using oracle software with same version and release. Could
I do it between different versions/releases, for example, test site is 8.1.5 and
production site is 8.1.7?

Thanks.

Pauline
and we said...
maybe -- only if the compatible on 817 was set to 815 or lower AND if you used
no new features found only in 816/817 (there are TONS of thoses) and only if you
use the downgrade scripts to revert the data dictionary back to an 815 style
data dictionary.

I would not suggest this.
Review & Followup
Rating: 4
June 29, 2001
Reviewer: Pauline

June 28, 2001 TAPAS -- Thanks for the question regarding "Migrating OCI application from 32-bit Oracle to 64-bit Oracle", version 8.1.7
You Asked
Hi Tom,

We have our C++ applications written using OCI8 libraries and currently they
work on 32-bit Oracle database (8.1.7). For performance improvement reasons, we
are thinking to upgrade our database to 64-bit so that we can use larger SGA.
Our main concern is whether the existing OCI applications will run against the
64-bit databse? Are there any migration issues? I searced a lot in Oracle
documentation and on the web but couldn't find much on this subject. Could you
please share your experience/views on this.

Thanks a lot

Tapas
and we said...
They will.

You can leave your apps as 32bit (probably best).  The issues will be in your
code.  The word size will double, unless you always used sizeof(), properly cast
 everything, were very very careful with pointers and so on -- you'll have bugs.

Your code will not benefit from 64 bits -- in fact, your code would probably run
a little slower.

The database will benefit from it ONLY if you can truly benefit from a massive
SGA.  I've seen databases stop dead as the SGA gets bigger (bigger is NOT always
better -- definitely NOT).  Depends on what you are doing.

As a first step, i would install 64bit and copy my prod database over to it and
just use the 32bit apps and test to see if going 64bit buys me anything.  I
would leave my apps 32bits for the immediate future.
Review & Followup
Rating: 5
Found answer for customer May 06, 2002
Reviewer: Paul Ruscito from Waltham, MA
Tom,

I was about to try and figure out this very question on my own by going through
the doc (God forbid) and decided to take a peek here and found the answer.

Rock on,
Paul

June 29, 2001 -- Thanks for the question regarding "oracle applications pdf files", version 11
You Asked
how can i download pdf files for oracle applications. i mean the user's guide
for modules like general ledger, inventory, etc.
and we said...
Sign up at appsnet, goto the members section.
http://www.oracle.com/appsnet/

it is all there.
June 29, 2001 Pierre -- Thanks for the question regarding "How can i load file (into a clob) from my directories and not specially from the directory created like MY_FILES", version 8
You Asked
This is my program

.....
htp.TableData( cvalue =>'Fichier : ', cattributes=>'BGCOLOR="FFFFCC"' );
        htp.p('<TD>');
        htp.p('<INPUT TYPE="FILE" SIZE="47" NAME="fichier">');
         htp.p('</TD>');
        htp.TableData( cvalue =>' (champs obligatoire pour insertion et
modification)', cattributes=>'BGCOLOR="FFFFCC"' );
.....

good_date := TO_DATE(ladate,'DD/MM/YYYY','NLS_DATE_LANGUAGE=FRENCH');
insert into deliberations values
(seq_delib.nextval,lenom,empty_clob(),good_date)
returning c_clob into l_clob;
l_bfile := bfilename('MY_FILES', fichier);
dbms_lob.fileopen(l_bfile);
dbms_lob.loadfromfile( l_clob, l_bfile,dbms_lob.getlength(l_bfile));
dbms_lob.fileclose(l_bfile);
commit;
ctx_ddl.sync_index( 'pierre.index_clob' );

I want to be able to load a file into my table deliberations without this
description.
I want to load files which are in more directories and I will find them in the
variable "fichier"

Please help me and give me an example to make that.
and we said...
You have to use a directory object in order to use a bfile -- plain and simple.
It is a requirement.

If we let anyone read any directory -- that would be something of a security
issue.  Hence, only those priveleged to execute the CREATE DIRECTORY command are
able to provide access to the filesystem.

You can grant yourself "create any directory" and simply query dba_directories
to see if the directory you want exists.  for example, something like:

function fileopen( p_path_trans in varchar2 ) return bfile
is
    pragma autononomous_transaction; -- does DDL
    l_path  varchar2(2000);
    l_file  varchar2(255);
    l_n     number;
    l_dname sys.dba_directories.directory_name%type;
    l_bfile bfile;
begin
    l_n := instr( p_path_trans, '/', -1 );
    if ( l_n = 0 ) then
        l_n := instr( p_path_trans, '\', -1 );
    end if;

    l_path := substr( p_path_trans, 1, l_n-1 );
    l_file := substr( p_path_trans, l_n+1 );

    for i in 1 .. 2 loop
        begin
            select directory_name into l_dname
              from dba_directories
             where directory_path = l_path and rownum = 1;
            exit;
        exception
            when no_data_found then
                if ( i = 1 ) then
                    select web_bfile_seq.nextval into l_dname from dual;
                    execute immediate 'create directory web_' ||
                                      l_dname || ' as ''' || l_path || '''' ;
                    execute immediate 'grant read on directory web_'
                                      || l_dname || ' to public';
                else
                    raise;
                end if;
        end;
    end loop;

    l_bfile := bfilename( l_dname, l_file );
    dbms_lob.fileopen( l_bfile );
    return l_bfile;
end;
June 29, 2001 -- Thanks for the question regarding "Object Caching Service", version 9i
You Asked
I'm looking for examples code, using the Object Caching Service for Java.
First, I need to understand the main concepts, so I'm using Object Caching
classes (cache.jar) with some code from "Oracle9iAS Object Caching Service for
Java Developer's Guide".
I need some examples (demo applications) using Object Caching Service.
Also, I don't find Javadoc for classes included in cache.jar

Thanks
and we said...
I asked Cameron O'Rourke, our 9iAS expert for some pointers on this one and he
says:

...
You can find OCS4J related material, including a demo and documentation, in
this
http://otn.oracle.com/products/ocs4j/content.html
location on OTN.
Another way to get there, is to go to the Oracle9iAS Container for Java
page, and then click on the Object Caching Services link which is on the
right hand side, in the Related Products and Features Section.

BTW, this
http://www.jcp.org/jsr/detail/107.jsp
JSR was submitted by Oracle
and is based on OCS4J.
....
Review & Followup
Rating: 4
It's very helpful June 29, 2001
Reviewer: A reader from Montreal Canada
Thanks lot

Rating: 4
Please complete the Javadoc July 04, 2001
Reviewer: A reader
The Javadoc is incomplete.

Thanks

June 29, 2001 -- Thanks for the question regarding "dbms_space", version 8.1.6
You Asked
Tom:

why do i need dbms_space package if i can analyze table and get information from
user_tables?
and we said...
analyze is a point in time and takes a bit of time

dbms_space is right here, right now.
June 29, 2001 -- Thanks for the question regarding "efficient way to query count", version 8.1.6
You Asked
Tom:

what is the most efficiency way to know if some kind of row exist or not?

emp(empno,sal,loc);
we want to know if there are somebody have sal>4000.

1.
select count(0) into a where sal>4000
if a>0 the return true;
else return false;

2.
select empno from emp where sal>4000 and rownum<2
return true;
exception
when no_data_found then
return false;

is there any other solution?
and we said...
I myself like:

  select count(*) into l_cnt
    from dual
   where exists ( select NULL
                    from emp
                   where sal > 4000 );

that'll return 0 or 1.  The where exists short circuts after finding the first
row.
June 30, 2001 Pham Quang -- Thanks for the question regarding "Oracle Application Server", version 4082
You Asked
Hi Tom!

I am not familar to Oracle Application Server in Sun Solaris. In my recent
project,
I installed oas4082 in Sun Solaris 5.7 (I created Oracle user and worked with
that user)
 I intended to startups it automatic by creating a file (named S101Oas) in
/etc/rc3.d directory with the
content as following:
   #!/bin/sh
   owsctl start -nodemgr &
   owsctl start &
but when I reboot, there is the error:

/etc/rc3.d/S101Oas: owsctl: not found
/etc/rc3.d/S101Oas: owsctl: not found

Could you explain the reason and Pls, tell me the way to start it automatic.

Thank in advance,

Tien.
and we said...
those scripts are run as root (the etc/init.d scripts are).  you most likely
want to run them as oracle (or set up the root environment so that the command
is in fact found -- but then your webserver is running as root)

something like:

su - oraweb  -c webstart

where ORAWEB is the software owner and they have created a script with all of
the commands necessary to start the apps server.
Review & Followup
Rating: 2
for windows nt July 02, 2001
Reviewer: reader from India
how can start all services of oracle application server when windows nt start

June 30, 2001 M. -- Thanks for the question regarding "Latches, Nested Loop and more...", version 8.1.6
You Asked
Hi Tom,

I have few questions.
1) How do you define LATCHES and where they are used, please any example.

2) What is the Difference in Merg Join and Nested Loop in an output from Explain
Plain.

3) If you have one procedure, is it better to keep it stand alone or put in a
Package? and Why?

4) What is Swapping and Paging, Definitions and any example please.

5) What is the purpose of Connect by and Start with in SQL queries, any example
'll be great.

Thanks for your Time.
and we said...
1) a latch is a lightweight serialization device.  It is used to control access
to a shared data structure.

We use them for example to control access to the shared pool.  When you go to
parse a query, we "latch" (serialize) data structure modifications in the shared
pool.

Latches are typically implemented physically at the hardware level using an
atomic "test and set" command.

2) A nested loop can be thought of as:

 for x in ( select * from T1 )
 loop
     for y in ( select * from T2 where t2.key = t1.key )
     loop
           output X + Y;
     end loop;
  end loop;

A merge join is more like:

   sort t1 into t1_sorted
   sort t2 into t2_sorted

   loop
      read t1_sorted into X
      read t2_sorted into Y
      exit when either of t1_sorted or t2_sorted is out of data

      if ( t1.key = t2.key ) then output X+Y
      elsif ( t1.key < t2.key ) then read t1_sorted into X (catch t1_sorted up)
      else then read t2_sorted into Y (catch t2_sorted up)
   end loop

it is a "merge" of two sorted result sets.

3) always in a package.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:286816015990
4) swapping and paging are OS terms.  swapping is typically done when memory is
really really low.  It "swaps" an entire process out of ram onto disk.  paging
is done when more memory is needed for something but the requests for memory are
still reasonable -- then only unused pieces of programs (pages of programs --
chunks of programs) are paged out to disk.

5) It is for building a hirearchy.  Take the scott/tiger EMP table.  It has an
empno column and a mgr column.  It might be interesting to start with the guy
who has NO MGR (mgr is NULL) and connect to that all records such that their
records MGR is his EMPNO (and then keep doing that for each record)

for example:

scott@ORA8I.WORLD> select lpad( ' ', level*2, ' ' ) || ename ename
  2  from emp
  3  start with MGR is NULL
  4  connect by prior empno = mgr;

ENAME
---------------------------------------------------------------------------------
--------------------------------------------------
  KING
    JONES
      SCOTT
        ADAMS
      FORD
        SMITH
    BLAKE
      ALLEN
      WARD
      MARTIN
      TURNER
      JAMES
    CLARK
      miller

14 rows selected.
Review & Followup
Rating: 5
July 02, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

June 30, 2001 Torrence -- Thanks for the question regarding "Using Bind Variable in a Store Produre", version 8.1.5
You Asked
Hi Tom,

First thanks for the archive information about retrieving multiply rows from a
store procedure.

But now, I must look processing Text data with tick's and other special
characters. How could I implement bind variables in a store procedure to process
a update or insert.

Thanks,

Torrence
and we said...
In PLSQL -- when you use STATIC SQL -- everything is bound for you already.

If you have a procedure:

   is
      l_var1 number;
      l_var2 date;
      l_var3 varchar2(255);
   begin
      .....
      insert into t values ( l_var1, l_var2, l_var3, ... );
   end;

that statement is in fact "bound". PLSQL will rewrite your insert to use binds
where it finds PLSQL variables.

The only time in PLSQL you have to "bind" is when you do dynamic sql.  Never
Never Never code:

   begin
      execute immediate
      'insert into t values ( ' || l_var1 || ', ''' || l_var2 || ''', ''' ||
       l_var3 || ''' )';
   end;

that would glue the constants into the sql statement so that it might look like:

    insert into t values ( 1, '01-jan-00', 'Hello World' );

You want to use bind variables so you would code:

  begin
    execute immediate 'insert into t values ( :x1, :x2, :x3 )'
    USING l_var1, l_var2, l_var3;
  end;

Not only is the code cleaner (no double quoting issues) but it is a million
times more scalable and performant.
June 30, 2001 -- Thanks for the question regarding "Indexes=N", version 8.05
You Asked
Hi Tom
To speed up the import it is recommended to put the indexes=N in the script.
Once the import is done then we have to rebuild the indexes. What does this
"Rebuild" means? Does it mean with the imported data the data in the indexes
from the source is not received in the destination database.
But the Primary Keys are imported even if you put indexes=N?

Thanks
Tansdot
and we said...
Well, look at it this way.  Import will:

o import the table.
o index the table.
o enable the constraints on the table.

Unless you plan on doing the indexes using parallel query, or doing them in
parallel (5 or 10 at a time or something) -- it'll not speed up anything.
import puts the indexes on AFTER the table is loaded.

So, if you were just going to run the indexes manually, just imp.

Else, you can:

imp ... full=y indexfile=index.sql

to get the DDL for the indexes, alter it to do them in parallel or use paralle
query and import with indexes=n.  Then run the index.sql to get the indexes
back.

constraints that require indexes (primary keys) will create them  HOWEVER, you
could import with constraints=n as well and simply uncomment the constraints you
find in the index.sql file as well (it'll have the DDL to recreate the objects
only the indexes will not be commented out)

Try this:

exp userid=u/p tables=some_table
imp userid=u/p full=y indexfile=some_table.sql

to see what you'll have to work with.

(i believe the recommendation you speak of is to drop indexes before importing
lots more data into an existing database and then rebuild them after the load)
Review & Followup
Rating: 4
Possibile enhancement by Oracle July 01, 2001
Reviewer: VJ from Boston, MA USA
The export utility dumps the data out from table. And, if it would be possible
to dump them atleast in PK index order, then we can say constraint=N and
subsequently, the PK Index can be created very fast by using NOSORT option and
using parellel options.

This is just a suggestion for enhancement.

July 01, 2001 balraj -- Thanks for the question regarding "PGA", version 8163
You Asked
1.What part of SGA is given to PGA(when a process starts).Does it consist of

Shared Pool or Database Block Buffers

Is Sort_area_size allocated to each and every PGA running or is it assigned when
required.

2.What all other structures does PGA consist of it.

3.When a particular rows are requested(are the rows are brought to the Block
buffers as it is)

  When a row in block is updated,what all information is sent to redo log
buffers regarding the changes,and how is it managed to match it later to the
actual data blocks in the data files
and we said...
1) PGA is the process global area and is not part of the SGA at all
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:557222937288
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:404110378143

sort area size (of which a single session might have more then one of) amounts
of memory are dynamically allocated as needed.  It is not a static overhead

2) see links above

3) the first part doesn't make sense to me -- when a row is requested (eg: via a
rowid from an index), we look in the buffer cache for the block that contains
the row and if we cannot find it, we read it in from disk.

The bytes needed to redo the action are recorded (as well, the bytes needed to
redo the ROLLBACK that was generated are recorded).  We locate blocks by DBA's
(data block addresses) -- like rowids.  Transaction ids are recorded with it as
well.

July 01, 2001 -- Thanks for the question regarding "Trace
      performace in Pro*C", version 8.1.7

      You Asked
Tom

What are the different ways in which we can trace the peformance statistics of
sql in a pro*c script?

Thank you

      and we said...
My absolute favorite is

http://asktom.oracle.com/~tkyte/tkprof.html
TKPROF.

You can use stats pack at the database as well (but it'll get the the entire
instance, not just your application).

You can snapshot (just create a copy of) the stats in various v$ tables
(v$mystat and v$session_event being the MOST relevant) to see what sorts of
things you did as well -- eg: create a copy of these tables in your app, run
your app, diff the copy with the current and print it out.

There is also Oracle Trace and OEM (enterprise manager) as well.
July 01, 2001 Lydia -- Thanks for the question regarding
      "Autonomous transaction ", version 8.1.7

      You Asked
I'm using ANSI dynamic SQL in a Pro*C program.

I'm looking for a solution for the following problem:

Update Table1 row 10
Update Table2 row 3

Select Table1 row 10 ----> I do not want to see the changes
                           done on row 10 done by the previous update.

Update Table 3 row 4
Commit ;

I thought of an autonomous Tx, but I only found a PL/SQL solution.
Since the SQL statements are dynamic I do not know how to do this.

The code to do the dynamic SQL looks as follows:
--------------------------------------------------

T_result QL_DB_FetchData(T_OutputListGet *ZF_OutputList_ptr)
{
  T_RowLinkedList *ZL_CurrentRow;
  T_RowLinkedList *ZL_NewRow;

  ZL_NewRow = ZF_OutputList_ptr->B_FirstRow_ptr;
  ZL_NewRow->B_Column = NULL ;
  ZL_NewRow->B_NextRow_ptr = NULL;
  ZL_CurrentRow=ZL_NewRow;
  ZG_NbrRows=0;

  EXEC SQL WHENEVER SQLERROR GOTO sql_error;

  EXEC SQL PREPARE ZL_PrepareCursor FROM :ZG_CmdStrCat;
  EXEC SQL DECLARE ZL_CursorGet CURSOR FOR ZL_PrepareCursor;
  EXEC SQL OPEN ZL_CursorGet;
  EXEC SQL DESCRIBE OUTPUT ZL_PrepareCursor
      USING DESCRIPTOR GLOBAL :ZG_OutputDescriptor;
  EXEC SQL GET DESCRIPTOR GLOBAL :ZG_OutputDescriptor :ZG_OraOutputNbrColumns =
COUNT;

  for (ZG_ColCnt = 0; ZG_ColCnt < ZG_OraOutputNbrColumns; ZG_ColCnt++)
  {
    ZG_Occurs = ZG_ColCnt+1;
    EXEC SQL GET DESCRIPTOR GLOBAL :ZG_OutputDescriptor VALUE :ZG_Occurs
             :ZG_OraOutputType[ZG_ColCnt] = TYPE, :ZG_ReturnLength = LENGTH;
    ZG_DefaultType=12;
    strcpy(ZG_OraOutput[ZG_ColCnt],"");

    ZG_ReturnLength = C_MAX_VALUE_LENGTH;

    EXEC SQL SET DESCRIPTOR GLOBAL :ZG_OutputDescriptor VALUE :ZG_Occurs
             TYPE = :ZG_DefaultType, LENGTH = :ZG_ReturnLength, REF DATA =
:ZG_OraOutput[ZG_ColCnt];

  } /* end for loop */

  EXEC SQL WHENEVER NOT FOUND GOTO end_select_loop;
  /* FETCH each row selected and print the column values. */

  for (;;)
  {
    ZL_CurrentRow->B_Column =(T_CellValue
*)malloc(sizeof(T_CellValue)*ZG_OraOutputNbrColumns);
    if (ZL_CurrentRow->B_Column == NULL)
    {
      M_EH_CALL(E_FATAL,
              C_ERRNBR_MemoryAllocation,
              "No memory available",
              sizeof(T_CellValue)*ZG_OraOutputNbrColumns,
              0,0,0);

      return (E_FAILED);
    } /* end if (ZL_CurrentRow->B_Column == NULL) */

    EXEC SQL FETCH ZL_CursorGet INTO DESCRIPTOR GLOBAL :ZG_OutputDescriptor;
    for (ZG_ColCnt = 0; ZG_ColCnt < ZG_OraOutputNbrColumns; ZG_ColCnt++)
    {
      switch (ZG_OraOutputType[ZG_ColCnt])
      {
        case 1 : case 12 :
          strcpy(ZL_CurrentRow->B_Column[ZG_ColCnt].B_u.U_char,
ZG_OraOutput[ZG_ColCnt]);
          ZL_CurrentRow->B_Column[ZG_ColCnt].B_discri = E_CellValue_char;
          break;

        case 2 : case 3 : case 4 : case 5 : case 6 : case 7 :
          ZL_CurrentRow->B_Column[ZG_ColCnt].B_u.U_s_int32 = 0;

          if ( strcmp(ZG_OraOutput[ZG_ColCnt],"") != 0 )
          {
            ZL_CurrentRow->B_Column[ZG_ColCnt].B_u.U_s_int32 =
atol(ZG_OraOutput[ZG_ColCnt]);
          }

          ZL_CurrentRow->B_Column[ZG_ColCnt].B_discri = E_CellValue_s_int32;
          break;

        default:
          M_EH_CALL(E_INFO,
                C_ERRNBR_OutOfRange,
                "Value of variable is out of range",
                ZG_OraOutputType[ZG_ColCnt],
                0,0,0);

          return(E_FAILED);
          break;

      } /* end switch */

      strcpy(ZG_OraOutput[ZG_ColCnt],"");

    } /* end for loop */

      and we said...
Well, I suppose you have your reasons.  The BEST way would be to:

OPEN CURSOR BUT DO NOT FETCH;

Update Table1 row 10
Update Table2 row 3

NOW JUST FETCH FROM OPENED CURSOR.

Update Table 3 row 4
Commit ;

If you cannot do that, another option would be to "trick" the precompiler.  It
would require a double parse ( bummer, hope you don't execute this thousands of
times a date ).  You would parse the string in pro*c to set up the descriptor
but then OPEN it using PLSQL.

Say you have a routine like:

create or replace package types
as
    type cursorType is ref cursor;
end;
/

create or replace
procedure proc( p_cursor in out types.cursorType, p_str in varchar2 )
AUTHID CURRENT_USER
as
    pragma autonomous_transaction;
    l_cursor    types.cursorType;
begin
    open p_cursor for p_str;
end;
/

Then you can:

static void process2()
{
EXEC SQL BEGIN DECLARE SECTION;
    char* dyn_statement = "SELECT ename, empno FROM emp";
    int deptno_type = 3;
    int deptno_len = 2;
    int deptno_data = 10 ;
    int ename_type = 97;
    int ename_len = 30 ;
    char ename_data[31] ;
    int empno_type = 3;
    int empno_len = 4 ;
    int empno_data ;
    long SQLCODE = 0 ;

    SQL_CURSOR  dyn_cursor;
EXEC SQL END DECLARE SECTION;

    EXEC SQL ALLOCATE :dyn_cursor;

    EXEC SQL DELETE FROM EMP;
    printf( "%d rows deleted \n", sqlca.sqlerrd[2] );

    EXEC SQL EXECUTE
    BEGIN
        proc( p_cursor=>:dyn_cursor, p_str=>:dyn_statement );
    END;
    END-EXEC;

    EXEC SQL ALLOCATE DESCRIPTOR 'out' ;
    EXEC SQL PREPARE s FROM :dyn_statement ;

    EXEC SQL DESCRIBE OUTPUT s USING DESCRIPTOR 'out' ;

    EXEC SQL SET DESCRIPTOR 'out' VALUE 1 TYPE = :ename_type,
                    LENGTH = :ename_len, DATA = :ename_data ;

    EXEC SQL SET DESCRIPTOR 'out' VALUE 2 TYPE = :empno_type,
                    LENGTH = :empno_len, DATA = :empno_data ;

    EXEC SQL WHENEVER NOT FOUND DO BREAK ;

    while (SQLCODE == 0)
    {
        EXEC SQL FETCH :dyn_cursor INTO DESCRIPTOR 'out' ;
        EXEC SQL GET DESCRIPTOR 'out' VALUE 1 :ename_data = DATA ;
        EXEC SQL GET DESCRIPTOR 'out' VALUE 2 :empno_data = DATA ;

        printf("\nEname = %s Empno = %d", ename_data, empno_data) ;
    }

    EXEC SQL CLOSE :dyn_cursor;
    EXEC SQL DEALLOCATE DESCRIPTOR 'out';

    EXEC SQL ROLLBACK;
}

See how we delete the rows from emp before opening the dyn cursor but the dyn
cursor will of course still see them since its another transaction
(multi-versioning and read consistency at work).  Additionally we used authid
current_user so as to not make the cursor open with the privs of the definer,
but rather the current user.

This prints out:

Connected to ORACLE as user: /

14 rows deleted

Ename = SMITH                         Empno = 7369
Ename = ALLEN                         Empno = 7499
Ename = WARD                          Empno = 7521
Ename = JONES                         Empno = 7566
Ename = MARTIN                        Empno = 7654
Ename = BLAKE                         Empno = 7698
Ename = CLARK                         Empno = 7782
Ename = SCOTT                         Empno = 7788
Ename = KING                          Empno = 7839
Ename = TURNER                        Empno = 7844
Ename = ADAMS                         Empno = 7876
Ename = JAMES                         Empno = 7900
Ename = FORD                          Empno = 7902
Ename = miller                        Empno = 7934

showing that it works.

Review &
      Followup

      Rating: 5
Autonomous
      Tx  July 02, 2001
Reviewer:  Lydia
       from Belgium
Thanks Tom,

The reason behind this is that we have only one process to
a) configure data by an operator and
b) get data asked for by the real time platform (initialisation of the real time
platform)
The request from the real time platform can come in while the operator is
configuring (worst case between the update and commit). We do not want the real
time platform to see not committed data.
Maybe it would be better to have 2 threads each of them having a seperate
connection, but this would affect a lot of code.
Thanks !

July 01, 2001 Chris -- Thanks for the question regarding
      "Physical sizing of a VARCHAR2 variable", version 8.1.7.0

      You Asked
Hiya,

I was always under the impression that the physical sizing of VARCHAR2 variables
in memory depended on the size of the content of the variable i.e. a variable
declared as VARCHAR2(2000) would only allocate a few bytes of memory for storage
if the data stored in the variable was say 'abcd'.  However, one of our senior
developers is maintaining that for up to VARCHAR2(500) Oracle will always
allocate space sufficient to store 500 characters irrespective of the data in
the variable.  He thinks that it is only once you get over 500 characters does
it become "worth Oracles while" to do dynamic memory allocation for variables.
Therefore it is always better to delcare variables as VARCHAR2(501) ( in his
books ) because that means you always get dynamic memory allocation.  Just
curious as to what you thought.

Cheers

Chris

      and we said...
He is off by 1500 bytes.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1542606219593
It is a tradeoff between speed and less ram usage.  You have to pick and choose.
 If you have a variable that is between 20 and 30 bytes -- using a
varchar2(2000) for it would waste time at runtime (in the grand scheme of
things, whats 30 bytes for a stack variable).

IMHO -- if one way was superior to the other in all cases, we would only provide
one method.  Don't follow strict rules when it comes to this, use variables that
are sized appropriately.  In the grand scheme of things, a couple of bytes for a
stack variable are not going to make or break you.

If you are worrying about this, you are missing the forest for the trees.  There
are lots of other MUCH lower hanging fruit to go after.

If dynamic memory was the fastest, best way to allocate all memory -- languages
like C wouldn't give you stack variables (nor would PLSQL -- it would be trivial
for us to change the way it happens).

Review &
      Followup

      Rating:
      4
  July 02, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia


Subject | Article | Last Updated (East coast time)
Equvivalent function for ISDATE() | article only | Jul 02, 2001 09:00 am
SQL Query speed | article only | Jul 02, 2001 09:21 am
sqlplus - string limitation | article only | Jul 02, 2001 09:28 am
Procedures vs Triggers | article only | Jul 02, 2001 01:08 pm
How to link oracle8.1 and sql-server database , both will be present on different machines. | article only | Jul 02, 2001 02:45 pm
DBMS_JOB | article only | Jul 02, 2001 09:24 pm
import | article only | Jul 02, 2001 09:33 pm
datafile corruption | article only | Jul 03, 2001 09:15 am
insert problem. | article only | Jul 03, 2001 09:50 am
UNCL_ARRAY | article only | Jul 03, 2001 10:48 am
dbms_job | article only | Jul 03, 2001 11:46 am
how to separate index table from data tablespace | article only | Jul 03, 2001 12:12 pm
Problem between long raw and index | article only | Jul 03, 2001 12:14 pm
Handling Sequences in Replication | article only | Jul 03, 2001 12:39 pm
Database trigger | article only | Jul 04, 2001 08:55 am
Suspend rollback | article only | Jul 04, 2001 09:04 am
Equivalent Statement for Transform (Ms-Access) | article only | Jul 04, 2001 09:53 am
datafile corruption | article only | Jul 04, 2001 10:16 am
Incremental Backup - Reg | article only | Jul 04, 2001 10:31 am
A lot of extent means that we need reorganizing table? | article only | Jul 05, 2001 11:14 am
Efficiency/Speed of function columns vs exists in where clause | article only | Jul 05, 2001 11:28 am
To capture exception messages from PRO*C | article only | Jul 05, 2001 11:30 am
Fetching last record from a table | article only | Jul 05, 2001 11:43 am
Column Name | article only | Jul 05, 2001 11:49 am
setting sql_trace=true from pro*c | article only | Jul 05, 2001 02:41 pm
Recording system activity | article only | Jul 05, 2001 04:04 pm
Constraints | article only | Jul 05, 2001 04:07 pm
How to spool in different format | article only | Jul 05, 2001 07:08 pm
Trapping Return Codes from Stored Procedures on Win NT | article only | Jul 06, 2001 09:42 am
datafile corruption | article only | Jul 06, 2001 09:51 am
NT to UNIX | article only | Jul 06, 2001 11:11 am
Tracking Progress Of A Delete Statement | article only | Jul 06, 2001 11:21 am
Processing of Oracle Data | article only | Jul 06, 2001 11:25 am
Cursor | article only | Jul 06, 2001 01:25 pm
iot | article only | Jul 06, 2001 07:02 pm
example for multiple for a partition key | article only | Jul 06, 2001 07:19 pm
Translating a BFILE data type to a directory path and file name via SQL | article only | Jul 06, 2001 07:23 pm
Concatenating Substitution Variables in SQL*Plus | article only | Jul 07, 2001 09:21 am
Objects as input parameter in a Stored Procedure | article only | Jul 07, 2001 11:39 am
Write ahead cache | article only | Jul 07, 2001 04:36 pm
Nested Tables & Ref Cursor - Problems returning rows from Nested table using Ref Cursor | article only | Jul 08, 2001 09:55 am
row(s) 1 - 41 of 41
July 02, 2001 Srinivasan -- Thanks for the question regarding "Equvivalent function for ISDATE() ", version 8 and above
You Asked
Hi Tom,

I've been using Oracle for Sometime now, I use a lot of MSSQL and Sybase, I'm
trying to load some ascii file using SQL Loader(sqlldr), I want to know if there
is any oracle function equvivalent to ISDATE() function in MSSQL or Sybase.

If my Ascii file contains data which is not of date datatype, I want to insert a
NULL instead of loading some wrong data or getting an error in sqlload.

Thanks for your Help
Srini
and we said...
 You can simply:

ops$tkyte@ORA817.US.ORACLE.COM> create or replace
     function my2date( p_str in varchar2 ) return date
  2  is
  3  begin
  4          return to_date( p_str );
  5  exception
  6          when others then
  7                  return null;
  8  end;
  9  /

Function created.

And then in sqlldr, use:

....
date_field   "my2date(:date_field)",
....
Review & Followup
Rating: 5
Equvivalent function for ISDATE() July 02, 2001
Reviewer: Srinivasan Subramanian from Burlingame, CA, USA
Tom, Thanks a ton,
I'm in the Learning process, It didn't strike me to write a function on my own.
It has solved many problems of mine.

July 02, 2001 Paul -- Thanks for the question regarding "SQL Query speed", version 8.1.5
You Asked
Tom,

1. One day, I ran a query by using a select statement on 3 tables with 2 inner
joins. One table with about 400,000 rows and the other two are 400 and 100
respectively. It took about 2 minutes to finish the query. Yet when I changed
one of the inner joins to outer join, the query finished in less than 30
seconds. Can you explain to me why?

2. For the same query, when I ran explain plan on the query, even I had the
proper indexes on those tables, the plan showed only two tables were scanned
with index. The last one, no matter how I specified hints, it was showed being
scanned fully. If I ran a query on first two tables and saved the result set
into a temp table, then ran a second query on the temp table and the third
table, it took much less time than it ran one query with all 3 tables. Do you
think it's always worth to use more queries on select from multi tables?

Thanks,

Paul Huang
and we said...
1) you radically changed the QUESTION and changed the driving table.

You don't specify whether you use CBO, RBO, collect stats or anything.  I'll
hypothesize.

You use RBO (rule based).  You wrote the query:

select *
  from 100_row_table a, 400_row_table b, 400000_row_table c
 where c.c1 = b.c2 and b.c3 = a.c4
/

Using RBO, we would use 400000_row_table as the driving table -- so the join
was:

 for x in ( select * from 400000_row_table ) loop
     for y in ( select * from 400_row_table where c2 = x.c1 ) loop
       for z in ( select * from 100_row_table where c4 = y.c3 ) loop
           output x, y, z
       end loop;
     end loop
 end loop;

You then changed to an OUTER join on the 400000_row_table:

select *
  from 100_row_table a, 400_row_table b, 400000_row_table c
 where c.c1(+) = b.c2 and b.c3 = a.c4
/

Well, now 400000_row_table CANNOT be used as the driving table, either 100 or
400 row table was.  The number of rows processed by the query was significantly
less due to the tables being processed in a better order.

Hint:  analyze your tables and indexes and use the CBO -- it is not sensitive to
the order of columns in the from clause.

there are dozens of other answers for this question.  Use TKPROF
http://asktom.oracle.com/~tkyte/tkprof.html
to see what the plans and amount of work done by each query was.

2) If your query was like the above (no predicates other then joins) -- a full
scan is THE ONLY OPTION.  You need a predicate to use an index and we have to
start somewhere.  What index would you have used on that third table????

DON'T DO THAT TEMP TABLE THING.  You would end up with 2 full scans and really
ugly code.  This is Oracle, not sqlserver.  Do as much work as you can in a
SINGLE QUERY.
Review & Followup
Rating: 5
Ak May 10, 2002
Reviewer: ak from India
Hi tom,
   can You help me to get following output.
1) table A---id varchar(5) -primary key
             stat char(1)
             dt   date

2) table b--id varchar2(5)
            txcode number(3)

3)table c--txcode number(3)
           txdesc varchar2(10)

I want following report....

stat   txdesc  10/05/2002 09/05/2002
x       x1    100       90
y       y1    200       80
z       z1    300       180

I have one not in condition where stat not in ('d1','d2')
Under 10/05/2002 column 100,200,300 is nothing but
count(id) for that date for that status.This should always
display last six days data,like 10,9,8,7,6,5(if i run the
query on 10th).I am using 8.1.5 database,planning to go for
9i.It is basically how many id with perticular status on
perticular date(last six days).There are lots of status like x,x1,x2,x3 etc.

Thanks,

Regards
  Ak

July 02, 2001 Senthil -- Thanks for the question regarding "sqlplus - string limitation", version 8.1.5
You Asked
hi thomas,

a question about sqlplus string limitation.

here are the script i used/called.

testsql.sh
----------
HELLO="jjjjjjjjjjjfasdlkfj dfkjdkjfdkfj la;ksjfasl;dkjfa ;sldk  ;slkdfjasl;dkjf
a;lsjfa asl;dkfja ;slksdjfa;sldfkja;slkdfjal;sdkjflaskdjfa ;sdlfkj asl;jfk as;ld
fkja ;slkjfa;lskdjfal;sdkfj al;sdkjfal;skdjf adlkdjf al;kjfd a;lsdfkjalskdjfl;as
djfasdl;"
sqlplus scott/tiger @check.sql "'$HELLO'"

check.sql
---------
update tt set value = '&&1';
commit;
exit;

SQL> desc tt
 Name                                      Null?    Type
------------------------------- -------- ----------------------------
 VALUE                                              VARCHAR2(4000)

If i run the above shell script(testsql.sh), i am getting this error...

$ sh tstr.sh

SQL*Plus: Release 8.1.5.0.0 - Production on Fri Jun 29 16:56:27 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to:
Oracle8i Release 8.1.5.0.0 - Production
With the Java option
PL/SQL Release 8.1.5.0.0 - Production

string beginning "'jjjjjjjjj..." is too long. maximum size is 239 characters.
SQL>

Is it Oracle limitation or Unix...if i reduce the string length, ie, value for
the variable HELLO, then its updating without any problem. Is there any
workaround for this.

thanks,
senthil.

Updated Information:
No, its not working for me tom, if you have a blank space in the string...it is
skipping the rest.

when i ran the modified script, i got this result...

$ sh tstr.sh

SQL*Plus: Release 8.1.5.0.0 - Production on Mon Jul 2 09:08:57 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to:
Oracle8i Release 8.1.5.0.0 - Production
With the Java option
PL/SQL Release 8.1.5.0.0 - Production

old   1: update tt set value = '&&1'
new   1: update tt set value = 'jjjjjjjjjjjfasdlkfj'

1 row updated.

Commit complete.

Disconnected from Oracle8i Release 8.1.5.0.0 - Production
With the Java option
PL/SQL Release 8.1.5.0.0 - Production
gulper:/home/sramanujam/oracle$

And also the value stored in the table is...

SQL> select * from tt;

VALUE
---------------------------------------------------------------------
jjjjjjjjjjjfasdlkfj

SQL> select length(value) from tt;

LENGTH(VALUE)
-------------
           19

thanks.
and we said...
Ok, i see now, it is a sqlplus DEFINE limit

see
http://technet.oracle.com/doc/oracle8i_816/sqlplus.816/a75664/appc.htm#623300
"User variable value length"   240

You'll have to use the shell to do variable replacement:

#!/bin/csh

dev817
setenv HELLO "jjjjjjjjjjjfasdlkfj dfkjdkjfdkfj la;ksjfasl;dkjfa ;sldk
;slkdfjasl;dkjfa;lsjfa asl;dkfj
a ;slksdjfa;sldfkja;slkdfjal;sdkjflaskdjfa ;sdlfkj asl;jfk as;ldfkja
;slkjfa;lskdjfal;sdkfj al;sdkjfal
;skdjf adlkdjf al;kjfd a;jfl;asdjfasdlafdafdafdafdafdasfdafdafds;"

sqlplus scott/tiger <<EOF

select '$HELLO' from dual;
exit

EOF

works for me.
Review & Followup
Rating: 4
July 02, 2001
Reviewer: A reader

July 02, 2001 Srikrishna -- Thanks for the question regarding "Procedures vs Triggers", version 8.0.5
You Asked
I am trying to tune a trigger of 274 lines code. Since trigger code should not
cross 60 lines according to oracle, I am planing to move this code to a
procedure and calling it from this trigger. This tip I read from some document.

How does it help in terms of performance and memory usage?
and we said...
It is not relevant anymore.  Pre-Oracle7.3, triggers were not stored compiled.
Starting with 7.3 they are.  They are as efficient as procedures.

See
http://asktom.oracle.com/~tkyte/tkprof.html
for info on tkprof, a tool you will find invaluable for tuning Oracle with.
Review & Followup
Rating: 3
Limit on triggers July 03, 2001
Reviewer: Jeroen from Singapore
A good tip.

However, I found that triggers exceeding a source code size larger than 32 KB
(can be checked via column sys.trigger$.actionsize) give problems when trying to
retrieve the source from dictionary views like all_triggers.

Not when you select in SQL*PLUS with a high value for LONG but when you try to
select it into something in PL/SQL.

July 02, 2001 KAVITA -- Thanks for the question regarding "How to link oracle8.1 and sql-server database , both will be present on different machines.", version oracle8.1
You Asked
Hi ,
I have an store procedure in oracle8.1 through which I want to fetch data from
sql-server database which will reside on some other machine.
I know that it is possible to connect 2 oracle databases using create database
link .Is there any way to connect oracle-sqlserver ?

Thanks in advance
Regards
Kavita D.
and we said...
http://www.oracle.com/gateways
You would use the transparent gateway for this.

Alternatively, you could load in the jdbc driver for sqlserver into Oracle and
use a java stored procedure to login to sqlserver and get the data.
Review &
      Followup

      Rating:
      3
  July 03, 2001
Reviewer:
      A reader

July 02, 2001 Suresh -- Thanks for the question regarding
      "DBMS_JOB", version 8.1.7

      You Asked
Tom,
   A trivia question for you.
   I have scheduled a job to run at 10 AM everyday on my test machine. Since I
shut down my machine during weekends, the first thing that I notice on Monday
morning (8 AM) when I startup the database is that the scheduled job starts
running irrespective of what time it is supposed to run. Is this the way it has
been designed to run ?? If so, what if I only want to run the job at 10 AM only
and if the database is shutdown on that day at that time, then it should run
only at 10 AM the nextday when the database is up and not to run until it is 10
AM.

Thanks so much

      and we said...
It does this by design.  Jobs run as soon AFTER their scheduled time as they
can.  The NEXT_DATE is the earliest the job will run -- it can run any time
after that.

The solution for you is to have your JOB look at what time it is and figure out
if it is going to run again today.  Since the NEXT_DATE is the first possible
time it'll run again -- if it finds itself running before 10am on any day, it
knows that it will be run again at 10am.

The job would have at the beginning:

  ...
  if ( to_char( sysdate, 'hh24' ) < 10 )
  then
      return;   -- i do not want to run
  end if;
  ....

and the interval should be:

  decode( sign( to_char(sysdate,'hh24')-10 ), -1, trunc(sysdate)+10/24,
                                                  trunc(sysdate)+1+10/24 )

That will evaluate to

o 10am TODAY if it is currently before 10am TODAY (to get the job to run again
today at 10am)

o 10am TOMORROW if it is after 10am

If you don't want to change the stored procedure, you can just change the job
submission itself:

dbms_job.submit( :job,
                 'begin
                     if ( to_char(sysdate,''hh24'') >= 10 ) then
                         your_procedure;
                     end if;
                  end;',
                  trunc(sysdate)+10/24,
                 'decode( sign( to_char(sysdate,''hh24'')-10 ),
                             -1, trunc(sysdate)+10/24,
                                 trunc(sysdate)+1+10/24 )'
               );

Review &
      Followup

      Rating: 5
Thanks so much
      for the info  July 03, 2001
Reviewer:
      A reader

July 02, 2001 grace -- Thanks for the question regarding
      "import", version 8.1.6

      You Asked
Hi, Tom

I am trying to import a table from a production database (b) to my testing
database (a). Both database are running in unix box. The table in b has initial
298844160 next 33554432 storage setting. when I do a import from a full export
file of b, I get errors ora-01658:unable to create INITIAL extent for segment in
tablespace DATA. Since database a is for testing and small, I only need that
table's structure without data. I don't want to add any datafile in my testing
database. Except manually create this table in my testing system, is there
another way around?
One way I tried is to edit the export file for this table's storage parameter by
using vi. but when I using this edited export file for import, I got error
message imp-00038:could not convert to environment character set's handle.

thank you very much!

grace

      and we said...
You cannot edit a DMP file, its binary.

You can do this:

imp userid=u/p tables=TABLE_YOU_ARE_HAVING_PROBLEM_WITH indexfile=temp.sql

that'll not actually import the data, it'll just plop the DDL to create the
table into temp.sql for you.

Edit this file, change the allocation, run the script.  Then, run

imp userid=u/p IGNORE=Y

That will ignore object creation errors and will just import the data for you.
Review &
      Followup

      Rating:
      4
  July 03, 2001
Reviewer:  grace
       from nj usa

July 03, 2001 Anil -- Thanks for the question regarding
      "datafile corruption", version 8.1.5

      You Asked
Hi tom,
  Y'day mail of yours was very informative,but still i have some
  doubts

1)As you said in case of system datafile corruption,i should have
  some kind of backup.Just assume my database is running in archive
  log mode and i have taken my last hot back up on 20th.
  After ten days my system datafile crashes....And during this ten
  days lot of insert,delete,update has happened.For this last 10 days
  i might not have all the archive log also,because i Generally
  delete all the archive except last 3 days.
  In this scnerio if system datafile crashes,will copying from my
  last backup(10 days old) insures my database is recovered till
  the point when it crashed ??If so how oracle does this,because
  i don't have all the last 10 days archive logs,then the scn info
  will be different from what it was, when i have taken hot backup.
  Controlfile info will be different when i have taken this hot
  backup,so how oracle will make everything in sync.

2) In same case assume i have 10 days old COLD BACKUP,databse in
   archivelog...So when it crashes..i will just copy system datafile
   from my backup dir .And after this i have problem,because i might
   not have all the archive log needed,because as i told you i keep
   only last 3 days archive.So how to come out from this
   situation.

I have lot of confusion over this question,please clarify.
I will appreciate your answer in this regard.

Regards
  ak

      and we said...
1) you have a very bad backup and recovery approach then if you delete your
archives every three days.  The second you deleted an archive and did not make
another backup, you removed your ability to recover using your backups.  They
are totally, wholly useless at that point.

You need to read:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/toc.htm
from cover to cover and gain a better understanding of backup and recovery if
you ever want to be able to recover from a failure.

2) Keep ALL ARCHIVES since you backup.  You also need to keep at least 2
backups.  If you backup weekly, you need to keep:

o the backup from two weeks ago
o the backup from last week
o ALL ARCHIVE log generated for the last 2 weeks.

July 03, 2001 Raghavendra -- Thanks for the question regarding
      "insert problem.", version 8.1.6

      You Asked
hi tom,

I have a problem in inserting a row,
Eg: insert into emp ( ‘ D’souza’ );
If I made ( ‘D’’Souza’) is working  in the back end,
 For example user wants to enter from front end , any solution from oracle side.

thank you
raghavendra

      and we said...
Use bind variables so that you insert:

insert into emp values ( :x )

and bind

D'souza

to :x and then execute the statement.  Bind variables are crucial for
performance, scalability, and the proper usage of oracle.  They will also
obviate the need to double up the quotes.
July 03, 2001 jim
      -- Thanks for the question regarding "UNCL_ARRAY", version 8.1.6

      You Asked
I have just started to look DBMS_UTILITY.COMMA_TO_TABLE and the example uses
UNCL_ARRAY. I can not find any information on this data type, I was able to find
more examples on UNCL_ARRAY but no explanation. Can you help?

Thanks

      and we said...
It is defined in the spec of dbms_utility.  I seriously doubt you want to use
this procedure however.  Here is an extract from my book describing these
procedures:

COMMA_TO_TABLE, TABLE_TO_COMMA

These two utilities either take a comma delimited string of IDENTIFIERS and
parse them into a PL/SQL table (COMMA_TO_TABLE) or take a PL/SQL table of any
type of string and make a comma delimited string of them (TABLE_TO_COMMA). I
stress the word IDENTIFIERS above because COMMA_TO_TABLE uses NAME_TOKENIZE to
parse the strings – hence as we saw in that section, we need to use valid Oracle
identifiers (or quoted identifiers). This still limits us to 30 characters per
element in our comma-delimited string however.

This utility is most useful for applications that want to store a list of
tablenames in a single string for example and have them easily converted to an
array in PL/SQL at runtime. Otherwise, it is of limited use.  If you need a
general purpose “COMMA_TO_TABLE” routine that works with comma delimited strings
of data, see Chapter 20, Using Object Relational Features.  In the “SELECT *
from PLSQL_FUNCTION” section, I demonstrate how to do that.

Here is an example using this routine and demonstrating how it deals with long
identifiers and invalid identifiers:

scott@TKYTE816> declare
  2      type vcArray is table of varchar2(4000);
  3
  4      l_names  vcArray := vcArray( 'emp,dept,bonus',
  5                                   'a,  b  ,   c',
  6                                   '123, 456, 789',
  7                                   '"123", "456", "789"',
  8           '"This is a long string, longer then 32 characters","b",c');
  9      l_tablen number;
 10      l_tab    dbms_utility.uncl_array;
 11  begin
 12      for i in 1 .. l_names.count
 13      loop
 14          dbms_output.put_line( chr(10) ||
 15                                '[' || l_names(i) || ']' );
 16      begin
 17
 18          dbms_utility.comma_to_table( l_names(i),
 19                                       l_tablen, l_tab );
 20
 21          for j in 1..l_tablen
 22          loop
 23              dbms_output.put_line( '[' || l_tab(j) || ']' );
 24          end loop;
 25
 26          l_names(i) := null;
 27          dbms_utility.table_to_comma( l_tab,
 28                                       l_tablen, l_names(i) );
 29          dbms_output.put_line( l_names(i) );
 30      exception
 31          when others then
 32              dbms_output.put_line( sqlerrm );
 33      end;
 34      end loop;
 35  end;
 36  /

[emp,dept,bonus]
[emp]
[dept]
[bonus]
emp,dept,bonus

So, that shows that it can take the string emp,dept,bonus and break it into a
table and put it back together again.

[a,  b,    c]
[a]
[  b  ]
[    c]
a,  b,    c

This example shows that if you have whitespace in the list, it will be
preserved. You would have to use the trim function to remove leading and
trailing white space if you do not want any.

[123, 456, 789]
ORA-00931: missing identifier

This shows that to use this procedure on a comma delimited string of numbers, we
must go one step further as demonstrated below:

["123", "456", "789"]
["123"]
[ "456"]
[ "789"]
"123", "456", "789"

Here it is able to extract the numbers from the string. Note however, how it not
only retains the leading whitespace but it also retains the quotes. It would be
up to you to remove them if you so desire.

["This is a long string, longer then 32 characters","b",c]
ORA-00972: identifier is too long

PL/SQL procedure successfully completed.

And this last example shows that if the identifier is too long (longer then 30
characters) it will raise an error as well – these routines are only useful for
strings of 30 characters or less. While it is true that TABLE_TO_COMMA will take
larger strings then 30 characters, COMMA_TO_TABLE will not be able to undo that
work.

July 03, 2001 -- Thanks for the question regarding "dbms_job",
      version 816.3

      You Asked
hi
can you please tell me how to run a job only from 6am until 10 pm
how would i set up the interval
i want it should run every hour between 6 am and 10 pm
thank you

      and we said...
So, the logic is:

  if ( the time is 6am or later )
  then
      if ( it is before 10am ) then
             return 1 hour from now
      else
             return 6am tomorrow
      end if;
  else (it is before 6am today)
     return today at 6am
  end if;

the decode for that is:

decode( sign(to_char(sysdate,'hh24')-5),
          1, decode( sign( to_char(sysdate,'hh24')-22 ),
                         -1, trunc(sysdate,'hh')+1/24,
                             trunc(sysdate)+1+6/24 ),
              trunc(sysdate)+6/24 )

this just shows what time will be returned given that the job runs at a certain
time (shows what the NEXT_DATE would be if the job was run at "dt" )

ops$tkyte@ORA817.US.ORACLE.COM> select dt, to_char(dt,'hh24'),
  2         decode( sign(to_char(dt,'hh24')-5), 1,
  3                 decode( sign( to_char(dt,'hh24')-22 ),
                 -1, trunc(dt,'hh')+1/24, trunc(dt)+1+6/24 ),
  4                 trunc(dt)+6/24
  5                 )
  6    from ( select sysdate+rownum/24 dt from all_objects where rownum < 25 )
  7  /

DT                   TO DECODE(SIGN(TO_CHAR(
-------------------- -- --------------------
03-jul-2001 12:45:37 12 03-jul-2001 13:00:00
03-jul-2001 13:45:37 13 03-jul-2001 14:00:00
03-jul-2001 14:45:37 14 03-jul-2001 15:00:00
03-jul-2001 15:45:37 15 03-jul-2001 16:00:00
03-jul-2001 16:45:37 16 03-jul-2001 17:00:00
03-jul-2001 17:45:37 17 03-jul-2001 18:00:00
03-jul-2001 18:45:37 18 03-jul-2001 19:00:00
03-jul-2001 19:45:37 19 03-jul-2001 20:00:00
03-jul-2001 20:45:37 20 03-jul-2001 21:00:00
03-jul-2001 21:45:37 21 03-jul-2001 22:00:00
03-jul-2001 22:45:37 22 04-jul-2001 06:00:00
03-jul-2001 23:45:37 23 04-jul-2001 06:00:00
04-jul-2001 00:45:37 00 04-jul-2001 06:00:00
04-jul-2001 01:45:37 01 04-jul-2001 06:00:00
04-jul-2001 02:45:37 02 04-jul-2001 06:00:00
04-jul-2001 03:45:37 03 04-jul-2001 06:00:00
04-jul-2001 04:45:37 04 04-jul-2001 06:00:00
04-jul-2001 05:45:37 05 04-jul-2001 06:00:00
04-jul-2001 06:45:37 06 04-jul-2001 07:00:00
04-jul-2001 07:45:37 07 04-jul-2001 08:00:00
04-jul-2001 08:45:37 08 04-jul-2001 09:00:00
04-jul-2001 09:45:37 09 04-jul-2001 10:00:00
04-jul-2001 10:45:37 10 04-jul-2001 11:00:00
04-jul-2001 11:45:37 11 04-jul-2001 12:00:00

24 rows selected.
Review & Followup

      Rating: 5
Excellent and
      very useful  July 03, 2001
Reviewer:  Bernal
      G.  from Costa Rica

July 03, 2001 Lilian -- Thanks for the question regarding "how
      to separate index table from data tablespace", version 8.1.6

      You Asked
Hi Tom:

in our production there is a tablespace called USER_DATA which included both all
data tables and index tables, i am new in oracle dba career, i would like to
know if i am going to move these index tables from USER_DATA tablespace and
create a new index tablespace to hold these index tables:

1. how should i do it? would you show me some examples?
2. how do i decide a size of index tablespace?
3. if i do rebuild index monthly, would it clean fragmentation of the
tablesapce?

thanks in advance.

an

      and we said...
1) create the new tablespace and then:

alter index INDEX_NAME rebuild tablespace OTHER_TABLESPACE;

this can be on "online" as well.

2) you need to do that based on the size of the indices themselves.  See how big
they are now (select sum(bytes) from dba_segments where tablespace_name =
'USER_DATA' and segment_type = 'INDEX' );

3) don't schedule rebuilds of indexes on a periodic basis.  An index rebuild is
a rare thing to have to do.  Do it only to indexes that need it and only when
they need it.
Review & Followup

      Rating: 3
oracle
      dba  July 03, 2001
Reviewer:  L An
       from DE, USA
thank you very much for your quick response, and it's veru helpful.

July 03, 2001 Pierre -- Thanks for the question regarding
      "Problem between long raw and index", version 8

      You Asked
when I insert data in my table deliberations, automatically my file (.doc) is
inserted in the fields "content" (=long raw) of a table webdb.wwv_document

This table has an index on the field "content" but after my insert i do :
ctx_ddl.sync_index('webdb.index_clob');

My problem is that :

ORA-20000: interMedia Text error:
DRG-10017: you must be CTXSYS or WEBDB to do this: SYNC
ORA-06512: at "CTXSYS.DRUE", line 126
ORA-06512: at "CTXSYS.CTX_DDL", line 1298
ORA-06512: at "PIERRE.TEST_CHARGEMENT", line 104
ORA-06512: at line 5

How can I do to resolve this problem or is there another way to do :

      and we said...
Umm, you need to be webdb or ctxsys to do that as it says.

Create a procedure in webdb's schema that is:

begin
   ctx_ddl.sync_index('webdb.index_clob');
end;

and grant execute on that to pierre.  Alternatively:

Enable automatic index maintenance.  See

http://technet.oracle.com/doc/oracle8i_816/inter.816/a77063/cdefaul6.htm#1000930
for details.

July 03, 2001 DATTA KUMAR -- Thanks for the question regarding
      "Handling Sequences in Replication", version Oracle

      You Asked
Dear Tom,

We cannot replicate sequences, but I read some where that we can do so, by
assuming that we are using them as primary key values, by concatenating them
with something unique to the site.  I am unable to understand the implementation
part.  Please throw light on this.
Thanks
Datta

      and we said...
Don't do that (concatenate).  Rather do this:

o determine the max number of sites you will replicate to.  Say that is 10.

o multiply that by 10 to be safe (100).

o at site 1 (the first site) you would:

  create sequence my_seq start with 1 increment by 100;

  at site 2:

  create sequence my_seq start with 2 increment by 100;

  at site N:

  create sequence my_seq start with N increment by 100;

Now each site generates its own unique stream of numbers.
Review &
      Followup

      Rating: 3
Handling
      Sequences in Replication  July 03, 2001
Reviewer:
      DATTA KUMAR  from NJ, USA
Hi Tom,
Thanks for your spontaneous reply.
Datta

July 04, 2001 Amit -- Thanks for the question regarding
      "Database trigger", version 8.1.6

      You Asked
Tom,

One of our large tables (16Mil rows) in Prod has a database trigger "after
insert" and "after delete" which populates another table(s). We seldom delete
from this table though. Mostly inserts.
Approx.(40K rows / day)

What do think, is it a good idea to convert the database trigger code in to a
stored procedure and call it from the application whenever triggering action
takes place ?

Our application is a mix of Datawarehousing and reporting and I am wanting to
get rid of the database triggers. I am of the opinion that the trigger is
causing some delays in loading data.

Please, explain the illeffects of having a database trigger the application in
view of resources they consume or nature of locks or recursive sql...

Thank you,
Amit.

      and we said...
You may find a stored procedure to be somewhat more efficient then a trigger
doing the same work.

Especially if you combine bulk array processing.  Consider a tiny example:

(13seconds, 9seconds, 1/2 second -- trigger, stored procedure, bulk arrays)

tkyte@TKYTE816> create table t1 ( x int );
Table created.

tkyte@TKYTE816> create table t2 ( x int );
Table created.

tkyte@TKYTE816> create or replace trigger t1_trigger
  2  after insert on t1 for each row
  3  begin
  4          insert into t2 values ( :new.x );
  5  end;
  6  /
Trigger created.

tkyte@TKYTE816> declare
  2          l_start number default dbms_utility.get_time;
  3  begin
  4          for i in 1 .. 40000 loop
  5                  insert into t1 values ( i );
  6          end loop;
  7          dbms_output.put_line( (dbms_utility.get_time-l_start) ||
                                                    ' hsecs' );
  8  end;
  9  /
1298 hsecs

PL/SQL procedure successfully completed.

tkyte@TKYTE816> drop trigger t1_trigger;
Trigger dropped.

tkyte@TKYTE816> truncate table t1;
Table truncated.

tkyte@TKYTE816> truncate table t2;
Table truncated.

tkyte@TKYTE816> declare
  2          l_start number default dbms_utility.get_time;
  3  begin
  4          for i in 1 .. 40000 loop
  5                  insert into t1 values ( i );
  6                  insert into t2 values ( i );
  7          end loop;
  8          dbms_output.put_line( (dbms_utility.get_time-l_start) ||
                                      ' hsecs' );
  9  end;
 10  /
871 hsecs

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816> truncate table t1;

Table truncated.

tkyte@TKYTE816> truncate table t2;

Table truncated.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> declare
  2          type numArray is table of number index by binary_integer;
  3          l_data1 numArray;
  4          l_data2 numArray;
  5          l_empty numArray;
  6          l_cnt   number default 0;
  7          l_start number default dbms_utility.get_time;
  8  begin
  9          for i in 1 .. 40000 loop
 10                  l_cnt := l_cnt+1;
 11                  l_data1(l_cnt) := i;
 12                  l_data2(l_cnt) := i;
 13
 14                  if ( l_cnt = 500 )
 15                  then
 16                          forall j in 1 .. l_cnt
 17                                  insert into t1 values ( l_data1(j) );
 18                          forall j in 1 .. l_cnt
 19                                  insert into t2 values ( l_data2(j) );
 20
 21                          l_data1 := l_empty;
 22                          l_data2 := l_empty;
 23                          l_cnt   := 0;
 24                  end if;
 25          end loop;
 26          if ( l_cnt > 0 )
 27          then
 28                  forall j in 1 .. l_cnt
 29                          insert into t1 values ( l_data1(j) );
 30                  forall j in 1 .. l_cnt
 31                          insert into t2 values ( l_data2(j) );
 32          end if;
 33          dbms_output.put_line( (dbms_utility.get_time-l_start) ||
                        ' hsecs' );
 34  end;
 35  /
60 hsecs

PL/SQL procedure successfully completed.

followup to comment one below

Yes, it is true that as of 7.3 triggers are stored in a compiled format.  Prior
to that, only a stored procedure was stored compiled -- triggers where compiled
the first time they were executed.

Why is a stored procedure faster then the trigger above?  It is just more
efficient to have plsql call the sql directly:

 PLSQL -> SQL
 PLSQL -> SQL

Rather then

  PLSQL -> SQL -> PLSQL trigger -> SQL

is all -- instead of firing up another PLSQL VM (virtual machine) stack in the
trigger, we simply use the plsql environment we have setup.  It is a reduced
code path, less code = faster execution.  A trigger runs in a special
environment, we removed that overhead.

Review &
      Followup

      Rating: 3
Why stored
      procedure efficient than a trigger  July 04, 2001

Reviewer:  KP  from India
Quote "You may find a stored procedure to be somewhat more efficient then a
trigger
doing the same work."

with oracle 7.3 and upwards triggers and  stored procedures
are compiled and stored. Pcode is stored in both the cases.
Theny y stored procedure to be somewhat more effecient then a trigger doing the
same work when both r written in PL/SQL.

July 04, 2001 Paul -- Thanks for the question regarding
      "Suspend rollback", version 8.1.5

      You Asked
Hi Tom,

1. Once in a while, I need to delete large number of rows from a table. I am 100
percent sure those rows are to be removed(no need to rollback the operation).
Since Oracle automatically logs the transaction on its rollback segment, it
takes much longer time and sometimes not sufficient rollback segment error is
raised. How do I tell Oracle to suspend the log ( no logging ) on rollback
segment?

2. I use Oracle jdbc client to develop a connection pool. Yet I can only setup
about 120 concurrent connections to Oracle DBMS before the limit is  reached.
Can you tell me how to increase the number, say up to 500?

Thank you!

Paul Huang

      and we said...
1) You may not need to roll it back but we sure the heck do (power failure in
the middle of your delete would mean a corrupt table when you restarted,
constraint violation on the last row would mean a corrupt table, software
failure would mean corrupt table, and so on)

If you want to get rid of ALL rows, truncate the table.

If you want to get rid of MOST all rows --

Create table temp unrecoverable as select THE ROWS YOU WANT TO KEEP;
truncate the table
insert /*+ APPEND  */ into the table select * from temp;

You cannot disable logging on normal DML.  Only special operations, like a
direct path load, an initial create or rebuild and so on can be done in a
non-logged fashion.  With these operations, if we fail in the middle - we don't
care -- just drop the affected object.

2) one would need to know the exact error message.  I'll guess it is "max
processes exceeded".  Raise your processes init.ora parameter.

followup to comment one

well, I'm disappointed in the comment.

A database is designed to provide highly concurrent, safe, consistent access to
lots of data.  Data integrity is paramount.  As I said -- if a delete failed 1/2
way through for ANY reason -- the table would be totally corrupt -- garbage,
unusable.

I would look at my design if I had tables that I frequently needed to delete
MOST rows from in one fell swoop.  There might be ways -- such as physical table
partitioning -- to make this very very fast.  Given the information I had --
truncate and CTAS are the way to go.

We really don't do extra work for nothing.  Operations that can safely be
performend without logging are permitted to be performed without logging.  Other
operations -- operations that would damage the database in the event of a
failure -- are not.  Data integrity and protection is our first job.

followup to comment two

Excellent -- we can do that very fast.  You have three cases:

some may want 90 days, some want 120 days, some even want 360 days

We can partition data by DATE and RETENTION.   You would be adding partitions to
one end of the table for new data every 90, 120, 360 days and dropping old
partitions with old data at the end of 90, 120 and 360 days.  The removal of
data would be instantaneous -- you could even archive it easily.

Interested in more details??

followup to comment three

You are wrong.  An INSERT is very very different then an UPDATE OR DELETE.

An insert is trivial to do in a non-logged fashion.  We can easily add a new
extent at the "end" of the table and put the new data in there.  If the
operation fails for any reason, that extent just never becomes part of the real
table - no harm done.  The bottom line is with the insert, we can insure that
the new data doesn't get INTERMINGLED with the old data.  We can load it and
attach it to the table without harming anything.

An update or delete on the other hand is terribly intermixed with the EXISTING
data.  If a delete was 1/2 way through and the system crashed -- the table is
now in a totally indertiminate state (eg: corrupt).  It is because an update and
delete work on data that is intermingled with other data that will not be
changing that we cannot do this operation unlogged -- we NEED to be able to
recover the operation else the table is corrupt after any failure.

Review &
      Followup

      Rating:
      3
  July 03, 2001
Reviewer:  Paul
      Huang  from NY USA
I am kind of disappointed to the answer to the question 1. Oracle should allow
users to reorganize data efficiently when we need to get rid of some junks.

Tom made a correct guess on the question 2. It worked like a chime now. The
limit is on the server side, not as I guessed on the client.

      Rating:
      3
  July 04, 2001
Reviewer:  Paul
      Huang  from NY USA
Well, Tom, not all tables are the same.
We have a billing system that downloads activities from our applications across
the nation. We use a table to hold the original records from which we generate
summary reports. Based on the agreement with our clients, we keep the original
records on billing system for certain days -- some may want 90 days, some want
120 days, some even want 360 days. So each week, we need to purge millions of
rows. Yet the table has no relationships to any other tables in the system. If
it fails during the operation, just re-issue the delete statement again. No data
integrity is violated. No transaction is to worry about. Because it's simply a
stand alone table.

      Rating:
      3
Insert  July 04, 2001
Reviewer:  KP
       from India
In the case of insert u said

quote

"like a
direct path load, an initial create or rebuild and so on can be done in a
non-logged fashion.  With these operations, if we fail in the middle - we don't
care -- just drop the affected object."

In the case insert u can do it with non-logged fashion.
Why not the samething can be applied to delete.  Even
if delete fails 1/2 way  or after 99.99% undo it.
How it is to be done is to be viewed at architectural
level.

What i mean to say is what can be done for insert can be done delete and update.

Wheteher the database architecture
supports it or not is different issue.

      Rating: 3
I think Tom
      might have mentioned Direct load insert and nologging  July
      04, 2001
Reviewer:  Ravi Ammamuthu  from CA,US

There is no way of doing the nologging operations for conventional insert. It is
as same as any DELETE or UPDATE operations. Only DIRECT-LOAD insert can be done
with nologging. I think, TOM might have mentioned that.

July 04, 2001 Venkatesh KR -- Thanks for the question regarding
      "Equivalent Statement for Transform (Ms-Access)", version 8i

      You Asked
hi Tom,
Is there any equivalent statement in oracle for Transform Statement
in Ms-Access..Since we are using VB as front end ,initially we were
using MS-Access as Backend..Now,since we had to decide on Oracle as
back-end,we have to convert all the Transform Queries from Access
to their Oracle equivalent..
So,please revert back to me in this...
For Example i have used  a transform query in access to calculate the
count of all bills which are paid /unpaid using a receipt_flag field
which stores a boolean value(Yes for Paid,No for Unpaid)..We require
a transform here since the count of paid/unpaid both come from calculation of 1
field..hope u got it..if not please specify

Example :

Input Table  :
---------------------------------------------
CustomerID    Receipt_Flag
---------------------------------------------
    1        Yes
    2        No
    3        No
    4        No
    5        Yes

Output :
-------------------------------------------
    Paid        Unpaid
-------------------------------------------
     2             3

bye,
Venkatesh

      and we said...
decode:

select sum( decode( receipt_flag, 'Yes', 1, 0 ) ) Paid,
       sum( decode( receipt_flag, 'No, 1, 0 ) ) Unpaid
  from t;

thats it.

Review &
      Followup

      Rating: 5
McAccess to
      Oracle queries  July 05, 2001
Reviewer:
      A reader  from Florida
This was excellent Tom

July 04, 2001 Anil -- Thanks for the question regarding
      "datafile corruption", version 8.1.5

      You Asked
Hi tom,
  According to y'day mail,it look like you haven't understood what i am trying
to say ...So once again I am putting down same.

1)I have NOt said that "EVERY THREE DAYS" I am deleting my archive.
Actual word was i am deleting all the archives "EXCEPT LAST THREE DAYS".AT ANY
point of time i will have last three days archive.
for example.
 i)SAY MY DATAFILE(The one in which we put our data)gets corrupted
on 20th june 2001,so when it gets corrupted i will have
17th,18th,19th,20th archive.Since it was working till 20th,that means
some thing wrong has happened on 20th.so i think keeping last three days archive
should be enough,because when i recover oracle should
ask for maximum of 19th archive or 20th archive(before crash),which
i have,and infact i have recovered many times like this.

If you feel it is NOT enough,please tell me the situation where i might have the
problem.

2)My concern is what if my system datafile gets corrupted.
  i)  I take cold backup on 01 june 2001(all data files)
  ii) Database  is in archive mode.
  iii)Say on 15th june 2001 my system datafile gets
      corrupted,database halts.
  1v) As i told you i am having last three days archive meaning to
      say 12th,13th,14th,15th(till crash) archive i am having.
  v)  Just tell me if i copy 01 june 2001 system datafile(cold backup
      one) back to my database and apply this archive(last three
      days),will it be ok.I just cann't keep all the archive from
      the time i have taken cold backup(i:e from 01 june 2001).
  vi) And also please tell me same case if i have taken hot backup
      in above case i:e on say 01 june 2001.

I have gone thro link given by you.

Expecting your answer in above case.

Regards
  ak

      and we said...
No, I understood you fully.

1) that is what I thought you said -- every third day AFTER you backup, you
delete some archives.

The second you do that -- you made your backup totally useless.  You might as
well erase that as well.  You need to keep ALL archives since your last backup,
the last three days worth is utterly useless.  Just wasting space at that point.

You say "on 20th june 2001,so when it gets corrupted i will have
17th,18th,19th,20th archive."

Well, as I count -- that is 4 days of archives but anyway, you originally said
(quote)

...
  Just assume my database is running in archive
  log mode and i have taken my last hot back up on 20th.
  After ten days my system datafile crashes....And during this ten
  days lot of insert,delete,update has happened.For this last 10 days
  i might not have all the archive log also,because i Generally
  delete all the archive except last 3 days.
....

So, lets work with that example.

o June 20'th, you take a backup.

o It is now June 30'th.  You have the archives from the last 3days (30, 29, 28,
27 -- using your math).

o You restore the backup from the 20'th.  The FIRST archive it is going to want
are the archives generated on the 20'th, then the 21st, 22cnd, 23rd, ... 26th.
NONE of which you have.

Your backup is useless.

Only if the database fails on the 20th, 21st, 22cnd is your approach "ok".

2) for this point the answer is trivial

NO, your database is wiped out.  You can restore to June 1st and that is it.
You lost all work from june 1-15'th.  You don't have the work that was done on
june 2cnd, 3rd, 4th,5th and so on.

Your backup is almost worthless.  The only thing it can do is restore your
database to the point in time of june 1.  Rolling forward is quite impossible.

If you did a HOT backup on June 1 -- your backup is TRULY 100% useless as it
cannot even be restored -- you need the archive redo from june 1 to make the
files consistent.

Again, I urge you to read

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/toc.htm
from cover to cover.
Review & Followup

      Rating: 5
Very
      True  July 05, 2001
Reviewer:  Usama Munir
      Dar  from Islamabad
You Can not expect to make ur files consistent unless u have all the archives
since ur last cold backup. And even in the case of hot backup u can only restore
up to the point u took ur last back and till the day u have ur archives.

July 04, 2001 -- Thanks for the question regarding "Incremental
      Backup - Reg", version 8.1.7.0

      You Asked
Hi Tom

Is it possible to take incremental backup without rman?

Regards

      and we said...
Nope, RMAN is required for that functionality.  You need something smarter the a
simple file copy command -- something has to read the datafiles to find the
blocks that have changed, thats what RMAN does.
Review &
      Followup

      Rating: 3
i think its
      also possible through Export  July 05, 2001

Reviewer:  Vicky

July 05, 2001 Il hwan -- Thanks for the question regarding "A
      lot of extent means that we need reorganizing table?", version 8.0.6.1

      You Asked
how can I recognize table which is requried to reorg for performance?
someone said that We don't have to worry about a lot of extents.
it doesn' influence about performace at all.
But,A lot of extents make SQL resulting in log of disk IO and growing
to be slower in performance,I think.
According to oracle magazine,clustering factor between data and index
is a important factor to make decision that we neeed to reorg.
I wanna know which criteria I can apply to reorg.
which table is truly required to be reorg for performance

      and we said...
A lot of extents is OK, perfectly OK, really truly just fine -- not a problem.
Don't lose a moments sleep over it.  Don't reorg because of it.

If you have a 500 meg table in 1 extent or a 500 meg table in 1,000 extents --
what is the difference in IO (rhetorical question -- the answer is 500meg in
both cases).

If you access a table via an index, the number of extents is truly not relevant.
 We get a file/block/slot on block and do an IO to read that.  Doesn't matter if
the table is in 1 or 10,000 extents.  Does not matter at all.

If you access a table using a full scan, we read the table
db_file_multiblock_read_count blocks at a time.  It will not matter if we have
to read 1 extent, 10 extents, 1,000 extents.  It is not as if the disk heads
will be exactly where you left them (its a multi-user system -- after you
complete your IO the disk is off doing someone elses work).  Even if they were
exactly where you left them -- the operating system does not create contigous
files -- the very next IO you perform might be way over on the other side of the
disk.  Even for a full scan, it matters NOT that the table has many extents.

This is the biggest, hugest myth out there.

As for the cluster factor -- make sure you understand this.  In general (in most
cases) only ONE index per table can be nicely clustered -- all other indexes
will have "bad" cluster factors.

The cluster factor of an index is a rating of how probable that the rows next to
eachother in an index point to the same block (the data in the table is
physically in the same order as the index).   In general ONLY ONE index will
have a really good cluster factor (data can only be sorted in one way after
all).

Consider if ALL_OBJECTS was a table for a moment -- you have an index on
OBJECT_ID and  another on OBJECT_NAME.  Only one of them might be clustered --
if the data is sorted by object_id, object_name is randomly spread throughout
the table.  If the data is sorted by object_name -- object_id is random in the
table.  Consider:

ops$tkyte@ORA817.US.ORACLE.COM> create table t unrecoverable as select * from
all_objects order by object_id;

Table created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> create index t_idx1 on t(object_id);

Index created.

ops$tkyte@ORA817.US.ORACLE.COM> create index t_idx2 on t(object_name);

Index created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> analyze index t_idx1 compute statistics;

Index analyzed.

ops$tkyte@ORA817.US.ORACLE.COM> analyze index t_idx2 compute statistics;

Index analyzed.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> select index_name, CLUSTERING_FACTOR from
user_indexes
  2  where index_name like 'T_IDX_';

INDEX_NAME                     CLUSTERING_FACTOR
------------------------------ -----------------
T_IDX1                                       369
T_IDX2                                     16013

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> drop table t;

Table dropped.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> create table t unrecoverable as select * from
all_objects order by object_name;

Table created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> create index t_idx1 on t(object_id);

Index created.

ops$tkyte@ORA817.US.ORACLE.COM> create index t_idx2 on t(object_name);

Index created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> analyze index t_idx1 compute statistics;

Index analyzed.

ops$tkyte@ORA817.US.ORACLE.COM> analyze index t_idx2 compute statistics;

Index analyzed.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> select index_name, CLUSTERING_FACTOR from
user_indexes
  2  where index_name like 'T_IDX_';

INDEX_NAME                     CLUSTERING_FACTOR
------------------------------ -----------------
T_IDX1                                     15483
T_IDX2                                       369

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

At any point in time the table can be clustered by object_id or by object_name
BUT NOT BOTH.

If you have a really crucial table -- that you do TONS of index range scans on
by some index -- and performance can be increased by clustering the data by that
index you might consider:

o IOT's -- index organized tables
o CLUSTERS -- cluster the data by that key

before you consider re-orging on a regular basis.
Review &
      Followup

      Rating: 5
I'm not
      alone  June 18, 2003
Reviewer:  Bob
      McAusland  from Glasgow, Scotland, UK
Nice to have an expert view on the 'many extents not a problem'.
I've supported this view for many a year, and others seem to be aghast!

July 05, 2001 Easo -- Thanks for the question regarding
      "Efficiency/Speed of function columns vs exists in where clause", version
      7.x - 8.x

      You Asked
Hello,
  I was hoping to get some information on the above mentioned subject.
Assuming that indexes are used in all joins and for a co-related join.

e.g. (not really
Query 1
-------
Select 'x'
  from emp
 where exists (select 'exist'
                 from dept
                where deptno = emp.deptno);

Query 2
-------

Select 'x'
  from emp
 where Deptno_Exists (emp.deptno) = 'Y';

Function Deptno_Exists typically uses the select in the exists clause.

Thanks

      and we said...
If you can do it in sql with native SQL functions it will almost certainly be
faster then having sql call out to PLSQL.

The correlated subquery is better.
July 05, 2001 --
      Thanks for the question regarding "To capture exception messages from
      PRO*C ", version 8.1.5

      You Asked
Hi Tom,
I have a pro*c program to call the stored procedure defined in db. What is the
best way to capture the full stack exception messages encountered?
For example:

  EXEC SQL EXECUTE
      BEGIN
         :iCode := GetCode(:SystemName)
      END;
   END-EXEC;

Thanks.

      and we said...
  1  create or replace procedure p
  2  as
  3  begin
  4     raise_application_error(-20001, 'Error Error' );
  5* end;
ops$tkyte@ORA8I.WORLD> /

Procedure created.

and then code in Pro*C:

static void sqlerror_hard()
{
    EXEC SQL WHENEVER SQLERROR CONTINUE;

    printf("\nORACLE error detected:");
    printf("\n% .70s \n", sqlca.sqlerrm.sqlerrmc);

    EXEC SQL ROLLBACK WORK RELEASE;
    exit(1);
}

static void process()
{
        EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();

        EXEC SQL EXECUTE BEGIN p; END; END-EXEC;
}

and you'll get:

$ ./t

Connected to ORACLE as user: /

ORACLE error detected:
ORA-20001: Error Error
ORA-06512: at "OPS$TKYTE.P", line 4
ORA-06512:

Review &
      Followup

      Rating: 5
Working code is
      always a big help  July 05, 2001
Reviewer:
      Harrison  from Haymarket, VA USA
It is always great to get working code.  It makes me
start to wonder if I'll get to use C again, except
for the fun of it, but I'll file this away with my
good stuff.

July 05, 2001 Hassan -- Thanks for the question regarding
      "Fetching last record from a table", version 8.0

      You Asked
I was wondering if there is some possible way that I can fetch the last record
from a table. In this particular case, obviously one is unaware of the number of
records in a table. All I want is to write a query whcih will simply fetch all
the columns of the last record. I have tried using ROWNUM, but I guess it
does'nt work that way. If I generate a report, then I want to base my report on
the same query whcih will simply fecth all the columns of the last record.

Are there any built-ins in report builder which can fetch the last record of a
table?

Thanks

Hassan

      and we said...
What is your definition of the last record?

You know, the last record inserted may very well be the first record returned by
"select * from t", it may be the 100'th, it may be the 1000'th, it may in fact
be ANY record.

Records are not returned in order of anything.

If you want the last record inserted, you need to have a timestamp or sequence
number assigned to each record as they are inserted, then:

select * from t where TIMESTAMP_COLUMN = ( select max(timestamp_column) from T )
and rownum = 1;

will get the "last" record.  It is the ONLY way.

 followup to the first 6 comments below

Proof by example (this proof shows all of the suggestions below are WRONG - the
ONLY way to do this is to have some column you can order on to find the "last"
row):

If ANY of these approaches worked -- the answer would be 4.  It is NEVER 4
in the following example:

tkyte@TKYTE816> create table t ( x int, a char(2000), b char(2000), c char(2000)
);

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> insert into t (x) values ( 1 );

1 row created.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816> insert into t (x,a,b,c) values ( 2, 'x', 'x', 'x' );

1 row created.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816> insert into t (x,a,b,c) values ( 3, 'x', 'x', 'x' );

1 row created.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816> delete from t where x = 2;

1 row deleted.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816> insert into t (x,a) values ( 4, 'x' );

1 row created.

tkyte@TKYTE816> commit;

Commit complete.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> select x from t where rowid in(select max(rowid) from t);

         X
----------
         3

tkyte@TKYTE816>
tkyte@TKYTE816> select x from t where rownum = 1 order by rowid desc;

         X
----------
         1

tkyte@TKYTE816>
tkyte@TKYTE816> select x from ( select * from t order by rowid desc ) where
rownum = 1;

         X
----------
         3

tkyte@TKYTE816>
tkyte@TKYTE816> select x from t minus select x from t where rownum < (select
count(*) from t);

         X
----------
         3

tkyte@TKYTE816>
tkyte@TKYTE816>

Trust me on this one -- there is exactly ONE way to sort of get the last row
inserted.  You MUST have some column that you can order by.

Rowid - won't work.  Its based on flie/block/slot.  We reuse rowids, we can even
change them (partitioned tables, IOTS).  You might have extent #1 in file 55 and
extent #2 in file 2.   Extent 4 might start on block 555 of file 3, Extent 5
might start on block 2 of file 3.  Rowids are NOT sortable.

Rownum -- doesn't work either, it just doesn't work.

Review &
      Followup

      Rating: 3
Last
      record  July 05, 2001
Reviewer:  AKS
       from India
I think this can be done by using max(rowid) in the where clause.

      Rating: 3
Fetching Last
      Record from a table  July 05, 2001
Reviewer:
      Rajasekar N  from India
Tom,
Can't we fetch the last record like this...?

select * from t
minus
select * from t
where rownum < (select count(*) from t)

      Rating: 3
Fetching Last
      Record from a table  July 05, 2001
Reviewer:
      Rajasekar N  from Mumbai, India
Tom,
Can't we fetch the last record like this...?

select * from t
minus
select * from t
where rownum < (select count(*) from t)

      Rating: 2
Use
      ROWNUM  July 05, 2001
Reviewer:  Dhawal Shah
       from India
This is very much possible with rownum.
The solution which is given here calls for the overhead of
one column.

Though the cost for the following query may be a bit high,
you can reduce the overhead of storing a column.

" select * from emp where rownum = 1 order by rowid desc; "

      Rating: 3
one more way
      ?  July 05, 2001
Reviewer:  Vikram
       from from India
can't we use this ...
select * from t where rowid in(select max(rowid) from t);

      Rating: 3
Last
      row  July 05, 2001
Reviewer:  Danial
       from MD USA
"I think this can be done by using max(rowid) in the where clause" -- would it
still work if you do alot of deletes and updates?

      Rating:
      5
Great  July 05, 2001
Reviewer:
      Reader  from USA
What a greate clarification for a daily misconcept.

Thanks

      Rating:
      5
Great  July 05, 2001
Reviewer:
      Reader  from USA
What a greate clarification for a daily misconcept.

Thanks

      Rating: 2
Fetching last
      record from a table  July 05, 2001
Reviewer:
      DATTA KUAMR  from EDISON, NJ
I feel, whatever Mr.Tom has given is right.  By using select max(rowid) from
table, no doubt gives the result.  If we try this soon after inserting a record
into the table, we will get the correct result.  But, try after inserting a row,
select ... from table, order by ..., and again try select max(rowid) from table,
I am sure you will not get the desired result.

      Rating: 5
Fetching of
      Last Record  July 06, 2001
Reviewer:  Hassan
      Ayub  from Islamabad, PAKISTAN
Thanks a lot Tom for a very thorough and well explained answer.. I tried the
approaches you suggested and you are certainly right!!!

      Rating: 5
clearest
      solution  July 27, 2001
Reviewer:  Daikun
       from Germany
the securest way to get consistent results! once more you made the theory behind
sql and database-concepts clear! This ist more important than using 'dirty'
tricks to improve performance...

July 05, 2001 Guru -- Thanks for the question regarding "Column
      Name", version Oracle 8i

      You Asked
Hi Tom,

I have a table say emp.The table has following columns:

EmpId
EmpName
EmpSal
EmpDesig

This table has 2 million records.One day my PM calls me and asked me to change
the coulmn name say Empsal to EmployyeSalary without changing the filed values
and other things.

I need a SQL Script to change the Column Name without affesting the existing
data / structure / constraints.

Regds
guru

      and we said...
rename table emp to emp_table;

create view emp
as
select empid, empname, empsal employeeSalary, empdesig
from emp_TABLE;

You cannot rename a column directly in Oracle8i and before.  A view is the
proper method for doing that.  Just GRANT on the view what you granted on the
table before ( a simple select against DBA_TAB_PRIVS will give you the info you
need).

follow up to comment one below

Yes, modified to have the correct FROM clause ;)

thanks

followup to comment two below

you missed steps:

0) remove access to the table for the duration of steps 1... on
0.1) find all child tables and disable their foreign keys
....
5) replace all constraints
6) find all child tables and enable their foreign keys
7) add all triggers
8) do all grants

I myself prefer the view over drop/recreate every time.  No muss, no fuss, no
lost constraints, no down time.

Dropping and recreating the table is an option but it consists of TONS more work
for something that could be done in a very trivial fashion.

This is what a view is really good for.

followup to comment 3 below

My solution is to:

rename table emp to emp_table;

create view emp
as
select empid, empname, empsal employeeSalary, empdesig
from emp_TABLE;

The applications will all see EMP -- however, since the column name is changed
you need to revist all applications anyhow (even if you drop and recreate).

I sort of think changing a column name midstream is silly myself (there are lots
bigger fish to fry) but.....

So, you would have to revisit all applications but not because you are using a
view, because you are changing a column name.

Review &
      Followup

      Rating: 4
From Emp again?
      Or from emp_table?  July 02, 2001
Reviewer:
      Reader  from US
Is it really should be:
" as....
from emp_table"?

Thanks

      Rating: 2
column name
      change  July 03, 2001
Reviewer:  DATTA KUMAR
       from EDISON, NJ
What you have given is perfect.  I feel this is one of the alternatives  :

1.  create table emp1
    as select EmpId, EmpName, EmpSal EmployeeSalary,
    EmpDesig from emp;

2.  drop table emp;

3.  rename table emp1 to emp;

4.  re-create index.

Please let me have your comments.

      Rating:
      4
  July 05, 2001
Reviewer:  Sudip
      Sarkar  from Calcutta, India
Hi!Tom
I feel that creating a view in this case will result into major change in the
application code i.e. where ever the the old tablename is refered will now have
to be changed to the view name.
Pl. Correct me if I am wrong.

July 05, 2001 -- Thanks for the question regarding "setting
      sql_trace=true from pro*c", version 8.1.7

      You Asked
Tom

Can you give me an example as to how to set sql_trace=true from within a pro*c
program, and then turn it off at the end of the program..

Further, can you suggest me a good book or web site to learn pro*c.

I went to barnes and noble to buy your book, but they could not locate.. is your
book released, or is it delayed..

thank you

      and we said...
exec sql alter session set sql_trace=true;

exec sql alter session set sql_trace=false;

I myself learned everything I know about pro*c from

http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76942/toc.htm
I am not personally aware of any 3rd party books to recommend.

the book is out and shipping:

http://shop.barnesandnoble.com/booksearch/isbnInquiry.asp?isbn=1861004826
http://www.amazon.com/exec/obidos/ASIN/1861004826

July 05, 2001 -- Thanks for the question regarding "Recording
      system activity", version 817

      You Asked
Hello Tom
Im a new dba in my company. Im trying to document & understand my database. What
is the best way to go for Recording the peak , normal & normal activity periods.
Should I run the ultbstat in the morning & ultestat at the end of the day;should
I monitor the waits of the system ,shared_pool_size for memory.What other things
to look for.
Could you please help me in how to go about this ?
Thanks

      and we said...
I would (and do) use statspack for this.  Infinitely superior to utlestat/bstat
-- better report, better snapshot capability.

You could set it up to snapshot stats every hour and then generate reports that
spanned any of those hours.  bstat/estat wouldn't let you do that.

goto

http://www.oracle.com/oramag
and search for statspack for details.
July 05, 2001 Cindy -- Thanks for the question regarding
      "Constraints", version 7.3.3.4 & 8.1.7

      You Asked
How to add a constraint to a existing table that DOES NOT allow %
character(symbol) to be inserted into a particular field of a table? I have
tried this:
ALTER TABLE tablename
ADD CONSTRAINT "constraint_name" CHECK (field_name NOT LIKE '%%%' ESCAPE '')

But it seems like this constraint did not kick in, because it still allow me to
insert this % symbol into that field_name of the table. Have any idea why or
have alternative solution to is issue?

Thanks!
-- Cindy

      and we said...
ops$tkyte@ORA817.US.ORACLE.COM> create table t
             ( x varchar2(20) check ( x not like '%\%%' escape '\' ) );

Table created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'hello world' );

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'hello%world' );
insert into t values ( 'hello%world' )
*
ERROR at line 1:
ORA-02290: check constraint (OPS$TKYTE.SYS_C0016438) violated

Your escape was "null" letting anything in.
July 05, 2001 Menaka -- Thanks for the question regarding "How
      to spool in different format", version 8.0.5

      You Asked
Hi TOm,

How can i spool query results from sqlplus to excel sheet or lotus 123
directly..

If say for example

Spool c:\menaka.xls and run the query and if i try to open menaka.xls...i could
not open it...

Please let me know how can i do this?

Thanks
Menaka

      and we said...
Well, you need to create a file format that excel can understand.  The normal
output of a query is a report -- excel won't read that.

You have at least two choices

o CSV (comma separated values)
o SYLK

See

http://osi.oracle.com/~tkyte/flat/index.html
for #1
and

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:728625409049
for #2

July 06, 2001 Anirban -- Thanks for the question regarding
      "Trapping Return Codes from Stored Procedures on Win NT", version 3.x

      You Asked
I  am using a 3rd party scheduler on NT to schedule Stored Procedures
within an Oracle 8.1.6 database on NT.
I need to be able to trap the return codes (SUCCESS/FAILURE/User-Defined)
from the Stored Procedure  so that the scheduler
can access  this and make a decision as to whether it should process
the next step of the job stream or not.
In UNIX the output of PUT_LINE can be piped into a shell variable,
but can this be achieved on NT ? I would like to avoid creating
a file that contains the return code.
Any help, possibly with an example, would be appreciated.

Thanks

      and we said...
Why wouldn't you use the native job scheduling facility (DBMS_JOB) inside of the
database?  Then you just schedule one procedure that runs the procedures --
detecting errors and such??

Portable, works the same everywhere, you already have it, only runs IF the
database is up, etc....

anyway, if you really want to do it in a cmd file (not much of a programming
language is it) you can:

-------------------------------------------------------
sqlplus tkyte/tkyte @ok.sql
IF %ERRORLEVEL% LEQ 1 goto okay1
echo Error Error -- run away
goto done
:okay1

sqlplus tkyte/tkyte @bad.sql
IF %ERRORLEVEL% LEQ 1 goto okay2
echo Error Error -- run away
goto done
:okay2

echo Success!
:done
-------------------------------------------------------

if you set up ok.sql to be:

whenever sqlerror exit failure
select * from dual;
exit

and bad.sql to be:

whenever sqlerror exit failure

begin
  raise_application_error(-20001, 'failure' );
end;
/

exit

you'll see you can capture failures just by letting them propagate out of
sqlplus.

July 06, 2001 Anil -- Thanks for the question regarding
      "datafile corruption", version 8.1.5

      You Asked
Hi tom,
 Simply excellent,yes this is what i will say to your explanation of
my datafile corruption.But i still have little doubt

1)Assume my database is running(in archive mode) and suddenly i see
my system datafile gets corrupted(say on 15 june 2001),and ofcourse i have
archive for last three days(12,13,14,15(here i am saying
15th because it is possible that it might get crashed as soon as
clock moves to 12 a.m,using this math i include 15th also),the
bottomline is i have archive from last three days till it crashed, say on 15
morning anytime.I know i can recover anytime datafile(transaction one ,because i
have done that),but i am not sure whether this archive will be sufficiant
to recover system data file.If this is sufficient how redo log
maintence system datafile info in archive ??Because normally redolog will have
transaction details and so is the case for archive log file..
If I am wrong please clarify...

2) Another question is do we have anything like #define of C
in pl/sql
 In c we say #define a=sqrt(25)
and we use this a whereever we want,i am just looking something like
this in pl/sql,can you help me on this ..

Thanks,

Regards
  Ak

      and we said...
If you have a corrupted datafile -- we call that a MEDIA FAILURE -- you need to
take the last backup and apply ALL intervening archived and online redo log
files.

If you backed up your system datafile on the 12-15'th - you are OK.  If you
backed it up on the 11'th, you are not.  You cannot recover that file (because
you erased the archives from the 11th)

Closest thing we have to a #define is a CONSTANT

tkyte@TKYTE901.US.ORACLE.COM> declare
  2  x constant number default sqrt(25);
  3  begin
  4  null;
  5  end;
  6  /

PL/SQL procedure successfully completed.

July 06, 2001 Suresh -- Thanks for the question regarding "NT
      to UNIX", version 8.1.7

      You Asked
Tom,
   We have just developed our application on NT box using Oracle 8.1.7, VB and
Crystal Reports. We are planning to move our application to UNIX very soon. Any
idea or advise about the types of issues that we may have to face in the new
environment will be highly appreciated. As always, thank you so much for your
guidance.

      and we said...
Well, I don't know about VB and Crystal Reports on Unix -- you'll have to ask
those vendors about that.

Oracle is Oracle is Oracle.  It'll be very much the same.  Your DBA will be most
impacted, make sure they have Oracle/Unix experience.

To the developer, they will never know.
July 06, 2001 elie
      -- Thanks for the question regarding "Tracking Progress Of A Delete
      Statement", version oracle 8.1.7.0

      You Asked
Sometimes I run a DELETE statement that takes a long time to complete.  I have
often wondered how many rows have already been deleted so that I can decide
whether or not to abort the statement.  Is there a way to display how many rows
have been deleted while the DELETE is occurring?

Thank you.

Elie Grunhaus
egrunhaus@concentrix.com

      and we said...
Sure, I cannot tell you the rows but for any long running query we can get lots
of good info.

I loaded a table with 1.5 million rows and then issued "delete from t".  Gave it
a bit of time to run and then queried (the SID of the delete was 17, found that
in v$session) :

ops$tkyte@ORA817.US.ORACLE.COM> exec print_table( 'select * from
v$session_longops where sid = 17 and time_remaining > 0' )

SID                           : 17
SERIAL#                       : 84
OPNAME                        : Table Scan
TARGET                        : OPS$TKYTE.T
TARGET_DESC                   :
SOFAR                         : 6415
TOTALWORK                     : 23601
UNITS                         : Blocks
START_TIME                    : 06-jul-2001 11:13:33
LAST_UPDATE_TIME              : 06-jul-2001 11:17:56
TIME_REMAINING                : 705
ELAPSED_SECONDS               : 263
CONTEXT                       : 0
MESSAGE                       : Table Scan:  OPS$TKYTE.T: 6415 out of 23601
Blocks done
USERNAME                      : OPS$TKYTE
SQL_ADDRESS                   : 83255028
SQL_HASH_VALUE                : 4031062735
QCSID                         : 0

And then later:

ops$tkyte@ORA817.US.ORACLE.COM> exec print_table( 'select * from
v$session_longops where sid = 17 and time_remaining > 0' )
SID                           : 17
SERIAL#                       : 84
OPNAME                        : Table Scan
TARGET                        : OPS$TKYTE.T
TARGET_DESC                   :
SOFAR                         : 9450
TOTALWORK                     : 23601
UNITS                         : Blocks
START_TIME                    : 06-jul-2001 11:13:33
LAST_UPDATE_TIME              : 06-jul-2001 11:20:11
TIME_REMAINING                : 596
ELAPSED_SECONDS               : 398
CONTEXT                       : 0
MESSAGE                       : Table Scan:  OPS$TKYTE.T: 9450 out of 23601
Blocks done
USERNAME                      : OPS$TKYTE
SQL_ADDRESS                   : 83255028
SQL_HASH_VALUE                : 4031062735
QCSID                         : 0
-----------------

It shows how long the statement is running and even tries to guess as to how
long it'll take.  You can see in this case the number of blocks processed so
far...

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1035431863958
for print_table if you like that output...

Review &
      Followup

      Rating: 5
Tracking
      Progress Of A Delete Statement  July 06, 2001

Reviewer:  Elie Grunhaus  from Rochester, NY USA

Thanks very much for the QUICK response!  I like the expertise available to me
through your column.  It makes my job much easier.

July 06, 2001 Ron -- Thanks for the question regarding
      "Processing of Oracle Data", version Oracle 8i

      You Asked
Tom:
     I am working on a project to convert a Mainframe System(Marketing) to a
Unix  System using an ORACLE Database. I am testing
 some logic on the employee table.
      The starting Oracle Table would be in size about 30GB.
The primary key would be account #.  The client would  want the
accounts to be tagged e.g. 'If credit score < 120 and credline < 5000  then
assign code = 'n001'. There would be about 120 of
conditions such as the example. Also the client would pass about
20 tables to be tagged when these tables matches to the Oracle Database Table.
This is the method I am planning to use.
 Is this the best approach.  Please advice.
                   Thank You
Note on execution : Compile error at the second declare

DECLARE CURSOR  fusa_cur  IS  SELECT empno, job, dropcode FROM emp_dup
        WHERE (empno IN ('7566','7369','7654'))
        AND   (  job IN ('MANAGER','CLERK','SALESMAN'))
          FOR UPDATE;
BEGIN
    FOR fusa  IN fusa_cur LOOP
      IF fusa.job = 'MANAGER' AND
           fusa.EMPNO = '7566' THEN
        UPDATE EMP_DUP
         SET  DROPCODE = 'D01'
          WHERE CURRENT OF fusa_cur;
      ELSIF
             fusa.job = 'CLERK' AND
           fusa.EMPNO = '7369' THEN
        UPDATE EMP_DUP
         SET  DROPCODE = 'D02'
            WHERE CURRENT OF fusa_cur;
       ELSIF
        fusa.job = 'SALESMAN' AND
           fusa.EMPNO = '7654' THEN
        UPDATE EMP_DUP
         SET  DROPCODE = 'D03'
            WHERE CURRENT OF fusa_cur;
      END IF;
   END LOOP;
END;

DECLARE CURSOR  fusa_cur2  IS  SELECT f.empno, d.fccof   FROM emp_dup,
                fccof d
                where f.empno = d.empno
                  FOR UPDATE;
BEGIN
    FOR fusa2  IN fusa_cur2 LOOP
               UPDATE EMP_DUP
         SET  DROPCODE = 'D04'
          WHERE CURRENT OF fusa_cur2;
    END LOOP;
END;

      and we said...
Never do procedurally what you can do in a single SQL statement.  Your logic
above is simply:

begin
   execute immediate
   'update emp
        set dropcode =
           case when ( job = ''MANAGER'' and empno = 7566 ) then ''D01''
                when ( job = ''CLERK'' and empno = 7369 )   then ''D02''
                when ( job = ''SALESMAN'' and empno = 7654 )then ''D03''
                else NULL
           end
     where empno in ( ''7566'',''7369'',''7654'')
       AND job IN (''MANAGER'',''CLERK'',''SALESMAN'')';

   update emp
      set dropcode = 'D04'
    where empno in ( select empno from fccof );
end;

we have to use dynamic sql on the first update since plsql doesn't understand
CASE until 9i but thats not really relevant...

Unlearn "procedural" coding.  Try to do it in sql, resorting to procedural logic
only when truly necessary.

The code you have didn't compile because all "declares" happening before the
code:

declare
   cursor c1 is ...
   cursor c2 is ...
begin
   for x in c1 loop
      ...

   for x in c2 loop
     .....

followup to comment

The approach that reads and processes the table in a single statement will be
faster then read  a record/process a record/read a recode/process a recode
procedurally will be.

Review &
      Followup

      Rating: 5
Processing
      Oracle Data  July 06, 2001
Reviewer:  Ron
      Cheddie  from New York City, New York
Tom:
     Thank you for your solutions. It has give me a template to do programmimg.
Your solution would make
as many passes on the table as the the number of updates. The declare
cursor solution would make as many passes on the table as
the number of cursors. If the table is about 30GB to 40GB,
how would this affect processing in terms time.

July 06, 2001 Marcelo -- Thanks for the question regarding
      "Cursor", version 8.1.6

      You Asked
Hi Tom.

Consider a procedure where there is a cursor (c1) that returns 25.000.000 rows.
For each row, a second cursor (c2) will be opened twice. What would be the
impact (positive or negative) if I don't close the second cursor.

See the structure below:

open c1
loop c1
  open c2(p1)
  ...
  close c2

  open c2(p2)
  ...
  close c2

Can you point me some paper concerning how to calculate parallel degree ?

Thanks a lot.
Marcelo

Hi Tom,
I'm talking about PL/SQL and you answered the question (The cursor must be
closed, but it will be cached, so no big matter).

I'm changing the program, I don't like its logic. Just a question... the
information that will be read is the the same, does not matter if I use one or
two queries. If right, what is the advantage of using one query? (I can think
about something, but I would appreciate your comments... I have learned a lot
with you, thanks).

I'm thinking about using parallel query. How can I calculate the degree of
parallelism?

Tks,
Marcelo

      and we said...
are we talking PLSQL here?  In PLSQL you have to close the cursor but it will
not really truly close the cursor -- it'll logically close the cursor but plsql
will cache it open for us anyway.

So, in plsql, the effect will be that if you do not close it the program will
FAIL.  If you do close it, the program will not fail (due to this anywhow).

In java/jdbc -- you would prepare a statement once and just bind/execute in the
loop.

I can say that I question logic that needs to loop over 25mill records and open
two cursors in the middle, care to share more of the logic -- probably a way to
do it in a single query.

In any case, if you can combine the two queries into one to get the same answer
-- that will be better.  Here is a quick and dirty example:

ops$tkyte@ORA817.US.ORACLE.COM> create table run_stats ( runid varchar2(15),
name varchar2(80), value int );

Table created.

ops$tkyte@ORA817.US.ORACLE.COM> create or replace view stats
  2  as select 'STAT...' || a.name name, b.value
  3        from v$statname a, v$mystat b
  4       where a.statistic# = b.statistic#
  5      union all
  6      select 'LATCH.' || name,  gets
  7        from v$latch;

View created.

ops$tkyte@ORA817.US.ORACLE.COM> column name format a40

ops$tkyte@ORA817.US.ORACLE.COM> declare
  2          l_cnt1  number;
  3          l_cnt2  number;
  4
  5          l_start number;
  6  begin
  7      insert into run_stats select 'before', stats.* from stats;
  8
  9          l_start := dbms_utility.get_time;
 10          for i in 1 .. 1000
 11          loop
 12                  select count(*) into l_cnt1 from dept;
 13                  select count(*) into l_cnt2 from emp;
 14          end loop;
 15          dbms_output.put_line( (dbms_utility.get_time-l_start) ||
                                                                   ' hsecs' );
 16
 17      insert into run_stats select 'after 1', stats.* from stats;
 18
 19          l_start := dbms_utility.get_time;
 20          for i in 1 .. 1000
 21          loop
 22                  select cnt1, cnt2 into l_cnt1, l_cnt2
 23                    from (select count(*) cnt1 from dept ),
 24                             (select count(*) cnt2 from emp );
 25          end loop;
 26          dbms_output.put_line( (dbms_utility.get_time-l_start) ||
                                                                ' hsecs' );
 27
 28      insert into run_stats select 'after 2', stats.* from stats;
 29  end;
 30  /
39 hsecs
27 hsecs

PL/SQL procedure successfully completed.

already you can see 1 query is faster...

ops$tkyte@ORA817.US.ORACLE.COM> select a.name, b.value-a.value run1,
c.value-b.value run2,
  2         ( (c.value-b.value)-(b.value-a.value)) diff
  3    from run_stats a, run_stats b, run_stats c
  4   where a.name = b.name
  5     and b.name = c.name
  6     and a.runid = 'before'
  7     and b.runid = 'after 1'
  8     and c.runid = 'after 2'
  9     and (c.value-a.value) > 0
 10     and (c.value-b.value) <> (b.value-a.value)
 11   order by abs( (c.value-b.value)-(b.value-a.value))
 12  /

NAME                                           RUN1       RUN2       DIFF
---------------------------------------- ---------- ---------- ----------
...
STAT...recursive cpu usage                       38         30         -8
LATCH.shared pool                               165        143        -22
LATCH.cache buffers chains                    20096      20132         36
STAT...redo size                              21468      21424        -44
STAT...execute count                           2005       1005      -1000
STAT...calls to get snapshot scn: kcmgss       2006       1005      -1001
STAT...recursive calls                         2032       1031      -1001
LATCH.library cache                            4299       2291      -2008

35 rows selected.

and there is why.  1,000 less executes (context switches), 2,000+ less library
caches latches and so on...

As for the degree of parallelism, it'll be a function of how many CPUs, disks,
memory and such you have.  If you are the only one on the machine, start with 2x
CPUs and tune from there.
July 06,
      2001 -- Thanks for the question
      regarding "iot", version 8.1.7

      You Asked
Tom

We have table  into which we insert million records every day, and the following
day the data is deleted, and new data is inserted.

Data is deleted not at once, but my different processes, through multiple delete
statements , during different timings. That means data is being inserted and
deleted almost during the whole day.

As soon as the data is inserted on a particular day, some reports will be
generated.

1.Is this table a good candidate for an IOT. why or why not.
2.Can we partition a IOT
3.Can we swap a partition betweed an IOT, and a regular partitioned table.

      and we said...
1) probably not.  there will be considerable overhead in maintaining the index
structure -- especially with all of the rest of the data tagging along.  Only if
the table consists almost ENTIRELY of the primary key might i use an IOT --
sounds like too much DML in this case.

2) Yes

tkyte@TKYTE816> CREATE TABLE partitioned
  2  ( x int,
  3    y int,
  4    z varchar2(25) primary key
  5  )
  6  organization index
  7  PARTITION BY RANGE (z)
  8  (
  9  PARTITION part_1 VALUES LESS THAN('M') tablespace users storage
                  ( initial 500k next 400k ),
 10  PARTITION part_2 VALUES LESS THAN('Z') tablespace tools storage
                  ( initial 2k next 5k )
 11  )
 12  ;

Table created.

3) no, the objects need to be homogenous.

July 06, 2001 -- Thanks for the question regarding "example for
      multiple for a partition key", version 8.1.7

      You Asked
Tom

1.Can you give an example for a partition key  having multiple columns?

2.In our scenario the most relevant column is country name and a type code, both
varchar2 fields, the ideal partition key would be a combination of these two

but will range partition allow me use the columns as partition key, as range
partition is possible only with date and number?

Thank you

      and we said...
1)

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c09parti.htm#445324
2) Yes it does allow for varchar's

tkyte@TKYTE816> CREATE TABLE t
  2  ( cc        varchar2(2) check ( cc in ( 'US', 'UK' ) ),
  3    type_code varchar2(1) check ( type_code in ('A','B','C') )
  4  )
  5  PARTITION BY RANGE (cc, type_code)
  6  ( PARTITION p1 VALUES LESS THAN ( 'UK', 'B' ),
  7    PARTITION p2 VALUES LESS THAN ( 'UK', 'C' ),
  8    PARTITION p3 VALUES LESS THAN ( 'UK', 'D' ),
  9    PARTITION p4 VALUES LESS THAN ( 'US', 'B' ),
 10    PARTITION p5 VALUES LESS THAN ( 'US', 'C' ),
 11    PARTITION p6 VALUES LESS THAN ( 'US', 'D' )
 12  )
 13  /

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> insert into t values ( 'UK', 'A' );

1 row created.

tkyte@TKYTE816> insert into t values ( 'UK', 'B' );

1 row created.

tkyte@TKYTE816> insert into t values ( 'UK', 'C' );

1 row created.

tkyte@TKYTE816> insert into t values ( 'US', 'A' );

1 row created.

tkyte@TKYTE816> insert into t values ( 'US', 'B' );

1 row created.

tkyte@TKYTE816> insert into t values ( 'US', 'C' );

1 row created.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> select * from t partition ( p1 );

CC T
-- -
UK A

tkyte@TKYTE816> select * from t partition ( p2 );

CC T
-- -
UK B

tkyte@TKYTE816> select * from t partition ( p3 );

CC T
-- -
UK C

tkyte@TKYTE816> select * from t partition ( p4 );

CC T
-- -
US A

tkyte@TKYTE816> select * from t partition ( p5 );

CC T
-- -
US B

tkyte@TKYTE816> select * from t partition ( p6 );

CC T
-- -
US C

Review &
      Followup

      Rating:
      4
  January 07, 2004
Reviewer:
      A reader

July 06, 2001 Terry -- Thanks for the question regarding
      "Translating a BFILE data type to a directory path and file name via SQL",
      version 8.1.6

      You Asked
Tom:

Assume one has performed the following steps:
  CREATE DIRECTORY BFILE_DIR AS 'C:\TEMP\BFILEDIR';
  CREATE TABLE MY_BFILES (ID NUMBER, FIL BFILE);
  INSERT INTO MY_BFILES VALUES (1, BFILENAME('BFILE_DIR','FILE1.DAT');
  INSERT INTO MY_BFILES VALUES (2, BFILENAME('BFILE_DIR','FILE2.DAT');

Is there a standard function (or set of functions) in the
SQL syntax that allows one to perform something like:

  SELECT ID, func_name(FIL) AS EXT_FILE FROM MY_BFILES

to have it produce output like:

    ID EXT_FILE
------ ---------------------------------------------------
     1 C:\TEMP\BFILEDIR\FILE1.DAT
     2 C:\TEMP\BFILEDIR\FILE2.DAT

(2 rows)

Or do I have to write my own function using the DBMS_LOB package???

I had thought about storing the BFILENAME function's parameters as
separate fields in the table but that seems redundant and could lead
to problems if one set of fields was updated and the other was not.

Also, it appears that to do my own translation, I would have to access
the ALL_DIRECTORIES view.  As a result, if I don't have read privilege
to the directory referenced, I will not be able to do the translation.

Thanks in advance for you help.

Terry

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:756602687874
you have to create a function to select that from SQL.  Only the OWNER of the
function needs access to dba_directories so you can create this in one account
that does have access to that view and then grant execute on that function to
PUBLIC and now everyone can use it without error.
July 07, 2001 Andrew -- Thanks for the question regarding
      "Concatenating Substitution Variables in SQL*Plus", version 8.1.7

      You Asked
I have a number of tables HELLO_A HELLO_B, HELLO_C, and GOODBYE_A, GOODBYE_B,
and GOODBYE_C.  Now I want to write a query that is like:

SELECT *
FROM &1_A;  --User can call this script with args HELLO or GOODBYE

However, instead of accepting the first argument as &1 and concatenating with
_A, this prompts the user for the substitution variable &1_A.

If I put a space in between, i.e. "&1 _A" it accepts the 1st argument to the
script as &1 but keeps the space in between which causes an Oracle error.

Is there some way to concatenate this?  I know I can use dynamic PL/SQL but this
would force me to use DBMS_OUTPUT and would rob me of the SQL*Plus built-in
formatting that I need.

Thanks,
Andrew

      and we said...
select * from &1._a

dot optionally terminates the substitution variable.

If you actually need a dot to follow a substitution variable, you need to use

select * from &1..emp

(eg: &1 was SCOTT -that would be select * from SCOTT.emp)

followup to comment
in the "Where and How to Use Substitution Variables" section

http://technet.oracle.com/doc/oracle8i_816/sqlplus.816/a75664/ch33.htm#1001931
Review &
      Followup

      Rating: 5
Great fast
      help!  July 06, 2001
Reviewer:  Andrew Cohen
       from Berkeley, CA
I do not believe this was documented in the SQL*Plus reference manual, and it is
a real time-saver to know this.  Thanks a lot Tom!!!!

July 07, 2001 Govindhan -- Thanks for the question regarding
      "Objects as input parameter in a Stored Procedure", version 8.0.5

      You Asked
Hi tom,

     I have created an object(create type typename as object.....). Is it
possible to send an input parameter with datatype of the above object. If
possible pls explain the situation where it arises with example.

Govind

      and we said...
Sure, it is not only possible, it is done all of the time.

All of the interMedia types are Object types (text, video, audio, spatial, etc)
are object types.

Once you have an object type, it is now a SQL type -- you can define plsql
variables of that table, tables of that type, columns of that type and so on.
Pretty much anywhere you can use the NUMBER type -- you can use your object
type.

The example is as simple as:

create or replace type mytype as object ( .... );

create or replace procedure my_procedure( x in mytype )
as
begin
    ....

July 07, 2001 Muhammad -- Thanks for the question regarding
      "Write ahead cache", version 8.1.6.0

      You Asked
I have posted this question in several forums and still did not quite get a
satisfactory reply.
We are having a debate wit our unix admin (we have HA-H80 AIX machine)
Unix admin are asking us to allow them to switch on write ahead cache in JFS
upon creation used for data files. We came to know from different sources that
Oracle doesnot recommend this at all and that
there might be data corruption, data integrity violations/problems etc. Which we
failed to convince them. Yes the poer faiure is one reason not to go but we have
fault tolerant systems, besides we have ups. And the main point from Unix admin
side is to leverage the cost, since these cache chips are expensive and it would
not be wise to use them. If you can give an example with enough echnical detail
to do a little simulation, would be nice or atleast give a detail so that we can
convince them, not that "there might be data corruption but a valid sound
reason". Wouldn unix os take care of all data that oracle request OS to to do an
i/o against data files and take care of their consistency?Anyway we reply on
your input now.

Another question if of a confirmation of our startegy:

We will soon turn on archiving on one of ur database.
We plan to do the folowing:

1. Take full database hot backup twice a week
2. In between we will archive the online redo logs to two different location.
3. we will do full db backup directly to tape which is of LTO advanced media and
is the fasted I/O.
We would like to know what archived logs in specific do we need to copy to tape
to make our full databas hot backup logically a omplete one? would you confirm
the following at backup time to tape?
 1) switch log file and Note current log seq no
 2) take full tablespace hot backup,,,,,,
 3) switch log file and take a note of current log seq no
 4) copy to tape all archived logs produce for sequcnes from step1 till step
3(inclisive of those seq nos at the log switch)/

Also you dont need all archived logs less than step1 for recovery anymore?
correct?
Now to copy those archoved logs we are thinking of writing a pl/sql proc to
identify the in between logs and create an os command to include tar to tape? is
there a better approach?
In additon to above we will backup to tape archived logs, every three hrs. How
do we know which archived logs to tar, hpow do we knoe wich ones are archioved
in arch location. Offcourse we can usev$log but how to automate the whol
eproceesss, can you give us a clue.

Pardon for the typo here.
Cheers

      and we said...
Where did you hear we don't recommend a delayed write cache?  As long as it is
battery backed, it is just dandy (can be awesome actually)...

We do not recommend (say to "avoid") log files on such a device but datafiles
are great.

It MUST be battery backed, else a power failure will kill us (and the file
system).

As for the backup -- recommend you keep at least two of them available at all
times -- don't overwrite the last backup with the current backup (i've see disks
fail in the middle of a backup - if your new backup overwrites the old backup,
you have NO backup!)

You should switch logfiles before starting the backup.  If you note the current
log sequence -- you need ALL archives generated AFTER that point in order to do
a recovery.

If you do a switch logfile after the backup -- and you copy the archives
generated during the backup, you will have the minimum you need to restore the
database to that point in time.  You need all subsequent archives to restore the
database to the current point in time.

(don't forget your control file backups!)

A rather simplistic method to get the files to copy is:

#!/bin/sh
echo "Time started" `date`
echo " "
for FN in /arch1/oradata/ora8i/arch /arch2/oradata/ora8i/arch
  do
     FILE_LST=`ls -1 $FN/*.log | sed '$d'` # get file list except last file
        if [ "$FILE_LST" != " " ]
           then
             for f in $FILE_LST
               do
               /opt/gnu/bin/gzip -v $f  <<< === i'm compressing, you would copy
               done
           else echo "No files to compress"
        fi
  done
echo " "
echo "Time Finished" `date`

A much more complex method I also use (gets the last archive as well if it is
done being archived).  It works by getting a list of completed archives MINUS
the ones that I've already processed (i can tell they were processed cause they
were compressed)

#!/bin/ksh

export ORACLE_SID=ora8i
export ORACLE_HOME=/export/home/oracle8i
export PATH=$PATH:$ORACLE_HOME/bin:/opt/gnu/bin
export DUPLEX_LOC=/arch2/oradata/ora8i/arch

echo $ORACLE_HOME
echo $ORACLE_SID

echo set heading off > /tmp/$$.sql
echo set feedback off >> /tmp/$$.sql
echo set linesize 200 >> /tmp/$$.sql
echo set trimspool on >> /tmp/$$.sql
echo column cmd format a70 >> /tmp/$$.sql
echo spool /tmp/$$.sh >> /tmp/$$.sql
echo select "'/opt/gnu/bin/gzip -v ' || name ||' ; cp -p '||name||'.gz
$DUPLEX_LOC ' " >> /tmp/$$.sql
echo 'from sys.v_$archived_log' >> /tmp/$$.sql
echo 'where name in(' >> /tmp/$$.sql
ls /arch1/oradata/ora8i/arch/*.log | sed "s/^/'/;s/"'$'"/',/" >> /tmp/$$.sql
echo 'NULL ) and sequence# not in ' >> /tmp/$$.sql
echo '( select sequence# from v$log where archived = '"'NO'"')' >> /tmp/$$.sql
echo '/' >> /tmp/$$.sql
echo spool off >> /tmp/$$.sql
echo exit >> /tmp/$$.sql

sqlplus / @/tmp/$$.sql

sh /tmp/$$.sh

rm /tmp/$$.*

Review &
      Followup

      Rating: 5
backup &
      recovery  July 09, 2001
Reviewer:  Muhammad
      Javed Ilyas.  from Pakistan
Hello Mr.Tom

My name is Muhammad Javed Ilyas,

My question is what is the backup & recovery stretagy in nonarchive and archive
mode please tell me in detail and how we use in practical life.

thanks

muhammad javed ilyas

      Rating: 5
backup &
      recovery  July 09, 2001
Reviewer:  Muhammad
      Javed Ilyas.  from Pakistan, karachi
Hello Mr.Tom

My name is Muhammad Javed Ilyas,

My question is what is the backup & recovery stretagy in nonarchive and archive
mode please tell me in detail and how we use in practical life.

thanks

muhammad javed ilyas

      Rating: 5
disk
      layout  December 11, 2002
Reviewer:
      A reader

      Rating:
      5
performance  December 11, 2002
Reviewer:
      A reader

July 08, 2001 Saravana -- Thanks for the question regarding
      "Nested Tables & Ref Cursor - Problems returning rows from Nested
      table using Ref Cursor", version 8.1.7.1

      You Asked
Hi Tom,Is there any PL/SQL restrictions in using REFCURSOR with the NESTED
Tables?

I've created a nested table with a two column object.

T_Typ as object - (x varchar2(100),y varchar2(1000))
Collection - T_Nst_Typ as table of T_Typ
TABLE T_NST -  T_id,T_desc,T_ind,T_criteria,T_dyn,T_Nst_Typ,T_dt

Here is my problem. When I tried to return the record set using the ref cursor I
am getting the error ORA-01427: single-row subquery returns more than one row ,
if the table has more than one row . Some queries are working fine in stand
alone but not inside a stored procedure.

This the query that is returning the error:

SELECT T.T_id,T.T_desc,T_ind,T_criteria,OB.X ,OB.Y ,T.T_DT
FROM T_NST T,TABLE (SELECT T2.T_dyn FROM T_NST T2 )OB
/

The following query works fine in stand alone but I could not compile inside the
stored procedure.
SELECT T.T_id,T.T_desc,T_ind,T_criteria,OB.X ,OB.Y ,T.T_DT
FROM   T_NST T, TABLE (SELECT T2.T_dyn FROM T_NST T2 WHERE T2.T_ID = T.T_ID )OB

Is there any PL/SQL restrictions in using REFCURSOR with the NESTED Tables?

Please let me know for any work around.

I have provided all the scripts needed for testing. I know you may not need this
, as you may have an answer right away.

Thanks
Saravana

Scripts:
--------
--Drop the Objects:
-----------------

drop table T_NST
/
drop type T_Nst_Typ
/
drop type T_Typ
/

-- Create the objects
---------------------

create or replace type T_Typ as object
(       x varchar2(100),
        y varchar2(1000)
 )
/
create or replace type T_Nst_Typ as table of
T_Typ
/

CREATE TABLE T_NST
 (
  T_id                          NUMBER(9) NOT NULL,
  T_desc                        VARCHAR2(255),
  T_ind                 varchar2(1),
  T_criteria                    VARCHAR2(2000),
  T_dyn                     T_Nst_Typ,
  T_dt                 DATE
   )
TABLESPACE users
NESTED TABLE T_dyn STORE AS T_stor_tab
/

-- Data Manipulation
--------------------

--Delete:
-------

truncate table t_nst;

--Insert:
-------
INSERT INTO T_NST (     T_id
              ,T_desc
              ,T_ind
              ,T_criteria
              ,T_dyn
             ,T_dt
           )
VALUES
        (     1
            ,'Test1'
            , 'D'
            , null
            ,(T_Nst_Typ(    T_Typ('T1','Test1'),
                    T_Typ('T2','Test2'),
                    T_Typ('T3','Test4')))
            ,sysdate)
/
INSERT INTO T_NST (     T_id
              ,T_desc
              ,T_ind
              ,T_criteria
              ,T_dyn
             ,T_dt
           )
VALUES
        (     2
            ,'Test2'
            , 'D'
            , null
            ,(T_Nst_Typ(    T_Typ('T4','Test8'),
                    T_Typ('T5','Test9'),
                    T_Typ('T6','Test10')))
            ,sysdate)
/
INSERT INTO T_NST (      T_id
              ,T_desc
              ,T_ind
              ,T_criteria
              ,T_dyn
             ,T_dt
           )
VALUES
        (     3
            ,'Test3'
            , 'S'
            , '1000771,1000006,1000002,10107,1001071,2673,1000283'
            ,null
            ,sysdate)
/

commit
/
-- Select
---------

Query I : Works fine in standalone but could not compile inside the stored proc
-------
SELECT
                T.T_id,
        T.T_desc,
        T_ind,
        T_criteria,
                OB.X ,
                OB.Y ,
                t.T_DT
FROM
        T_NST T, TABLE (T.T_dyn) OB
/
Query II : Works fine in standalone but could not compile inside the stored proc
--------
SELECT
              T.T_id,
              T.T_desc,
              T_ind,
              T_criteria,
              OB.X ,
              OB.Y ,
              T.T_DT
FROM
        T_NST T, TABLE (SELECT T2.T_dyn FROM T_NST T2 WHERE T2.T_ID = T.T_ID )OB
/

Query III : Could able to compile but gives the error ORA-01427: single-row
subquery returns more than one row

SELECT
                      T.T_id,
                  T.T_desc,
                  T_ind,
                  T_criteria,
                      OB.X ,
                      OB.Y ,
                      T.T_DT
    FROM
                T_NST T,
            TABLE (SELECT T2.T_dyn FROM T_NST T2 )OB
/
-- Package Creation
-------------------

CREATE OR REPLACE PACKAGE T_PKG
IS

TYPE CUR_T IS REF CURSOR;

Procedure      GET_T
(  V_CR        IN OUT  CUR_T
);
END;

CREATE OR REPLACE PACKAGE BODY T_PKG
IS

Procedure      GET_T
(  V_CR        IN OUT  CUR_T
)
IS

BEGIN

DBMS_OUTPUT.ENABLE(1000000);

Open V_CR FOR

SELECT
                      T.T_id,
                  T.T_desc,
                  T_ind,
                  T_criteria,
                      OB.X ,
                      OB.Y ,
                      T.T_DT
    FROM
                T_NST T,
            TABLE (SELECT T2.T_dyn FROM T_NST T2 )OB;

EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
END;

-- Procedure Execution
------------------------

var  R1 refcursor
BEGIN

-- Call the stored program
T_PKG.GET_T(:R1);
END;
/
print :R1

      and we said...
The ORA-01427 is to be expected given your query.  It attempts to join EVERY
nested table to EVERY row.  That cannot be done.

Here is an exmaple showing your query working, then failing and then the proper
syntax to flatten a nested table:

ops$tkyte@ORA8I.WORLD> create type myScalarType as object ( x int, y int )
  2  /

Type created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create type myArrayType as table of myScalarType
  2  /

Type created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create table t ( x int primary key, y myArrayType )
  2  nested table y store as y_tab
  3  /

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into t values
  2  ( 1, myArrayType( myScalarType( 5, 6 ), myScalarType( 7,8 ) ) );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> SELECT T.x, ob.x, ob.y
  2  FROM T T,TABLE (SELECT T2.Y FROM T T2 )OB
  3  /

         X          X          Y
---------- ---------- ----------
         1          5          6
         1          7          8

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> insert into t values
  2  ( 2, myArrayType( myScalarType( 15, 16 ), myScalarType( 17,18 ) ) );

1 row created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> SELECT T.x, ob.x, ob.y
  2  FROM T T,TABLE (SELECT T2.Y FROM T T2 )OB
  3  /
FROM T T,TABLE (SELECT T2.Y FROM T T2 )OB
                *
ERROR at line 2:
ORA-01427: single-row subquery returns more than one row

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select t.x, ob.*
  2    from t t, table( t.y ) ob
  3  /

         X          X          Y
---------- ---------- ----------
         1          5          6
         1          7          8
         2         15         16
         2         17         18

As for the ref cursor issue, anytime plsql gives you a hard time with a query
you know is syntactically valid, that just means the the plsql parser is having
a hard time.  We just need to bypass it:

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> variable x refcursor
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> begin
  2          open :x for 'select t.x, ob.*
  3                     from t, table( t.y ) ob';
  4  end;
  5  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> print x

         X          X          Y
---------- ---------- ----------
         1          5          6
         1          7          8
         2         15         16
         2         17         18

ops$tkyte@ORA8I.WORLD>
Review & Followup

      Rating: 5
Woh ! It's a
      Great Tip  July 08, 2001
Reviewer:  Saravana
       from NJ,USA
It's really very useful to know how to bypass the PL/SQL parser. Thanks for the
tip to use a dynamic sql in the REF CURSOR.


Subject | Article | Last Updated (East coast time)
Pinning Large Objects in memory | article only | Jul 09, 2001 08:30 am
Dynamic HTML pages generated with the htp, htf and owa_* packages | article only | Jul 09, 2001 08:31 am
cpu | article only | Jul 09, 2001 08:37 am
backup | article only | Jul 09, 2001 09:42 am
backup and recovery strategy | article only | Jul 10, 2001 08:31 am
questions. | article only | Jul 10, 2001 08:37 am
Problem creating a foreign key | article only | Jul 10, 2001 09:58 am
unrecoverable and logging | article only | Jul 10, 2001 10:02 am
NAGLE | article only | Jul 10, 2001 01:44 pm
Selective ORDER BY | article only | Jul 10, 2001 01:53 pm
PARTITION names in a stored procedure | article only | Jul 11, 2001 10:04 am
SID descriptor length | article only | Jul 11, 2001 01:27 pm
Oracle Data dictionary | article only | Jul 11, 2001 02:42 pm
SQLLOADER - Error Field in data file exceeds maximum length | article only | Jul 11, 2001 04:36 pm
why is difference between trace statistics... | article only | Jul 12, 2001 08:38 am
Container | article only | Jul 12, 2001 08:52 am
Pinning Scripts on NT Automatically ... | article only | Jul 12, 2001 06:36 pm
dbms_utility_analyze | article only | Jul 12, 2001 07:04 pm
Locally managed Tablespaces and Partitioning | article only | Jul 13, 2001 02:25 pm
Monitoring extends | article only | Jul 13, 2001 02:58 pm
sys/system acount | article only | Jul 13, 2001 03:13 pm
Creating a Clone of an existing Active DB | article only | Jul 13, 2001 07:52 pm
Force password prompt for internal in UNIX | article only | Jul 14, 2001 09:49 am
Why these tables/views can be qieried without roles | article only | Jul 14, 2001 09:51 am
Data Loading from one db into another. | article only | Jul 14, 2001 01:51 pm
formatting tracefiles... | article only | Jul 14, 2001 01:57 pm
Creating a Java stored procedure with String array parameters | article only | Jul 15, 2001 08:45 am
Effect of "alter table x set unused..." on space usage on subsequent inserts | article only | Jul 15, 2001 08:50 am
how make to oracle8i Database synchronization? | article only | Jul 15, 2001 09:22 am
values less than | article only | Jul 15, 2001 12:02 pm
java.io.IOException when executing rc | article only | Jul 15, 2001 12:08 pm
Creating snapshots for existing tables with triggers | article only | Jul 15, 2001 12:56 pm
Backup and Recovery | article only | Jul 15, 2001 05:39 pm
Rollback Segment | article only | Jul 15, 2001 07:06 pm
shrink rollback ...... | article only | Jul 15, 2001 09:47 pm
row(s) 1 - 35 of 35
July 09, 2001 Jenna -- Thanks for the question regarding "Pinning Large Objects in memory", version 8.1.6
You Asked
PLease can you tell me how to find out which packages, triggers, sequences or
procedures should be pinned into memory?

The application I support is an OLTP system, with a small amount of overnight
batch processing.  The application is composed of around 20 packages, only a few
of which are used for OLTP.  For this reason, I thought it would be useful to
have those packages pinned into memory along with frequently required large
procedural objects such as STANDARD and DIUTIL.

How can I tell which packages are frequently accessed.  Is there a dynamic view
I can query that will tell the package name and not just the PL/SQL that has
just been run?

Thanks

Jenna
and we said...
Before you waste time doing anything like this, check out your library cache hit
ratio using statspack (if you are not familar with statspack, goto
www.oracle.com/oramag and search for statspack, many articles demonstrating its
use).

If the cache hit ratio on the library cache is very good and the soft/hard parse
ratio is very high - you have no need of this.

Else -- since the library cache is an LRU cache -- the more frequently used
objects will be there.  The objects that are getting flushed that you don't want
flushed are the ones your knowledge of the application must come to bear for.
The issue is -- if they are getting flushed and might benefit from keeping --
you won't (by definition) see them in the shared pool.  If they aren't getting
flushed -- you don't NEED to keep them.
July 09, 2001 dieter -- Thanks for the question regarding "Dynamic HTML pages generated with the htp, htf and owa_* packages", version 8
You Asked
i'm using the htp, htf and owa_* package to create dynamic html and have a
question related to the submit form functionality.

when submitting a form the corresponsing oracle package will be executed and the
fields in the form will be submitted to the procedure as parameter.

(1) is it possible to prevent the html form from sending ALL fields to the
procedure ? this would be helpful, when using quite complicated forms where only
some of the fields need to be send to the procedure

(2) what are the conversion rules when defining a parameter as number instead
then defining it as varchar2 and receiving the content of the form fields that
(per definition) must be text ?

(3) is it possible to include static HTML text (eg. the content of a file given
as URL) when generating a HTML page via HTP calls ?

thank you

dieter
and we said...
1) I'm sure java script could probably do this but as I've never had this
particular requirement -- I've not done it myself.  Try looking at java script
-- there is nothing the middle tier will do.

You might look at "flexible parameter passing" as well.  There the arguments
will be passed to you as an array of NAMES and an array of VALUES.  In this
fashion, you look in the names array for the argument you want and go the
corresponding slot in the values array.  That way, you just ignore what you do
not want.

2) I always define the arguments are VARCHAR2 as HTML is all character string
based.  Then, I convert the fields as needed:

   l_my_number := p_input_string;

and if I need - i do exception handling to catch errors:

   begin
      l_my_number := p_input_string
   exception
      when value_error then
             ....
   end;

3) Only if you open the file using UTL_FILE and read it yourself.  Another
option might be to use a PLSQL server page (like ASP or JSP).  There you take a
file that is a mixture of HTML and PLSQL and compile it into PLSQL only and load
that into the database.
Review & Followup
Rating: 5
thanks July 09, 2001
Reviewer: dieter from vienna
quick and precise answer!

July 09, 2001 Anil -- Thanks for the question regarding "cpu", version 8.1.5
You Asked
Hi tom,
  I Just wanted to know,whether oracle takes advantage of multiple
cpu automatically or we have to tell oracle explicitly.I have 8 cpu
on my server,i need to know it,so that i can utilize it perfectly.

Thanks,

Regards
  Ak
and we said...
Oracle will automatically make use of 8 cpus.  Oracle is a multi-process or
multi-threaded (depending on platform) database that will automatically use all
of the available cpus on the machine.

Depending on your needs, you may enable parallel query -- which will allow a
single session to utilize all of the CPU on your machine.  You would do this in
cases of data warehouses and such -- not on an OLTP system however.

The DBA can always be lookging for ways to exploit the additional cpus -
building objects in parallel and so on.
July 09, 2001 Anil -- Thanks for the question regarding "backup", version 8.1.5
You Asked
Hi tom,
  Can you give me well structured backup plan,where in any cases
i will not loose the data,here is my database condition ..(space is
not a problem)

1)Running in archive mode
2)Can be shutdown on saturday night till sunday.

I want to know ,how often we should take cold backup and hot backup
and  simil. archive log.Can you share your experiance with me in this
regard.If you are the dba what backup&recovery plan you will have ??

Thanks

Regards
  Ak
and we said...
We do full HOT backups every monday/wed/frid and retain the last three backups
and all archive logs necessary to recover them fully .

I never shutdown for a backup -- I keep the database up as long as my machine is
up.  You wipe out all of the work in the shared pool/buffer cache when you
shutdown.  I never do cold backups.

We keep three backups in the event there is an error reading one of them or some
physical data corruption was introduced and we backed it up (eg: I had a bad
block introduced into the system on tuesday due to a controller error -- I
backed that up wed and fri -- saturday we discovered it and replaced the faulty
hardware.  We are able to restore MONDAYS backup and roll forward -- missing the
corruption).

The more frequently you backup, the more backups you should keep -- giving
yourself the opportunity to go back a week or so if you need to.

The backup and recovery plan is very simple -- backup religiously, test the
backups frequently (restore them to another machine every now and again, make
sure you know HOW to), test recovery scenarios (lost datafile, lost system
tablespace, lost a single table via a drop, and so on)...

The second part of the plan is to never have to recover ;)  thats the hard part.
July 10, 2001 -- Thanks for the question regarding "backup and recovery strategy ", version 8.1.5
You Asked
Hi,Tom
    I want for your help again! My questions is how to define a perfect backup
and recovery strategy under this environment:
 1.DB is Noarchivelog mode
 2.24-hour operations ,every day have hundreds of millions  rows DML
 3.SUN server have five disks ,but have no RAID
                                 Thanks,  Micheal
and we said...
1) PUT THE DATABASE IN ARCHIVELOG MODE IMMEDIATELY.
2) REREAD #1

If you do not, you will lose data some day.  That is not "maybe you will
lose..." but rather "you WILL lose...."

Additionally, I don't see how you can be 24 hours a day without being in
archivelog mode.  You have to shutdown for backups.

Once you are in archivelog mode, perform regularly scheduled HOT backups and
keep at LEAST the last two full hot backups (and all archive logs necessary to
recover them).  Never overwrite the last backup with the current backup --
rather rotate at least two sets of tape.

Make sure to multi-plex your control, redo and archive log files.

followup to comment two

Michael -- I hope you come back and read this.

You do understand that in archive log mode the ONLY difference in the system is
that there will be an ARCH process that will read and copy a log file.  It is
not a CPU instensive process (hardly uses any CPU).  It is an I/O intesive
process and if you felt a performance impact, it is solely due to not tuning
your I/O.

Optimally, one would have 6 devices for redo.  Lets say they are called disk1,
disk2, ... disk6.

You would have online redo log groups 1, 3, 5, ... (odd numbers) duplexed on
disks 1&3.

You would have online redo log groups 2, 4, 6, ... (even numbers) duplexed on
disks 2&4.

You would have your duplexed archive destination set to disks 5&6.

You would not have anything else optimally using these devices.  Now, when LGWR
writes to an ODD group -- ARCH is reading and copying the EVEN group.  LGWR
would write to 1&3, ARCH will read 2&4, ARCH will write 5&6.  When LGWR switches
to an EVEN group ARCH will read 1&3, LGWR writes 2&4, ARCH writes 5&6.

In a situation like this, no contention -- ZERO performance impact.

Every real production system running Oracle runs in archivelog mode.  To
characterize it as a "performance inhibitor" is just plain wrong.  If you
are making basic mistakes like putting log and archive on the same device, using
RAID-5 for log/archive, not tuning contention -- ANYTHING will be a performance
inhibitor.   We run all of our TPC-Cs in archivelog mode - if it killed
performance, we'd be in real trouble.  When I run customer benchmarks -- I
actually ask that all databases run in the equivalent of archive log mode (eg:
sqlserver cannot run in "truncate log on checkpoint" mode and such) since it
does not affect our performance but does affect others.

I spent along time on this followup just so that everyone is aware of the basic
fact that running in archivelog mode is the way it is done, the way people do
it, and it does not have to impact performance at all

As for doing cold backups every week and exports every day -- you will LOSE
DATA.  I 100% assure you of this.  Consider that is it 6pm at the end of your
busiest day.  You disk crashed.  It happened to have had SYSTEM on it.  Good bye
database!  You just lost the entire days work with no chance of recovery.  An
export is no backup -- its good to have in order to "cover your butt" in the
event of an "accidental" table drop but it is not a very good "backup" scheme.

You must, if you value your data, put the database into archive log mode.  I
will reiterate points 1 and 2 above -- put it in archive log mode, do it now,
and if you notice performance related issues and have metrics to prove it (eg:
here is the stats pack report before archivelog mode and after, before it took
0.x seconds to do this, now it takes 0.y seconds) -- feel free to email me and
we'll take care of it.
Review & Followup
Rating: 4
More tapes, please. July 09, 2001
Reviewer: Harrison from Haymarket, VA USA
Hi Tom:

It is amazing that you need to write that administrators can not use the same
tape every day, but I went to a DOD site to restore a drive, and they had one
tape (production site) and the drive had failed part way through the backup (of
course!).  Another site by the same organization had one tape for each day of
the year, but they were doing hot backups in noarchive mode (testing would have
shown a problem but they had "failure=not_allowed" in their initsid.ora, so they
hadn't tested the backups.) So everyone needs to test what they are doing or
needs to explain to management the consequences of not having a box to test on,
or tapes to burn. If you can't explain it now, it will be hopeless to try when
the system crashes. No work is more important than being able to restore.  When
the average site has an operator or hardware error, they lose some data. Life as
a dba is much better if you can minimize that.

Rating: 2
But in archivelog mode ,customers cann't tolerance performance July 10, 2001
Reviewer: michael
Customer choose Oracle ,as it's PERFORMANCE better than DB2.But in archivelog
mode ......
Now every weeks,I do a shutdown backup;every day export important tables and
tablespaces.
I want to know if tablespace mode export is valuable.

Rating: 4
Simply great July 10, 2001
Reviewer: Randy from Austin, TX
I hope people appreciate the time you've taken to explain this Oracle concept
(rather, rule to live by) and hammer it home.  This is the sort of thing that
could very well save your job--NOT following these instructions would be a
classic mistake.  I didn't find this column until after I some experience, but
would have given my right arm for it when I was starting out.

July 10, 2001 ahmed -- Thanks for the question regarding "questions.", version 6
You Asked
hello......
i want you tell me how can i learn oracl...and what a right stepsto make me
professional .....thank you
and we said...
step 1) Read the documentation - start with the server concepts manual and then
continue down either the admin guides or the application developer guides --
which ever is appropropriate.

step 2) get an entry level job and learn by doing.  Its the only way to learn
this stuff.  The books will get your started, experience will get you smart.

Don't expect to be an expert in 6 months or even a year.  I've been doing Oracle
for 12 years now and still learn something new almost every day.
Review & Followup
Rating: 5
Additional Info July 10, 2001
Reviewer: Mark from Indianapolis, IN USA
You may also want to purchase (OK, definitely *SHOULD* puchase and read) these
two books:

Expert One-on-One Oracle (written by some guy named Tom Kyte :) )

AND

Practical Oracle8i by Jonathan Lewis.

Both are commonly available and are tremendous books - especially if you are
just starting out, need to deepen your knowledge, and/or need a refresher.  Each
has a different perspective, and I have found them to be very complimentary.

Also, join technet and use the online docs...

July 10, 2001 Nick -- Thanks for the question regarding "Problem creating a foreign key", version 8.1.7
You Asked
This should be simple. I am trying to create a foreign key on a primary key in
another table. The primary index has an index associated with it. The other
table is in a different schema and tablespace. The command I'm using is:

Alter table ps.ps_issue add constraint "FK_ISSUE_JOURNAL"
foreign key (journal) references core.journal(journal);

I get the error ORA-00942: table or view does not exist with the * pointing at
core.journal.

Desc core.journal shows that the table does exist. If I try to use a public
synonym for core.journal and leave off the schema name I get the same message.
It seems the error message is misleading. Any ideas? I'm sure I'm missing
something obvious.

Thanks again for all your help. Your book arrived yesterday.
and we said...
It is the same issue as for procedures/views:
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
you need direct access to core.journal

SQL> grant REFERENCES on core.journal to YOUR_ACCOUNT;

try this:

SQL> set role none
SQL> desc core.journal

that should fail -- indicating you have the grant via the role.

Hope you enjoy the book.
Review & Followup
Rating: 5
It did the job. July 10, 2001
Reviewer: Nick from Richmond, VA

Rating: 5
Thank you so much February 23, 2003
Reviewer: Jonas from Berkeley, CA
I was searching for an hour for this answer. This is exactly the information I
needed.

July 10, 2001 -- Thanks for the question regarding "unrecoverable and logging", version 8.1.7
You Asked
Tom

1.create table b UNRECOVERABLE as select * from a;

In the above statement what does unrecoverable mean?

Can you give me the link to the document , where in I can get the full syntax
for all the sql commands and there explanation and examples( I find the syntax
at a few places but not there explanation nor examples).

2.What does the option logging and no logging mean? can you please explain.

3.I remember you replying to me that you wrote only one book, but in amazon.com
, when I search under your name it pulls up 2 books, did you also contribute a
few chapters, in any other book.

Thank you
and we said...
1) the SQL reference manual has the syntax for everything, followed by examples
http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/toc.htm
The syntax and examples are all physically collocated.

(i should have used NOLOGGING actually but they are the same)

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/ch4g9.htm#65765
for what nologging does for yuo.

2) see #1, they are the same as unrecoverable/recoverable

3) I wrote chapter 16 of Professional Oracle 8i Application Programming with
Java, PL/SQL and XML
July 10, 2001 -- Thanks for the question regarding "NAGLE", version 8.1.6
You Asked
Tom:

what is NAGLE?
and what's benefit and disadvantage by setting
tcp.no_delay=true in protocol.ora?

Regards
and we said...
Do you mean the Nagle Algorithm in relation to TCP/IP:

            A TCP SHOULD implement the Nagle Algorithm [TCP:9] to
            coalesce short segments.  However, there MUST be a way for
            an application to disable the Nagle algorithm on an
            individual connection.  In all cases, sending data is also
            subject to the limitation imposed by the Slow Start
            algorithm (Section 4.2.2.15).

By default, SQL*Net waits before transmitting a request until the
SDU buffer is filled up. This can mean in some occasions that a
request is not send immediately to its destination.
By specifying the 'no_delay' parameter, this buffering is skipped
and every request is send straight away. A practical implication of
this is that the network traffic can increase due to the smaller
(and more fequent) network packets being transmitted between the
client and the server.

This parameter should only be used if TCP timeout are encountered.
July 10, 2001 Chris -- Thanks for the question regarding "Selective ORDER BY", version 8.1.6.3
You Asked
Hi Tom,

We are currently looking to order a query that returns the titles of books.
When ordering (very simply) the order takes into account the "The" string in
book titles.
I want the query to return the book titles in alphabetical order ignoring the
'The' part of the title.

How can this be achieved???

Thanks Mr Kyte!!

Chris
and we said...
order by
 replace( upper(decode( instr(upper(x),'THE '), 1, substr(x,5),x)),
                                                          ' THE ', ' ' )

where X is you column name will do a case insenstive sort on X replacing all
THE's with ' ' and removing, if need be, the leading THE.

If you have puncuation in the title, we can remove that as well using a
TRANSLATE function call.
Review & Followup
Rating: 5
July 11, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

July 11, 2001 Ed -- Thanks for the question regarding "PARTITION names in a stored procedure", version 8.1.7.1
You Asked
Hi Tom--
I have the most vexing problem-- I have a stored procedure to look at a very
volatile table consisting of 150 partitions, if the partition is empty,
truncate.  Long story, but the partitions of this table can grow enormously and
be deleted from in their entirety by an application.  I would like this truncate
routine to run at night (no contention with users) and lower the high water mark
of these partitions to help performance.

This is the procedure:
==================================================================
CREATE OR REPLACE PROCEDURE CLEANUP_SANDBOX AS
v_count NUMBER;
v_partition_name VARCHAR2(30);
sql_statement VARCHAR2(100);

cursor SANDBOX_USERS IS
select unique partition_name from USER_TAB_PARTITIONS
where TABLE_NAME like 'CONFIG_SANDBOX';

BEGIN
FOR SANDBOX_RECORD IN SANDBOX_USERS LOOP

    v_partition_name := sandbox_record.partition_name;

 DBMS_OUTPUT.PUT_LINE(v_partition_name);

SELECT count(*) INTO v_count FROM xcm.config_sandbox partition
(v_partition_name);

 if v_count = 0 THEN
 DBMS_OUTPUT.PUT_LINE(v_count);
 sql_statement := 'ALTER TABLE XCM.CONFIG_SANDBOX TRUNCATE PARTITION
PT'||v_partition_name;
 DBMS_OUTPUT.PUT_LINE(sql_statement);
 EXECUTE IMMEDIATE sql_statement;
 DBMS_OUTPUT.PUT_LINE('TRUNCATED PARTITION '||v_partition_NAME);
 end if;

END LOOP;
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE(SUBSTR(SQLERRM,1,80));
END;
=================================================================
I consistently get invalid partition name (ora-02149).  Why?  Config_sandbox has
150 partitions name 'PT1'...'PT150'. When I run this as a PL/SQL block in
SQLPlus and supply the partition name (eg. PT1) it runs good as gold.  My
dbms_output of partition_name supplies 'PT1' (see below) so this is correctly
getting into the variable.  I would guess a datatype mismatch is going on but
from all I can discover the partition_name is varchar2(30).

serveroutput:
SQL> execute xcm.cleanup_sandbox
PT1
ORA-02149: Specified partition does not exist

PL/SQL procedure successfully completed.

Any suggestions?
and we said...
You cannot use varibles where an IDENTIFIER is mandatory - the queries:

select * from t partition (p1);
select * from t partition (p2);

are totally different queries and need to be parsed/optimized/security checked
and everything separately.

You must use dynamic sql.

A faster approach, rather then read every row, is just check for A row:

  execute immediate
  'select count(*)
     from dual
    where exists ( select NULL
                     from xcm.config_sandbox
                          partition( ' || v_partition_name || ')
                 )' INTO v_count;

That'll do as little work as possible....
July 11, 2001 Randy -- Thanks for the question regarding "SID descriptor length", version 8.1.7
You Asked
Exactly what are the rules on the length and format of a SID?  I've always used
4-character long SIDs, but wondered:

-are there any problems with a length of 2 or 5 characters?
-does it have to start with a letter?
-have the rules changed with newer versions?

Thanks.
and we said...
The SID length is dependent on the version and OS.  For example, from the win/nt
admin guide for 816:

For releases 8.1.3 through 8.1.6, the SID can be a maximum of 64 alphanumeric
characters in length. For all releases prior to
8.1.3, the SID was a maximum of 4 alphanumeric characters.

So, it is dependent on the OS and version.  Please consult your OS admin guide
for limits.

Note: various tools may have other limits, eg: the dbassist tool stops you at 8
character.
July 11, 2001 Girish -- Thanks for the question regarding "Oracle Data dictionary", version 9i
You Asked
Dear Tom,

I am looking for a place from where I can download the tree view of
Oracle Data Dictionary, which will give me the various system table
and views that Oracle maintains, and the relationships between these
tables.

Thanks,
Girish.
and we said...
You might be intereseted in
http://www.revealnet.com/pipelines/dba/archives/wpoddusr.htm
http://www.revealnet.com/pipelines/dba/archives/wpdbaerd.htm
and there may be others out there but I'm not aware of them personally
Review &
      Followup

      Rating: 5
one of many
      daily viewers  July 11, 2001
Reviewer:  WL
       from Round Rock, TX USA
A great link, thanks Tom as always.

      Rating:
      5
  July 11, 2001
Reviewer:  Pauline
       from NY,U.S.A.
Tom's great link just likes a right key. It leads us to open
a door and obtain many good stuff.

      Rating: 5
Fantastic
      !!!!  July 12, 2001
Reviewer:  Vidyesh
       from India
That's fascinating TOM!! A great help.

      Rating:
      5
  July 12, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

      Rating:
      5
Great  July 12, 2001
Reviewer:  Ganesh
      R  from India

      Rating: 5
Just about the
      best link yet..  July 12, 2001
Reviewer:
      Ken  from Maryland, USA
  Every DBA should have this.  I wonder if Revealnet has hard-copy posters?
Thanks again Tom.

      Rating: 5
Great
      Information, Thanks  July 12, 2001
Reviewer:
      Yatman  from Markham, ON Canada
This is great. Every DBA should bookmark the URL.

      Rating:
      3
dictionary  July 21, 2001
Reviewer:
      Umesh S. Kasrturi  from Bangalore , India
A real key to the Oracle Dictionary

July 11, 2001 Janette -- Thanks for the question regarding
      "SQLLOADER - Error Field in data file exceeds maximum length", version
      8.1.6

      You Asked
Hi,
I am trying to load a data file into a database table using SQL loader. I
received the data in an Excel spreadsheet but I saved it as a comma delimited
file.
When I run the SQL Loader command no records are loaded - looking at the log
file I get the following error:
  Rejected - Error on table PROSPECTUS, column PR_FULL_DESC.
  Field in data file exceeds maximum length
I don't understand why this is happening as the maximum length of the
PR_FULL_DESC field for any record I've attempted to load so far is 400
characters long and the field definition in the database table is
VARCHAR2(4000).
Please help!
Thanks,
Janette

The control file I used is:
LOAD DATA
INFILE 'p.dat'
APPEND  INTO TABLE PROSPECTUS
FIELDS  TERMINATED BY ','  OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS
(
PR_CODE         NULLIF PR_CODE=BLANKS,
PR_NAME         NULLIF PR_NAME=BLANKS,
PR_REF_NUM    NULLIF PR_REF_NUM=BLANKS,
PR_TRANSACTION         NULLIF PR_TRANSACTION=BLANKS,
PR_SHORT_DESC          NULLIF PR_SHORT_DESC=BLANKS,
PR_FULL_DESC           NULLIF PR_FULL_DESC=BLANKS,
PR_LOCN         NULLIF PR_LOCN=BLANKS)

Database Table - PROSPECTUS:
 Name                            Null?    Type
 ------------------------------- -------- ----
 PR_CODE                          VARCHAR2(30)
 PR_NAME                          VARCHAR2(30)
 PR_REF_NUM                     VARCHAR2(30)
 PR_TRANSACTION                          VARCHAR2(6)
 PR_SHORT_DESC                           VARCHAR2(1000)
 PR_FULL_DESC                            VARCHAR2(4000)
 PR_LOCN                          VARCHAR2(80)

Sample data (just one record):
PADDY,,PRP002,C,"A bright, spacious, attractive, ground floor, three bedroom
apartment, situated on the corner of Townsend Street and Lombard Street East","A
bright, spacious, attractive, ground floor, three bedroom apartment, situated on
the corner of Townsend Street and Lombard Street East. Trinity Square is well
located within walking distance of Trinity College, I.F.S.C., Pearse Street DART
station and Temple Bar. The apartment will be sold with the benefit of a secure
private car space.",CARDIFF,

      and we said...
The default datatype in SQLLDR is char(255).  Simply code:
...
PR_SHORT_DESC   char(1000)       NULLIF PR_SHORT_DESC=BLANKS,
PR_FULL_DESC    char(4000)       NULLIF PR_FULL_DESC=BLANKS,
....

in the control file to have sqlldr allocate a big enough buffer to hold it

Review &
      Followup

      Rating: 5
thanks for the
      sqlldr response  October 23, 2001
Reviewer:
      Gail  from Cleveland OH 44118
it helped me with my sqlldr error getting the

Field in data file exceeds maximum length

message.

Gail

      Rating: 5
SQLLDR Varchar2
      Max Lengths  August 28, 2002
Reviewer:  Jeff
      W  from San Francisco, CA, USA
When in doubt, consult "Ask Tom" first!!  I spent hours trying to figure out
what I found on your site in less than 5 minutes!  Search is powerful and answer
I was looking for was right on the money.

Thanks Tom!!

      Rating: 5
Thank
      god...  February 04, 2003
Reviewer:  john
       from manhattan
I guess this was in the concepts guide somewhere, but beats me if I remember
ever having seen it...

Thank god Tom addressed this as it had been driving me crazy...

July 12, 2001 il hwan -- Thanks for the question regarding "why
      is difference between trace statistics...", version 8.0.6.1

      You Asked
First,after customer executing program from client,we've got a trace like below.
SELECT/*+ INDEX(A PK_TAS_TRSR_RECP_BASE) */
A.TAXI_CLMN_C,B.TAXI_CLMN_NM,COUNT(*),SUM(A.M_TX+A.ETAX+A.FTAX)
  FROM ASD.ASTSRB A,ASD.ASTXCC B WHERE A.ORG_C=:b1 AND A.ORG_C=B.ORG_C AND
A.TAXI_CLMN_C=B.TAXI_CLMN_C AND A.RECP_BR_C=:b2 AND A.RECP_DATE IN(SELECT YYMMDD

FROM COD.COYYMD WHERE YYMMDD BETWEEN:b3 AND:b4)AND A.TR_TC=:b5 GROUP BY
A.TAXI_CLMN_C,B.TAXI_CLMN_NM

call countcpu    elapsed  disk    query    current    rows
------- -------------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch       29      2.00       3.12       2326      96617          0          28
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       31      2.00       3.13       2326      96617          0          28

second,I asked what variable input had been input.
after replacing binding variable,connect to system user and run it.
we've got like below trace file.

SELECT/*+ INDEX(A PK_TAS_TRSR_RECP_BASE)   */
A.TAXI_CLMN_C,B.TAXI_CLMN_NM,COUNT(*),SUM(A.M_TX+A.ETAX+A.FTAX)
  FROM ASD.ASTSRB A,ASD.ASTXCC B WHERE A.ORG_C='001'AND A.ORG_C=B.ORG_C AND
A.TAXI_CLMN_C=B.TAXI_CLMN_C AND A.RECP_BR_C='701' AND   A.RECP_DATE IN(SELECt
YYMMDD FROM COD.COYYMD WHERE YYMMDD BETWEEN '20010710' AND '20010711') and
a.tr_tc = '01'
  GROUP BY A.TAXI_CLMN_C,B.TAXI_CLMN_NM

call countcpu    elapsed  disk    query    current    rows
------- -------------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        3      0.01       0.02          38        871          0
28
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        5      0.02       0.02          38        871          0
28

I wonder why block io in query,current column between first and second
is different.
I heard from my customer that sometimes first one resulted in time out.
that's why I tried test like above.
I want to let my customer know why this is happening.
thank you!

      and we said...
Well, first of all -- look at the first tkprof.

It did not time out, it returned 28 returns (a row at a time) in 3.12 seconds.
No time out there?

Second, the difference in query plans for:

select * from t where x = :x

and

select * from t where x = 'constant'

can be astronomical -- you don't show the plans.

Third -- it took 2,326 physical IOs to satisfy their query -- yours took 38.
This can be caused by many factors.  I would have to assume that during the
first run, the system was being used "normally" -- meaning there were many
modifications being made to the base tables.  This can be a side effect of our
consistent read mechanism and what you are seeing are reads to the rollback
segments.  Now, with such a large disparity between the two runs, one might
guess that your buffer cache is woefully undersized.

You array size (or lack of an array fetch in the first example) is affecting
this as well-- see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:880343948514
where I demonstrate how the same query in the same environment against the same
data can result in anywhere from 686 to 22 consistent gets -- all by playing
with the array fetch size.  You used an array fetch size of at least 10 in the
second example (3 fetches, 28 rows).  Your array size was 1 in the first example
(29 fetches, 28 rows).
July 12,
      2001 Robert -- Thanks for the question
      regarding "Container", version 8.1.6

      You Asked
DROP FUNCTION RET_SEQUENC;

CREATE OR REPLACE FUNCTION RET_SEQUENC(ID NUMBER) RETURN TABLEAU IS

TABL TABLEAU;

BEGIN

        FOR V_COUNT IN 1 .. ID LOOP

        SELECT SIRTF_SEQNC_UNIQ.NEXTVAL INTO TABL(V_COUNT) FROM DUAL;

        END LOOP;

        RETURN TABL;

END;
/
That's my function who return a array. ok
if a got select statement like this.

select RET_SEQUENC(3) from dual; will return this error
"ERROR at line 1:
ORA-06531: Reference to uninitialized collection
ORA-06512: at "SIRTF_CSE_PAY.RET_SEQUENC", line 10
ORA-06512: at line 1"
How do that please how make a array in the select statement.
Thanks Bob

      and we said...
ops$tkyte@ORA8I.WORLD> create or replace type tableAu as table of number
  2  /
Type created.

ops$tkyte@ORA8I.WORLD> drop sequence my_seq;
Sequence dropped.

ops$tkyte@ORA8I.WORLD> create sequence my_seq;
Sequence created.

ops$tkyte@ORA8I.WORLD> create or replace function ret_sequence( p_cnt in number
) return tableAu
  2  as
  3          l_data tableAu := tableAu();
  4  begin
  5          for i in 1 .. p_cnt
  6          loop
  7                  l_data.extend;
  8                  select my_seq.nextval into l_data(i) from dual;
  9          end loop;
 10
 11          return l_data;
 12  end;
 13  /

Function created.

ops$tkyte@ORA8I.WORLD> select ret_sequence(3) from dual
  2  /

RET_SEQUENCE(3)
-----------------------------------------------------
TABLEAU(1, 2, 3)
Review & Followup

      Rating: 5
You are the
      best !!!  July 12, 2001
Reviewer:  Robert
      Thibault  from Canada (quebec)
Thanks Tom for all.
Your take a time for my question and i very appreciate that
Have a good !
Bob

July 12, 2001 -- Thanks for the question regarding "Pinning
      Scripts on NT Automatically ...", version version 8.1.5

      You Asked
I would like to know how to pin the objects automatically when the Instance is
up automatically on WINDOWS NT.

Also need to know few tips regarding improving performance on NT.

      and we said...
We would use a STARTUP database trigger to accomplish this.  Here is a small
example showing the pinning of a sequence in the shared pool upon startup:

SQL> drop sequence scott.my_seq;
Sequence dropped.

SQL> create sequence scott.my_seq;
Sequence created.

SQL> create or replace trigger PIN_STUFF
  2  after startup on database
  3  begin
  4          sys.dbms_shared_pool.keep( 'SCOTT.MY_SEQ', 'Q' );
  5  end;
  6  /
Trigger created.

SQL> shutdown
Database closed.
Database dismounted.
ORACLE instance shut down.

SQL> startup
ORACLE instance started.

Total System Global Area   43775244 bytes
Fixed Size                    70924 bytes
Variable Size              38825984 bytes
Database Buffers            4800512 bytes
Redo Buffers                  77824 bytes
Database mounted.
Database opened.
SQL>
SQL> select owner, name, kept
  2    from v$db_object_cache
  3   where owner = 'SCOTT'
  4  /

OWNER      NAME       KEPT
---------- ---------- -----
SCOTT      MY_SEQ     YES

As for improving performance on NT, it really won't be significantly different
then on Unix or MVS.  90% of the tuning is done at the application level (tuning
queries and such) and is fairly easily accomplished with SQL_TRACE,
TIMED_STATISTICS and TKPROF.

The guide:

http://technet.oracle.com/doc/server.815/a67775/toc.htm
is the server tuning guide which covers all of these topics in great detail.

followup to comment

It must be installed as SYS (or internal or "/ as sysdba")

A public synonym is NOT created for it, no grants are made on it.  So, after you
install it as SYS, you must grant yourself DIRECT (not via a role) access to it
to create the above trigger.
Review &
      Followup

      Rating:
      4
DBMS_SHARED_POOL  July 12, 2001
Reviewer:
      Gururaj Kulkarni  from Norcross GA, USA
Hi Tom,
could you tell me how do I create package
dbms_shared_pool ? I tried running dbmspool.sql, but
it created with compilation errors.

Thanks in advance
-Gururaj

July 12, 2001 Mohammad -- Thanks for the question regarding
      "dbms_utility_analyze", version 8.1.6.3.0

      You Asked
I try to define atrigger after
startup on database that analyze the users Tables.

Each time i started the database i got this error

create or replace procedure analyze_schema
is
sl number;
begin
sl:=180;
dbms_lock.sleep(sl);
dbms_utility.analyze_schema('TEST','COMPUTE');
end;
create or replace trigger analyze_trigger
after startup on database
begin
sys.analyze_schema;
end;
The errors in the alert file look like this
Errors in file C:\Oracle\admin\oracle\udump\ORA01312.TRC:
ORA-00604: Fehler auf rekursiver SQL-Ebene 1
ORA-30511: Ungultiger DDL-Vorgang in Systemtriggern
ORA-06512: in "SYS.DBMS_DDL", Zeile 161
ORA-06512: in "SYS.DBMS_UTILITY", Zeile 254
ORA-06512: in "SYS.ANALYZE_SCHEMA", Zeile 16
ORA-06512: in Zeile 2

I asked by oracle and i become the following answer

An attempt was made to perform an invalid DDL operation in a system
trigger. Most DDL operations currently are not supported in system
triggers. The only currently supported DDL operations are table
operations and ALTER/COMPILE operations.
Action:
Remove invalid DDL operations in system triggers.
.
It is not possible to use ANALYZE_SCHEMA in the startup trigger (which is a
system trigger)

Is there any way to define such trigger to analyze schema?

best regards
Mohammad Salameh

      and we said...
This would be a really bad idea, a truly bad idea.  You don't want to wait for
this every time you startup do you?

If you really want to analyze the schema upon startup, what I suggest you do is

create or replace trigger analyze_trigger
after startup on database
declare
  l_job number;
begin
  dbms_job.submit( l_job, 'sys.analyze_schema;' );
end;
/

And configure the job queues to be running if they are not.  This will cause the
schema to be analyzed right after the database is up and running.

July 13, 2001 Sudip -- Thanks for the question regarding
      "Locally managed Tablespaces and Partitioning", version 8.1.6

      You Asked
Hi! Thomas,

1)When a export import is done on a schema which is based on locally managed
tablespace. The import doesnot defragment the tablespace. Where as when the
import is done on a dictionary managed tablespace then defragmentation happens?
Why?

2) Is it possible to change a table with huge data set to a partitioned table?
How?

3) I have been trying to send email through database using utl_smtp package. Now
I am able to send mail in unix prompt by mail; -tw command. My oracle server is
on the same machine and utl smtp is giving the following error (I got the
procedure from yr site and was trying it out) -

CREATE OR REPLACE PROCEDURE mysend_mail (sender    IN VARCHAR2,
                     recipient IN VARCHAR2,
                     message   IN VARCHAR2)
IS
    mailhost    VARCHAR2(30) := '155.201.244.74';
    mail_conn  utl_smtp.connection;

BEGIN
    mail_conn := utl_smtp.open_connection(mailhost, 25);
    utl_smtp.helo(mail_conn, mailhost);
    utl_smtp.mail(mail_conn, sender);
    utl_smtp.rcpt(mail_conn, recipient);
    utl_smtp.data(mail_conn, message);
    utl_smtp.quit(mail_conn);
EXCEPTION
    WHEN OTHERS THEN raise;
        -- Handle the error
END;

exec
mysend_mail('SudipSarkar@rediffmail.com','sudip.sarkar@in.pwcglobal.com','Trial
MAil from Oracle');

ERROR at line 1:
ORA-29540: class oracle/plsql/net/TCPConnection does not exist
ORA-06512: at "EPRO.MYSEND_MAIL", line 16
ORA-06512: at line 1

SQL> !oerr ora 29540
29540, 00000, "class %s does not exist"
// *Cause: Java method execution failed to find a class with the indicated name.

// *Action: Correct the name or add the missing Java class.

Sorry for asking so many questions, but I was piling them up as I was getting
the access.

Regards
 Sudip

      and we said...
1) i have no idea what you mean.  If you consider a table in multiple extents to
be "fragmented" -- don't.  It is normal, desirable and totally OK.  I love LMT's
and I am not at all afraid to have a table with hundreds/thousands of extents.

I hate dictionary managed tablespaces.

2) as the data must be totally reorg'ed (physically moved) your choices are:

o create a new partitioned table and direct path insert into it
o create a new partitioned table as select
o export the existing table, drop it and recreate it and import it with ignore=y

You can turn a table into a partitioned table with a single partition but that
is not very useful (all of the data would be in a single partition)

3) see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:958229976043
and make sure you have the java server stuff installed as well
Review &
      Followup

      Rating: 4
Export and
      import  July 14, 2001
Reviewer:  Sudip
       from Calcutta, India
Thomas,
Many Thanx for the answers.

July 13, 2001 David -- Thanks for the question regarding
      "Monitoring extends", version 8.1.7.0.0

      You Asked
I would like to be able to find out the last time any database object took a new
extent, to assist in monitoring ongoing object growth.  Is that information
stored anywhere in the data dictionary - or in the underlying tables/views?

      and we said...
No, it is not stored (especially with locally managed tablespaces - the only
kind to use in 8i and up, as they are simply bitmaps).

What I've seen people do is take regular snapshots of the DBA_EXTENTS table

create table extents_log as select sysdate ts, dba_extents.* from dba_extents;

and then every day or whatever, run:

  1  insert into extents_log
  2  select sysdate, e.*
  3    from ( select OWNER, SEGMENT_NAME, PARTITION_NAME, SEGMENT_TYPE,
                     TABLESPACE_NAME,
  4                  EXTENT_ID, FILE_ID, BLOCK_ID, BYTES, BLOCKS, RELATIVE_FNO
  5             from dba_extents
  6           MINUS
  7           select OWNER, SEGMENT_NAME, PARTITION_NAME, SEGMENT_TYPE,
                     TABLESPACE_NAME,
  8                  EXTENT_ID, FILE_ID, BLOCK_ID, BYTES, BLOCKS, RELATIVE_FNO
  9             from extents_log
 10*        ) e
ops$tkyte@ORA8I.WORLD> /

July 13, 2001 -- Thanks for the question regarding "sys/system
      acount", version 8.1.7.0

      You Asked
Hi Tom

U always say dont use sys/system they r dba accounts.
What r the problems we are going to face by using sys/system
account. I create a table in system account with tablespace users.
Is there going to be any problem?.

Or is it just a thumb rule and precautinary measure?

Regards

      and we said...
SYS is special, it has special rules.  It is the owner of the data dictionary.
In fact in Oracle9i, unless you change an init.ora parameter, you cannot even
log in as SYS.

SYS is an account you should use only when pressed.

Now, as for SYSTEM.  It is an Oracle account.  It holds Oracle objects -- queues
and such.  It is part of the database.  It is ours.  Just don't use it.  It is a
bad idea. There is no reason to, there are only reasons not to (it is part of
the database, drop something it owns "by accident", changes it privileges "by
accident", do anything -- your database might stop working properly).

Just don't do it, get out of the habit of doing it.  It is not necessary, nor is
it even the easiest approach (after your done testing, its nice to be able to
drop the test schema).  Just create accounts for yourself and use them.
July 13, 2001 Rajesh -- Thanks for the question regarding
      "Creating a Clone of an existing Active DB", version 8.1.6.3

      You Asked
Tom,I have a relatively large DB running on NT 4.0. I have to create a duplicate
database (same data, tablespace etc. with a different name) on the same machine.
What is the easiest way to accomplish this ? I think, export/import is not the
most convenient way considering the limitation on the size of the dump file.
Thanx in anticipation.

A suggestion...Can there be a way that whatever new question is posted in this
forum and your reply to that question are emailed to the registered people on
the daily or periodical basis. OR the links can be emailed so that all who are
interested can follow the link and come to the site and pickup the question as
well as your answer to that.

      and we said...
I would backup the database (cold backup be easiest), and restore it.  It'll be
very much like the steps outlined in:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:634671569269
which show how to rename a database but you can COPY the files instead of
renaming them (you want a copy -- not a rename) and don't delete the old
service.

Suggestion: do a backup before you do this, just in case

As for the suggestion, navigate to my home page and click on the Search/Archives
tab.  Then goto archives.  I have all of my answers listed by date of last
modification by week there.  If you want to get the last weeks worth -- they are
all there on one big page, suitable for printing/downloading/whatever.
Review &
      Followup

      Rating: 5
Extremely
      Thankful  July 14, 2001
Reviewer:
      A reader

July 14, 2001 Alex -- Thanks for the question regarding "Force
      password prompt for internal in UNIX", version 8.1.7

      You Asked
Hi

Is it possible to force user oracle in UNIX to enter the internal password when

sqlplus internal is used?

Or connect internal will always work without asking password if we are an unix
user in group DBA?

      and we said...
Nope....  no password for INTERNAL if you are using Unix and in the proper
group.

Yes.... it'll work if you are in the proper group

this is one of the reasons connect internal is going away in 9i, it is
implemented differently on different platforms.  On NT it is possible to
password protect internal.

"as sysdba" will be used to connect internal in 9i exclusively, giving us a
consistent implementation.
July 14,
      2001 Alex -- Thanks for the question
      regarding "Why these tables/views can be qieried without roles", version
      8.1.6

      You Asked
Hi

I have created an user with only create session privilege and no roles but this
user is able to query some V$ views/tables (however I have to put username in
front, such as sys.v_$LOADCSTAT) why is this? I thought the user needs to have
select_catalog?role to query these tables?

      and we said...
they are granted to PUBLIC, anyone can see them:

  1  select owner, table_name
  2  from dba_tab_privs
  3  where grantee = 'PUBLIC'
  4* and privilege = 'SELECT'
ops$tkyte@ORA817.US.ORACLE.COM> /

OWNER                          TABLE_NAME
------------------------------ ------------------------------
SYS                            DUAL
SYS                            SYSTEM_PRIVILEGE_MAP
SYS                            TABLE_PRIVILEGE_MAP
SYS                            STMT_AUDIT_OPTION_MAP
SYS                            V_$BH
SYS                            V_$SESSION_LONGOPS
SYS                            V_$NLS_PARAMETERS
SYS                            V_$NLS_VALID_VALUES
SYS                            V_$MLS_PARAMETERS
SYS                            V_$OPTION
SYS                            V_$VERSION
SYS                            V_$PQ_SESSTAT
SYS                            V_$SESSION_CONNECT_INFO
SYS                            V_$PQ_TQSTAT
SYS                            V_$ACTIVE_INSTANCES
SYS                            V_$LOCK_ACTIVITY
SYS                            V_$RSRC_CONSUMER_GROUP_CPU_MTH
SYS                            V_$RSRC_PLAN_CPU_MTH
SYS                            V_$RSRC_CONSUMER_GROUP
SYS                            V_$RSRC_PLAN
SYS                            V_$TEMPORARY_LOBS
SYS                            V_$MAX_ACTIVE_SESS_TARGET_MTH
SYS                            V_$PARALLEL_DEGREE_LIMIT_MTH
.......
July 14, 2001 Maruti -- Thanks for the question regarding "Data
      Loading from one db into another.", version 8.1.6

      You Asked
I would like to populate a database with data from another database? Is there
way ofdoing it without exporting and importing ?

I want to avoid the 2 stage of process of export and import.

thanks,

      and we said...
sqlplus copy command

http://technet.oracle.com/doc/oracle8i_816/sqlplus.816/a75664/ch816.htm#1013063
or a database link work well.

July 14, 2001 -- Thanks for the question regarding "formatting
      tracefiles...", version 8.1.7

      You Asked
Hello tom,

I changed timed_statistics=true and enabled sql_trace in the current session.
Then I would like to run TKPROF on that trace file.  But there were already many
tracefiles available.  How should I find a trace file that I generated.

Can I add some text 'check', or 'sql' etc to trace file names, before creating,
so that it will be easy for me to find out.

thankyou very much

      and we said...
On NT, this does it:

select c.value || '\ORA' || to_char(a.spid,'fm00000') || '.trc'
  from v$process a, v$session b, v$parameter c
 where a.addr = b.paddr
   and b.audsid = userenv('sessionid')
   and c.name = 'user_dump_dest'
/

On Unix, its :

select c.value || '/' || d.instance_name || '_ora_' ||
               to_char(a.spid,'fm99999') || '.trc'
  from v$process a, v$session b, v$parameter c, v$instance d
 where a.addr = b.paddr
   and b.audsid = userenv('sessionid')
   and c.name = 'user_dump_dest'
/

July 15, 2001 Erik -- Thanks for the question regarding
      "Creating a Java stored procedure with String array parameters", version
      8.1.7

      You Asked
Tom,

I would like to create a stored procedure for a method in a Java class.  The
method takes several parameters, two of which are String arrays - the lengths of
the arrays are not the same and will vary.  For example,

public class MyClass
{
   public static void doStuff(String   a,
                              String[] b,
                              String[] c)
   {
      // process the input
   }
}

I was able to load the class into the database using the loadjava command, but I
haven't found an example for the create procedure command using String arrays.
Could you tell me how to create the procedure and also give an example of how to
call the procedure from SQLJ client code.

Thanks for your help.

Erik

      and we said...
Well, you'll have to write YAJL (yet another java layer) to create a Java
routine that is callable from SQL (it will use a collection type) and it will
convert the collection into a java string array -- call your doStuff and then
(if need be) convert the java string arrays back into SQL collections.  There is
no direct mapping to each and every possible Java Type -- rather, to/from each
and every SQL type there is a mapping.  The java stored procedures you call
directly from the SQL layer are confined to using SQL types only.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:986230504001
it will show "java passing to plsql" (thats the SQLJ client passing an array to
the SQL layer for you) and "plsql passing to java" which shows what your YAJL
will recieve and how to deal with it.
July 15, 2001 Omar
      -- Thanks for the question regarding "Effect of "alter table x set
      unused..." on space usage on subsequent inserts", version 8.1.6

      You Asked
Hi,
      we have what we consider a large table with 201 columns of
which we'd like to drop 140. The table uses up 37GB. I estimate that
dropping the columns will take more than 3 weeks, so my question is:
if we set the columns to unused and then load more data (through
sqlldr, as we do every month) what effect does that have on space
usage from then on? In other words, is the space for the "unused"
columns still used or we can count that as freed space from that
point onwards? Thanks in advance.

Regards,
Omar Charles

      and we said...
You must have the slowest disks on the entire planet if you thing it would take
3 weeks to reorg a mere 37gig of data.  I have laptops with more storage then
that and would expect to be able to do that in hours, not weeks.

Anyway.

If you set a column to unused, it is flag deleted.  The space is not and will
not be reclaimed.

Only when you drop the columns (and I cannot imagine it taking 3 weeks) will
space be reclaimed.

A thought just hit me -- are you thinking 3 weeks due to the serial nature of
drop column, drop column, drop column 140 times?  If so, you can set unused the
140 columns and drop them ALL at the same time using "drop unused".  You can
even have that checkpoint so that its restartable in the event of a failure
partway through and so that it doesn't chew up all of your rollback.

Also, if the 61 remaining columns are a pretty small percentage of the total
volume of data, consider:

create table tmp UNRECOVERABLE as select <columns to keep> from old_table;

perhaps using parallel query even.... and then drop old_table, rename tmp to
old_table and then index/grant/etc on it.
Review &
      Followup

      Rating:
      4
  July 16, 2001
Reviewer:  Omar
      Charles  from Canberra, ACT, Australia
The information provided was really useful in that we found
a problem with dropping a large number columns from a table
in Oracle 8.1.6 (there is a known bug that was fixed in
8.1.7).

What wasn't too clear is: does the new data keep using
storage for the unused columns or not? From the sentence
"The space is not and will not be reclaimed" I feel
inclined to assume the storage space will keep being used,
but it could have been explained a bit better.

Very useful and prompt reponse though.

July 15, 2001 yuwen -- Thanks for the question regarding "how
      make to oracle8i Database synchronization?", version 8.1.7

      You Asked
Hi Tom

   I have cloned a 8i database form  node A to node B(both node have the same os
windows2000),node A is for OLTP( in archivelog mode).
   I want to know how to apply archived log in node A  to node
B,so both of node are in synchronization.

      and we said...
That is called a standby database configuration

read

http://technet.oracle.com/doc/oracle8i_816/server.816/a76995/toc.htm
it tells you everything about it.
Review &
      Followup

      Rating: 3
No another way
      do this?  July 15, 2001
Reviewer:  yuwen
       from china
Node B must be a standby database? if not ,can I make the two nodes
synchronization?

July 15, 2001 -- Thanks for the question regarding "values less
      than", version 8.1.7

      You Asked
ops$tkyte@ORA815> CREATE TABLE t
  2  ( cc        varchar2(2) check ( cc in ( 'US', 'UK' ) ),
  3    type_code varchar2(1) check ( type_code in ('A','B','C') )
  4  )
  5  PARTITION BY RANGE (cc, type_code)
  6  ( PARTITION p1 VALUES LESS THAN ( 'UK', 'B' ) tablespace users,
  7    PARTITION p2 VALUES LESS THAN ( 'UK', 'C' ) tablespace users,
  8    PARTITION p3 VALUES LESS THAN ( 'UK', 'D' ) tablespace users,
  9    PARTITION p4 VALUES LESS THAN ( 'US', 'B' ) tablespace system,
 10    PARTITION p5 VALUES LESS THAN ( 'US', 'C' ) tablespace system,
 11    PARTITION p6 VALUES LESS THAN ( 'US', 'D' ) tablespace system
 12  )
 13  /
Table created.

o.k. Tom , I have a table as above and  now if I have a new cc like ..
uk-regular and I want all the values for uk-regular to go into a different
partition.. how should I give the bound  i.e. valuess than  ???

same thing with US.. what if I have a new code... US-NONREGULAR,  and I want all
the records with this code to go into a separate partition..

2.When you say 'PARTITION p1 VALUES LESS THAN ( 'UK', 'B' ) ' and
do insert into t values('UK', 'B'), where will they go and reside, becasue there
is no partition like ..VALUES LESS THAN ( 'UJ', 'A' ) '.

My question actually is 'insert into t values('UK', 'B')'.. will it insert the
record into p1.... more specifically , when you say values less than.. does it
mean values less than and equal to ..

Nag

      and we said...
1) It is LESS THAN, not LESS THAN OR EQUAL TO.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:930642161660
for the original example, it shows what goes where when you insert the values.

UK-REGULAR would go into the partition LESS THEN ('UK', 'S')  (S being the next
thing AFTER R, anything that starts with R is less than S).

2) 'UK', 'B' will go into partition p2.  'B' is not less than 'B', 'B' is less
then 'C', hence p2 is where it will go.

I do not understand the sudden reference to 'UJ', 'A'

July 15, 2001 joselmo -- Thanks for the question regarding
      "java.io.IOException when executing rc", version 8.1.7

      You Asked
Hi Tom, I'm using Oracle 8.1.7 on Windows NT.

about

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:952229840241
When i execute  rc('DIR') de oracle return this:

java.io.IOException
at oracle.aurora.java.lang.OracleProcess.create(OracleProcess.java)
at oracle.aurora.java.lang.OracleProcess.construct(OracleProcess.java)
at java.lang.Runtime.execInternal(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at Util.RunThis(Util:14)

Can you help me?
 Thank you!

      and we said...
DIR is not a program.  DIR is an argument that command.com/cmd.exe understands
and processes.

Something like:

cmd /c dir

would work BUT you would need to give privs on  C:\WINNT\system32\cmd.EXE which
basically allows them to run ANY command.

Pick some EXECUTABLE to run.
Review &
      Followup

      Rating:
      4
java.io.IOException  July 16, 2001

Reviewer:  Joselmo Carvalho  from Rio, Brazil

Thank you so much, Tom!!!!

Your solution is runing :O)

Thank you, again!!!

July 15, 2001 Pichaimani -- Thanks for the question regarding
      "Creating snapshots for existing tables with triggers", version 8.0.6

      You Asked
Hi Tom,
   Hello. We are planning for replication, but the master tables have lot of
before and insert triggers, can I create snapshots on such situations. Or better
put it, what are the steps we should follow for creating a replication
environment for a running application, specifically for creating snapshots. Or
can the application triggers co-exist with snapshot triggers.

Thanks

      and we said...
They can co-exist.  We introduced multiple same type triggers many years ago for
just such a purpose.  We'll be using an AFTER-for each row trigger, but you may
use your own as well.
Review & Followup

      Rating:
      3
  July 15, 2001
Reviewer:
      Pichaimani  from San Jose, CA USA
Thanks for your immediate response.

July 15, 2001 Sandy -- Thanks for the question regarding
      "Backup and Recovery", version 8.1.5

      You Asked
Hi Tom,

I am mid-level DBA and trying to more information about recovery. About recovery
I have some questions here:

1. Some time ago there was some problem in our database and we were not able to
open the database and after that one of our Sr. Oracle DBA
apply all the archve logs file and database is just running fine.
My question is
.how to find, when to apply archive log files,
.how to find out what all archive logs we need to apply and
.how to apply arrchive logs.

2. Is there any document (Except Oracle documentation) available where I can get
so many recovery scenarios and their solution. I have gone through with Oracle
documentation and still looking for so many
recovery scenarios.

3. I was looking a document and find some thing says, database runninng in to
recovery mode. What do you mean by "recovery mode".

Thanks for your help.

Sandy

      and we said...
1) the database would tell you when you issue the startup command.  It would say
"file x needs recovery"

The database will tell you what archives it needs when you tell the database to
recover that file.

The database will apply the redo logs itself.  You only need to make them
available.

2) well, I've found the backup and recovery guide to have hit on most of them
myself.

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/toc.htm
But, yes, there is a backup and recovery guide published by Oracle Press.

http://www.amazon.com/exec/obidos/ASIN/0072127171/
3) you probably mean a standby database.  See

http://technet.oracle.com/doc/oracle8i_816/server.816/a76995/toc.htm

Review &
      Followup

      Rating:
      2
  July 15, 2001
Reviewer:
      A reader

July 15, 2001 Peter -- Thanks for the question regarding
      "Rollback Segment", version 8.1.6

      You Asked
Hi Tom:

I have several questions regarding to "Rollback Segment" in Oracle:

1. How to assign specific rollback segments to transactions or session?

2. Do we need to create extra rollback segment for new tablespace or Oracle
internally creates for us?

Thanks!
Peter Cheng

      and we said...
1) the set transaction statement does that.

ops$tkyte@ORA8I.WORLD> set transaction use rollback segment rbs_30;

Transaction set.

It is very rare you would need to do this and if you feel the need to do this
on a recurring basis, it indicates you have undersized the rollback segments for
your system.  I'm not a big fan of this statement.

2) rollback segments are assigned to transactions, not tablespaces.  A
transaction makes use of rollback and that transaction may modify data in any
tablespace.

followup to comment one

No.  Your OLAP (online analytical processing) queries will need to read the
rollback segments populated by the OLTP transactions.  They will not generate
rollback generally (they are read only), but they will need to read the rollback
your OLTP generates if both are happening at the same time.

Review &
      Followup

      Rating:
      3
  July 15, 2001
Reviewer:  Peter
      Cheng  from Gaithersburg, USA
Do we need to create two sets of Rollback Segment for OLTP and OLAP application?
That is the reason for my question.

July 15, 2001 il hwan -- Thanks for the question regarding
      "shrink rollback ......", version 8.0.6.1

      You Asked
In case that a transaction(like of long update batch) is using a rollback and we
shrink the rollback segment,
will it rollback current transaction or
shrink wait until the transaction is done(transaction run normally)?
Another question is that long update batch has been running,
used ublock column in v$transaction was about 400,000 and
it stopped on the way cause shortage of rollback space.
it took about 4 hours until used ublock column gets to 0.
is there any way to do fast rollback ?

      and we said...
shrink won't abort a currently running transaction, it'll only shrink if it can
shrink without affecting anything.

In 8.0 you can "speed" this up by setting cleanup_rollback_entries higher:

        The number of undo records processed at one time when rolling back a
        transaction. Prevents long transactions from freezing out shorter
        transactions that also need to be rolled back.

In 8i, this is obsoleted as pmon will hand over the rolling back of killed
sessions to smon which can use a fast start parallel rollback if setup.  That
means that locks on the modified rows are released effectively immediately --
smon will rollback individual blocks on demand.  the rollback appears to be
instantaneous (but will still be happening in the background)

Review &
      Followup

      Rating:
      4
rollbacks  July 17, 2001
Reviewer:  roel
      hendriks  from netherlands
simple and clear answer


Subject | Article | Last Updated (East coast time)
Hot or Cold Backups vs. $$$ | article only | Jul 16, 2001 08:08 am
Standby database | article only | Jul 16, 2001 08:15 am
Conceptual | article only | Jul 16, 2001 02:03 pm
Child-Parent Recurcive SQL | article only | Jul 17, 2001 08:23 am
lock -- catching a named exception from an ORA-xxxxx error | article only | Jul 17, 2001 08:47 am
Parsing the sort option as an argument of a procedure | article only | Jul 17, 2001 03:37 pm
rollback segment | article only | Jul 17, 2001 09:23 pm
start partition , stop partition | article only | Jul 18, 2001 07:52 am
host command. | article only | Jul 18, 2001 08:38 am
Lob purge | article only | Jul 18, 2001 08:50 am
Deferred Rollback and More.. | article only | Jul 18, 2001 09:05 am
different between db_writer_processes and dbwr_io_slaves | article only | Jul 18, 2001 09:16 am
Infroming the client of progress in a stored procedure | article only | Jul 18, 2001 04:19 pm
Processes P00x in my database ... | article only | Jul 18, 2001 04:21 pm
accessing procedure from diffrent user | article only | Jul 18, 2001 04:52 pm
Performance: PL/SQL stored procedures or embedded sql | article only | Jul 18, 2001 07:54 pm
store procedure | article only | Jul 19, 2001 09:57 am
Error using sqlldr73 with DECODE statement | article only | Jul 19, 2001 10:25 am
Calling Java classes stored on file system from PL/SQL stored procedure | article only | Jul 19, 2001 12:42 pm
Explicit <-> Implicit Cursors | article only | Jul 19, 2001 02:08 pm
all about bulk binds | article only | Jul 19, 2001 07:01 pm
Read only user | article only | Jul 19, 2001 09:37 pm
Several questions | article only | Jul 20, 2001 10:08 am
bulk binds follow up | article only | Jul 20, 2001 10:53 am
about bind variable | article only | Jul 20, 2001 11:06 am
concatenated indexes | article only | Jul 21, 2001 09:22 am
Indexes | article only | Jul 21, 2001 09:29 am
date conversion into seconds | article only | Jul 21, 2001 09:30 am
runaway process | article only | Jul 21, 2001 04:42 pm
Usage of 'From Select' Clause. | article only | Jul 22, 2001 05:43 pm
row(s) 1 - 30 of 30
July 16, 2001 Doug -- Thanks for the question regarding "Hot or Cold Backups vs. $$$", version 8.1.7
You Asked
Tom - I am trying to figure out a cheap.. *nearly* 24x7 solution which has me a
little confounded.  $$$ is an issue.  I am aware of the usual redundant options,
parallel server, fail-over, stand-by etc.,   However, since $$$ is *such* an
issue for reasons I won't get into, I have the following choice:

Hot backups only.. no redundancy in hardware etc.,
Investment in Shark Drives which will allow for a cold backup with only 15 min.
of down time per day..

The question is the following..  Of all the seasoned Oracle DBA's I know, none
really cares for hot backups although perhaps I am too green to know why.  They
say they are complicated, tricky, sometimes unreliable etc.,   Q1 is, can you
confirm or deny this?  Is it a matter of just really knowing what you're doing?
If so, how can I ensure I really know what I'm doing.

If an investment in amazing disk drives would allow for a cold backup instead of
a hot one, which would you pick and why?  The more expensive option which is
preferred by many of the crew is dual-ported disk drives across two boxes
(parallel server).. however, I'm afraid this is too much $$$ once again.

Thanks,
Doug

PS Love your book..
and we said...
Funny, out of all of the seasoned DBAs I know -- hot backups are the ONLY WAY TO
GO.

If they feel otherwise, I would quite simply LOVE to hear why.

Using RMAN, there is NO difference between hot and cold.

Using tar/cp/whatever, you must put a tablespace into backup mode but other then
that, THERE IS NO DIFFERENCE between hot and cold (mechanically speaking).

Now, a cold backup does have the somewhat bad side effect of wiping out your
shared pool, your buffer cache and preventing your users from logging in to do
work.  Your database is like a car, it runs better when it is warmed up.  If you
want to cold start it - be prepared for rough running when you restart as we
have to rebuild that shared pool, that buffer cache and so on.

I would say you do not know seasoned DBAs, you know people who haven't had the
real experience, who don't know any better, who are able to get away with
shutting down the database by keeping those "who don't know" in the dark.

The only kind of backup we do on our production systems here is hot, I'd say we
have more then one or two seasoned Oracle DBA's.

Hot is no harder (or easier) then cold.  You need to retain the same exact
amount of archived redo log and so on (i truly hope that they run the production
databases in ARCHIVELOG mode, else I can assure you that you will lose data
someday).

Hot is not unreliable, it is something we sort of pride ourselves on -- being
able to recover from failure (it is after all, one of the major reasons you are
using a database).

I can most wholeheartedly DENY their unfounded misconceptions and if one of them
would care to discuss it, I'd be more then willing to open a special thread on
it.

It is, like everything else, a matter of knowing what you are doing.  To ensure
you know what you are doing, get a test system and practice.  Put the database
into archive log mode, do your hot backups to another disk, bang on the system
and then do things like:

o disconnect the drives with the system tablespace and recover.
o wipe out all of your control files, and recover
o wipe out an online redo log group while its active and recover as much as you
can

and so on.  practice, testing, simulation.  thats the only way.

I would never pick cold over hot given the chance.  No benefit, only downsides.
Review & Followup
Rating: 5
Excellent July 19, 2001
Reviewer: Sreekanth from NJ
I fully agree with you, at the same time I feel using RMAN has more benifits
than Hot mode.

Rating: 4
Hot or Cold Backups vs. $$$", version 8.1.7 August 06, 2001
Reviewer: Rohit from Newyork USA
I am 200% agree with TOM. Thank you very much TOM for the explanation

July 16, 2001 -- Thanks for the question regarding "Standby database", version 8.1.7
You Asked
Thanks for replying my previous question.

      I   need setup the Primary and Standby database. I need to keep the last
one hour transaction only in my Primary Database server. I need keep  all the
data to Standby database server.  Is it possibe to update my standby database
every 30 minutes or 1 hr. If any problem in my Primary database, I need to up
the Standby database. I am using Sun solaris 2.8. Pls advise me. Thanks in
advance.
and we said...
Yes you can do this however you'll have to script it.  Normally, in managed
standby mode, we apply the redo logs as they switch - every log switch would
automatically send the log files to the standby to be applied.

If you only want to do this every half hour or hour, instead of whenever a log
switch occurrs, you'll have to script the moving of the logs (not hard, just not
done for you).

If the concern is that you want to FORCE a log switch AT LEAST every half hour
(and if they are switching faster thats OK), you can use dbms_job to schedule a
plsql block that looks like:

begin
  execute immediate 'alter system switch logfile';
end;

every 1/2 hour -- then you can use managed mode again.
Review & Followup
Rating: 5
Standby database July 16, 2001
Reviewer: Shanmugam from Singapore
The answer is most useful to me.

Rating: 3
July 16, 2001
Reviewer: Gururaj Kulkarni from Norcross GA USA
Hi Tom,

Could you explain in detail, about the sending (IS it copying ?) and applying
the redo logfiles ?

Thanks in advance
-Gururaj

July 16, 2001 San -- Thanks for the question regarding "Conceptual", version 8.1.5
You Asked
Tom:

As far as I know there are two things:
1. archived redo logs AND
2. Redo log

but at so many places I have seen something called "online redo logs",

What is that?

Thanks
San
and we said...
#2 is online redo logs.

there are two types of logs

- online, those that are online and being used by the database
- archive, those that were filled and copied elsewhere.  immediately before
becoming an archive redo log file, it was an online redo log file
Review & Followup
Rating: 4
July 17, 2001
Reviewer: A reader

Rating: 5
Great! August 02, 2002
Reviewer: Fiza from Canada
Very simple and great deffination

July 17, 2001 -- Thanks for the question regarding "Child-Parent Recurcive SQL", version 8.1.6
You Asked
Hi...,

I have a table 'cp' and the columns are
(child varchar2(10),
parent varchar2(10),
is_bottom varchar2(1));

This table keeps the child-parent records & is_bottom flag tell u that whether
the node  is the bottom of the branch 'Y' & 'N'

eg : If the tree structure looked like this
101
--102 (This is the bottom)
--103
----113 (this is the bottom)
----114
------- 124 (Bottom)
------- 125 (Bottom)
--104
-----141 (bottom)
--105 (bottom)

The sql should return the node from where u are starting & the bottom most
leaves of the branch

The result should look like this when u start wiht 101

101,102
101,113
101,125
101,141
101,105
103,113
103,124
103,125
114,124
114,125
104,141

Regards,

Praveen
and we said...
You'll have to do it procedurally. SQL alone cannot do that one.  You can do
something like this (there might be more efficient ways to build the result set
-- that is just the first thing i thought of)

tkyte@TKYTE816> create table cp ( child int, parent int, bottom char(1) );
Table created.

tkyte@TKYTE816> insert into cp values ( 101, null, 'N' );
tkyte@TKYTE816> insert into cp values ( 102, 101, 'Y' );
tkyte@TKYTE816> insert into cp values ( 103, 101, 'N' );
tkyte@TKYTE816> insert into cp values ( 113, 103, 'Y' );
tkyte@TKYTE816> insert into cp values ( 114, 103, 'N' );
tkyte@TKYTE816> insert into cp values ( 124, 114, 'Y' );
tkyte@TKYTE816> insert into cp values ( 125, 114, 'Y' );
tkyte@TKYTE816> insert into cp values ( 104, 101, 'N' );
tkyte@TKYTE816> insert into cp values ( 141, 104, 'Y' );
tkyte@TKYTE816> insert into cp values ( 105, 101, 'Y' );

tkyte@TKYTE816> create type myScalarType
  2  as object ( parent int, child int )
  3  /
Type created.

tkyte@TKYTE816> create type myArrayType
  2  as table of myScalarType
  3  /
Type created.

tkyte@TKYTE816> create or replace function get_data( p_start in int ) return
myArrayType
  2  as
  3     l_data myArrayType := myArrayType();
  4  begin
  5      for x in ( select *
  6                   from cp
  7                  where bottom = 'Y'
  8                  start with parent = p_start
  9                connect by prior child = parent )
 10      loop
 11          for y in ( select *
 12                       from cp
 13                      where parent is NOT NULL
 14                      start with child = x.child
 15                    connect by prior parent = child )
 16          loop
 17              l_data.extend;
 18              l_data( l_data.count ) := myScalarType( y.parent, x.child );
 19          end loop;
 20      end loop;
 21
 22      return l_data;
 23  end;
 24  /

Function created.

tkyte@TKYTE816> variable x number
tkyte@TKYTE816> exec :x := 101

PL/SQL procedure successfully completed.

tkyte@TKYTE816> select *
  2    from TABLE ( cast ( get_data( :x ) as myArrayType ) )
  3   order by parent
  4  /

    PARENT      CHILD
---------- ----------
       101        102
       101        113
       101        124
       101        105
       101        141
       101        125
       103        113
       103        125
       103        124
       104        141
       114        124
       114        125

update....
Demidenko Sergey from Russia noted that "Well, you can do this in SQL".  He came
up with this query:

SQL> variable x number
SQL> exec :x := 101

PL/SQL procedure successfully completed.

SQL> SELECT
  2    a.child, b.child
  3  FROM
  4    (SELECT
  5       child, rnm,
  6       lag(rnm) over (order by rnm desc) next_rnm
  7     FROM
  8       (SELECT
  9          parent, child, bottom, level lvl, rownum rnm
 10        FROM cp
 11        START WITH (bottom='N')
 12        CONNECT BY prior child=parent
 13       )
 14     WHERE lvl=1
 15    ) a,
 16    (SELECT
 17       child, bottom, rnm
 18     FROM
 19       (SELECT
 20          child, bottom, rownum rnm
 21        FROM cp
 22        START WITH (bottom='N')
 23        CONNECT BY prior child=parent
 24       )
 25     WHERE child IN
 26       (SELECT
 27          child
 28        FROM cp
 29        WHERE bottom='Y'
 30        START WITH parent=:x
 31        CONNECT BY prior child=parent
 32       )
 33    ) b
 34  WHERE (a.rnm<=b.rnm)
 35    AND ((a.next_rnm>b.rnm) OR (a.next_rnm IS NULL))
 36  ORDER BY a.child
 37  /

     CHILD      CHILD
---------- ----------
       101        102
       101        105
       101        113
       101        141
       101        124
       101        125
       103        113
       103        124
       103        125
       104        141
       114        124
       114        125

12 rows selected.

And also pointed out that perhaps the first cut at the procedural code wasn't
100% correct:

....But there is one more detail, that I want to
describe you... Let's try begin our calculation with
node number 103 (your or my upper variant does not
metter):

SQL> exec :x:=103

PL/SQL procedure successfully completed

SQL> select *
  2  from TABLE ( cast ( get_data( :x ) as myArrayType ) )
  3  order by parent;

    PARENT      CHILD
---------- ----------
       101        113
       101        124
       101        125
       103        113
       103        124
       103        125
       114        124
       114        125

8 rows selected.

 I think that result rows should not contain rows
with parent 101 in this case (as far as I understand
the soul of this question only children of starting
nodes required)...
 I decided suggest you one more variant of SQL that
operate as I understand the soul of the problem:

SQL> exec :x:=103;

PL/SQL procedure successfully completed.

SQL> SELECT
  2    a.child, b.child
  3  FROM
  4    (SELECT
  5       child,rnm,next_rnm
  6     FROM
  7       (SELECT
  8          child, rnm,
  9          lag(rnm) over (order by rnm desc) next_rnm
 10        FROM
 11          (SELECT
 12             parent, child, bottom, level lvl, rownum rnm
 13           FROM cp
 14           START WITH (bottom='N')
 15           CONNECT BY prior child=parent
 16          )
 17        WHERE (lvl=1)
 18       )
 19     WHERE child IN
 20       (SELECT
 21          parent
 22        FROM cp
 23        WHERE (parent IS NOT NULL)
 24        START WITH parent=:x
 25        CONNECT BY prior child=parent
 26       )
 27    ) a,
 28    (SELECT
 29       child, rnm
 30     FROM
 31       (SELECT
 32          child, rownum rnm
 33        FROM cp
 34        START WITH (bottom='N')
 35        CONNECT BY prior child=parent
 36       )
 37     WHERE child
 38        IN (SELECT
 39              child
 40            FROM cp
 41            WHERE bottom='Y'
 42            START WITH parent=:x
 43            CONNECT BY prior child=parent)
 44    ) b
 45  WHERE (a.rnm<=b.rnm)
 46    AND ((a.next_rnm>b.rnm) OR (a.next_rnm IS NULL))
 47  ORDER BY a.child
 48  /

     CHILD      CHILD
---------- ----------
       103        113
       103        125
       103        124
       114        124
       114        125

I took the procedural approach because after looking at this for a couple of
minutes -- I didn't see an intuitive way to do this in SQL.  Demidenko has shown
that SQL can do many things -- but (as he admits) it took more then a couple of
minutes to come up with this particular query.

I would still opt for the procedural code (adjusting it if need be to accomidate
the second case) in this particular example since it is so much more
understandable and maintainable.  The queries show the power of SQL but are
quite complex to say the least ;)

Thanks
July 17, 2001 Suresh -- Thanks for the question regarding "lock -- catching a named exception from an ORA-xxxxx error", version 8.1.7
You Asked
Hi Tom,
   In a database procedure, I am trying to lock specific records in a table by
the statement
    select * from t where t1 = 1 for update nowait;

  If the above statement fails , it is going to go to the exception section. Is
there a specific exception code that I can use to handle and find out if the
table has been locked , other than using

EXCEPTION
    WHEN OTHERS..

Thanks,
Suresh
and we said...
Use the PRAGMA EXCEPTION_INIT.  Using this you can map any ORA-xxxxx code to a
named exception.  In your case this would be:

ops$tkyte@ORA815> declare
  2       resource_busy  exception;
  3       pragma exception_init( resource_busy, -54 );
  4
  5       l_empno emp.empno%type;
  6  begin
  7
  8       select empno into l_empno from emp where rownum = 1 for update nowait;
  9
 10  exception
 11       when resource_busy then
 12            dbms_output.put_line( 'You lose' );
 13  end;
 14  /
You lose

PL/SQL procedure successfully completed.

That is the output when I run this block in another session after already having
run it in some other session.
Review & Followup
Rating: 4
Using Pragma Exception Init July 18, 2001
Reviewer: Subrata Saha from Bangalore, India
A good use of Pragma exception Init.

July 17, 2001 Peter -- Thanks for the question regarding "Parsing the sort option as an argument of a procedure", version 8
You Asked
Hello
I have a procedure that selects fields from a table and I
want to have some flexibilty for  sorting the result.
I am having difficulty parsing a variable to a procedure
as this variable seems to be ignored.
The following example will take the argument but the
select clause will ignore it. Can you help please?

create or replace procedure show_data (mySort in Number)
IS
Begin
cursor c1 is
select field1, field2, field3 from myTable
sort by mySort;
end;
and we said...
well, it is not IGNORING it, it is doing exactly what you asked it to.

If the value of mySort has the value 'field1' that is exacly like:

 select field1, field2, field3 from mytable ORDER BY 'field1';

it is ordering by the CONSTANT 'field1'.  You cannot use bind variables where an
identifier is needed.  The reason is that:

  select field1, field2, field3 from mytable ORDER BY 'field1';

and

  select field1, field2, field3 from mytable ORDER BY 'field2';

are two totally different queries and would need two totally different query
plans (one make make use of an index, the other not for example).  In any case,
they are two different queries.

You didn't give the VERSION TO 3 digits so I'll have to guess.

In Oracle8i, you will code:

is
   type rc is ref cursor;

   l_cursor rc;
begin
   open l_cursor for
      'select field1, field2, field3 from mytable ORDER BY' || mySort;

   loop
      fetch l_cursor into ...;

that is, dynamically open the ref cursor.  In 8.0 you cannot do this,  if you
have three columns to choose from you can code:

is
   type rc is ref cursor;

   l_cursor rc;
begin
   if ( mySort = 'field1' ) then
      open l_cursor for
      select field1, field2, field3 from mytable ORDER BY field1;
   elsif ( mySort = 'field2' ) then
      open l_cursor for
      select field1, field2, field3 from mytable ORDER BY field2;
   elsif ( mySort = 'field3' ) then
      open l_cursor for
      select field1, field2, field3 from mytable ORDER BY field3;
   end if;

   loop
      fetch l_cursor into ...;

An alternative to the above is to use decode:

create or replace procedure show_data (mySort in Number)
IS
Begin
cursor c1 is
select field1, field2, field3 from myTable
order by decode( mySort, 'field1', field1, 'field2', field2, 'field3', field3);
end;

you just need to make sure that field1, 2, and 3 are returned as the same type -
if field1 is a varchar2, field2 a number and field3 a date you could:

decode( mySort, 'field1', field1, 'field2', to_char(field2,'00000000000009'),
         'field3', to_char(field3, 'yyyymmddhh24miss' ) )

to make sure everything sorts OK.
Review & Followup
Rating: 4
Parsing the sort option as an argument of a procedure July 18, 2001
Reviewer: A reader
Thanks TOM. I am improving my knowledge daily.

Cheers
M.Balaji

Rating: 4
That explains July 18, 2001
Reviewer: A Reader from USA
I had used the DECODE method recently in my code but it never worked properly
even though there were no compilation errors.

I think now I can make it work.

July 17, 2001 sushmita -- Thanks for the question regarding "rollback segment", version 8.1.5
You Asked
Hi,

    I would like to know how a particular rollback segment can be assigned to a
particular user permanently, so that whenever the user logon , it is using only
that particular rollback segment instead of assing it at session level each time
it logon.

thanks and regards,
sushmita
and we said...
Nope,

transactions are assigned to a rollback segment, not users.

After each and every commit/rollback -- the very next transaction you do will
use (probably) a different RBS.

If you have such a need, I believe you are doing something wrong.  All RBS's
should be the same size with the same number of extents.  In 9i, using an UNDO
tablespace, this is done automagically, you don't even have rollback segments.
Until then, equi-sized RBS is the way to go.  Every rollback segment should be
as good as any other rollback segment.
Review & Followup
Rating: 4
Very useful July 18, 2001
Reviewer: Girish Hulikantimath from Karnataka,India
Ive tested this its very easy way comapred to my way
Thnx giriyaa@yahoo.com

Rating: 3
rollback segment July 18, 2001
Reviewer: sushmita from california
THanks for the prompt reply. it did help to clear my doubt.

July 18, 2001 sj -- Thanks for the question regarding "start partition , stop partition", version 8.1.7
You Asked
UPDATE
*******

SQL> CREATE TABLE t ( cc        varchar2(20))
  2  PARTITION BY RANGE (cc)
  3   ( PARTITION p1 VALUES LESS THAN ( 'UK' ) ,
  4    PARTITION p2 VALUES LESS THAN ( 'US')
  5     );

Table created.

  1* insert into t VALUES ('UNITED')
SQL> /

1 row created.

SQL> COMMIT;

Commit complete.

SQL>  SELECT * FROM T PARTITION(P1);

no rows selected

SQL> C/1/2
  1*  SELECT * FROM T PARTITION(P2)
SQL> /

CC
--------------------
UNITED

SQL> EXPLAIN PLAN
  2  SET STATEMENT_ID='SEL'
  3  FOR
  4  SELECT * FROM T WHERE CC='UNITED'
  5  /

Explained.

SQL> @EXPLAIN
Enter statement_id: SEL

  ID PARENT OPERATION                           OBJECT_NAME
---- ------ ----------------------------------- ------------------------------
   0        SELECT STATEMENT
   1      0  TABLE ACCESS FULL                  T

SQL>
SQL> SELECT PARTITION_START, PARTITION_START FROM PLAN_TABLE
  2  WHERE STATEMENT_ID='SEL';

PARTITION_START
--------------------------------------------------------------------------------
PARTITION_START
--------------------------------------------------------------------------------

2
2

1.Tom, kindly observe that the explain plan shows  a table access full, but when
you do a SELECT PARTITION_START, PARTITION_START FROM PLAN_TABLE   2  WHERE
STATEMENT_ID='SEL';
it clearly tells you that only one partition is scanned(IE.E. PARTITION 2)..
according to this this conclusively proves that there was no full table acces,
but only a full partition access..

can you give me a explain plan query which also gives the PARTITION_START,
PARTITION_START i.e. the partition details..

2.How can I avoid a full partition access.. is the only way to do this is
creating alocal index?

**********
UPDATE END

ORIGINAL QUESTION
*****************

Tom

When I run a query against a partitioned table, and do a explain plan..

if the output show me  as full table access and the values for start partition
and stop partition is the same , say for example 3.

1.Does it mean that only one partition was scanned for the whole query(in effect
meaning that partition elimination has occurred).

2.Does in also mean that there is nothing like 'full partition scan' described
in plan_table.. so even if a single full partition scan is occurring then it
will be shown as full table access..

Iam I right?

3.How should I arrive at the total size of a particular table?

Thank you
and we said...
1) yes,
ops$tkyte@ORA815> CREATE TABLE t
  2  ( x int,
  3    data      varchar2(25)
  4  )
  5  PARTITION BY RANGE (x)
  6  (
  7  PARTITION part_1 VALUES LESS THAN(2) tablespace users,
  8  PARTITION part_2 VALUES LESS THAN(3) tablespace system
  9  )
 10  /

Table created.

ops$tkyte@ORA815>
ops$tkyte@ORA815> delete from plan_table;

3 rows deleted.

ops$tkyte@ORA815>
ops$tkyte@ORA815> EXPLAIN PLAN
  2  SET STATEMENT_ID = 'xxx'
  3  FOR
  4  select * from t where x = 1;

Explained.

ops$tkyte@ORA815>
ops$tkyte@ORA815> column operation format a30
ops$tkyte@ORA815> column options format a30
ops$tkyte@ORA815> column partition_start format a4
ops$tkyte@ORA815> column partition_stop format a4
ops$tkyte@ORA815> SELECT LPAD(' ', 2*(LEVEL-1))||operation operation,
  2                  options || '(' || object_name || ')' options, position,
  3             PARTITION_START, PARTITION_STOP
  4  FROM plan_table
  5  START WITH id = 0 AND statement_id = 'xxx'
  6  CONNECT BY PRIOR id = parent_id AND statement_id = 'xxx'
  7  /

OPERATION                   OPTIONS                          POSITION PART PART
--------------------------- ------------------------------ ---------- ---- ----
SELECT STATEMENT            ()                                      1
  TABLE ACCESS              FULL(T)                                 1 1    1

2) there will be a partition range scan directive if it cannot determine the
partition:

ops$tkyte@ORA815> EXPLAIN PLAN
  2  SET STATEMENT_ID = 'xxx'
  3  FOR
  4  select * from t where x =:1 ;

Explained.

ops$tkyte@ORA815>
ops$tkyte@ORA815> column operation format a30
ops$tkyte@ORA815> column options format a30
ops$tkyte@ORA815> column partition_start format a4
ops$tkyte@ORA815> column partition_stop format a4
ops$tkyte@ORA815> SELECT LPAD(' ', 2*(LEVEL-1))||operation operation,
  2                  options || '(' || object_name || ')' options, position,
  3             PARTITION_START, PARTITION_STOP
  4  FROM plan_table
  5  START WITH id = 0 AND statement_id = 'xxx'
  6  CONNECT BY PRIOR id = parent_id AND statement_id = 'xxx'
  7  /

OPERATION                   OPTIONS                          POSITION PART PART
--------------------------- ------------------------------ ---------- ---- ----
SELECT STATEMENT            ()                                      1
  PARTITION RANGE           SINGLE()                                1 KEY  KEY
    TABLE ACCESS            FULL(T)                                 1 KEY  KEY

until run time.

3) search for show_space on my site.
July 18, 2001 Severino -- Thanks for the question regarding "host command.", version 4.5.9.7
You Asked
Hi Tom,

Could  you help me on this,

I'm calling a program the HOST command from my form.

The program is that when I run my program on NT, once the host command is
executed, everything is on suspend until it is finished, which is the way it
should be and the way I want it.  BUT in W2K I have problem that occurs at this
point, when the HOST command runs, it continues without finishing the process of
the program called, it should be waiting until I'm done with it, like in NT.

Could help me on this please,

Thanks,

Severino,
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:689424854669
you can use that method to run the program and tell the START command to WAIT,
eg:

host( 'cmd /c "start /WAIT prog.exe"' );
July 18, 2001 Anil -- Thanks for the question regarding "Lob purge", version 8.1.5
You Asked
Hi tom,
  1)i have  a table which has lots of LOB along with other data(diff. data
type),i just wanted to remove all the lob but keep other data in that
record,when i tried updating that lob to NULL ,it worked but
i didn't see any space improvement(meaning it hasn't relesed any space),after
that i tried using dbms_lob.erase but this also in same way didn't released any
space.My concern is space here...i MUST get
space here.

2)My another question is i have a tablespace (dictionary managed)
in which we only store lobs.(we redirect lobs to this tablespace).
couple of days before i noticed dba_free_space says 700mb space is
free for that tablespace.but next day morning i got error
"unable to extend(next was 100mb)".i checked again ,it was showing
700mb free.So i feel it is fragmented.(at this point of time i don't
want to transfer table to locally managed tablespace.)
Can you tell me what is easiest... other way to solve this problem.
because i am not able to use my 700mb.

3)Regarding my rollback segment i still get lot of wraps(100-150 in 48 hours)
and couple of time waits(wait for one or two segment).Can you tell me what is
this wait all about and is it harmful to have ??..But i have no extend and
shrink,sometime(very rarely)when we do batch job i get "snapshot too old error"
also.i have ten rollback segment initial=next=1m minextent =20 maxextent=50 in a
tablespace of 300mb.Can you suggest me something for this.

thanx

Regards
   AK
and we said...
1) blobs are stored out of line once they exceed 4,000 bytes (you can also
specify that they are always stored out of line as well).

In all likelhood, you freed space in your LOB segment but did nothing to your
table segment.

If the blobs were all inline, each taking 4000 or less bytes, then you did free
space in your table.  The table will not shrink in size (tables NEVER shrink)
but it will have more blocks on its free list for subsequent inserts.  Search
for show_space on my site to see how to see how many blocks are on your freelist
with free space on them.

2) search my site for free.sql.  It'll show you the free space by tablespace as
well as the LARGEST next extent possible.  You will have to alter your lob
segments NEXT extent attribute to be less then the largest free chunk.

3) if you are getting an ORA-1555, you need to increase the permanently
allocated size of your rollback segments.  This will also reduce your wraps.
Wraps by themselves are perfectly normal, you cannot avoid them.  If you are
getting a 1555 however, that means you are in fact wrapping too fast -- make the
RBS's *permanently* bigger, allocate more extents to them.  Set the minextent to
25 and see if the 1555 doesn't stop, if it doesn't, make them bigger still.

The probability of a 1555 is directly proportional to the size of your SMALLEST
rbs.
July 18, 2001 M. -- Thanks for the question regarding "Deferred Rollback and More..", version 8.1.6
You Asked
Hi Tom,

I really apprecite your service to this Oracle Community with the most
authenticated answers .

1) What are the major differences in Oracle 8.1.5 and 8.1.7

2) I read about the Deferred Rollback Segment which is Oracle managed. Why is it
there? If a Tablespace can not be taken offline if it has any active transaction
??? What becomes the role of the Deferred Rollback Segment in this story.

3) Could you please expalain to me PCTUSED and PCTFREE in Table Storage with
examples. I know the basic definitions but could not understand the behaviour of
these two. What about the First time extent is assigned to a segment ... What is
the Role of PCTUSED here.

4) Is there any way that you can commit or Rollback someone's transactions
(Work) without getting in his or her session as DBA.

5) Would you recommend any Good book to learn Unix that is used purely for
Oracle Developers or DBA's.

Thanks a Lot.
and we said...
1) See:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76962/toc.htm
http://technet.oracle.com/docs/products/oracle8i/doc_library/817_doc/addendum.817/a85455/toc.htm
2) You are in the middle of a transaction, it has generated rollback.  it has
affected tablespace t1.

the disk that t1 is on fails.

the datafile is offline, the tablespace goes offline.  We have some rollback
that we need.   We move it out of the regular rollback segments so as to not
botch them up (we cannot advance into a rbs extent that has data we need in it
and hence this rbs we were using would grow and grow and grow if we didn't get
this data out of there.  We put that into a deferred rollback segment so that
when you restore T1 and recover it, we can roll it back.

3) PCTUSED has nothing to do with the adding of an extent.
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:681671986842
also, just search for pctfree pctused on my site, there are a couple of articles
on this topic

4) not commit.  you can roll it back by KILLING them.

5) I'm not personally aware of any myself.

July 18, 2001 -- Thanks for the question regarding "different
      between db_writer_processes and dbwr_io_slaves", version 8.1.6

      You Asked
Tom:

what is the different between db_writer_processes and dbwr_io_slaves.
what is the relationship?

      and we said...
Here is a support note, available on metalink, that describes this:

Article-ID:         <Note:97291.1>
Circulation:        PUBLISHED (EXTERNAL)
Folder:             server.Performance.Database
Topic:              Tuning Buffer Cache
Title:              DB_WRITER_PROCESSES or DBWR_IO_SLAVES?
Document-Type:      FAQ
Impact:             LOW
Skill-Level:        NOVICE
Server-Version:     07.00 to 08.01
Updated-Date:       26-JUN-2001 13:40:10
References:
Attachments:        NONE
Content-Type:       TEXT/PLAIN
Keywords:           PARAMETERINFO;
Products:           5/RDBMS (7.0.X to 8.1.X);
Platforms:          GENERIC;

FREQUENTLY ASKED QUESTIONS
--------------------------
You have just upgraded to 8.0 or 8.1 and have found that there are 2 new
parameters regarding DBWR.  You are wondering what the differences are and
which one you should use.

DBWR_IO_SLAVES
==============

In Oracle7, the multiple DBWR processes were simple slave processes; i.e.,
unable to perform async I/O calls.  In Oracle80, true asynchronous I/O is
provided to the slave processes, if available.  This feature is implemented
via the init.ora parameter dbwr_io_slaves.  With dbwr_io_slaves, there is still
a master DBWR process and its slave processes.  This feature is very similar to
the db_writers in Oracle7, except the IO slaves are now capable of asynchronous
I/O on systems that provide native async I/O, thus allowing for much better
throughput as slaves are not blocked after the I/O call.
I/O slaves for DBWR are allocated immediately following database open when the
first I/O request is made.

DB_WRITER_PROCESSES
===================

Multiple database writers is implemented via the init.ora parameter
db_writer_processes.  This feature was enabled in Oracle8.0.4, and allows true
database writers; i.e., no master-slave relationship.  With Oracle8
db_writer_processes, each writer process is assigned to a LRU latch set.  Thus,
it is recommended to set db_writer_processes equal to the number of LRU latches
(db_block_lru_latches) and not exceed the number of CPUs on the system.  For
example, if db_writer_processes was set to four  and db_lru_latches=4, then
each writer process will manage its corresponding set.

Things to know and watch out for....
====================================

-- 1.  Multiple DBWRs and DBWR IO slaves cannot coexist.  If both are enabled,
then the following error message is produced: ksdwra("Cannot start multiple
dbwrs when using I/O slaves.\n");  Moreover, if both parameters are enabled,
dbwr_io_slaves will take precedence.

-- 2.  The number of DBWRs cannot exceed the number of db_block_lru_latches.
If it does, then the number of DBWRs will be minimized to equal the number
of db_block_lru_latches and the following message is produced in the
alert.log during startup:
("Cannot start more dbwrs than db_block_lru_latches.\n");
However, the number of lru latches can exceed the number of DBWRs.

-- 3. dbwr_io_slaves are not restricted to the db_block_lru_latches;
i.e., dbwr_io_slaves >= db_block_lru_latches.

Should you use DB_WRITER_PROCESSES or DBWR_IO_SLAVES?
=====================================================

Although both implementations of DBWR processes may be beneficial, the general
rule, on which option to use, depends on the following :
1) the amount write activity;
2) the number of CPUs (the number of CPUs is also indirectly related to the
    number LRU latch sets);
3) the size of the buffer cache;
4) the availability of asynchronous  I/O (from the OS).

There is NOT a definite answer to this question but here are some considerations
to have when making your choice.  Please note that it is recommended to try
BOTH (not simultaneously) against your system to determine which best fits the
environment.

-- If the buffer cache is very large (100,000 buffers and up) and the
 application is write intensive, then db_writer_processes may be beneficial.
 Note, the number of writer processes should not exceed the number of CPUs.

-- If the application is not very write intensive (or even a DSS system) and
 async I/O is available, then consider a single DBWR writer process;
 If async I/O is not available then use dbwr_io_slaves.

-- If the system is a uniprocessor(1 CPU) then implement may want to use
 dbwr_io_slaves.

Implementing db_io_slaves or db_writer_processes comes with some overhead cost.
Multiple writer processes and IO slaves are advanced features, meant for high
IO throughput.   Implement this feature only if the database environment
requires such IO throughput.  In some cases, it may be acceptable to disable
I/O slaves and run with a single DBWR process.

Other Ways to Tune DBWR Processes
=================================

It can be easily seen that reducing buffer operations will be a direct benefit
to DBWR and also help overall database performance.   Buffer operations can be
reduced by:
1) using dedicated temporary tablespaces
2) direct sort reads
3) direct Sqlloads
4) performing direct exports.

In addition, keeping a high buffer cache hit ratio will be extremely beneficial
not only to the response time of applications, but the DBWR as well.

July 18, 2001 Christopher -- Thanks for the question regarding
      "Infroming the client of progress in a stored procedure", version 8.1.6

      You Asked
We are writing a sotred procedure that will run against a million rows and take
over 24 hours to complete.  This proceduer will be executed from our client
software using an Objects for OLE connection.  Is there anyway to inform the
client software of the status of the procedure while it is running?  I would
like to pass a counter back to the client while the procedure is running, but I
can't figure out how to do so. I can only manage to pass information back after
the procedure has completed.

      and we said...
Well, you do not want to run this procedure in the foreground -- thats for sure.
A simple network failure, client crash, power outage and that work is all gone.

Better to run the procedure in the BACKGROUND.  Use DBMS_JOB to run it
asyncronously.  Have the procedure that runs for 24 hours make many calls to the
DBMS_APPLICATION_INFO package (see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/dbms_app.htm#999107
).  You want to use the set_session_longops api to set values in the
v$session_longops table.

Now your client can log off and come back whenever and simply query the
v$session_longops table to see the progress.  The only thing that would break
your process would be a database instance failure now and if that happens, your
process will auto-restart upon database restart.

See DBMS_JOB in the supplied packages guide for details on using that as well.
In short, you'll make sure

job_queue_processes
job_queue_interval

are set and you will run your job by:

begin
  dbms_job.submit( :n, 'your_procedure;' );
  commit;
end;
/

Review &
      Followup

      Rating:
      5
Excellent  July 18, 2001
Reviewer:
      Chris  from Massachusetts
This is exactly the type of functionality we were looking for!

July 18, 2001 Fernando -- Thanks for the question regarding
      "Processes P00x in my database ...", version Oracle 8.0.x

      You Asked
Dear Tom,

Is it normal if my Oracle 8.0x database starts to create "strange" sessions with
the next set of characteristics:

- They are created eventually (2 or 3 times a day),
- They are created with the name of the end users (field v$session.username),
- If I check the program associated (field v$session.program), it says:
"ORACLE80.EXE(P001)" or (P002) or 3 or 4
- If I kill that session, I'm not killing the session of the end user (I think
I'm killing a process in the server that's creating a dump file). If I check in
my dump-directory the files <SID>P001.trc I find the text: "ksedmp: internal or
fatal error"

Is there any way to avoid it (I mean avoid those "new sessions")?!

Thanks,

Fdo.

      and we said...
they are parallel query slaves.  You have enabled parallel query in your
database and your end users are (trying to) taking advantage of it.

don't kill them, turn off parallel query if you want, but don't kill them.

July 18, 2001 sadiq -- Thanks for the question regarding
      "accessing procedure from diffrent user", version 8i

      You Asked
can we use the stored procedure of user ops$user1
in  user
ops$user2 to update the table of ops$user2 if yes
how and what i have to do
i tried as below but it is updating the table of ops$user1 itself

SQL> grant all on final to ops$devmat;

Grant succeeded.

SQL> grant all on HR_TEST to ops$devmat;

Grant succeeded.

SQL> conn
Enter user-name: ops$devmat@nt8i
Enter password: ******
Connected.
SQL> create table hr_test as select * from ops$hrd246.hr_test;

Table created.

SQL> select * from hr_test;

NATUREOFRECORD            FCODE     CREATE CREATEDON AUTHOR AUTHORISE S
ENO
------------------------- --------- ------ --------- ------ --------- -
---------
ADDRESS                   COMM      SYSTEM 22-JUN-01 SYSTEM 22-JUN-01 Y
ADDRESS                   EMER      SYSTEM 22-JUN-01 SYSTEM 22-JUN-01 Y
ADDRESS                   PERM      SYSTEM 22-JUN-01 SYSTEM 22-JUN-01 Y
ADDRESS                   AAAAA     PAY    13-JUL-01                  N
ADDRESS                   123       PAY    13-JUL-01 PAY    13-JUL-01 Y

SQL> exec
ops$hrd246.final('hr_test','AUTHORISEDBY','TEST','AUTHORISEDON','STATUS','Y','NAT
UREOFRECORD','ADDRESS','FCODE','AAAAA');

PL/SQL procedure successfully completed.

SQL> select * from hr_test;

NATUREOFRECORD            FCODE     CREATE CREATEDON AUTHOR AUTHORISE S
ENO
------------------------- --------- ------ --------- ------ --------- -
---------
ADDRESS                   COMM      SYSTEM 22-JUN-01 SYSTEM 22-JUN-01 Y
ADDRESS                   EMER      SYSTEM 22-JUN-01 SYSTEM 22-JUN-01 Y
ADDRESS                   PERM      SYSTEM 22-JUN-01 SYSTEM 22-JUN-01 Y
ADDRESS                   AAAAA     PAY    13-JUL-01                  N
ADDRESS                   123       PAY    13-JUL-01 PAY    13-JUL-01 Y

SQL> CONN
Enter user-name: OPS$HRD246@NT8I
Enter password: ***
Connected.
SQL> select * from hr_test;

NATUREOFRECORD            FCODE     CREATE CREATEDON AUTHOR AUTHORISE S
ENO
------------------------- --------- ------ --------- ------ --------- -
---------
ADDRESS                   COMM      SYSTEM 22-JUN-01 SYSTEM 22-JUN-01 Y
ADDRESS                   EMER      SYSTEM 22-JUN-01 SYSTEM 22-JUN-01 Y
ADDRESS                   PERM      SYSTEM 22-JUN-01 SYSTEM 22-JUN-01 Y
ADDRESS                   AAAAA     PAY    13-JUL-01 TEST   17-JUL-01 Y
ADDRESS                   123       PAY    13-JUL-01 PAY    13-JUL-01 Y

      and we said...
stored procedures in Oracle8i come in two flavors

- definer rights
- invoker rights

a stored procedure by default (definer rights) is statically bound to the schema
that created it (user1).  It will access a static (deterministic) set of tables
regardless of WHO executes it.

an invokers rights routine will work on the tables the INVOKER sees.

This is a complex difference and fundementally changes the way the stored
procedure runs.  You need to understand the ramifications of using an invokers
rights routine thoroughly before using them.  The really nice thing about
definers rights routine is the forced cursor sharing that will take place --
your shared pool is much better off with definers rights routines.

My book has a rather large section on Invokers and Definers rights routines you
may be interested in as well.  The plsql manual goes into some detail too.
July 18, 2001 --
      Thanks for the question regarding "Performance: PL/SQL stored procedures
      or embedded sql", version 8.1.6/7

      You Asked
I understand the advantages of using PL/SQL stored procedures (sp)instead of
embedded SQL in regards to maintainability. But how about performance?
Assuming I have an optimized query, and assuming the query is in the library
cache and that the sp is pinned, which option is faster? When using the sp, does
oracle need to search the library cache twice (find sp and find sql)?

      and we said...
It really depends on what you want to do with the query -- if the client needs
to process it, you'll be using a ref cursor.  if plsql can process it -- you'll
use static sql.

PLSQL has tons of micro optimizations to make dealing with Oracle faster.  For
example, it caches cursors so that only on the first execution do we have to do
a soft parse -- every other execution is done with the already opened cursor -
no soft parse.  PLSQL also makes you use bind variables -- you have no choice
really.  In all other APIs it is far too easy to not use them (and that will
KILL your performance and scalability, totally).

Using the stored procedure will be faster, better, cheaper and easier to manage.

Don't pin things unless you have some valid reason to.  Its not necessary.
July 19, 2001 --
      Thanks for the question regarding "store procedure", version 8.1.6

      You Asked
tom:

i followed your answer at

http://asktom.oracle.com/pls/ask/f?p=4950:8:10107::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:1137834554916,{soft}%20and%20{parse}
and find out that although soft parse for select * from dept only take once, it
take as many as exection times for BEGIN P; END;

So

1.
if my business rule is bery complex,then put it into store procedure will
definitely help performace, but
if i need write a java program,the business rule of which is to execute insert
into mytable values (?,?);

don't u think the performace will improve if i put it into a store procedure and
call that store procedure from my java program?

      and we said...
Yes, I think using stored procedures to encapsulate your business logic is an
excellent approach, one that I use myself.

Let me put it this way:

o I've never met a Java programmer who really knew a ton about the database,
transaction processing, all of the advanced features of the database.

o I've never met a really good database developer who programmed Java for a
living.

Divide and conquer -- specialize, do you what you do best.

followup to comment one

That might be overkill -- but maybe not.

Remember stored procedures run with the privs of the owner.  Here you have given
execute on the procedure to some people, not INSERT on the table.  The only way
to insert is via your procedure.  Need special auditing? -- no problem, you can
add it.  Need to split that table into two tables?  -- no problem, you can do
it.  Need to add more logic to the transaction?  --- no problem you can do it.
You can do it for ALL applications simultaneously.  Remember before the web,
client server was IT.  Then the web came along.  Bummer, all of my logic is in
this client server program - have to find it, document it and reimplement it.
Putting the logic really really close to the data - that overcomes that.  In
another year when cool technology "X" comes along - you'll be ready.

followup to comment three

While I would hardly call myself a java "guru" (competent perhaps), I would say
I know a bit about PLSQL and the database.  I've written some large Java
programs (palm sync conduits for example to sync up the palm with the database).
 I found doing SQL in Java painful.  I found doing SQL in PLSQL painless.  It is
not because I knew PLSQL better than Java -- rather because of the impedenence
mismatch between SQL and "your favorite 3gl here".  With PLSQL -- my datatypes
are -- SQL types.  I can fetch into a record naturally, in fact -- my records
are created based on my cursors for me automagically.  I can do in 5 lines of
code what would take 25 or more lines of Java code.  Not only that -- but I can
take advantage of each and every database feature easily.

The issue is NOT PLSQL vs JAVA.  PL/SQL is just a language.  Java is just a
language.  Java is a much larger language -- it is a general purpose language.
You could write a PL/SQL compiler and interpreter in Java -- I would say you
would be hard pressed to write a Java compiler and interpreter in PL/SQL.

The issue is (warning, generalization coming) -- the people writing Java code
have formal training in programming -- not database design, not
transaction processing, not SQL and database tuning and so on.  In fact,
most of them view the database as somewhat of a nuisance, something they are
forced to use -- not as a tool.  Many Java developers would be happier
serializing their classes to a flat file.

The people who know the database backwards and forwards -- know how to do really
efficient data models, queries, transactions, how to utilize the database to the
fullest -- they are not "programmers".  They have not taken the months it
requires to become proficient in Java (java is a huge, huge language).  They
focused on the database.

My point is -- do what you do best.  The people who know how to make a really
good user interface -- they many times do not know squat about other elements of
the system (distributed design, other advanced features).  The people who know
how to architect the java middle tier -- they are not database people, it takes
as long or longer to become a really good database developer as a really good
java developer.

My point is -- you cannot do everything (well, most of us cannot do everything,
I'm sure there are some people who can do the best, most intuitive GUI in the
world plus architect and implement the most elegant scalable middle tier
solution plus build the most scalable database application to boot -- I've just
never met one yet).

So, it is not OO vs Procedural.  It is not that PLSQL programmers find it hard
to do objects.  It is not even a mind set.  It is the very nature of the SCOPE
of knowledge one must have to do it all.
Review &
      Followup

      Rating:
      4
  July 18, 2001
Reviewer:
      A reader
even though the store procedure may as simple as the following?
create or replace mypro( a varchar2,b varchar2)
as
begin
insert into mytable values (a,b);
end;

      Rating:
      5
  July 18, 2001
Reviewer:
      A reader
i got your point
:-)

      Rating: 5
PL/SQL and
      Java  July 19, 2001
Reviewer:  Eric Ma
       from Berkeley Heights, NJ USA
Interesting observation - Do you mean there is no simultaneous PL/SQL and Java
gurus, even within Oracle Corp.?  Do you think it is because the mind-set?
PL/SQL is procedural and Java is OO, and Java developers just don't want to
write PL/SQL, where most PL/SQL developers find it difficult to design objects.
PL/SQL 8.0 introduced objects (not in the true sense like in Java or C++), and I
wonder how many people within Oracle Corp. are using this feature.

      Rating: 4
Fit the tool to
      the job - and get the "book"  July 19, 2001

Reviewer:  Tony  from Philadelphia, PA
I had a great deal of confusion with Java vs. PL/SQL until I got Tom's book - it
really clears up when you should and shouldn't.  I'm a big fan of stored
procedures, but I recently hit a roadblock trying to implement credit card
verification for my client's web site.  All the business logic for purchasing
was wrapped up in a PL/SQL package except the verification module provided by
Verisign ( a standalone 'C' program distributed by Verisign) invoked from the
web page.  I didn't like the current solution - I really wanted to get the CC
authorization inside the PL/SQL package where it would be safe and secure ;)
After reading Tom's chapter on Java stored procedures, I checked Verisign's
developer site for a Java implementation - and voila - there it is.  I loaded
the JAR into Oracle, wrote a snippet of Java, wrote the PL/SQL wrapper and -
BOOM! - problem solved! Thanks Tom!

      Rating:
      5
  July 20, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

      Rating:
      5
  July 20, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

July 19, 2001 Kimathi -- Thanks for the question regarding
      "Error using sqlldr73 with DECODE statement", version 7.3.4.5

      You Asked
Hi Tom,
I get the following error when using sql loader (sqlldr73) for 7.3.4.5.
SQL*Loader-930: Error parsing insert statement for column SCOTT.EMPLOYEE.AGENCY.
ORA-00936: missing expression

My control file looks like this;
LOAD DATA
INFILE 'employee.txt'
BADFILE 'employee.bad'
DISCARDFILE 'employee.dsc'
APPEND
INTO TABLE SCOTT.EMPLOYEE
FIELDS TERMINATED BY ","
TRAILING NULLCOLS
(
LAST_NAME    CHAR(24),
FIRST_NAME    CHAR(12),
EMPLOYEE_NUMBER    CHAR(10),
AGENCY        "decode(:AGENCY,NULL,(select code_item_id from scott.code_items
where item_description=:AGENCY and rownum=1))",
DIVISION    "decode(:DIVISION,NULL,(select code_item_id from scott.code_items
where item_description=:DIVISION and rownum=1))",
HOTLIST_STATUS    "decode(:HOTLIST_STATUS,NULL,(select code_item_id from
scott.code_items where
decode(item_description,'Yes','Y','No','N','Pending','P')=:HOTLIST_STATUS and
rownum=1))"
)

I have used the exact same control file to load the same data into an Oracle 8i
database and it works perfectly.

Is there a limitation in Oracle7?
If so, how do I resolve this?
Your help is highly appreciated.
Regards
K

      and we said...
a select ( select ... )

is new syntax available in 8.1 and up only.  You can write a PLSQL function:

create or replace function lookup( p_agency in varchar2 ) return varchar2
as
   l_code_item_id code_items.code_item_id%type;
begin
   select code_item_id into l_code_item_id
     from code_items
    where item_description = p_agency
      and rownum = 1;

   return l_code_Item_id;
exception
   when no_data_found then return null;
end;

and use:

...
AGENCY  "decode( :agency, NULL, lookup( :agency ) )",
....

Your logic in the decode as it is now looks "off".  It would do the subquery
only if AGENCY was null -- but if agency is null the subquery would return no
rows (item_description is NEVER equal to null).....

Review &
      Followup

      Rating:
      5
Perfect  July 31, 2001
Reviewer:
      Kim  from CA,USA
Your response was spot on.

July 19, 2001 Jennifer -- Thanks for the question regarding
      "Calling Java classes stored on file system from PL/SQL stored procedure",
      version Oracle 8.1.6

      You Asked
Is there a way to call Java classes that are stored on the file system   (not
stored in the database) from a PL/SQL stored procedure?  I do not want to store
the Java classes in the database, if it is possible to just call them while they
are sitting out on the file system.  If this is possible, how can one accomplish
this and would you include an example?  Thanks!

      and we said...
Nope, you would need to have the loaded into the database and create a SQL
wrapper for them to enable PLSQL to call them.  The JVM in the database can only
run them from the database.  PLSQL can only "talk" to java running in the JVM in
the database.
July 19, 2001 -- Thanks for the question regarding "Explicit
      <-> Implicit Cursors", version 8.1.7

      You Asked
Hai Tom,

Thankyou verymuch for clearing my earlier doubt. I have some more, I hope I will
not be disppointed.....

1) How can I reduce missing SEQUENCE no's (jumping), By using CACHE option or
NOCACHE ?

2) I want to create partitions as...

STOCK_MAST -->table
---------
chas_no
model
price
..
..
..
item_type  --> value is one of 'C','P','M'

Here C,P,M means Car,Power Product,Motor cycle resp.

If a record is having item_type 'C' then it should be moved to CAR_PARTITION
,similarly POWER_PARTITION,MOTORS_PARTITION and if none of these matches then
should be moved to OTHERS_PARTITION.  I think I have to use HASH partition ?
But please can u tell me how should I create it.  This is the first time I want
to use partitions.  If u can give example it would really help me.

3) My databse version is 8.1.7.  Which version  of designer2000 should I use ?
Please tell me in which order I should intall these products on one machine(NT)
.

4)Most people say that using EXPLICIT cursor will be good in forms to reduce
network traffic.  Because IMPLICIT cursor more than a network trip.  Which one
is good , to perform validations in forms 5.0 ?

I am doing validations on data entered by user in the following way.
This is fine if colum type is number.  Can u please modify following
function so that it will work for both Character & Number type columns.

create or replace function get_row_counts
                (p_table in varchar2,p_column in varchar2,
                            p_cdata in number ) return number
 as
     l_theCursor    integer   default dbms_sql.open_cursor;
     l_columnValue  number  default NULL;
     l_status       integer;
 begin
     dbms_sql.parse(  l_theCursor,
                     'select count(*) from ' || p_table|| '
                       where '||p_column||' = '||p_cdata,
                      dbms_sql.native );
     dbms_sql.define_column( l_theCursor, 1, l_columnValue );
     l_status := dbms_sql.execute(l_theCursor);
     if ( dbms_sql.fetch_rows(l_theCursor) > 0 )
     then
         dbms_sql.column_value( l_theCursor, 1, l_columnValue );
     end if;
     dbms_sql.close_cursor( l_theCursor );
     return l_columnValue;
 end;
/

Really, ur help is highly appreciated....

Thanks , Thank u very much...

regs
Abdullah

      and we said...
1) you can decrease performance and decrease the gaps that will occur when the
sequence is aged out of the shared pool or when the database is shutdown by
using NOCACHE.

I would recommend not losing sleep over gaps in sequences, use CACHE and get the
perfrmance.

2) you really want 9i then -- it has LIST partitioning - the ability to
partition by a list of discrete values.

Prior to that, you must use RANGE partitioning.

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:930642161660
for an example.  Notice how the range is one letter LARGER then the letter I
want to put in that partition.  Ranges are not inclusive.

It'll be near impossible to satisfy "the rest go over here" unless they all are
less then 'C' or greater then 'P'

3) designer 6i release 4 as of this writing.

see the release and installation notes for designer, I believe they cover this
topic.

Install database first
Designer second, make sure its in its OWN oracle home, NOT the database

4) Most people would be wrong then

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1544606261686
benchmark it yourself and see which works best (its what I do)

that is a terrible way to do that.  You need to use bind variables, they are
probably the MOST important thing to use.

the entire routine should just be:

scott@ORA815> create or replace function get_row_counts
  2                  (p_table in varchar2,
  3                   p_column in varchar2,
  4                   p_cdata in varchar2,
  5                   p_function in varchar2 default 'to_number' ) return number
  6   as
  7       l_columnValue  number  default NULL;
  8   begin
  9       execute immediate
 10       'select count(*)
 11          from ' || p_table || '
 12         where ' || p_column || ' = ' || p_function || '(:x)'
 13       into l_columnValue
 14       using p_cdata;
 15       return l_columnValue;
 16   end;
 17  /

Function created.

scott@ORA815>
scott@ORA815> exec dbms_output.put_line( get_row_counts( 'emp', 'empno', 7782 )
);
1

PL/SQL procedure successfully completed.

scott@ORA815> exec dbms_output.put_line( get_row_counts( 'emp', 'ename', 'KING',
NULL ) );
1

PL/SQL procedure successfully completed.

that'll work with numbers and strings AND it'll use shared sql when you query
the same table/column.

It seems to me, it would be easier for the caller to just code the sql
themselves....
Review & Followup

      Rating: 5
Sequence
      maintenance  July 19, 2001
Reviewer:  Connor
       from UK
You can get a "compromise" with sequences by setting them to nocache and then
back to cache on a shutdown trigger.  Then you don't lose (as many)
numbers....This (sometimes) keeps the auditors happy

July 19, 2001 play -- Thanks for the question regarding "all
      about bulk binds", version 8.1.7

      You Asked
1.
http://asktom.oracle.com/pls/ask/f?p=4950:8:11486::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:850996414841,{bulk}%20and%20{binds}
What is the difference between adding a column in between and adding a colyumn

2.
http://asktom.oracle.com/pls/ask/f?p=4950:8:11486::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:1444404365767,{bulk}%20and%20{binds}

"you might use arrays of different
types (arrays of dates and numbers) to avoid the implicit
conversions"

Will the above lead to any performance improvement.. why should we avoid
implicit conversions

3.All your examples have been of bulk inserts using bulk binds, can you give an
example of doing deletes using bulk binds.

4.Suppose my data is not coming from tables, but coming from caluculations of my
application , how can I use bulk binding feature
to do bulk inserts.

5.what is the max limit of limit clause in bulk binding?

6.The time taken for inserting 1 row or 1000 rows should be the same
while using bulk inserts (limit set to 1000), Iam I right ?

7.which will be faster, do a insert into select * from table name..
or inserting using bulk binds..

thak ya

      and we said...
1) I assume you mean "whats the difference between adding a column in between
two existing columns and just adding a column".  If so, its the effect it has on
SELECT * from T and INSERT into T values (...) -- where they leave off the list
of columns.

Adding a column in the middle will make it appear in the middle of the lists of
columns for these statements.

2) ALWAYS avoid implicit conversions -- when they work, they are OK, when they
don't -- they are miserable to discover.

Most of the Y2k bugs I observed were due to implicit conversions between date ->
string -> date.  The centuries would get wiped out, time components get lost and
so on.  Additionally if you compare a STRING to a NUMBER -- what happens?  Does
the string get turned into a number or the number into a string.  Be explicit
and you won't be faced with this question.

3) forall i in 1 .. 10
       delete from t where x = array(i);

its the same, just load up array with the values of X you want to delete from T
and go for it.

4) for i in 1 .. 100
   loop
      array(i) := f(x);
   end loop;

   forall i in 1 .. 100
          insert into t values ( array(i) );

(i must be missing something here?)

5) limited by available ram or +2billion (biggest plsql table size)

6) no, the time to insert 1000 rows will be longer, it generates more redo, more
rollback, more work.

doing 1,000 rows ONE at a time will take lots longer then 1,000 rows 100 at a
time.  Thats the comparison you want to make

7) insert into select * from

the less code you write, the faster we go.
July 19, 2001 Marlon -- Thanks for the question regarding "Read
      only user", version 7.3

      You Asked
Hi,

I create a user 'jon' for read only access.

    connect system/manager;
    create user jon identified by jonx;

I do not give any privieliege to user 'jon'. BUT
I can connect and modify to any tables

   connect jon/jonx;
   update xena set closing_date=sysdate where x0=1;

Why user 'jon' can connect and modify table without privieleges
to create session,select table, let alone update table ???

Or in other word how can I create a user with read only access,
i.e. only create session and select table privieleges ??

> select * from dba_sys_privs where grantee in ('PUBLIC', 'JON' )
>
> return?
SQL>
Wrote file afiedt.buf
  1* select * from dba_sys_privs where grantee in ('PUBLIC','JON')
  2  /

GRANTEE        PRIVILEGE                 ADM
------------------------------ ---------------------------------------- ---
PUBLIC         CREATE ANY VIEW           NO
PUBLIC         CREATE SESSION            NO
PUBLIC         INSERT ANY TABLE          NO
PUBLIC         SELECT ANY TABLE          NO
PUBLIC         UPDATE ANY TABLE          NO

Please help me.

regards,
marlon b

      and we said...
OH MY!

thats horrible.

That means every user can:

o login (everyone has create session)

o overwrite ANY view in ANY schema (eg: any user could replace all_objects if
they wanted to!) everyone has create any view!

o insert into ANY table (including the system tables!!!) they all have insert
any table

o select any data from ANY table -- they all have select any table

o update any row in any table in the database (including once again the data
dictionary itself) -- they all have udpate any table

Wow, I don't believe I've ever seen that in real life.

this is the most insecure system i've run across yet.

You need to talk to the person in charge and get this straightened out right
away.  The unfortunate thing for you is that when you revoke any of those
priveleges every single stored procedure/view/trigger and so on will go
INVALID in your database -- every single one.  This is quite a mess, there is
no avoiding that.  Additionally, many of your procedures/triggers/views might be
reliant on one of these EXTREMELY broad privileges -- you will need to take time
to figure out what privileges exactly the owner of those procedures and so on
actually need.

There is no easy way out of this hole.  If there is anything resembling
sensitive information in that database, my suggestion is to immediately --
revoke all 5 of those privs from public.  This will immediately shutdown your
apps more or less as everything will go invalid (your database will be
recompiling stuff for days).  Additionally -- many users won't be able to log in
and many things will be invalid due to lack of privs.  It'll be a mess but the
flip side is -- right now -- everyone can do anything to anyone at anytime.

July 20, 2001 MR -- Thanks for the question regarding "Several
      questions", version Oracle8i Enterprise Edition Release 8.1.5.0.0 -
      Production

      You Asked
Hi Tom,

I have several doubts.

(1). I have a DATA tablespace. I want to re-create this tablepsace so that I can
retrieve a large amount of storage space and tidy up the tablespace. This table
contains all the objects owned by 2 schemas. What should i do to recreate this
tablespace so that i don't miss any objects? Also the size the tablespace is
huge (63 GB with 13 GB of data). What method should I use to export (since there
is a limit of 2GB on the dump file size in Unix)? What parameters to set in exp
parameter file? Please explain me in detail.

(2). Is the location of the data files in anyway affect performance?
creating data files in the same disk or spreading across disks....
which is better?

(3). For the creation of large tables,
(a). Is having a small extent size slow down the creation of
the table?
(b). Is the extent size should be equal to the sort_area_size for the DATA
tablespace?

(4). Is it possible to rename a tablespace?

Thanks and Regards,
MR

      and we said...
1) how about alter table MOVE tablespace (new tablespace and new storage
parameters)

Make sure this NEW tablespace is a LOCALLY MANAGED tablespace with uniform
extents!! you'll never have to move the data again.

I would not use exp myself for this -- i would do a NOLOGGING move and then
rebuild the indexes.

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:47812348053
2) your goal is to evenly distribute IO across your disks.  placement of
datafiles is how you do this.

3) a) not with LMT's (locally managed tablespaces)
   b) only for TEMP

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:870967214635
4) no

followup to comment one below

The second link above points to a page that shows how you might set up the
extent sizes for objects ranging in size from 16k to 1.6gig

If you have an LMT with uniform extent sizes, the extent sizes in the storage
clause are not used -- the LMT enforces UNIFORM extents.  If you have an LMT
with 1m Uniform extents and a storage clause like ( initial 10m next 50m
minextents 2 ) -- Oracle will allocate 60 1m extents for you.

I myself do not use auto allocate.  I like uniform.

As for the file question -- thats upto you and your needs.  Your goal is to
evenly distribute IO over all of your devices.  If you can accomplish that
effectively with one disk disk and striping -- go for it.  Having many volumes
gives you some degree of control and the ability to move "hot" data around.

Review &
      Followup

      Rating: 4
very useful
      answer  July 20, 2001
Reviewer:  MR
       from UK
Hi Tom, Thanks for ur answer. It gave me new insight. Now I have started using
locally managed tablespaces. I have some more doubts in ur answer. My database
contains only historical data. It doesn't change. I have tables and indexes with
different sizes from 16KB to 1650MB. What is the optimal way to define extent
sizes? If i have a locally managed tablespace with uniform extent size and
create a table on it with a different extent size using the storage parameters,
will it cause fragmentation? Is "auto allocate" a better choice for this
situation? Also I have dedicated disks to use for my database. Creation of a
single large data file or multiple data files...which is better? Thanks in
advance.

      Rating: 4
Thank u very
      much  July 20, 2001
Reviewer:  MR  from
      UK
Tom...Thanks a lot. sorry to disturb u again. I still need one more
clarification in your answer regarding storage clause.

When I use alter table move method using the moveall.sql given by you,
OR
just give "alter table table_name move new_tablespace_name" without any storage
clause
OR
create a new table with storage clause difft. from the uniform extent size
then the LMT doesn't enforce its extent size. It does for next_extent but not
for initial_extent. The initial_extent in all 3 cases above is their extent size
in the old tablespace or the size specified in the storage clause.

Also, how can i move LOB INDEXES and LOB SEGMENTS to the new tablespace?

July 20, 2001 play -- Thanks for the question regarding "bulk
      binds follow up", version 8.1.7

      You Asked
http://asktom.oracle.com/pls/ask/f?p=4950:8:12906::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:1014467648744,
The question number was what is the difference between adding a new column
between two existing columns and  adding it at the first or last in the list of
columns

Arent your answers for 6 and 7 contradictory

in 6 you say..

"doing 1,000 rows ONE at a time will take lots longer "

and in 7 you say..

insert into select * from

the less code you write, the faster we go.

If Iam inserting 10,000 records woudnt it take more time doing with insert into
select * from ............ because it has to insert 10,000 records one at a
time..

Where as bulk binds will do it 1000 at a time, so that is only 10 inserts...

Kindly clarify..

Actually, can you explain when should I do inserts with bulk binds and  when
should I insert with insert into table select * from .....

I will clarify question 4 tommorow.. I will try to come up with the exact
scenario..

Thank you

      and we said...
and hopefully i answered the difference between adding the column in the middle
vs anywhere else (i believe I did)

6 and 7 do not contradict.

insert into t select * from t;

does all of the rows in one statement.  It'll do 1000 rows in one call.  It will
not insert 1000 rows 1 at a time.

the database does that as one big statement for you.

Benchmark it yourself.  You have access to exactly the same tools I do for this,
see

http://asktom.oracle.com/~tkyte/tkprof.html
If you can do it with:

insert into t select * from t;

you should do it that way for the following reasons (written in order of my
prioritization):

1) It is less code you have to write.  It will have less bugs, less maintenance.
2) It is more straight forward and easy to read.  It is very clear what you are
doing
3) it'll almost CERTAINLY be faster.

Try this out for yourself:

create table t
as
select object_name, object_id from all_objects where rownum <= 10000
/

My all_objects has 22k rows -- make sure to put 10k rows into T

create table t2
as
select * from t where 1=0;

alter session set sql_trace=true;

declare
    type vcArray is table of varchar2(30) index by binary_integer;
    type numArray is table of number index by binary_integer;

    l_object_name vcArray;
    l_object_id   numArray;
begin

    insert into t2 select * from t;
    rollback;

    select * BULK COLLECT into l_object_name, l_object_id from t;

    forall i in 1 .. l_object_name.count
        insert into t2 values ( l_object_name(i), l_object_id(i) );

    rollback;
end;
/

Now, tkprof shows me:

INSERT INTO T2 SELECT *   FROM T

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.08       0.08          0        144        201       10000
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.08       0.09          0        144        201       10000

So, the overall time to get and insert 10k rows was 0.08 cpu seconds.  Now,
looking at the fetch it out and insert it:

SELECT *
FROM
 T

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.12       0.11          0         51         12       10000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.12       0.11          0         51         12       10000

INSERT INTO T2
VALUES
 ( :b1,:b2  )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.12       0.12          0         93        189       10000
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.12       0.13          0         93        189       10000

Hmmm, 0.24 total CPU seconds -- or 3 times longer -- to do the same work.

the ONLY rule of thumb I have is easily stated:

o if you can do it in a single SQL statment -- do it, its always best
o if you cannot do it in a single SQL statment, do it in plsql
o if you cannot do it in plsql, use a java stored procedure (this should only
occurr when you need to access something OUTSIDE of the database)
o if you cannot do it in java, or java is just too slow, use C (external
procedures)

July 20, 2001 -- Thanks for the question regarding "about bind
      variable", version 8.17

      You Asked
hi tom:
in your archives i find some article about bind variable,i know it's very
significant for improve the performance of my program.
there is many pl/sql procedure in our program, but i'm not exact know how would
i do to use bind variable.
my question is
1. how can i use bind variable in the select,update,insert,delete and cursor
statement.
2. i have a test as follow
drop table test_b;
create table test_b (code number,value varchar2(80),memo varchar2(80));

create or replace procedure sp_test_insert_v
as
l_start number default dbms_utility.get_time;
i    number;
begin
    for i in 1 .. 1000
    loop
    execute immediate
    'insert into test_b values(:a,:b,:c)'
    using i,'testfdgfscgbcvbdfchg',to_char(sysdate);
    end loop;
    commit;
    dbms_output.put_line( round( (dbms_utility.get_time-l_start)/100, 2 ) ||'
seconds...' );
end;
/

create or replace procedure sp_test_insert_n
as
l_start number default dbms_utility.get_time;
i    number;
begin
    for i in 1 .. 1000
    loop
    insert into test_b values(i,'testfdgfscgbcvbdfchg',to_char(sysdate));
    end loop;
    commit;
    dbms_output.put_line( round( (dbms_utility.get_time-l_start)/100, 2 ) ||'
seconds...' );
end;
/

truncate table test_b;
alter system flush shared_pool;
execute sp_test_insert_v;

truncate table test_b;
alter system flush shared_pool;
execute sp_test_insert_n;

the result is:
dbauser@MCHT_DB> execute sp_test_insert_v;
11.61 seconds...

dbauser@MCHT_DB> execute sp_test_insert_n;
2.11 seconds...

i know because sp_test_insert_v have Parse 1000 times,so it's slowly,but how can
i optimize the procedure sp_test_insert_n?
is the variable 'i' in procedure sp_test_insert_n called bind variable?

could you please help me.

Thanks in advance.

michael

      and we said...
In PLSQL -- the work is done for you.  We "autobind" automagically -- this is
one of the greatest benefits of PLSQL -- it FORCES you to bind.

So, in your insert:

    insert into test_b values(i,'testfdgfscgbcvbdfchg',to_char(sysdate));

i is in fact a bind variable.  Everytime you use a plsql variable in a query or
dml, its a bind variable.

As for making sp_test_insert_n faster, use bulk binds:

ops$tkyte@ORA817.US.ORACLE.COM> create or replace procedure sp_test_insert_n
  2  as
  3          l_start number default dbms_utility.get_time;
  4          i    number;
  5  begin
  6      for i in 1 .. 1000
  7      loop
  8          insert into test_b
values(i,'testfdgfscgbcvbdfchg',to_char(sysdate));
  9      end loop;
 10      commit;
 11      dbms_output.put_line( round( (dbms_utility.get_time-l_start)/100, 2 )
||
 12              ' seconds...' );
 13  end;
 14  /

Procedure created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> create or replace procedure
sp_test_insert_n_faster
  2  as
  3          type numArray is table of number index by binary_integer;
  4
  5          l_data  numArray;
  6          l_start number default dbms_utility.get_time;
  7  begin
  8      for i in 1 .. 1000
  9      loop
 10                  l_data(l_data.count+1) := i;
 11          end loop;
 12
 13          forall i in 1 .. l_data.count
 14          insert into test_b
values(l_data(i),'testfdgfscgbcvbdfchg',to_char(sysdate));
 15
 16      commit;
 17      dbms_output.put_line( round( (dbms_utility.get_time-l_start)/100, 2 )
||
 18              ' seconds...' );
 19  end;
 20  /

Procedure created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> exec sp_test_insert_n
.29 seconds...

PL/SQL procedure successfully completed.

ops$tkyte@ORA817.US.ORACLE.COM> exec sp_test_insert_n_faster
.04 seconds...

PL/SQL procedure successfully completed.

.29 down to .04 -- not too bad.

Review &
      Followup

      Rating: 4
thank you very
      much  July 22, 2001
Reviewer:  michael
       from china
now, i understand.

      Rating: 5
Bind
      Variable  December 18, 2001
Reviewer:  Gavin
      Martin  from Fairfax, VA
Tom (the man!),
Thank you for answering what, for me, has been a nagging question in my mind
since reading your book.  For whatever reason, the fact that pl/sql variables
are bind variables, didn't sink in...I was trying to rewrite my code using
EXECUTE IMMEDIATE and DBMS_SQL in order to get the performance gains from bind
variables...but the opposite was happening...now all is clear.

Thanks for writing your book.   Let me know if you plan on a follow up so I can
get in line now :-)

July 21, 2001 Benny -- Thanks for the question regarding
      "concatenated indexes", version 8.1.7

      You Asked
I was told before that in order for a concatenated index to be
used, it had to be referenced in order starting from the first
column (allowing for subsets of the columns)

I heard that this has changed in Oracle later releases where
the first column doesn't have to be used as long as the columns
are sequential.  Can you verify this, thanks!

      and we said...
We can use an index in a couple of ways

- in a range scan.  Here, obviously, the leading edge of the index must be used.
If you have an index on a,b,c -- then a predicate that queries on (a), or (a,b),
(a,c) or (a,b,c) can use this index with varying degrees of success (a,b,c) will
be the most successful, (a,b) the next most, and (a), (a,c) the "least"
successful as they scan the most data)

- as a FAST FULL scan -- here we read the index out of order and use it as if it
were a skinnier version of the table.  Here, if the table were really wide (fat)
and you had an index on (a,b,c), a query "select distinct(c) from t" might go
faster if we did a fast full scan of the index instead of the table. Here the
index IS the table.

followup to comment one

sure, here you go:

ops$tkyte@ORA817.US.ORACLE.COM> create table t nologging as select * from
all_objects;

Table created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> create index t_idx on
t(object_id,generated,secondary);

Index created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> analyze table t compute statistics
  2  for table
  3  for all indexes
  4  for all indexed columns
  5  /

Table analyzed.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> set autotrace on
ops$tkyte@ORA817.US.ORACLE.COM> select count(distinct secondary) from t
  2  /

COUNT(DISTINCTSECONDARY)
------------------------
                       2

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=1)
   1    0   SORT (GROUP BY)
   2    1     INDEX (FAST FULL SCAN) OF 'T_IDX' (NON-UNIQUE) (Cost=3 Card=27021
Bytes=27021)

ops$tkyte@ORA817.US.ORACLE.COM> select secondary from t where generated = 'Y';

.....
N
N

177 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=177 Bytes=354)
   1    0   INDEX (FAST FULL SCAN) OF 'T_IDX' (NON-UNIQUE) (Cost=3 Card=177
Bytes=354)

ops$tkyte@ORA817.US.ORACLE.COM> set autotrace off

it used the index to answer the question, not the table.
Review &
      Followup

      Rating: 3
Could you an
      example for the 2nd case?  July 20, 2001
Reviewer:
      Sean  from Atlanta

July 21, 2001 Suresh -- Thanks for the question regarding
      "Indexes", version 8.17

      You Asked
Tom,
   In CBO, does 'driving' table really matter in a three table join select. What
I mean is , should I really concentrate on which is going to be the driving
table in case of multi table join select query.

Thanks,
Suresh

      and we said...
Yes.  Definitely.

Say you have this

t1  -- 1 row    (x int) has value 1
t2  -- 1 row    (x int) has value 2
t3  -- 1 billion rows  ( x int ).  Most of the rows have the value "3"

you join t1, t2, t3 by x.

what happens if t3 is used to drive the query?  (full scan of t3, but no rows
returned)

what happens if t1 is used to drive the query?  (full scan of t1, but no rows
returned)

One of the queries scanned 1 billion rows.  the other none.

Yes, the driving table can make a huge difference in real life as well.

followup to comment

you asked if the 'driving' table matters -- yes it does.

you did not ask if the 'order of table matters'.  Under the CBO - it *never*
mattered what the order of the tables was.  Under RBO is always mattered (and
still does)

followup to comment two

Not knowing how you did your tests, I have to question them.  Pure math on this
issue -- pure math.

I have 22k objects in my database, so my table t has about 22k rows in this
example:

ops$tkyte@ORA817.US.ORACLE.COM> create table t nologging as select * from
all_objects;

Table created.

ops$tkyte@ORA817.US.ORACLE.COM> alter table t add constraint t_pk primary
key(object_id);

Table altered.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> create table t2 ( x int primary key );

Table created.

ops$tkyte@ORA817.US.ORACLE.COM> insert into t2 values ( 1 );

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> set autotrace on

First, use T as the driving table:

select /*+ ORDERED */ *
  from t, t2
 where t.object_id = t2.x

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.53       0.53          0      27394         12           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.53       0.53          0      27394         12           0

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 334  (OPS$TKYTE)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  NESTED LOOPS
  27021   TABLE ACCESS FULL T
      0   INDEX UNIQUE SCAN (object id 70383)

and now T2 as the driver

select /*+ ORDERED */ *
  from t2, t
 where t.object_id = t2.x

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          3          4           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.00       0.00          0          3          4           0

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 334  (OPS$TKYTE)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  NESTED LOOPS
      2   INDEX FAST FULL SCAN (object id 70383)
      0   TABLE ACCESS BY INDEX ROWID T

fairly measurable difference.  Trust me -- the choice of a driving table in a
query is CRITICAL to performance.  It is the job of the CBO to choose this
table.

Review &
      Followup

      Rating: 3
Indexes in
      8i  July 20, 2001
Reviewer:  Rajesh Hassija
       from FL, USA
Hi Tom:
I am using 8.1.6 and i have noticed that in CBO the order of tables did not make
a difference, i have also explain planned the query .. but the cost was same ,
also i tried sql trace which did not show any difference.

Although i remember that in prior veriosn to 8.0 (i.e. 7.x) it used to make a
hell of difference , even in the where clause it used to make )

      Rating: 3
driving
      table  July 20, 2001
Reviewer:  Benny Ching
       from Los Angeles
I ran similar tests on large versus small driving tables and I didn't notice any
difference.  I didn't use such a large difference as 1 vs 1 billion but I ran
test using tables
in size 100's vs 100,000

July 21, 2001 Andreas -- Thanks for the question regarding
      "date conversion into seconds", version 8.1.7

      You Asked
is there a more elegant way to convert a date into number of seconds since
1970-01-01 00 00 00 than the sql below?
SQL> select sysdate, (sysdate-to_date('19700101000000', 'YYYYMMDDHH24MISS') ) *
86400 secs from dual;

SYSDATE                   SECS
------------------- ----------
2001-07-19.17:44:20  995564660

      and we said...
Elagance I suppose is in the eye of the beholder.

You can make this more "elegant" i suppose by writing a PLSQL function to hide
the math -- but that would be slower then doing it directly.

See

http://osi.oracle.com/~tkyte/Misc/CTime.html
you need to add some timezone conversion in there as well.  The standard "number
of seconds since 1970" should be in UTC

followup to comment one below

the to_char( ..., 'sssss' ) returns the number of seconds since midnight.  He
would still need to multiply 86400 by the number of days, adjust for the
timezone issue and then add this in.
Review &
      Followup

      Rating:
      3
Seconds  July 20, 2001
Reviewer:  Rajesh
      Hassija  from FL, USA
I guess he can he even use the  TO_CHAR(sysdate, 'sssss') option this returns
the time in seconds.

if this can solve the purpose it will be more easier.

July 21, 2001 -- Thanks for the question regarding "runaway
      process", version 8.1.6

      You Asked
Dear Tom

I came to hear that, in oracle 8.6.1, when session is killed at the client , but
is still alive on the datbase  server... if the dba manually kills the session,
then the database crashes....

is it true? if this is so, Iam really surprised.. becasue at many client sites
sessions hang on the server site even after getting killed at the client..

Kindly clarify..

What is a runaway process?

How should I kill a runaway process?

How should I know , what objects are locked, and locked by whom, and by what
sessions?

What is the relationship between v$LOck and V$Transaction views..

When is your next book coming , and what is it about?

      and we said...
I've never heard of such a thing myself, i've been running 816 for quite a while
and have killed more then one session.

Code this (don't, just pretend to)

begin
   loop
      null;
   end loop;
end;
/

that'll take your dedicated server and through it into a hard loop, alter system
kill session won't get it (too busy), it'll consume all of the cpu available.
Its known as a "runaway".  killing at the OS level is often the only recourse.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:839412906735
for v$lock/transaction

Does that mean you've read all 1,297 pages of the first one!  I'm not currently
writing any books at this moment.  Just trying to enjoy having my life back.  It
takes an incredible amount of time to write a book.  When you read a page,
consider that it represents at least 1 hour of my life -- each page....

July 22, 2001 shiva -- Thanks for the question regarding "Usage
      of 'From Select' Clause. ", version 8.1.5

      You Asked
Dear Sir,

 Doing a great service to oracle community. I am one of the ardent fans of
oracle. But lately i didnt get much chance to update on oracle features..

My First Question :
I have written some complex queries using 'FROM SELECT' clause. My basic doubt
is in terms of performance which is better to write
a.)complex queries with 'From Select' clause or b.) write as a different select
statement. The other doubt is, will oracle internally treat 'FROM SELECT' clause
as one single statement or different 'SELECT' statement alltogether. Writing of
'FROM SELECT' clause is encourageable in terms of performance. If not is there
anyother method which performs the same function of 'FROM SELECT' clause.

My Second question :
Sir, how do u manage 'ASK TOM ' oracle site. are u people using entire set of
oracle products to manage this beautiful site. Sir, my sincere appreciation to
the entire team who are involved in this building of this site. Sir, can u
please share the technical know hows of this site, so that it will be benificial
for us to educate the client to stay with oracle products only. As i earlier
said i am an ardent fan of oracle and there should be sufficient proof for me to
say the oracle application server & Database and some front end are enough to
develop a good site with considerable no. of users and transactions.

Thanks in Advance
with best regards
shiva

      and we said...
The "from select" is known as an INLINE view.

They are wonderful constructs that allow you to

o express a query in a syntactical more meaningful way -- they are easier to
read and write

o express queries that were impossible before without views

They simply create temporary views.  they can be extremely efficient (or not)
depending on what you are asking, what you are doing.

You should have NO reservations with regards to using them, they are great.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:995030557145
for a little more info on this.

As for the question about asktom.

We use

o Oracle the database
o interMedia text (for indexing and searching)
o iAS the webserver + mod_plsql

the pages themselves do not exist on disk anywhere, they are all generated as a
result of a stored procedure call.  We do all state management and processing in
the database.

followup to comment one
mod_plsql is the PLSQL module that runs under Apache.  In a nutshell, it
translates a URL into a stored procedure call.

See

http://technet.oracle.com/docs/products/ias/doc_library/1022doc_otn/index.htm
for the docs.
Review & Followup

      Rating: 5
What is
      mod_plsql stands for?  July 22, 2001
Reviewer:
      Initial Learner  from USA
Hi, Tom, what is mod_plsql stands for, and where we can find docus about that?

Thanks

      Rating: 4
regardig 'FROM
      SELECT' usage  July 23, 2001
Reviewer:
      Shiva  from INDIA
Thanks for ur update on 'FROM SELECT' and 'ASK TOM' site.


Subject | Article | Last Updated (East coast time)
should I define column length as precise as possible? | article only | Jul 23, 2001 08:39 am
How are we suppose to go about printing by pdf and excel format in Oracle 7.3 | article only | Jul 23, 2001 08:44 am
Help with v$statname and v$sysstat | article only | Jul 23, 2001 09:43 am
Usage of cursor variables/dynamic SQL within packages | article only | Jul 23, 2001 09:45 am
Creating users on the replicated DB | article only | Jul 23, 2001 07:32 pm
number conversion | article only | Jul 23, 2001 07:37 pm
volume of inserts increase | article only | Jul 24, 2001 08:08 am
One User to Another through Forms 6.0 | article only | Jul 24, 2001 07:41 pm
size of MINIMUM EXTENT | article only | Jul 24, 2001 07:46 pm
Stored procedure -- are they evil | article only | Jul 24, 2001 08:05 pm
Using Alias | article only | Jul 26, 2001 01:21 pm
row(s) 1 - 11 of 11
July 23, 2001 hahaer -- Thanks for the question regarding "should I define column length as precise as possible?", version 8.1.6
You Asked
One senior developer of our company defines his table column length at some
random. E.g. he would define an employee table as follows:

CREATE TABLE employee {
 id         number,
 name       varchar2(200),
 job        varchar2(200),
 hobby      varchar2(200),
 education  varchar2(200),
 deptment   varchar2(200)
);

All VARCHAR2 columns are 200 bytes long, and no length limit on id  column even
we can not have employees more than 20000. He said it was simple to define
columns in this way and because columns were VARCHAR2 type, they would be saved
as they were, and wouldn't waste much space, not like CHAR type.  So could u
tell me what benifits can I get if I define column length as precise as possible
so I can persuade him? It will save a lot of memory when DBWR loads data into
buffer cache? Thanks.
and we said...
Well, does this programmer use primary keys? constraints? triggers?  any data
integrity constraints?

If so, tell him to consider the length of a field yet another data integrity
constraint.  Thats what it is.

If the id is a number between 1 and 20,000, it should technically be a number(5)
-- perhaps with a check constraint.  The more DECLARITIVE you can be the better.

Consider it is 2 years from now, this "SR" developer has decided to move on to
greener pastures.  Your new programmer is left with that table.  Unbeknownst to
him, the name field is really limited to 80 bytes, job is a 10 character field,
hobby is 125 characters max.  All of this documentation is LOST, missing, not
there.

At some point, someone will stuff 20 characters into job, which will crash some
other existing program that is expecting 10 characters max.

The table structure is meta-data, it describes the maximum width of these
fields.  Your SR developer is ignoring the self documenting features here.  They
should most definitely be supplying valid values there.

It is not wasting any runtime memory,  it is only contributing to bugs and
errors down the road.  It is the wrong approach, tell them to take the time to
do it right.
Review & Followup
Rating: 4
MR July 23, 2001
Reviewer: Rao chelli from k.s.a
this explination answers may of the programmers questions.
thankx for the clear explination.

Rating: 3
July 23, 2001
Reviewer: Pichaimani Balaubramanian from San Jose, CA USA

July 23, 2001 Prashanth -- Thanks for the question regarding "How are we suppose to go about printing by pdf and excel format in Oracle 7.3", version Oracle7 Server Release 7.3.4.4.0
You Asked
Hi Tom

I am using Oracle Web server3.0 Our Database is Oracle 7.3 with PL/SQL Release
2.3.4.4.0 and Unix 5.0

My requirement is i need to convert the output of a select statement to be
displayed as PDF or EXCEL
for the user to display on the web or give an option to down load the same if he
dosent have one.

I tried out as below. But the browser responds with an alert "Document contains
no data"

   owa_util.mime_header( 'application/pdf' );
      for x in ( select empno, ename from emp ) loop
         htp.p( x.empno || chr(9) || x.ename );
      end loop;

I exactly am not aware as how i am to proceed to get the queried result on to
the above formats.

It would be very much helpful if you give me a detail process, as you do give
for the other queries.

If you think i am supoose to shed out more details then do write back to me. I
am just relying on the solution that you are going to give. As i have searched
your other Question and i was not able to get a topic that was of this
requirement.

Thanks a lot. Shall be waiting for an early reply

Prashanth B S
and we said...
You would need to fully understand the entire PDF file format and generate a
valid PDF file.

Open a PDF file in an editor sometime, you'll see it looks very strange.  It is
not just text.

To get PDF out of the database, I would recommand you use Oracle Reports.  It is
a tool that can generate PDF for you.

As for getting into EXCEL.  Search my website for "owa_sylk" it does this.
July 23, 2001 Mandar -- Thanks for the question regarding "Help with v$statname and v$sysstat", version 8.1.6
You Asked
Tom,

  Can you please provide info on how can I find the
  full table scan and index table scan activities
  in the database using v$statname and v$sysstat?

  Do I need to set TIMED_STATISTICS=TRUE before running
  queries against v$sysstat?

  Also, I look at v$sqlarea for most offensive sqls, is
  there a better way to find the most offensive SQLs?

Thanks in advance,

 -Mandar.
and we said...
  1* select * from v$sysstat where lower(name) like '%table%'
ops$tkyte@ORA8I.WORLD> /

STATISTIC# NAME                                CLASS      VALUE
---------- ------------------------------ ---------- ----------
        48 DBWR transaction table writes           8        614
       144 transaction tables consistent         128          0
           reads - undo records applied

       145 transaction tables consistent         128          0
           read rollbacks

       158 table scans (short tables)             64    1676475
       159 table scans (long tables)              64       3942
       160 table scans (rowid ranges)             64          0
       161 table scans (cache partitions)         64       7153
       162 table scans (direct read)              64          0
       163 table scan rows gotten                 64 1512068438
       164 table scan blocks gotten               64   24283078
       165 table fetch by rowid                   64   22813564
       166 table fetch continued row              64     309293

  1* select * from v$sysstat where lower(name) like '%full%'
ops$tkyte@ORA8I.WORLD> /

STATISTIC# NAME                                CLASS      VALUE
---------- ------------------------------ ---------- ----------
        76 commit cleanouts successfully           8     268320
           completed

       174 index fast full scans (full)           64      10981
       175 index fast full scans (rowid r         64          0
           anges)

       176 index fast full scans (direct          64          0
           read)

will get that.   You do not need timed_stats however, i would recommend you just
leave it on, it is so useful.

I use statspack to find the "top offenders" as far as SQL goes.  Goto
www.oracle.com/oramag and search for statspack for a couple of articles on this
utility.
Review & Followup
Rating: 5
Full Table Scans July 10, 2003
Reviewer: Jaideep from Grand Rapids, MI , USA
Wonderful answer. I was not looking for anything more than this !

July 23, 2001 Omar -- Thanks for the question regarding "Usage of cursor variables/dynamic SQL within packages", version 8.1.6
You Asked
Hi,
      I have a program which requires 8 very similar cursors (the differences
are the table name and the columns of the table referenced). I have read about
cursor variables and dynamic SQL allowing you to change the query performed by
the cursor dynamically. This sounds wonderful, but I haven't been able to
declare a cursor variable within a package. My first impression is that cursor
variables are severely limited by this restriction.

Is there a workaround so that I can use a cursor variable and keep my procedures
and functions neatly in a package? Thanks in advance.

Regards,
Omar Charles
and we said...
You cannot create a GLOBAL VARIABLE of type ref cursor.  You would use it as a
formal parameter if you needed to pass it from routine to routine.

As global variables are "bad" from a programming practice, this limitation will
actually make your code "better".

create or replace package my_pkg
as
   type rc is ref cursor;

   procedure p;

end;

create or replace package body my_pkg
as

procedure p2 ( p_cursor in out rc )
is
begin
     ... process p_cursor here ....
end;

procedure p
is
  l_cursor rc;
begin
    open l_cursor for 'select * from ' || .......

     p2( l_cursor );
end;

end;
/

You can even send this to procedures in other packages:

create package my_pkg2
as
   procedure p( p_cursor in out my_pkg.rc );
end;
/
Review & Followup
Rating: 3
Excellent response but... July 23, 2001
Reviewer: Jim.Adamski@attws.com from Redmond WA
I would like to see more detail in how
the cursor is processed when you respond.

I know you have a lot to do but for 'newbies'
like me it would help.

Rating: 3
PLEASE DON'T INCLUDE QUESTIONS IN THIS PART July 24, 2001
Reviewer: Riaz Shahid from PRAL, Islamabad, Pakistan
Hi all!

I have seen that many people use this area to ask a question while there is no
use of this. Because that question can NEVER BE ANSWERED. So i request all of
memebers not to ask any question from Tom in this seciotn.

Regards

July 23, 2001 Pichaimani -- Thanks for the question regarding "Creating users on the replicated DB", version 8.0.6
You Asked
Hi Tom,
   We are planning replication for our application, one of our modules
allows adding,deleting & modifiying oracle users for the app. Could you suggest
me the best way to replicate the users, I'm hesitant to create the users and
grant them privileges manually.I know my app usernames from one of our app
tables.
   To put it better what are the oracle tables I need to replicate so that our
application users can start using the replicated DB without any wait.

Thanks and Regards
Pichaimani
and we said...
You cannot replicate any tables to replicate users.  You must execute the DDL on
all of the sites.

What I suggest is that you investigate the use of procedure based replication

see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76959/repover.htm#12432
the procedure you replicate can either

o create the user directly using DBMS_SQL

o or if that fails (i'm not sure if the procedure is called as a remote
procedure or a local procedure, if its called remotely, you cannot do DDL in
it), your procedure will use DBMS_JOB to submit a job that creates the user
right after the job is run -- it'll have the same effect as doing the DDL
directly
Review & Followup
Rating: 3
July 23, 2001
Reviewer: A reader

July 23, 2001 kamini -- Thanks for the question regarding "number conversion", version 8.1.7
You Asked
Hi tom

1. The following query returns me the value in Scientific notation.

select
to_char(to_number('9999999990009999999999000099999999999999012345699900')) from
dual

I need the output as decimal.

2. Is it possible to partition a table based on any of the following conditions
          (a) col_name1 = to_date(col_name1)
          (b) col_name = to_date(col_name2)
          (c) col_name = '123'

Thanx
and we said...
we "only" do 38 digits of precision, thats 50.  No can do.  You lose the end of
the number no matter what.

I say "only" because thats a ton more then most....

You can only partition on fixed ranges (eg: x between CONSTANT and CONSTANT) or
on hashes of columns.

You cannot compare two columns and say "if column1 = column2 then partition1
else partition2" directly.  You CAN maintain a third column to which you assign
a value in a trigger based on the values of column1 and column2.  You can then
partition based on this third column.  So in an indirect way you can achieve
this.

(c) is possible in range partitioning as '123' is less then '1234' so you would
create a range partition with a upper bound of '1234'.  In 9i, there is discrete
list partitioning as well that makes this very easy.
July 24, 2001 sam -- Thanks for the question regarding "volume of inserts increase ", version 8.1.7
You Asked
Tom

The application I maintain has a table x, every day my application inserts
50,000 records . These inserts occur simultaneous to the deletes of the records
of the previous day.

Now the number of records are going to increase to 40 million due to change in
some business ruless..

I tested inserting 2 million records in the dev database, to check the time it
takes.. it took round about 5 minutes.. no how much can I depend on this time..
to make my caluculations..

What are the factors which can make a difference when running the same inserts
in the prod or test database.. which can result in a change of timing.

One of my seniors has suggested partitioning the table, but Iam really afraid of
doing so , as I dont know anything of the technology.
In fact the advise I got was to divide the table into 5 partitions , and then
sub divide them into 20 partitions each.
Iam not able to take a decesion?

These inserts will happen in batches of 10,000 , 12,000 , that is there will be
some caluculations and then some inserts and so on..
Iam arguing with my co-developer that collecting 50,000 records each and doing
insert at once is better than doing 5 * 10,000,  insert into statements ,  can
you throw some light on this issue.

Lastly, what will happen to the selects on this huge table.. on 50,000 records
they are doing really well, now what is going to happen, do my users have to
wait for ever, how can I make the selects equally efficient on this table after
doing those high volume inserts.

You opinion and guidance is awaited
and we said...
How much can you depend on that time -- no idea.  If the servers are equivalent
and the loads on each are identical, they will be the same.  If the production
machine is doing 5 times the work of development, all bets are off.  It is a
good first cut.

You'll want to make sure you have sufficient redo/rollback configured -
especially redo.  You'll want to make sure redo is fast -- use dedicated devices
and do not allow for contention on these devices.

If you have multiple processes inserting this data, make sure to set freelists
higher then the default of 1.  Set them to the number of concurrent inserters
for both tables and indexes.

Partitioning is great, and excuse my bluntness but fear of the unknown is silly.
 We'd never move forward....

Now, 5x20 = 100 partitions = 400k rows/ partition might be overkill.  You
probably don't need that many.  If you can partition the data in such a way that
all inserts go into a NEW partition and all of the mass deletes delete data in
an old partition, you can make this very efficient using a rolling window
whereby you simply drop a partition to delete (fast... no redo, no rollback) and
you direct path load a new partition to add (fast.... no redo, no rollback).
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:928294572145
for an example.

As for how many rows to array process, it will vary but I find diminishing
marginal returns after about 100-500 rows per batch (yes, much lower then
10,000).  Here is why -- you are spreading the load out between you and the data
much more evenly.  The database does lots in the background.  If you spend lots
of time getting 10k rows together and then ship them over -- the database will
not be able to do as much in the background because some of its buffers will
overflow (eg: the redo log buffer will have to be flushed -- WHILE you wait,
some dirty blocks in the buffer cache might have to be flushed -- WHILE you
wait).  On the other hand, if you do a little, send 500 rows over, do a little,
send 500 rows over -- the database can be flushing buffers, getting ready for
you while you prepare the rows.  You wait less.

parameterize the number of rows you send and play with it.  start low like 100
at a time and build up from there.

Doing 50k at a time would not be better then doing 5x10k at a time, and that
would probably be best done 500 or so at a time.  Don't argue -- benchmark it
(its what I would do)

Selects, unless you have lots of full scans, are not affected by the size of a
table.
Review & Followup
Rating: 3
Use Bulk Binds July 26, 2001
Reviewer: A Reader from Asia
Hi, Why dont u try and use Bulk Binds if u have to Insert so many rows, will
obviously save u a lot of time.

July 24, 2001 Anup -- Thanks for the question regarding "One User to Another through Forms 6.0", version 8
You Asked
Through forms I will be accepting the username. It may be B or C or D. I want to
select,insert records into these various users according to the username.

If I am using that blockname.username in code it is giving error.

emp(blockname)
uname(text field)[This is for accepting Username)
Scheme(Table Name of Other User)
sm_type(Field Name of Scheme)

Consider I am accepting username as AAA.

So in forms I am giving like

Select :emp.uname.Scheme.sm_type into lv_smtype
from :emp.uname.Scheme;

This statement is giving error.

So how can I use the username? Is it possible to send the username as a
parameter to backend?

Thanx in advance.

Regards
Anup.
and we said...
You have to use dynamic sql to do this.

See the EXEC_SQL package in forms.

You cannot "bind" an identifer -- bind variable are used only where a character
string constant could be used.

eg:

select * from emp where ename = 'KING'

implies that "select * from emp where ename = :bind_variable"  is OK.

but since it is not legal to code:

select * from 'EMP', we cannot code "select * from :bind_variable"
July 24, 2001 Lilian -- Thanks for the question regarding "size of MINIMUM EXTENT", version 8.1.6
You Asked
Hi Tom:

1. what is advantage to specify a size of MINIMUM EXTENT when creatin g a
tablespace? what it really means?
2. i have dba privilege, but i could not grant scott table to other user, can
you tell me which privilege level will allow me to grant scott table to other
users?
thank you very much,
an
and we said...
1) in Oracle8i -- that should be considered an obsolete option as you should be
using locally managed tablespaces which will enforce uniform or auto-allocated
extent sizes.

The minimum extent size was implemented to avoid have objects allocate tiny
extents that would not be re-usable when those objects where dropped in that
tablepsace.  It was an attempt to reduce tablespace free space fragementation.
If you use locally managed tablespaces -- you cannot have free space
fragmentation -- ever.

2) there is no privilege like that.

SCOTT would have to grant to you some privilege WITH GRANT OPTION, eg:

grant select on emp to YOU with grant option;

as scott.

Alternatively, SCOTT can write a small procedure:

create procedure do_grant( p_priv in varchar2, p_obj in varchar2, p_to in
varchar2  )
as
begin
   execute immediate 'grant ' || p_priv || ' on ' || p_obj || ' to ' || p_to;
end;

and grant you execute on that.  the procedure will run "as scott" when you run
it and hence the grant will succeed.
Review & Followup
Rating: 3
oracle dba July 24, 2001
Reviewer: an from wilmington, de
thank you very much, it's great!

Rating: 5
NEED ADVICE July 30, 2001
Reviewer: SHAQ from FAISALABAD,PAKISTAN
HI TOM,
      I AM A STUDENT STUDYING ORACLE8i,I HAVE SO MANY QUESTIONS TO ASK,BUT MY
TEACHERS DONT HAVE ENOUGH TIME AND SOMETIMES I ASK SO STUPID QUESTIONS, AS THEY
SEEM BUT MEAN A LOT TO ME ,EVERY CHAPTER I STUDY MAKES ME MORE CONFUSE,I HAVE
LOST HOPE,MAY BE I HAVE CHOOSEN THE WORNG PAHT,BUT STILL I DONT WANT TO QUIT,I
WOULD LIKE YOU OR ANY ONE WHO CAN HELP ME,TO GUIDE ME,UNDERSTANDING THE BASICS
OF 'ORACLE DATABASE'.I KNOW I CAN BE A GOOD DBA I JUST NEED A WAY TO FIGURE OUT
AS HOW I SHOULD STUDY,I REQUEST A GREAT TIP UNDERSTANDING DATABASE.

Rating: 5
Shaq, Tom has written a book, buy that book. August 02, 2001
Reviewer: Harrison from Haymarket, VA USA
Hi Shaq, Tom has written a book, and the best "great tip" anyone can give you is
buy his book. Learning anything involves learning one thing (a molehill) and
then adding more to it (until you have a mountain of knowledge). If you try
different teachers or books (books are less expensive) someone will say, "this
is like (something)" and that will make sense to you, and you will start putting
more bits together until you are good at it.  Learning always look grim until
you have learned some "basics" so that you can tie something to things you
already know. If you can learn English (hard) you can learn Oracle (just
slightly less hard).  Tom does a good job of making Oracle as simple and as
direct as any teacher can do.  Even the best book can't answer your questions,
so you may have to read several versions to get some things clear, but even two
books are a lot less expensive than one class. Good luck. (see
http://asktom.oracle.com/
for a link
to Tom's book.)

July 24, 2001 Arif -- Thanks for the question regarding "Stored procedure -- are they evil", version 7.3.3.6.0
You Asked
What are the drawbacks in using stored procedures ? Is there any overhead ?

 I am one of the novice ORACLE DBA. I have been asked by one of the SQL
programmer to authorize him with CREATE PROCEDURE system privilege on an ORACLE
user on a production instance. The user has CREATE PROCEDURE privilege on
development instance but not on production instance.

The user account in question has been there for past many years.
I am wondering as to why did the original DBA authorized this user with the
CREATE PROCEDURE on devlopement instance and not on the production instance ?
and we said...
Stored procedures are a great:

o security mechanism
o programming device
o performance enhancing tool

I cannot imagine a database without them.

The developers can do as much damanage using client applications with SQL in
them -- in fact, they can do more because you cannot see the code at all.  If
you have them put their SQL in the database -- you can fix (they can fix) poorly
performing queries in the stored procedures and immediately have all clients
running the better query -- without re-deploying anything.
Review & Followup
Rating: 3
putting their SQL in the database? July 24, 2001
Reviewer: Tom from Florida
How do you put their SQL in the database?  views?  or returning CURSOR
references from procedures?

Do you recommend putting all SQL code (selects, too) in procedures?

Rating: 5
re: putting their SQL in the database? July 24, 2001
Reviewer: Lionel Mandrake from Burpelson, AFB
Gosh, what would be a good way to put SQL into the database instead of leaving
it on the client-side?  Oh, wait, I know, maybe something like... a stored
procedure? or even better, a package and package body containing the
procedures/functions?  Then you could use simply use the *_SOURCE views if you
needed to see the, um, well, source...

Also, I would never give a developer create privileges (or the CONNECT/RESOURCE
roles) on PROD.  EVERY object (ie, table, package, index, etc...) that goes into
production goes through one of our DBA's desks first.  Non-admin users get
'create session' and that is all they need (as far as system privs).  Now, maybe
if all our developers promise to read Tom's book and follow the guidelines, it
would be a different situation... :)  I can guarantee from the code that has
been sent back to the developers lately, not much reading has been going on :(
I mean, is it really that hard to use a bind variable, for instance?  Ah, but I
digress...

Rating: 2
Devloper's Don't need privileges on the Production Database July 25, 2001
Reviewer: MSK from OH USA
It's DBA job to move the code from the Development Database
to production database. Developer's shouldn't have access
for the production database. Any code before moved into
prodcution should be viewed by the DBA

Rating: 3
Have to disagree with MSK July 25, 2001
Reviewer: KT from Scotland
I don't believe it is the DBA's job to give code the once over before putting it
into a production environment. That's why developers are paid big bucks is
because they know what they're doing (sometimes!). That's why a successful
development team will always have an experienced developer who a) knows his code
and b) knows the business to look over any code before releasing to production.
As part of our development standards a developer must produce documented proof
that they are using the most effecient method for retrieving data, whether
that's via tkprof output or explain plans.

Rating: 3
Have to disagree with MSK July 25, 2001
Reviewer: KT from Scotland
I don't believe it is the DBA's job to give code the once over before putting it
into a production environment. That's why developers are paid big bucks is
because they know what they're doing (sometimes!). That's why a successful
development team will always have an experienced developer who a) knows his code
and b) knows the business to look over any code before releasing to production.
As part of our development standards a developer must produce documented proof
that they are using the most effecient method for retrieving data, whether
that's via tkprof output or explain plans.

Rating: 3
re: putting their SQL in the database? July 25, 2001
Reviewer: Tom from Florida
Lionel misinterpreted my question.  We use packages and package bodies
extensively in our application; in fact, we don't use UPDATE or DELETE from
clients at all.  We do, however, use SELECT statements in the client.  Is this a
bad practice?
Perhaps my question should have been "Are you suggesting that we code SELECT
statements into packages and return the cursor as an ORACLETYPES.CURSOR?"
In (the knowledgable) Tom's answer, he states "if you have them put their SQL in
the database--you can fix (they can fix) poorly performing queries in the stored
procedures...."
I assume he also means SELECT statements.  Am I wrong?

Rating: 5
to: tom from fl July 25, 2001
Reviewer: Lionel Mandrake from Burpelson, AFB
Tom (from FL):

Didn't mean to go tripping on you, and, yes, I did misinterpret your question -
my bad.  Let's just say yesterday was one of those days where we had a slew of
"consultants" in-house that "had never worked with Oracle before, but we know
SQL Server."  Like that is a big help.  Anyway, what we do here (even though you
didn't ask) is encourage developers to put as much in the db as possible.  If
the client allows it (and the developer can do it), I encourage returning ref
cursors.  Most client-side development here is done using VB and using Oracle
Objects for OLE on the client-side allows ref cursors with no problem.  Having
said that, though, I am not a developer, so a developer may have better input.
Sorry for the confusion again.

-LM

Rating: 3
Response to KT July 30, 2001
Reviewer: Jim from Philly,PA
imho  even experienced developers forget what the differences between DEV and
PROD. So I require that a DBA install and compile stored procedures. I find that
most developers are either inexperienced with Oracle or are not knowledgable
about the configuration of the production environment.

July 26, 2001 user -- Thanks for the question regarding "Using Alias", version 8.1.5
You Asked
Good moring Tom:

I have an object as a column 'created' data type in my table. Please see:

SQL> desc whodated_t;
 Name                            Null?    Type
 ------------------------------- -------- ----
 WHO                                      VARCHAR2(40)
 DATED                                    DATE

if I select one of the fields from this object from mytable, query will be
failed:

SQL> select created.dated from mytable where id = 10991;
select created.dated from mytable where id = 10991
               *
ERROR at line 1:
ORA-00904: invalid column name

But, if I use a table alias, the query will be successed:

SQL> select p.created.dated from mytable p where p.id = 10991;

CREATED.D
---------
04-JUL-01

The alias 'p' is a temporary name assigned to 'mytable' within this SQL
statement. Why the result is a different?

Thank you
and we said...
well, your describe and query use two wholly different tables and I don't see
created in the described table but anyway....

You must use a correlation name when using the extended dot notation into the
object in a query.

select object_column.component from t

will never work, it must be

select correlation_name.object_column.component from t correlation_name;

This is due to the way SQL itself works.  Otherwise, statements like:

select a.y from t, a

would be ambiguous.  Suppose T has a column A and A has a column Y.

Is that selecting the column A from table T
or
the column Y from table A?

the correlation name removes the ambiguity.
Review & Followup
Rating: 5
July 26, 2001
Reviewer: A reader from Morristown, NJ USA
it is helpful to me.

Rating: 3
July 30, 2001
Reviewer: A Reader from Atlanta, GA
The answer was usefull regarding aliases.... but i couldn't really understand
the question... it seems very ambigious...


Subject | Article | Last Updated (East coast time)
Flat files and History Tables | article only | Aug 04, 2001 02:21 pm
ARE INDEXES USEFUL FOR DELETES | article only | Aug 04, 2001 02:45 pm
indexes | article only | Aug 04, 2001 07:45 pm
Internal operation for dropping columns | article only | Aug 04, 2001 07:58 pm
how to enable object type in version 8? | article only | Aug 05, 2001 10:23 am
Create Oracle Accounts Using External Text File | article only | Aug 05, 2001 10:29 am
How can i run my daly Scripts at specfic Time | article only | Aug 05, 2001 01:34 pm
row(s) 1 - 7 of 7
August 04, 2001 Ron -- Thanks for the question regarding "Flat files and History Tables", version Oracle 8i
You Asked
Tom:
     I have two questions:

A)I have to extract a  flat file from an Oracle Data Table            for the
users.  This Table  has about 100 Columns. How is the best
way to proceed.  Oracle is accessed thru a Unix OS.
 For a few variables , I saw code :
  Select to_char(employee_id) || ',' ||' " ' || employee_name   etc.   Please
advice.

B) Every month flat files are passed to me to create Oracle Tables.
   But now I have to build a history Tables. This means that I would
  have to use Updates, Inserts and Deletes.  There is no indicator on
  the flat files to indicate whether it is an update etc.
   How is the best way to proceed.

            Thank You.
and we said...
a)

see
http://osi.oracle.com/~tkyte/flat/index.html
for a SQLPlus method, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:459020243348
for a pro*c method and finally:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:235814350980
for a PLSQL method of doing this.

b)

If you have a primary key on this table (a pre-requisite for what you describe
so I assume you must), you can emulate this using SQLLDR in a fashion (i have a
complete example of this in my book - this is the outline of the steps you would
undertake):

1. Load all of the data with the APPEND option and specifying errors=99999999,
using a large number for errors lets all of the “good” records get loaded. The
records that would be used for UPDATES will get rejected based on a primary key
or unique constraint violation. They will be written to a BAD file. We will get
all of the new records loaded this way.

2. Load the BAD file into a working table with the TRUNCATE option. This table
is structurally the same as the "real" table – should have the same set of
constraints and such. This will make it so that only the duplicate records are
loaded. Records that were rejected for other data validation reasons will be
rejected again from this table.

3. Update the join of the real table and the working table. Eg, if you were
trying to update the DEPT table from a DEPT_WORKING table (loaded with the "bad"
records from step 2) you might code:

tkyte@TKYTE816> update ( select /*+ ORDERED USE_NL(dept) */
  2             dept.dname        dept_dname,
  3             dept.loc          dept_loc,
  4             dept.last_updated dept_last_updated,
  5             w.dname           w_dname,
  6             w.loc             w_loc,
  7             w.last_updated    w_last_updated
  8            from dept_working W, dept
  9           where dept.deptno = w.deptno )
 10    set dept_dname = w_dname,
 11        dept_loc   = w_loc,
 12        dept_last_updated = w_last_updated
 13  /

In Oracle9i there is a new MERGE SQL command that can be used to MERGE new data
with existing data (eg: Update the row if it exists, insert it otherwise).  when
used in conjunction with the new EXTERNAL TABLE feature (allows a flat file to
be accessed like a table for selects) -- we'll be able to do this in one single
MERGE command (load and update) without sqlldr at all.
August 04, 2001 play -- Thanks for the question regarding "ARE INDEXES USEFUL FOR DELETES", version 8.1.7
You Asked
Tom

1.I have a delete statement which has a where clause , I will be deleing 30% of
the rows in the table using this where query. The columns in the where clause
have a composite index on them.

Now is it beneficial to have indexes to do selective deletes like the one
described above, where you have a where clause.

Because , it is commonly believed that indexes are not good for inserts and
deletes.

2.Further, what does the time format 00:00:00:00 mean.
example

00:01:128:34

3.when I see the raw trace file contents , I see a lot of cursors but I did not
issue so many sql statements, what do all these cursors refer to.

4.

This is the output of a delete statement, where in I forced the use of a local
non unique index using a hint.

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      2     34.98     114.33      25191      21135     214862      142117
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3     34.98     114.34      25191      21135     214862      142117

=====================
PARSING IN CURSOR #1 len=308 dep=0 uid=974 oct=7 lid=974 tim=901741764
hv=4159339775 ad='8d490908'
PARSE #1:c=0,e=5,p=4,cr=10,cu=0,mis=1,r=0,dep=0,og=4,tim=901741764
*** 2001-08-03 12:32:46.568
=====================

without using an index the output is

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1     52.54     126.17      38033      33109    1056178      142117
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2     52.54     126.18      38033      33109    1056178      142117

Do you think it is beneficial for me to force the use of the compostie index.

That you very much for you patience.
and we said...
1) if you are deleting about 30% of the rows -- I would say you have a very
NON-selective delete.  In this case, an index would probably slow you down.
Anytime you are accessing more then 10-20% of the data in the table -- an index
will be of questionable use (but it depends).

In this case, if there are stats on the table, the optimizer will probably just
full scan for the delete (rule based optimizer will always pick an index if it
can).

To answer whether indexes are useful for inserts and deletes -- the answer in
both cases is DEFINTELY YES...

for deletes it is straightforward -- indexes are as useful for deletes as they
are for selects -- think about it.  A delete is just a select that deletes the
rows as it finds it.  If a query takes 5 hours to run as a select -- it will
take longer then 5 hours as a delete.  If you add an index that makes that query
run in 1/1000 of a second, that delete will speed up as well. (eg: "delete from
one_million_row_table where x = 5"  where X is not indexed.  Then add "create
unique index x_idx on one_million_row_table(x)" and do the delete again -- it'll
be much faster)

for inserts -- maybe its not so straightforward.  Consider however these two
cases:

a) a table with a primary /unique constraint.  There are indexes on those
columns that are used to EFFICIENTLY and quickly enforce the constraint.
Without those indexes, each insert would have to full scan the entire table --
slow.....

b) an insert into "select * from ....." type of query.

The bottom line is -- indexes should be used where appropriate.  Over indexing =
bad.  Underindexing = bad.  You index when and where you must to improve
performance.

2) I've not seen 00:00:00:00, 00:00:00.00  yes....

it is hours:minutes:seconds.hundredths_of_secs

I've seen it go over 60 seconds like that on various platforms....

3) without having a single example, i'd have to guess that its recursive sql we
do on your behalf to parse queries, verify access to objects, allocate space,
etc...

Also, sqlplus does lots of its own stuff in the background as well.

4) In your case, with your specific delete, the hint helped (marginally).  If
you change the delete to go after different data -- or run it next month when
the data has changed -- you might not see the same effect.

The question to you is -- is the job the optimizer doing good enough or do you
need that extra 12 seconds.  Don't forget to DROP that local non-unique index
you are forcing the for the delete (if you created it for the delete) as you are
penalizing the other delete by forcing it to maintain it!
August 04, 2001 nag -- Thanks for the question regarding "indexes", version 8.1.7
You Asked
Tom

Iam submitting the question again as I typed my email wrong.

why should an index be rebuilt, when should an index be rebuilt, actually i deal

with 8 huge tables, I want to check for myself if the index have to be rebuilt ,

and then inform the dba about how many indexes have to be rebuilt?

can you give me a script which will give me the script to give the statistics of

an index

how can I find the following statistics

size of a single row of a table
total size of a table
size of a given index

I dont have access to any dba_ views , how should I use your show_space program
and we said...
If you don't have access to the DBA_* tables -- this isn't your problem.  Its
the DBA's job.

That aside, you can:

analyze index INDEX_NAME validate strucuture;

Then, peek at the dynamic view INDEX_STATS.  For example:

ops$tkyte@ORA817.US.ORACLE.COM> create table t as select rownum x from
all_objects;

Table created.

ops$tkyte@ORA817.US.ORACLE.COM> create index t_idx on t(x);
Index created.

ops$tkyte@ORA817.US.ORACLE.COM> delete from t where mod(x,2) = 0;
13514 rows deleted.

ops$tkyte@ORA817.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817.US.ORACLE.COM> analyze index t_idx validate structure;
Index analyzed.

ops$tkyte@ORA817.US.ORACLE.COM> exec print_table( 'select * from index_stats' );

HEIGHT                        : 2
BLOCKS                        : 64
NAME                          : T_IDX
PARTITION_NAME                :
LF_ROWS                       : 27028
LF_BLKS                       : 59
LF_ROWS_LEN                   : 422078
LF_BLK_LEN                    : 7996
BR_ROWS                       : 58
BR_BLKS                       : 1
BR_ROWS_LEN                   : 676
BR_BLK_LEN                    : 8028
DEL_LF_ROWS                   : 13514
DEL_LF_ROWS_LEN               : 210904
DISTINCT_KEYS                 : 27028
MOST_REPEATED_KEY             : 1
BTREE_SPACE                   : 479792
USED_SPACE                    : 422754
PCT_USED                      : 89
ROWS_PER_KEY                  : 1
BLKS_GETS_PER_ACCESS          : 3
PRE_ROWS                      : 0
PRE_ROWS_LEN                  : 0
-----------------

PL/SQL procedure successfully completed.

That shows me that DEL_LF_ROWS/LF_ROWS = 1/2 -- that 50% of my index is "empty"
space (i've show somewhat of the WORST case here).  This might be a candidate
for a rebulid.  Using this data, you can see whats up with your index without
access to the dba_ tables.

You do not need access to any dba_ tables to use my show_space:

ops$tkyte@ORA817.US.ORACLE.COM> create user a identified by a;
User created.

ops$tkyte@ORA817.US.ORACLE.COM> grant create session, create procedure, create
table to a;
Grant succeeded.

ops$tkyte@ORA817.US.ORACLE.COM> alter user a default tablespace users quota
unlimited on users;

User altered.

a@ORA817.US.ORACLE.COM> create table t ( x int );

Table created.

a@ORA817.US.ORACLE.COM> set serveroutput on
a@ORA817.US.ORACLE.COM> exec show_space('T');
Free Blocks.............................0
Total Blocks............................64
Total Bytes.............................524288
Unused Blocks...........................63
Unused Bytes............................516096
Last Used Ext FileId....................7
Last Used Ext BlockId...................79369
Last Used Block.........................1

PL/SQL procedure successfully completed.

a@ORA817.US.ORACLE.COM>

To find the size of a single row -- use VSIZE on each of the columns and add
them up.  The size of a table -- show_space or ANALYZE it and look at
user_tables.  Index -- same as a table (but query user_indexes of course)
August 04, 2001 Lisa -- Thanks for the question regarding "Internal operation for dropping columns", version 8.1.7
You Asked
Tom,

When issuing ALTER TABLE DROP COLUMN command, does oracle internally REBUILD the
table?

thanks in advance for the answer.

-Lisa
and we said...
It'll rewrite the table, generating redo/rollback and such (you can use a
checkpoint option on this command to have it "commit" every now and then so you
can restart from whence it "failed" due to a power outage or whatnot.

A drop is a rewrite (not really a rebuild, no rowids will change, space will be
reclaimed on each block)

A set unused is a flag delete....
August 05, 2001 raj -- Thanks for the question regarding "how to enable object type in version 8?", version 8
You Asked
how to enable object type creation in oracle 8?when I try to create
the object type(OOPS) it says that object type is not enable.
and we said...
In version 8.0 you need to have:

o Oracle 8 Enterprise Edition
o The Objects Option (it was an extra cost option with Oracle8)

You either have standard edition or did not license the objects option, you
cannot use it with your installation.

With Oracle8i, it is part of the database (everyone has it)
August 05, 2001 Dale -- Thanks for the question regarding "Create Oracle Accounts Using External Text File", version 8.0.5
You Asked
I'm preparing to create over 50 Oracle UserIDs in our Database, and I'd like to
be able to load them all at once instead of using SQL*Plus or OEM to create each
one individually.

Is there a way ( i.e., tool or script ) to create Oracle Accounts using an
external text input file containing the account id names?  For example, can I
use sqlldr or similar tool to load the IDs from an Input File?

Thanks,
Dale Klepinger
Database Administrator
Ingram Micro, Inc.
E-Mail:  dale.klepinger@ingrammicro.com
Altername E-Mail: klepindk@home.com
and we said...
The easiest way I can think to do this in 8.0 is as follows (not knowing the OS,
on unix I might take a different approach but this works on all OS's):

1) use sqlldr to load the names/passwords into a table
2) run a script like:

set heading off
set feedback off
set linesize 100
set trimspool on
set termout off
spool tmp.sql
select 'create user ' || USERNAME || ' identified by ' || PASSWORD || ';'
 from your_table;
select 'grant connect to ' || username || ';'
  from your_table;
spool off
set termout on
set feedback on
@tmp

Use SQLPlus to write the SQL that you want to run based on the data you just
loaded and then run the sql that is generated.

In Oracle8i and up, I might be tempted to use an autonomous transaction in a
trigger on the table you load into with EXECUTE IMMEDIATE to dynamically create
the user as well.
Review & Followup
Rating: 5
Creating Multiple Oracle Accounts in a Single Operation August 06, 2001
Reviewer: Dale Klepinger from Santa Ana, CA
The method suggested to load many Oracle Accounts at once is very, very useful
and should help a great deal in minimizing the time spent creating the accounts.
 I've been looking in a casual way for a method such as this, but have never
been able to find a satisfactory way to load User Accounts in the past, except
in a tedious, one-by-one way.
I also appreciate VERY MUCH the prompt response to my inquiry, which I submitted
only the day before.  I expected to wait quite awhile for an answer, because I
thought my question was one of a great many waiting in a "queue", and I
basically had to "wait my turn."  Because your Team answered right away, I now
have a method I can use immediately on a list of over 100 UserIDs, which have to
be loaded ASAP.

August 05, 2001 Mohammed -- Thanks for the question regarding "How can i run my daly Scripts at specfic Time", version 8i.0.7
You Asked
hiTom,

I am always spooling some of the company report to LST file.
And I am looking for method for running these SQL statements
Every day at 6:00 in the morning.
Becouse it takes me along time to run.

I hope if you can give me one method for doing this job with an example .
Do you think that thire is a method for doing that .
  Best regards ,
and we said...
I use DBMS_JOB and stored procedures to run recurring jobs in the database.
This is nice because:

- the database does the running, if the database is up, the job runs, if not --
it doesn't

- it is totally platform independent, it works on NT as well as UNIX (and job
execution is highly platform dependent).

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/dbms_job.htm#999107
for more info on that.

Actually, in looking at your request -- you say "I have some sql statements I
want to run".  I think you might be a candidate for SNAPSHOTS also known as
Materialized views.  For example, a simple:

create materialized view my_data
build immediate
refresh complete next trunc(sysdate)+1+6/24
AS
<your query goes here>

then a simple "select * from my_data" at anytime will return the results of your
query.  Every morning at 6am, this materialized view will refresh itself.


Subject | Article | Last Updated (East coast time)
Indexes with DMLs | article only | Aug 06, 2001 10:42 am
index_desc hint and index_asc hint | article only | Aug 06, 2001 12:38 pm
Conceptual | article only | Aug 06, 2001 12:49 pm
Assign value to shell variable | article only | Aug 06, 2001 01:20 pm
several question regarding oracle 8i | article only | Aug 08, 2001 06:55 pm
disconnected from a sql session | article only | Aug 08, 2001 07:13 pm
Function-based index | article only | Aug 09, 2001 09:00 am
Explain Plan, Directory Service and V$table | article only | Aug 09, 2001 09:06 am
transaction status after raise_application_error | article only | Aug 09, 2001 09:26 am
Questions | article only | Aug 09, 2001 10:00 am
which is fast pro* c or pl/sql and why | article only | Aug 09, 2001 10:11 am
switching to CBO | article only | Aug 09, 2001 10:53 am
How does oracle decide whether a data block is in buffer cache or on the disk | article only | Aug 09, 2001 11:33 am
How can I know how many rows a block contains | article only | Aug 09, 2001 02:51 pm
block dba | article only | Aug 09, 2001 03:29 pm
query and current follow up | article only | Aug 09, 2001 03:35 pm
2pc | article only | Aug 09, 2001 04:36 pm
Oracle Questions | article only | Aug 09, 2001 04:37 pm
Quoted Strings inside of Oracle Spatial function calls | article only | Aug 09, 2001 04:51 pm
<> and !=, yyyy and rrrr | article only | Aug 09, 2001 08:24 pm
stored procedures execution monitoring | article only | Aug 10, 2001 08:58 am
dba hashed value-dba-data block-rowid-rows in the block | article only | Aug 10, 2001 09:16 pm
row(s) 1 - 22 of 22
August 06, 2001 Omar -- Thanks for the question regarding "Indexes with DMLs", version 8.1.5
You Asked
Hi Tom,
It is known that not to build indexes on tables that have heavy DML operations,
but what we do with primary and unique keys (which as you know build unique
indexes)

thanks in advance
and we said...
I would say it is not known that you do not build indexes on tables that have
heavy DML operations.  Like every "rule of thumb" it is misleading (and pretty
much 'wrong' when stated as simply as above).

Let's say you have a one_billion_row_table.  You issue frequently:

  delete from one_billion_row_table where x = 5;
  update one_billion_row_table set y = y+1 where x = 2;

Assume X is fairly discriminating (a given value of x selects about 100 or so
rows).  If you do not index X on that table -- you have failed to correctly
implement your application.  Your deletes and updates will take forever.

The rule of thumb on indexing a heavily modified table should be something more
like:

"Use care in adding indexes to a heavily modified table.  Every index will add
to the amount of time it takes to modify a given row since that structure must
be maintained.  However, this additional time must be viewed in light of the
amount of time the index SAVES in performing other operations and how useful
this index is overall.  For example -- a primary key index, well you gotta have
it, no if and or buts about it -- IF you want that column to be unique.  That
index will be there.  A frequently searched on column in a large table -- again,
GOTTA have it (else the performance of queries will be very poor).

When indexing a heavily modified table -- you must ensure that indexes you add
ADD VALUE.  If they do not -- they will affect your performance negatively with
no pay back.  If they add value -- you need them and there is nothing you can do
(other then change the way you use this table)."

In short -- add the indexes you need to, validate the existing indexes are
necessary, but do NOT hesitate to index that table.

followup to comment 1 below

Then consider an IOT in which case you have an INDEX and the table is not
necessary.

Or consider that the overhead of an index on a tiny table (must not insert into
it very often) will not be noticable.....
Review & Followup
Rating: 2
Unique without indexes August 06, 2001
Reviewer: A reader from Singapore
What if the table contains only a few rows where index does not make sense, but
uniqueness has to be maintained?

Rating: 3
Tuning Consideration August 07, 2001
Reviewer: A reader from India
Hi Tom,

You said that the overhead of an index will not be noticeable on tiny tables.
But, what happens if a number of tiny tables (does not insert into) that has to
be read from disk.  It will be multiple I/Os instead of one (consider the I/O to
read the Index).

August 06, 2001 play -- Thanks for the question regarding "index_desc hint and index_asc hint", version 8.1.7
You Asked
tom

It is interesting that a hint index_desc is provided, doesnt oracle sort the
index in an desc order naturally. Then what is the purpose of providing a hint
like index_desc.

can you please discuss index_desc and index_asc.

lastly, whenever we have a distinct in a query , isnt it true that a full table
scan is done for sure

for example

select distinct ename,deptno from emp;

this query will definitely do a full table scan of emp table.

is there a scenario where you do a distinct select from 1 , 2 or 3 tables, but
there is no full table scan.
and we said...
Hints are typically used in a Rule based (RBO) environment to make a query
behave a certain way.

the cost based optimizer (CBO) will use an index in a desc/asc fashion as it
sees fit.  The RBO isn't as smart and must be told to do certain things.
Additionally, you can use this hint with the CBO to suggest it uses an index in
a certain fashion when it decided NOT to use an index.

No, that query will not definitely full scan the table.  It might full scan an
index on ename,deptno.

ops$tkyte@ORA8I.WORLD> create table emp as select * from scott.emp;
Table created.

ops$tkyte@ORA8I.WORLD> create bitmap index emp_idx on emp(ename,deptno);
Index created.

  1* select /*+ index(emp emp_idx) */ distinct ename, deptno from emp
ops$tkyte@ORA8I.WORLD> /

ENAME          DEPTNO
---------- ----------
ADAMS              20
ALLEN              30
BLAKE              30
CLARK              10
FORD               20
JAMES              30
JONES              20
KING               10
MARTIN             30
SCOTT              20
SMITH              20
TURNER             30
WARD               30
miller             10

14 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=FIRST_ROWS (Cost=31 Card=82 Bytes=1640)
   1    0   SORT (UNIQUE NOSORT) (Cost=31 Card=82 Bytes=1640)
   2    1     BITMAP INDEX (FULL SCAN) OF 'EMP_IDX'

Also, if you add a where clause to the query, we might use an index on the
"where'ed"  columns to access the table
August 06, 2001 Sandy -- Thanks for the question regarding "Conceptual", version 8.1.5
You Asked
Hello Tom,

I want to know,
Question: What is the biggest possible size of Oracle database? What is the
biggest size of Oracle database can be transfer from one machine to another
machine and how?
Question: How to validate the database backup?
Question: Whet is Cartradige Utility? Where to get mroe information about that?
Question: What exactly "alter system switch logfile" do?
Question: Is there any way by which directly (Withoud shuting down) I can change
database stataus from open to mount.

Regards,
Sandy
and we said...
The largest theoretical size is 512 petabytes.
There is no limit to the size that can be transfered.

Restore it is the best way.  Its the only way you know you know how to do it.

I'm not familar with a "Cartradige Utility".  There are various "cartridges" you
might be talking about instead?  see
http://technet.oracle.com/doc/oracle8i_816/inter.816/index.htm
The alter system switch logfile causes us to switch from the current logfile to
the next.  It advances the log file.

Alter database close;
Review & Followup
Rating: 4
Good One August 07, 2001
Reviewer: Sanjeev from California

August 06, 2001 -- Thanks for the question regarding "Assign value to shell variable", version 8i
You Asked
Hi,
 I want to get the value of the parameter 'log_archive_dest' from the
v$parameter view and assign it to a variable in my shell script.

 How can I do it?

Thnks.
and we said...
This shows howto in the csh (you'll need to modify for your preferred shell of
course).  The concepts are the same regardless of the sh you choose:

--------------------------------------------------------------
#!/bin/csh

set x = `sqlplus /<<EOF | grep '^KEEP' | sed 's/^KEEP//' \
select 'KEEP' || value from v\$parameter where name = 'log_archive_dest'; \
exit \
EOF`

echo the value is $x
---------------------------------------------------------------

You might find:

grep '^log_archive_dest' $ORACLE_HOME/dbs/init$ORACLE_SID.ora |
 sed's/.*=//;s/^ *//'

(on one line) to be easier tho
August 08, 2001 sridhar -- Thanks for the question regarding "several question regarding oracle 8i", version 8.1.7
You Asked
hi ,
  i have several questions
1) I need to know,how to get the current Transaction level.
2) Is there a way to get the list of
        system,string,numeric,timedate
        functions list and SQL KEYWORDS list by querying the database?
3) what is the maximum number of tables in a select statement?.
4) Are batch updates executed in a loop ?.
5) Does oracle support updatable concurrency for
     TYPE_FORWARD_ONLY,TYPE_SCROLL_INSENSITIVE<TYPE_SCROLL_SENSITIVE
resultsets?.

Thanks in advance.
bye sridhar
and we said...
1) there is no such concept in Oracle as a transaction level.  You are either IN
a transaction or not.  It it not necessary.

To see if you are IN a transaction you can query:

select count(*)
  from v$session
 where sid = ( select sid from v$mystat where rownum=1 )
   and taddr is not null;

if you get 0, you are not in an active transaction, count = 1, you are.

2) the view v$reserved_words gives you that.

3) as many as you like, there is no limit.  I have personally tested upto 350 at
one time (far far away from 16)

4) i do not understand?  Sounds like a Sybase construct -- we are very very
different from Sybase/SQLServer in regards to transactions

5) in the lastest JDBC drivers (1.2 jdk) -- yes.  See
http://technet.oracle.com/doc/oracle8i_816/java.816/a81354/resltse2.htm#1018065
for the details.
Review & Followup
Rating: 4
several question regarding oracle 8i August 10, 2001
Reviewer: Sridhar Kondoji from NH USA
Hi,
  The response was very usefull and thanks for verifying my doubts.

I actually meant Transaction Isolation level.
So how can i get the information about Transaction isolation level.
I know how to set these levels,but i nned to know what Isolation level the user
is in.?

Thanks sri

August 08, 2001 Branka -- Thanks for the question regarding "disconnected from a sql session ", version 8.1.7
You Asked
Where can I find the reason why I am disconnected from a sql session during
either of the following events:
-execution of a large procedure (more than an hour in duration)
      -inactive sql window (about half an hour)

I received ORA-03113 end-of-file on communication channel when the window is
inactive and then I try to run something.  When I am running the procedure no
error occurs, the session is just dropped.

The server is Oracle 8.1.7. The client is Oracle 8.1.6. We are using MTS server,
but I am connecting with DEDICATED on the client side. Can the problem be on the
server, network, or firewall? Or something else?
and we said...
many firewalls have a "timeout" feature whereby if they see no network activity
for a long time, they close the connection.

You are most likely hitting this.

To execute a procedure that will take a long time like that, I can recommend you
use DBMS_JOB to submit it in the background.  You would make calls in your code
to the dbms_application_info package (see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/dbms_app.htm#999107
for details) so the session that submitted the job can see how far along the job
is.
August 09, 2001 Arvind -- Thanks for the question regarding "Function-based index", version 8.1.7.0.0
You Asked
Hi Tom,
I am having problwm with using function-based index.
I had created index as:
CREATE INDEX IND1 ON  TTL_DATABASE_SUBSETS(UPPER(DBSB_DISPLAY_NAME));

Then If I am trying my query as:
SELECT *
FROM   TTL_DATABASE_SUBSETS DBSB
WHERE  UPPER(DBSB.DBSB_DISPLAY_NAME) LIKE '%'||UPPER('test')||'%';

Then it is not using INDEX at all.

Explain plan is like this:
TABLE ACCESS(FULL) OF TTL_DATABASE_SUBSETS.

Can you suggest me something that could use index.

Thanks in advance.

Regards
Arvind Kapil.
and we said...
You are starting the like with a  '%'.

It would have to scan the ENTIRE index in order to make use of it.  That would
not be the correct thing to do.  Think about it, like '%TEST%' must read each
and every index entry.

You can "trick it".

select * from ttl_database_subsets dbsb
where upper(dbsb_display_name) like :x;

Using a bind variable, it won't know that the search string always begins with a
'%' and *might* (depends on the distribution of data) use the index.

you want to use bind variables in ANY case for performance and scalability.

followup to comment one

visit
http://osi.oracle.com/~tkyte/article1/index.html
make sure you meet all of the criteria ( CBO, enable query rewrite, etc )....

followup to comment two

Here is an example, we'll create a table with some data (about 22k rows in my
case)

ops$tkyte@ORA8I.WORLD> create table t unrecoverable
  2  as
  3  select * from all_objects;

Table created.

ops$tkyte@ORA8I.WORLD> create index t_idx on t(object_name);
Index created.

now, we'll use a query with and without a bind variable -- the query plans
will be different even though the answers are the same

ops$tkyte@ORA8I.WORLD> set autotrace traceonly

ops$tkyte@ORA8I.WORLD> select * from t where object_name like '%x%';
3431 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (FULL) OF 'T'

Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
        644  consistent gets
        327  physical reads
          0  redo size
     417919  bytes sent via SQL*Net to client
      25738  bytes received via SQL*Net from client
        230  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
       3431  rows processed

ops$tkyte@ORA8I.WORLD> variable str varchar2(25)
ops$tkyte@ORA8I.WORLD> exec :str := '%x%'

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> select * from t where object_name like :str;
3431 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T'
   2    1     INDEX (RANGE SCAN) OF 'T_IDX' (NON-UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       3804  consistent gets
        313  physical reads
          0  redo size
     458606  bytes sent via SQL*Net to client
      25738  bytes received via SQL*Net from client
        230  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
       3431  rows processed

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> set autotrace off

followup to comment five below

The result does not show better:

The before,
Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
        644  consistent gets
        327  physical reads

And the after

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       3804  consistent gets
        313  physical reads

Its the count of the logical IOs i'm seriously interested in here -- 644 (full
table scan) versus 3,804.  Reading the entire table via the index = slow.

followup to comment six

the bigger the table, the worse off you will be reading it via an INDEX.

Say you have a table that has 10,000,000 rows in it and has 10 rows / block on
average.

Reading that table via an index will take at least 10,000,000 plus
consistent gets (read the index, read a block to get that row, read the index,
read another block to get that row -- every row will be a consistent get).

Reading that able via a full scan will take only 1,000,000 consistent gets
AND the IO will be done using multiblock reads (reading 8, 16, 32 or more blocks
in a single IO) whereas doing it via an index will do single block IO.

Going further, it could be that reading that table via an index will take
10,000,000 PHYSICAL IOs -- reading it via a full scan will take 1,000,000 at
most.

You do not want to use an index to access a table for tons of rows.  I have a
large section with lots of examples in my book on this very topic.
Review & Followup
Rating: 4
Still facing problem but got solution a little June 15, 2001
Reviewer: Arvind Sharma from USA
My link is this,where I asked question from you.
http://asktom.oracle.com/pls/ask/f?p=4950:9:::NO::F4950_P9_ORIG,F4950_P9_DISPLAYID:Y,810176041414
I am still facing problem as :
select * from ttl_database_subsets
where upper(dbsb_display_name)='x';
My this query is also not using Index even though Index is there, as:
CREATE INDEX IND1 ON  TTL_DATABASE_SUBSETS(UPPER(DBSB_DISPLAY_NAME));
Please help me out of this.
Thanks.

Rating: 4
June 16, 2001
Reviewer: Trinh from Atlana
"Using a bind variable, it won't know that the search string always begins with
a
    '%' and *might* (depends on the distribution of data) use the index."

I am very interested in. Very appreciatly if you can illustrate an example.

Rating: 5
June 16, 2001
Reviewer: trinh from atlanta

Rating: 5
Working fine June 18, 2001
Reviewer: Arvind Kapil from USA
My problem is solved.
Thanx for your help Tom.

Rating: 3
It does not look like better than the FTS for binding %x%? August 08, 2001
Reviewer: DJAS from INDEY, US
The result does not show better:

The before,
Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
        644  consistent gets
        327  physical reads
          0  redo size
     417919  bytes sent via SQL*Net to client
      25738  bytes received via SQL*Net from client
        230  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
       3431  rows processed

And the after

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       3804  consistent gets
        313  physical reads
          0  redo size
     458606  bytes sent via SQL*Net to client
      25738  bytes received via SQL*Net from client
        230  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
       3431  rows processed

Could you please give another example for binding %X%?

Rating: 3
read entire table via index =slow? August 08, 2001
Reviewer: Sean from Atlanta, USA
If it were a hugh table, 10,000,000 rows, which one would be better?

August 09, 2001 -- Thanks for the question regarding "Explain Plan, Directory Service and V$table", version 8.1.7
You Asked
1.  SELECT sid, wait_time, event FROM V$SESSION_WAIT;

If the above query returns 0 for SQL*Net message from client and if the total
count is more than 30 plus, what should be done, do we need to go for MTS
or is there any way the wait time for the SQL*Net event can be reduced /
minimized ?

2.  What is directory Service and what are the benefits of that ?

3.  Specified below is the Explain Plan statistics which I grabbed.

Statistics
----------------------------------------------------------
         19  recursive calls
        489  db block gets
        832  consistent gets
        650  physical reads
        692  redo size
       1226  bytes sent via SQL*Net to client
        248  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
         10  sorts (memory)
          0  sorts (disk)
          0  rows processed

Can you explain what does each heading means and which is optimal ?

4.  Say if I use != in sql query it might be a bottleneck for performance, what
can be the best alternative for != operator.
and we said...
1) the sql*net message from client is a "busy wait" wait event.  Just go into
sqlplus, let it sit there and in another session watch that other sessions wait
on this event go up.  Ignore that one.  It just shows how long the server was
waiting for the client to tell them to do something.

2) a directory service is a database that tells you where things are.  DNS is an
example of a type of directory service.  As things get bigger, as you have more
things to track (like users for example) you need a directory service to
consolidate all of this data.  OID (Oracle Internet Directory) is an LDAP server
built on top of Oracle that provides this functionality.

3) thats not an explain plan stats -- that is statistics about the execution of
a DML statement.

It did 19 recursive calls.  recursive SQL is sql that is executed on your behalf
to execute your SQL.  It could be caused by dynamic space managment (need to get
another extent).  It could be caused by parsing the query (needed to read the
data dictionary).  there are many causes for recursive sql.

It did 489 db block gets. "db block gets" counts logical reads in current mode.
Also includes direct read blocks (sort-on-disk) blocks. Current mode means you
might have had to wait for those blocks (you can get blocked reading current
mode blocks).  If this was a query, that was probably a read on the data
dictionary as part of the parsing of the query.

It did 832 consistent gets.  These are logical i/os of blocks in "consistent"
mode -- read consistent mode.  These reads will not block, we'll reconstruct the
block from the rollback segments if we must.

If did 650 physical I/Os to answer your question.

It generated 692 bytes of redo information that LGWR will have to write out.

It sent 1,226 bytes to the client (the result of your query).

You sent it 248 bytes (your question)

One trip back and forth to execute the statement.

10 sorts were performed for you during the execution of this statment and they
all fit into your sort_area_size.

It affected no rows.

4) well, if you need everything that is NOT EQUAL to something, what else can
you do? If you know the positive set of things to get -- that would be the
alternative.

followup to comment one

Well, perhaps I was misleading above -- you don't ALWAYS want to ignore that,
you usually do. Suppose you have a batch program that connects to Oracle and is
supposed to be constantly doing something in the database -- say its a LOAD
program (read records, "fix them up" and insert them sort of program).  If you
observe LOTS of waits in "SQL*Net message from client" that indicates your batch
program is taking lots of time to do its processing (you would expect the batch
program to be busy in the database constantly, a high SQL*Net message from
client indicates that it is not).

In your case however, it is normal for high SQL*Net message from client.  In
your connection pool setup (not knowing what connection pooling software you
might be using), you need to configure the MIN and MAX connections it will pool.
 Its like setting min and max MTS servers for Oracles Multi-threaded server.  If
we set min servers to 5 and max servers to 1,000 you would expect to see
anywhere between 5 and 1,000 shared servers in the database.  With your
connection pool -- you have to tell it how many MAX connections (requests for a
connection ABOVE the max connections will be queued and will recieve their
connection object as another becomes free).  Apparently someone has configured
this very high -- you just need to find out where/how to configure this with
your software.
Review & Followup
Rating: 2
always ignore SQL*Net message from client ? August 08, 2001
Reviewer: Dean Reynolds from Nashville
I have a Java app with conneciton pooling (hah!).

On every other machine, it works fine.

On our production servers, the connections won't hang up.

Instead of peaking out at about 300 connections, I currently have 814 siitng on
this wait event.

The nature of the app is that Java connects just to run a transaction, then
closes the connection (returns it to the pool).

All of these connections show the 3 basic cursors:

ALTER SESSION SET nls_language = 'AMERICAN'
ALTER SESSION SET nls_date_format = 'MM-DD-YYYY HH24:MI:SS'
SELECT VALUE FROM nls_instance_parameters WHERE parameter = 'NLS_DATE_FORMAT'

Obviously something is going wrong.  I expect it's the middle-tier, but doesn't
the SQL*Net message from client events confirm that the app is not waiting on
Oracle, but that Oracle is saying "Okay, you got connected, now what do you want
to do?"

I'm thinking this tells me SOMETHING, doesn't it?

Thanks, love the book.

Rating: 5
Very useful August 09, 2001
Reviewer: C Clearly from NJ USA
<b>Nice Tom very good explaination for<BR>
the DML Statistics.
</b>

August 09, 2001 Mahesh -- Thanks for the question regarding "transaction status after raise_application_error", version 8.1.7
You Asked
Hi Tom,

My question is on the behaviour of the pl/sql procedure
raise_application_error.

I have a stored procedure which does a few dml operations
and then there is an exception. In the handler i call
raise_application_error with a custom message for the
calling application. Before this do i have to explicitly
rollback
to reverse the effect of statements before the one that
caused the exception, or raise_application_error implicitly
issues a rollback?

thanks,

mahesh
and we said...
It will depend (i have a large section on this in my book with
all of the details and examples if you are interested).

If the CALLING application is "outside" of the database -- it
will rollback the work performed by the stored procedure.

If the CALLING applicatio is "inside" of the database (another
stored procedure) -- we are still logically in the same statment
and the work would have to be rolled back yourself (in the
procedure).

If you let the error propagate OUT of the database, the
statement (stored procedure) you submitted to the datbase is
"undone".

If you catch the error in the database and handle it there, the
statment is considered to have "succeeded".

Consider this:

ops$tkyte@ORA8I.WORLD> create table t ( x int );
Table created.

ops$tkyte@ORA8I.WORLD> create or replace procedure p( data in
int )
  2  as
  3  begin
  4      insert into t values ( data );
  5      raise_application_error( -20001, 'error' );
  6  end;
  7  /
Procedure created.

REM pretend to be a client OUTSIDE the database:

ops$tkyte@ORA8I.WORLD> exec p(1)
BEGIN p(1); END;

*
ERROR at line 1:
ORA-20001: error
ORA-06512: at "OPS$TKYTE.P", line 5
ORA-06512: at line 1

REM the "statement" p was rolled back:

ops$tkyte@ORA8I.WORLD> select * from t;

no rows selected

REM Now be a client INSIDE THE database and catch/handle the
error:

ops$tkyte@ORA8I.WORLD> begin
  2     p(2);
  3  exception
  4      when others then
  5          dbms_output.put_line( 'caught and handled an error'
);
  6  end;
  7  /
caught and handled an error

PL/SQL procedure successfully completed.

REM the "statement" succeeded this time, outstanding work
persists (not committed
REM but not rolled back EITHER)

ops$tkyte@ORA8I.WORLD> select * from t;

         X
----------
         2

REM Now be a client inside the database that wants errors to be
handled
REM like they were OUTSIDE the database:

ops$tkyte@ORA8I.WORLD> begin
  2      savepoint before_p;
  3      p(3);
  4  exception
  5      when others then
  6          rollback to before_p;
  7          dbms_output.put_line( 'caught and handled an error'
);
  8  end;
  9  /
caught and handled an error

PL/SQL procedure successfully completed.

REM notice that the other row was not added, we rolled it back
(but rolled back ONLY
REM the work done by p this time -- not the PRIOR outstanding
work we still have)

ops$tkyte@ORA8I.WORLD> select * from t;

         X
----------
         2
August 09, 2001 Bhaskara -- Thanks for the question regarding "Questions", version 8.1.5
You Asked
Hi Tom,

    I have few questions. Please provide answers for them.
Thank you very much in advance.

1. What are the various reasons for Table mutatiting error? How
to avoid it?

2. How to check filesystem fragmentation?

3. What is the purpose of gathering statistics of tables/indexes
into user tables instead of dictionary tables?

4. What are the main reasons for Index unbalancing? How to
prevent it?

5. What are the responsibilities of Oracle Apps DBA?

6. On what basis we have to go for multiple databases for same
project?

7. What are the factors to be considered while migrating oracle
database from NT to Unix plarform or vice-versa?

Thanks,
Bhaskara
and we said...
1)
http://osi.oracle.com/~tkyte/Mutate/index.html
2)
consult your operating system manuals.  It varies obviously by
operating system.

3)
so you can move them to another database, or you can have many
different point in time copies of stats to see what sorts of
plans the optimizer will generate (eg: load your table...
analyze estime 10%, 20%, 30%, 40%, 100% into 5 different user
tables.  Now one by one move the user stats into the dictionary
stats table and run your application.  You can now determine
which of the % settings you need to use to get the best bang for
the buck)

4) I'm going to recommend a book for you on this.  Jonathan
Lewis wrote "Practical Oracle8i", he covers alot of this stuff
and the book is so good you'll read it at least twice.  It
covers it much better then I can in this limited space.

5)
They would be the same as any DBA for any database would be.
Depending on how your company parcels out work -- you might be
doing the backup, recovery, patch installation, software
updates, tuning and so on.

Its just like being a DBA on any other database with some 3rd
party software running on it.

6) My opinion is you would want to use as few databases as
possible.  In many cases, an off the shelf application (eg:
Oracle apps) should have a dedicated instance but for all
developed applications you build in house -- the fewer databases
the better.

7) the volume of data -- you have to export/import or dump to a
flat file and reload or use sqlplus copy or create table as
select over a dblink to move the data.
August 09, 2001 nag -- Thanks for the question regarding "which is fast pro* c or pl/sql and why", version 8.1.7
You Asked
Tom

Can you give an example carried out in pro* c and  the same done
in pl/sql, and show us which is faster and why.

I guess pro*c also does array inserts which in pl/sql we call
bulk binds. Which of them is faster.

thank y
and we said...
I can show you code that will be faster in Pro*C then in PLSQL.

I can show the SAME EXACT code where PLSQL will be faster then
Pro*C.

You have to consider where in the world the processing takes
place.  Lets say you have a very fast network and a super fast
client.  Pro*C can easily pull the data out of the database,
over the network, work on it quickly and put it back into the
database.  It might be plsql here simply because it has a fast
network and a very fast machine to work on.

Now lets say the pro*c client is on a busy network and the
client machine its running on is very utilized (busy).  Now,
PLSQL in the database -- since it doesn't have the network
overhead and perhaps the database is not as utilized -- beats
the pants off of pro*c (or more specifically C).

The answer (as always) is -- it depends.  There is no cut and
dry answer for this.

I personally prefer to put all data processing stuff in the
database.  In that fashion, I can do the processing from Pro*C,
Java, Vb, SQLPlus -- whatever I want.  If I find a bug in the
processing, I can fix the stored procedure right there and I
don't have to track done all of the code that might have
duplicated this processing (and fix all of the copies).  If I
want to tune it, I just get the stored procedure out of the
database -- tune it and put it back in.

So, neither is blanket "faster" then the other.  There are many
reasons to put the logic in the database and as long as it goes
fast enough -- thats my approach.
August 09, 2001 nag -- Thanks for the question regarding "switching to CBO", version 8.1.7
You Asked
Tom

We are planning to switch to CBO from RBO, by doing a analyze
statistics on all the objects in our database.

can you tell me , what will be the impact on the current
queries, what are the areas where there can be adverse impact,
and is there any home work which we need to do on our queries
before we switch to
CBO.

What are all the objects on which analyze command can be run.
and we said...
You should do this in a test environment first of course. There
will be changes in plans -- some for the better, some not.
You'll need to identify the poor performers and determine why
(can you fix it by adjusting the optimizer_index_cost_adj
init.ora parameter, a simple rewrite or hint or what).

You'll want to understand the access paths and options open to
you -- see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/toc.htm
before you start.

You can analyze your tables and indexes, dbms_stats is probably
the way to go (instead of analyze directly) as it can do things
analyze cannot (eg: parallel analyze for example).

followup to comment one

Jonathan Lewis has a great book "Practical Oracle8i" that has
the best discussion on this I've seen, I highly recommend it:
http://www.amazon.com/exec/obidos/ASIN/0201715848/
You'll read that book at least two times.

You can also read about it here:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76961/ch1122.htm#41039
and in the designing and tuning for performance guide:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/toc.htm
Please see:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76936/dbms_sta.htm#999107
for more info on dbms_stats and its abilities.

As for the difference between an "analyze" and a "parallel
analyze" -- its the difference between a serial operation and an
operation done in parallel.  Suppose you have a 10gig table.  If
you use ANALYZE, it'll serially process 10gig of data.  If you
use a parallel analyze via dbms_stats, you can have 10 processes
munching through 1gig of data each.
Review & Followup
Rating: 3
August 09, 2001
Reviewer: A reader from USA
Can you tell more about  optimizer_index_cost_adj  parameter,
and what are the advantages of using dbms_stats in place of analyze, what is the
difference between analyze and parallel analyze.

Rating: 4
Can you list the new 8i features only working under CBO? August 09, 2001
Reviewer: John from New Yrok

August 09, 2001 play -- Thanks for the question regarding "How does oracle decide whether a data block is in buffer cache or on the disk", version 8.1.7
You Asked
Tom

I give a query

select * from emp;

all the data blocks belong to the emp table are read into the buffer cache.

Now once again I give a select like select ename from emp where empno=1010, this
time the blocks are not fetched from the disk , but from the disk but from the
buffer cache.

How did oracle decide or know that the block is in the buffer cache and not on
the disk.

Secondly,
i.I heard a vague statement from my lead , 'that everything in oracle database
is read through the rollback segment except a select', what does that mean.

ii.At what stage are records copied to rollback when doing a delete or update.
when data is committed , what happens to the data blocks in the rollback which
contained the said data, or are they wiped out, and wait for other update and
delete statements.

iii.A user has given an update statement against a table and has not committed,
now we have the data in the data blocks of that respective table i.e. segment,
and also in the rollback data blocks. Now another user comes in and issues a
select against the same table, where is the data read from, from the data blocks
of the table segment or the data blocks of the rollback segment.

thridly

what is the reason for

SQL> INSERT INTO t SELECT * FROM t1;
ERROR at line 1:
ORA-01631: max # extents (505) reached in table PLAY.T

and how should this be fixed, especially what is the syntax to fix it.
and we said...
for the IO question, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:557622939598
i) thats seems backwards.  A select will USE a rollback segment IF and WHEN
needed to reconstruct a block as it appeared when the query begin (this is
multi-versioning and read consistency).  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c23cnsis.htm#17882
it is NOT true that everything is read though the rollback segments.  It is true
that we use rollback segments to read through locks (maybe thats what he said)

ii) upon doing the insert/update/delete -- right then and there rollback is
generated.

Rollback is used in a circular fashion -- the rollback you just generated will
be overwritten when the rollback segment gets to the "end", wraps back to the
beginning and eventually gets to where your rollback entires where.

iii) see i) -- read that referenced link.

As for the max extents, you can:

ops$tkyte@ORA817.US.ORACLE.COM> alter table t storage ( maxextents 1000 );
Table altered.

to let you have 495 more extents or

ops$tkyte@ORA817.US.ORACLE.COM> alter table t storage ( maxextents unlimited );
Table altered.

to let you have lots more extents or

ops$tkyte@ORA817.US.ORACLE.COM> alter table t storage ( next 5m );
Table altered.

you can increase the size of NEXT so that the 505 extents you allocate represent
a larger amount of space.
August 09, 2001 play -- Thanks for the question regarding "How can I know how many rows a block contains", version 8.1.7
You Asked
Tom

An interesting question

a.How can I know how many rows does a data block contain, and how do I determine
the ideal size for a particular database. what are the parameters taken into
consideration.

b.How can I know how many data blocks a segment , and an index contain.

c.How can I know into how many blocks a particular row has chained.

i.e. i want to get a list of blocks into which a particualr row has chained or
migrated, how can I do it.

d.How can I know how many rows have chained or migrated in a particular segment.

e.can a row chain into multiple blocks spread across multiple tablespaces

f.how can I know how many rows have chained , and how many rows have migrated.

can chaining occur with rollback data blocks?
and we said...
a) you cannot really.  You can find the AVERAGE by using analyze -- but unless
you actually dump the block in ascii to a trace file and edit the trace file,
you do not know how many rows are in a block.

In the very special case where you have a table with NO chained/migrated rows --
you can use:

ops$tkyte@ORA817.US.ORACLE.COM> select dbms_rowid.ROWID_BLOCK_NUMBER( rowid ),
count(*)
  2    from t
  3   group by dbms_rowid.ROWID_BLOCK_NUMBER( rowid )
  4  /

DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)   COUNT(*)
------------------------------------ ----------
                                8586        662
                                8587        662
....

b) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
c)

You can measure how many table fetch continued rows it takes to retrieve the
entire row.  For example:

ops$tkyte@ORA817.US.ORACLE.COM> create table t ( x int,
  2                                   a varchar2(4000),
  3                                   b varchar2(4000),
  4                                   c varchar2(4000),
  5                                   d varchar2(4000),
  6                                   e varchar2(4000) );

Table created.

ops$tkyte@ORA817.US.ORACLE.COM> create or replace procedure how_many_blocks
  2  as
  3          l_before number;
  4          l_total  number;
  5  begin
  6     select b.value into l_before
  7       from v$statname a, v$mystat b
  8      where a.statistic# = b.statistic#
  9        and a.name = 'table fetch continued row';
 10
 11     for x in ( select * from t )
 12     loop
 13          null;
 14     end loop;
 15
 16     select b.value-l_before into l_total
 17       from v$statname a, v$mystat b
 18      where a.statistic# = b.statistic#
 19        and a.name = 'table fetch continued row';
 20
 21     dbms_output.put_line( 'Row is now on ' || (l_total + 1) || ' blocks' );
 22  end;
 23  /
Procedure created.

ops$tkyte@ORA817.US.ORACLE.COM> insert into t (x) values (1);
1 row created.

ops$tkyte@ORA817.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817.US.ORACLE.COM> exec how_many_blocks
Row is now on 1 blocks
PL/SQL procedure successfully completed.

ops$tkyte@ORA817.US.ORACLE.COM> update t set a = rpad( '*', 4000, '*' );
1 row updated.

ops$tkyte@ORA817.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817.US.ORACLE.COM> exec how_many_blocks
Row is now on 1 blocks
PL/SQL procedure successfully completed.

ops$tkyte@ORA817.US.ORACLE.COM> update t set b = rpad( '*', 4000, '*' );
1 row updated.

ops$tkyte@ORA817.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817.US.ORACLE.COM> exec how_many_blocks
Row is now on 2 blocks

This shows that when the row exceeded 8000 bytes (i have an 8k block size), it
starting chaining...

PL/SQL procedure successfully completed.

ops$tkyte@ORA817.US.ORACLE.COM> update t set c = rpad( '*', 4000, '*' );
1 row updated.

ops$tkyte@ORA817.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817.US.ORACLE.COM> exec how_many_blocks
Row is now on 3 blocks

PL/SQL procedure successfully completed.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> update t set d = rpad( '*', 4000, '*' );

1 row updated.

ops$tkyte@ORA817.US.ORACLE.COM> commit;

Commit complete.

ops$tkyte@ORA817.US.ORACLE.COM> exec how_many_blocks
Row is now on 4 blocks

PL/SQL procedure successfully completed.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> update t set e = rpad( '*', 4000, '*' );

1 row updated.

ops$tkyte@ORA817.US.ORACLE.COM> commit;

Commit complete.

ops$tkyte@ORA817.US.ORACLE.COM> exec how_many_blocks
Row is now on 5 blocks

PL/SQL procedure successfully completed.

d) analyze table list chained rows....

e) no, it'll be in A tablespace.  a segment is always in A tablespace

f) there is no real difference between the two -- they are both chained rows,
just for different reasons.

You can tell if a row is migrated IF the sum of the vsizes of the columns
indicate it could fit on a block.  A row is chained otherwise.

lastly -- that doesn't make sense since rollback is rollback -- its not rows and
columns in a table and chaining only applies to rows and columns of a table.
Review & Followup
Rating: 5
Wonderful answer August 09, 2001
Reviewer: A reader

Rating: 5
Good Questions, Perfect Answers January 06, 2003
Reviewer: Brain.Xu from China
Good Questions, Perfect Answers.

Tom's answer is classical and useful.

August 09, 2001 rd -- Thanks for the question regarding "block dba", version 8.1.5
You Asked
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:557622939598
"
Its a good question.  Each block has a DBA (data block address) associated with
it.  We hash this DBA and store the blocks in lists according to their hashes.
When you want a block -- we hash the dba -- look in that list and see if we can
find it, if not read it and put it into the correct list.
"

Can you show us how a block is hashed internally?

what do you actually mean by hashing the DBA, and where are these list of dba
values stored.

from the above para it seems that you hash the dba's periodically and every time
 a block is needed , Iam I right.

What does a DBA contain, what constitutes a DBA.

      and we said...
I mean hashing, like a hash function.  For example, suppose I wanted to store
things in one of 5 lists.  I can use a hash function like:

select dbms_utility.get_hash_value( 'This is my DBA', 1, 5 ) from dual;

DBMS_UTILITY.GET_HASH_VALUE('THISISMYDBA',1,5)
----------------------------------------------
                                             5

select dbms_utility.get_hash_value( 'This is another DBA', 1, 5 ) from dual;

DBMS_UTILITY.GET_HASH_VALUE('THISISANOTHERDBA',1,5)
---------------------------------------------------
                                                  2

Here, if I was given DBA "This is my DBA", i would find its value by searching
through list 5.  If given "This is another DBA", I would find it by searching
through list 2.

We use a hash function to break up what normally would be a very very large long
list into many many much shorted lists, to reduce the time it'll take to find
the block.

These list are the buffer cache if you will -- they are stored in the SGA.

A DBA = Data Block Address = File + block offset in file.

followup to comment one

Ok, as I said a DBA is simply a "data block address".  A data block address
consists of the FILE ID for the data block and the block number within that
file.  Given a FILE ID and a BLOCK NUMBER, we have the ADDRESS of a block.  If
you tell me those two bits of information -- I can find that block on disk.

If you want to see the DBA for a given file/block, you can:

select dbms_utility.make_data_block_address( 5, 5532 ) from dual;

DBMS_UTILITY.MAKE_DATA_BLOCK_ADDRESS(5,5532)
--------------------------------------------
                                    20977052

they are usually expressed in hex, so you can also:

  1* select to_char(dbms_utility.make_data_block_address( 5, 5532 ),'xxxxxxxxx')
from dual
tkyte@TKYTE9I.US.ORACLE.COM> /

TO_CHAR(DB
----------
   140159c

So, 140159c is the DBA of the data block found in file 5, block 5532.

As for the question about:

What do you mean by "These lists are the buffer cache if you will -- they are
stored in the SGA. "

the original question states:

"what do you actually mean by hashing the DBA, and where are these list of dba
values stored."

To be more clear my answer is:

we have this thing called a buffer cache.  In there are lots and lots of data
base blocks.  Every database block as an address associated with it (the file it
came from and the block number in that file).  Instead of the buffer cache being
one big long list of database blocks organized by their DBA -- we use many
hundreds/thousands of smaller lists.  To determine where in the buffer cache a
block with a given address would be -- we take the DBA (eg: 140159c) and we hash
it given the number of lists we have (lets say we have 5,000 lists of blocks out
there):

  1* select dbms_utility.get_hash_value('140159c',1,5000) from dual
ops$tkyte@ORA817.US.ORACLE.COM> /

DBMS_UTILITY.GET_HASH_VALUE('140159C',1,5000)
---------------------------------------------
                                         4594

and in this case we would goto list number 4,594 to start looking for the cached
block with the DBA = 140159C.  If that block from file 5, block 5532 is to be
found in the buffer cache -- we will find it in that list.

Hope that is more clear.

Review &
      Followup

      Rating: 3
example for a
      dba  August 09, 2001
Reviewer:  Khan
       from pak
A DBA = Data Block Address = File + block offset in file.
CAN YOU GIVE AN EXAMPLE OF A DBA ,,,
What do you mean by "These list are the buffer cache if you will -- they are
stored in the SGA.
"

August 09, 2001 play -- Thanks for the question regarding "query
      and current follow up", version 8.1.7

      You Asked
http://asktom.oracle.com/pls/ask/f?p=4950:8:48615::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:1116296715674,
"
Here we had no indexes -- just rows.  Well, we did a full scan and that gets
some blocks in CURRENT mode (the extent info and such).  We also deleted 99 rows
-- each of the ROWS we deleted gets its block in CURRENT mode.  If we deleted 5
rows we might have read 1 block in query mode but we'll get 5 blocks (the same
block) in CURRENT MODE.  Each row deleted is a current mode get.  We get the
block in current mode, delete the row, and give it back.

So, the more rows you delete, the more current mode gets you'll do.
"

Your explanation is not very clear to me.

From what I understand. If i read one block in query mode for a delete. For the
delete I would still get only one block in the current mode, as the row is in
that one block. Then how come you say we get 5 blocks.

The only way in my opinion current can be more than query is that more rows have
been added to the table which meet the delete criteria, after the read part of
the delete statement was over.

Please explain in detail.

      and we said...
Here is how a delete is processed logically (assumming no indexes, a full scan)

we are processing "delete from t where x < 100"

  loop over all of the blocks in QUERY mode for the table
      loop over all of the rows in this block
           if this row is such that x < 100
                 Get this block in CURRENT MODE
                 delete the row
                 UN-get the block in CURRENT MODE (give it back)
           end if
      end loop
  end loop

So, we read the blocks in QUERY MODE and start looking at the rows on it.  When
we find a row of interest, we get the block in CURRENT MODE -- do the delete of
that SINGLE row -- and give it back.  If we have 5 rows on the query mode block
to delete - we'll do 5 CURRENT GETS of that block in rapid succession.  We need
to do this to serialize changes to this block in the buffer cache (imagine for a
moment you have 2 sessions -- each wanting to delete a row on this block -- we
MUST serialize the actual in memory rewrite of the block -- there can only be
ONE current version of the block else we'll lose changes)

We do not delete all of the rows on a block -- we delete a ROW at a time, we do
not process blocks, we process rows.  Each row deleted will incurr a CURRENT
MODE get.  In between the time we delete our first row on that block and our
second row on that block -- another session may have also modified that very
same block.

Clearer?

followup to comment one

When we get the block in current mode, we "lock it", we serialize access to it
-- its in the buffer cache.  When we are done with it -- we "unlock it",
allowing other sessions to get it.

We do not increment the count when we "unget" the block -- just on the get.  For
example, if you run this script:

create table t ( x int );

insert into t values ( 1 );
insert into t values ( 2 );
insert into t values ( 3 );
insert into t values ( 4 );
insert into t values ( 5 );

commit;

alter session set sql_trace=true;

select * from t;
delete from t;
commit;

begin
    for i in 1 .. 10 loop
        insert into t values ( i );
    end loop;
end;
/
select * from t t2;
delete from t t2;
commit;

TKPROF will show us:

select * from  t

call     count     cpu    elapsed  disk  query  current   rows
------- ------  ------ ---------- ----- ------ --------  -----
Parse        1    0.00       0.02     0      0        0      0
Execute      1    0.00       0.00     0      0        0      0
Fetch        2    0.00       0.00     0      2        4      5
------- ------  ------ ---------- ----- ------ --------  -----
total        4    0.00       0.02     0      2        4      5
***************************************************************
delete from t

call     count     cpu    elapsed  disk  query current    rows
------- ------  ------ ---------- ----- ------ -------  ------
Parse        1    0.00       0.00     0      0       0       0
Execute      1    0.00       0.00     0      1      11       5
Fetch        0    0.00       0.00     0      0       0       0
------- ------  ------ ---------- ----- ------ -------  ------
total        2    0.00       0.00     0      1      11       5

Now, we can see the full scan (select * from t) does 4 current mode gets to get
the information used in order to scan the table itself.  When we look at the
delete, we can see it used 7 current mode gets (11-4) to process the delete.
Later, when we have 10 rows in there:

delete from t t2

call     count     cpu    elapsed  disk query    current    rows
------- ------  ------ ---------- ----- ----- ----------  ------
Parse        1    0.00       0.00     0     0          0       0
Execute      1    0.00       0.00     0     1         14      10
Fetch        0    0.00       0.00     0     0          0       0
------- ------  ------ ---------- ----- ----- ----------  ------
total        2    0.00       0.00     0     1         14      10

we can see it does 10 (14-4) current mode reads.  In fact, if you continue the
example with 20 rows, 30 rows, 40 rows (as i did myself), you'll find it does
20, 30, 40, .... current mode gets -- ONE each for each row.

We do not write the block to disk after an "unget", that block flushing takes
place later during a checkpoint.

followup to comment three

Sorry, I tried to make that clear with:

Now, we can see the full scan (select * from t) does 4 current mode gets to
get the information used in order to scan the table itself.

In order to full scan a table, we need to know where it is -- right now, right
then, at that point in time.  In order to do that, we do a couple of reads in
current mode (NOT query mode, we don't want to know what the table LOOKED like,
we need to know what it LOOKS like) to find out where the table is.  I did the
"select *" purely to demonstrate that a full tablescan will do these 4 current
mode gets.....

followup to comment four

I cannot account for that directly, I just redid the test and:

delete from t t5

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.00       0.00          0          1          9           5
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.01          0          1          9           5

it does 5 (9-4).  I'll write it off to "noise".  I did the test over and over
and over with these results:

1   row           5 current mode reads (all of these include the 4)
5   rows          9 mostly, sometimes 11
10  rows         14
20  rows         24
50  rows         54 mostly, sometimes 56
100 rows        106 mostly, sometimes 108
200 rows        208 and 210

its not 100% deterministic as far as that goes but its very very close.

followup to comment six

when we full scan, we need to know what the table looks like.  When we access
the table via the index -- we get an rowid which includes the FILE, BLOCK and
row on the block that data is.  We don't need to know the exact size and shape
of the table itself, we need to read the index structure only.  Blocks don't
MOVE -- but the size and shape of a table may very well change.

So, a full scan does some current mode gets (its really the same block gotten 4
times I believe) to get the layout of the table.  An indexed read -- since the
ndex TELLS us what part of the table to read -- does not need to do that.

followup to comment seven

No, it was not the SELECT * I was pointing out there.  SELECT NULL from T,
select x from T, select 103 from T, select 'hello world' from T, select count(*)
from t, anything that FULL SCANS T would exhibit those 4 current mode gets -- I
was showing that the full scan the DELETE would be doing below will have 4
current mode gets as a side effect of the FULL SCAN itself.

followup to comment eight

Thats coming from right field given this thread but the answer is -- you might
be able to peek at x$bh to get an idea but it would probably take you longer to
do that then just to run the query and see what happens.

Review &
      Followup

      Rating: 5
Great answer,
      but one more question  August 09, 2001
Reviewer:
      Khan  from Pak
This is the best explanation I have ever read.

 lets nail it further

can you explain the stage 'UN-get the block in CURRENT MODE (give it back)' .
You get the block , make changes. Is giving back ( whatever it means) also
counted under the CURRENT. If so , in your example, if one block is read once
and fetched 5 times to delete 5 rows then the query reads will be 1   and
current reads will be 10  , 5 to get , and 5 to return, Iam I right.

When you say give it back, do you mean wrtitig it back to the disk.

What is the process of memory rewrite. What does it mean.

      Rating: 5
excellent
      explanation  August 09, 2001
Reviewer:  dave
       from UK

      Rating: 4
Resonse to
      comment one answer  August 09, 2001
Reviewer:
      Khan  from pak
Why does it show current mode gets for a select, dont we get all the blocks in a
read consistent state i.e. query mode when we do selects.

I expect to see a zero for current, when doing selects???

*****----*****

      Rating:
      4
clarification  August 09, 2001
Reviewer:
      Mike  from USA
Why is it doing 7 current mode gets to get 5 rows and delete them. Does this
mean that 5 rows are spread into multiple blocks.

Because, assuming that 5 rows are in the same data block, then there should be
only 5 curents gets of the same block.

It can be seven only when, these 5 rows are spread across multiple blocks. So is
there any row chaining here.

      Rating: 5
I have the same
      question as Mike  August 09, 2001
Reviewer:
      Cheng  from USA
Why is it doing 7 current mode gets to get 5 rows and delete them. Does this
mean that 5 rows are spread into multiple blocks. Because, assuming that 5 rows
are in the same data block, then there should be only 5 curents gets of the same
block. It can be seven only when, these 5 rows are spread across multiple
blocks. So is there any row chaining here.

      Rating: 5
follow up to
      comment 3 ?  August 09, 2001
Reviewer:  George
      Quinoes  from USA
Tom

your follow up to comment 3 is interesting

you say "   In order to full scan a table, we need to know where it is -- right
now, right then, at that point in time.  "

why is it necessary only for a full table scan, why not for other selects.

For example , when you do 'SELECT * FROM EMP WHERE DEPTNO =10", shouldnt I know
where where the blocks are at that point, and not where they existed when the
query started.

      Rating: 5
select * and
      select column name  August 09, 2001
Reviewer:
      Mike  from USA
Tom

Your emphasis "select *"  in response to comment 3 , does it mean that we will
get current gets only when doing a select * , and not when we do select column
names .

In what situations do we get blocks in current mode when doing selects?

      Rating: 5
before
      hand  August 09, 2001
Reviewer:  Cheng
       from USA
Is it possible to know for us before , that if all the blocks or what percentage
of blocks for a partitular table or indes are in the buffer cache

      Rating: 5
full marks ,
      but one question against reply to comment 7  August 09, 2001

Reviewer:  Bibi Za  from USA

Are you saying that if a particular query(select) does not do a full table scan
then, the current gets will be zero.

August 09, 2001 -- Thanks for the question regarding "2pc ",
      version 8.1.6

      You Asked
Tom:

let's say for 2pc.
three site was involved. site1 is the coordinator,
site1 has asked site2 to prepare to commit, and site 2 has done so.
site1 then asked site3 to prepare to commit. and site 3 has done so.
then what's the next?
site one ask site2 and site 3 commit?
if that's the case, what happen if site2 successfully commit but site3 somehow
can't commit because power, network or some other failure?

you give me an example at page 149.
but that one only mention the situation that site1 fail.
we can manually rollback site2 and site3 so everything is ok.

in my case, site2 is commited, site3 can't commit because of power failure,
what should we do then?

      and we said...
You are at the point where a failure can occur, we've made the window as small
as possible.  Here Site1 has gotten the "votes" from site's 2 and 3 and they are
positive.  Now -- Site1's vote is the outcome of its COMMIT.

When it commits it will tell site 2 to commit.  Now say the system fails.  Site3
is left with an in-doubt distributed transaction.  That transaction will be held
open indefinitely until

- the systems are talking again
- the DBA at site 3 calls the dba at site1 and asks "hey, what was the outcome
of distributed transaction XYZ?" and then forces site 3 to eithr commit it or
roll it back.

In short -- whether you have 2 sites, 3 sites or 100 sites -- the scenario of
events that occur is the same.

there is no difference between 2 sites and 3.

August 09, 2001 Bhaskara -- Thanks for the question regarding
      "Oracle Questions", version 8.1.5

      You Asked
Hi Tom,
   I have few questions. Please provide solution for them.
   Thank you very much in advance.

1) In Oracle Apps11i, How to maintain the history of patches applied and
monitor the concurrent managers?

2) For what kind of Tablespaces (i.e Data, Index, Rollback, Temp) Localloy
managed tablespace is suitable?

Thanks,
Bhaskar

      and we said...
There is a file in the $APPL_TOP/sid_name called applptch.txt which tracks all
of the patches you've applied.

Also, see

http://oracle.com/ip/deploy/database/system_mgmt/index.html?appsmanage.html
for information on Enterprise Manager with the Applications Pack which can be
used to play with the concurrent manager.  In addition, there is a new product
called Oracle Applications Manager (same url) that can be used to do something
similar.

As for the second question -- there is not a single tablespace (with the
exception of SYSTEM) that is not suitable for locally managed space management.
In fact, in 9i, the DEFAULT type of tablespace is a LMT
August 09, 2001 Ronda -- Thanks for the question regarding
      "Quoted Strings inside of Oracle Spatial function calls", version Orace
8.1

      You Asked
We are created stored packages and need to create robust select statements that
make calls to Oracle Spatial functions.  These functions require qouted strings
within the function parameters (ie functionName(param1, param2,
'distance=param3') = 'TRUE').  When I use the following methods, I receive the
following errors.

USING TWO SINGLE QUOTES WITHIN THE ORIGINAL SINGLE QUOTES:
----------------------------------------------------------
43           IF p_table = 'SDE.SCHOOL_LOCATION_SP' THEN
44                v_qry := 'SELECT ' ||
45                    'a.pin, b.school' ||
46                 ' FROM SDE.LAND_REC_POLY_SP A, ' || p_table || ' B ' ||
47                 'WHERE A.PIN = p_pin ';
48                ' AND sdo_within_distance(B.points, A.points,
''distance=5000'' ) = ''TRUE'' ';

ERROR MESSAGE IN SQLPLUS:
-------------------------
Errors for PACKAGE BODY OS_EDUCATION:

LINE/COL ERROR
-------- -----------------------------------------------------------------
49/6     PLS-00490: illegal statement
49/6     PL/SQL: Statement ignored

CONCANTENATING SINGLE QUOTE WITH THREE SINGLE QUOTES CONCANTENATED:
-------------------------------------------------------------------
49           IF p_table = 'SDE.SCHOOL_LOCATION_SP' THEN
50                v_qry := 'SELECT ' ||
51           'a.pin, b.school' ||
52        ' FROM SDE.LAND_REC_POLY_SP A, ' || p_table || ' B ' ||
53        'WHERE A.PIN = p_pin ' ||
54       ' AND sdo_within_distance(B.points, A.points, ' ||
55       ''' || 'distance=' || p_distance || ''' ||

ERROR MESSAGE IN SQLPLUS:
-------------------------
Errors for PACKAGE BODY OS_EDUCATION:

LINE/COL ERROR
-------- -----------------------------------------------------------------
55/14    PLS-00103: Encountered the symbol "DISTANCE" when expecting one
         of the following:
         . ( * @ % & = - + ; < / > at in mod not rem
         <an exponent (**)> <> or != or ~= >= <= <> and or like
         between is null is not || is dangling
         The symbol "." was substituted for "DISTANCE" to continue.

56/26    PLS-00103: Encountered the symbol "TRUE" when expecting one of
         the following:
         . ( * @ % & - + ; / at mod rem <an exponent (**)> and or ||
         The symbol ". was inserted before "TRUE" to continue.

      and we said...
The error in the first example:

46                 ' FROM SDE.LAND_REC_POLY_SP A, ' || p_table || ' B ' ||
47                 'WHERE A.PIN = p_pin ';  <<<<=========
48                ' AND sdo_within_distance(B.points, A.points

is that you have a semi colon on line 47 -- not a ||

The error in this is:

54       ' AND sdo_within_distance(B.points, A.points, ' ||
55       ''' || 'distance=' || p_distance || ''' ||

that the ''' should be ''''''

However, what I suggest is you formulate the query like this:

  IF p_table = 'SDE.SCHOOL_LOCATION_SP' THEN
     v_qry :=
     'SELECT a.pin, b.school
        FROM SDE.LAND_REC_POLY_SP A, ' || p_table || ' B
       WHERE A.PIN = p_pin
      AND sdo_within_distance(B.points, A.points, "distance=5000" ) = "TRUE" ';

     v_qry := replace( v_qry, '"', '''' );
     ....

That way -- you don't have the double quote conundrum (its easier to write).
Also note that you don't really need to || each line together, you can let it
spill from line to line -- i find that personally easier to read as well (it'll
add some bytes of whitespace to the string..)

August 09, 2001 rd -- Thanks for the question regarding "<>
      and !=, yyyy and rrrr", version 8.1.5

      You Asked
Tom

is there any difference between using  <> and !=,if so which one is better.

what is the difference between using 'yyyy' and 'rrrr' in the date format for
years?

instead of

AND (a.cc_cd IN ('aus','eng','ind') OR b.sec_cc_cd IN ('aus','eng','ind'))

can I do

AND a.cc_cd or b.sec_cc_cd  in ('aus','eng','ind')

can you discuss a similar example for me, and illustrate

If the optimizer is set to choose, will the optmizer automatically choose cbo
when we use full or first_rows hint, what are the hints which are valid for rbo.

      and we said...
they are the same <> and !=

one defaults the century, the other does not:

  1  select 'yyyy 99', to_char( to_date( '99', 'yyyy' ), 'yyyy' ) from dual
  2  union all
  3  select 'rrrr 99', to_char( to_date( '99', 'rrrr' ), 'yyyy' ) from dual
  4  union all
  5  select 'yyyy 01', to_char( to_date( '1', 'yyyy' ), 'yyyy' ) from dual
  6  union all
  7* select 'rrrr 01', to_char( to_date( '1', 'rrrr' ), 'yyyy' ) from dual
ops$tkyte@ORA817.US.ORACLE.COM> /

'YYYY99 TO_C
------- ----
yyyy 99 0099
rrrr 99 1999
yyyy 01 0001
rrrr 01 2001

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

No, you cannot do "a or b in (x,y,z)" instead of "a in (x,y,z) or b in (x,y,z)"

Regardless of the optimizer goal set, if you use a HINT you will be using the
CBO -- period.

The only valid "hint" for RBO is /*+ RULE */  -- telling the optimizer to use
RBO.  There are no hints available for RBO.

August 10, 2001 Leon -- Thanks for the question regarding "stored
      procedures execution monitoring", version 8.1.6

      You Asked
Hi Tom,

How to count stored procedures executions by name? Some options that come to
mind are Audit, trace, custom made logging, third party tools. What would you
recommend for system wide monitoring? The ultimate goal is to have as less
overhead as possible.

Thanks
Leon

      and we said...
Auditing would be the way I would do this.

Trace is pretty expensive.

Custom Made logging would be hard to implement (you would have to use the same
autonomous transaction capability we do to do it and you would have to code it)

A third party tool cannot do it reliably.

followup to comment one

I always assume people want accurate answers over a long period of time.

Most people do not (and correctly SHOULD NOT) pin objects.  Pinning is a path of
last resort and typically only needed in systems where the developers refused to
use bind variables (making shared pool managment impossible).  This would be
reliable only for pinned packages and ONLY for the life of the instance -- a
simple shutdown wipes out all counters.

This is not really a viable solution in my opinion -- not if you want accurate
answers over a long period of time anyway.

Review &
      Followup

      Rating: 2
"stored
      procedures execution monitoring", version 8.1.6  August 10,
      2001
Reviewer:  Svend Jensen  from Denmark

Some overview can be had with this query.
select  owner, name, type, executions , decode(substr(kept,1,1),'Y', '    ',
'Not Pinned') "Pinned"
  from v$db_object_cache
where type in ('PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'PROCEDURE')
order by executions  desc

August 10, 2001 play -- Thanks for the question regarding "dba
      hashed value-dba-data block-rowid-rows in the block", version 8.1.7

      You Asked
Now I understand that as soon as we issue a sql , oracle accesses the dba, and
decides whether to go to the buffer cache or the disk to get the blocks.

1.so where does oracle find these hashed values for the dba's. First it has to
find the hashed values for the dba, then it has to map the hashed values to the
dba's , which will tell the block address, then oracle will go to the block , IS
MY UNDERSTANDING RIGHT?

2.immedietly after we give the query , what makes oracle go to the locaation of
the hashed values of dba's. What is that process.

3.In which table are the DBA's stored, or where are the hashed values of the
DBA's stored. How does oracle map the dba's with the data blocks.

4.what is the difference between a dba and a rowid. is dba part of the rowid.

5.what is the difference between rowid , prior to oracle 8 and 8.

6.what is dbms_rowid package  used for? is it usefull at all.

7.Apart from dba what does the oracle data block header contain. I guess it
contains the freelists, or multiple freelists etc. Apart from this what does a
data block contain.

Tom, kindly dont give a link, explain like a story , like you usually do.

      and we said...
1) We have a DBA (we know we want the block from file 5, block 5532 for
example).  We HASH that DBA using a function -- dbms_utility.get_hash_value is
an example of a hash function.  Thats where we get the hash.  Then we goto that
list (the list indicated by the hash value) and search for that block on that
list.

If its there, bingo.  If not, read it.

2) Oracle parses the query:

select * from emp where empno = 1234

for example.  That'll probably be: INDEX RANGE SCAN, followed by TABLE ACCESS BY
ROWID.

Ok, in order to read the index, we need to know where the root block of the
index is.  We query the data dictionary to discover this and that returns us the
DBA of the root block of the index.  We have the first DBA we need and we get
that block (either from the buffer cache or from disk).  Now we inspect that
block and find that we need to "go left" in the index ( the index is a data
structure) to find the entry for 1234.  That really is just pointing us to
another block via yet another DBA.  We get that block.  This is the leaf block
in the index (at the bottom).  We find the entry for empno=1234 on there.  Every
index entry includes the ROWID of the row to which it points.  Now we can take
this rowid and extract the FILE/BLOCK of the data block that contains the entire
row.  We now have the DBA of the block we need and we get it.

Now we issue the query:

select * from emp;

that'll full scan emp (no indexes).  Now we are going to "make up" the DBA's --
what we need to know is

a) what file(s) is the emp table in
b) what block ranges in those files

This comes straight out of the DBA_EXTENTS view  -- we have the file ids and the
starting block number and the number of blocks.  We can generate the DBA for any
block in that table now.

3) DBA's are found on the block -- they are derived data.  The dba is a result
of WHERE the block came from.  Its like a rowid -- a row has a rowid because of
where it is on disk.  A block has a dba because of where it is.

4) a dba is in the rowid -- a rowid has more data to point to a row in the
block.

5) See

http://technet.oracle.com/doc/server.804/a58227/ch6.htm#918
for what all is in a rowid in 8 and up.

In 7.x and before a rowid had three things in it -- file/block/slot

file/block = dba.
slot = row number on the block that is the row.

6) use it and see.  If you want to extract the dba from a rowid, you'll need it.
 If you want to know what block a row starts on you'll need it.  Yes, I find it
useful

7) a block header would not contain freelists -- those are things associated
with segments.

see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c02block.htm#2601
Yes i know that is a link (please don't ask me to NOT supply a link, I'm not
just going to type in whats already typed in).

The server concepts manual is an EXCELLENT document, I will refer to it
repeatedly when answering questions.  Additionally my book has similiar
information in it, presented in a slightly different manner.

followup to comment one

The number of lists is a function of the number of database blocks.  It varies
from release to release as we fine tune it over time.  It can be controlled
externally via a hidden, undocumented init.ora that in times of need support
will fill you in on (but its very rare to use it).

Review &
      Followup

      Rating: 4
how many lists
      are there  August 10, 2001
Reviewer:
      A reader
"Thats where we get the hash.  Then we goto that
list (the list indicated by the hash value) and search for that block on that
list. "

How are many lists are there? what is the criteria for these lists, are they
grouped by some criteria.

where can we get the info information on these lists.


Subject | Article | Last Updated (East coast time)
Nested Table | article only | Aug 13, 2001 10:23 am
clob & concatenate function | article only | Aug 13, 2001 02:54 pm
virtual memory | article only | Aug 13, 2001 02:57 pm
VARCHAR Diminishing Returns | article only | Aug 13, 2001 04:34 pm
How to do this 10 million record insert | article only | Aug 13, 2001 07:24 pm
Show SGA: 'redo_buffers' size versus 'log_buffer' in the init.ora | article only | Aug 13, 2001 08:33 pm
Invalid Snapshots and snapshot logs | article only | Aug 13, 2001 08:48 pm
Read from MS-OUTLOOK and MS-Word | article only | Aug 13, 2001 09:16 pm
sqlload | article only | Aug 14, 2001 03:28 pm
Can u please explain, why this index is using more than expected storage space? | article only | Aug 14, 2001 03:41 pm
example at page 200 | article only | Aug 14, 2001 09:09 pm
why do i have db file sequential read? | article only | Aug 15, 2001 10:34 am
lock_sga | article only | Aug 15, 2001 10:59 am
Creating objects with raw devices on WIN 2K | article only | Aug 15, 2001 11:45 am
Renaming Process | article only | Aug 15, 2001 01:39 pm
Explicit Vs Implicit & Temporary tables ! | article only | Aug 15, 2001 02:32 pm
External Routines ... [OS calls in particular]... | article only | Aug 16, 2001 05:27 pm
Conflicting answers on object privilege?? | article only | Aug 16, 2001 05:31 pm
is cursor for loop an implicit cursor?, sql plus questions, and parallel dml | article only | Aug 16, 2001 06:59 pm
Hardware specs | article only | Aug 17, 2001 12:53 pm
Export & import and miscllaneous | article only | Aug 17, 2001 01:17 pm
How truncate is handled during recovery using archived logs | article only | Aug 17, 2001 01:26 pm
Query returns length as 8 | article only | Aug 17, 2001 01:56 pm
nested table | article only | Aug 17, 2001 02:14 pm
Errors not explained in Oracle Documentation - ORA-1536 | article only | Aug 19, 2001 03:59 pm
What to do if open_cursor reached in 24x7 environment? | article only | Aug 19, 2001 04:05 pm
Different Questions | article only | Aug 19, 2001 04:14 pm
oracle tuning | article only | Aug 19, 2001 04:26 pm
row(s) 1 - 28 of 28
August 13, 2001 Suresh -- Thanks for the question regarding "Nested Table", version 8.1.7
You Asked
Tom,
   I have just started working on nested tables and I have a few questions about
it.

I designed a table as shown below.

create or replace type filing_ty as object
(filing_state   varchar2(5));
/
Type created.

create type filing_states_nt as table of filing_ty;
 /
Type created.

SQL> create table l_v(
     legal_vehicle    varchar2(10),
     name             varchar2(5),
     filing_states   filing_states_nt)
     nested table filing_states store as filing_states_nt_tab;

Question 1.) Assuming that I inserted  a record into the above table by
   insert into l_v(legal_vehicle, name) values ('1','first');
   commit;
   Now, how can I enter values for the nested table (filing_states)
   for that first record?

Question 2.)
     Stmt a.) DELETE FROM L_V;
              insert into l_v values ('1','first', filing_states_nt
              (filing_ty('NJ'), filing_ty('NY')));
              insert into THE (SELECT FILING_STATES FROM L_V WHERE
                   LEGAL_VEHICLE = '1')
              VALUES  (FILING_TY('OR'));

     Stmt b.) DELETE FROM L_V;
             insert into l_v(legal_vehicle, name) values
            ('1','first');
             insert into THE (SELECT FILING_STATES FROM L_V WHERE
             LEGAL_VEHICLE = '1')
             VALUES  (FILING_TY('OR'));

Stmt a. works, meaning, I have 3 records in the nested table at the end.
Stmt b. does not work and gives me an error while executing the last insert
statement. why?

Question 3.) Could you please give us an example as to how to update and delete
records in a nested table?

Thanks for your time.
and we said...
Question 1) you can either use an INSERT or an UPDATE to do it.

ops$tkyte@ORA817.US.ORACLE.COM> create or replace type filing_ty as object
  2  (filing_state      varchar2(5));
  3  /

Type created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> create type filing_states_nt as table of
filing_ty;
  2  /

Type created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> create table l_v(
  2       legal_vehicle    varchar2(10),
  3       name             varchar2(5),
  4       filing_states   filing_states_nt)
  5       nested table filing_states store as filing_states_nt_tab;

Table created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> insert into l_v(legal_vehicle, name) values
('1','first');

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM> commit;

Commit complete.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> declare
  2          data filing_states_nt := filing_states_nt( filing_ty('x'),
filing_ty('y') );
  3  begin
  4          update l_v
  5         set filing_states = data
  6       where name = 'first';
  7  end;
  8  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> insert into TABLE( select filing_states from l_v
where name = 'first' )
  2  values ( filing_ty('z') )
  3  /

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> select * from l_v;

LEGAL_VEHI NAME
---------- ------------------------------
FILING_STATES(FILING_STATE)
---------------------------------------------------------------------------------
--------------------------------------------------
1          first
FILING_STATES_NT(FILING_TY('x'), FILING_TY('y'), FILING_TY('z'))

Question 2:

the array was not initialized:

ops$tkyte@ORA817.US.ORACLE.COM> insert into THE (SELECT FILING_STATES FROM L_V
WHERE LEGAL_VEHICLE = '1')
  2  VALUES     (FILING_TY('OR'));
VALUES  (FILING_TY('OR'))
         *
ERROR at line 2:
ORA-22908: reference to NULL table value

there is no TABLE to insert into yet.  You would:

ops$tkyte@ORA817.US.ORACLE.COM> DELETE FROM L_V;

1 row deleted.

ops$tkyte@ORA817.US.ORACLE.COM> insert into l_v(legal_vehicle, name,
filing_states) values
  2  ('1','first', filing_states_nt() );

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> insert into THE (SELECT FILING_STATES FROM L_V
WHERE LEGAL_VEHICLE = '1')
  2  VALUES     (FILING_TY('OR'));

1 row created.

and then it will work.

It looks like you might be using OLD documenation given your syntax (the THE
keyword is depricated in 8i).  All docs are online at
http://otn.oracle.com/
Review & Followup
Rating: 5
As always thanks so much for your help August 13, 2001
Reviewer: Suresh

August 13, 2001 -- Thanks for the question regarding "clob & concatenate function", version oracle 8i
You Asked
Target is to migrate data
from table 'A' of  database 'D1'  to 'A' table of another database 'D2'.

datatype for 'descr' column in 'D1' databse is VARCHAR2(2000).
datatype for 'descr' column in 'D2' databse is CLOB.

I have 5 records in source table with same prime_id.
want to migrate all  5 records in the one record of target database with descr
from source concatenated.
Example:  source db
prime_id    seq_id        descr
1        01        dlsfjaslkjflka
1        02        LSDKJFLKASJFLKASD
1        03        LSJDFLKASD
1        04        jlfkas
1        05        dkfljlasd;fjlsdfjld

target db
prime_id    descr
1        concatenated descr from source db orderby seq_id

 how can I do this?
and we said...
procedurally.

I would use a database link so that database D1 is accessible via a dblink from
D2

Then code such as:

  declare
     l_clob clob;
     l_last number;
  begin
      for x in ( select * from A@D1 order by prime_id, seq_id )
      loop
         if ( nvl(l_last,-1) <> x.prime_id )
         then
              insert into a values ( x.prime_id, empty_clob() )
              returning descr into l_clob;

              l_last := x.prime_id;
         end if;
         dbms_lob.writeAppend( l_clob, length(x.descr), x.descr );
      end loop;
  end;

(did not actually run this, please consider it psuedo code -- make sure you
understand what it is doing) will fetch all of the rows for by prime id and glue
the descr's together in the clob.
Review & Followup
Rating: 4
Bulk insert August 18, 2001
Reviewer: A reader
Hi

The above mentioned code works fine for records by record
insertion but is failing in case of bulk insert

can u help?

Followup:
give me an example of the failing code WITH the error message and I'll take a
look (I cannot guess what you might be doing...)

August 13, 2001 Anil -- Thanks for the question regarding "virtual memory", version 8.1.5
You Asked
Hi tom,
   I have set shared_pool_size=1gb.So this should get allocated
from the main memory we have,but I see in task manager virtual memory
taking 1 gb and actual memory shows less than 1 gb for oracle..
why ??

2) How do i see all oracle process(like dbwr,lgwr,ckpt etc) running in NT and
it's consumption of memory and cpu ??

Thanks,

Regards
 Ak
and we said...
a 1 gig shared pool?  thats pretty large.  you need to have a really good reason
for needing to go over 150meg or so.  That is an outrageous amount of ram,
especially on NT where you are limited to 2gig/process and the multi-threaded
setup on NT limits you to a single process (you've allocated 50% of the
available ram to the shared pool making it totally unavailable to other
components of the database)

The way NT works is that it will not necessarily give you real memory until you
need it.  In a properly designed Oracle system, you'll never use any where NEAR
1 gig of shared pool (if you do -- it indicates you are NOT using bind variables
and you NEED to fix that or buy 8 extra CPUS just to do parsing).

On NT, we run as a single process, dbwr, lgwr, etc are threads.  You'll use
perfmon or some 3rd party utility to see whats going on.
August 13, 2001 Pete -- Thanks for the question regarding "VARCHAR Diminishing Returns", version 8.0.5
You Asked
Hi Tom,

My question is whether there is any rule of thumb concerning the conversion of
data from CHAR to VARCHAR for a data warehouse? We have a number of one and two
byte columns that are converted in our warehouse tables. I'm not sure this is
the right approach for columns of this length.

Please advise...
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:173612348069
A char is simply a blank padded varchar2.

char(1) = varchar2(1) -- they are the same;

char(2) might waste space when compared to a varchar2(2) and you would have to
be careful to blank pad bind variables in queries to be 2 bytes long.

I recommend varchar2 across the board.
August 13, 2001 play -- Thanks for the question regarding "How to do this 10 million record insert", version 8.1.7
You Asked
Tom

I need to do this test.

I need to insert 10 million records in one of our tables. The average rowsize is
150 bytes. The number of columns are 30. I  tried doing this by doing.

begin
For i in 1..10000000 loop
insert into t VALUES(
i,
1,
'sfsdfsdfsd',
'del',
sysdate,
sysdate,
'stypc',
3456,
3457,
5643,
5464,
'dfsdf',
'USER',
SYSDATE,
'5675',
'6785',
34534,
'P',
111,
12,
12,
'TR',
'E',
'sdfsdfsd',
'EREFE',
'sdfsdf',
3434,
'E',
4568);
end loop;
commit;
end;

I ran this anonymous pl/sql block from sqlplus. It just hang on for ever. I
killed the session.

1.How should I know whether the inserts are going on or not.

2.How can I determine how many inserts took place, and how many still have to be
done at a given point of time.

3.Is there anyway we can do this with no logging.

4.Rollback takes a lot of time, if we kill this process in between, is there
anything we can do about it.

5. what is the best way to insert 10 million records into this table.

6.This is just a test, and I want to commit for every insert of 10K records.
i.e. for every 10,000 records.

why does sqlplus hang up, from the task manager in windows is there any way to
know what are the resources being taken by this task. How about in unix.

Kindly guide me.
and we said...
Here is what I would do:

drop table t;
create table t ( x int, y date, z varchar2(20) );

declare
    l_cnt number default 0;
    l_rows number default 100000;
begin
    insert /*+ APPEND */ into t ( x, y, z )
    select rownum+l_cnt, sysdate, 'blahblah'
      from all_objects;
    l_cnt := sql%rowcount;
    commit;

    while( l_cnt < l_rows )
    loop
        insert /*+ APPEND */ into t ( x, y, z )
        select rownum+l_cnt, sysdate, 'blahblah'
          from t
         where rownum < l_rows-l_cnt+1;

        l_cnt := l_cnt + sql%rowcount;
        dbms_application_info.set_client_info
        ( 'Added ' || sql%rowcount || ' rows, ' || l_cnt || ' total' );
        commit;
    end loop;

end;
/

that loop seeds the table T with N rows (where N = number of rows in All
objects).  It then doubles the table size with each insert -- since it uses the
APPEND hint, it'll generate no rollback / redo.  Make sure to INDEX AFTER you
load up the table (including primary key indexes!!) and do that with NOLOGGING
(and in parallel) to speed them up (no redo/rollback for them either)

The dbms_application_info allows you to query:

select username, client_info from v$session where client_info is not null;

to monitor the progress of this script in real time.

Don't commit every 10k records, commit ever batch (since they don't generate
rollback -- no worries there).

SQLPlus is NOT hanging up, its waiting for the block to complete.  If you
ctl-c'd that you were waiting for the rollback to finish (which could take
LONGER then the initial operation).

I ran the above block on my little machine and it took about 3 minutes to do
10,000,000 rows....

followup to comment one

Well, -- I generated the same exact amount of redo/rollback that a direct path
load would do -- I used a direct path insert.  I would recommend using my
method above because:

1) you don't have to write a program in some 3gl/script to generate 10,000,000
records to the file system
2) you don't have to write the ctl file to load it
3) you don't have to run sqlldr

the above can generate 10,000,000 records very nicely -- without redo/rollback.

followup to comment two

True the snippet did 100k, I did test 10million (in fact I'm using that table
for the discussion on select count(*) vs select (1) right now) and it took about
3 minutes on my small machine.

I did 10million, not to worry -- works great -- no redo, no rollback (yes I
measured that as well)

followup to comment three

No, see the followup to comment one -- it would be a waste of time, energy and
resources.  (and would be slower from start to finish since you have to create
and save the 10million records to disk and then read and write the 10 million
records to disk).
Review & Followup
Rating: 3
You could also use SQL*Loader August 13, 2001
Reviewer: Arup Nanda from Norwalk, CT, USA
If you want to load 10 million rows and all of your column values except one
have static values, I recommend the good ol' SQL*Loader with direct option and
NOLOGGING. That way you can generate a lot less redo and the load is much
faster. If the table you want to load is not emplty, you can partition the
table, load data into a temporary table and then ALTER TABLE...EXCHANGE
PARTITION with the newly loaded table.

Rating: 4
August 13, 2001
Reviewer: A reader
Tom I think you inserted  100000 rows ,and not 10,000,000 rows.

Rating: 5
how can we do these inserts with sql loader August 13, 2001
Reviewer: A reader
Can you show us how to do these same inserts using sql loader

Rating: 4
Using Sqlloader August 14, 2001
Reviewer: Vidyesh from Pune, India
Very usefull answer.
In our application we NEED to take data from flat files.
The index creation is taking hell lot of time. Around 20gig
of data insert per day.Can you pl suggest us how to improve
performance of 'data insert' and 'index creation' thereafter.

Rating: 5
Response to previous post August 14, 2001
Reviewer: Connor from UK
(Although Tom would have probably preferred this to be a separate question...).
Using SQL Loader with direct and parallel seems to be the fastest mechanism.
You can load scary amounts of data very quickly. I've seen this used to get
100's of millions of (cell phone data) records into a database in just a few
minutes.  Indexing is more about good design - if you can partition the table
than the index partitions can be built individually.  Then its just crank up
sort size, parallel and nologging options to improve the performance.

Rating: 4
Oracle DBA August 14, 2001
Reviewer: lilian an from wilmington, DE
it's great answer! but i think sql loader should be easy, fast way to do it.

Rating: 3
January 03, 2002
Reviewer: Chandra
Hi Tom,
I don't Understand the reason for using all_objects here.
Can't just  use  the following ?
declare
    l_cnt number default 0;
    l_rows number default 100000;
begin
    while( l_cnt < l_rows )
    loop
        insert /*+ APPEND */ into t ( x, y, z )
        select a,b,c,d
         from  table1,
               table2
         where table1.key = table2.key;
        l_cnt := l_cnt + sql%rowcount;
        dbms_application_info.set_client_info
        ( 'Added ' || sql%rowcount || ' rows, ' || l_cnt || ' total' );
        commit;
    end loop;

end;
------------------------------------------------------------
drop table t;
create table t ( x int, y date, z varchar2(20) );

declare
    l_cnt number default 0;
    l_rows number default 100000;
begin
    insert /*+ APPEND */ into t ( x, y, z )
    select rownum+l_cnt, sysdate, 'blahblah'
      from all_objects;
    l_cnt := sql%rowcount;
    commit;
    while( l_cnt < l_rows )
    loop
        insert /*+ APPEND */ into t ( x, y, z )
        select rownum+l_cnt, sysdate, 'blahblah'
          from t
         where rownum < l_rows-l_cnt+1;
        l_cnt := l_cnt + sql%rowcount;
        dbms_application_info.set_client_info
        ( 'Added ' || sql%rowcount || ' rows, ' || l_cnt || ' total' );
        commit;
    end loop;

end;
------------------------------------------------------------

August 13, 2001 Beth -- Thanks for the question regarding "Show SGA: 'redo_buffers' size versus 'log_buffer' in the init.ora", version 8.1.6
You Asked
Our log_buffers in the init.ora are:
log_buffer = 32768

But the redo_buffers shown in 'show sga' state:
90112 bytes

Aren't these supposed to match?

(I just bounced the db, so the init.ora is definitely in sync with the database.)
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:972030403607
On your platform, we have decided that 90,112 is the smallest effective size we
will support (a value of 1-2 meg is typically great for most implementations)
Review & Followup
Rating: 3
Thanks. Is it documented? August 14, 2001
Reviewer: Beth from USA
Thanks!  We are on Solaris 7.  Are the minimum amounts documented somewhere, and
if so, where?

August 13, 2001 Logo -- Thanks for the question regarding "Invalid Snapshots and snapshot logs", version 8.1.6
You Asked
Tom,

Can I drop the snapshots from the first query that don't have an associated
snapshot logs? Please note the CAN_USE_LOG=Yes

In the second query, can I drop the sanpshot logs that don't have any associated
snapshots?

Oracle8i Enterprise Edition Release 8.1.6.1.0 - Production
With the Partitioning option
JServer Release 8.1.6.1.0 - Production
SQL> SELECT S.OWNER, S.NAME FROM DBA_SNAPSHOTS s
  2  WHERE CAN_USE_LOG = 'YES'
  3  and not exists (select null from dba_snapshot_logs sl where sl.log_owner =
s.master_owner and sl.master=s.master);

OWNER                          NAME
------------------------------ ------------------------------
MSC                            MSC_ATP_PLAN_SN
INV                            MTL_DEMAND_SN
INV                            MTL_SUPPLY_SN
ONT                            OE_ODR_LINES_SN
INV                            MTL_MTRX_TMP_SN

SQL>
SQL> SELECT LOG_OWNER, MASTER FROM DBA_SNAPSHOT_LOGS
  2  MINUS
  3  SELECT MASTER_OWNER, MASTER FROM DBA_SNAPSHOTS;

LOG_OWNER                      MASTER
------------------------------ ------------------------------
BIM                            BIM_EDW_RVCT_DLY_F
BIM                            BIM_EDW_RVCT_MTH_F
BIM                            EDW_BIM_CAMP_CMPGNS_L1_LTC
BIM                            EDW_BIM_CAMP_CMPGNS_L2_LTC
BIM                            EDW_BIM_CAMP_CMPGNS_L3_LTC
BIM                            EDW_BIM_CAMP_CMPGNS_L4_LTC
BIM                            EDW_BIM_CAMP_CMPGNS_L5_LTC
BIM                            EDW_BIM_CAMP_CMPGNS_L6_LTC
BIM                            EDW_BIM_CAMP_CMPGNS_L7_LTC
BIM                            EDW_BIM_CAMP_CMPGNS_L8_LTC
BIM                            EDW_BIM_CAMP_CMPGNS_LTC
BIM                            EDW_BIM_CAMP_SCHEDULES_LTC
BIM                            EDW_BIM_CMPGNS_A_LTC
BIM                            EDW_BIM_CMPSTATS_A_LTC
BIM                            EDW_BIM_CSTA_CMPSTATS_LTC
BIM                            EDW_BIM_EVENTS_A_LTC
BIM                            EDW_BIM_EVNT_EVENTS_LTC
BIM                            EDW_BIM_EVNT_EVTOFFERS_LTC
BIM                            EDW_BIM_IHMD_IH_MEDIA_LTC
BIM                            EDW_BIM_IHOT_IH_OUTCOME_LTC
BIM                            EDW_BIM_IHRN_IH_REASON_LTC
BIM                            EDW_BIM_IHRS_IH_RESULT_LTC
BIM                            EDW_BIM_IH_MEDIA_A_LTC
BIM                            EDW_BIM_IH_OUTCM_A_LTC
BIM                            EDW_BIM_IH_REASN_A_LTC
BIM                            EDW_BIM_IH_RESLT_A_LTC
BIM                            EDW_BIM_LEADS_A_LTC
BIM                            EDW_BIM_LEAD_LEADLINES_LTC
BIM                            EDW_BIM_LEAD_LEADS_LTC
BIM                            EDW_BIM_LEAD_STATUS_A_LTC
BIM                            EDW_BIM_LIST_SRCLSTS_LTC
BIM                            EDW_BIM_LSTA_LEADSTATUS_LTC
BIM                            EDW_BIM_MDCHN_A_LTC
BIM                            EDW_BIM_MDCH_CHANNELS_LTC
BIM                            EDW_BIM_MDCH_MDCHN_LTC
BIM                            EDW_BIM_MDCH_MDTYPES_LTC
BIM                            EDW_BIM_MDCH_MEDIA_LTC
BIM                            EDW_BIM_MKSG_MKTSGMTS_LTC
BIM                            EDW_BIM_MKTSGMTS_A_LTC
BIM                            EDW_BIM_OFFERS_A_LTC
BIM                            EDW_BIM_OFFR_OFFERS_LTC
BIM                            EDW_BIM_OPPORTUNITIES_A_LTC
BIM                            EDW_BIM_OPPR_OPPLINES_LTC
BIM                            EDW_BIM_OPPR_OPRNTIES_LTC
BIM                            EDW_BIM_OPP_STATUS_A_LTC
BIM                            EDW_BIM_OSTA_OPPSTATUS_LTC
BIM                            EDW_BIM_SRCLSTS_A_LTC
BIM                            EDW_BIM_TGSMT_A_LTC
BIM                            EDW_BIM_TGST_TGSMT_L1_LTC
BIM                            EDW_BIM_TGST_TGSMT_L2_LTC
BIM                            EDW_BIM_TGST_TGSMT_L3_LTC
BIM                            EDW_BIM_TGST_TGSMT_L4_LTC
BIM                            EDW_BIM_TGST_TGSMT_L5_LTC
BIM                            EDW_BIM_TGST_TGSMT_L6_LTC
BIM                            EDW_BIM_TGST_TGSMT_L7_LTC
BIM                            EDW_BIM_TGST_TGSMT_L8_LTC
BIM                            EDW_BIM_TGST_TGSMT_LTC

57 rows selected.

SQL> exit
and we said...
In the first query - you tell me.  Do you WANT to drop those snapshots?  the
can_use_log simply is a flag that says "hey, if there were to be a log
available, this snapshot would be able to use it".  It does not mean that there
MUST or even SHOULD be a log.

I would say "no", do not drop them.  they are snapshots your system has created
and there is probably an application out there using them.

As for the second one, again, I would say -- do YOU WANT to drop those logs?
Your query only shows logs that are used by local snapshots.  what about
snapshots that are coming in from other sites to use this data?  They are most
likely using these snapshot logs.  Only if you have NO other databases that have
snapshots on these should you drop these logs.
August 13, 2001 Venkateswara -- Thanks for the question regarding "Read from MS-OUTLOOK and MS-Word", version 8.1.5 and Forms 6.0
You Asked
Hi Tom,

I am very happy to inform that you had come early(One day ).
Now My company CEO wants to do a programm that read from MS-OUTLOOK messages
from D2K Ver6.0 and insert into my Oracle Database 8i (8.1.5.
I would like to know how to read from MS-OUTLOOK and MS-ACCESS and How can I
insert into my database.

Please give me some examples and where I can get more information.

Please keep in mind while giving answer, I am small person in "ORACLE
REVOLUTIONARY WORLD"

Thanks in advance

Reddy
and we said...
This would not be easy to do from d2k.

This would be easy to do from Java.

To talk to an MS Exchange server (you will not be reading "outlook" messages --
outlook is an email CLIENT -- you will be getting the messages from the server
which I assume is exchange in your case since everything else is MS based)....

Using the Java Mail API it is easy to read email from a variety of Email
Servers.  Using JDBC, it would likewise be easy to insert them into the
database.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:255615160805
for an example using Java to SEND (not recieve) email.  It is packaged into the
database -- but that is not necessary.  It simply shows how you might use the
Java Mail API from sun to do this.

See
http://java.sun.com/products/javamail/
for all of the details.

followup to comment

That is funny -- how are OLE and DDE "Oracle technologies"???

Java is (a technology embraced and supported by Oracle) -- OLE and DDE -- well,
they are the property of another company (and a single company).

If the reader wants information on how to program OLE and DDE, Microsoft would
be the correct place to go.

As I said in the answer, doing this in D2k would be *very hard*.
Doing this from the database using Java -- trivial.

If you read the link I provided, I show how to provide a very simple interface
to java using PLSQL -- very simple. At the end of the day, the coders user
PLSQL, not Java.  The java is just there to read the mail.

If the people on site know OLE and DDE -- they should actually be able to answer
this question then (i cannot, I never bothered to learn those two technologies
myself - sorry)....

I try to give useful advice, better paths to take.
Review & Followup
Rating: 1
August 13, 2001
Reviewer: A reader
Since the question was how to read from Outlook, the response should of
addressed this issue.  Providing an alternative NON-Oracle solution had no
value.  Some of us are looking at DDE and OLE2.  I have had limited success with
this.  I know that JAVA would also be a better interface; however, the client
wants a ORACLE built in that is NOT JAVA because the client's in-house staff
doesn't have enough experience with it to date.

Rating: 5
:-) August 14, 2001
Reviewer: Just another DBA from UK
The original response was excellent
The followup even better hope it cleared it up
for "reader"

Rating: 3
Other methods...... August 15, 2001
Reviewer: DJG from Reading, UK
With 8.1.6 of Oracle, the Heterogeneous Services option (HS)
allows you to connect to an ODBC driver interface - provided you have these for
your MS products you could examine this.
You can then write D2K or PL/SQL or SQL or whatever to use the HS database links
to process the foreign data store.It's all documented in the manuals, at
http://docs.oracle.com/

      Rating: 3
Use
      perl  August 20, 2001
Reviewer:
      A reader
You can download the MAPI module from activestate and do this thro' perl.

August 14, 2001 -- Thanks for the question regarding "sqlload",
      version 8.1.6

      You Asked
Tom:

i have csv file like this
a1,b1,c1
a2,b2,c2
a3,b3,c3

i have table x( third varchar2(20);

i want to load the first column and third column to table x
so x have value.
a1c1,
a2c2,
a3c3.

is that possible?

i tried
LOAD DATA
INFILE *
APPEND INTO TABLE x
fields terminated by ','
(
first filler,
second filler,
third char ":first||:third "
)
BEGINDATA
A1 ,     B1,c1
A2  ,    B2,c2
)

but it didn't work.

      and we said...
LOAD DATA
INFILE *
INTO TABLE x
REPLACE
fields terminated by ','
(
third position (1:80)
 "substr(:third,1,instr(:third,',')-1)|| substr(:third,instr(:third,',',1,2)+1)"
)
BEGINDATA
a,b,c
argle,bargle,blah

will do it.
August 14, 2001 Prince -- Thanks for the question regarding "Can
      u please explain, why this index is using more than expected storage
      space?", version 8.1.7

      You Asked
Tom:

This is the output from executing ur procedures,

exec print_table( 'select * from index_stats' );

HEIGHT                        : 3
BLOCKS                        : 18496
NAME                          : IDX_NORMLAPACHELOG_HIT_DATE
PARTITION_NAME                :
LF_ROWS                       : 3365891
LF_BLKS                       : 18393
LF_ROWS_LEN                   : 63951929
LF_BLK_LEN                    : 3900
BR_ROWS                       : 18392
BR_BLKS                       : 77
BR_ROWS_LEN                   : 297622
BR_BLK_LEN                    : 3932
DEL_LF_ROWS                   : 0
DEL_LF_ROWS_LEN               : 0
DISTINCT_KEYS                 : 2426950
MOST_REPEATED_KEY             : 61
BTREE_SPACE                   : 72035464
USED_SPACE                    : 64249551
PCT_USED                      : 90
ROWS_PER_KEY                  : 1.38688106471085106821318939409546962237
BLKS_GETS_PER_ACCESS          : 4.19344053235542553410659469704773481118
PRE_ROWS                      : 0
PRE_ROWS_LEN                  : 0

o/p of show_space:

Free Blocks.............................0
Total Blocks............................18496
Total Bytes.............................75759616
Unused Blocks...........................24
Unused Bytes............................98304
Last Used Ext FileId....................12
Last Used Ext BlockId...................126289
Last Used Block.........................8

Though, I remembered the 10% PCTFREE, I forgot to include the rowid overhead
while calculating the space occupied.

Also, I have another question regarding the indexes. If I have a varchar2(500),
will the index key be of size 500 or whatever the length of the column ?

Thanks you very much for all your responses.

Prince,,

Dear Tom:

I have a index created as follows
CREATE INDEX IDX_NORMLAPACHELOG_HIT_DATE"
ON "NORMALIZEDAPACHELOG"("HIT_DATE")
TABLESPACE "WEBINDX" PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE ( INITIAL 512K NEXT 128K MINEXTENTS 1 ) ;
HIT_DATE is a DATE field.
After running analyze validate, I got the following results.
HEIGHT BLOCKS NAME LF_ROWS LF_BLKS LF_ROWS_LEN
LF_BLK_LEN BR_ROWS BR_BLKS BR_ROWS_LEN BR_BLK_LEN DEL_LF_ROWS
DEL_LF_ROWS_LEN DISTINCT_KEYS MOST_REPEATED_KEY BTREE_SPACE USED_SPACE
PCT_USED ROWS_PER_KEY BLKS_GETS_PER_ACCESS PRE_ROWS PRE_ROWS_LEN
------ ------ -------------------------- ------- -------- -----------
---------- -------- ------- ------------ ---------- -----------
--------------- ------------- ----------------- ----------- ----------
---------- ------------ -------------------- ---------- ------------
3 18496 IDX_NORMLAPACHELOG_HIT_DATE 3365891 18393 63951929 3900
18392 77 297622 3932 0 0
2426950 61 72035464 64249551 90 1.38688106
4.19344053 0 0
This Index currently has 578 extents on a UNIFORM extented size LMT with extent
size of 128K. That means it is occuping approx 73984KB.
select INITIAL_EXTENT, NEXT_EXTENT, LEAF_BLOCKS, DISTINCT_KEYS,
AVG_LEAF_BLOCKS_PER_KEY, NUM_ROWS, MIN_EXTENTS, PCT_INCREASE
from dba_indexes where index_name = 'IDX_NORMLAPACHELOG_HIT_DATE' ;
INITIAL_EXTENT NEXT_EXTENT LEAF_BLOCKS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY
NUM_ROWS MIN_EXTENTS PCT_INCREASE
-------------- ----------- ----------- ------------- -----------------------
---------- ----------- ------------
524288 131072 15733 2072383 1
2879025 1 0
How is it possible, for this index with 2879025 rows with 7 bytes (ie 19681KB)
to occupy 73984KB? Please explain.

Thanks,
Prince..

      and we said...
Here is the answer then:

1) an index has the rowid in it, double your row size (date+rowid)

ops$tkyte@ORA8I.WORLD> select vsize(rowid)+vsize(sysdate) from dual;

VSIZE(ROWID)+VSIZE(SYSDATE)
---------------------------
                         18

2) your btree size is 63951929, not 73984KB (there is free space in the
structure, space allocated but not yet used).  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
for a routine to see how much allocated but not yet used....

in the above, you have

Total Bytes.............................75759616
Unused Bytes............................98304

so there is some unused space (not much but some).

3) indexes, when created, use the pctfree to set aside space -- by default 10%
of the space on the block (after the header) is set aside, if this is a new
index, it'll have blank space in it.

4) you do not have 2879025 rows, you have 3365891 rows -- the LF_ROWS shows
that.  You are getting an average of 183 rows/block in your index using an
average of 3900 bytes / block (4k block size) so each index entry is on average
taking 21bytes in the data structure (its a data structure, there is overhead in
there)

As for:

Also, I have another question regarding the indexes. If I have a varchar2(500),
will the index key be of size 500 or whatever the length of the column ?

it'll be the length of the actual data, not 500 bytes fixed.

followup to comment one

Well, actually the book is for DBA's and developers alike.

DBA's should be interested in architecture, locking/concurrency, transactions,
redo/rollback, tables, indexes, imp/exp, data loading, tuning strategies/tools,
plan stability, materialized views, partitioning, fine grained access control,
necessary supplied packages.

Thats over 1/2 of the book (developers should be interested in that list of
topics as well).  the other parts such as analytic functions, dynamic sql --
maybe thats not 100% of interest....

A really good book is also Jonathan Lewis's "Practical Oracle8i".  I promise you
you'll read that one two times just to pick up what you missed the first time (i
did).

Review &
      Followup

      Rating:
      4
Fantastic...  August 14, 2001
Reviewer:
      A reader
Thanks Tom,

Its very clear now. Also, I was reading your book on the chapter on indexes (I
guess chap 6), which made me understand more.

The book has so much detail an many other book combined. Will you be writing a
book, for the DBAs?

Thanks,

August 14, 2001 -- Thanks for the question regarding "example at
      page 200", version 8.1.6

      You Asked
Regarding the example at page 200.
i am pretty sure i followed your instruction at the very begining
( you can reread my previous email, i got v$waitstat before i run
and then got another one afterward)
however, this time i followed EXACT what you said.
at beginning, three window still don't work,
it still gives me value for data block,segment header and undo header.
then i restarted my database, after that,
three window is ok, it gives me 0 for everything.

then i create table t( x int) storage(freelists 10).
then opened 10 windows to run it at same time.
below is the result.

CLASS                   COUNT       TIME
------------------ ---------- ----------
bitmap block                0          0
bitmap index block          0          0
data block              45545       5101
extent map                  0          0
free list                   0          0
save undo block             0          0
save undo header            0          0
segment header             15          0
sort block                  0          0
system undo block           0          0
system undo header          0          0

CLASS                   COUNT       TIME
------------------ ---------- ----------
undo block                  0          0
undo header              1019        646
unused                      0          0

14 rows selected.

Elapsed: 00:00:00.01

then i increase number of window step by step, up to 7 window is ok,
it gives me 0 for every values. when i open 8 window concurrently.
it gives me big value for data block,segment header and undo header.

then i test
create table t(x int) storage( freelists 8).
the increase concurrent window step by step.
up to 5 windows works fine.
but 6 windows give me value for data block,segment header and undo header.

so my conclusion is if you expect N concurrent transaction, you should setup
freelists to N+2.

can you test it at your machine and tell me what did you get?

      and we said...
What is happening to you as you go up and up in the numbr of sessions is that
the sessions are getting assigned to the same freelist based on their process
id.

Having 10 freelists does not gaurantee that the sessions will absolutely be
assigned to 10 different freelists.  You must be seeing two sessions (or more)
getting assigned to the same freelist.  You have no control over this.

I've never seen it happen with 2 or 3 sessions started one after the other.  Not
surprised to see it with more.

Even with N+2, you might hit this as well since the assignment to a freelist is
based on a function of your session -- more then one person will get assigned to
the same freelist.

It is interesting to note that in Oracle9i, there is a new space management
feature that obsoletes freelists and fixes this problem pretty much alltogether.

see

http://download-west.oracle.com/otndoc/oracle9i/901_doc/server.901/a90117/tspaces.htm#19171
for info on that feature.

followup to comment one

If you have 10 users CONCURRENTLY requesting free space from some segment
simultaneously and some of them are using the same freelist -- you will see some
contention.

Adding multiple freelists will reduce, drastically reduce (dramatically reduce)
the contention.  It will not assure zero contention.
Review &
      Followup

      Rating:
      3
  August 14, 2001
Reviewer:
      A reader
so in that case, if i have up to ten concurrent users.
the contention between data block,segment header and undo header is unavoid.  is
that right?

August 15, 2001 -- Thanks for the question regarding "why do i
      have db file sequential read?", version 8.1.6

      You Asked
Tom:

I opened only ONE window and run

  1  begin
  2  for i in 1..100000 loop
  3  insert into t values(i);
  4  commit;
  5  end loop;
  6* end;

and at another window i query v$session_wait.
i found that event like :

log file parallel write
db file sequential read

why db file sequentila read happen, why system need to read db file?

      and we said...
You need to read the table even to insert into it.

We'll be reading the freelists, we'll be reading blocks in that are on the
freelist to insert into, we'll be getting blocks in from above the HWM in order
to insert into them and so on.
August
      15, 2001 -- Thanks for the question
      regarding "lock_sga", version 8.1.6

      You Asked
Tom:

i shutdown my databas.
add lock_sga=true to init.ora
startup

it gives me error

SQL> startup
ORA-27126: unable to lock shared memory segment in core
SVR4 Error: 1: Not owner

why?

      and we said...
LOCK_SGA is operating system dependent and not supported on Solaris.  I assume
you are on solaris.
Review & Followup

      Rating: 5
and
      also...  August 15, 2001
Reviewer:  Connor
       from UK
Oracle on Solaris will use intimate shared memory (use_ism = true by default)
which is "synonymous" (very loosely) with lock_sga.

August 15, 2001 Steve -- Thanks for the question regarding
      "Creating objects with raw devices on WIN 2K", version 817

      You Asked
I am little confused on raw devices and hope you can help.

We are having to set-up raw devices for OPS on Windows 2000.

First Question, can objects span multiple raw devices? For instance, say I
create a 2gb raw partition and the EMP table grows to be larger than 2gb. Can I
not just add another raw partition to the TS? I am hearing from different people
that objects cannot extend past the bounds of a raw partition, please clarify.

and Part 2,
Am I correct in assuming that there is no 2gb limit on creating raw devices on
Win 2k? I can create them as large as I want (and the file system will allow) ,
correct?

tks

Steve

      and we said...
q1) objects may span files (be they raw or cooked files) no problem there.  You
can definitely do what you describe

What they might mean is that you cannot effectively "autoextend" a raw partition
like you can a cooked file.

q2) there is large file support for win2k yes -- they can be larger then 2gig
Review &
      Followup

      Rating: 5
Thanks
      again  August 15, 2001
Reviewer:  Steve
      Montgomerie  from Dallas
Your answer is bang on. I appreciate the help

Steve

August 15, 2001 Venkata -- Thanks for the question regarding
      "Renaming Process", version Version 8.1.5

      You Asked
The process of renaming a table is taking too much time
in case of big tables because it is not just changing the
names.
What is wrong in expecting the process to be as follows

user enters Rename command

Oracle checks the new name's it uniqueness and validating the
name.

change in the data dictionery and other places wherever
there was a reference to this table. Or it can keep
a table to locate the new name and the old name for the
purpose of references only from triggers or from views, snapshots
etc.

If the above process can not be implemented please explain the
details.

Thanks

Giri

      and we said...
That is pretty much what it does.  It is not a function of the size of the table
-- its a function of how many related things there are in the database AND,
since updates to the data dictionary are serialized pretty much, a function of
what else was going on.

I ran a small test:

ops$tkyte@DEV816> select count(*) from t1;

  COUNT(*)
----------
     23293

Elapsed: 00:00:00.31
ops$tkyte@DEV816> select count(*) from t2;

  COUNT(*)
----------
     93176

Elapsed: 00:00:00.35
ops$tkyte@DEV816> select count(*) from t3;

  COUNT(*)
----------
    232942

Elapsed: 00:00:02.34
ops$tkyte@DEV816>
ops$tkyte@DEV816> set timing on
ops$tkyte@DEV816> rename t1 to t1_new;

Table renamed.

Elapsed: 00:00:00.06
ops$tkyte@DEV816> rename t2 to t2_new;

Table renamed.

Elapsed: 00:00:00.03
ops$tkyte@DEV816> rename t3 to t3_new;

Table renamed.

Elapsed: 00:00:00.03
ops$tkyte@DEV816>

showing that in single user mode, with similar tables, you would expect similar
results timewise.

It should be a rarity to rename a table, not a day to day process.  DDL can
definitely take a while in some systems (rename being DDL) as it will be
serialized (at the recursive SQL layer) to protect the data dictionary itself.

followup to comment one

Doing DDL on a system will invalidate all dependent objects.  If I rename a
table for example - every parsed query plan in the shared pool will be flushed,
all views that reference it will become invalid and will have to be recompiled,
all stored procedures will do the same and so on.

the DDL itself that modifies the data dictionary will be done in isolation
(serially), it is expensive.

On a day to day basis I want to be doing NONE of the above -- I want my plans to
stay in the shared pool forever, I don't want my views to be recompiling, I
don't want my code to go invalid.  All of these things will recover by
themselves but I'll be doing tons of extra work to do so.  Parsing and compiling
are EXCESSIVELY CPU intensive.  You will notice this going on in a busy system.

followup to comment two

recursive sql is sql we do on your behalf or sql called from sql (eg: the sql
you do in PLSQL is recursive sql as well).

when you parse a query, we run some sql to query the data dictionary to get
information about data types and such.

when you do space allocation in a dictinary managed tablespace, we do sql to get
the space

and so on -- we run lots of sql on your behalf.
Review &
      Followup

      Rating:
      4
  August 15, 2001
Reviewer:
      A reader
Can you explain more on (((()))))

""""It should be a rarity to rename a table, not a day to day
process.  DDL can definitely take a while in some systems
(rename being DDL) as it will be serialized (at the recursive
SQL layer) to protect the data dictionary itself.
"""""

      Rating:
      4
  August 15, 2001
Reviewer:
      A reader
Tell us more about recursive sql layer

August 15, 2001 -- Thanks for the question regarding "Explicit Vs
      Implicit & Temporary tables !", version 8.1.7

      You Asked
Hai Tom,

Thankyou verymuch for clearing my earlier doubt. I have some more, I hope I will
not be disppointed.....

1)I would like to store one file say LETTER.DOC into database. I followed...
DOC_MAST
--------
ID_NO    NUMBER
DOCUMENT BFILE;

Insert into DOC_MAST values (1,BFILE('C:\TEMP\','LETTER.DOC'));

Then I think, Oracle will only store a pointer to this file ? What if somebody
deletes that file ( on operating system).  Is there anyway to store the file
completely into database ? If yes, then how should I move file back from table
to O/S. ?

2) I want to create partitions as...

STOCK_MAST -->table
---------
chas_no
model
price
..
..
..
item_type  --> value is one of 'C','P','M'

Here C,P,M means Car,Power Product,Motor cycle resp.

If a record is having item_type 'C' then it should be moved to CAR_PARTITION
,similarly POWER_PARTITION,MOTORS_PARTITION and if none of these matches then
should be moved to OTHERS_PARTITION.  I think I should use HASH partition ?  But
please can u tell me how should I create it.  This is the first time I want to
use partitions.  If u can give example it would really help me.

Of the following queries, which one will be efficient (performance wise)...
SELECT * FROM STOCK_MAST
SELECT * FROM STOCK_MAST PARTITION (CAR_PARTITION);

3) My databse version is 8.1.7.  Which version  of designer2000 should I use ?
Please tell me in which order I should intall these products on one machine(NT)
.

4)  How can I reduce missing SEQUENCE no's, By using CACHE option or NOCACHE ?

5)Most people say that using EXPLICIT cursor will be good in forms to reduce
network traffic.  Because IMPLICIT cursor more than a network trip.  Which one
is good , to perform validations in forms 5.0 ?

I am doing validations on data entered by user in the following way.
This is fine if colum type is number.  Can u please modify following
function so that it will work for both Character & Number type columns.

create or replace function get_row_counts
                (p_table in varchar2,p_column in varchar2,
                            p_cdata in number ) return number
 as
     l_theCursor    integer   default dbms_sql.open_cursor;
     l_columnValue  number  default NULL;
     l_status       integer;
 begin
     dbms_sql.parse(  l_theCursor,
                     'select count(*) from ' || p_table|| '
                       where '||p_column||' = '||p_cdata,
                      dbms_sql.native );
     dbms_sql.define_column( l_theCursor, 1, l_columnValue );
     l_status := dbms_sql.execute(l_theCursor);
     if ( dbms_sql.fetch_rows(l_theCursor) > 0 )
     then
         dbms_sql.column_value( l_theCursor, 1, l_columnValue );
     end if;
     dbms_sql.close_cursor( l_theCursor );
     return l_columnValue;
 end;
/

6)  I have a situation where the end users of our 4 branches will be generating
sales invoices.  Sales invoice Report is  very slow (as this invoice table(s)
are having hugre no. of records.  To get reports quick , is there any solution.
Is using temporary tables can be a solution for this.

your help is highly appreciated....Thanks ! Thank u very much...

regs
Abdullah

      and we said...
1) correct, thats just a pointer.  You can use DBMS_LOB.LOADFROMFILE to load the
file into the database.  It would be upto the client to fetch and write the file
to the OPERATING system (or a java stored procedure can do this easily)

2) In 8i you will use a range partition where the first partition will be less
than 'D' (that'll get 'C'), the second will be less than 'N' (that'll get 'M')
and the third will be less than 'Q' (that'll get 'P').

As for which is more efficient:

SELECT * FROM STOCK_MAST
SELECT * FROM STOCK_MAST PARTITION (CAR_PARTITION);

they are two TOTALLY different queries.  the two you can compare are:

SELECT * FROM STOCK_MAST where item_type = 'C';
SELECT * FROM STOCK_MAST PARTITION (CAR_PARTITION);

Now, those return the same results and will perform the same (since we can
eliminate the 2cnd and 3rd partitions with that predicate)

3) It is 6i release 4 you want.  Install the database in it's own ORACLE_HOME,
say c:\oracle\ora81. Designer6i, and the Developer Tools - Reports6i and Forms6i
plus their associated components - can share an ORACLE_HOME but MUST NOT go into
the database home. I usually put them in c:\oracle\6itools. After installing the
software binaries, follow the instructions in the Designer6i Installation Guide
VERY CAREFULLY in order to install the Oracle Repository.

4) NOCACHE but that is like setting "slow=true".  Gaps will be there, assume
they will be there, use CACHE and don't lose sleep over gaps.  Does it really
matter if they are small or large if they are there at all??

5) tell most people that they are absolutely wrong.  IMPLICIT (select into, for
x in ( select ... )) cursor RULE -- they are faster, easier to code and consume
less resources.

They are optimized -- we recognize that a select into is an "open; fetch; fetch;
close" and do it in one call.  If you explicitly code it -- we do it in 3 or 4.

As for your get_row_counts -- thats a terrible way to do that!!!  You are not
using bind variables.  Totally slow, totally non-scalable (for one that is
worried about performance you've done absolutely the WORST thing you can!)

Here is how to write that to support numbers, dates, and string AND bind
variables:

ops$tkyte@ORA8I.WORLD> create or replace package my_pkg
  2  as
  3      function get_cnt( p_table in varchar2,
  4                        p_cname in varchar2,
  5                        p_cdata in number ) return number;
  6
  7      function get_cnt( p_table in varchar2,
  8                        p_cname in varchar2,
  9                        p_cdata in date ) return number;
 10
 11      function get_cnt( p_table in varchar2,
 12                        p_cname in varchar2,
 13                        p_cdata in varchar2 ) return number;
 14
 15  end;
 16  /

Package created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create or replace package body my_pkg
  2  as
  3      function get_cnt( p_table in varchar2,
  4                        p_cname in varchar2,
  5                        p_cdata in number ) return number
  6      is
  7          l_cnt number;
  8      begin
  9          execute immediate
 10            'select count(*)
 11               from ' || p_table ||
 12            ' where ' || p_cname || ' = :x'
 13          into l_cnt
 14          using p_cdata;
 15          return l_cnt;
 16      end;
 17
 18
 19      function get_cnt( p_table in varchar2,
 20                        p_cname in varchar2,
 21                        p_cdata in date ) return number
 22      is
 23          l_cnt number;
 24      begin
 25          execute immediate
 26            'select count(*)
 27               from ' || p_table ||
 28            ' where ' || p_cname || ' = :x'
 29          into l_cnt
 30          using p_cdata;
 31          return l_cnt;
 32      end;
 33
 34      function get_cnt( p_table in varchar2,
 35                        p_cname in varchar2,
 36                        p_cdata in varchar2 ) return number
 37      is
 38          l_cnt number;
 39      begin
 40          execute immediate
 41            'select count(*)
 42               from ' || p_table ||
 43            ' where ' || p_cname || ' = :x'
 44          into l_cnt
 45          using p_cdata;
 46          return l_cnt;
 47      end;
 48
 49  end;
 50  /

Package body created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> exec dbms_output.put_line( my_pkg.get_cnt( 'dual',
'rownum', 1 ) );
1

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> exec dbms_output.put_line( my_pkg.get_cnt( 'dual',
'sysdate', sysdate ) );
1

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> exec dbms_output.put_line( my_pkg.get_cnt( 'dual',
'dummy', 'X' ) );
1

PL/SQL procedure successfully completed.

6) the size of a table does not imply slowness or fastness.  Unless you are full
scanning this table (and have to full scan it), size doesn't mean anything.

See

http://asktom.oracle.com/~tkyte/tkprof.html
and see what queries are running slow in your report and fix them.

Review &
      Followup

      Rating:
      4
  August 16, 2001
Reviewer:
      A reader

August 16, 2001 Vikram -- Thanks for the question regarding
      "External Routines ... [OS calls in particular]...", version 8.1.6

      You Asked
Hi Tom,

1. How do I find out all the external routines used in a Database ?
      The Table/Column to query in dictionary

2. Should I be reviewing all these external routines (from a security
perspective) ?
      Say, a shared object library is created, which can run OS(Unix) commands.
The same way it runs a Pro*C executable on the Server.
      Don't these external routines run as oracle (owner of ORACLE Database),
Unix user ?
      Can I, say for example, pass something drastic like:
      /usr/bin/rm -Rf *
      to this routine ?

If, so

3. How do I restrict the external library to execute only a limited number of
scripts ?

OR

4. Make all the external OS calls to be run as a different user (on Unix, other
than oracle) ?

Yours answers to these questions will be greatly appreciated,
I would like to know how to close some security holes which exist in the
Database I support now.

Thanks
Vikram

      and we said...
1) the first thing that popped into my head was this:

select owner||'.'||name name, type, referenced_name
  from dba_dependencies
 where REFERENCED_TYPE = 'UNDEFINED'
   and referenced_name in ( select library_name from dba_libraries )
/

it won't be fast (in fact, you might just want to create table t as select *
from dba_dependencies and then run against that to fine tune it)

That'll show you the packages/procedures and so on that are dependent on a
library -- these are the extprocs

2) YES, yes you should, definitely.

The extproc service will start up under the userid the listener that spawns it
is using.  If you use the listener running as Oracle -- it'll run as Oracle!  It
could do that for sure (the rm -rf * trick)

You can (and should) run your extproc service using a Net8 listener that was run
by some other user -- just like many people run their webservers as "nobody".
Just set up a separate listener "extproc" and start it as some other user.

3) you can control the number of libraries in the system.  All libraries not
supplied by Oracle would have to be passed through to you for review I suppose.

You would get the source, and compile it yourself.

4) You should probably do this, you'll sleep better at night.

Review &
      Followup

      Rating:
      3
extprocs  August 16, 2001
Reviewer:
      Vikram  from Phoenix, USA
It was good, but I cant understand why this "risk" has not been outlined in any
documentation (about the fact that all processes are spawned off by oracle ?!!
Cause most people end up giving execute privilege on this Object, though they
dont realize that this procedure can call any executable on the OS for which
oracle has execute permission to !

But, Thanks anyway for the eye-opener

      Rating:
      3
extprocs  August 16, 2001
Reviewer:
      Vikram  from Phoenix, USA
It was good, but I cant understand why this "risk" has not been outlined in any
documentation (about the fact that all processes are spawned off by oracle ?!!
Cause most people end up giving execute privilege on this Object, though they
dont realize that this procedure can call any executable on the OS for which
oracle has execute permission to !

But, Thanks anyway for the eye-opener

August 16, 2001 Joseph -- Thanks for the question regarding
      "Conflicting answers on object privilege??", version 8.0.4

      You Asked
Tom,

In one of your answers to Shailesh you said ..

------------------------
It is, in my opinion, a security hole big enough to fly the
space shuttle through -- 10 of them across even.What I suggest is

o you immediately change the password for this account,
disabling all access to it except by valid users.

o setup another account, say "APPLICATION".  Grant CREATE
SESSION and CREATE SYNONYM to this account only for now. Nothing else.

o in the SHAILESH account, grant the barest minimal set of
priveleges the people need on the tables.  For example, if
people should only QUERY table T and use a procedure X to insert/update it --
   GRANT SELECT ON T to APPLICATION
   GRANT EXECUTE ON X to APPLICATION
do not "over" grant -- don't give them insert or anything on a
table if they do not ABSOLUTELY need it.

o in the APPLICATION schema, now create synonyms for all of the objects
   CREATE SYNONYM T for SHAILESH.T
   CREATE SYNONYM X for SHAILESH.X

------------------------

My question..

Based on my understanding from reading your other answers about rights, I
thought that a user needs to have basic INSERT/UPDATE/DELETE privilege on a
table in order for him/her to execute a procedure that inserts/updates/deletes a
table. But you are saying that by removing table privileges and granting execute
privilege on a procedure that does DDL on a table, a user can execute the stored
procedure which in turn inserts/update/deletes on table that he has no right
too??? Is this relating to your DEFINER's / INVOKER's right stuff?

Thanks.

      and we said...
Sorry if you got that impression - I never meant to relate to anyone anywhere
that you needed both "insert" and "execute"-- Its always been "execute" INSTEAD
OF "insert".

Thats the power of the procedure, I can write a trusted process that does
whatever checks and inserts the data.  I grant access on that procedure to some
other user.  They can indirectly insert into the table now but ONLY via the
procedure.

Yes, this relates heavily to invokers/definers rights.
August 16, 2001 rd -- Thanks for the question regarding "is
      cursor for loop an implicit cursor?, sql plus questions, and parallel
      dml", version 8.1.5

      You Asked
X.

http://asktom.oracle.com/pls/ask/f?p=4950:8:63566::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:1180618018840,
"
The whole story is that

o implicit cursors are easier to code by their very nature. (i'm including
cursor for loops in here as well -- not just select intos)

o implicit cursors run faster

o implicit cursors are easiest to understand in the code, less code to read
through, less code to manage.
"

Tom, some basics needs to be cleared here:
We dont code implicit cursor, they are automatically created by oracle
implicitly, then why do you repeately say
'implicit cursors are easier to code by their very nature'

and you say '(i'm including
cursor for loops in here as well -- not just select intos)'

do you mean that a cursor for loop is a implicit cursor, how come. In order to
use a cursor for loop, youshould
first create a cursor, isnt it? and once you create a cursor then it become or
is known as explict cursor. Kindly

clarify .

I.
what is the difference between
x number and
x integer

give me values which are valid for x number , and not valid for x integer.

x number;  -- what is the max value of storage in this case

II.
Why is time statistics from tkrpof better than set timing on. Why is set timing
not accurate.

I get a figure like 134 for secons when I set the timing on . does it mean 2
minutes and 14 seconds.
When you get a value like real: 3244 , when using set timing on how will you
convert it
into minutes and seconds.

III
do you suggest me creating a package even if I have only a single procedure for
my process.
Why?

IV
what is the purpose of v$session_longops, what kind of long operations are
logged into it.
Is the functionality of v$session_longops the same as
dbms_application_info.set_client_info.

V
Does parallel query work only against partitioned table. Why?

What should I do to set up parallel query, should I set up some init.ora
parameters, and give hints in the query.

Is it mandatory to specify the degree of parallelism as hint to a query.

How does a single query get split into so many parallel queries. What is the
guarantee that the slave queries dont

selec the same rows. How do the split parallel queries select different rows.
And then how are all the results

merged.

Vi
From on of your previous answers
"
because SQLPlus uses only one cursor for your statements.  PLSQL caches and
keeps many cursors open for you.  PLSQL is optimized for running SQL and PLSQL
in the database.  SQLPlus is just a simple little interface.

"
can we make the sqlplus use more cursors than one, is it the same case with any
front end tool like pl/sql

developer and sql navigator. Can we control the number of cursors cachable for
pl/sql.

Vii. Why is ddl in plsql considered very expensive, why not the same with dml?
Viii.How do you manage to minimize the context switches between sql engine and
pl/sql engine. How should we code
to achieve this objective.
If I have a cursor in my procedure which does a select for each loop, then there
is switch between pl/sql engine

to sql engine for every loop ,Iam I right.
Suppose if a function is called in a sql statement, will there be a switch to
pl/sql engine?

IX.This is a question which has been bugging me for a lot of time.
Even a procedure can return a value like a function. Then what is the actual
difference between a function and a procedure. This is a often asked interview
question too.

      and we said...
whew, been getting some pretty looonnngg questions.  Ok, here we go

X. Here is an explicit cursor:

declare
   cursor c is select * from emp;
   l_rec   c%rowtype;
begin
   open c;
   loop
        fetch c into l_rec;
        exit when c%notfound;
        ....
   end loop;
   close c;
end;

Here is the same thing with an implicit cursor:

begin
    for l_rec in ( select * from emp )
    loop
        ...
    end loop;
end;

If you don't see the word "cursor" anywhere, you have an implicit one.  It is
true that you can also:

declare
   cursor c is select * from emp;
begin
   for l_rec in c
   loop
      ...
   end loop;
end;

and I would call that an implicit cursor as well.  If you (you personally) do
not do the cursor managment (open, close, fetch, %isopen, %notfound, etc) it is
implicit.

I.  difference between number and integer.

This is like asking a C programmer whats the difference between a float and an
int.

An integer is alot like a number(38,0) -- in fact, it is.  It has 38 digits of
precision but NONE of those digits appear to the right of the decimal point.

A number has 38 digits of precision, and might have a fractional component.

Here is the difference:

ops$tkyte@ORA8I.WORLD> create table t ( x int, y number );

Table created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1.555, 1.555 );

1 row created.

ops$tkyte@ORA8I.WORLD> select * from t;

         X          Y
---------- ----------
         2      1.555

ops$tkyte@ORA8I.WORLD>

X will round to the nearest integer, Y will preserve every digit (upto 38 of
them)

II. Set timing on -- say you use it with autotrace (many try).  It times the
autotrace stuff as well as your query -- autotrace can add tons of overhead (v$
table queries can be very slow)

Say you use set timing on with: select * from really_big_table.  that timing
will include the time it takes sqlplus to paint the screen and scroll, or write
to a spool file.

I'm interested in how long the query takes in the server -- thats all tkprof
reports.

As I recall -- the times where in thousands of seconds so 3244 would be 3.244.
A quick and dirty way to confirm (or deny) this would be:

SQL> set timing on
SQL> exec dbms_lock.sleep(1)

if that puts out 1000, then it was thousands, if it puts out 100 then it was
hundredths (div by 100, not 1000 to get seconds)

III

If that procedure is called by another procedure -- yes.  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:286816015990
for why

IV

I have a good chapter on this in my book -- in the section on
dbms_application_info in the necessary supplied packages guide.  See also:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:927351834270
it shows how you can use this table -- if you use dbms_application_info you too
can populate it

V

False, we dynamically partition objects for parallel query.  Parallel
updates/deletes (parallel dml) works against partitioned objects only.

To test with this, you can set parallel_min|max_servers and use some hints to
see how it works.  You can also set parallel_automatic_tuning and set the
default degree of parallelism on the tables themselve (but the hint would be
better for just testing purposes as it won't affect anyone NOT doing the hints)

As for the "how does parallel query work" -- i'll refer you to the docs.
Suffice it to say that they never get the same rows as they all work on
non-overlapping rowid ranges.  see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c22paral.htm#22669
VI

No, you cannot change the way SQPlus is coded - think about how you would write
sqlplus -- you would have a cursor and as the end user input a statement you
would parse and execute it.  thats what plus is doing.

PLSQL is not a "front end" tool IMO - its a back end tool, its in the server.
It is optimized to do one thing -- execute tons of SQL really efficiently.  I
would say most front end tools are not optimized this way (forms is however)

VII

DDL invalidates objects in your database.  Drop an index/Add an index -- views
go invalid.  Alter a table -- procedures/views/triggers go invalid, etc.  Doing
DDL changes things and invalidates lots of things.  This is bad in a production
(stable) system.  You don't want things going invalid

DDL is serialized.  Data dictionary changes are expensive.

DML does not do the above.

VIII (you know what, roman numerals are a pain ;)

You can minimize it by using BULK operations in PLSQL (less switching from PLSQL
to SQL.  10 Array inserts of 100 rows -- much faster then 1000 inserts of a row.
 1 fetch of 100 rows -- much faster then 100 single row fetches.

If a function is called in SQL, there is a switch from sql to plsql for each
call.  Function based indexes can virtually eliminate this.   Use of application
contexts are another alternative (if you are just trying to parameterize a view
or something)

IX

A function in PLSQL (as with most languages) is simply a PROCEDURE that can
return a value.  It is nothing special.

Some people feel functions should have only IN parameter and a single output.  I
disagree.

A function is nothing more then a procedure with an extra un-named OUT
parameter.

Review &
      Followup

      Rating: 5
but , more
      discussion on IX, please  August 17, 2001

Reviewer:  joseph  from USA
Tom

You have to illustrate you statement
'Some people feel functions should have only IN parameter and a single output.
I
disagree. '

and

what do you mean by unnamed out parameter.

thank you

          Followup:

Lets say you have a procedure:

create procedure p( x in number, y in number, z out date )
as
begin
   z := sysdate+x+y;
end;

That could be written as:

create function f( x in number, y in number ) return date
as
begin
   return sysdate+x+y;
end;

Here the function F is effectively the same as procedure P -- the return value
is like an "un-named" (anonymous) OUT parameter.  The return value is in place
of Z in the procedure.

August 17, 2001 lisa -- Thanks for the question regarding
      "Hardware specs", version 9i

      You Asked
We are implementing an web site using the Oracle 8i database server and
application server 9i.  Is it necessary to have two separate physical servers
for each of these applications?  What if our volume is anticipated to be rather
small?

      and we said...
I use one server (hardware) to run asktom (and osi.oracle.com and
www.promedmail.org and oai.oracle.com and many other sites).

You do not need two physical boxes, all of the above and more is running on one
physical machine (a 4cpu e450 sparc) with reserve capacity.
August 17, 2001 rajinikanth -- Thanks for the question regarding
      "Export & import and miscllaneous", version oracle7.x-8.x

      You Asked
Hi,

1.I want to know how to take an export of oracle816  and import into into an
oracle7.3.2.Could you please tell me what are all the steps and scripts to be
run.

2.How to use operating system login(OPS$) to connect to oracle through the
client sql.
To be more specific,I've installed oracle816 in my pc. We've many databases with
differnt versions & different operating system.Say I want to connect an
oracle7.x of VMS OS or any UNIX OS from my pc. I've all the databases entries in
my local tnsnames.ora.I can connect as sys or system for any database.I want to
know about the OPS$ account.

3.ANALYZE Table test compute statistics.Can I use the option for all index
statistics with this command. If so please explain me.

4.Rollback segments are used for all dml statements. So does it mean the
rollback segments exists in sga if the queries are in the MRU-LRU list,even
though its been created inside a tablespace. Or any buffer image exists for
rollback segments. If this is a stupid question ,please excuse me.

Many thanks

Rajini

      and we said...
1) You would run catexp7 in the 8i database.  This is found in
$ORACLE_HOME/rdbms/admin, should be run using svmrmgrl when connected as sys.

You would then use the 7.3 EXP tool over sqlnet to do the export. DO NOT use the
8i export tool, that dmp file will not be readable by the 7.3 imp.

2) I could tell you how to do this however, it would open a security hole big
enough to fly a jumbo jet through.  All anyone would have to do is create a Unix
account using your name they are in your database as you.  Very very insecure.

Don't do this.

3) analyze table test compuate statistics
   for table
   for all indexes
   for all indexed columns;

will get stats on the table, all indexes on it, and compute histograms for
indexed columns.

4) a rollback segment is buffered (cached) in the SGA just like anything else.
Rollback is written to by DML, read by Queries (DML do queries as well so DML
will actually read and write rollback)

August 17, 2001 Hugh -- Thanks for the question regarding "How
      truncate is handled during recovery using archived logs", version 8i

      You Asked
What happens to the truncated table if I do a recovery using archived logs to a
point in time later than when the truncate coammand was issued ? Would the table
essentially be truncated and all transactions after the truncate be re-applied ?

For example, I insert and commit 100 rows in table A at 1 am. I backup at 2am
(still 100 rows in table A). I truncate table A at 3am. At 4am I insert 50 rows
in table A and commit. at 4:05 am I deleted the data files and all the online
redo logs because I started to sleep on the job. I started recovery using my 2am
backup and applied all archived redo logs until 4:04 am. Will I have 50 rows in
table
A or 150 rows (I do not have a unique index on table A).

Thanks very much.

      and we said...
Yes, that is what would happen.  We would recover the table -- hit the truncate
(which just updates the data dictionary) and then begin recovering the table
again.

It will work, the table will be restored.

You will have 50 rows.
Review & Followup

      Rating:
      4
  August 17, 2001
Reviewer:  Sean
       from Atlanta
Not the 100 rows though

          Followup:

Correct, the last 50 rows inserted will be there after a PITR to 4:04am

August 17, 2001 -- Thanks for the question regarding "Query
      returns length as 8", version 8.1.7

      You Asked
QUERY :
SELECT TO_CHAR(1234, '0000000'), length(TO_CHAR(1234, '0000000')) from dual;

OUTPUT :
TO_CHAR( LENGTH(TO_CHAR(1234,'0000000'))
-------- -------------------------------
 0001234                               8

why is there a leading "space" and why is the length showing as "8" ?

Thanks,
Uday

      and we said...
Maybe if you look at it like this:

  1* sELECT TO_CHAR(-1234, '0000000'), length(TO_CHAR(-1234, '0000000')) from
dual
ops$tkyte@ORA8I.WORLD> /

TO_CHAR( LENGTH(TO_CHAR(-1234,'0000000'))
-------- --------------------------------
-0001234                                8

it makes more sense.  it is there for the SIGN.  You can get rid of it like
this:

ops$tkyte@ORA8I.WORLD> SELECT TO_CHAR(-1234, 'fm0000000'), length(TO_CHAR(-1234,
'fm0000000')) from dual
  2  /

TO_CHAR( LENGTH(TO_CHAR(-1234,'FM0000000'))
-------- ----------------------------------
-0001234                                  8

ops$tkyte@ORA8I.WORLD> SELECT TO_CHAR(1234, 'fm0000000'), length(TO_CHAR(1234,
'fm0000000')) from dual
  2  /

TO_CHAR( LENGTH(TO_CHAR(1234,'FM0000000'))
-------- ---------------------------------
0001234                                  7

useing the fm (format modifier) mask, the blanks will be trimmed.
Review &
      Followup

      Rating: 3
Query returns
      length as 8  August 17, 2001
Reviewer:  Uday
      Addala  from NJ, USA
Good and fast response.

August 17, 2001 Ioulia -- Thanks for the question regarding
      "nested table", version 8.1.7.1

      You Asked
Hi Tom,

I have a very odd problem. I hope that you will be able to help me (as it
happened before).
Below are 2 scenarios that I tried.
With the scenario #1 I am getting an error: Invalid column name
With the scenario #2 * is fine, I am getting results
v_dhk_except is my nested table.
v_cursor is ref cursor.
Scenario #1:
v_sql := 'select * from table (cast(v_dhk_except as t_dhk_except))';
open v_cursor for v_sql; => error Invalid column name
Scenario #2:
open v_cursor for select * from table (cast(v_dhk_except as t_dhk_except)); =>
no errors. I am getting results.

Any suggestions?

I appreciate your response. What I really need is scenario #1, since I need to
pass sql string to owa_sylk package.
Thank you.
Ioulia

      and we said...
In the dynamic sql version, the variable v_dhk is "out of scope" -- you are not
in PLSQL opening a cursor, you have bypassed PLSQL and have gone right to the
SQL engine.

You cannot reference any local variables like that.  Now, what you can do is
BIND in the value of v_dhk_except.  For example:

ops$tkyte@ORA8I.WORLD> create or replace type myArrayType as table of number
  2  /

Type created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> variable c refcursor;
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> declare
  2          array myArrayType := myArrayType(1,2,3,4);
  3  begin
  4          open :c for 'select * from table (cast(:x as myArrayType))' USING
array;
  5  end;
  6  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> print c

COLUMN_VALUE
------------
           1
           2
           3
           4

ops$tkyte@ORA8I.WORLD>

However -- that won't work with my owa_sylk stuff since that uses DMBS_SQL, not
Native Dyanmic SQL (and no, it cannot be written to use Native dynamic -- it
needs the funcationality of dbms_sql)

So, how to do this in DBMS_SQL?  Easy -- make a function that returns that table
variable --  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:110612348061
for an example.  Then, you can bind in a simple comma delimited string that I'll
parse into a collection type and return.

August 19, 2001 Jay -- Thanks for the question regarding "Errors
      not explained in Oracle Documentation - ORA-1536", version 8.1.5

      You Asked
Hi Ari,

Salutations to my virtual guru ..

I have 4 tables in a single tablespace , when I try to insert data into three of
the tables Oracle accepts it without any problem.

But , when I do "insert into" on the fourth table ( it has about 100 rows) I get
a quota exceeded error.

Aren't all the table's supposed to use the same tablespace , how is it that only
'one' table says , quota exceded ?

btw, I did a "alter user...quota unlimited" and solved the problem ,
I had revoked unlimited tablespace to that user earlier.

Can you please let me know the reason why I got the ORA-1536 for one table.

And where do I get to see the error numbers which are not available
in Oracle documentation.

Thank you,

Jay

      and we said...
If all 4 tables are in the same tablespace -- they use the same tablespace.
There is no rule saying all four will be in the same tablespace however.

Assuming they were in the same tablespace, the reason why you got the ORA-1536
on the 4th insert is because the first three tables were able to accomidate your
data without having to GROW -- they had sufficient space allocated to them.  The
fourth table however was "full" - by inserting a new row you caused the table to
attempt to allocate more space.  However, that would have caused the owner of
the table to exceed their QUOTA on that tablespace.

So, that is why you got the 1536.

Any undocumented error codes would be an oversight, they should all be
documented.  Do you have a specific one?  ORA-1536 is documented so that isn't
the one...
Review & Followup

      Rating: 4
Thank
      you  August 19, 2001
Reviewer:  Jay Shankar
       from India
The error is documented ... but your answer is more clear.

August 19, 2001 Doug -- Thanks for the question regarding "What
      to do if open_cursor reached in 24x7 environment?", version 8.1.7

      You Asked
Tom - I'm curious what to do if an open cursor limit is reached in a 24x7
environment.  I don't believe it's a parameter that can be dynamically changed,
but I could be wrong.  That would change things a little I think, but even so,
is there any way to force a close of certain cursors that I am confident are not
needed?  Or is one pretty much stuck with bouncing the database with a new
value?  I know these things should be sized correctly before even starting, this
is just a "what if" sort of thing.

      and we said...
Well, in a 24x7 environment -- it is my opinion you would have detected the max
open cursor exceeded in testing before deploying the application.  You would
have fixed the issue way before it ever got to that machine that cannot be
restarted.

There is no way for you to externally close cursors for a session from another
session (and frankly -- I don't see how you know they could be closed unless the
application is "leaking" them and hence the application should be corrected so
as to not leak them -- if you KNOW they won't be reused ever in the app, the
developer of the app KNOWS this as well and should have closed them).

What if the resource was "open files" and the developer exceeded max open files?
 Would you try to dynamically rebuild the unix kernel or have the developer fix
the application?

In any case, in 8i you cannot change this parameter dynamically for the system.
In 9i however, you can:

Oracle9i Enterprise Edition Release 9.0.1.0.0 - Production
JServer Release 9.0.1.0.0 - Production

ops$tkyte@ORA9I.WORLD> alter system set open_cursors = 5000;

System altered.

but if your apps are leaking cursors, this is just something that will allow
them to run a little longer.  Ultimately -- they'll hit this again.

August 19, 2001 Omar -- Thanks for the question regarding
      "Different Questions", version 8.1.7

      You Asked
Hi Tom,

We are all , Oracle lovers, appreciate your efforts.

I have a lot of question , I really want you to spare no pain to clarify.
1. I am a dba in a university and we have only one database we work from 8am -
5pm. What is the best strategy to take backup , what to use , RMAN or sql
statement , shall I ran my DB in archivelog mode or not. shall I shutdown the db
and take physical backup or I always take hot backup.

2.In 9iAS How to run pl/sql procedure without writing in the URL /pls

      and we said...
1) if you value your data at all -- if you cannot lose work you have done -- you
will run in archivelog mode.  Period, plain and simple.  If you do not, I can
assure you 100% that some day you will lose 8 hours, 59 minutes and 59 seconds
of work (all that was done from 8am to 5pm).  Archivelogmode is the only mode
for a production system that has changes applied to it (eg: a data warehouse
might not need this).

Since you are running in archivelog mode -- your backups should all be HOT
backups. You want to shutdown only when forced to -- never to take a backup.
The database runs better if it is allowed to stay "warm".  Otherwise every
morning you will spend much time reparsing the same queries you did yesterday,
the day before and so on.  Your cache is cold, you'll do more IO then you need
and so on.

To take the backup, it depends.  If you have a small number of databases --
using good ole "tar" or "cp" works just fine.  RMAN is good when you have lots
of databases to deal with as the recovery catalog does the book-keeping for you.
 There are also features available with rman that are not otherwise like
incremental backups and tablespace point in time recovery.  Whether these are
relevant to you -- you must decide.

Just make sure you keep AT LEAST two backups (never right over your last
backup).  That is a fatal mistake.  Its happened more then once that a disk
fails AS you are backing it up -- that means you don't have a backup of that
file from the disk that failed anymore.  Its really ugly -- don't get caught in
that.  Keep the last N backups (5 makes me sleep better at night) to protect
yourself.

(btw: shutting down the database would give you a "consistent" backup, both HOT
and COLD are physical backups)

2) when you map the URL, don't include /pls/ in it. for example, on of my
mappings is:

# this is for AUTHENTICATED requests against the people system
<Location /plsa>
  SetHandler pls_handler
  Order deny,allow
  Allow from all
</Location>

there my url is /plsa/.....  instead of /pls/
Review &
      Followup

      Rating: 3
Hi
      tom  August 21, 2001
Reviewer:  C Vivek Anand
       from Hyderabad
Tom to say the fact ,these  answers are some or other way definitely very
informative .U may be going through a simple question's answer but u definitely
can get some very valuable point in the simple answer itself .The answers are
very meticulously written.

Hats off tom

August 19, 2001 ashraf -- Thanks for the question regarding
      "oracle tuning", version 8i

      You Asked
 when i run the this sql i get :

select empno,ename,(select loc from dept where emp.deptno=dept.deptno),
(select dname from dept where emp.deptno=dept.deptno) from emp;

Statistics
----------------------------------------------------------
          0  recursive calls
          4  db block gets
         14  consistent gets
          0  physical reads
          0  redo size
       1544  bytes sent via SQL*Net to client
        425  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         14  rows processed

select a.empno,a.ename,b.loc,b.loc from emp a,dept b where a.deptno=b.deptno;

Statistics
------------------------------------------------------
          0  recursive calls
          8  db block gets
          3  consistent gets
          1  physical reads
          0  redo size
       1448  bytes sent via SQL*Net to client
        425  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
         14  rows processed
can you explain whey different db block gets,consistent gets

second:
in database tuning i found a lot of variable like recurisve calls where can i
found this variable defination

best reg
ashraf gamal

      and we said...
The first query is done like this:

  for x in ( select * from emp  ) loop     <<<=== x blocks for full scan
       select loc from dept where ...;     <<<=== x2 blocks for index scan+table

                                                  access/rowid
       select dname from dept where ....;  <<<=== x3 blocks for index scan+table
                                                  access/rowid
       output empno, ename, loc, dname
  end;

So, the total number of blocks processed is X + number_rows_in_emp * (x2+x3)

The second query was probably more like (assuming it full scanned EMP and then
index read dept:

   for x in ( select * from emp ) loop  <<<==== x block for full scan
           select loc, loc from dept    <<<==== x2 blocks for index scan+table
                                                access/rowid
           output record
   end loop

total number of blocks processed is X + number_rows_in_emp * ( x2 )

it just did less work since it didn't have to do the two subqueries.....

The designing and tuning for performance guide is a great place to start, for
example:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/ch14_str.htm#1395

....
Review
      & Followup

      Rating:
      4
  August 20, 2001
Reviewer:  ashraf
      gamal  from kuwait


Subject | Article | Last Updated (East coast time)
bind variables | article only | Aug 20, 2001 02:45 pm
Debugging PL/SQL program | article only | Aug 20, 2001 03:01 pm
about ' oracle9i for linux' install on Redhat linux 7.0 | article only | Aug 21, 2001 08:14 am
How will we know when you update my question post | article only | Aug 21, 2001 11:12 am
can store procedure reduce parse? | article only | Aug 22, 2001 04:19 pm
OS User and Data File Droping | article only | Aug 22, 2001 09:09 pm
Package Vs Sub-program | article only | Aug 23, 2001 08:24 am
sort using index | article only | Aug 23, 2001 08:55 am
create domain index parameters | article only | Aug 23, 2001 11:21 am
Dropping objects or user | article only | Aug 23, 2001 12:52 pm
pl/sql - ref cursor problem | article only | Aug 23, 2001 01:38 pm
Miscallaneous 082101 | article only | Aug 23, 2001 03:26 pm
Temporary Tablespaces & Local Management | article only | Aug 23, 2001 07:31 pm
Maximum Row Size | article only | Aug 24, 2001 08:02 am
"Encrypt" Procedures | article only | Aug 24, 2001 08:23 am
Sql Loader | article only | Aug 24, 2001 12:01 pm
DBMS_JOB | article only | Aug 24, 2001 06:42 pm
Another COUNT performance question | article only | Aug 24, 2001 06:47 pm
native dynamic sql, dynamic sql and dbms_sql | article only | Aug 25, 2001 01:18 pm
control | article only | Aug 25, 2001 01:34 pm
v$session_longops | article only | Aug 26, 2001 08:13 pm
row(s) 1 - 21 of 21
August 20, 2001 Suresh -- Thanks for the question regarding "bind variables", version 8.1.7
You Asked
Tom,
  I have been going through your book and it is really good. Following is the
database procedure that I am using to disable all constraints in a schema.
Please let me know how can I modify it to use bind variables.

CREATE OR REPLACE PROCEDURE DISABLE_CONS AS
cons_name    varchar2(30);
table_name   varchar2(30);
CURSOR FIRST_CURSOR IS
     SELECT TABLE_NAME,CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE
     STATUS = 'ENABLED' AND CONSTRAINT_TYPE = 'C';
CURSOR SECOND_CURSOR IS
     SELECT TABLE_NAME,CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE
     STATUS = 'ENABLED' AND CONSTRAINT_TYPE = 'P';

BEGIN
 OPEN FIRST_CURSOR;
 LOOP
   FETCH FIRST_CURSOR INTO table_name,cons_name;
   EXIT WHEN FIRST_CURSOR%NOTFOUND;
   EXECUTE IMMEDIATE ' ALTER TABLE ' || TABLE_NAME || ' DISABLE CONSTRAINT ' ||
CONS_NAME;
 END LOOP;
   CLOSE FIRST_CURSOR;

    OPEN SECOND_CURSOR;
 LOOP
   FETCH SECOND_CURSOR INTO table_name,cons_name;
   EXIT WHEN SECOND_CURSOR%NOTFOUND;
   EXECUTE IMMEDIATE ' ALTER TABLE ' || TABLE_NAME || ' DISABLE CONSTRAINT ' ||
CONS_NAME ||' CASCADE';
 END LOOP;
   CLOSE SECOND_CURSOR;
END;
/

Thanks.
and we said...
You cannot use bind variables in DDL, only DML and queries.  (you'll also notice
that DDL isn't there in the shared pool, we get it out of there so the
efficiencies of bind variables would be lost on it)

I can say the code would be more readable and efficient if you coded simply:

create or replace procedure disable_cons
as
begin
   for x in ( select table_name, constraint_name
                from user_constraints
               where status = 'ENABLED'
                 and constraint_type in ( 'C', 'R', 'P' )
               order by decode( constraint_type, 'C', 1, 'R', 2, 'P', 3 ) )
   loop
        execute immediate 'alter table ' || x.table_name ||
                          ' disable constraint ' || x.constraint_name;
   end loop;
end;
/

Implicit cursors are

o faster
o easier to code
o easier to read
o more efficient
o better

than explicit cursors.

Additionally using the in and order by falls in line with my mantra:

o if you can do it in a single sql statment, do it.
o if not use a little plsql
o if plsql cannot do it (eg: send an email with an attachment) try a little java
o if that doesn't do it (too slow or you have existing 3gl code) do it in C via
an external procedure
August 20, 2001 Rengasamy -- Thanks for the question regarding "Debugging PL/SQL program", version 8.1.7.0.0
You Asked
Hi Tom,

I have a PL/SQL procedure as follows:

    begin
        for i in ( select empno, ename from emp )
        loop
           insert into table1
           ( empno, ename) values ( i.empno, i.ename ) ;
        end loop ;
    end ;

    The table TABLE1 has the following two columns
              EMPNO  NUMBER (4)
              ENAME  VARCHAR2 (5)

Assume that table emp has 1000 rows and for some of records the length of ename
is more than 5. Now i got following error:

    ORA-01401: inserted value too large for column
    ORA-06512: at line 4

I know the reason why it fails. In my actual program, i have 5 inserts in the
loop. when i got this error, i was not able to find for which column, this error
occurs. How to identify this. Is there any way to find the insert statement
executed when i got the error.

Thanks
and we said...
There is no direct way to do it, what I can recommend is to use a procedure to
do the inserts and validate the data.  Here is a script you can use to generate
just such a procedure.  On the dept table, it'll build a procedure like:

create or replace procedure insert_dept(
p_DEPTNO in dept.DEPTNO%type default null
,p_DNAME in dept.DNAME%type default null
,p_LOC in dept.LOC%type default null
)
as
l_DEPTNO dept.DEPTNO%type;
l_DNAME dept.DNAME%type;
l_LOC dept.LOC%type;
begin
begin l_DEPTNO := p_DEPTNO; exception when others then
raise_application_error( -20001, 'Column DEPTNO failed...' ); end;
begin l_DNAME := p_DNAME; exception when others then
raise_application_error( -20002, 'Column DNAME failed...' ); end;
begin l_LOC := p_LOC; exception when others then
raise_application_error( -20003, 'Column LOC failed...' ); end;
insert into dept (
DEPTNO
,DNAME
,LOC
) values (
l_DEPTNO
,l_DNAME
,l_LOC
);
end;
/

It does the validation -- catches any data errors and raises a unique error that
includes the column id in the error code or inserts the data.  Your application
will call:

  insert_dept( 10, 'research', 'boston' );

intead of codeing:

   insert into dept (deptno,dname,location) values ( 10, 'research', 'boston' );

-------------- gen_insert.sql ----------------------------------
set heading off
set feedback off
set embedded on
set verify off
set linesize 255
set trimspool on

spool tmp.sql

prompt create or replace procedure insert_&1(
select decode(column_id,1,'',',') ||
        'p_' || column_name || ' in &1..' ||
        column_name || '%type' ||
       ' default null'
  from user_tab_columns
 where table_name = upper('&1')
 order by column_id
/
prompt )
prompt as
select 'l_' || column_name || ' &1..' || column_name || '%type;'
  from user_tab_columns
 where table_name = upper('&1')
 order by column_id
/
prompt begin

select 'begin l_' || column_name ||
          ' := p_' || column_name ||
          '; exception when others then ' ||
          ' raise_application_error( ' || (-20000-column_id) ||
          ', ''Column ' || column_name || ' failed...'' ); end;'
  from user_tab_columns
 where table_name = upper('&1')
 order by column_id
/
prompt insert into &1 (
select decode(column_id,1,'',',') || column_name
  from user_tab_columns
 where table_name = upper('&1')
 order by column_id
/
prompt ) values (
select decode(column_id,1,'',',') || 'l_' || column_name
  from user_tab_columns
 where table_name = upper('&1')
 order by column_id
/
prompt );;
prompt end;;
prompt /

spool off
set heading on
set feedback on
set verify on
---------------------------------------------------------------
Review & Followup
Rating: 4
Maybe this can help (Even though Tom does not like to use "WHEN OTHERS") August 20, 2001
Reviewer: Suresh
 begin
   for i in ( select empno, ename from emp )
   loop
      BEGIN
        insert into t1(empno,ename) values
                      (i.empno,i.ename ) ;
     EXCEPTION
         WHEN OTHERS THEN
           BEGIN
             DBMS_OUTPUT.PUT_LINE (i.empno||' '||i.ename);
             RETURN;
            END;
          END;
  end loop ;
 end ;

Followup:
Hey - I used a when others in my code above!  ;)

I don't like "when others" that are not followed by a RAISE to re-propagate the
error or raise_application_error to raise a more specific one.

I would suggest changing the return in your exception block to a RAISE; that
way, you can see the dbms_output stuff (SQL> exec null will dump the buffer) AND
you know an error ocurred.

Rating: 3
Useful August 21, 2001
Reviewer: Rengasamy Balasubramanian from Singapore
Hi tom,

The answer is very useful when we start development fresh. But when i get the
error like insert value too large or value error for the existing application, i
need the insert statement. Because Now i cannot modify the code in existing
application.

Thank you for your answer.

Bala

Rating: 3
Useful August 21, 2001
Reviewer: Rengasamy Balasubramanian from Singapore
Hi tom,

The answer is very useful when we start development fresh. But when i get the
error like insert value too large or value error for the existing application, i

need the insert statement. Because Now i cannot modify the code in existing
application.

Thank you for your answer.

Bala

August 21, 2001 befresh -- Thanks for the question regarding "about ' oracle9i for linux' install on Redhat linux 7.0", version 9.0.1
You Asked
hi,tom
    i installed oracle8.1.7 on redhat 7.0,but oracle9i is wrong,
i don't know how i may do?
    please tell me  steps about install oracle9i.

thanks

befresh
and we said...
You must wait until it is released for redhat -- which should be the end of this
month/beginning of next month.  (as of August 21, 2001)

Right now, only the Suse distribution is available (as it says on technet "Note:
Oracle9i for Linux is certified on SuSe7.1, Kernel 2.4.4 and the operating
system library GNU Lib C 2.2 only.")
August 21, 2001 nag -- Thanks for the question regarding "How will we know when you update my question post", version 8.1.7
You Asked
Hi Tom

I see that nowadays you are replying in the comments area. This is proving to be
very useful. We dont have to post new questions on the same subject.

But how will we know , if you update a old post in response to a question. If I
had posted a question and you have answered it, and then after one month ,
someone posted a question as a comment  and you update my question.

Then how will I know that my post has been updated. I want to know because, I
will be interested, in following my post. That might be helpful to me.

You have to do something about this.

Thank you
and we said...
Well, this is what happens.

When the author of the question updates the question using the link I sent to
them (they get a special link) I notify them that I updated it.  So, if you put
a review on your question and I follow up, I'll let you know.

If someone else puts a review on there and I followup -- I look at what is being
asked in the review and how old the question is.  If I feel the followup is
truly relevant (eg: I changed my mind or guidance or the information provided is
something I feel the author of the original question should have) I notify the
original questioner.  If the question is pretty old (2 or 3 months is really old
to me) or the followup isn't particularly relevant in my opinion, I don't do
that.

So, it already happens in a fashion, I just do it based on my judgement.

Let's use this question as a VOTE.  Would people be interested in the ability to
be automatically notified anytime a review/followup was added to their question
(only their question -- not any question, I don't have the capacity to email
everyone when some question is modified).  Would you find that useful?  Just
followup this question and I'll see if there is enough interest.  Then you won't
be relying on my judgement, you'll just get the email whenever the question is
updated.
Review & Followup
Rating: 5
I want to be emailed every time August 19, 2001
Reviewer: Andrew from UK
I will be interested in knowing all the follow up to my question, even if it
does not deal exactly with the question I asked.

My vote is for getting an email for each follow up to my question.

Rating: 3
VOTE August 20, 2001
Reviewer: A from INDIA
My vote is for getting an email for each follow up to my question.

Rating: 5
I would like to be emailed whenever there's a followup on my question. Thanks TOM. August 20, 2001
Reviewer: Raj from USA

Rating: 4
Review of comments August 20, 2001
Reviewer: Bhavesh from Singapore
Yes Tom, I would certainly like to review all the comments to the question what
so ever I post. I will VOTE in FAVOUR of having a system having ability to
automatically notify anytime a review/followup was added to the author of
question.
Regards

Rating: 5
Ak from swiss August 20, 2001
Reviewer: Ak from swiss
Yes tom, i will appreciate if you Include this
Feature Here.

Rating: 5
Just to be difficult... August 20, 2001
Reviewer: Connor from UK
I don't think the email is required - like any "public" forum, it makes sense to
come back every once in a while and look at AskTom and look at questions that
are NOT your own even if they do appear to be relevant. I think an email just
encourages you to look at only your own questions and no-one elses, which IMHO
equates to less learning.

Rating: 5
regarding "How will we know when you update my question post" August 20, 2001
Reviewer: Sasa Stefanovic from Yugoslavia
Yes, Tom,

i think it is very useful.

Thanks for your good will.

Rating: 5
Great Idea August 20, 2001
Reviewer: Joel K. from Columbus, OH USA
Tom, I think this would be a great idea!

Rating: 5
I want to be mailed every time. August 20, 2001
Reviewer: Rakesh Tripathi from Ahmedabad, Gujarat, INDIA
Yes, I would like to be mailed very time.

Thanks,

Rakesh.

Rating: 5
It is "ask Tom", not an narrative notification system within a company August 20, 2001
Reviewer: Reader from USA
Hi,

I agree with Cornor. After all, this site is "Ask Tom" not ask somebody else, so
you must continously come back now and then to referesh and learn more stuffs
from the questions of both yoursself and others. On the other side, not all of
the followups by others are relevant to the original issues by yourself, and it
is very difficult to determine.

Rating: 5
My Opinion August 20, 2001
Reviewer: Jim Spofford from Dallas
Tom, This forum goes hand-in-hand with my daily cup of coffee (i.e., I read it
from the website each day). Responding to comments in the comment section makes
a topic much more readable (no paging up and down, counting comments). However,
my concern is that when you do reply to a comment in the comment section, I
would still like the topic reposted in the "Recent Questions" section (which is
what happens now when you respond in the "and we said..." section) so that I do
not miss any of your insight and wisdom. Thanks, Jim

Rating: 5
Yes, I vote in favor of being emailed every time my question is emailed. August 20, 2001
Reviewer: Kapil from India

Rating: 5
Yes, I would like to be e-mailed when there is a follow-up to my question August 20, 2001
Reviewer: Suresh from New York, USA
Tom,
   If I get an update on my question nearly 3 months later, how would I know
somebody updated my question.  Also, whenever we get time we browse "AskTom",
but most of the times we have just enough time to see only 10 to 15 questions
maximum. So, It is always better to keep the author posted about the update to
the main question.

Rating: 5
Yes, I would like to be emailed, when someone updates my question August 20, 2001
Reviewer: Michel from USA

Rating: 4
August 20, 2001
Reviewer: amol from sweden
I very much agree with Connor ,
this is a public forum and we can always come back and check .
otherwise you will end up sending mails to n number of people , then managing
bounced mails and so on....

Rating: 5
Yes, I would like to be emailed, when someone updates my question August 20, 2001
Reviewer: Michel from USA

Rating: 5
I would like to be notified. August 20, 2001
Reviewer: Gautam from Vancouver, Canada.
Yes, Tom, it will be the great service to the people.
I will be happy if i am notified.

Rating: 5
email me with mine and post updates as recent August 20, 2001
Reviewer: no guru but trying from MA
I learn a lot here, and review and rereview questions daily.
I note you're now answering questions Sat and Sun (24x7 heh)
Alot of times, the first question that comes to me, someone got to and luckly,
most of the time, you go in dept in answering. Some I link and review later.
Some are dumb questions that a lack of experience on my part are judged 'Not
Relevent in your opinion'. What about my opinion, Guru? How will I be proficient
in these topics if I can't have a 'Relevent' ""DUMB"" question every now and
then.
How many guys you got there, anyway? You can't know all this stuff!
loving the book.

Rating: 5
I would prefer an email on additional comments August 20, 2001
Reviewer: Srimal from Trenton, NJ
This is a extremely useful site and it would be extremely helpful if additional
email is sent of any follow up comment

Rating: 4
I vote to be notified for every response August 20, 2001
Reviewer: Van from Groton, CT USA

Rating: 5
I vote yes August 20, 2001
Reviewer: Benny from Los Angeles, CA USA

Rating: 5
No email necessary August 21, 2001
Reviewer: frank from NL
I tend to agree with Connor, if people are not encouraged to
search this forum every now and again, there will be more and more of the same
questions.

Rating: 5
I vote Yes August 21, 2001
Reviewer: Shrek

Rating: 5
August 21, 2001
Reviewer: A reader
yes

Rating: 5
yes August 21, 2001
Reviewer: A reader

Rating: 3
Vote not to email August 21, 2001
Reviewer: Ringo Li from Hong Kong
Email to follow up is good but I will consider a luxary.

Please do so onlyif you have spare time (no more question to answer) or else I
would rather to see more question begin answer. Guess what, just by reviewing
this page, I reckon that I may learn more than attending a course.
By the way, your book is excellent, but a bit too thick. I am now considering to
cut it into serval part of easy to carry about. Any plan to turn it into an E
book??

Rating: 4
Useful August 21, 2001
Reviewer: Balaji from California
It would be really useful if there is a notification

Rating: 5
How will we know when you update my question post August 22, 2001
Reviewer: Pavel Levin from UKRAINE
I think you shouldn't mail. It will be too much.
I'm appreciated very much for your answers.
That is the best teaching, the best training.

Rating: 3
August 22, 2001
Reviewer: Harish Babu from India
yeah.. we cant miss any of u'r comments

Rating: 5
August 22, 2001
Reviewer: Jeff Hunter from Oxford, CT, USA
I trust your judgement.  If you think the new response is relevent, send it
along.  If I wanted another opinion on my issue, I would post to
comp.databases.oracle...

Rating: 5
How about offering multiple options? August 22, 2001
Reviewer: Barbara Boehmer from Norwalk, CA USA
How about providing some sort of check boxes or something when the question is
posted, where we could check one box to be notified of relevant responses or
check another box to be notified of all responses or check another box if we
don't want to be notified at all?  I read your posts frequently and quote you
frequently, but so far I have never posted a question of my own.  I might
hesitate to post a question if I thought that doing so would add to my already
overflowing e-mail.

Rating: 4
August 23, 2001
Reviewer: BVK from INDIA
yes tom,
It seems to be a good idea.

August 22, 2001 -- Thanks for the question regarding "can store procedure reduce parse?", version 8.1.6
You Asked
Tom:

in my question why so many recursive call.
i got the exact same result as you.
http://asktom.oracle.com/pls/ask/f?p=4950:8:72264::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:1137834554916,%7Brecursive%7D%20and%20%7Bcall%7D
that's when i run procedure p several times from SQLPLUS
it shows me that system only parse it for only ONCE.
however when i call procedure p from java several times.
it still give me exact same number of parse_calls and executions.
is it normal?

based on my understanding, it is not because of stored procedure.
it is because sqlplus cache some cursor and reuse it, so when we run
procedure p several times, parse_call only increase 1 and executions increase
a lot.IT IS NOT BECAUSE OF STORE PROCEDURE.

can you tell me by some example how store procedure can help
reduceing soft parse?
and we said...
It is the stored procedure, it really is.  You CAN code it in java so it only
does one parse as well (and you should) but many people (sigh) do not.  Using a
stored procedure "just does it" and you don't have to worry about it.

sqlplus does NOT cache cursors -- plus itself uses only one.

Ok, here is an example.  Suppose you have:

create or replace procedure p
as
begin
    for x in ( select * from dual )
    loop
        null;
    end loop;
end;
/

alter session set sql_trace=true;

exec p
exec p
exec p
exec p
exec p
exec p

In a sqlplus script.  When you run that, you will see:

BEGIN p; END;

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        6      0.01       0.01          0          0          0           0
Execute      6      0.00       0.00          0          0          0           6
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       12      0.01       0.01          0          0          0           6

********************************************************************************

SELECT *
FROM
 DUAL

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.00          0          0          0           0
Execute      6      0.00       0.00          0          0          0           0
Fetch       12      0.00       0.00          0          6         24           6
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       19      0.01       0.00          0          6         24           6

Ok, here the call to the procedure P is parsed 6 times and executed 6 times (as
expected).  However the SELECT * FROM DUAL was parsed ONE time and executed 6
times.  If we just ran select * from dual on the sqlplus command line, we would
see it parsed 6 times -- we don't here because PLSQL is caching that cursor for
us.  Now, we code a java program (poorly, we code this in a "bad" way"):

import java.sql.*;
import oracle.jdbc.driver.*;
import oracle.sql.*;

class test
{

public static void main(String args[])throws Exception
{
    DriverManager.registerDriver
     (new oracle.jdbc.driver.OracleDriver());

    Connection conn=DriverManager.getConnection
      ("jdbc:oracle:thin:@aria-dev:1521:ora817dev"
          ,"scott","tiger");

    Statement stmt = conn.createStatement ();

    stmt.execute( "alter session set sql_trace=true" );
    stmt.execute( "begin p; /* this is java */ end;" );
    stmt.execute( "begin p; /* this is java */ end;" );
    stmt.execute( "begin p; /* this is java */ end;" );
    stmt.execute( "begin p; /* this is java */ end;" );
    stmt.execute( "begin p; /* this is java */ end;" );
    stmt.execute( "begin p; /* this is java */ end;" );
}
}

the tkprof of this shows us:

begin p; /* this is java */ end;

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        6      0.01       0.01          0          0          0           0
Execute      6      0.01       0.01          0          0          0           6
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       12      0.02       0.02          0          0          0           6

********************************************************************************

SELECT *
FROM
 DUAL

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      6      0.00       0.00          0          0          0           0
Fetch       12      0.00       0.00          0          6         24           6
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       19      0.00       0.00          0          6         24           6

Once again -- begin p; end; was parsed 6 times, executed 6 times.  The select *
fromdual however -- parsed ONCE, executed 6 times (in fact if you added more and
more SQL to P -- they would all be parsed 1 time, executed 6).

Now, a properly coded Java routine like this can go even further performance
wise:

import java.sql.*;
import oracle.jdbc.driver.*;
import oracle.sql.*;

class test
{

public static void main(String args[])throws Exception
{
    DriverManager.registerDriver
     (new oracle.jdbc.driver.OracleDriver());

    Connection conn=DriverManager.getConnection
      ("jdbc:oracle:thin:@aria-dev:1521:ora817dev"
          ,"scott","tiger");

    Statement stmt = conn.createStatement ();

    stmt.execute( "alter session set sql_trace=true" );

    PreparedStatement ps =
      conn.prepareStatement ("begin p; /* this is better java */ end;" );

    ps.execute();
    ps.execute();
    ps.execute();
    ps.execute();
    ps.execute();
    ps.execute();
}
}

Its tkprof shows us:

begin p; /* this is better java */ end;

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      6      0.01       0.00          0          0          0           6
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        7      0.01       0.01          0          0          0           6

********************************************************************************

SELECT *
FROM
 DUAL

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      6      0.00       0.00          0          0          0           0
Fetch       12      0.00       0.00          0          6         24           6
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       19      0.00       0.00          0          6         24           6

Now, not only is the SELECT parsed only one time -- so is the PROCEDURE call
itself!  thats perfection, that is what you are shooting for -- 1 parse, many
many executes.
August 22, 2001 -- Thanks for the question regarding "OS User and Data File Droping", version 8.0.5
You Asked
Dear Tom!

You are really helpful. Now I have two questions to ask.

I am on Solaris 8 with Oracle 8.0.5

1. I have owner of database is OPS$xps_prd. This is the user what OS has and I
don't need to enter username and password to enter into Oracle. This user is the
owner of Database. What type of user it is? And if I want to export one table of
the database with owner is ops$xps_prd, by using SYSTEM user. But when I give
table name in export command OPS$XPS_PRD.Table1 It give me error. I am confused.
Please clear me on it.

2. I added a data file to a tablespace name tblData1 by mistake. I droped the
data file after 10 minutes after making sure that no data has been written
during this time. Now some time during running bacth queries I see the error
reporting to missing data file, which I dropped some days ago. I can not efford
to drop table space and to re-create it. Is there a way  to avoid that. You help
will be an assest like the way you were before.

Regards
Amer
and we said...
1) that user is the same type of user as anyone else.  They are just "identified
externally" (by the os).

You don't provide any sort of error, so I'll have to guess.  You are trying
this:

$ exp system/xxxx tables=ops$tkyte.t
tkyte: Undefined variable

thats due to the shell seeing $string and thinking thats an environment
variable.  The solution is simply to escape it:

$ exp sys/o8isgr8 tables=ops\$tkyte.t

Export: Release 8.1.7.0.0 - Production on Wed Aug 22 21:07:03 2001

(c) Copyright 2000 Oracle Corporation.  All rights reserved.

Connected to: Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production
With the Partitioning option
JServer Release 8.1.7.0.0 - Production
Export done in US7ASCII character set and US7ASCII NCHAR character set
server uses WE8ISO8859P1 character set (possible charset conversion)

About to export specified tables via Conventional Path ...
Current user changed to OPS$TKYTE
. . exporting table                              T          2 rows exported
Export terminated successfully without warnings.

2) See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:515222144417
In a nutshell once a file has been added to a tablespace, it is part of the
database UNTIL you drop that tablespace.  There is no way to remove a datafile
from a tablespace.  The offline drop command you probably used it not intended
to remove a file.
Review & Followup
Rating: 4
Great Help as Always August 23, 2001
Reviewer: Mirza Amer Baig from Pakistan
I am very confient in saying that u are real helpful. Believe me U are my real
asset.

Regards
Amer

Rating: 4
Great Help as Always August 23, 2001
Reviewer: Mirza Amer Baig from Pakistan
I am very confient in saying that u are real helpful. Believe me U are my real
asset.

Regards
Amer

August 23, 2001 -- Thanks for the question regarding "Package Vs Sub-program", version 8.0
You Asked
Hi,

Is it better to have all related sub-programs into one big package or have
individual sub-programs in the database? In which case the performance would be
better?
and we said...
Never use standalone procedures for anything other than examples and small bits
of throw away code.

Use packages for all real, production code.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:286816015990
for why

(in addition to the nice ability to have private routines in a package body,
package variables for state, automatic initialization code executed and so on)

Packages = the only way to go.
Review & Followup
Rating: 5
Thanks August 22, 2001
Reviewer: Jatinder from US
Thanks for providing such clear explanation.

Rating: 5
Except for grants.... August 23, 2001
Reviewer: Jurij Modic from Slovenia
The only drawbacks I see in packaging all procedures/functions is in the field
of granting execute privilege. With packages it is all-or-nothing - you can only
grant the execution of the whole package, you can't grant the packaged
procedures/functions individualy, which sometimes is annoying.

Followup:
Well, as I see it there are two very easy solutions to that.

1) functions that need not be called outside of the package should not be in the
specificiation at all.  In this manner, only the procedures/functions in the
package itself may call that procedure or function (eg: it is a private
function/procedure).

2) split the package into two -- eg: a package that is generally callable by
everyone and then an "admin" package.

The benefits of packages far far far outweigh this consideration (since there
are ways to solve this problem).  Taking it to an illogical extreme -- you
should use a package with one procedure instead of a standalone procedure for
the reasons pointed out in the link.

Rating: 5
August 23, 2001
Reviewer: A reader
hi tom.
your book is the best.I am developer and also have lot's of knowledge about
oracle database.I want to become DBA but i don't have expertise in UNIX( In your
book ch 2, you mention if DBA don't know OS well get new DBA!). What sholud i
do? give me some advice on this.

August 23, 2001 -- Thanks for the question regarding "sort using index", version 8.1.6
You Asked
Tom:

i know order by will use sort_area.

but what if i have a index on that column?

create table test(a int,b int);
insert to test some values.

select * from test where a>10;

does this one use sort_area?
and we said...
like everything -- it depends.

If test is a 1 million row table with values for a of 1 .. 1,000,000 (meaning
most are >10), we will most likely full scan, sort and return rather then do
999,990 indexed reads into the table to get the result set.

If test is a 1 million row table with value for a of -1,000,000 .. 0, we will
likely index range scan and skip the sort.

You know what I would do?  I would set up some tests and SEE what it does.  If
the  query plan says "index range scan" -- we are using the index.  If not, we
aren't.
August 23, 2001 William -- Thanks for the question regarding "create domain index parameters", version 8.1.6
You Asked
Hi Tom,

Where would I find the list of parameters when creating a domain
index ie

create index myidx on mytable (col1)
indextype is test parameters('string')
/

What are values that can be passed in the 'string' field?

Thanks

William
and we said...
It depends on the domain index.  They are specific to the index type itself.

For a ctxsys.context index, you would see the interMedia guides.
For a spatial index type -- the spatial guides.

For an index you write yourself -- your documentation.

The parameters is a free-form list of name/value pairs that is defined by the
creators of the indextype itself.
Review & Followup
Rating: 3
what are domain index parameters all about August 23, 2001
Reviewer: Play from USA
Tom

What are these domain index parameters, what are we talking about,
How are these indexes different from the regular indexes we create for the
columns of our table.

Followup:
See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c08schem.htm#11148
Also, I have a section on them in my chapter on indexes in my book and a whole
chapter on interMedia text which makes heavy use of them.

August 23, 2001 -- Thanks for the question regarding "Dropping objects or user", version 8.1.6
You Asked
I was just wondering if you could tell me what's more efficient;

Drop user Scott cascade;(and then just recreate the user)

or

Drop table Dept cascade constraints; Drop table Emp cascade constraints; Drop
table x cascade constraints;........etc.

Is just dropping the user and then recreating the user better? Or would it be
better to write a script to drop each table individually? I have seen in the
past when dropping each table individually, the infamous "ORA-01555 Snapshot too
old".

As always thank you for any input you may have concerning this subject.
and we said...
I've never see the infamous "ora-1555" when issueing a "DROP" command?  Or do
you mean you were doing something like:

 for x in ( select *from all_objects where owner = 'some_user' )
 loop
    execute immediate 'drop some_user.' || x.object_type;
  end loop;

I could see how that can get a 1555 since the drop is a commit inside of the
cursor for loop and it changes the objects being queried.

drop user USERNAME cascade is obviously the easiest.  You don't have to worry
about "drop table T cascade constraints" and dropping types in the right order
and (so on and so on and so on).

I would use drop user cascade (i do use drop user cascade).  If you are curious
as to how it is progressing, you can always use another session  to count the
number of objects still owned by that user.
August 23, 2001 -- Thanks for the question regarding "pl/sql - ref cursor problem", version 8.1.7
You Asked
hi tom:

I am using a ref cursor in a stored procedure and the code is like
set serveroutput on
-----------------------------------------------------------
CREATE OR REPLACE PACKAGE TempEdocs AS

TYPE TempAcctsCursor IS REF CURSOR;

v_email1 varchar2(255):=null;
v_email2 varchar2(255):=null;
v_email3 varchar2(255):=null;

PROCEDURE TempMyRetrieve(i_in0 IN CHAR,
                         l_cursor OUT TempAcctsCursor);

END TempEdocs;
/

CREATE OR REPLACE PACKAGE BODY TempEdocs AS

PROCEDURE TempMyRetrieve(i_in0 IN CHAR,
                         l_cursor OUT TempAcctsCursor) IS
BEGIN

OPEN l_cursor FOR

SELECT nvl(email1,'noemail'),
       nvl(email2,'noemail'),
       nvl(email3,'noemail')
FROM   accountEmails
where  orgprofile=i_in0;
fetch l_cursor into v_email1, v_email2, v_email3;
if l_cursor%notfound then
dbms_output.put_line('notfound');
        INSERT INTO accountemails VALUES(i_in0,null,null,null,null);
        commit;
close l_cursor;
else
dbms_output.put_line('found');
     open l_cursor for
     SELECT nvl(email1,'noemail'),
       nvl(email2,'noemail'),
       nvl(email3,'noemail')
     FROM   accountEmails
     where  orgprofile=i_in0;
close l_cursor;
end if;
END TempMyRetrieve;
END TempEdocs;
/
-------------------------------------------------------------------
i am calling the above from java and basically if i don't find a record, i want
to do an insert and if i do find a record then i want to just return the
selection criteria. however, from java i am gettig a "fetch out of sequence"
error and i believe the way i have written
the above is the worst of plsql programming. i have tried several other ways,
even with the no_data_found exception and it doesn't
seem to work. can u please enlighten me as to how to do this
correctly. also if u could include the testing code i would
appreciate it.

manay thanks
and we said...
you appear to be CLOSING the cursor.  the fetch out of sequence is happening due
to you fetching from a closed cursor.

don't close it.

Here is one alternate method you could use:

ops$tkyte@ORA8I.WORLD> CREATE OR REPLACE PACKAGE TempEdocs
  2  AS
  3
  4      TYPE TempAcctsCursor IS REF CURSOR;
  5
  6      v_email1 varchar2(255):=null;
  7      v_email2 varchar2(255):=null;
  8      v_email3 varchar2(255):=null;
  9
 10      PROCEDURE TempMyRetrieve(i_in0 IN CHAR,
 11                               l_cursor OUT TempAcctsCursor);
 12
 13  END TempEdocs;
 14  /

Package created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> CREATE OR REPLACE PACKAGE BODY TempEdocs
  2  AS
  3
  4  PROCEDURE TempMyRetrieve(i_in0 IN CHAR,
  5                           l_cursor OUT TempAcctsCursor)
  6  IS
  7      PRAGMA AUTONOMOUS_TRANSACTION;
  8      l_cnt  number;
  9  BEGIN
 10
 11      select count(*)
 12        into l_cnt
 13        from dual
 14       where exists ( select null
 15                        from emp
 16                       where ename like i_in0 );
 17
 18      if ( l_cnt = 0 )
 19      then
 20          insert into log values ( 'no data for ' || i_in0 );
 21          commit;
 22      end if;
 23
 24      open l_cursor for select ename, empno from emp where ename like i_in0;
 25  end;
 26
 27  end;
 28  /

Package body created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> variable x refcursor
ops$tkyte@ORA8I.WORLD> set autoprint on
ops$tkyte@ORA8I.WORLD> exec tempEdocs.TempMyRetrieve( 'A%', :x );

PL/SQL procedure successfully completed.

ENAME           EMPNO
---------- ----------
ALLEN            7499
ADAMS            7876

ops$tkyte@ORA8I.WORLD> select * from log;

no rows selected

ops$tkyte@ORA8I.WORLD> exec tempEdocs.TempMyRetrieve( 'Z%', :x );

PL/SQL procedure successfully completed.

no rows selected

ops$tkyte@ORA8I.WORLD> select * from log;

MSG
-------------------------
no data for Z%

I used an autonomous transaction here because I believe it to be a FATAL error
to have a utility rouine like this do a commit (and only commit SOMETIMES).
Suppose the caller was 1/2 way through a transaction??  Now you commit it
(sometimes) or not (other times).  Totally unreliable.  The caller needs to
control transactions.  My book:
http://www.amazon.com/exec/obidos/ASIN/1861004826/002-0082367-4217640
has a pretty big chapter on using this feature.

Secondly, I use a where exists to see if at least one record will match our
predicate.  then we do something if not.

Last, we ALWAYS open (and do close) a cursor for the client to use.
August 23, 2001 oracle -- Thanks for the question regarding "Miscallaneous 082101", version 8.1.7
You Asked
Tom

The following are some (silly) questions, which have bothered me in the past few
days. Any I definitely know they have bothered quite a few other developers
around.

1. SQL> select distinct qdate from prod.heka_pol_num where rownum<501;

qdate
---------
02-MAR-01
02-MAR-01
02-MAR-01
02-MAR-01
02-MAR-01

I expect to see only 02-MAR-01( as Iam using distinct). why is it
returning 5 rows. Is the rest of the data in the rows, effecting the result.
Can you explain when this kind of thing can happen.

2.SQL> select l_id from prod.daily_def
  2  where rownum between 100 and 200;

no rows selected

SQL> select count(*) from prod.daily_def;

  COUNT(*)
----------
      5016

cant we use between with rownum, should it always be less than rownum?

4.I have two tables t, t1 and  there is a common column called id in
both the tables. But it t the column has 100 values, and in t1 we have
100000 rows but have no values at all for id. Now i want to update t1
with 1000 rows each for  each value of id in t.

5.If I have a lot of processing being done in one of my database
triggers , say after update trigger, how should I monitor it.If I make calls
to dbms_outpu.put_line, can I see the output when the trigger gets
fired.
I have a delete and then a insert statement in my trigger, I want to
see by dbms_output.put_line, what records are being inserted and what
records are being deleted. How can I make this possible.

6.How can we make the trace files name more understandable, so that it
is easy for me to identify my own trace files( from a bunch of them)

7.From V$session:
SQL_ADDRESS                                        RAW(4)
PREV_SQL_ADDR                                      RAW(4)

What does raw mean, and why do they have to be raw, and not varchar2

8.I see abbrievations like OLAP, DSS, OLTP, is there a doc which gives
a full form of all
such terms?

9.This question must have been asked, again and again
but once again__
If my from clause has 5 tables. How can I know how many rows are being
returned from each of those tables, for resolving my select. Yes, when
I do an explain plan I get the numbers. But can show me a small
example, and tell me how many rows are being returned by each table.

10.Is the performance of my query or a report which Iam running,  be
effected by other applications Iam running on my client. For example, Iam
running 10 applications or accessing 10 applications from my client ,
and at the same time , I run my query or a oracle report  , will the
performance of this query or report be hindered because Iam also doing
resource intesive operations on the other applications.

11.
call     count       cpu    elapsed       disk      query    current
rows
------- ------  -------- ---------- ---------- ---------- ----------
----------
Parse        1      0.06       0.07          0          0          0
0
Execute      2      0.00       0.00          0          0          0
0
Fetch      210    178.49     209.17      18138    1469584         14
19464
------- ------  -------- ---------- ---------- ---------- ----------
----------
total     210   178.49     209.17     18138    1469584         14
19464

can I consider 209.24 as the exact time taken by the query to execute. When I
ran it from sql navigator it showed
that 352 seconds. What is the difference for. Is the difference of more that 150
seconds , just for dislaying the output on screen( in sqlplus, or sql
navigator).

In the tkprof output I see

Rows     Row Source Operation
-------  ---------------------------------------------------

Rows     Execution Plan
-------  ---------------------------------------------------

what is the difference between both of them

13.

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: CHOOSE
  19464   SORT (UNIQUE)
  19464    SORT (GROUP BY)
  29691     FILTER
  29691      FILTER
  59523       MERGE JOIN (OUTER)
  59524        SORT (JOIN)
  59523         NESTED LOOPS
  59524          NESTED LOOPS
  59524           NESTED LOOPS (OUTER)
  59524            NESTED LOOPS
  59524             NESTED LOOPS
  32339              NESTED LOOPS
  32339               NESTED LOOPS (OUTER)
  32339                NESTED LOOPS (OUTER)
  32339                 NESTED LOOPS
  40753                  TABLE ACCESS (FULL) OF
                             'DEAL_LEGS'
  73090                  TABLE ACCESS (BY INDEX ROWID) OF
                             'DL_CODES'
  81504                   INDEX (UNIQUE SCAN) OF
                              'PK_DL_CODES' (UNIQUE)
  32338                 TABLE ACCESS (BY INDEX ROWID) OF
                            'PRD_PARTIES_C'
  64676                  INDEX (UNIQUE SCAN) OF
                             'PK_PRD_PARTIES_C' (UNIQUE)
     33                INDEX (UNIQUE SCAN) OF
                           'PK_T_PRODUCT_EXCH' (UNIQUE)
  64676               TABLE ACCESS (BY INDEX ROWID) OF
                          'PRODUCT_TYPES'
  64676                INDEX (UNIQUE SCAN) OF
                           'PK_INSTRUMENT_TYPES' (UNIQUE)
  91861              TABLE ACCESS (BY INDEX ROWID) OF
                         'TERM_TAP_LIST'
  93069               INDEX (RANGE SCAN) OF
                          'FK_TERM_TAP_LIST_01' (NON-UNIQUE)
 119046             TABLE ACCESS (BY INDEX ROWID) OF
                        'NP_DEL_PT'
 119046              INDEX (UNIQUE SCAN) OF
                         'UK_SNP_DEL_PT' (UNIQUE)
  59523            TABLE ACCESS (BY INDEX ROWID) OF
                       'NSU_REG
 119046             INDEX (UNIQUE SCAN) OF 'UK_NSU_REG'
                        (UNIQUE)
 119046           TABLE ACCESS (BY INDEX ROWID) OF
                      'TERM_TAP_RL'
 119046            INDEX (RANGE SCAN) OF 'FK_TERM_TAP_RL_01'
                       (NON-UNIQUE)
  59523          TABLE ACCESS (BY INDEX ROWID) OF 'TERM_TAPS'
 119046           INDEX (RANGE SCAN) OF 'FK_TERM_TAPS_01'
                      (NON-UNIQUE)
  59523        SORT (JOIN)
    194         TABLE ACCESS (FULL) OF 'DEF_PORTS'

From the above explain plan it is evident that the smallest NUMBER OF
rows returned are from table T_PRODUCT_EXCH, then should this be the
driving table for the query. But from the above plan we see that the
query is starting execution with a table which is returning 81,504
rows.

What will happen if we arrange the tables in the from clause in the
order of number of rows they return, with the
table returning the least number of rows being on the right.

the optimizer for the above query is RBO.

14. Can we give a join this

t.col1(+) = t2.col1)

Will the outer join be considered, and will it have any adverse impact
on the performance of the query.

Thank you
and we said...
1) all dates have a TIME component.  either:

select distinct TRUNC(qdate) from prod.heka_pol_num where rownum<501;

or

select distinct to_char(qdate,'dd-mon-yyyy hh24:mi:ss') from ....

there are 5 distinct qdates in your result set, you are just not seeing the
"time"

2) rownum is incremented AFTER a row passes the predicate (and before any sorts
or aggregates).

So, the query:

select l_id from prod.daily_def
 where rownum between 100 and 200;

is conceptually processed like this:

    rownum = 1
    for x in ( select * from prod.daily_def )
    loop
          if ( rownum between 100 and 200 )
          then
                  OUTPUT record
                  rownum := rownum + 1;
          end if;
    end loop

Since your predicate is NEVER satisfied, there is NO row 2 -- ever.

try:

   select * from ( select rownum r, * from t ) where r between 100 and 200;

instead.

3)

4) just any rows?? sounds silly to me.  No conditions?  Just take the first
value from t and update 1000 random rows in t2 with that id -- then update 1000
random rows in t2 with the next id from t and so on?

If so, here is but one approach but it wont be "fast".  This is with 2 values
instead of 100 and 50 rows instead of 1000 but the concept is the same:

ops$tkyte@ORA817.US.ORACLE.COM> create table t ( id int );

Table created.

ops$tkyte@ORA817.US.ORACLE.COM> create table t2 ( id int );

Table created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 1 );

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 2 );

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> insert into t2 select null from all_objects
where rownum <= 100;

100 rows created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> begin
  2          for x in ( select * from t )
  3          loop
  4                  update t2 set id = x.id where id is NULL and rownum <= 50;
  5          end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> select id, count(*) from t2 group by id;

        ID   COUNT(*)
---------- ----------
         1         50
         2         50

Each update will get slower and slower and slower as there will be more data to
scan and scan and scan.

5) I don't know what you mean by "monitor it".  If you mean "trace performance"
then TKPROF and DBMS_PROFILER are the tools (search for each on my site).

If you mean "i want to see what it did" -- you can use dbms_output inside of
SQLPlus or SVRMGRL by setting set serveroutput on.

6) On unix I use:

select c.value || '/' || d.instance_name || '_ora_' || to_char(a.spid,'fm99999')
|| '.trc'
  from v$process a, v$session b, v$parameter c, v$instance d
 where a.addr = b.paddr
   and b.audsid = userenv('sessionid')
   and c.name = 'user_dump_dest'
/

on NT

select c.value || '\ORA' || to_char(a.spid,'fm00000') || '.trc'
  from v$process a, v$session b, v$parameter c
 where a.addr = b.paddr
   and b.audsid = userenv('sessionid')
   and c.name = 'user_dump_dest'
/

works

7) RAW means they are "binary data" -- string "text strings".  they are raw
because they are arbitrary addresses, not text strings describing something

8)  see
http://www.acronymfinder.com/
or any number of ancronym finders on the web

9) No I cannot -- the optimizer tries to guess but until you ACTUALLY DO IT --
no one knows (maybe you do but thats only because you know exactly what is in
there)

10) the performance of the QUERY will not be affected (that runs on the server).
 The performance of the REPORT in client/sever mode will be affected, it is
doing its computations on your workstation and will have less resources with
which to do it.

11) the elapsed time is the time spent in the database (not on the network)
doing that query.  SQL Navigator will add in the network time between the client
and the, the time it spent retrieving the data, the time it spent displaying the
data, the time it spent doing whatever else it does.  This is why for example I
do not use timing in sqlplus for fine grained results.  that counts the time
sqlplus spends doing things.  If you set autotrace on -- the timing in plus is
really skewed (it  counts that as well).  I don't know what all sql navigator is
doing under the covers personally.

12) row source operation shows what really truly happened, execution plan -- if
it matches row source operation line/line can be used to get object names
instead of object ids.  If the execution plan (generated by explain plan when
you run tkprof) does not match the row source operation -- IGNORE it, it is NOT
the plan actually used (eg: if you CREATE an index or DROP one AFTER running the
query but before running TKPROF -- you'll get two different plans -- the one
that was used and the one that would be used right now)

13) it is NOT at all EVIDENT.

consider this:

select *
from t1, t2
where t1.object_id = t2.object_id

Rows     Row Source Operation
-------  ---------------------------------------------------
     50  NESTED LOOPS
    101   TABLE ACCESS FULL T2
     50   TABLE ACCESS BY INDEX ROWID T1
    150    INDEX UNIQUE SCAN (object id 71546)

According to you, it is evident that T1 should be the "driving table" here since
it only returns 50 rows.  So, lets try that out:

select *
from t2, t1
where t1.object_id = t2.object_id

Rows     Row Source Operation
-------  ---------------------------------------------------
     50  NESTED LOOPS
  27087   TABLE ACCESS FULL T1
     50   TABLE ACCESS BY INDEX ROWID T2
  27136    INDEX UNIQUE SCAN (object id 71547)

If the constraints against your T_PRODUCT_EXCH that cause it to return only 33
records are only able to be evaluated AFTER some other joins and such take place
-- it is not evident at all that T_PRODUCT_EXCH should be the leading table.  In
fact, (not knowing the query/indexes) it may be IMPOSSIBLE for T_PRODUCT_EXCH to
be the driving table in your query.

Play with it and see what happens.

14) yes, and NO.  Yes you can do a join like that.  I say NO because if you are
doing an OUTER join it is because you NEED to.  The query that uses "a = b"
cannot be compared to "a(+) = b" since they are apples and oranges.
Review & Followup
Rating: 5
q14 and q9 August 22, 2001
Reviewer: A reader
14) I dont think outer joins can be specified as given in question 14. Will they
yield same result if given like that.
It should be t.col=t1.col(+)

The purpose of that question was to know if there would be any bad performance
if a outer join is given as such. Can you clarify.

9)then how should we know how many rows a table returns. Especially when you are
using RBO, because we have to decide the driving table depending on that.

Followup:
If you don't THINK it could be that way, why not try it???  Give me the example
that shows it doesn't work (thats what I would do for you).

In any case:

scott@ORA8I.WORLD> select dept.dname, emp.ename
  2  from emp, dept
  3  where emp.deptno(+) = dept.deptno;

DNAME          ENAME
-------------- ----------
ACCOUNTING     CLARK
ACCOUNTING     KING
ACCOUNTING     miller
RESEARCH       SMITH
RESEARCH       ADAMS
RESEARCH       FORD
RESEARCH       SCOTT
RESEARCH       JONES
SALES          ALLEN
SALES          BLAKE
SALES          MARTIN
SALES          JAMES
SALES          TURNER
SALES          WARD
OPERATIONS

16 rows selected.

Very quickly shows that emp.deptno(+) = dept.deptno (which is the SAME as
dept.deptno = emp.deptno(+) but it very very different from emp.deptno =
dept.deptno(+))  works as I said it would work.

t1.a(+) = t2.b  says to outer join T1 to T2 (makes up a row in T1 if there is no
match)

t1.a = t2.b(+) says to outer join T2 to T1 (makes up a rows in T2 if there is no
match)

9) you have to look at the predicates involved and using your smarts determine
how many rows will be returned.  You have AS MUCH, if not more, information then
the optimizer does.  You should not be using RBO in 817, you should use CBO and
then this question quite simply becomes MOOT.

Look at this query:

select *
   from t1, t2
  where t1.a = t2.a
    and t1.b between 1 and 1000
    and t2.c < 50;

You have to answer this:

will (select * from t1 where b between 1 and 1000) be smaller AND faster to
evaluate then (select * from t2 where c < 50).  Thats what you have to decide
when picking a driving table (and the software that is called the CBO will do
that for you if you give it the statsitics to do so!)

Rating: 4
AMMEND August 23, 2001
Reviewer: ashraf from kuwait
I think Tom It is better if amend your page so if any one submit a questions the
answer will follow to the question because i think it's hard to read the
question and then go down to see the answer and then up....

so i prefer as you profs. to amend so the questions is enter in separate input

Followup:
Well -- I would prefer it if people kept it to a question / page however....

I made a decision to never edit/interleave with the original question.  I do not
even have the ability to modify your question in any fashion (or your comments,
short of deleting them totally).  I do not want to change anything people put
there -- to avoid issues with regards to that.

So, the real solution is for people to ask ONE question, not a laundry list of
them (something I reject lists of questions without answering them as they are
just too long)

Rating: 5
August 23, 2001
Reviewer: Tianhua Wu from Atlanta, GA
Hi Tom,
I want like to make a suggestion.  Could you limit the questions a person can
ask at one time?  That way, it will be easier to read the answer without
forgetting what the question is, also people do not need to wait a long period
of time to submit or receive an answer? Otherwise more and more people will ask
a long list of questions and the waiting time will be longer and longer.
Just my 2 cents,
Thanks for everything you did here!

Followup:
You know what -- I'll just stop answering those big long ones.  Good idea.

Rating: 4
sometimes answering 10 questions might take less time than answering 1 question August 23, 2001
Reviewer: play from USA
Tom

We are really concerned when you say you will stop answering long list of
questions.

The questions might be very trivial in nature, and instead of posting them one
at a time, one might decide to pool these questions say 5 to 10 of them, and
post it at once.

If you feel that a question requires a detailed answer, you can just put a
default answer asking to post it as a separate question.

We are really concerned because , it is in these long list of trivial questions,
that we find solutions to small irritating issues we face day to day. What I
mean is there are a lot of day to day sundry issues which we encounter, but
leave it alone, but we have always found answers to such issues in these long
list of questions.

Can you address our concerns.

Followup:
What do others think here, I'm willing to listen.

I personally find the "long list" very hard and time consuming to answer myself.
 Others have commented more then once that they find them hard to read (and they
are).

the problem is one of scalability here -- there is one of me (and believe it or
not, I do other things here at Oracle).  If one person submits 14 questions in
one, it takes me that much longer to answer other peoples questions.

Rating: 5
Long lists of questions August 23, 2001
Reviewer: Lester Burnham from Orlando, FL USA
Tom,

Maybe if some of the question posers took the time to a) search your site,
and/or b) RTFM (that's Read The Fabulous Manuals) before posting lists of
questions, you wouldn't get so many lists of questions.  Take the first question
from this very list - I mean, how hard could it be to look up in the manuals and
discover that the date type also has a time component?  I'm certainly not
perfect, but it seems that alot of the question posers just ruch to post a
question to 'AskTom' without ever trying to figure anything out on their own.
Maybe their employers should be paying you, since you are apparently being the
DBA for more than a handful of companies.  Sorry for the rant.  Thanks, and keep
up the good fight.

Rating: 5
Multiple Questions August 23, 2001
Reviewer: Nick from Richmond, VA
I find a large number of unrelated questions to be to be an awkward approach. I
can accept a limited number of questions (maybe 5 or fewer) that all relate to a
given topic (say indexing), but asking 15 questions about a wide variety of
topics in the same post seems totally unnecessary.

Rating: 5
We have to agree to a certain number of questions August 23, 2001
Reviewer: Play from USA
o.k. Tom, I  think the need of the hour is to decide how many questions shoud be
allowed per post, and that if they all need to belong to one single topic.

Why dont you put it to voting.

I personally believe that the limit should be between 3 to 5 questions, with the
topics ranging from one to two.

Otherwise, a single person will end up posting 5 different questions 5 times,
and as you know if the threshold is reached you dont receive any more questions.
This will hurt more.

In my opinion a max of 5 to 6 questions is practical, and if any question needs
a lot of attention, you can ask them to be posted as separate question, or
postpone answering that question untill you get sufficient time.

But believe me, if you limit only one or 2 questions per post, very a larger
number of people will end up having no chance to post at all.

Thanks

Rating: 5
Make it one question per user per day August 23, 2001
Reviewer: Joel from Columbus, OH USA
Holy smoke!

Last time I checked, this was the "Ask Tom" site, not the "Tom, do my work for
me because we have never been to training" site or the "Tom, I am lazy and will
not look in any book or electronic resource first" site.

People are abusing this resource and you are letting them abuse it by responding
to such a huge laundry list of questions.  14 questions on one "question"?
You've got to be kidding.

My vote...one question per person per day.  That's it.  There are too many
resources out there (Usenet, MetaLink, Web sites, manuals, Consulting, training)
to not do *your* own work first before coming to this site.

Rating: 5
One Topic with 1 - 3 ***RELATED*** Questions August 24, 2001
Reviewer: Jim from Dallas
I strongly feel that if someone has more than one topic, they should post each
topic separately.

Rating: 5
August 24, 2001
Reviewer: AB from UK
Joel and Lester are absolutely right. Some of the questions being asked are so
simple that it follows that the answers can easily be found in any manual or
book. The online manuals at OTN don't cost you anything. Come on you less
experienced people, try to figure some things out for yourself. If you can't
find the answer, THEN ask Tom by all means.

I have the problem of never being able to ask a question because I am in the UK
and work on a different clock, so by the time I get to logon, you US guys have
filled up Tom's quota again. Now I come across some really advanced problems
from time to time that I have to figure out elsewhere or myself, because Tom is
too busy answering questions on how to turn a date into a string !!!

Tom is a guru - he has a lot of knowledge that us Senior guys want access to -
ask your colleague that really simple PLSQL problem and leave Tom alone for us.

Lecture over.

Rating: 5
August 24, 2001
Reviewer: A reader
The difference between a senior  and a Guru is, how he clarifies the doubt. The
doubt might be a silly or stupid one.

I agree asking 14 questions at one go is a bit too much, but asking these
questions to Tom is not inappropriate.

I say asking a max of 5 questions relating to a related topic or related field
will be the right approach according to me.

Put a limit of one question per post, and the result will be that in the effort
of putting a group of questions into one question , the main question will get
hurt.

Rating: 2
Outer Joins January 30, 2002
Reviewer: Raghav from Bangalore,India
14)
Yes tom i agree with u that we can use the outer joins like that. but i have a
different problem for u.
 suppose i have a column - 'Current_Dept' in Dept table which can hold values
'Y','N' or NULL.
If i give (as one of the conditions in where clause)
       dept.Current_Dept(+) = 'Y'
will that consider the NULL values also for Current_Dept.

Pls clarify it,
Thanks
Raghav

August 23, 2001 Vinnie -- Thanks for the question regarding "Temporary Tablespaces & Local Management", version 8.1.5
You Asked
When a user is assigned a LM temporary tablespace like the following:

CREATE TEMPORARY tablespace TEMPFILE ....
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 64K;

Do all SORT operation occur in this tablespace & does it act like
the dictionary version?
and we said...
All sorts that exceed the sort_area_size (you want your extent to be the same
size as your standard sort_area_size) will use that, yes.

No it does not act like the dictionary one, its an LMT -- its better then the
dictionary one.
August 24, 2001 Sandy -- Thanks for the question regarding "Maximum Row Size", version 8.1.5
You Asked
Tom:

Can U tell me What is maximum row size in Oracle table? 4 GB or 4,000 GB and any
other data type restiction for any table.

THX
Sandy
and we said...
You can get this information from the Oracle Reference manual:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76961/ch4.htm#4762
Basically, a table may have 1,000 columns.  If you use non-lob types that means
a row could be

1,000 x 4,000 = 4,000,000 bytes in length.

If you use LOBS, you could have a row that in theory would be 1,000 x 4gig in
size.
Review & Followup
Rating: 5
August 29, 2001
Reviewer: Sanjeev Varshney from California

August 24, 2001 -- Thanks for the question regarding ""Encrypt" Procedures", version 8.0.5
You Asked
Hi,

Is it possible to hide the source code of any compiled functions/procedures,
meaning users are not able to retrieve its raw contents from the data
dictionary?

Regards,
Siew Yen
and we said...
"wrap" it
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a77069/c_wrap.htm#1859
...
August 24, 2001 -- Thanks for the question regarding "Sql Loader", version 805
You Asked
Hi Tom

Can I specify multiple ctl files in the infile clause of sqlloader.
I have 100s of files loading into one table. Is there an easy option to deal
with this situation.

Thanks
and we said...
I think you mean "multiple dat files"

on the command line, you can supply the file to load:

$ sqlldr .... data=filename.dat

So, in csh, you might:

$ foreach f  (*.dat)
? sqlldr userid=u/p contrl=x.ctl data=$f
? end

In NT, you would use the FOR command (do FOR /? for help)
Review & Followup
Rating: 1
Sql Loader August 24, 2001
Reviewer: Kurt Cearley from Austin, Texas USA
Security issue with password embedded in sqlldr call.
I can not use this on a production environment because of
the security issue.

Followup:
HUH??

Umm, how does this ANSWER introduce any sort of "security issue"?  Doing it in a
loop does not introduce any sort of security issue that you didn't already have
when you DIDN'T do it in a loop.

You still have to call SQLLDR don't you?  This solution to the asked question
(how to load >1 datafile using sqlldr) doesn't introduce any more "security
issues" then anything else.

In any case, do this:

$ foreach f  (*.dat)
? sqlldr userid=/ contrl=x.ctl data=$f
? end

and use an OS authenticated account.  That is what I do for all automated
scripts run by cron or some other facility.  Run sqlldr on the same machine with
the database, using an OS authenticated account and there are no passwords in
scripts.

August 24, 2001 Keith -- Thanks for the question regarding "DBMS_JOB", version 8.1.7
You Asked
Tom,

I have a job (dbms_job) running (Win2000 w/ 8.1.7) that executes a procedure to
update a column (on_sale_flag) value to 'false' if the offsale date
(sale_end_date) is less than the sysdate. The job is supposed to run every hour
on the hour. If I run the procedure independently, the update is immediate. When
the job runs the procedure, it takes minutes for the update to occur throwing
off the update schedule. The job is not broken and has not had any failures. Can
you tell me why it takes so long for the job to run the procedure and what I can
do to make the job run faster? We were previously using perl scripts and Win2000
AT scheduler to accomplish this task but for some reason the AT scheduler on the
server does not want to work for more than 24 hours so this unfortunately is no
longer an option. As always, thanks.

Keith
and we said...
do you know that the job runs slower?

Look at the TOTAL_TIME, remember that time, after the next run -- look at total
time again.  The difference will be the runtime.

What is more likely happening is "slippage".  The job queues are inspected every
N seconds where you control N (job_queue_interval).  If this is set to 60
seconds for example -- then your job might run at 12:01 instead of 12:00.  If
you compute the next interval like this:

  'sysdate+1/24'

your job might next be scheduled for 1:02  (see job NEXT_DATES are computed
BEFORE the job runs -- that is why I doubt the length of the job runtime has
anything to do with this.  If the job took 5 minutes -- it would not matter, the
next_date was already computed).

When the job runs next -- it might be 1:03 -- the next date will be 2:03.  At
2:04 it gets run and so on.  Over time -- it slips.

So, how to get it as close to the hour on the hour?  Use a FIXED computation on
time -- not a sliding one.  Use:

  'trunc(sysdate,''hh'')+1/24'

then, when the job does run at 12:01 -- the NEXT_DATE it computes will be 1:00
-- NOT 1:01.  It won't slip anymore.

Also bear in mind that if you use jobs lots -- your job_queue_processes could be
coming into play as well.  If a job is running at 1pm (not your job, some other
job) and you have job_queue_processes = 1, then you will WAIT until that job is
done.  Just increment your job_queue_processes.

If you really need the job to run at exactly the hour on the hour -- schedule
the job a little BEFORE the hour.  then, have it sleep for N seconds.  Eg: say
your job_queue_interval is 60 (1 minute -- very reasonable).  You might schedule
the job to run at xx:58 instead of xx:00 using:

   'round(sysdate,''hh'')+58/24/60'

What that will do is when its just before/after the hour, it'll round the time
to the nearest hour and add 58 minutes:

  1* select sysdate, round(sysdate,'hh')+58/24/60 from dual
ops$tkyte@ORA817.US.ORACLE.COM> /

SYSDATE              ROUND(SYSDATE,'HH')+
-------------------- --------------------
24-aug-2001 18:58:16 24-aug-2001 19:58:00

Now, your job should:

   n := (round(sysdate,'hh')-sysdate)*24*60*60;
   if ( n > 0 )
   then
         dbms_lock.sleep(n);
   end if;

that way, if it is just a little before the appointed hour, it'll wait and then
run.  If it is on the hour or just after -- it'll run right away.
August 24, 2001 Carol -- Thanks for the question regarding "Another COUNT performance question", version 8.1.7
You Asked
Hi Tom,

In previous questions, you have specified that COUNT(*) performs the same as
COUNT(1).  Is this also true for COUNT(indexed_column), or is there a
difference?

Thank you.
and we said...
Well, count(*) is not equivalent to count(indexed_column) -- they can and will
return different answers:

ops$tkyte@ORA817.US.ORACLE.COM> create table t ( x int );

Table created.

ops$tkyte@ORA817.US.ORACLE.COM> create index t_idx on t(x);

Index created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values (null);

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> select count(*), count(x) from t;

  COUNT(*)   COUNT(X)
---------- ----------
         1          0

So, where as count(1) and count(*) are the same -- these two are different.

So, how do they compare performance wise?  Lets see:

ops$tkyte@ORA817.US.ORACLE.COM> create table t as select * from all_objects;

Table created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> alter table t add constraint t_pk primary
key(object_id);

Table altered.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> analyze table t compute statistics
  2  for table
  3  for all indexes
  4  /

Table analyzed.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> select count(*) from t;

  COUNT(*)
----------
     27196

ops$tkyte@ORA817.US.ORACLE.COM> select count(object_id) from t;

COUNT(OBJECT_ID)
----------------
           27196

ops$tkyte@ORA817.US.ORACLE.COM> alter session set sql_trace=true;

Session altered.

ops$tkyte@ORA817.US.ORACLE.COM> select count(*) from t;

  COUNT(*)
----------
     27196

ops$tkyte@ORA817.US.ORACLE.COM> select count(object_id) from t;

COUNT(OBJECT_ID)
----------------
           27196

select count(*)
from
 t

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.02       0.03          0         58          4           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.02       0.04          0         58          4           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 334  (OPS$TKYTE)

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
  27196   INDEX FAST FULL SCAN (object id 73106)

select count(object_id)
from
 t

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.02       0.02          0         58          4           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.02       0.02          0         58          4           1

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
  27196   INDEX FAST FULL SCAN (object id 73106)

once again -- as long as they  can make use of the same plan, they will be
about the same.  The select count(indexed_column) can use indexes in some cases
where a count(*) cannot ( a count(*) needs a NOT NULL indexed column,
count(indexed_column) does not)
Review & Followup
Rating: 5
Why August 24, 2001
Reviewer: Sanjay from USA
"a count(*) needs a NOT NULL indexed column,
count(indexed_column) does not"

Why is it so? Explain.

Followup:
It is because count(*) counts all of the rows in a table and an index on a
NULLABLE column does not necessarily have an entry for EVERY row in the table.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:678824574412
for an example.

So, if count(*) used an index on a column that contained nulls -- it could get
the wrong count.

Now, if we ask for count(indexed_column) -- that is asking for the count of NON
NULL values for indexed_column.  Here, we can definitely use the index since we
don't want to count NULLs anyway.

Rating: 4
very nice August 27, 2001
Reviewer: A reader
<table><td>good</td><tr><td>answer</td></table>

August 25, 2001 sam -- Thanks for the question regarding "native dynamic sql, dynamic sql and dbms_sql", version 8.1.7
You Asked
I.what is the difference between native dynamic sql, dynamic sql and dbms_sql.
Believe me Tom, there must be scores of Developers who want this cleared for
them.

II.select deptno, count(*)
from emp
group by deptno
union
select to_number(null), count(*)
from emp;

DEPTNO COUNT(*)
---- ----
10 3
20 5
30 6
  14

Does to_number of a null has any meaning.

III. I have procedure which does a delete  then a insert and then a update. Now
these dml operations are done depending upon the look up value_id's in a table
called t.

desc t;

value_id number,
     ,proc_status     varchar2(10)
    ,start_dtm            date
    ,end_dtm            date
    )

Now when the procedure doing  the delete,insert, and update into different
tables, we want to show the status of that particular value_id as  CURRENT (
prior to that the status will be SLEEPING), and after all the operations are
over the status should be OVER.
Further start_dtm, and end_dtm should get populated with values of date and time
when the said operations start and end for a particular value_id .
We have tried a couple of methods but the results have not bee satisfactory. Can
you propose an efficient method to do this.

thank you
and we said...
I.  In my book -- i go into some 35 pages on this very subject.  The summary is:

In Closing

In this chapter we thoroughly explored dynamic SQL in stored procedures.  We
explored the differences between Native Dynamic SQL and DBMS_SQL ? showing when
to use one over the other.  Both implementations have their time and place.

Dynamic SQL allows you to write procedures that are otherwise impossible ?
generic utilities to dump data, to load data, and so on.  Further examples of
dynamic SQL based routines can be found on the WROX web site such as a utility
to load dBase III files into Oracle via PLSQL, printing the results of a query
down the page in SQLPlus (see the Invokers/Definers rights chapter), pivoting
result sets (see the analytic functions chapter for details on that) and much
more.

In a nutshell -- there is Native dynamic sql (execute immediate) and dbms_sql.
They are BOTH dynamic sql (sql that is not known until runtime).  It really does
take quite a bit of space to go over when to use one over the other -- the small
checklist I have in that chapter is:

DBMS_SQL will be used when?

o You do not know the number or types of columns you will be working with.
DBMS_SQL includes procedures to ?describe? a result set.  Native Dynamic SQL
does not.  With Native Dynamic SQL you need to know what the result set will
look like at compile time if PLSQL is to process the results.

o You do not know the number or types of possible bind variables you will be
working with.  DBMS_SQL allows us to procedurally bind inputs into our
statements.  Native Dynamic SQL requires us to be aware of the number and types
of bind variables at compile time (but we will investigate an interesting
workaround to this issue).

o You will be fetching or inserting 1,000's of rows and can employ array
processing.  DBMS_SQL permits ?array? processing, the ability to fetch N rows in
a single call instead of a row at a time.  Native Dynamic SQL in general does
not, there is a workaround demonstrated below.

o You will be executing the same statement many times in the same session.
DBMS_SQL will allow us to parse the statement once and execute it many times
over.  Native Dynamic SQL will cause a soft parse with each and every execution.
 See the section on Tuning for why this extra parsing is not desirable.

Native Dynamic SQL should be used when?

o You know the number and types of columns you will be working with.
o You know the number and types of bind variables (we can also use application
contexts to use the easier native dynamic SQL to get around the fact we don't
know the number and types)
o You will be doing DDL.
o You will be executing the statement a very few (one optimally) times.

The book has the "why" behind the advice (and many examples/benchmarks)

II)  As for "Does to_number of a null has any meaning." -- yes it does.

If you try it without it:

  1  select deptno, count(*)
  2  from emp
  3  group by deptno
  4  union
  5  select null, count(*)
  6* from emp
scott@ORA817.US.ORACLE.COM> /
select deptno, count(*)
       *
ERROR at line 1:
ORA-01790: expression must have same datatype as corresponding expression

you'll find that a NULL by default will be treated as a varchar2 -- the select
lists for unions must be exatly the same types.

III) Sounds like you might want to use an autonomous transaction.  Again, I have
a big chapter on this particular feature in my book.  Here:
http://osi.oracle.com/~tkyte/autonomous/index.html
i have a bit of what they are about as well.  You might have a procedure:

create or replace procedure update_t( p_value_id in number,
                                      p_status   in number,
                                      p_start_dtm in date default null,
                                      p_end_dtm   in date default null )
as
   pragma autonomous_transaction;
begin
   update t
      set status = p_status,
          start_dtm = nvl( p_start_dtm, start_dtm ),
          end_dtm = nvl( p_end_dtm, end_dtm )
    where value_id = p_value_id;

   commit;
end;

when you start, call update_t( 123, 'CURRENT', sysdate );
when you end, call update_t( 123, 'OVER', null, sysdate );
when you go from current to sleeping call update_t( 123, 'SLEEPING' );

is that what you are looking for?
Review & Followup
Rating: 5
If the job is broken or job fails August 24, 2001
Reviewer: Sam from USA
In the above procedure the requrement is that there is also a status called
failed, if my insert fails then the status of the value_id should be set to
failed. As also if due to some other reason the job fails the status should be
set to failed.

Further, this job wakes up every minute,the procedure which gets executed picks
up all the value_id's whose status is sleeping.

Now each time it will find 10 to 15 value_id's. The procedure has a loop which
first sets the status of the value_id to current, and then does the said
operations.

 But the problem this job cannot get finished within one minute all processing
for all the value_id's picked up by the cursor.
When the next minute the next job wakes up , some of the previous value_id's
might get selected again. How should I handle this situation.

In my given situation how can I run parallel jobs to share the value_id's
available at a given point of time, and that the next job will not pick up the
same value_id's.

I hope I was clear, if not let me know.

Followup:
Then catch the exception and call update_t with those status values.

It looks like you are trying to implement a process queue in the database ( a
queue of things to do).

I would strongly encourage you to use the existing QUEUEING software that comes
with the database:
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76938/toc.htm
It'll save you a TON of effort and code.

Rating: 5
Why should there be a call to pragma autonomous transaction August 25, 2001
Reviewer: SAM from USA
-Why should there be a call to pragma autonomous transaction.
Why cant we do a commit like in the calling procedure itself, instead of doing
it in a separate procedure as you have done, and then giving a call to it.
Just before I do a insert I will do the update statement and do the commit, the
same after the insert, why do I have to code a separate procedure for that with
pragma autonomous transaction.
( and as you are repeating telling us, some thing which can be come with pure
sql , should not be done using pl/sql)

-Why are we doing an nvl in the following
start_dtm = nvl( p_start_dtm, start_dtm ),
          end_dtm = nvl( p_end_dtm, end_dtm )

Followup:
I used an autonomous transaction because I thought the original questioner
wanted this status table to be readable by other sessions as a "status" of sort
(hence we need to commit) but I didn't want to interleave this utility routines
transactional logic with the larger program as a whole.  That is, i wanted this
update to be a transaction (i needed to commit) but i didn't want to commit any
outstanding work in the caller.

Hence, this is NOT something that could have been done in SQL since you need a
plsql block to do an autonomous transaction.

Also, don't take the "do it in sql, if not able do it in plsql, if not able ..."
mantra of mine and try to twist into "don't write modular code".  I put a single
update into a utility routine that is callable from many places.  I'm still
doing all of the logic in SQL here (reference the very next comment where I
explain the usage of NVL() in there.  This is a perfect example "if you can do
it in a single sql statment -- do it".

Rating: 5
nvl August 25, 2001
Reviewer: SAM from USA
start_dtm = nvl( p_start_dtm, start_dtm ),
          end_dtm = nvl( p_end_dtm, end_dtm )

The quesion actually is , for the null value substitution, why are you using
start_dtm , and end_dtm, becasue when no value is passed even these will be
null.

Can you give a clarification please.

Thank you

Followup:
I did that cause of the way I demonstrated the "update_t" routine.  It has the
ability to set the status, start_dtm, end_dtm fields but start_dtm and end_dtm
are not always to be set

when you start, call update_t( 123, 'CURRENT', sysdate ); updates start_dtm,
not end_dtm

when you end, call update_t( 123, 'OVER', null, sysdate ); updates end_dtm,
not start_dtm

when you go from current to sleeping call update_t( 123, 'SLEEPING' ); updates
NEITHER

Instead of having 3 different updates, i just used one:

 update t
      set status = p_status,
          start_dtm = nvl( p_start_dtm, start_dtm ),
          end_dtm = nvl( p_end_dtm, end_dtm )
    where value_id = p_value_id;

If p_start_dtm is NULL, we don't update start_dtm in the database (well,
technically we do but we don't change it values).  If P_end_dtm is passed as
NULL, we don't change the current value of end_dtm in the database.  That is the
meaning of that update.

Also as for "why are you using start_dtm , and end_dtm, becasue when no value is
passed even these will be null." that is not the case.   When I call:

when you go from current to sleeping call update_t( 123, 'SLEEPING' );

start_dtm most certainly will not be NULL in the database.

Rating: 5
autonomous transactions August 25, 2001
Reviewer: Vladimir Zakharychev from Yaroslavl, Russia
To do a small clarification of this topic (and free Tom's time for more
important stuff ;):

autonomous transaction in this particular case ensures that only this particular
update will be committed (and thus guaranteed to always happen) no matter what
happens in calling procedure. Right now you are sure that you do a commit
immediately before this procedure is called, so it actually doesn't make much
sense to envelope the status update in an autonomous transaction, but in the
future you may well consider to not do that commit. In this case you won't have
to rewrite the status update - it still will commit its own work no matter what
happens on the upper level. As Tom's article on autonomous transactions shows,
autonomous transactions are most useful for implementing custom audit or
logging, and, of course, in row-level triggers, where you might want to alter
other data in the same table that activated the trigger, but are denied to do so
due to mutating table state - autonomous transactions give you ability to alter
that data:
although the table is mutating, actually only one particular row is being
changed, so other rows are pretty static and accessible at this point.
Autonomous transaction allows you to access these other rows from the trigger,
alter them and commit your work. Keep in mind though, that although the trigger
may result in an exception and the transaction which triggered it will probably
be rolled back, autonomous transaction changes WILL NOT be rolled back in this
case, so you should be very careful here.
Obvious use of this cool ability is a hierarhical table. For example, you might
want to delete particular leaf in such table and want its siblings to be
automatically moved to its parent, not deleted in cascade. Autonomous
transaction in a trigger before delete would easily do this by setting parent id
of all siblings of deleted leaf to leaf's parent id and then allowing delete to
proceed.

regards,
   Bob.

August 25, 2001 oracle -- Thanks for the question regarding "control", version 8.1.7
You Asked
Tom

I have an interesting question, or lets call it a basic question.

Lets say you have forms application. On one of the forms you have a
submit button. Once the user clicks the submit button, a trigger on table A
fires and has to insert 10000 rows into TABLE B.

During this operation of insert is on, the control does not return to
the form, Iam I right. Why doesnt the control does not return to the form.
Why does the control return to the form only after the transaction gets
completed.

Thanks
and we said...
(being technical here but its important to me.  That insert is NOT a
transaction, it is a statement, part of a larger thing called a transaction.
control returns AFTER the STATEMENT completes)

Its called client server.  When the client submits a request to the database,
you don't get control back until the request is complete.  Consider this:

begin
    insert into t values ( 1, 'hello' );
    update t2 set a = (select c2 from t where c1 = 1);
end;

Now, if control returned to the client IMMEDIATELY after submitting the insert
but BEFORE the insert finished and the client submitted the update -- what would
happen?  Sometimes it might see the data, sometimes not.

SQL is a syncronous protocol.  If you want the activity to take place in the
background, use DBMS_JOB to schedule a procedure to run after you commit.
August 26, 2001 play -- Thanks for the question regarding "v$session_longops", version 8.1.7
You Asked
Tom

1.I want to display the percentage of rows for dept no 10 and the total number
of rows in emp table. How can I do it with sql?

2.Using purely sql,  can I code a query where date between sysdate and infinity
date. If it is possible, how can this be done.

3.Is there a way to flush just the buffer cache?

4.I tried to query the v$session_longops using username and time_remaining>0,
becasue I dont have access to v$session to know the sid. The qeury worked and I
was able to see the details
of my long running query in my other session. But suddenly it started pulling
the details of queries run by an another user, AND  again after a minute of so
it started showing the details of my query. I dont understand this, firstly my
operation is not complete yet, and secondly how come it pulled up the details of
the query being run by some other user.

Thank you
and we said...
1) one possible is:

  1  select round( sum(decode(deptno,10,1,0))/count(*) * 100, 2 ), count(*)
  2*   from emp
scott@ORA817.US.ORACLE.COM> /

ROUND(SUM(DECODE(DEPTNO,10,1,0))/COUNT(*)*100,2)   COUNT(*)
------------------------------------------------ ----------
                                           21.43         14

2) to_date( '01-dec-9999', 'dd-mon-yyyy' ) is our infinity date.

3) if you offline the tablespace, the blocks from that tablespace will be
flushed to disk and removed from the cache.

4) If you have access to v$mystat (you should be able to get access to that if
you got access to v$session_longops) you can get your sid.

Not knowing what query you ran, I cannot possibly answer your question.  I've
not experienced what you describe.
Review & Followup
Rating: 5
Where is this information available on technet August 24, 2001
Reviewer: A reader
"to_date( '01-dec-9999', 'dd-mon-yyyy' ) is our infinity date."
What is the reason that it is set to 01-dec, and not anyother date, or a matter
of fact any other year.

Is there a particular reason that '01-dec-9999' is chosen

Followup:
whoops - should have been 31-dec-9999 (but close enough right ;)

thats just the last date our date datatype will hold.  We have a definite year
10000 problem looming in 8000 years.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/ch23.htm#33867

Rating: 3
I'm missing something. August 24, 2001
Reviewer: A reader
Between sysdate and inifinity is the same thing as greater than sysdate. Why do
you need to use between?

Followup:
I'll guess -- they have an app where people can specify:

1) the start date

2) the start and end date

They want to be efficient and use one cursor for both.  Hence:

select * from t where dt between :start and :stop;

is the single query that could do both.  They just default the bind variable for
:stop to to_date('31-dec-9999','dd-mon-yyyy') and they got it.

Rating: 5
Are u ready for 31-DEC-9999 bug ? ;) Just a joke, good answer ! August 24, 2001
Reviewer: Reader

Rating: 5
more details ? August 25, 2001
Reviewer: A reader from USA
Apart from v$session, v$session_longops, v$transaction
what are the other views which contain information on the happenings in a
session, and  with a partition transaction and then a sql statement in specific.

Rating: 5
August 25, 2001
Reviewer: A reader from USA
Apart from v$session, v$session_longops, v$transaction
what are the other views which contain information on the happenings in a
session, and  with a PARTICULAR transaction and then a sql statement in
specific.

Is there a script which gives the total details of whats going on with a sql
statement in a session, including the rows its processing, the number of rows it
has locked and other and all details.

Followup:
The information you are looking for (the rows it is processing right now and the
rows locked) are not kept anywhere.  Locks are stored as an attribute of the
data (on the block with the data), not in a big lock table anywhere.  The rows
being processed changes so quickly that it would be meaningless even if we
tracked it.

Rating: 5
August 26, 2001
Reviewer: A reader from USA
For transaction which is going on , what kind of information  should a
deverloper be aware of about that transaction. i.e. as a developer what kind of
info should he know without fail.

that same with a statement.

Rating: 3
Process Appearing and disappearing March 08, 2002
Reviewer: Steve kiteley from Worcester, UK
I have experienced the same behavior of a process disappearing and reappearing
withe a query doing a hash join on two large tables.

I have also noticed that running the same query from within a trigger in forms 5
there is a delay of several minutes before it appears on v$session_longops.


Subject | Article | Last Updated (East coast time)
displaying the output in two columns | article only | Aug 27, 2001 11:29 am
9iAS connect to database | article only | Aug 27, 2001 01:28 pm
SQL query exceptions | article only | Aug 27, 2001 04:27 pm
Views vs Stored Procedures | article only | Aug 27, 2001 09:02 pm
Backup Agent for Oracle with RMAN | article only | Aug 28, 2001 08:13 am
To use index for where clause ? | article only | Aug 28, 2001 08:16 am
ref cursors | article only | Aug 28, 2001 08:43 am
index_ffs | article only | Aug 28, 2001 08:53 am
DBMS_JOBS | article only | Aug 28, 2001 11:08 am
Exception | article only | Aug 28, 2001 11:52 am
IS NULL and Index | article only | Aug 28, 2001 02:38 pm
Complex View Merging on 8.1.7 | article only | Aug 28, 2001 02:40 pm
How to get the top 5 salaries from the salary table | article only | Aug 28, 2001 03:44 pm
Next Extent... | article only | Aug 28, 2001 03:55 pm
dbms_job.submit | article only | Aug 28, 2001 04:37 pm
PL/SQL TABLES | article only | Aug 28, 2001 04:49 pm
DBMS_JOB.Interval | article only | Aug 29, 2001 09:32 am
Locatin of listener.ora and tnsnames.ora files | article only | Aug 29, 2001 10:13 am
Caching dataset (rows) retrieved by a query | article only | Aug 29, 2001 08:25 pm
Error in dynamic sql | article only | Aug 29, 2001 08:34 pm
Comments on objects in the database. | article only | Aug 30, 2001 07:31 am
Function Based Index -- what privs are needed. | article only | Aug 30, 2001 07:32 am
The way Oracle allocates physical disk space | article only | Aug 30, 2001 10:29 am
Calculate index space... | article only | Aug 30, 2001 07:28 pm
difficult question about "MAXEXTENTS" | article only | Aug 30, 2001 08:07 pm
extent allocation and rman compression | article only | Aug 30, 2001 08:17 pm
RE: SID in V$session_longops not in V$session | article only | Aug 31, 2001 08:26 am
Pro C OCIExtProcContext error | article only | Aug 31, 2001 09:12 am
Last logon for user | article only | Aug 31, 2001 11:27 am
rowid | article only | Aug 31, 2001 11:45 am
Extents, Data blocks, OS blocks | article only | Aug 31, 2001 11:50 am
Intervalle Date, bug ? | article only | Aug 31, 2001 02:35 pm
View Performance | article only | Aug 31, 2001 04:46 pm
useful packages for developer and dba | article only | Aug 31, 2001 08:34 pm
row(s) 1 - 34 of 34
August 27, 2001 vishnu -- Thanks for the question regarding "displaying the output in two columns", version 8i
You Asked
Hi Tom
You are always help full..I have the following problem..
I hv a table by name "colors"
It has the following coloumns

state      pigment     allowed
pa         a           yes
ca         a+          yes
da         b           no
vv         a           no
zz         s           yes
nj         a           no
nw         a           yes
dc         a           yes

the requirement is the user wiill selects the state and pigments
like the user has selected pa,ca,zz (these are state) and 'a '(pigments)..
I need to construct a sql to display .the state and pigment are in multi select
combo and i am passing these to the sql with bind variables..
The following out put is required from the query for the selected
states and pigments..

allowed_states        not_allowed_states
pa                    vv
nw                    ny
dc

Pl help ....
and we said...
SQL results are "square" in nature.  Your result is not "square".

Consider if allowed_states and not_allowed_states were in different tables --
you might think "join" -- but how would you join these totally unrelated sets of
data?

There is a trick you can use but it works ONLY if you know the maximum number of
states (and if that number if sufficiently small).

Here, I make the assumption we will never get back more than 100 rows:

ops$tkyte@ORA817.US.ORACLE.COM> create table t ( state varchar2(2), pigment
varchar2(2), allowed varchar2(3) );
Table created.

ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'pa','a','yes' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'ca','a+','yes' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'da','b','no' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'vv','a','no' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'zz','s','yes' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'nj','a','no' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'nw','a','yes' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( 'dc','a','yes' );

ops$tkyte@ORA817.US.ORACLE.COM> select a.state allowed_states,
                                       b.state not_allowed_states
  2    from ( select state, rownum r
                from t where pigment = 'a' and allowed = 'yes' ) a,
  3         ( select state, rownum r
                from t where pigment = 'a' and allowed = 'no' ) b,
  4             ( select rownum r from all_objects where rownum < 100 ) c
  5   where c.r = a.r(+)
  6     and c.r = b.r(+)
  7     and (a.state is not null or b.state is not null)
  8  /

AL NO
-- --
pa vv
nw nj
dc
Review & Followup
Rating: 4
The report does'nt show up August 27, 2001
Reviewer: A reader
Tom Thanks for the reply ,...I used the same query with few
modifications...Down below is the query
country_name,pigments_name,permitted are the columns and cr_colreg is the name
of the table..Pl help me what am i missing here...

select a.country_name allowed_countries,
       b.country_name not_allowed_countries
    from ( select country_name, rownum r
                from BPSI_COLREG.CR_COLREG where  cr_colreg.pigments_name in
:pigmentsName and cr_colreg.country_name
 in  :CountryName and cr_colreg.permitted = 'yes' ) a,
           ( select country_name, rownum r
                from BPSI_COLREG.CR_COLREG where     cr_colreg.pigments_name in
:PigmentsName and cr_colreg.country_name
  in :CountryName  and cr_colreg.permitted = 'no' ) b,
             ( select rownum r from all_objects where rownum < 100 ) c
     where c.r = a.r(+)
      and c.r = b.r(+)
      and (a.country_name is not null or b.country_name is not null)

It gives the following message
Cursor is not open

No row returned.

pl help

Followup:
You cannot bind an "in list" like that.  Try it in sqlplus first -- that query
works (the one i provided).  The one you have, with the IN is not doing an "IN"
if you bind 'a','b','c' to it - that IN is the equivalent of EQUALS

Rating: 4
The report does'nt show up August 27, 2001
Reviewer: A reader
Tom Thanks for the reply ,...I used the same query with few
modifications...Down below is the query
country_name,pigments_name,permitted are the columns and cr_colreg is the name
of the table..Pl help me what am i missing here...

select a.country_name allowed_countries,
       b.country_name not_allowed_countries
    from ( select country_name, rownum r
                from BPSI_COLREG.CR_COLREG where  cr_colreg.pigments_name in
:pigmentsName and cr_colreg.country_name
 in  :CountryName and cr_colreg.permitted = 'yes' ) a,
           ( select country_name, rownum r
                from BPSI_COLREG.CR_COLREG where     cr_colreg.pigments_name in
:PigmentsName and cr_colreg.country_name
  in :CountryName  and cr_colreg.permitted = 'no' ) b,
             ( select rownum r from all_objects where rownum < 100 ) c
     where c.r = a.r(+)
      and c.r = b.r(+)
      and (a.country_name is not null or b.country_name is not null)

It gives the following message
Cursor is not open

No row returned.

pl help

Rating: 4
Query works fine ....But in portal August 27, 2001
Reviewer: A reader
Tom Sorry for disturbing u again and again...
I am developing a report in portal...User will open the customization form and
selects the countries and pigments(multi select combos) and he would expect the
results like to see the countries where all the pigments are permitted and the
list of countries where not permitted...
so in portal i hv written the query like below...

Can u pl help
Tom Thanks for the reply ,...I used the same query with few
modifications...Down below is the query
country_name,pigments_name,permitted are the columns and cr_colreg is the name
of the table..Pl help me what am i missing here...

select a.country_name allowed_countries,
       b.country_name not_allowed_countries
    from ( select country_name, rownum r
                from BPSI_COLREG.CR_COLREG where  cr_colreg.pigments_name in
:pigmentsName and cr_colreg.country_name
 in  :CountryName and cr_colreg.permitted = 'yes' ) a,
           ( select country_name, rownum r
                from BPSI_COLREG.CR_COLREG where     cr_colreg.pigments_name in
:PigmentsName and cr_colreg.country_name
  in :CountryName  and cr_colreg.permitted = 'no' ) b,
             ( select rownum r from all_objects where rownum < 100 ) c
     where c.r = a.r(+)
      and c.r = b.r(+)
      and (a.country_name is not null or b.country_name is not null)

It gives the following message
Cursor is not open

No row returned.

Followup:
Sorry -- I've not programmed Portal.  they don't use "real" bind variables all
of the time so I'm not sure exactly what the query looks like after they get
done with it.

Please try:
http://otn.oracle.com/
there are monitored discussion groups that you might find helpful for this.

August 27, 2001 tom -- Thanks for the question regarding "9iAS connect to database", version 1.0.2.0.1
You Asked
Hi, Tom
I was told that the application server can only connect to one database, is it
true? If not, how to configure to connect more than one database? Thanks.
and we said...
The application server runs your code.  Your code will mandate how many
databases it will connect to.  If you write a java servlet you can connect to 0,
1 or one hundred databases -- totally up to you.

Some functions of iAS -- for example the mod_plsql cartrige -- connect to a
database at a time.  mod_plsql can connect to dozens of databases, but each
REQUEST will be routed to a single database.  You would use database links to
access more then one database in a single request.
August 27, 2001 pete -- Thanks for the question regarding "SQL query exceptions", version 8.1.6
You Asked
Hi Tom,

I am running a query that converts applicaion date fields (MMDDYY) to Oracle
dates using to_date.

The query runs for a while and then fails due to invalid data in the field I am
converting.

It there a way with SQL*Plus to not abort the query and just log an exception?

Is there any easy way to find the bad data?
and we said...
write your own to_date function:

create or replace function my_to_date( p_string in varchar2 ) return date
as
    pragma autonomous_transaction;
    msg    varchar2(5000)
begin
    return to_date( p_string, 'YOUR FORMAT' );
exception
    when others then
         msg := sqlerrm;
         insert into log_table values (msg, p_string);
         COMMIT;
         return NULL;
end;

that will return the converted date (or NULL) and when an error occurs, it'll
log an error message.  The autonomous transaction will allow it to be called
from SQL.
August 27, 2001 -- Thanks for the question regarding "Views vs Stored Procedures", version 817
You Asked
Hi Tom
I have a question on comparing the performance of views vs stored procedures.

We are integrating two applications A & B. B would be requesting data through A
which gets the data from its oracle database. B accesses A's data through A's
interface tables.
Now my question is should I use stored procedures for this process or Views? The
stored procedures would load the required data in A's interface tables. The
application B would then access data from these interface tables.
The views would get the data from A's database on the fly and B would access
data through these Views.
Whose performance is better
and we said...
Neither is necessarily "better".

Both have advantages.  Using stored procedures, I can fix "bugs" from the other
side (from B's side).  I (as A) know how best to use my tables, I can write
really good code to do that.

On the other hand, I can use array processing and other features to insert
really fast (or select really fast) from these tables.

I myself am a HUGE fan of API's (procedures).  A will provide to B an API with a
static interface.  A is now free to change its implementation without affecting
B as long as A maintains the API's.  You also get very clear documentation about
how B uses A's tables and where (the dependency mechanism).  It makes things
more clear.
August 28, 2001 oscar -- Thanks for the question regarding "Backup Agent for Oracle with RMAN", version Oracle 7
You Asked
Hi Tom,
I had installed ARCserve2000 and Oracle Backup Agent with RMAN into server
running in Win2000. I know that we must have backup agent to do online backup.
QUESTION :
1.  But how the backup agent perform internally with RMAN to ask Oracle server
to BEGIN BACKUP while online backup is requested by ARCserve?

2.  Is it after installed everything mention as above then we do backup for
whole drive (include database drive) using ARCserve, then backup agent will
automatic deal with oracle server (oracle server will auto issue BEGIN BACKUP)
without any coding/script write in RMAN?

Thank you very much.
and we said...
1) RMAN doesn't do a "begin backup".  It is not necessary when you use RMAN.
RMAN does an intelligent copy of the database blocks (as opposed to a simple OS
copy) and it ensures we do not copy a fractured block.  The whole purpose of the
begin backup is to record more info into the redo logs in the event an OS copy
copies a "fractured block" - where the head and tail do not match (can happen
since we are WRITING to the database at the same time the backup would be
reading).  When RMAN hits such a block -- it re-reads it to get a clean copy.

2) as for the level of scripting, you'll have to refer to the ARCServe 2000
documentation as the backup agent for Oracle is developed by CA -- not Oracle.
I am not sure of what its capabilities are.  It should be that you script their
product, not RMAN in this case (they use RMAN, you use ARCServe).

If anyone out there knows, feel free to followup.
Review & Followup
Rating: 4
Backup Agent for Oracle with RMAN August 28, 2001
Reviewer: Oscar Lee from Malaysia
Thanks a lot TOM

August 28, 2001 -- Thanks for the question regarding "To use index for where clause ?", version 8.0.6
You Asked
Hi Tom,
How can we utilize the index created for the following query:

  lv_emp_name = UPPER(pv_emp_name);
  select *
  from  emp
  where rtrim(emp_name)= lv_emp_name

if the emp_name stores in the table emp is 'JOHN   ' with spaces and the
parameter values passed in is 'john'?

Shall I create index for RTRIM(UPPER(emp_name))?

Thanks.
and we said...
In Oracle8.0.6 as you have, a function based index is not possible.  That
feature was introduced in Oracle8i release 1 (see:
http://osi.oracle.com/~tkyte/article1/index.html
for details).  If emp_name is a CHAR type (and hence blank padded) I would
suggest you use this approach instead:

  lv_emp_name := rpad( upper(pv_emp_name), LENGTH_EMP_NAME_COLUMN );
  select * from emp where emp_name = lv_emp_name;

instead.  that'll use a conventional index on emp_name.
August 28, 2001 oracle -- Thanks for the question regarding "ref cursors", version 8.1.7
You Asked
I want to use ref cursors, and I dont know where to use them. Where should I ,
or in what situations should I use them.

Thank you
and we said...
We use them most often to return a result set from a stored procedure to a
client.  See
http://osi.oracle.com/~tkyte/ResultSets/index.html

You also use them in PLSQL when you are not quite sure WHAT query you will be
running until runtime.  For example:

scott@ORA815> create or replace procedure p( p_order_by in varchar2 )
  2  is
  3          type rc is ref cursor;
  4
  5          l_cursor rc;
  6          l_rec    emp%rowtype;
  7  begin
  8          if ( p_order_by = 'ename' )
  9          then
 10                  open l_cursor for select * from emp order by ename;
 11          elsif ( p_order_by = 'sal' )
 12          then
 13                  open l_cursor for select * from emp order by sal;
 14          else
 15                  open l_cursor for select * from emp order by job;
 16          end if;
 17
 18          loop
 19                  fetch l_cursor into l_rec;
 20                  exit when l_cursor%notfound;
 21                  dbms_output.put_line( l_rec.ename );
 22          end loop;
 23
 24          close l_cursor;
 25  end;
 26  /

Procedure created.

scott@ORA815>
scott@ORA815>
scott@ORA815> exec p( 'ename' );
ADAMS
ALLEN
BLAKE
....
PL/SQL procedure successfully completed.

scott@ORA815> exec p( 'sal' );
SMITH
JAMES
ADAMS
....

Lastly, they are very handy with native dynamic SQL instead of DBMS_SQL as well,
for example:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
...
August 28, 2001 play -- Thanks for the question regarding "index_ffs", version 8.1.7
You Asked
Tom

I have observed that in a few queries of mine, I am retrieving columns which are
part of the composite primary key, or the whole primary key.

then explain shows that this is doing a index scan and a table scan by rowid.

Now if I force the optimizer to use index_ffs, will it be more economical
performance wise.

my optimizer right now is rbo, I will get the tables analyzed to do the above.

Want your suggestions, and examples.

Further, when I do a select empno from emp where rownum<2, it will return only
one row to be

1.Will it do a full table scan
2.Will it make use of the index on empno
3.Will it return the row after it reads the first two rows, or does it read the
whole table.
3.If for my key value there are multiple rows, and I want to return only one,
what is the way apart from where rownum<2

Thanks
and we said...
Well, as with everything in life, it depends.

An INDEX_FFS (index fast full scan) will read the ENTIRE index structure.  If
you have a 2 gig index on a 200 gig table and you are only retrieving 20 rows
from it -- reading the index as a data structure and NOT full scanning it will
be faster.

an index ffs reads the entire index structure as if it were a table.  You would
only want to use it when you are getting MOST of the rows -- not just a few.

As for the rownum <2, the plan will say "full scan emp" but it will include a
"count stopkey".  Meaning it will start full scanning emp but quit the moment
the rownum is exceeded.

It MIGHT use the index on emp, but maybe not ( with rownum < 2, it'll be easier
to full scan the table rather then process an index structure).

It will not read the whole table.

as for "if for my key value there are >1 rows", you would have to give me some
method to "identify" the row you want.  If you don't care which row you get,
rownum = 1 is as good as anything else.
August 28, 2001 Sam -- Thanks for the question regarding "DBMS_JOBS", version 8.1.7
You Asked
Tom

Say, I have a job set up to fire every 1 minute. Now the job wakes up after the
1 minute expires. It is working. One minute is past. Now according to what we
set up , it should wake up again. Will the job wake up again, even though it is
still working on the process which it has taken up the previous time it woke up.

If this is true then, assuming that my job takes 31 minutes to complete, in 30
minutes I will have 30 jobs running. Is this the way it works.

THNAKS
and we said...
Nope, it does not work that way.  A job that is running will not run again until
it completes running.

To have 30 jobs going at the same time -- you need 30 jobs scheduled.
August 28, 2001 Omer -- Thanks for the question regarding "Exception ", version 8.1.5
You Asked
if I  have a cursor like

cursor x is select empno
from emp

begin

some processing

exception
wheno thers them
dbms_output.put_line('error ecountered while processing empno'||rec.empno)

can i or can i not use the rec.empno in the exception section, when I tried it
is returned error, why?
and we said...
Where the heck is rec coming from?

If rec is implictly defined in a cursor for loop -- it is only visible in the
cursor for loop, eg:

declare
   cursor x is select empno from emp;
begin
    -- rec does not exist here
    for rec in x loop
       -- rec is visible here
    end loop;

    -- rec is not here either
exception
    when others then
        -- rec isn't here either
end;

If rec was a defined variable -- it would be visible:

declare
   cursor x is select empno from emp;
   rec   x%rowtype;
begin
   open x;
   loop
         fetch x into rec;
         exit when x%notfound;
          ....
   end loop;
   close x;
exception
   when others
       IF (X%ISOPEN ) then
           close x;
       end if;
       ....
end;

in that block, REC is visible everywhere.  Alternatively (preferably perhaps)

declare
   cursor x is select empno from emp;
begin
   for rec in x
   loop
      begin
           ....
      exception
           when others then
                -- rec is visible here!
       end;
    end loop;
end;

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1155066278457
for my thoughts on WHEN OTHERS
Review & Followup
Rating: 5
? August 28, 2001
Reviewer: A reader from USA
BEGIN
.....

BEGIN
.....

EXCEPTION
   WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001  .....SOME ERROR
END;

END LOOP;

EXCEPTION
   WHEN OTHERS THEN
   RAISE_APPLICATION_ERROR(-20001, .... SOME ERROR

Can we use the same error number for raise application error in two different
blocks of the same procedure.

Followup:
yes you can.

August 28, 2001 mike -- Thanks for the question regarding "IS NULL and Index ", version 8.0
You Asked
Tom,
I have trouble to make the following qery using the index on LAST_PROCESS_DATE.

select pid_code FROM logistics_TEMP
where   LAST_PROCESS_DATE < sysdate - 1
or LAST_PROCESS_DATE is NULL
/

I had tried the hint on index and it did not work. The HWM on the table is high,
I do not see Oracle doing FTS on the table. Is there any work around?

Thank you.
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:678824574412
unless you have a bitmap index on last_process_date (they index nulls), that
query cannot use an index as NULL index entries are not made.
A bitmap index is only good in a data warehouse (no / little updates).

What you might consider is using the date:

to_date( '01010001', 'ddmmyyyy' )

instead of NULL for last_process_date.  OR, adding a NOT NULL column to the
index which will get NULL last_process_dates indexed:

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create table t ( last_process_date date, dummy char(1)
NOT NULL )
  2  /

Table created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> create index t_idx on t(last_process_date)
  2  /

Index created.

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> exec dbms_stats.set_table_stats( user, 'T', numrows =>
100000000, numblks => 10000000 );

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> set autotrace on explain
ops$tkyte@ORA8I.WORLD> select /*+ first_rows */ * from t where last_process_date
< sysdate -1 or last_process_date is null;

no rows selected

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=1517738 Card=9750000
Bytes=292500000)
   1    0   TABLE ACCESS (FULL) OF 'T' (Cost=1517738 Card=9750000
Bytes=292500000)

ops$tkyte@ORA8I.WORLD> drop index t_idx;

Index dropped.

ops$tkyte@ORA8I.WORLD> create index t_idx on t(last_process_date,dummy)
  2  /

Index created.

ops$tkyte@ORA8I.WORLD> select /*+ first_rows */ * from t where last_process_date
< sysdate -1 or last_process_date is null;

no rows selected

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=5 Card=5250001
Bytes=157500030)
   1    0   CONCATENATION
   2    1     INDEX (RANGE SCAN) OF 'T_IDX' (NON-UNIQUE) (Cost=2 Card=250001
Bytes=7500030)
   3    1     INDEX (RANGE SCAN) OF 'T_IDX' (NON-UNIQUE) (Cost=2 Card=250001
Bytes=7500030)

ops$tkyte@ORA8I.WORLD> set autotrace off
Review & Followup
Rating: 5
Great Answer August 27, 2001
Reviewer: Raj from USA
Tom, Are you real or imaginary!! You never say 'I don't know' and give us the
best possible solution. I wish if I were like you.

Followup:
I just don't PUBLISH the ones I say "i don't know"  -- there are people out
there that know that I say that ;)

Rating: 5
A different way August 28, 2001
Reviewer: mike from USA
Suppose I do not want to add the new index. I just want Oracle to use index scan
to avoiding the Full Table Scan, because the HWM is high. There is a PK for
LOGISTICS_ID_NO (number(9)), and without the functionality changes:
select /*+ index( logistics_TEMP logistics_TEMP_pk) */
pid_code FROM logistics_TEMP
where   (LAST_PROCESS_DATE < sysdate - 1
or LAST_PROCESS_DATE is NULL) and LOGISTICS_ID_NO like '%'
/
The explain plan shows using the index.

Followup:
That works well if and only if the table is very very small (has very very few
rows).  Otherwise the overhead of reading the entire table via an index will
rapidly outweight the cost of full scanning the table.  (rapidly).

Rating: 3
function based index August 29, 2001
Reviewer: A reader
You can also create a function based index for last_process_date such as

create index fbx1 on tablename (nvl(last_processed_date, sysdate-2))

amend your query as:
select pid_code FROM logistics_TEMP
where   nvl(LAST_PROCESS_DATE, sysdate-2) < sysdate - 1
/

this will use the index.

August 28, 2001 Matt -- Thanks for the question regarding "Complex View Merging on 8.1.7", version 8.1.7
You Asked
I have 3 tables:

create table fk_tab_master( fk_refno NUMBER NOT NULL PRIMARY KEY )

create table fk_tab_detail( fk_det_refno NUMBER NOT NULL PRIMARY KEY,
                                fk_refno     NUMBER NOT NULL REFERENCES
fk_tab_master( fk_refno ) )

create table drive_tab ( drive_refno        NUMBER NOT NULL PRIMARY KEY,
                            fk_det_refno NUMBER NULL REFERENCES fk_tab_detail(
fk_det_refno ) )

When running the following SQL I get:

select count(*)
from fk_tab_master mst,
     fk_tab_detail det,
     drive_tab drv
Where mst.fk_refno = det.fk_refno
and   drv.fk_det_refno = det.fk_det_refno (+)

SELECT STATEMENT Optimizer=CHOOSE
  NESTED LOOPS
    NESTED LOOPS (OUTER)
      TABLE ACCESS (FULL) OF DRIVE_TAB
      TABLE ACCESS (BY INDEX ROWID) OF FK_TAB_DETAIL
        INDEX (UNIQUE SCAN) OF SYS_C0078766 (UNIQUE)
    INDEX (UNIQUE SCAN) OF SYS_C0078761 (UNIQUE)

select /*+ push_join_pred( il1 ) */ count(*)
from ( select mst.fk_refno,
                 det.fk_det_refno
       from fk_tab_master mst,
               fk_tab_detail det
       where mst.fk_refno = det.fk_refno
      ) il1,
    drive_tab drv
where drv.fk_det_refno = il1.fk_det_refno (+)

SELECT STATEMENT Optimizer=CHOOSE
  MERGE JOIN (OUTER)
    SORT (JOIN)
      TABLE ACCESS (FULL) OF DRIVE_TAB
    SORT (JOIN)
      VIEW
        NESTED LOOPS
          TABLE ACCESS (FULL) OF FK_TAB_DETAIL
          INDEX (UNIQUE SCAN) OF SYS_C0078761 (UNIQUE)

The predicate from the outer query doesn't get pushed into
the inline view.

This is a much simplified example to the one I am using.

Also, could you point me in the direction of a document explaining
how to gauge the optimal HASH_AREA_SIZE for an instance.
and we said...
We'll, we don't push the predicate down because that would change the meaning of
the query in this case.  You seem to thing that your two queries should be
equivalent -- but they are not.  Consider (assume your tables were empty):

ops$tkyte@ORA815> insert into fk_tab_master values ( 1 );

1 row created.

ops$tkyte@ORA815>
ops$tkyte@ORA815> insert into drive_tab values ( 100, null );

1 row created.

ops$tkyte@ORA815>
ops$tkyte@ORA815> select count(*)
  2  from fk_tab_master mst,
  3       fk_tab_detail det,
  4       drive_tab drv
  5  Where mst.fk_refno = det.fk_refno
  6  and   drv.fk_det_refno = det.fk_det_refno (+)
  7  /

  COUNT(*)
----------
         0

ops$tkyte@ORA815>
ops$tkyte@ORA815> select /*+ push_join_pred( il1 ) */ count(*)
  2  from ( select mst.fk_refno,
  3                   det.fk_det_refno
  4         from fk_tab_master mst,
  5                 fk_tab_detail det
  6         where mst.fk_refno = det.fk_refno
  7        ) il1,
  8      drive_tab drv
  9  where drv.fk_det_refno = il1.fk_det_refno (+)
 10  /

  COUNT(*)
----------
         1

They give different answers.  Looking at the query:

select count(*)
from fk_tab_master mst,
     fk_tab_detail det,
     drive_tab drv
Where mst.fk_refno = det.fk_refno
and   drv.fk_det_refno = det.fk_det_refno (+)

I would say it was in improper use of an outer join.  In this case -- if we find
a row in DRV that doesn't have a match in DET and we "make up a row" for it --
the predicate "Where mst.fk_refno = det.fk_refno" will immediately drop it for
us (nothing is ever equal to NULL).  Hence the outer join in this example is
only useful to negatively impact performance (it limits the plans available to
the optimizer but its existence does not change the outcome ever).

You can drop the (+) in that query and you'll have exactly the same query!

the second query however, outer joins to the JOIN.  As demonstrated above -- the
predicate "Where mst.fk_refno = det.fk_refno" no longer drops the row from the
result set since IT is done first and the result of that is outer joined to the
other table.

See
http://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&p_id=41954.1
for the hash_area_size.  It describes the process and how this parameter is used.
Review & Followup
Rating: 3
August 28, 2001
Reviewer: Matt
I think in this case I gave a bad example to compare with.
I am still surprised that the plan for the inline view
did a full table scan on fk_tab_detail when it could have gone
in on the index.

Followup:
If you mean this query and plan:

select /*+ push_join_pred( il1 ) */ count(*)
from ( select mst.fk_refno,
                 det.fk_det_refno
       from fk_tab_master mst,
               fk_tab_detail det
       where mst.fk_refno = det.fk_refno
      ) il1,
    drive_tab drv
where drv.fk_det_refno = il1.fk_det_refno (+)

SELECT STATEMENT Optimizer=CHOOSE
  MERGE JOIN (OUTER)
    SORT (JOIN)
      TABLE ACCESS (FULL) OF DRIVE_TAB
    SORT (JOIN)
      VIEW
        NESTED LOOPS
          TABLE ACCESS (FULL) OF FK_TAB_DETAIL
          INDEX (UNIQUE SCAN) OF SYS_C0078761 (UNIQUE)

Well, look at the inline view:

select mst.fk_refno, det.fk_det_refno
  from fk_tab_master mst,
       fk_tab_detail det
 where mst.fk_refno = det.fk_refno

in light of the fact that there are no PREDICATES other then the join -- one of
the two tables would be full scanned.  There is no "index access" to either
table that could be used to START the query.  The index into the other table was
used (because it made sense).

August 28, 2001 Rajan -- Thanks for the question regarding "How to get the top 5 salaries from the salary table", version version 8.1.5
You Asked
How to get the top 5 or top N no. of rows from a table having salary column.
and we said...
In Oracle8i version 8.1.5 as you have, the easiest way is:

scott@DEV8I.WORLD> select *
  2    from ( select distinct SAL
  3             from EMP
  4            order by 1 desc )
  5   where rownum <= 5
  6  /

       SAL
----------
      5000
      3000
      2975
      2850
Review & Followup
Rating: 4
Thanks June 04, 2001
Reviewer: wayen_wang from china
I counld not find suitable words to describe the useful of information you give
me.

Rating: 1
August 28, 2001
Reviewer: A reader
how WOULD this query work!!!
eve after sytax correction it would not give top 5

Followup:
umm -- what planet did you drop in from?

That was a straight cut and paste from SQLPlus -- try it (note the requirement
of Oracle8i 8.1.5 and above first)

Then tell me it doesn't work.

There are no syntax errors there, it works and -- lo and behold -- it gives the
top 5.

Rating: 4
Technically, there is a mistake August 28, 2001
Reviewer: Nick from Richmond, VA USA
It should be 'where rownum <= 5' to retrieve the top 5.

Followup:
whoops -- thanks, fixed that.  Much more useful then the previous comment.

August 28, 2001 Senthil -- Thanks for the question regarding "Next Extent...", version 8.1.5
You Asked
Tom,

what exact formula makes the next extent...

here is an e.g...

SQL>  create table t (x int, y char(2000) default '*') storage (initial 10k next
10k minextents 5 pctincrease 50);

Table created.

SQL> select extent_id, bytes, blocks from user_extents where segment_name = 'T'
order by 1;

 EXTENT_ID      BYTES     BLOCKS
---------- ---------- ----------
         0      12288          3
         1      12288          3
         2      20480          5
         3      40960         10
         4      61440         15

my block size is 4k...

i tried NEXT=NEXT*(1+PCTINCREASE/100)...and rounded it...but still i couldn't
get the value what Oracle is allocating.

And also...how many rows would you think it can store per block. i guess...you
would say 1 row per block...but the table size doesn't cross 2k itself.

would you throw some lights...

thanks,
senthil.
and we said...
See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c02block.htm#2846
for  the algorithm behind grabbing extents.  It is a function of what space is
available as well.

It'll store 1 row per block because we hate to chain rows across more then 1
block and on a 4k block (minus the block overhead and minus the 10% free you
have) there isn't enough room for two rows to completely fit.

Suggestion:  avoid dictionary managed tablespaces and NEVER use pctincrease with
a value of anything other then 0 if you do use them.  Use locally managed with
uniformly sized extents.
Review & Followup
Rating: 4
August 28, 2001
Reviewer: A reader

August 28, 2001 alex -- Thanks for the question regarding "dbms_job.submit", version 816
You Asked
Hi,

I wrote a package that kicks off  a procedure in the background using dbms_job.
 This works fine when I hard code the string, but when I pass it in as vbls then
it does not work, I get a 6550 error (which I could not find too much about on
metalink).  When I use dbms_output to look at the string passed in its identical
to what I hard code. I also check the length and that too is the same.

Any idea why the input would work when hard coding but not when passing as a
vbl?

Thanks
Alex

Attached is the first code hard coding, the second is where I assemble the data
into the string “lv_proc_txt”
----------CUT 1
   PROCEDURE status                                                         --
                   (
      i_jobtype_txt   IN   VARCHAR2,
      i_jobname_txt   IN   gen_labels.job_name%TYPE,
      i_branch_txt    IN   adp_branch.no%TYPE,
      i_jobct_num     IN   NUMBER
   )
   IS
      -- LIST LOCAL VARIABLES
      lv_checkjob_num   PLS_INTEGER    := 0;
      lv_err_msg        VARCHAR2 (150);
      lv_dbmsjob_num    NUMBER;
      lv_proc_txt       VARCHAR2 (128);
   BEGIN
      DBMS_JOB.submit
(lv_dbmsjob_num,'gen_labels_pkg.make_labels(''E'',''TEST'','''',10);');
      DBMS_JOB.run (lv_dbmsjob_num);
      COMMIT;
   EXCEPTION
      WHEN OTHERS
      THEN
         DBMS_OUTPUT.put_line ('Error ' || TO_CHAR (SQLCODE) || lv_err_msg);
   END status;

----------CUT 2
   PROCEDURE status                                                         --
                   (
      i_jobtype_txt   IN   VARCHAR2,
      i_jobname_txt   IN   gen_labels.job_name%TYPE,
      i_branch_txt    IN   adp_branch.no%TYPE,
      i_jobct_num     IN   NUMBER
   )
   IS
      -- LIST LOCAL VARIABLES
      lv_checkjob_num   PLS_INTEGER    := 0;
      lv_err_msg        VARCHAR2 (150);
      lv_dbmsjob_num    NUMBER;
      lv_proc_txt       VARCHAR2 (128);
   BEGIN
      lv_proc_txt :=
         '''' || 'gen_labels_pkg.make_labels(' || '''' || '''' || i_jobtype_txt
||
            '''' ||
            '''' ||
            ',' ||
            '''' ||
            '''' ||
            i_jobname_txt ||
            '''' ||
            '''' ||
            ',' ||
            '''' ||
            '''' ||
            i_branch_txt ||
            '''' ||
            '''' ||
            ',' ||
            i_jobct_num ||
            ');' ||
            '''';
      DBMS_JOB.submit (lv_dbmsjob_num, lv_proc_txt);
      DBMS_JOB.run (lv_dbmsjob_num);
      COMMIT;
   EXCEPTION
      WHEN OTHERS
      THEN
         DBMS_OUTPUT.put_line ('Error ' || TO_CHAR (SQLCODE) || lv_err_msg);
   END status;
and we said...
The string you are submting in the first case is:

ops$tkyte@ORA815> select 'gen_labels_pkg.make_labels(''E'',''TEST'','''',10);'
  2  from dual;

'GEN_LABELS_PKG.MAKE_LABELS(''E'',''TEST'',''
---------------------------------------------
gen_labels_pkg.make_labels('E','TEST','',10);

(the '' is just a way to get a single quote into a string, see how its really a
single quote?).  In the second case it is:

 1  select
  2    '''' || 'gen_labels_pkg.make_labels(' || '''' || '''' || dummy ||
  3              '''' ||
  4              '''' ||
  5              ',' ||
  6              '''' ||
  7              '''' ||
  8              dummy ||
  9              '''' ||
 10              '''' ||
 11              ',' ||
 12              '''' ||
 13              '''' ||
 14              dummy ||
 15              '''' ||
 16              '''' ||
 17              ',' ||
 18              dummy ||
 19              ');' ||
 20                     ''''
 21* from dual
ops$tkyte@ORA815> /

''''||'GEN_LABELS_PKG.MAKE_LABELS('||''''||''''||D
--------------------------------------------------
'gen_labels_pkg.make_labels(''X'',''X'',''X'',X);'

see the '' are in there -- but they should not be (they are ONLY used in
character string literals).  You want to build a string that looks like the
first string -- single quotes, no leading and trailing quotes.

In any case -- the BEST way to do this (to avoid having a unique statement for
every job you submit) is to do this:

create table gen_labels_pkg_PARMS
( jobtype_txt        varchar2(255),
  jobname_txt        varchar2(255),
  branch_txt         varchar2(255),
  jobct_num          number,
  job_id             number PRIMARY KEY
)
/

create or replace PROCEDURE status
(
      i_jobtype_txt   IN   VARCHAR2,
      i_jobname_txt   IN   gen_labels.job_name%TYPE,
      i_branch_txt    IN   adp_branch.no%TYPE,
      i_jobct_num     IN   NUMBER
)
IS
      lv_checkjob_num   PLS_INTEGER    := 0;
BEGIN
      dbms_job.submit( lv_checkjob_num, 'gen_labels_pkg.make_labels(JOB);' );
      insert into gen_labels_pkg_parms
      (jobtype_txt, jobname_text, branch_txt, jobct_num, JOB_ID )
      values
      (i_jobtype_txt, i_jobname_text, i_branch_txt,
       i_jobct_num, lv_checkjob_num );

      commit;

      (why were you running the job?  you might just as well execute it directly
as dbms_job.run BLOCKS while it runs it -- It does not background it)

end;

Then your gen_labels_pkg procedure would take one input (the job number assigned
to it) and goto the PARMS table and do this in its startup code:

is
  ....
   l_parms   gen_lables_pkg_parms%rowtype;
begin
   select * into l_parms from gen_labels_pkg_parms where job_id = i_job;
   delete from gen_labels_pkg_parms where job_id = i_job;

   ......

That way the string you submit to the job queue is now a CONSTANT (there will
not be many copies of this procedure call flooding your shared pool -- there
will be but one parsed statement "gen_labels_pkg.make_labels(JOB);" in your
entire instance) AND you avoid this quoting issue all together.

If you are interested in more details on how my approach above works -- i have a
pretty good chapter on dbms_job in my book that describes how dbms_job works
(what  goes on under the covers) and how best to use it.
August 28, 2001 oracle -- Thanks for the question regarding "PL/SQL TABLES", version 8.1.7
You Asked
Tom

I have heard so many developers say that if is very fast to load a pl/sql table
with primary key values and then delete them from the table.

I dont understand. Can you please explain a few situations where we delete
using pl/sql tables.

Can you also give me examples or illustrations of use of pl/sql tables.

thank you
and we said...
They are talking about bulk (array) operations.  Consider:

create table t as select * from all_objects;
alter table t add constraint t_pk primary key(object_id);

Then, I fill up an array with 1,000 rows to delete:

create or replace package demo_pkg
as
    type numArray is table of number index by binary_integer;
    l_pks  numArray;
end;
/

declare
    l_empty demo_pkg.numArray;
begin
    demo_pkg.l_pks := l_empty;
    for x in ( select object_id from all_objects )
    loop
        demo_pkg.l_pks(demo_pkg.l_pks.count+1) := x.object_id;
        exit when demo_pkg.l_pks.count = 1000;
    end loop;
end;
/

When we compare the performance of "loop over the array and delete each row",
versus "send the array to the kernel and let it loop over the array" we find:

begin
    for i in 1 .. demo_pkg.l_pks.count
    loop
        delete from t t1 where object_id = demo_pkg.l_pks(i);
    end loop;
end;

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.15       0.15          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.15       0.15          0          0          0           1

DELETE FROM T T1
WHERE
 OBJECT_ID = :b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute   1000      0.28       0.72         34       2000       3096        1000
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total     1001      0.28       0.72         34       2000       3096        1000

that was the "loop over the array and delete each one", now for the "send the
array down" version:

begin
    forall i in 1 .. demo_pkg.l_pks.count
        delete from t t2 where object_id = demo_pkg.l_pks(i);
end;

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.01       0.01          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.01       0.01          0          0          0           1

DELETE FROM T T2
WHERE
 OBJECT_ID = :b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.01          0          0          0           0
Execute      1      0.21       0.74         34       1002       3097           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.22       0.75         34       1002       3097           1

Rows     Row Source Operation
-------  ---------------------------------------------------
   1000  DELETE T
   1000   INDEX UNIQUE SCAN (object id 15505)

You can see that the CPU time spent in PLSQL is way way down and the delete
itself (it deleted the same number of rows) is a bit more efficient as well.
Review & Followup
Rating: 5
enlightening August 28, 2001
Reviewer: Ason from USA
In my code at a place Iam doing the following.(the cursor which feeds this
delete has round about 6000 records.)

For rec in cu_delrec
Loop
Delete
from t
where id=rec.id;
End Loop;

do you think I should load up all the id's into an array and do a for all
delete.

You are looping out after inserting 1000 recs into your array. How should I loop
out, actually, Idont think it is necessary to explicitly exit out of the loop
for me, after the 6000 id's are loaded up it automatically exits from he loop.

so, if I use the method you suggested for the above delete will it be more
efficient. Then why do many 1000's of developers around just do deletes like the
above.

Are there any situations where we  should not do a array delete.

thank you very much

Followup:
actually, in your case, I would not code ANY procedural code.  I would just:

   delete from t where id in ( <query that defined cu_delrec here> );

and do it in one line of code.  Why even bother getting the ID out via a query
if you just turn around and delete them right away?

remember

- if you can do it in a single statement, do it
- if not, a little plsql is good
- if plsql cannot do it (eg: send an email with an attachment), use a java
stored
  procedure

Rating: 4
but August 28, 2001
Reviewer: Ason
But for each of those id's I should set the status to deleted in an another
table.

If I follow your method, then I should follow up the delete statement with an
update statement updatting the concerned column to 'DELETED' ( the table has
round about 5000 rows)

wouldnt this be more expensive , then looping throught he curosr , deleting a id
, setting it to 'DELETED' and then go pick up another id.

Followup:
then you should probably:

update another_table set status = 'DELETED'
  where id in ( <query that defined cu_delrec here>  )

delete from t where id in ( <query that defined cu_delrec here> );

Unless the query defined by cu_delrec is a totally "long running, poor
performing" query -- it'll be faster just to let the sql engine do it's job.

If that query WAS a poor performer, I might be tempted (after exhausting all
tuning avenues) to do this:

   insert into A_GLOBAL_TEMPORARY_TABLE_CREATED_WITH_ON_COMMIT_DELETE_ROWS
    <query that defined cu_delrec here>;

   update another_table set status = 'DELETED'
     where id in ( select * from that temp table );

   delete from t where id in ( select * from that temp table );

See also
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1205168148688

Rating: 5
???? August 28, 2001
Reviewer: Ason from USA
Tom

I dont see any difference between the situation you have described above and my
situation, you have 10000 rows, I have 6000 rows.

Then why do you say that a direct delete works better for me, why didnt you
chose a direct delete in your case.

When should I delete with pure sql , and when should I delete with arrays.

Iam sorry, but can you beat this to death, and no rebirth.

Please

Followup:
I didn't do a direct delete for two reasons:

1) the question asked how to array delete -- so that is what I did.

2) I didn't know where the primary keys were coming from.  There is no rule
saying they were in a table.  One of your comments said "they came from this
cursor".  I just loaded up an array with values.  I could just as easily loaded
the array with random numbers.

Sometimes a demo is just that -- a demo.

You should delete with SQL when you can.
When you cannot (eg: the pk's are being passed to you, they don't exist handily
in a table, etc) you should use plsql.

Rating: 5
Well, you are doing good, but Iam dumb, I need examples August 28, 2001
Reviewer: Ason from USA
Tom

This is definitely not beating to death, leave alont beating to no rebirth.

You need to illustrate this with an example.

"When you cannot (eg: the pk's are being passed to you, they don't exist handily
in a table, etc) you should use plsql."

Dont leave me with ?'s in my mind.

Followup:
I'm sorry -- i can't followup on this thread anymore.  I don't know what else to
say.

I'll say it one more time

- if the primary keys were already in a table, identifiable via SQL -- DON't
read them out and then send them back to the database.  Just use a subquery.

- if the primary keys are NOT in a table, for example a client application just
sent you an array of them, use PLSQL.

So, if you can:

  delete from t1 where x in ( select y from t2 )

do it.  Don't code:

   for c in ( select y from t2 )
   loop
        delete from t1 where x = c.y;
   end loop;

August 29, 2001 Tran -- Thanks for the question regarding "DBMS_JOB.Interval", version 8.1.6.0.0
You Asked
Hi Tom,
How can I schedule a job running every day except two day of week? For example,
I want a job to run at 8 am every day except Thursday and Friday.

Thanks,
Tran Luong.
and we said...
your interval can be:

'trunc(decode( to_char( sysdate+1, ''DY'') ,
             ''THU'', next_day(sysdate,''SAT''),
             ''FRI'', next_day(sysdate,''SAT''), sysdate+1 ))+8/24'

(assuming english as the language, adjust THU, FRI, SAT as need be)

I tested with a query like this:

ps$tkyte@ORA8I.WORLD> select d,
  2        trunc(decode( to_char( d+1, 'DY') ,
             'THU', next_day(d,'SAT'), 'FRI', next_day(d,'SAT'), d+1 ))+8/24
  3  from ( select sysdate+rownum d from all_objects where rownum <= 25 )
  4  /

D                        TRUNC(DECODE(TO_CHAR(D+1
------------------------ ------------------------
Thu 30-Aug-2001 09:33:47 Sat 01-Sep-2001 08:00:00
Fri 31-Aug-2001 09:33:47 Sat 01-Sep-2001 08:00:00
Sat 01-Sep-2001 09:33:47 Sun 02-Sep-2001 08:00:00
Sun 02-Sep-2001 09:33:47 Mon 03-Sep-2001 08:00:00
Mon 03-Sep-2001 09:33:47 Tue 04-Sep-2001 08:00:00
Tue 04-Sep-2001 09:33:47 Wed 05-Sep-2001 08:00:00
Wed 05-Sep-2001 09:33:47 Sat 08-Sep-2001 08:00:00
Thu 06-Sep-2001 09:33:47 Sat 08-Sep-2001 08:00:00
Fri 07-Sep-2001 09:33:47 Sat 08-Sep-2001 08:00:00
Sat 08-Sep-2001 09:33:47 Sun 09-Sep-2001 08:00:00
Sun 09-Sep-2001 09:33:47 Mon 10-Sep-2001 08:00:00
Mon 10-Sep-2001 09:33:47 Tue 11-Sep-2001 08:00:00
Tue 11-Sep-2001 09:33:47 Wed 12-Sep-2001 08:00:00
Wed 12-Sep-2001 09:33:47 Sat 15-Sep-2001 08:00:00
Thu 13-Sep-2001 09:33:47 Sat 15-Sep-2001 08:00:00
Fri 14-Sep-2001 09:33:47 Sat 15-Sep-2001 08:00:00
Sat 15-Sep-2001 09:33:47 Sun 16-Sep-2001 08:00:00
Sun 16-Sep-2001 09:33:47 Mon 17-Sep-2001 08:00:00
Mon 17-Sep-2001 09:33:47 Tue 18-Sep-2001 08:00:00
Tue 18-Sep-2001 09:33:47 Wed 19-Sep-2001 08:00:00
Wed 19-Sep-2001 09:33:47 Sat 22-Sep-2001 08:00:00
Thu 20-Sep-2001 09:33:47 Sat 22-Sep-2001 08:00:00
Fri 21-Sep-2001 09:33:47 Sat 22-Sep-2001 08:00:00
Sat 22-Sep-2001 09:33:47 Sun 23-Sep-2001 08:00:00
Sun 23-Sep-2001 09:33:47 Mon 24-Sep-2001 08:00:00

25 rows selected.

That shows it computes the NEXT_DATE properly given your criteria.
Review & Followup
Rating: 4
August 29, 2001
Reviewer: Tran Luong from VietNam
Excellent

August 29, 2001 Ganesh -- Thanks for the question regarding "Locatin of listener.ora and tnsnames.ora files", version 7.3
You Asked
Hi Tom,

As far as my knowledge goes I understand in Solaris filesystem 'listener.ora'
and 'tnsnames.ora' files are in /var/opt/oracle/
area and for HP and Digital machines these files are found in /etc/
area by default .Is there anyway in which I can keep these files to some other
area in the filesystem.If Yes, then do let me know.

Thank you Tom .
and we said...
You can use the TNS_ADMIN environment variable to put them where ever you want

$ORACLE_HOME/network/admin

works as well -- you can put them there instead.
Review & Followup
Rating: 4
multiple homes August 29, 2001
Reviewer: Randy from Texas
What is your suggestion for the location when using multiple homes?  Should the
tns files be specific to a home (for compatiblity)?

Followup:
It depends on your needs.

If you are using ONE listener for all databases (you can use the listener from
817 to service and 815 database for example), you would put them in one place.

If you are running a listener/server - you might want to put your listener.ora
into the $ORACLE_HOME/network/admin directory for each oracle_home  just to keep
them separate.

As for the tnsnames.ora file, i generally find it easiest to use one on a
machine instead of one per server as they typically all end up with the same
list of servers.

Rating: 4
Unix Servers August 29, 2001
Reviewer: A reader
On most unix servers, if you have a common listener.ora file for multiple
databases, the most common place is in /etc directory.

Rating: 4
August 29, 2001
Reviewer: Tianhua Wu from Atlanta, GA
use truss(unix) or strace(linux) on "tnsping service_name", you will see Oracle
check several places.

August 29, 2001 Raj -- Thanks for the question regarding "Caching dataset (rows) retrieved by a query", version 8.1.6
You Asked
Hi Tom,

We have a table (say, user_security) that could end up with between 200,000 and
500,000 records. Every time a user clicks on a hyperlink within our application,
we will dip into this table to verify if the user has the permission to perform
this task. For each user, we will have about 2000 rows in this table. After
retrieving from user_security table for the first time, I want to cache these
2000 rows of each logged in user (there will be about 5-20 concurrent logged in
users) so that each subsequent permission check wouldn’t have to dip into the
500,000 row table.

One thought I had was that I would create a table say user_security_cache with
same schema as user_security. Every time a new user logs in, I would retrieve
his/her profile from user_security and insert these 2000 rows in
user_security_cache. If profile rows of this user already exist, they will first
be deleted and fresh profile rows will be inserted. What is your opinion on
this? Would insert/delete result into a lot of overhead?

1.    Can you recommend any better caching mechanism?
2.    Since there is no sub-totaling involved, could materialized views be
helpful here?
3.    Could we rely on 8.1.6’s caching mechanism instead and be guaranteed that
oracle would get data from the cache instead of going back to the 500,000 row
table every time?

Thanks,
Raj
and we said...
well -- here is my 2 cents.

The purpose of a cache is to hold frequently accessed data.  If the data hasn't
been accessed in a while- get rid of it.

That is how the buffer cache works.  If you don't use it -- you lose it.

As for a "cached" table -- it is somewhat of a mis-nomer.  The cache attribute
of a table only controls what happens when you FULL SCAN the table.  Normally,
in a full scan the blocks you just read are the FIRST blocks to get bumped out
of the buffer cache.  This is to avoid a full scan "blowing out" or reseting the
buffer cache.  Hence -- blocks that are full scanned tend to get out of the
cache very fast.  By setting a table to CACHE -- you will cause the blocks from
a full scan on that table to be treated as though they were accessed via an
index.  They will NOT tend to get flushed right away.

Hence -- if you "cache" a table that you read via an index -- you done
effectively "nothing".  In your case -- since you get 2000 rows from 500,000 I
would guess that you are using an index and hence the "cached" table will work
just like non-cached version (only you'll have TWO copies if you try the "user
security_cache and user_security trick since both tables would now be cached).

as for the direct questions

1) I would use the standard buffer cache.  I might look at various database
structures such as IOTS (index organized tables) and *especially* clusters to
physical locate all of the records for a user together. This will make MUCH
better use of the buffer cache.  If I just use a HEAP table -- the 2,000 entries
for a single user might be spread out on 2,000 blocks (and the rest of the data
on these blocks might be of NO interest to me right now).  So, 5 users might
need 10,000 blocks to cache their data.  Using a cluster I could make it so that
ll of user 1's rows are stored together on as few different blocks as possible
(say I get 100 rows/block -- on 20 blocks).  Now I need 100 blocks for these
same 5 users, huge difference.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1197906066709
for an IOT example and the effect this physical clustering of data can have.
Also, I have a pretty good chapter on this in my book if you are interested.

2) I don't see the aplicability here.

3) You will DEFINITELY rely on this.  You just need to maximize our ability to
efficiently cache data by using the proper storage mechanisms.
Review & Followup
Rating: 4
Why not use package variables August 29, 2001
Reviewer: Arup Nanda from Norwalk, CT, USA
As to the return question from Raj, I would suggest using package variables to
hold teh 2000 row data from the security table. Use a PL/SQL table or simply
2000 package variables to SELECT these rows INTO when the user first log on and
merely query the package variable. This will be real fast. However there is no
way to make sure the packaged variables are reloaded when the table changes.

Another option is to use a temporary table.

Rating: 4
August 29, 2001
Reviewer: Raj from New Jersey
Tom,
I now understand that the 2000 rows/per user are coming not from one table of
500,000 rows but rather from a join of several tables that result into 5000
rows. In which case, what do you think about the idea I had mentioned in my
original posting - if I insert these 2000 rows in a 'mini' table when a user
first lgos in and then make subsequent queries go against this mini table. Is
this viable? Would the overhead of inserts/deletes be too much? Another problem
I see is that if the permission data changes in one of the original tables, how
can that be reflected in this 'mini' table?
Thanks,

August 29, 2001 sangita -- Thanks for the question regarding "Error in dynamic sql", version 8.1.7
You Asked
Hi Tom
I am running a dynamic query using bind variables .
Here is the code

CREATE OR REPLACE PACKAGE A268343.PKG_TEST1
 AS
  TYPE var_resultset IS REF CURSOR;
Procedure P_GET_CALENDAR_LIST(var_category_id IN V_CATEGORY.CATEGORY_ID%TYPE,
                var_resource_id IN V_CALENDAR.RESOURCE_ID%TYPE,
                var_scount IN NUMBER,
                var_scategory_id IN VARCHAR2,
                var_group_id IN V_CALENDAR.GROUP_ID%TYPE,
                var_impact IN V_CALENDAR.IMPACT%TYPE,
                var_environment IN  V_CALENDAR.ENVIRONMENT%TYPE,
                var_start_date  IN VARCHAR2,
                var_end_date IN VARCHAR2,
                var_sort_by IN VARCHAR2,
                var_sort_dir IN VARCHAR2,
                              var_recordset OUT  var_resultset);

 END PKG_TEST1;

CREATE OR REPLACE PACKAGE BODY A268343.PKG_TEST1
AS
Procedure P_GET_CALENDAR_LIST(var_category_id IN V_CATEGORY.CATEGORY_ID%TYPE,
                var_resource_id IN V_CALENDAR.RESOURCE_ID%TYPE,
                var_scount IN NUMBER,
                var_scategory_id IN VARCHAR2,
                var_group_id IN V_CALENDAR.GROUP_ID%TYPE,
                var_impact IN V_CALENDAR.IMPACT%TYPE,
                var_environment IN  V_CALENDAR.ENVIRONMENT%TYPE,
                var_start_date  IN VARCHAR2,
                var_end_date IN VARCHAR2,
                var_sort_by IN VARCHAR2,
                var_sort_dir IN VARCHAR2,
                              var_recordset OUT  var_resultset)
IS
var_new_category_id V_CATEGORY.CATEGORY_ID%TYPE;
var_new_resource_id V_CALENDAR.RESOURCE_ID%TYPE;
var_new_group_id V_CALENDAR.GROUP_ID%TYPE;
var_new_end_date VARCHAR2(20);
var_new_start_date VARCHAR2(20);
var_new_scategory_id VARCHAR2(100);

sql_query varchar2(3000) default
    'SELECT t0.calendar_id,
        t0.mcategory_id,
        t0.scategory_id,
        t0.resource_id,
        t0.impact,
        t0.environment,
        t0.change_desc,
         to_char(t0.change_date,'||'''mm/dd/yy'''||') as change_date,
        t1.category,
        t2.category as scategory,
        t3.resource_name
    FROM v_calendar t0,
         v_category t1,
         v_category t2,
         v_resource t3
    WHERE t0.mcategory_id = t1.category_id
    AND t0.scategory_id = t2.category_id
    AND t0.resource_id = t3.resource_id';
--sql_query1 varchar2(1000) ;
sql_order_by varchar2(255) default 'ORDER BY t0.mcategory_id';
BEGIN
    If var_category_id <> -1 And var_category_ID is not null Then
        sql_query := sql_query ||' AND t0.mcategory_id = :1';
        var_new_category_id := var_category_id;
    Else
        var_new_category_id := null;
    End If;
    If var_resource_id <> -1 And var_Resource_ID is not null Then
        sql_query := sql_query ||' AND t0.resource_id = :2';
        var_new_resource_id := var_resource_id;
    Else
        var_new_resource_id := null;
    End If    ;
    If var_group_id  <> -1 And var_group_id is not null Then
        sql_query := sql_query ||'  AND t0.group_id = :3';
        var_new_group_id := var_group_id;
    Else
        var_new_group_id := null;
    End If    ;
    If var_end_date is not null Then
        sql_query := sql_query ||' AND t0.change_date <= :4';
        var_new_end_date:= var_end_date;
    Else
        var_new_end_date:=null;
    End If    ;
    If var_start_date is not null then
        sql_query := sql_query ||' AND t0.change_date >= :5';
        var_new_start_date := var_start_date;
    Else
        var_new_start_date := null;
    End If    ;
    If var_scategory_id is not null then
         sql_query := sql_query ||' AND t0.scategory_id in (:6)';
        var_new_scategory_id := var_scategory_id;
    Else
        var_new_scategory_id := null;
    End If    ;

    If var_sort_by = 'IMPACT' Then
        sql_order_by := sql_order_by ||', t0.impact '||nvl(var_sort_dir,'ASC') ;
    ElsIf var_sort_by = 'ENVIRONMENT' Then
        sql_order_by := sql_order_by||', t0.environment
'||nvl(var_sort_dir,'ASC') ;
    ElsIf var_sort_by = 'CHDESC' Then
        sql_order_by := sql_order_by||', upper(t0.change_desc)
'||nvl(var_sort_dir,'ASC') ;
    ElsIf var_sort_by = 'SCATEGORY' Then
        sql_order_by := sql_order_by||', upper(t2.category)
'||nvl(var_sort_dir,'ASC') ;
    ElsIf var_sort_by = 'CHDATE' Then
        sql_order_by := sql_order_by||', t0.change_date
'||nvl(var_sort_dir,'ASC') ;
    Else
        sql_order_by := sql_order_by||', t2.order_number, upper(t2.category),
upper(t0.change_desc), t0.change_date';
    End If;
sql_query:=sql_query||' '||sql_order_by;
dbms_output.put_line(substr(sql_query,1,250));
dbms_output.put_line(substr(sql_query,251,250));
dbms_output.put_line(substr(sql_query,501,250));
dbms_output.put_line(substr(sql_query,751,250));
open var_recordset for sql_query using
var_new_category_id,var_new_resource_id,var_new_group_id,var_new_scategory_id;
END P_GET_CALENDAR_LIST;
END PKG_TEST1;

Detail : where the input variable var_scategory_id is a string of id's
I also have used the null for variables in the using clause.

When I run the proc so that it just runs the default query i am getting the
following error

exec
pkg_test1.P_GET_CALENDAR_LIST(null,null,null,null,null,null,null,null,null,null,n
ull,:a)

ERROR
ORA-01006: bind variable does not exist
ORA-06512: at "A268343.PKG_TEST1", line 100
ORA-06512: at line 1

Please let me know your views on this and also how to handle the string of ids
in the variable var_scategory_id .

This package is being called by the ASP front end

Thanks in advance
Sangita saxena
and we said...
Ok, you have an unknown number of bind variables.  Sometimes NONE, sometimes
apparently as many as 6.

You always bind in 4 of them regardless.

The way to do this using Native Dynamic Sql is shown here:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
...
Review & Followup
Rating: 5
Dynamic Query August 30, 2001
Reviewer: Randy from Chicago, IL
Gesss!! Is this forum to debug the pl/sql program ? Cannt we expect a better use
of it ?

August 30, 2001 sj -- Thanks for the question regarding "Comments on objects in the database.", version 8.1.7
You Asked
Tom
What kind of comments are stored in the database
In which database view are comments stored.
What kind of comments are stored in the database. The comments I give in my
pl/sql procedures , can they be stored in a database.

Can you tell about comments.

THANK YOU
and we said...
See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/ch4e3.htm#16825
you can comment on TABLES/VIEW and COLUMNS of such.  They are stored in

VIEW         ALL_COL_COMMENTS
             ALL_TAB_COMMENTS
             DBA_COL_COMMENTS
             DBA_TAB_COMMENTS
             USER_COL_COMMENTS
             USER_TAB_COMMENTS

The comments you put into your procedures are preserved -- you can query
ALL_SOURCE to see your code with the comments intact.
August 30, 2001 Ruben -- Thanks for the question regarding "Function Based Index -- what privs are needed.", version 8.1.7
You Asked
Hi, tom

Some developers other than DBA, want to create function based index,
but the error ora-1031 is issued.
to resolve this, I granted 'em the role DBA for a while, meantime they
can create that indexes.

What privilege(s) should I grant to developers for they create the FBI,
instead to grant the DBA role.?
(I don't want they keep this role).

thanks in advance.
and we said...
See
http://osi.oracle.com/~tkyte/article1/index.html#how
...
August 30, 2001 Paul -- Thanks for the question regarding "The way Oracle allocates physical disk space", version 8- 817
You Asked
Tom, I am reading your book "expert one-on-one oracle", page 64.

My question is, How does oracle keep an extent contigous on the physical hard
disk operated by the operating system.  I am a qualified network engineer as
well and understand fully how this is done by the operating system on NT and
UNIX.  Because the disk controller will write in say (UNIX) 512k* blocks etc,
and the operating system must have control of the disk controller, how can
oracle control this to keep its extents say 1GB contigous, if I have lost the
plot and it is simple I appologise in advance. Please help as this is vexing me.

Thanks in advance
and we said...
Sorry -- I probably should not have said "on disk" -- i should probably have
said in a "file".

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1056598515561
hopefully that will clarify it.
Review & Followup
Rating: 5
The way Oracle allocates physical disk space August 30, 2001
Reviewer: Paul Dutton from Manchester, United Kingdom
Tom

Thanks, that has settled a little discussion the team was having.

August 30, 2001 Senthil -- Thanks for the question regarding "Calculate index space...", version 8.1.5
You Asked
Tom,

Is there anyway that we can calculate/predict space for index. i know there are
few methods to estimate space for table growth. Like that, do we have any method
or atleast workaround to estimate space for all indexes created for the table.

thanks,
senthil.
and we said...
Not with any accuracy.  Here is why.

Not only do you need to know how big your index entries are (hard/impossible
with varchars and numbers as they are varying length fields) but you need to
know how your index is modified.

Lets say you only insert and update in this index.  Well, your index could end
up being many times larger then it would be if you rebuilt it.  The reason is
that if you update a value -- the position it was in is "still there" in the
index structure.  We can reuse it -- but it depends on how you use the data.
For example:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x varchar2(1) );
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index t_idx on t(x);
Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'a' );
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'b' );
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'd' );
ops$tkyte@ORA817DEV.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817DEV.US.ORACLE.COM> update t set x = 'e' where x = 'b';
1 row updated.

ops$tkyte@ORA817DEV.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze index t_idx validate structure;
Index analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select lf_rows, del_lf_rows from index_stats;

   LF_ROWS DEL_LF_ROWS
---------- -----------
         4           1

that shows that there are 4 entries in the index -- but one of them is
"deleted".  There is a hole between 'a' and 'd' in the index.  If we put in some
data that fits there (note: it does not have to be the SAME data -- just has to
fall between 'a' and 'd'):

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'c' );
1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze index t_idx validate structure;
Index analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select lf_rows, del_lf_rows from index_stats;

   LF_ROWS DEL_LF_ROWS
---------- -----------
         4           0

we'll reuse that.

So, estimating on paper how an index will grow can be extremely tricky.  You
through some deletes in there with the updates -- the fact that an index block
will be reclaimed when ALL index entries on it are marked as deleted (space is
reused) but won't be if one entry remains, the fact that it is a complex data
structure and estimation before the fact is hard.

You can estimate the initial size of the index (search for sizing on my site)
using the same technique I use for sizing a table (load some representative
data, index it and multiply).

Estimating growth is something you can do after you either really use the index
or simulate how you will use the index (benchmark).
Review & Followup
Rating: 4
August 30, 2001
Reviewer: A reader
That was a nice explanation...thanks.

Rating: 5
necessitates index rebuilds August 30, 2001
Reviewer: Mark from Ca
so i am surmising that for an increasing sequential primary key, deleted index
space will never be reused, and will always be growing...thus necessitating an
index rebuild at appropriate times...
BTW: I enjoy your well run site and the competent, documented knowledge that you
disseminate.

Followup:
No, not at all.  Only in the worst of degenerate cases.

If you insert 1,2,3,4,5,6........ <big number>

and then delete 1,2,3,4,5,6.......<some number>

we'll reclaim all of the space.  If you delete every OTHER number -- we'll end
up with lots of holes that will not be reused (by the nature of the sequence).

I find in general however that most applications tend to "archive" old data and
would tend to delete all of the old data.  In this case, the index space would
be reused.

It is only the application that leaves some of the old data behind forever that
might necessitate a rebuild over a long period of time.

Rating: 5
August 30, 2001
Reviewer: mark from ca
thanks tom, i think i have the hole picture...

Followup:
No pun intended with "hole" in that comment was there ;)

August 30, 2001 Markus -- Thanks for the question regarding "difficult question about "MAXEXTENTS"", version 8.0.5.0.0
You Asked
Hi Tom,

Here is my problem:

I've a customer who ask's something about the
default value of the storageparmeter maxextents:

for best performance the books about oracle
suggest to use the following optimal value
(depend on the blocksize) for maxextents:

Blocksize:     Maxextent:

1 K            57
2 K            121
4 K            249  .......

and so on.

Now his questions:

1. Abstract:How does the extentadministration behave in detail ?

2. Does the algorithm for admistration of extents changes when
   I use a higher value for maxextents than the optimal one??

3. Is there a difference (in the administration algorithm)
   between using a value (for maxextents) higher than the
   optimal value or using "unlimited" extents??

Thank You very much for Your attention.

Ciao Markus
and we said...
Looks like old books on Oracle.  Those would have been
recommended in the days when the maximum number of extents in a
tablespace was dictated by the blocksize.  Those are the maximum
number of extents you could have in a tablespace given those
blocksizes.

I use maxextents unlimited typically with FIXED size extents
(pctincrease = 0, initial = next for all objects in a tablespace
and all objects use the same initial and next values).

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c02block.htm#2775
for details on extent management.

when you get to 8i, you will start using LOCALLY MANAGED
tablespaces as well.....
Review & Followup
Rating: 3
August 30, 2001
Reviewer: Senthil
I see you were recommending to use locally managed tablespace in your replies. i
guess...if we use locally managed tablespace, we are going to lose control in
storage allocation, and also it uses *unlimited* maxextents. we are not allowed
to allocate storage parameter value even in table creation level. lets say
locally managed tablespace is good enough than dictionary managed
tablespace...but to get that feature...do we have to monitor space growth for
our tables & tablespaces, since all our tables and tablespaces are allocated
*unlimited* maxextents. ofcourse we can restrict the growth in datafile level.
but what would be the best method.
Oracle has received this as a enhancement bug and...i guess...still they havent
fixed it in 9i. Please correct me if i am wrong.

Followup:
I don't see how having maxextents set to unlimited makes you do any more work
then having a limit on the number of extents (in fact, to the contrary -- you
have to monitor them less since you don't have to worry about the GETTING to
their maxextent).

You have to do the same amount of space monitoring here as you would for
anything else (well, maybe a little less monitoring since you don't have to
worry about objects getting close to their maxextent).

In an LMT, if there is room to grow -- it will grow.  If you artificially
prevent it from growing the only thing you've done is made it so your system
stops functioning (unable to extend, maxextents is hit).  If there is not room
-- it won't grow.

If you want to artificially limit the size of a table, put it in its own
tablespace and limit the size of the files.  Me, I'll watch the objects grow and
if need be add more space OR change the way they are used.  Putting an
artificial limit on the number of extents just doesn't make sense in my opinion.

August 30, 2001 ted -- Thanks for the question regarding "extent allocation and rman compression", version 8.1.6
You Asked
thomas,

1. I created a table with 64k initial 64k next 64k pctincrease 0
    minextents 5. segment extent indicate 64k for 5 extent.
    to my surprise when another table created with 40k allocation
    segment extent has 5 extents with 64k. I am using nt with 8k block
    size. user_table has initial 40k next 40k .why the inconsistency ?

2. Can you shed some light on how rman compress the tables on datafile ?

thnx ted chyn

  1  create table t ( x int, y char(2000) default '*' )
  2*     storage ( initial 64k next 64k pctincrease 0 minextents 5 )
  3  /

Table created.

SQL> select extent_id, bytes, blocks
  2       from user_extents
  3       where segment_name = 'T'
  4         and segment_type = 'TABLE';

 EXTENT_ID      BYTES     BLOCKS
---------- ---------- ----------
         0      65536          8
         1      65536          8
         2      65536          8
         3      65536          8
         4      65536          8

SQL> drop table t;

Table dropped.

 SQL> drop table t;

Table dropped.

SQL>  create table t ( x int, y char(2000) default '*' )
  2       storage ( initial 40k next 40k pctincrease 0 minextents 5 );

Table created.

SQL> select extent_id, bytes, blocks
  2       from user_extents
  3       where segment_name = 'T'
  4         and segment_type = 'TABLE';

 EXTENT_ID      BYTES     BLOCKS
---------- ---------- ----------
         2      65536          8
         3      65536          8
         4      65536          8
         0      65536          8
         1      65536          8
and we said...
1) see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c02block.htm#2846
there must have been some free space chunk out there 64k in size and are won't
orphan a tiny 3block chunk to satisfy such a small allocation.  We just gave you
64k instead of 40k and leaving a useless 24k orphaned chunk of free space.

If you issued an alter tablespace coalesce after the drop before the second
create, you might get a different result.

As you are using 816, you should just be using locally managed tablespaces with
uniform extents -- ignore dictionary managed tablespaces.

2) see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76990/rmanconc.htm#437766
rman does not compress tables in a datafile, rman can "compress" a backup set by
not copying blocks that have never been used.
August 31, 2001 pauline -- Thanks for the question regarding "RE: SID in V$session_longops not in V$session", version 8.1.7
You Asked
Tom,
How are you? Thanks for all your helps.
Today I have some questions.
1. Why some SIDs in V$session_longops are not in V$session and some  data in the
field of start_date in V$session_longops are totally wrong? For example, one of
our instance using 8.1.7 was created last year, but we see the value in
start_date with the date as 1998 or 1999. It is kind of strange.

2. We use locally managed tablespace for RBS tablesapce and created
RBS with minextents 20. But if select minextents from dba_rollback_segs, we
always see minextents for RBS with the value as
1. In other instance without using locally managed tablespace for RBS
tablespace, dba_rollback_segs shows the correct information.This made me
confuse. Why?

Thanks.

Pauline
and we said...
1) until a row is USED in v$session_longops -- the values are erratic.  The data
in there comes from a fixed size, uninitialized array.  You should ONLY consider
rows such that the SID exists in v$session.  other rows contain uninitialized
values OR values from sessions that no longer exist.

2) When creating segments in locally managed tablespace, Oracle calculates
initial extent size from minextents, initial, next, pctincrease.
and uses it as initial size. Then, Oracle allocate enought extents to be greater
than calculated size.  This value can be seen at INITIAL_EXTENT column (if you
look at your INITIAL extent -- you'll discover its big enough to be your
(min_extents-1)*next_extent+initial_extent from your create rbs statement)

The following example may be helpful to understand what will happen.

create tablespace test datafile ... size ...
  extent management local uniform size 128k;

create rollback segment r1 tablespace test
  storage (initial 200k next 200k minextents 10);

So, Oracle calculates initial segment size 2000k, and allocated 16 extents.
Minextents 10 is used only when creating. If you issue alter rollback segment
shrink, it will reduce to initial size(2000k, 16 extents), not 10.

That is why minextents is 1 in the LMT -- we adjusted all of the storage
parameters to fit into the sizing scheme for the LMT you put them into.
Review & Followup
Rating: 4
August 31, 2001
Reviewer: Pauline from NY, U.S.A.
Good explanation and it makes me much clear.

August 31, 2001 Petroula -- Thanks for the question regarding "Pro C OCIExtProcContext error", version 8.1.6.0.0
You Asked
Hello Tom

I am working with external procedures and I have a question
regarding Pro*C and an error message that I get. My code is as
follows:

#include<stdio.h>
#include<stdlib.h>
#include<ociextp.h>
#include<oratypes.h>
#include<string.h>
#include<oci.h>
#include<sqlca.h>
#include<ocikp.h>
#include<ocikp.h>
#include<ori.h>
#include<oro.h>
#include<ort.h>
#include<ociap.h>
#include<sqlcpr.h>
#include<assert.h>

EXEC SQL include sqlca;
EXEC SQL include sqlda;

void __declspec(dllexport) c_insert(OCIExtProcContext *ctx, int
id, short id_i, char *name1, short *name1_i, int name1_l,
              char *phone, short *phone_i, int *phone_l)
    {

      EXEC SQL REGISTER CONNECT USING :ctx;

      EXEC SQL BEGIN DECLARE SECTION;
      int id_n;
      VARCHAR *name2;
      VARCHAR *ph;
      EXEC SQL END DECLARE SECTION;

      if ((id_i==OCI_IND_NULL)||(*name1_i==OCI_IND_NULL))
       {
         if
(OCIExtProcRaiseExcp(ctx,(int)6502)==OCIEXTPROC_SUCCESS)
             { return;}
             else{assert(0);}
       }
       id_n=id;
       strcpy(name2,name1);
       strcpy(ph,phone);

       EXEC SQL INSERT INTO PETROULA.PERSON
                VALUES(:id_n, :name2, :ph);

        return;
        }

As you can see I have desperately tried to include every
possible library in my program to get rid of my problem. The
problem is as follows, when I precompile I get the following
message:

           ++: Release 8.1.6.0.0 - Production on Thu Aug 24
11:48:43 2000

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

System default option values taken from:
E:\Oracle\Ora81\precomp\admin\pcscfg.cfg

Semantic error at line 25, column 40, file
c:\petroula\c_insert.pc:
      EXEC SQL REGISTER CONNECT USING :ctx;
.......................................1
PCC-S-02322, found undefined identifier
Semantic error at line 25, column 40, file
c:\petroula\c_insert.pc:
      EXEC SQL REGISTER CONNECT USING :ctx;
.......................................1
PCC-S-02336, host variable expression has invalid type
Semantic error at line 25, column 40, file
c:\petroula\c_insert.pc:
      EXEC SQL REGISTER CONNECT USING :ctx;
.......................................1
PCC-S-02383, Expecting an expression of type OCIExtProcContext

Id this because I didn't add something to my options file or
what?
   Any help would be greatly appreciated.
and we said...
Add PARSE=FULL to the precompiler command line.

Without it, it is not recognizing ctx because ctx is not in a
BEGIN/END declare section.

Here is a generic makefile I use with extprocs on NT with Pro*C.
It is designed to be used on the command line with nmake.  The
precompile line you want is at the bottom.

The other alternative is to

exec sql begin declare section;
OCIExtProcContext * localCtx;
exec sql end declare section;

   localCtx = ctx;
   exec sql registion connect using :localCtx;

...

-------------------------------------------------
CPU=i386
WRB_DIR         = .\

!include <c:\msdev\include\win32.mak>

MSDEV       = c:\msdev
ORACLE_HOME = c:\oracle

TGTDLL      = extproc.dll

OBJS = lobtofile.obj

NTUSER32LIBS    = $(MSDEV)\lib\user32.lib   \
                  $(MSDEV)\lib\msvcrt.lib  \
                  $(MSDEV)\lib\oldnames.lib  \
                  $(MSDEV)\lib\kernel32.lib   \
                  $(MSDEV)\lib\advapi32.lib

SQLLIB  = $(ORACLE_HOME)\precomp\lib\msvc\orasql8.lib  \
          $(ORACLE_HOME)\oci\lib\msvc\oci.lib

INCLS   = -I$(MSDEV)\include \
          -I$(ORACLE_HOME)\oci\include \
          -I.

CFLAGS  = $(INCLS) -DWIN32 -DWIN_NT -D_DLL

all: $(TGTDLL)

cleanup:
    erase *.obj *.lib *.exp lobtofile.c

$(TGTDLL): $(OBJS)
    $(link) -DLL $(dllflags) \
        /NODEFAULTLIB:LIBC.LIB -out:$(TGTDLL) \
        $(OBJS) \
        $(NTUSER32LIBS) \
        $(SQLLIB) \

lobtofile.c: lobtofile.pc
        proc sqlcheck=semantics \
         include=$(ORACLE_HOME)\network\public \
         include=$(ORACLE_HOME)\proc\lib \
         include=$(ORACLE_HOME)\rdbms\demo \
         include=$(ORACLE_HOME)\oci\include \
         include=\msdev\include \
         lines=yes \
         parse=full \
         iname=lobtofile.pc
Review & Followup
Rating: 5
Could u give me the corresponding make file for Solaris -Urgent Request.. August 30, 2001
Reviewer: Srinivash Regupathi from India
Hi ,

It was quite interesting to see this message. Iam geting the same error in the
Sun solarus platform. Could u give me the sample make file for this platform. I
tried including the parse=full option.. but in vain..

Also Could u help me out with sample from calling Pro*C from Pl/sql using
external routines. I was very successful in calling a C from pl/sql. But the
Pro*C code is failing in the connect itself. (Though ruuning successfully from
the commandline). This is a very urgent requirement.

Thanx in advance..

Followup:
Here is a unix one:

MAKEFILE= $(ORACLE_HOME)/rdbms/demo/demo_rdbms.mk

INCLUDE= -I$(ORACLE_HOME)/rdbms/demo \
         -I$(ORACLE_HOME)/rdbms/public \
         -I$(ORACLE_HOME)/plsql/public \
         -I$(ORACLE_HOME)/network/public

TGTDLL= extproc.so
OBJS  = extproc.o

all: extproc.so

clean:
    rm *.o

extproc.so: $(OBJS)
    $(MAKE) -f $(MAKEFILE) extproc_callback \
     SHARED_LIBNAME=$(TGTDLL) OBJS=$(OBJS)

CC=cc
CFLAGS= -g -I. $(INCLUDE) -Wall

from Solaris.

If you get my book -- i have a 70 page chapter on nothing BUT external
procedures in C using OCI and Pro*C, you may find that useful.

In order to use Pro*C with extprocs you must use Oracle8i and up (not
supported/implemented in 8.0) and you use the following syntax to "connect" :

static void init( OCIExtProcContext * ctx )
{

    EXEC SQL REGISTER CONNECT USING :ctx;
......

Rating: 2
Still problem Exists.. PCC-S-02383, Expecting an expression of type OCIExtProcContext August 31, 2001
Reviewer: Srinivash Regupathi from India
Hi,

I tried ur solution.  As suggsted by u , I have used parse=full but I end up
with the same error message.

Semantic error at line 14, column 34, file sample.pc:
exec sql register connect USING :epctx;
.................................1
PCC-S-02383, Expecting an expression of type OCIExtProcContext

I have written a simple code

#include<stdio.h>
#include <oci.h>

EXEC SQL INCLUDE SQLCA.H;
EXEC SQL include sqlda;

exec sql begin declare section;
OCIExtProcContext *epctx;
exec sql end declare section;

void extp1(epctx)
{
char name[15];
exec sql register connect USING :epctx;
        EXEC SQL WHENEVER SQLERROR goto err;
        EXEC SQL SELECT ename INTO :name FROM emp WHERE empno = 9999;
        return;
err:
SQLExtProcError(SQL_SINGLE_RCTX,sqlca.sqlerrm.sqlerrmc,sqlca.sqlerrm.sqlerrml);
       return;
}

And Iam compiling using :

proc sqlcheck=semantics parse=full include=$ORACLE_HOME/network/public \
include=$ORACLE_HOME/proc/lib \
include=$ORACLE_HOME/rdbms/demo \ include=$ORACLE_HOME/oci/include \
include=/usr/include \
include=$ORACLE_HOME/rdbms/public/ \
lines=yes parse=full iname=sample.pc

Also.. Could u kindly tell me from where Can i ask questions to u ?

Thanx

Followup:
Your code is way wrong:

exec sql begin declare section;
OCIExtProcContext *epctx;
exec sql end declare section;

void extp1(epctx)
{
char name[15];
exec sql register connect USING :epctx;
        EXEC SQL WHENEVER SQLERROR goto err;
        EXEC SQL SELECT ename INTO :name FROM emp WHERE empno = 9999;
        return;
err:
SQLExtProcError(SQL_SINGLE_RCTX,sqlca.sqlerrm.sqlerrmc,sqlca.sqlerrm.sqlerrml);
       return;
}

You have TWO variables epctx.  One is global (a big no-no in an extproc btw --
do NOT use globals), the other is local (and untyped).

In the procedure extp1 the ariable epctx is a parameter passed to it with a
default type - a type that is explicitly not "OCIExtProcContext *" (its an int
or a char or something, I forget what the default type in C is -- mostly because
I would never rely on it).

Code:

void extp1(OCIExtProcContext * epctx)
{
char name[15];
exec sql register connect USING :epctx;
        EXEC SQL WHENEVER SQLERROR goto err;
        EXEC SQL SELECT ename INTO :name FROM emp WHERE empno = 9999;
        return;

as I did and lose that global variable that is out of scope in that function
anyway.

You can ask questions of me from the homepage on
http://asktom.oracle.com/
but as there is only one
of me and many people out there -- I am frequently in the mode of "not accepting
questions, try later".

Rating: 3
Pro*C Compilation Error July 11, 2002
Reviewer: Kalpesh Patel from NJ, USA
Hi Tom,
This is my PL/SQL query in my Pro*C code:
 select max(trade_date) into temp_trade_date from tkdaily.tbminutes
partition(day_4)
 WHERE  day = 4   AND symbol_id = (SELECT symbol_id FROM tkmaster.tbsymbols
WHERE symbol_name_reuters = :ric_name) AND trade_date between (hour_date-0.0416)
and hour_date;

I am getting following errors while compilation of my pro*C Code.

Semantic error at line 10564, column 77, file rtrqd02_amexstk.i:
                          select  ( ( trade_date ) > ( ) ? ( trade_date ) : ( )
) into temp_trade_date from tkdaily.tbminutes partition(day_4)
............................................................................1
PCC-S-02322, found undefined identifier
                          select  ( ( trade_date ) > ( ) ? ( trade_date ) : ( )
) into temp_trade_date from tkdaily.tbminutes partition(day_4)
.............................................................1
PLS-S-00103, Encountered the symbol ")" when expecting one of the following:

   ( - + mod not null others select <an identifier>
   <a double-quoted delimited-identifier> <a bind variable> avg
   count current exists max min prior sql stddev sum variance
   execute cast trim forall
   <a string literal with character set specification>
   <a number> <a single-quoted SQL string>

Semantic error at line 10511, column 2, file rtrqd02_amexstk.i:
        DECLARE
.1
PCC-S-02347, PL/SQL found syntax errors
*** Error code 1
make: Fatal error: Command failed for target
`/export/home/dpos/offshore/dprimary/obj/rtrqd02_amexst
k.o'
Failed to Compile

If I replace max(trade_date) with trade_date in my query.
It compiles and executes successfully.
What could be the reason and what is the fix.
Please let me know
Thanks
Kalpesh

August 31, 2001 Kevin -- Thanks for the question regarding "Last logon for user", version 7.3.4
You Asked
Tom,

Could you please tell me if there is a way of finding out when a user last
logged into the database. We currently have a number of usernames that we think
are no longer used and want to get rid of them based on their last access times.

If you can suggest an approach that would be most appreciated.

Kind regards.

Kevin Thomas
Technical Analyst
De-regulated Services
Calanais Ltd.
and we said...
You would enable auditing (set audit_trail=true in the init.ora), restart and
AUDIT CONNECT

See the Admin guide and SQL Reference for all of the details.

This information, by default, is not recorded.
Review & Followup
Rating: 4
This should do the logon auditing!!!!! August 31, 2001
Reviewer: A reader
AUDIT CONNECT WHENEVER SUCCESSFUL;

August 31, 2001 J -- Thanks for the question regarding "rowid", version 8.16
You Asked
Tom

I have a table:

SQL> desc d;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER(10)
 EMAIL                                              VARCHAR2(40)
 PASSWORD                                           VARCHAR2(40)
 DELETION_DATE                                      DATE

with the following data inserted:

1  anyone@another.com          testing     30-AUG-01
8  anyone@another.com         another
10 anyone@another.com         yetanother

What I want to do is to remove (or preferably put in another table) all
duplicates rows and leave only one entry if there is no entry in the deletion
date column. However, if there is a deletion date I want to leave one with
deletion date and one without. If all rows for that particular email has an
entry in the deletion date column I would like them all left.

Eg from the data above, I would want id = 8 removed only.

Based on other answers you have given on your site, I have been unsuccessfully
trying variations of the following query:

delete from d d1
where rowid <>
(select min(rowid) from d d2 where d1.email = d2.email........);

Thanks
and we said...
Well, it isn't clear what you expect when there are TWO rows with different
DELETION_DATES -- I assumed you only wanted one of them left. If this is NOT the
case, simply change my nvl2(deletion_date,....) into
nvl(deletion_date,to_date('01010001','ddmmyyyy')) and that'll happen.

Here is the data I tested with (i expect to remove id = 8 and 11)

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t;

        ID EMAIL                PASSWORD   DELETION_
---------- -------------------- ---------- ---------
         1 anyone@another.com   testing    30-AUG-01
         8 anyone@another.com   another
        10 anyone@another.com   yetanother
        11 tkyte@us.oracle.com  yetanother 01-JAN-01
        12 tkyte@us.oracle.com  yetanother 11-JAN-01

Here is the query to get your dups -- we do this by mapping all NON-NULL dates
to jan 1st, year 1.  All NULL dates are jan 2cnd year 1 (values I suspect won't
be found in your table)

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t
  2  where (email,nvl2(deletion_date,
  3                     to_date('01010001','ddmmyyyy'),
  4                     to_date('02010001','ddmmyyyy'))
  5        )
  6     in ( select email, nvl2(deletion_date,
  7                             to_date('01010001','ddmmyyyy'),
  8                             to_date('02010001','ddmmyyyy'))
  9            from t
 10           group by email, nvl2(deletion_date,
 11                                to_date('01010001','ddmmyyyy'),
 12                                to_date('02010001','ddmmyyyy'))
 13          having count(*) > 1 );

        ID EMAIL                PASSWORD   DELETION_
---------- -------------------- ---------- ---------
         8 anyone@another.com   another
        10 anyone@another.com   yetanother
        11 tkyte@us.oracle.com  yetanother 01-JAN-01
        12 tkyte@us.oracle.com  yetanother 11-JAN-01

And then here is the delete that removes all of the "highest id'd" duplicate:

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from t
  2   where (id,email,nvl2(deletion_date,
  3                        to_date('01010001','ddmmyyyy'),
  4                        to_date('02010001','ddmmyyyy'))
  5         ) NOT IN
  6         (select max(id), email, nvl2(t2.deletion_date,
  7                                      to_date('01010001','ddmmyyyy'),
  8                                      to_date('02010001','ddmmyyyy'))
  9            from t t2
 10           where t2.email = t.email
 11             and nvl2(t2.deletion_date,
 12                         to_date('01010001','ddmmyyyy'),
 13                         to_date('02010001','ddmmyyyy')) =
 14                 nvl2(t.deletion_date,
 15                        to_date('01010001','ddmmyyyy'),
 16                        to_date('02010001','ddmmyyyy'))
 17           group by email, nvl2(deletion_date,
 18                                to_date('01010001','ddmmyyyy'),
 19                                to_date('02010001','ddmmyyyy'))
 20         )
 21  /

2 rows deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t;

        ID EMAIL                PASSWORD   DELETION_
---------- -------------------- ---------- ---------
         1 anyone@another.com   testing    30-AUG-01
        10 anyone@another.com   yetanother
        12 tkyte@us.oracle.com  yetanother 11-JAN-01
August 31, 2001 Catherine -- Thanks for the question regarding "Extents, Data blocks, OS blocks", version 8.1.7
You Asked
Please can you give me some detail on the following:
1) When a table is created is the whole of the initial extent written to disk,
i.e. are even empty blocks written to disk and therefore OS blocks?
2) when data is updated in a data block will the same OS blocks be used when the
data is written back to disk. So for the lifetime of an Oracle block, will it
always map to the same OS block?

Thanks.
and we said...
1) when a tablespace is created, the blocks are formatted.

When a table grabs an extent, it gets already formatted blocks. We won't write
anything to them until you put data in them.

2) that is upto the OS.  I would say in general "probably" but I can think of
cases where it is not so -- it depends on the underlying OS and disk software.
(eg: consider an NT compressed drive for example -- it initially compresses very
well -- all zeroes on the empty block.  It takes very little room. When we put
data on it -- it does not compress as well hence it'll take more space, it may
occupy more / or different OS blocks now then before)....

NOT that it is recommended (quite the reverse) to use NT compressed drives for
datafiles -- but it is an example where the block may "move".  It is totally
upto the filesystem driver.  Logically speaking -- the block never moves,
physically-- it is beyond our control.
Review & Followup
Rating: 5
September 03, 2001
Reviewer: A reader
Thanks. I'm a lot clearer about how things work now!

August 31, 2001 Dardenne -- Thanks for the question regarding "Intervalle Date, bug ?", version 8
You Asked
Good morning,
I have a problem whith this request.

 Select
    To_char( BeginDate, 'dd/mm/yyyy hh24:mi:ss' ) BeginDate,
    To_char( EndDate, 'dd/mm/yyyy hh24:mi:ss' ) EndDate,
    Trunc( EndDate-BeginDate ) || ' days ' ||
    To_Char(Trunc(Mod((EndDate-BeginDate)*24,24)),'fm00')
    ||':'||
    To_Char(Trunc(Mod((EndDate-BeginDate)*24*60,60)),'fm00')
    ||':'||
    To_Char(Trunc(Mod((EndDate-BeginDate)*24*60*60,60)),'fm00') Elaps
 From tstdate;

The next lines with * are false ( result-1 seconde).
I dont unterstand why ?
Could you help me ?

Laurent Dardenne
Email : Laurent.Dardenne@Socgen.com
Oracle version 8 - Unix, Client v8.1.5

Start Date           End Date             Elaps
-------------------- -------------------- -----------------
28/05/2001 23:59:59  31/05/2001 00:00:00  2 days 00:00:00*
29/05/2001 23:59:59  31/05/2001 00:00:00  1 days 00:00:00*
30/05/2001 23:59:59  31/05/2001 00:00:00  0 days 00:00:01*
30/05/2001 00:00:00  31/05/2001 00:00:00  1 days 00:00:00
30/05/2001 02:00:00  31/05/2001 02:00:00  1 days 00:00:00

30/05/2001 02:00:00  31/05/2001 02:00:01  1 days 00:00:00 *
30/05/2001 02:00:00  31/05/2001 02:00:02  1 days 00:00:02

30/05/2001 02:00:00  31/05/2001 02:00:59  1 days 00:00:59
30/05/2001 02:00:00  31/05/2001 02:01:00  1 days 00:00:59*
30/05/2001 02:00:01  31/05/2001 02:01:00  1 days 00:00:59
30/05/2001 02:00:00  31/05/2001 02:01:01  1 days 00:01:01

30/05/2001 12:34:56  31/05/2001 12:34:54  0 days 23:59:58
30/05/2001 12:34:56  31/05/2001 12:34:55  0 days 23:59:59
30/05/2001 12:34:56  31/05/2001 12:34:56  1 days 00:00:00
30/05/2001 12:34:56  31/05/2001 12:34:57  1 days 00:00:00*
30/05/2001 12:34:56  31/05/2001 12:34:58  1 days 00:00:02

--------------------

 CREATE TABLE tstdate (
 StartDate      DATE    NULL,
 EndDate     DATE    NULL,
 DateDiff     DATE     NULL);

 insert into tstdate (StartDate,EndDate,datediff)
          values ( to_date('28/05/2001 23:59:59', 'dd/mm/yyyy hh24:mi:ss'),
               to_date ('31/05/2001 00:00:00', 'dd/mm/yyyy hh24:mi:ss'),
             null);

 insert into tstdate (StartDate,EndDate,datediff)
          values ( to_date('29/05/2001 23:59:59', 'dd/mm/yyyy hh24:mi:ss'),
               to_date ('31/05/2001 00:00:00', 'dd/mm/yyyy hh24:mi:ss'),
             null);
 insert into tstdate (StartDate,EndDate,datediff)
         values ( to_date('30/05/2001 23:59:59', 'dd/mm/yyyy hh24:mi:ss'),
              to_date ('31/05/2001 00:00:00', 'dd/mm/yyyy hh24:mi:ss'),
            null);

 insert into tstdate (StartDate,EndDate,datediff)
        values ( to_date('30/05/2001 00:00:00', 'dd/mm/yyyy hh24:mi:ss'),
             to_date ('31/05/2001 00:00:00', 'dd/mm/yyyy hh24:mi:ss'),
           null);

 insert into tstdate (StartDate,EndDate,datediff)
      values ( to_date('01/01/2002 02:00:00', 'dd/mm/yyyy hh24:mi:ss'),
           to_date ('02/01/2002 01:59:59', 'dd/mm/yyyy hh24:mi:ss'),

insert into tstdate (StartDate,EndDate,datediff)
       values ( to_date('30/05/2001 02:00:00', 'dd/mm/yyyy hh24:mi:ss'),
            to_date ('31/05/2001 02:00:00', 'dd/mm/yyyy hh24:mi:ss'),
           null);

insert into tstdate (StartDate,EndDate,datediff)
        values ( to_date('30/05/2001 02:00:00', 'dd/mm/yyyy hh24:mi:ss'),
             to_date ('31/05/2001 02:00:01', 'dd/mm/yyyy hh24:mi:ss'),
           null);

 insert into tstdate (StartDate,EndDate,datediff)
        values ( to_date('30/05/2001 02:00:00', 'dd/mm/yyyy hh24:mi:ss'),
             to_date ('31/05/2001 02:00:02', 'dd/mm/yyyy hh24:mi:ss'),
           null);

 insert into tstdate (StartDate,EndDate,datediff)
        values ( to_date('30/05/2001 02:00:00', 'dd/mm/yyyy hh24:mi:ss'),
             to_date ('31/05/2001 02:00:59', 'dd/mm/yyyy hh24:mi:ss'),
            null);

 insert into tstdate (StartDate,EndDate,datediff)
     values ( to_date('30/05/2001 02:00:00', 'dd/mm/yyyy hh24:mi:ss'),
          to_date ('31/05/2001 02:01:00', 'dd/mm/yyyy hh24:mi:ss'),
          null);

 insert into tstdate (StartDate,EndDate,datediff)
      values ( to_date('30/05/2001 02:00:01', 'dd/mm/yyyy hh24:mi:ss'),
           to_date ('31/05/2001 02:01:00', 'dd/mm/yyyy hh24:mi:ss'),
          null);

 insert into tstdate (StartDate,EndDate,datediff)
       values ( to_date('30/05/2001 02:00:00', 'dd/mm/yyyy hh24:mi:ss'),
            to_date ('31/05/2001 02:01:01', 'dd/mm/yyyy hh24:mi:ss'),
           null);

insert into tstdate (StartDate,EndDate,datediff)
          values ( to_date('30/05/2001 12:34:56', 'dd/mm/yyyy hh24:mi:ss'),
               to_date ('31/05/2001 12:34:54', 'dd/mm/yyyy hh24:mi:ss'),
             null);

insert into tstdate (StartDate,EndDate,datediff)
          values ( to_date('30/05/2001 12:34:56', 'dd/mm/yyyy hh24:mi:ss'),
               to_date ('31/05/2001 12:34:55', 'dd/mm/yyyy hh24:mi:ss'),
             null);

insert into tstdate (StartDate,EndDate,datediff)
          values ( to_date('30/05/2001 12:34:56', 'dd/mm/yyyy hh24:mi:ss'),
               to_date ('31/05/2001 12:34:56', 'dd/mm/yyyy hh24:mi:ss'),
             null);

insert into tstdate (StartDate,EndDate,datediff)
          values ( to_date('30/05/2001 12:34:56', 'dd/mm/yyyy hh24:mi:ss'),
               to_date ('31/05/2001 12:34:57', 'dd/mm/yyyy hh24:mi:ss'),
             null);

insert into tstdate (StartDate,EndDate,datediff)
          values ( to_date('30/05/2001 12:34:56', 'dd/mm/yyyy hh24:mi:ss'),
               to_date ('31/05/2001 12:34:58', 'dd/mm/yyyy hh24:mi:ss'),
             null);
and we said...
Looks like a small issue with rounding.  We can avoid that with a cast in
Oracle8i (you didn't mention the version out to three digits so I don't know
what 8.x release you have -- 8.1.x and up can do this) and avoid the mixed mode
math issues:

ops$tkyte@ORA817DEV.US.ORACLE.COM>  Select
  2      To_char( startDate, 'dd/mm/yyyy hh24:mi:ss' ) startDate,
  3      To_char( EndDate, 'dd/mm/yyyy hh24:mi:ss' ) EndDate,
  4      Trunc( days ) || ' days ' ||
  5      To_Char(Trunc(Mod(hrs,24)),'fm00') || ':' ||
  6      To_Char(Trunc(Mod(mns,60)),'fm00') || ':' ||
  7      To_Char(Trunc(Mod( sec ,60)),'fm00') Elaps
  8   From (select startdate,
  9                enddate,
 10                cast( enddate-startdate as number(38,20) ) days,
 11                cast( (enddate-startdate)*24 as number(38,20) ) hrs,
 12                cast( (enddate-startdate)*24*60 as number(38,20) ) mns,
 13                cast( (enddate-startdate)*24*60*60 as number(38,20) ) sec
 14      from tstdate )
 15  /

STARTDATE           ENDDATE             ELAPS
------------------- ------------------- --------------------
28/05/2001 23:59:59 31/05/2001 00:00:00 2 days 00:00:01
29/05/2001 23:59:59 31/05/2001 00:00:00 1 days 00:00:01
30/05/2001 23:59:59 31/05/2001 00:00:00 0 days 00:00:01
30/05/2001 00:00:00 31/05/2001 00:00:00 1 days 00:00:00
30/05/2001 02:00:00 31/05/2001 02:00:00 1 days 00:00:00
30/05/2001 02:00:00 31/05/2001 02:00:01 1 days 00:00:01
30/05/2001 02:00:00 31/05/2001 02:00:02 1 days 00:00:02
30/05/2001 02:00:00 31/05/2001 02:00:59 1 days 00:00:59
30/05/2001 02:00:00 31/05/2001 02:01:00 1 days 00:01:00
30/05/2001 02:00:01 31/05/2001 02:01:00 1 days 00:00:59
30/05/2001 02:00:00 31/05/2001 02:01:01 1 days 00:01:01
30/05/2001 12:34:56 31/05/2001 12:34:54 0 days 23:59:58
30/05/2001 12:34:56 31/05/2001 12:34:55 0 days 23:59:59
30/05/2001 12:34:56 31/05/2001 12:34:56 1 days 00:00:00
30/05/2001 12:34:56 31/05/2001 12:34:57 1 days 00:00:01
30/05/2001 12:34:56 31/05/2001 12:34:58 1 days 00:00:02

16 rows selected.

In 8.0 and before, this seems to do the trick:

ops$tkyte@ORA806.WORLD>  Select
  2      To_char( startDate, 'dd/mm/yyyy hh24:mi:ss' ) startDate,
  3      To_char( EndDate, 'dd/mm/yyyy hh24:mi:ss' ) EndDate,
  4      Trunc( days ) || ' days ' ||
  5      To_Char(Trunc(Mod(hrs,24)),'fm00') || ':' ||
  6      To_Char(Trunc(Mod(mns,60)),'fm00') || ':' ||
  7      To_Char(Trunc(Mod( sec ,60)),'fm00') Elaps
  8   From (select startdate,
  9                enddate,
 10                to_char(enddate-startdate,'999.9999999999999999')  days,
 11             to_char((enddate-startdate)*24,'99999.999999999999999999') hrs,
 12       to_char((enddate-startdate)*24*60,'9999999.999999999999999999') mns,
 13   to_char((enddate-startdate)*24*60*60,'9999999999.999999999999999999') sec
 14      from tstdate )
 15  /

STARTDATE           ENDDATE             ELAPS
------------------- ------------------- --------------------
28/05/2001 23:59:59 31/05/2001 00:00:00 2 days 00:00:01
29/05/2001 23:59:59 31/05/2001 00:00:00 1 days 00:00:01
30/05/2001 23:59:59 31/05/2001 00:00:00 0 days 00:00:01
30/05/2001 00:00:00 31/05/2001 00:00:00 1 days 00:00:00
30/05/2001 02:00:00 31/05/2001 02:00:00 1 days 00:00:00
30/05/2001 02:00:00 31/05/2001 02:00:01 1 days 00:00:01
30/05/2001 02:00:00 31/05/2001 02:00:02 1 days 00:00:02
30/05/2001 02:00:00 31/05/2001 02:00:59 1 days 00:00:59
30/05/2001 02:00:00 31/05/2001 02:01:00 1 days 00:01:00
30/05/2001 02:00:01 31/05/2001 02:01:00 1 days 00:00:59
30/05/2001 02:00:00 31/05/2001 02:01:01 1 days 00:01:01
30/05/2001 12:34:56 31/05/2001 12:34:54 0 days 23:59:58
30/05/2001 12:34:56 31/05/2001 12:34:55 0 days 23:59:59
30/05/2001 12:34:56 31/05/2001 12:34:56 1 days 00:00:00
30/05/2001 12:34:56 31/05/2001 12:34:57 1 days 00:00:01
30/05/2001 12:34:56 31/05/2001 12:34:58 1 days 00:00:02

16 rows selected.
Review & Followup
Rating: 3
Easier way... August 31, 2001
Reviewer: andrew from ca, usa
Interesting problem. BTW, there is an easier way to get the same result (adapted
from code by tas02 on orafans.com).

FUNCTION to_hms (v_days IN number)
   RETURN varchar2
IS
   v_retval   varchar2(25);
BEGIN
   v_retval := TO_CHAR (TRUNC (v_days)) || ' days '||
         TO_CHAR (TRUNC (SYSDATE) + MOD (v_days, 1), ' HH24:MI:SS');
   RETURN v_retval;
END to_hms;
/

Select
To_char( startDate, 'dd/mm/yyyy hh24:mi:ss' ) startDate,
To_char( EndDate, 'dd/mm/yyyy hh24:mi:ss' ) EndDate,
 to_hms(EndDate - StartDate)
from tstdate;

28/05/2001 23:59:59    31/05/2001 00:00:00    2 days  00:00:01
29/05/2001 23:59:59    31/05/2001 00:00:00    1 days  00:00:01
30/05/2001 23:59:59    31/05/2001 00:00:00    0 days  00:00:01
30/05/2001 00:00:00    31/05/2001 00:00:00    1 days  00:00:00
30/05/2001 02:00:00    31/05/2001 02:00:00    1 days  00:00:00
30/05/2001 02:00:00    31/05/2001 02:00:01    1 days  00:00:01
30/05/2001 02:00:00    31/05/2001 02:00:02    1 days  00:00:02
30/05/2001 02:00:00    31/05/2001 02:00:59    1 days  00:00:59
30/05/2001 02:00:00    31/05/2001 02:01:00    1 days  00:01:00
30/05/2001 02:00:01    31/05/2001 02:01:00    1 days  00:00:59
etc.

Rating: 3
September 04, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

August 31, 2001 -- Thanks for the question regarding "View Performance", version 817
You Asked
Hi Tom

Is there a performance hit if I use views to select from VIEWS as compared to
using views to select from TABLES.
I think the tables would already contain the data where as the views would have
to get the data on the fly.
Please help me in clearing my doubt.

Thanks
and we said...
A view is nothing more then a stored query.  A view selecting against a view
that selects against tables will perform identically to a View that selected
against the tables directly.

Tables hold data.
Views hold queries.

Queries access data stored in tables.

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1291563605946
for a very recent discussion on this very topic.
Review & Followup
Rating: 3
But, But, But August 31, 2001
Reviewer: J from MA
wouldn't a select on a view be better as far as parsing goes?

Followup:
No, in fact it would be marginally worse on the hard parse as the view
definition might have to be physically read into the dictionary cache (but
please -- don't let that scare you away from views -- excessively marginal)

August 31, 2001 sam -- Thanks for the question regarding "useful packages for developer and dba", version 8.1.7
You Asked
Tom

What according to you are the most important packages for a devevloper and for a
dba.

developer

dbms_profiler
dbms_utility
dbms_output
utl_file
dbms_trace
dbms_pipe
dbms_alert
dbms_sql

can you think of any more , actually can you arrange them in the order of there
importance, and in order of what you think are a must for a developer.

The same for the DBA
and we said...
Well, it really depends on what you do doesn't it?

I mean if you are a developer who NEVER has the need to create a file on the
server -- then UTL_FILE is useless.

If you are a developer who must create a file on the server -- UTL_FILE is of
the utmost importance.

I feel everyone should have a BASIC understanding of each package and what it
does (they need not master them all -- just be aware of the EXISTENCE of them
and what in general they do) so that when faced with a problem to solve you
could say "Hey -- maybe package XXXXX will be useful here".

Just breeze through the supplied packages guide, get an overview, and as
problems are presented ask yourself "did Oracle already write this code for
me"....

I use all of the above constantly but you are missing things like dbms_job (one
of my favorites), utl_smtp (very cool), utl_tcp (very flexible), utl_http (more
powerful then you know), etc etc etc

there are 65 packages in 8i, more in 9i.  Just KNOWING that they exist and
basically what they do -- thats all that can be asked.  Use them when
appropriate.
Review & Followup
Rating: 4
DEVELOPER September 01, 2001
Reviewer: SAMUEL J. CARTER from SOLDOTNA, ALASKA
THIS IS WHAT I HAVE BEEN LOOKING FOR...!  THANK YOU, SAMUEL

Rating: 5
September 01, 2001
Reviewer: Muthukumaran Nirmal Kumar from Qatar
Very Cool Answer, I like your way of answering very much.

Rating: 5
Nice Reply !!! September 02, 2001
Reviewer: AbuAhmad from Singapore
Keep it up!

Rating: 3
Good explanation September 03, 2001
Reviewer: EDMOND Gerard from France
Here's the clear way of explaining to complicated answers.
Cute and clear.

Rating: 5
useful packages for developer and dba September 04, 2001
Reviewer: Sudhanshu Kulshreshtha from NIIT- INDIA
Very very good and useful for me.

Thanks, Thanks a lot tom.

Rating: 5
C'mmon September 04, 2001
Reviewer: Jeel
C'mmon guys this a a great clarification, but you also need to thank the guy who
asked this question.

Thank you  Sam.


Subject | Article | Last Updated (East coast time)
Cascade Delete | article only | Sep 07, 2001 11:24 am
partition comparision is done from left to right | article only | Sep 07, 2001 11:58 am
Dynamic SQL to reset sequence value | article only | Sep 07, 2001 12:40 pm
REF CURSOR - varying number of elements in an IN LIST | article only | Sep 07, 2001 02:18 pm
Performance when a View using other Views | article only | Sep 08, 2001 08:56 am
follow up | article only | Sep 08, 2001 09:19 am
scrolling text | article only | Sep 08, 2001 09:39 am
trapping transaction information | article only | Sep 08, 2001 06:44 pm
Running a database with no datafiles on UNIX JFS | article only | Sep 09, 2001 08:50 am
data compression in Oracle | article only | Sep 09, 2001 10:38 am
need to display data in one row | article only | Sep 09, 2001 10:45 am
primary key violated | article only | Sep 09, 2001 05:35 pm
row(s) 1 - 12 of 12
September 07, 2001 Vivek -- Thanks for the question regarding "Cascade Delete", version 8.0.5
You Asked
I want to write cascade delete trigger on a table. What I want is to SET NULL in
child records for every parent records I want to delete. I have written BEFORE
ROW LEVEL trigger to trap the parent key value and BEFORE STATEMENT LEVEL to
update the child record to null for that parent key. But as BEFORE STATEMENT
LEVEL trigger fires before ROW LEVEL, I am not getting the desired result. I can
not use OLD reference in STATEMENT LEVEL trigger. I am also using package to
store parent key value.

How can I set the child record to null for every parent record I want to delete?

Vivek
and we said...
In Oracle8i (release 8.1.5 and up) you'll code:

create table p ( x int primary key );
create table c ( x references p on delete set null );

In 8.0, this is quite simply "not doable" in a trigger unless you use deferrable
constraints and three triggers (a very convuluted approach).

I would suggest this calls for a stored proceudre.  You would code:

procedure delete_parent( p_id in number )
as
begin
   update child set fk_to_parent = null where fk_to_parent = p_id;
   delete from parent where id = p_id;
end;
/

and have the applications call that instead of issuing a delete straight out.
Review & Followup
Rating: 4
take care of this September 02, 2001
Reviewer: SHAKEEL AMJAD ALI from FAISLABAD,PAKISTAN
I am a student studying oracel 'database'from the college 'NICON'.
     I want to bring to your notice that one of ur testing centers in Pakistan
is giving out exam questions for as less 1000-Rs(rupees)I was reaily shocked to
learn this and wanted to do somthing so,I decided to tell u.I reaily wish u
could do somthing about the serious matter which is harmfull to both Oracle and
the students.
     I will be glad to tell u about the site no.= PKP,in Faisalabad,Pakistan.

Rating: 3
Cascade Delete September 03, 2001
Reviewer: Vivek Saxena from UK
What you said is stored procedure is only way to achieve the result, if I can't
change the constraint to deferrable constraint in 8.0.5 version.
I am bit confussed over the behaviour of trigers that i have written.Could you
please help me in that, what i have done is in BEFORE ROW LEVEL i got p_id to
delete and in BEFORE STATEMENT LEVEL i updated the child to null and AFTER
STATEMENT LEVEL i initialised the array. I have declared an package for array
values. Now for the first time when i delete p_id i get ora-02292 error but
second time it works perfectly, p_id is deleted. Why does it work like that? How
does BEFORE STATEMENT LEVEL trigger gets the value of p_id in second attempt.

Thanks.

Rating: 3
Okay. September 03, 2001
Reviewer: Pritish Kulkarni from Mumbai, India
Your response is okay and gives the solution.
But why can't you create a before delete row levele trigger on parent table in
which you can set the child to null
as
create table a( p_id    number primary key);

create table b( fk_id  number references a);

create or replace trigger bef_del_a
before delete on a
for each row
begin
  update b set fk_id = null where fk_id = :old.p_id;
end;
/

is there any problem with this approach?

Followup:
It won't work in 8.0 and before...

ops$tkyte@ORA806.WORLD> insert into a values ( 1 );
1 row created.

ops$tkyte@ORA806.WORLD> insert into b values ( 1 );
1 row created.

ops$tkyte@ORA806.WORLD> commit;
Commit complete.

ops$tkyte@ORA806.WORLD> delete from a;
delete from a
            *
ERROR at line 1:
ORA-04091: table OPS$TKYTE.A is mutating, trigger/function may not see it
ORA-06512: at "OPS$TKYTE.BEF_DEL_A", line 2
ORA-04088: error during execution of trigger 'OPS$TKYTE.BEF_DEL_A'

Rating: 5
U can do that at the creation of table itself September 04, 2001
Reviewer: Raj Natt from very near to ORACLE ...Fremont , CA USA
hi ! Vivek
  the solution to ur problem is :
  at the time of creating the table..enable the foreign key
  with set to null parameter. u will notice that hence forth
  whenever u delete a parent value..oracle will set the
  corresponding child values to Null. This is the best way
  to ensure the Global enforcement of the constraint.

Rating: 5
Response to statement level trigger on 8.0.5 September 06, 2001
Reviewer: Todd A. Cox from Birmingham USA
To respond to Pritish Kulkarni, I believe that the solution you have provided
(row level triggers) will cause "Table x is mutating" errors when used with
8.0.x, though I believe it would work with 8.1.x (but is not required, as Tom
points out).

September 07, 2001 sj -- Thanks for the question regarding "partition comparision is done from left to right", version 8.1.7
You Asked
http://asktom.oracle.com/pls/ask/f?p=4950:9:::NO::F4950_P9_ORIG,F4950_P9_DISPLAYID:Y,1199992531506
"
Well, xyzdate = 16-aug-01 and col_code = abby which is less than dzz so that
goes into partition one..

For all other dates < 16-aug-01 -- they will ALL go into partition
part1_08_16_01

the partition comparision is done from left to right.  Any rows that have a
xyzdate less then august 16'th, 2001 will by definition go into partition part1
-- xzydate is less than 16-aug-2001, the first partition they fit into -- there
they go.

Only when the date is equal to (or greater than) 16-aug-2001 will we ever even
consider another partition.

"

In one of your previous answers to me you  have said that , partition bounds are
never equal to , never less than , infact we define less than. So when the date
is equal to 08_16_01  how is it going into the first partition.

I accept that abby fits into the first partition when considering the range
given for the second partition key , but when considerig both the columns in the
partition key, when it starts looking from left to right, THE PARTITION SHOULD
GET DISQUALIFIED , as soon as it finds that 16-aug-2001  is not less than but
equal to 16-aug-2001 .

Iam surprised to hear that anyrows less than 16-aug-2001 , will go right into
the first partition without even taking into consideration the second partition
key. IN MY OPINION  a DATE LIKE AUGUST 2ND 2001, AND COL_CODE LIKE WEST ,
should not go into the first partition but into the third partition. HOW COME IT
GOES INTO THE FIRST PARTITION?

THANK YOU

      and we said...
You have a set of vectors:

(to_date('08/16/00','mm/dd/yy'),'DZZ')
(to_date('08/16/00','mm/dd/yy'),'EASTA')
(to_date('08/16/00','mm/dd/yy'),'WDD')
(to_date('08/16/00','mm/dd/yy'),'WESTA')
(the-rest)

You give us a VECTOR (16-aug-2001,'ABBY')

We compare this vector to each of the above.  In a multi-column range
partitioned table, the values are compared from left to right.

If the first column in your vector is LESS-THAN the first column of some
partition range -- that is the partition it goes into.

If the first column in your vector is EQUAL-TO the first column of some
partition range -- we continue the comparision based on the second column.  In
this case, we compare 'ABBY' to 'DZZ' and discover that goes into that
partition.

The rules are pretty clear on this in the documentation -- its the way it is
supposed to work.  Consider your partition range to be a sequence of "characters
in a string".  Suppose you had a partition range:

( 'B', 'C' )   => string 'BC'
( 'B', 'E' )             'BE'
( 'B', 'G' )             'BG'

Now, if you compare the string 'AD' to each of those, you would find that 'AA' <
'BC' right?  'AD' is not greater then 'BC' -- even though D > C.  The compares
are done from LEFT to RIGHT and the first thing that stops the compare -- in
effect wins.

The same happens for partition ranges.  We compare the vector from the current
row to the vectors that define the partition and STOP immediate when we find the
thing that is LESS-THAN.  If that is the first column, so be it.  If you used
the partition ranges I have above ('bc','be','bg')  -- anything that starts with
A would go into the partition 'BC' since 'A' < 'B'.  The same holds true for
your dates.

You must have mis-intrepreted my response to you in a prior posting (if you
provide the URL, i'll take a look and see if I can make it more clear for
others)

Maybe this will help as well.  The partition ranges are compared and sorted in
exactly the same way a set of rows in a table would be.  Consider:

ops$tkyte@ORA817.US.ORACLE.COM> create table t ( d date, c varchar(5) );
Table created.

ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( '16-aug-2001', 'DZZ' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( '16-aug-2001', 'EASTA' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( '16-aug-2001', 'WDD' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( '16-aug-2001', 'WESTA' );

ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( '16-aug-2001', 'ABBY' );
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values ( '16-jan-2001', 'ZZZZ' );

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> select * from t order by d, c;

D         C
--------- -----
16-JAN-01 ZZZZ
16-AUG-01 ABBY
16-AUG-01 DZZ
16-AUG-01 EASTA
16-AUG-01 WDD
16-AUG-01 WESTA

6 rows selected.

So, if you are ever confused about what partition a row with certain values will
go into -- simply create a small table with columns having the same datatypes as
your partition key.  Insert your partition key values as I did and then insert
the row(s) you want to find out where they will go.  Select * from that table
ordering by the partition key.  The PARTITION row that comes out immediately
after your data row (my data rows are in bold above) is the partition that row
will go into.  This shows that 16-jan-2001 will go into partition 1 even though
ZZZZ is "really" big -- the first column sorts it to the top putting it into the
first partition.

See also:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c09parti.htm#430096
it has more examples and explains this as well.

Review &
      Followup

      Rating: 5
Oracle's
      documentation on partitions is not good.  August 19, 2001

Reviewer:  George  from USA
The link which you gave does not have satisfactory examples at all. ORACLE  is
not doing enough work at documentation. This is what will happen , if they come
up with too many new features, without any discretion. And what happened to all
the hard copied docs, why did they stop producing them.
FOLLOW UP:

"Well, xyzdate = 16-aug-01 and col_code = abby which is less than dzz so that
goes into partition one.."

though the high bound of the first partition is values less than 16-aug-01 , but
there is no other partition with a lesser high bound then that, that is the
reason why values less that the given date will go into part1_16-aug-01.

BUT , instead of abby if the col_cd for that record is EAST, will it go into the
second partition i.e.part1_16-aug-01. , according to your explanation it should
.

Are we right , Tom.

          Followup:

I didn't find it lacking (the documentation) -- it seems fairly clear to me.  I
particularly like the example:

<quote>
In mathematical terms, for vectors V1 and V2 which contain the same number of
values, Vx[i] is the ith value in Vx. Assuming that V1[i] and V2[i] have
compatible datatypes:

* V1 = V2 if and only if V1[i] = V2[i] for all i

* V1 < V2 if and only if V1[i] = V2[i] for all i < n and V1[n] < V2[n] for some
n

* V1 > V2 if and only if V1[i] = V2[i] for all i < n and V1[n] > V2[n] for some
n
</quote>

In the example you are talking about with the vectors:

(to_date('08/16/00','mm/dd/yy'),'DZZ')
(to_date('08/16/00','mm/dd/yy'),'EASTA')
(to_date('08/16/00','mm/dd/yy'),'WDD')
(to_date('08/16/00','mm/dd/yy'),'WESTA')
(the-rest)

It has NOTHING to do with there not being a partition for the date of 08/17/00.
The rules on vector comparision are listed above.  Regardless of whether or not
there was a partition with a date of 08/17/00 -- all rows with values less then
the vector (to_date('08/16/00','mm/dd/yy'),'WESTA') would go into one of the
first four partitions.

In this case using the vector:

('16-aug-01','ABBY') and using the rules above, we find that

('16-aug-01','ABBY') < (to_date('08/16/00','mm/dd/yy'),'DZZ')

and hence belongs in that partition) since V1[i] = V2[i] for i < 2 and V1[n] <
V2[n] for n = 2

For me, the only simple way I can express it is -- if you were to have a table
as I do above ( table t ( d, c ) ) -- we find the partition to put the data in
in the same fashion as a sort on that table would be.  You would not expect
16-aug-01, 'ABBY' to ever sort AFTER 16-aug-01, 'DZZ' (that would be a bug) --
the same rule applies for partitions.

      Rating:
      5
correction  August 19, 2001
Reviewer:
      George  from USA
Iam really sorry.

in the below paragraph

"though the high bound of the first partition is values less than 16-aug-01 ,
but there is no other partition with a lesser high bound then that, that is the
reason why values less that the given date will go into part1_16-aug-01. "

I did not mean a lesser high bound, actually I wanted it to be a higher bound
i.e. partitions with hight bound values of  15-aug-01 and higher.

secondly, lets say we have 8 partitions for 15th and 16th Aug. Now the user is
trying to insert records for 14th August. They will definitely go into
part1_08_15_01( as per the partitioning nameing convention in your example, I
would prefer the year to be the prefix.) But this way data will be spread
hapzardly, I think this will be harmful.

Is there any way where if data coming in , for example 12th Aug  in the above
case is made to go into an exclusive partition which is not part of the above
partitions( actually how can we create such a partition at the table creation
time, or how can we do this dynamically). How can this be done , how can this be
done at all.

          Followup:

You are associating "dates" with partitions -- it is true that dates are
frequently used to partition data, but there is nothing "inherit" in the
partitioning code that makes dates different from say a number.  For example, if
the partition vectors were:

(200,'DZZ')
(200,'EASTA')
(200,'WDD')
(200,'WESTA' )
(max_value,max_value)

we would do this no differently.  Anything with a value LESS THAN 200 (less than
august whatever) would go into the first partition.  Anything with a value EQUAL
to 200 would go into one of the remaining partitions dependning on the value of
the second column.  In your example, having august-15/august-16 and desiring
anything before august-15'th to go into its own special partition, you would set
up partitioning vectors:

ops$tkyte@ORA817.US.ORACLE.COM> create table t
  2  ( xyzdate date,
  3    col_code varchar2(10)
  4  )
  5  partition by range(xyzdate,col_code)
  6  (partition MIN_VALUES  values less than
           (to_date('08/14/2001','mm/dd/yyyy'),MAXVALUE),
  7   partition part1_20010815 values less than
           (to_date('08/15/2001','mm/dd/yyyy'),'DZZ'),
  8   partition part2_20010815 values less than
           (to_date('08/15/2001','mm/dd/yyyy'),'EASTA'),
  9   partition part3_20010815 values less than
           (to_date('08/15/2001','mm/dd/yyyy'),'WDD'),
 10   partition part4_20010815 values less than
           (to_date('08/15/2001','mm/dd/yyyy'),'WESTA'),
 11   partition part1_20010816 values less than
           (to_date('08/16/2001','mm/dd/yyyy'),'DZZ'),
 12   partition part2_20010816 values less than
           (to_date('08/16/2001','mm/dd/yyyy'),'EASTA'),
 13   partition part3_20010816 values less than
           (to_date('08/16/2001','mm/dd/yyyy'),'WDD'),
 14   partition part4_20010816 values less than
           (to_date('08/16/2001','mm/dd/yyyy'),'WESTA'),
 15   PARTITION MAX_VALUE VALUES LESS THAN(MAXVALUE,MAXVALUE)
 16  )
 17  /

Table created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> insert into t values (
to_date('08/14/2001','mm/dd/yyyy'), 'ZZZZ' );

1 row created.

ops$tkyte@ORA817.US.ORACLE.COM>
ops$tkyte@ORA817.US.ORACLE.COM> select * from t partition( min_values );

XYZDATE   COL_CODE
--------- ----------
14-AUG-01 ZZZZ

In otherwords -- there is nothing "haphazard" about it, the data just goes where
you tell us to.  the partitioning software is not expecting a partition/day (or
month or year or anything).

So, you can make it put the data where you want by setting up the proper range
partitions (eg: using august-14'th,maxvalue catches EVERY row that has a date of
august-14 and before -- regardless of the value in the second column.

      Rating: 5
ASCII value of
      the concatenation of the partition key  August 19, 2001

Reviewer:  Aba  from UK
SQL> ED
Wrote file afiedt.buf

  1* SELECT ASCII('200DZZ') FROM DUAL
SQL> /

ASCII('200DZZ')
---------------
             50

SQL> ED
Wrote file afiedt.buf

  1* SELECT ASCII('200EASTA') FROM DUAL
SQL> /

ASCII('200EASTA')
-----------------
               50

SQL> ED
Wrote file afiedt.buf

  1* SELECT ASCII('200WDD') FROM DUAL
SQL> /

ASCII('200WDD')
---------------
             50

SQL> ED
Wrote file afiedt.buf

  1* SELECT ASCII('200WESTA') FROM DUAL
SQL> /

ASCII('200WESTA')
-----------------
               50

The concatanation of your columns in the partition key , Tom, is resulting in
the same ASCII value. Then how do the records go into different partitions. I
might be missing something simple here, or this question might be very trivial,
but can you describe .

Thank you

          Followup:

ascii is a function that returns the numeric ascii code of the character you
pass to it:

ops$tkyte@ORA8I.WORLD> select ascii('2') from dual;

ASCII('2')
----------
        50

CHR is its inverse:

ops$tkyte@ORA8I.WORLD> select chr(50) from dual;

C
-
2

An ascii value is for a single character -- not a string.

I really don't know what you are trying to do here -- partition ranges are
compared column by column using their native types (numbers to numbers, strings
to strings).  They are not glued together as a big string and compared.

You have to compare VECTORS (if it is easier -- think of them as columns).  it
is the vector (200,'WESTA') -- not the string '200WESTA' we are dealing with.

      Rating: 5
Chop
      off  August 20, 2001
Reviewer:  READER
       from U.S.A
Hi, Tom,

Just a little suggestion:
In the Followup Tom, would you please start from the second line? The current
format result in chopping off several columns in the right hand side when i
print the whole topic out----- would you please just start from very left for
each line instead of what it is right now? I know you comment MUST BE different
from which created by others.

Thanks

      Rating: 1
Partition on
      Character keys  September 05, 2001
Reviewer:
      Swaminathan  from Singapore
Hi

I find the explanation of "values less than "clause in partitioning to be more
confusing.

Literally if I have a date column as say 16Th AUGUST 2001 and another keycolumn
value as say "SGP" and I have a composite partition with key columns on date
plus another Varchar2 type,

if i say
partition p1 values less than ( to_date('16-AUG-2001','dd-mon-yyyy'),'SNG') how
can a data with 16-AUG-2001 but with second value as say KL go in this partition
when the first column values are equal instead of the clause we specify as "less
than"

          Followup:

It is because we are doing SQL vector comparisons.  We are comparing two VECTORS

v1 < v2

NOT two scalars!!!  The rules for vector comparision are:

V1 = V2 if and only if V1[i] = V2[i] for all i

V1 < V2 if and only if V1[i] = V2[i] for all i < n and V1[n] < V2[n] for some n

V1 > V2 if and only if V1[i] = V2[i] for all i < n and V1[n] > V2[n] for some n

So the partition keys are compared from left to right with eachother.  The FIRST
partition key values in the two vectors are NOT equal stop the comparision.  We
look at their values and based on that decide if V1 is less than V2 or V1 is
greater than V2.

The partition clause is made against vectors:

partition part1_20010815 values less than
           (to_date('08/15/2001','mm/dd/yyyy'),'DZZ'),

Not against scalars.  That is the key point. Look at the ORDER BY example that
shows how these vectors would sort -- its the same thing.  The "row" if you will
is LESS THAN the other row based on the same rules as are used for the vector
comparisons.

September 07, 2001 Marcelo -- Thanks for the question regarding
      "Dynamic SQL to reset sequence value", version 8.1.6 / 8.1.7

      You Asked
Hi Tom,
I'm trying to create a dynamic code to reset a sequence number, like that...

declare
  v_initial number := 1;
  temp      number := 0;
  cmd       varchar2(100);

begin
  cmd := 'alter sequence SEQ increment by -1';
  execute immediate cmd;

  while true loop
    cmd := 'select SEQ.nextval from dual';
    execute immediate cmd;

    select last_number
      into temp
      from user_sequences
     where sequence_name = 'SEQ';

    if temp = v_initial then
       exit;
    end if;
  end loop;
end;

This is not working out. The first command is ok (the increment by is modified),
but the second command doesn't alter (decrease) the sequence value. What's wrong
?

Thanks for your attention,
Marcelo

      and we said...
Sequences are CACHED, the data dictionary won't reflect a nextval/nextval
decrement.

An easier way to do this would be:

tkyte@TKYTE901.US.ORACLE.COM> create or replace
  2  procedure reset_seq( p_seq_name in varchar2 )
  3  is
  4      l_val number;
  5  begin
  6      execute immediate
  7      'select ' || p_seq_name || '.nextval from dual' INTO l_val;
  8
  9      execute immediate
 10      'alter sequence ' || p_seq_name || ' increment by -' || l_val ||
                                                               ' minvalue 0';
 11
 12      execute immediate
 13      'select ' || p_seq_name || '.nextval from dual' INTO l_val;
 14
 15      execute immediate
 16      'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
 17  end;
 18  /

Procedure created.

tkyte@TKYTE901.US.ORACLE.COM>
tkyte@TKYTE901.US.ORACLE.COM> drop sequence my_seq;

Sequence dropped.

tkyte@TKYTE901.US.ORACLE.COM> create sequence my_seq increment by 1000;

Sequence created.

tkyte@TKYTE901.US.ORACLE.COM>
tkyte@TKYTE901.US.ORACLE.COM> select my_seq.nextval from dual;

   NEXTVAL
----------
         1

tkyte@TKYTE901.US.ORACLE.COM> select my_seq.nextval from dual;

   NEXTVAL
----------
      1001

tkyte@TKYTE901.US.ORACLE.COM> alter sequence my_seq increment by 1;

Sequence altered.

tkyte@TKYTE901.US.ORACLE.COM>
tkyte@TKYTE901.US.ORACLE.COM> select my_seq.nextval from dual;

   NEXTVAL
----------
      1002

tkyte@TKYTE901.US.ORACLE.COM> select my_seq.nextval from dual;

   NEXTVAL
----------
      1003

tkyte@TKYTE901.US.ORACLE.COM>
tkyte@TKYTE901.US.ORACLE.COM> exec reset_seq( 'my_seq' );

PL/SQL procedure successfully completed.

tkyte@TKYTE901.US.ORACLE.COM> select my_seq.nextval from dual;

   NEXTVAL
----------
         1

Review &
      Followup

      Rating: 5
IT
      Consultant  August 14, 2001
Reviewer:
      A reader  from Australia
Very useful Tom. I like the way you are thinking and solving problems.

      Rating: 3
Innovative
      work  September 03, 2001
Reviewer:  Amod
       from Bangalore, India
Hi,

 A really nifty and innovative work to reset sequences. But then wouldn't it be
more efficient to drop and recreate the sequence?

Just wondering...

          Followup:

It is better to reset then drop/create.

The major #1 reason is that dependent objects will NOT go invalid during a
reset, they will during a drop/create cycle.  If you have stored
procedures/triggers dependent on this sequence -- dropping would be bad.
Consider:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace procedure p
  2  as
  3          l_number number;
  4  begin
  5          select my_seq.nextval into l_number from dual;
  6  end;
  7  /
Procedure created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select object_type, object_name, status
  2  from user_objects
  3  where status = 'INVALID'
  4  order by object_type, object_name
  5  /
no rows selected

ops$tkyte@ORA817DEV.US.ORACLE.COM> drop sequence my_seq;
Sequence dropped.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create sequence my_seq;
Sequence created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select object_type, object_name, status
  2  from user_objects
  3  where status = 'INVALID'
  4  order by object_type, object_name
  5  /

OBJECT_TYPE        OBJECT_NAME                    STATUS
------------------ ------------------------------ ----------
PROCEDURE          P                              INVALID

the very next time the procedure is run, it'll be implicitly compiled.  This
adds overhead -- especially if you have LOTS of dependent objects

ops$tkyte@ORA817DEV.US.ORACLE.COM> begin
  2          for i in 1 .. 100
  3          loop
  4                  p;
  5          end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

so the procedure is valid again -- now, we'll "reset it"

ops$tkyte@ORA817DEV.US.ORACLE.COM> select my_seq.nextval from dual;

   NEXTVAL
----------
       101

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec reset_seq( 'my_seq' )
PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select my_seq.nextval from dual;

   NEXTVAL
----------
         1

ops$tkyte@ORA817DEV.US.ORACLE.COM> select object_type, object_name, status
  2  from user_objects
  3  where status = 'INVALID'
  4  order by object_type, object_name
  5  /

no rows selected

and this time the procedure is NOT invalid -- thats better.

      Rating: 4
Very
      detailed  September 07, 2001
Reviewer:  CL
       from DE USA
This is cool and informative.

September 07, 2001 Suresh -- Thanks for the question regarding "REF
      CURSOR - varying number of elements in an IN LIST", version 8.1.7

      You Asked
Tom,
  I have a package that sends out record sets thru' ref cursor.
 My requirement is as follows. I would be passing a string p_empno to the
package , say 1,2,3 and in the procedure how to code using ref cursors for

 select * from emp where empno in (p_empno);

I coded as following and it does not work.

 PROCEDURE GET_emp(p_empno   IN   VARCHAR2,
                   p_lvs    OUT   t_ref_cursor) AS
BEGIN
  EXECUTE IMMEDIATE 'OPEN p_lvs FOR SELECT * FROM EMP WHERE
                     EMPNO IN(' || p_empno || ');
end;

Thanks much,
Suresh

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:139812348065
...

You example would work as:

open p_lvs for 'select * from emp where empno in (' || p_empno || ' )';

but it does NOT use bind variables which is the single worst thing you could do.
 Use my approach instead (to provide scalability and performance)
Review &
      Followup

      Rating:
      4
  September 07, 2001
Reviewer:
      Suresh
Tom,Thanks a lot for your help.

September 08, 2001 -- Thanks for the question regarding "Performance
      when a View using other Views", version 7.X, 8.x

      You Asked
Tom,

Could you elaborate potential performance issues when selecting from a view that
uses other views. The views inside of the view could be very complex view and
may have group by and order by.

Your answer is very appreciated.

      and we said...
There is NO difference between selecting from a VIEW based on other VIEWS and
doing the select straight out -- if the two queries are equivalent.

This is where the mis-conception with regards to views comes in.  If a view
contains aggregates, outer joins, and some other complex operations -- the
ability to "merge" your request into the view definition becomes limited (if not
impossible).  Most of the times when I see people complain about the performance
of queries against views versus a straight out query -- it is because the two
queries they are comparing (the query against the view and their well performing
query) are not only syntactically different -- but they are SEMANTICALLY
different.

This:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1275680497791
is the classic example of what I mean.  The person writing that question wanted
to know why we didn't push the predicate down into the view (which would be
faster).  He compared it to a query directly against the tables where he DID
push it down himself.  The problem is (as demonstrated) that the queries
actually return DIFFERENT results.  That is, we could NOT push the predicates
down into the view, we could not merge the views together simply because that
would change the outcome.

What I see frequently is someone will define a set of views with outer joins and
aggregates but the query against them needs NEITHER the outer join or aggregate
to be present (and hence is an inappropriate view to be used in this case).  It
is due to this additional work (and the reduced number of plans open to the
query) that the view is deemed "slow".

When properly constructed and used -- a view of a view of a view of a view is no
slower (or faster) then the straight query itself.

That aside -- it is many times easier to write the query directly against the
base tables themself for performance (you are asking the specific question
against the base tables directly) then it is to write the query using "generic"
views not necessarily designed for your question.

So, don't be afraid of views of views (of views) -- just make sure they are
being used properly (and don't hesitate to NOT query the other views in there
when tuning -- go against the base tables when need be).

Review &
      Followup

      Rating: 4
Performance on
      views  September 08, 2001
Reviewer:
      A reader  from ca usa
Tom's column is my must read

      Rating:
      4
  September 08, 2001
Reviewer:  Muhammad
      Bilal  from Pakistan
Thanks Tom

      Rating: 4
Performances on
      Views  September 10, 2001
Reviewer:
      A reader  from San Jose, CA

September 08, 2001 nag -- Thanks for the question regarding "follow
      up", version 8.1.7

      You Asked
Tom

http://asktom.oracle.com/pls/ask/f?p=4950:9:::NO::F4950_P9_ORIG,F4950_P9_DISPLAYID:Y,1351177323876
When Objects first came
out -- if you tried to use the 7.3 sqlplus client to submit a "create or replace
type" command -- it would fail because sqlplus would submit it when it hit the
first ";" -- not the "/".  Plus did not know how to do that.

what do you mean by saying "when it hit the first ";" -- not the "/".  "

2.   4) see dbms_application_info.  It sets this.  It is a number that means
something to you.  It is just a number -- put anything you want in there.

how should I put that number value there, at what stage should I insert, and how
should I use this column meaningfully.

Thank you

      and we said...
1) I mean that if I use a 7.3 client to connect to and 8.x database and try to
create a TYPE:

$ sqlplus scott/tiger@ora8idev.us.oracle.com

SQL*Plus: Release 3.3.4.0.1 - Production on Sat Sep  8 09:12:12 2001
Copyright (c) Oracle Corporation 1979, 1996.  All rights reserved.
Connected to:
Oracle8i Enterprise Edition Release 8.1.7.2.0 - Production
With the Partitioning option
JServer Release 8.1.7.2.0 - Production

scott@ORA817DEV.US.ORACLE.COM> create type myType as object
  2  ( x int,
  3    member procedure foo
  4  );

Operation 77 succeeded.

not only do I get "meaningless" responses from these new commands but worse:

scott@ORA817DEV.US.ORACLE.COM> create type body myType
  2  as
  3  member procedure foo
  4  is
  5  begin
  6     null;

Operation 2438948 succeeded.

but sqlplus prematurely submitted my statement when it hit a ";" -- it did not
know that it NEEDED to wait for a "/" to run the block.  Additionally, it
"succeeded" and show errors does not work:

scott@ORA817DEV.US.ORACLE.COM> show errors
No errors.

A select on user_errors however shows:

scott@ORA817DEV.US.ORACLE.COM> select text from user_errors where name =
'MYTYPE';

TEXT
---------------------------------------------------------------------------------
--------------------------------------------------
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the
following:

   ;

that it really did not work.

2) you use dbms_application_info.SET_SESSION_LONGOPS.  One of the input
parameters is CONTEXT.  (if you have my book -- i have a whole section on using
dbms_application_info with examples -- otherwise the Supplied Packages Guide
does list and explain all of the inputs to these routines).

To use this column meaningfully is up to you.  I cannot tell you how to use it
meaningfully.  One "example" might be:

.... you have a long running stored procedure.  You decide to
"v$session_longops" enable it.  This stored procedure processes an ORDER in your
ORDER ENTRY system.  The order entry system uses a primary key of type NUMBER.
Your "context" could then be this number (your stored procedure recieves the
order number to process -- you would use the set_session_longops procedure to
SET this order number in the context column).  Now when people query
v$session_longops to monitor the process of your long running procedure, they
can see not only an estimate of how long it will take to complete based on
information you supply -- they can see the order number you are processing .....

Review &
      Followup

      Rating: 5
cool
      Tom  September 08, 2001
Reviewer:
      A reader
I got a solution.

September 08, 2001 mark -- Thanks for the question regarding
      "scrolling text", version developer 6i

      You Asked
i'd like to know how i can have a window pop up with scrolling text on one of my
forms. it is not a web based application. thanks

      and we said...
In a way yes -- you can do this with a timer.

What I did as an example was to create a new form with a default block on DEPT
(just to have some data).  On this canvas I put another non-database block
(called SCROLLING) with two items

o MSG -- a visible text area the width of which was set to the length of the
message portion I wanted to see

o OFFSET -- a non-visible text area where I would store the current offset.

In a when-new-form-instance trigger, I created a time.  You would create this
time when you wanted to have the message scroll and destroy it when you were
done scrolling.  It looked like this:

DECLARE
     timer_id Timer;
     interval NUMBER := 1000;
BEGIN
     timer_id := CREATE_TIMER('my_timer', interval, REPEAT);
END;

Then, also at the form level, I created a when-timer-expired trigger that looked
like this:

declare
  l_msg varchar2(255) := 'How now brown cow, the fox jumped over the moon....';
  l_tot_len number := length(l_msg);
  l_msg_len number := 10;
  l_offset number := nvl( :scrolling.offset, 1 );
begin
  :scrolling.msg := substr( l_msg, l_offset, l_msg_len );
  if ( l_offset+l_msg_len > l_tot_len )
  then
     :scrolling.msg := :scrolling.msg ||
                       substr( l_msg, 1, l_msg_len-length(:scrolling.msg)+1 );
  end if;
  :scrolling.offset := mod( l_offset, length(l_msg) )+1;
end;

This will display 10 character of the l_msg variable in the :scrolling.msg box
(depending on what your forms do -- you might need a "synchronize" call in there
at the end -- i did not).

September 08, 2001 Sudhir -- Thanks for the question regarding
      "trapping transaction information", version 8.1.7.2

      You Asked
Hello Tom! Hope your vacation was great. Also, thanks for your response on my
prior question.

This is my new question: In our application a user may update/insert/delete
row(s) from many tables. If we want to replay the user action we need to trap
the user transactions. One other problem is all the users have their own id but
backend server which does work for them always logs into db with the same
userid. Thus using LogMiner etc very difficult. Also I dont have any say in
asking for code change to reflect such information. Mainly if this can be done
on database non-intrusively then it is great.

I was thining along following lines
1) create a sequence to be used as transaction number (unless there is such
thing as a transaction number accessible in trigger)
2) use a global temporary table.
3) Put triggers on each table such that each checks if a row exists in global
temp. table. If one exists then you know some other trigger fired before you and
you are either in the middle of transaction or at the end of one. If no row
exists then insert sequence number in it and use it in "4" below.
4) Of course after every trigger fire, we will save all table row information
and transaction number and sysdate in txn_info table.
5) at the end of transaction the row in global temp will be gone unless it has
some use

So I should have a trail table like below

TXN#   TABLE_NAME    ACTION    TXN_DATE            OLD_VAL  NEW_VAL
   1   CUST          Delete    09/08/2001 12:12:30 some     some
   2   CUST_ADDR     Delete    09/08/2001 12:12:35 some     some
   1   CUST_ADDR     Update    09/08/2001 12:12:36 some     some
   2   ACCT_INFO     Add       09/08/2001 12:12:36 some     some
...

etc

So now if I say
select TXN#, TABLE_NAME, ACTION from tran_info
order by txn#, txn_date

i should get all the transactions.

Do you think this will work or is there any better way? Mind you I have really
not developed any complex triggers or such application.

thanks for sea of information you provide.

Sudhir

      and we said...
Well, you could use our transaction id instead (less work on your part, less
triggers and you could tie this into logminer after the fact).  A simple select
would get it for you.  You might consider having your DBA create a view that
replaces the query below and granting you select on that view (so you don't need
select on sys.v_$transaction, v_$session and v_$mystat, just the view).

ops$tkyte@ORA8I.WORLD> create table t ( x int );
Table created.

ops$tkyte@ORA8I.WORLD> create or replace trigger t_trigger
  2  after insert or update or delete on t
  3  for each row
  4  declare
  5      l_transaction_id varchar2(75);
  6  begin
  7      select xidusn || '.' || xidslot || '.' || xidsqn
  8        into l_transaction_id
  9        from v$transaction
 10       where addr = ( select taddr
 11                        from v$session
 12                       where sid = ( select sid
 13                                       from v$mystat
 14                                      where rownum = 1 )
 15                    );
 16
 17      dbms_output.put_line( l_transaction_id );
 18  end;
 19  /
Trigger created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 1 );
28.48.74514

1 row created.

ops$tkyte@ORA8I.WORLD> insert into t values ( 2 );
28.48.74514

1 row created.

ops$tkyte@ORA8I.WORLD> commit;
Commit complete.

ops$tkyte@ORA8I.WORLD> insert into t values ( 3 );
29.64.74394

1 row created.

Review &
      Followup

      Rating: 5
very good
      information  September 08, 2001
Reviewer:
      A reader
I thank you for the information. I will play with it.
Tom you are the best and the most humble person I have ever met.

thanks again!

Sudhir

September 09, 2001 Doug -- Thanks for the question regarding
      "Running a database with no datafiles on UNIX JFS", version 8/1/7

      You Asked
Tom - I encountered what I thought was an interesting phenomenon -
I had to wipe out a database and decided to try something.
I logged in as system and spooled out the control files, the log files, the
datafiles, and the temp files.   From another Unix session, I deleted the entire
database.

But.. from the original session, I was able to create a table and insert and
COMMIT rows... I could do all sorts of things until the inability to find the
next logfile on a switch crashed the database.

Here's some info I've dug up on what might be going on.
1) Files are not really deleted in UNIX even though you don't see them if
someone (oracle) has a handle for it. So.. Oracle is not really running without
files after all, it's only when it tries to grab the next logfile that it has a
problem, because that one really is gone for good.
2) Oracle does not write on commits, and is only making it's changes to the
log_buffer until checkpoint - (I don't like this possibility).
3) The JFS is buffering the information - if I used raw devices I might not see
the same thing.

Your thoughts?

Thanks,
Doug

      and we said...
1) that is correct. that is the way it works.  The files are unlinked from the
directory (making them appear gone) but they are not gone until the last process
that has them open closes them.

This is the expected behavior.  the database can run for many days after an rm
of its datafiles before anyone notices -- at which point you had best do an
immediate export (don't shutdown first) or be prepared to do media recovery

September 09, 2001 Sudhir -- Thanks for the question regarding "data
      compression in Oracle", version 8.1.7.2

      You Asked
Hi Tom!

Thanks for taking my question. We have a table which has 30mill rows and it is
not partitioned. Average row size is about 350. But there is one varchar2(1000)
field and other fixed column width is about 200, (so total max rec length 1200)

My question : Is there a compress function available or you have developed (kind
of like gzip/compress) on a particular column. Suppose this varchar2(1000) field
stores customer feedback or text like what we see on this forum. If I put it in
a file and compress it, minimum saving will be 60% etc. On 60GB or even more
table this could amount to serious saving.

Mind you the client can uncompress the data and client can send compress data as
well - if such gzip/compress API is put in client. In which case Oracle is just
storing this data without any work. But just in case it is possible to compress
text kind of data, I would like to know.

select id, date_called, uncompress(info)
from info_table where id = 1001;

insert into info_table values (id, sysdate, compress(info));

etc

Thank you for your help

Sudhir

      and we said...
You could definitely find and load some java classes that do this HOWEVER you
have to ask yourself -- is it really worth the serious increase in CPU capacity
to save on some disks?  Look at the cost of a single CPU on a big box (5-10k)
and you'll find that you can almost buy 60gig of disk for that much.

So, you can use a java stored procedure -- but is it really worth it.  Consider
what happens when someone wants to search on this text.  You won't be able to
search it -- no indexes.

If the average rowsize is 350 bytes -- I doubt you would save that much anyway.
If all of the text were in a single file -- yes, it could save alot.  In your
case, you have lots of 200/300/400 byte strings.  Here the OVERHEAD of the data
the compression routine needs to store will outweigh any compression benefits.

I took a couple of text files:

$ ls -l x*
-rw-r--r--   1 tkyte          93 Mar  4  1999 x
-rw-r--r--   1 tkyte         810 Aug 19  1997 x.lst
-rwxr-xr-x   1 tkyte         118 Dec 15  1998 x.sql
-rw-r--r--   1 tkyte         633 Jul 19  2000 xtmpx.sql
-rw-r--r--   1 tkyte          35 Feb 29  2000 xxtmpxx.sql

compressed them...

$ foreach f (x*)
? compress $f
? end
xxtmpxx.sql: -- file unchanged

$ ls -l x*
-rw-r--r--   1 tkyte          90 Mar  4  1999 x.Z
-rw-r--r--   1 tkyte         338 Aug 19  1997 x.lst.Z
-rwxr-xr-x   1 tkyte         114 Dec 15  1998 x.sql.Z
-rw-r--r--   1 tkyte         328 Jul 19  2000 xtmpx.sql.Z
-rw-r--r--   1 tkyte          35 Feb 29  2000 xxtmpxx.sql

The text had to be BIG before any benefit was shown -- in some cases -- compress
refused to compress since the resulting file would be larger.  For a
varchar2(1000) where the average size is less then 350 bytes -- it would simply
not be worth it.

Review &
      Followup

      Rating: 5
I agree with
      you.   September 09, 2001
Reviewer:
      A reader
One area is disk size. We use EMC storage and it costs substantial $$/gig per
year. Thus saving space will help. I agree on not able to search on the text and
added overhead to cpu due to compression as well.

Thanks

      Rating: 2
about
      oracle?...   September 11, 2001
Reviewer:
      jo  from korea
i want know.......please....
ummmm...
sorry.. i don't speak english....
uh...
anyway... i want know.. oracle

      Rating: 2
What if I
      really need compression...?  February 18, 2002

Reviewer:  Manoj Bajaj  from Singapore
Tom  looks like u have not answered the Q in details. Ok I have some scenerio
like this where I have to print text data on a machine which is at client place
using report exe and the time to fetch and tranfser data between server location
due to WAN is very high and user really cannot wait for so long ..Is there a way
to compress the data and send compressed data over network and uncompress the
same
when it comes to client report ...or Is it possible to instruct SQL*NET to
compress and uncompress..I tried to search for SQL*NEt but looks like there is
very few info available.....( We use 8i.)

September 09, 2001 vishnu -- Thanks for the question regarding "
      need to display data in one row", version 8i

      You Asked
Tom,
Hope u have enjoyed yr vacation...We missed you ..Here is my question
and i need help from you as usual..
I have a table "country" it will have two fields they are "id" and "name"
it will have many records ...I need to display data of"name" of the countries in
a row ..like

Name : USA,Canada,mexico,india,singapore,briton,..........etc
in row or rows instead of
USA,
Canada
mexico
india
singapore
briton
..........

can u pl help

      and we said...
If you know the maximum number of countries -- you can do this in SQL:

scott@ORA817DEV.US.ORACLE.COM> select rtrim( max( decode( rownum, 1, dname, null
) ) ||','||
  2                max( decode( rownum, 2, dname, null ) ) ||','||
  3                max( decode( rownum, 3, dname, null ) ) ||','||
  4                max( decode( rownum, 4, dname, null ) ) ||','||
  5                max( decode( rownum, 5, dname, null ) ) ||','||
  6                max( decode( rownum, 6, dname, null ) ), ',' )
  7   from dept
  8  /

RTRIM(MAX(DECODE(ROWNUM,1,DNAME,NULL))||','||MAX(DECODE(ROWNUM,2,DNAME,NULL))||',
'||MAX(D
---------------------------------------------------------------------------------
--------
ACCOUNTING,RESEARCH,SALES,OPERATIONS

Here, I know there are 6 or less dnames in my dept table -- it'll concatenate
them together for me...  If there were more then six -- they would silently be
ignored

If I don't know the max, I'll use plsql instead in a function callable from
sql

scott@ORA817DEV.US.ORACLE.COM> create or replace function get_dnames return
varchar2
  2  is
  3          l_data varchar2(4000);
  4  begin
  5          for x in ( select dname from dept )
  6          loop
  7                  l_data := l_data || ',' || x.dname;
  8          end loop;
  9
 10          return ltrim( l_data, ',' );
 11  end;
 12  /

Function created.

scott@ORA817DEV.US.ORACLE.COM>
scott@ORA817DEV.US.ORACLE.COM> select get_dnames from dual;

GET_DNAMES
---------------------------------------------------------------------------------
--------------------------------------------------
ACCOUNTING,RESEARCH,SALES,OPERATIONS

Note that regardless of method -- you are limited to 4000 characters in a
VARCHAR2 in SQL -- you cannot go longer then that with that datatype.

Review &
      Followup

      Rating: 5
I think it is
      more than that  September 09, 2001
Reviewer:
      ?
"Note that regardless of method -- you are limited to 4000 characters in a
VARCHAR2 in SQL -- you cannot go longer then that with that datatype."

1.Tom, I remember using a varchar2 datatype for a variable, while using utl_file
package, and write to a flat file, after concatanating a lot of data to the
varchar2 datatype string. I think the limit is 32,000 or something it 8i, kindly
confirm.

2.what is the max limit for a varchar2 column in a table.

3.why do these limits differe for a datatype which declaring a variable and
while declaring a column in a table.

          Followup:

1) I said "in SQL -- you cannot go longer then that".  In PLSQL -- the limit is
32k.  In SQL the limit is 4000

2) 4000

3) In plsql, varchar2 is just a variable -- it is in ram.  In SQL, it is
something coming from the disk -- it is storage.  The varchar2 type in a table
just doesn't support more then 4000 characters.  You need to use a CLOB for
larger types.

      Rating: 5
Excellant
      .......now i need to display records with spl characters between
      them  September 10, 2001
Reviewer:
      A reader
Tom ,
Yr answer is too good ...Now my problem is a similar one like
below..pigments_name is the name of the column in pigments table...
         pigments_name
1Indigo Carmine (Indigotine) / E132 / FD&C Blue 2 - GLOBAL
2Iron Oxide Black / E172 / 21 CFR 73.1200 - GLOBAL
3Iron Oxide Red / E172 / 21 CFR 73.1200 - GLOBAL
4Iron Oxide Yellow / E172 / 21 CFR 73.1200 - GLOBAL
5Titanium Dioxide / E171 / 21 CFR 73.1575 - GLOBAL&wed
6Allura Red AC.100 / E129,FD&C Red 40
7Amaranth / E123

Now my problem is to display the all the selected records in portal..and wrote a
query like this
"select pigments_name from pigments where pigments_name in
:pigments "

where :pigments is the bind varaible in a drop down list
user will select many records and i need to display them..

My problem is it is not giving me proper results ,may be because of special
characters like" /,$& .: "in between the records ..Can u please help me how to
solve this problem ..
what type of characters are not accepted between the records and why ? pl help

vi

September 09, 2001 mike -- Thanks for the question regarding
      "primary key violated", version 8.1.5

      You Asked
Tom,
I have created a table as:

create table t1
as
select object_id empno, owner||'.'||object_name ename,
       object_type city, mod(object_id,100) deptno,
       status division
  from all_objects
/

insert /*+ APPEND */ into t1
select empno + rownum+cnt,  ename,city ,deptno , division from t1,
(select count(*) cnt from t1)
;

.. a few more time for the INSERT as above.
then I tried to:
TRINH@TEST> alter table t1 add constraint t1_pk primary key(empno);
alter table t1 add constraint t1_pk primary key(empno)
*
ERROR at line 1:
ORA-02437: cannot validate (TRINH.T1_PK) - primary key violated

I beleive that empno is the candiate for PK:

SBU@TEST> select distinct count(empno) from t1;

COUNT(EMPNO)
------------
      387744

TRINH@TEST> select count(*) from t1;

 COUNT(*)
---------
   387744

TRINH@TEST> select count(*) from t1 where empno is null;

 COUNT(*)
---------
        0

What did it go wrong?

      and we said...
try select count( DISTINCT empno ) from t1 -- NOT select distinct count(empno)
from t1.  The count(distint empno) will tell you the count of the distinct
empno's in t1 whereas distinct count(empno) will return you the distinct COUNTS
of non-null empnos....

The dups are happening due to something like this:

assume object_ids 1 .. 1,000,000 are in use.
assum there are 10,000 objects in all_objects

When you do the create table as select, EMPNO = 10,002 was put into t1 (for
example).  There was some object with object_id = 10,002.

Assume also that an object with object_id = 1 existed.

Now, when you do the insert /*+ append */ -- you'll get object_id = 1 from
all_objects, add 10,000 to it (thats CNT the first time) and then add 1 (rownum
-- it just happened to be the first row returned).  Now you have just put 10,002
in the table -- AGAIN.

Maybe use

insert /*+ APPEND */ into t1
select rownum+cnt,  ename,city ,deptno , division from t1,
(select max(empno)+1 cnt from t1)
;

instead ( note -- removed empno from the function in the select list, just using
rownum and cnt and cnt is now the max(empno)+1 )....


Subject | Article | Last Updated (East coast time)
Snapshot Refreshment and Rollback Segment | article only | Sep 10, 2001 09:01 am
transaction control | article only | Sep 10, 2001 12:01 pm
Locally Managed Tablespace and DBA_FREE_SPACE view | article only | Sep 11, 2001 09:37 am
Matrix Report | article only | Sep 11, 2001 09:40 am
Hi tom | article only | Sep 11, 2001 10:48 pm
Runing Procedure | article only | Sep 11, 2001 11:50 pm
Pinning data buffers to memory | article only | Sep 12, 2001 10:26 am
Checksumming Concept & query resolution | article only | Sep 12, 2001 01:29 pm
restrict connections by application | article only | Sep 12, 2001 02:51 pm
GOTO statement | article only | Sep 12, 2001 02:59 pm
how to sort in SP | article only | Sep 12, 2001 03:38 pm
Persistant Value | article only | Sep 12, 2001 04:28 pm
Calling SP with PLSQL Tables indexed by char(1) parameters | article only | Sep 12, 2001 04:58 pm
Join a view with UNION | article only | Sep 12, 2001 05:22 pm
dbmssql, partition wise join, , parallel query | article only | Sep 12, 2001 06:13 pm
Compare initial_extent 7.3.4 vs 8.1.6 | article only | Sep 12, 2001 07:03 pm
Overhead of many freelists | article only | Sep 13, 2001 11:17 am
using snapshot for datawarehousing | article only | Sep 13, 2001 11:57 am
Index and Indexes | article only | Sep 13, 2001 12:55 pm
DB/system overhead regarding intermedia text | article only | Sep 13, 2001 04:54 pm
ref cursor | article only | Sep 13, 2001 06:16 pm
How to change the value in GLOBAL_NAME table | article only | Sep 13, 2001 11:31 pm
estimate space | article only | Sep 13, 2001 11:40 pm
Disabling PK constraint - how to preserve index definition | article only | Sep 14, 2001 10:26 am
insert and update in a single shot | article only | Sep 14, 2001 12:14 pm
Query the database.... | article only | Sep 14, 2001 01:25 pm
Rollback segments | article only | Sep 14, 2001 03:53 pm
update top rows randomly | article only | Sep 14, 2001 04:09 pm
Java basics.... | article only | Sep 14, 2001 04:50 pm
What is the function used on a function-based index? | article only | Sep 14, 2001 04:52 pm
Order of NULL/NOT NULL columns while creating table/Usage of Mixed case letters in procedures | article only | Sep 15, 2001 06:57 pm
form_ddl is not working | article only | Sep 15, 2001 07:12 pm
how to do it without ON DELETE CASCADE? | article only | Sep 16, 2001 03:15 pm
where are temporary LOB stored | article only | Sep 16, 2001 09:07 pm
efficiency of HASH join | article only | Sep 16, 2001 09:12 pm
row(s) 1 - 35 of 35
September 10, 2001 Young-Inn -- Thanks for the question regarding "Snapshot Refreshment and Rollback Segment", version 8.1.6
You Asked
Hi, there..

Firstly, thanks very much for your kind answers here..
Questings and their answers are very helpful to me - of course to others, for
sure, - for knowing Oracle.

I'm working on Snapshot, and that's why I'm here..

There are two servers, A and B(A is mine and B is remote DB server).
And there are some tables having some part of B in A.
Not same, but similiar.
For example, some column is same but the others are different in the table
having member informations.

What I have to do is..
After getting data from B by snapshot and  applying the changes
(Inserting/Updating/Deleting) to A - Process1 - ,
I have to send some tables of mine to B by snapshot- Process2 -.
It needs kind of sequencial process. Process2 After Process1!!

B --> A : Process1
A --> B : Process2

Although I can DBMS_JOB and DBMS_REFRESH to make them execute periodically in
different time, What I want is Process1 and Process2 is executed by the
procedure "getSnapshot" in A.
That's because I have no idea how long it will take when the data increase.

I made a snapshot group in A and B each. and some procedure too..
Process1 is fine....
but the problem is Process2.

I tried to refresh the snapshot group of B in the procedure "getSnapshot" in A.
I got an error.
And I tried to call the procedure, which rerfreshes the snapshot group of B and
the procedure is in B. But the same error occurred.

The errors is..

ORA-02074: cannot COMMIT or ROLLBACK in a distributed transaction
Cause: A COMMIT or ROLLBACK was attempted from a session other than the parent
of a distributed transaction.

Q1:Is there any way to refresh remote snapshot group ?

And when I created the snpashot groups in A and B, I did like this..

CREATE OR REPLACE PROCEDURE snp_make IS
      BEGIN
         DBMS_REFRESH.MAKE(
           name             => 'REP1',
           list             =>'..24 snapshots..',
           next_date        => SYSDATE,
           interval         => 'SYSDATE + 1',
           implicit_destroy => TRUE,
           rollback_seg     => 'testRBS'
         );
      END;
/

I made the rollback segment "testRBS", and I refreshed this group..
and then testRBS was getting bigger to 1.5G..
But after finishing refreshment, the size wouldn't be smaller.
I thought it would be back to the default size.
Snapshot doesn't turn back to RBS?

Q2 : Could you tell me why it was?

I hope you can understand what I mean..sorry for my poor Eng.

And thank you in advance..
and we said...
Q1 -- the way I do this is to remotely call DBMS_JOB on the other site:

declare
  l_job number;
begin
  dbms_job.submit@B( job=> l_job,
                     what => 'dbms_refresh......;',
                     instance =>  dbms_job.any_instance );
  commit;
end;
/

that will cause the refresh to happen very soon after you commit as a LOCAL
transaction on the remote site -- avoiding the "cannot commit" issue.

Q2 -- was the rollback segment set to optimal and did you hit the special
condition that causes rollback segments to "shrink"?

see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c02block.htm#8401
and look for  How Extents Are Deallocated from a Rollback Segment
September 10, 2001 nag -- Thanks for the question regarding "transaction control", version 8.1.7
You Asked
create or replace package demo_pkg
as
    type numArray is table of number index by binary_integer;
    l_pks  numArray;
end;
/

declare
    l_empty demo_pkg.numArray;
begin
    demo_pkg.l_pks := l_empty;
    for x in ( select object_id from all_objects )
    loop
        demo_pkg.l_pks(demo_pkg.l_pks.count+1) := x.object_id;
        exit when demo_pkg.l_pks.count = 1000;
    end loop;
end;
/

When we compare the performance of "loop over the array and delete each row",
versus "send the array to the kernel and let it loop over the array" we find:

begin
    for allin  i in 1 .. demo_pkg.l_pks.count
delete from t t1 where object_id = demo_pkg.l_pks(i);
end;

In the above case
How are errors handled? Let say there are 3 records, the first one completes,
and error out on the second one,
does error handling takes care of it

How about transaction control? Will the rollback segment be big enough to handle
multiple deletes? Is there an auto-commit within each FOR loop that I missed
because of a built in feature?

2.If my procedure is calling 10 others procedures, and Iam getting an error, is
there anyway I can know which procedure in there is actually returning an error.
How can this be known.

Thanks
and we said...
It will be handled the same as doing them one by one -- they will all be rolled
back:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t1 as select rownum x from
all_objects where rownum < 20;

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace trigger t1_trigger
  2  before delete on t1 for each row
  3  begin
  4          if :old.x = 10
  5      then
  6                  raise program_error;
  7          end if;
  8  end;
  9  /

Trigger created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2      l_empty demo_pkg.numArray;
  3  begin
  4      demo_pkg.l_pks := l_empty;
  5      for x in ( select x from t1 order by x )
  6      loop
  7          demo_pkg.l_pks(demo_pkg.l_pks.count+1) := x.x;
  8          exit when demo_pkg.l_pks.count = 10;
  9      end loop;
 10  end;
 11  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select count(*) from t1;

  COUNT(*)
----------
        19

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> begin
  2      forall i in 1 .. demo_pkg.l_pks.count
  3          delete from t1 where x = demo_pkg.l_pks(i);
  4  end;
  5  /
begin
*
ERROR at line 1:
ORA-06501: PL/SQL: program error
ORA-06512: at "OPS$TKYTE.T1_TRIGGER", line 4
ORA-04088: error during execution of trigger 'OPS$TKYTE.T1_TRIGGER'
ORA-06512: at line 2

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select count(*) from t1;

  COUNT(*)
----------
        19

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> begin
  2      for i in 1 .. demo_pkg.l_pks.count
  3          loop
  4          delete from t1 where x = demo_pkg.l_pks(i);
  5          end loop;
  6  end;
  7  /
begin
*
ERROR at line 1:
ORA-06501: PL/SQL: program error
ORA-06512: at "OPS$TKYTE.T1_TRIGGER", line 4
ORA-04088: error during execution of trigger 'OPS$TKYTE.T1_TRIGGER'
ORA-06512: at line 4

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select count(*) from t1;

  COUNT(*)
----------
        19

As for "will rollback segments be big enough" -- well, I cannot answer that for
you.  I can say that on my system -- they would be (i would have sized them with
these transactions in mind).

I am not a fan of the "commit in the loop to 'save' resources".  I am a fan of
sizing things to hold my TRANSACTION.  If I had to delete tons of rows -- I
would look for another way in some cases (see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:890462882545
)

Also, with the forall -- there is nothing saying you have to load up ALL the
rows you want to delete at once, you yourself control the number of elements in
the array.  You can array delete 100, 1000, 10000 at a time - whatever you want
(and commit if you really want to)

2) exception handlers.

  ...
  begin
       begin p1; exception when others then
          bad_procedure := 'p1';
          raise;
       end;
       begin p2; exception when others then
          bad_procedure := 'p2';
          raise;
       end;
       ....
Review & Followup
Rating: 3
Instead September 10, 2001
Reviewer: Obs
of doing what you said in solution to questin 2, can I I use dbms_trace , or use
format_error_stack , to know in which procedure the error occurred.  Actually,
how can I use the dbms_trace, and format_error_stack for the purpose.

I was told by my colleague that , if we use format_error_stack, in the when
others then
dbms_output.put_line( format_error_stack ........) , it will list out all the
procedures accessed , and the errors occurred.

more on this please.

Followup:
format_error_stack cannot be used -- it looses the "line number" information.
You would have to let the error propagate all of the way out of the procedure,
back to the client, in order to get the line number information:

ops$tkyte@ORA9I.WORLD> create or replace procedure p1
  2  as
  3  begin
  4  null;
  5  end;
  6  /

Procedure created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> create or replace procedure p2
  2  as
  3  begin
  4  raise program_error;
  5  end;
  6  /

Procedure created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> begin
  2          p1;
  3          p2;
  4  exception
  5          when others then
  6                  dbms_output.put_line( dbms_utility.format_error_stack );
  7  end;
  8  /
ORA-06501: PL/SQL: program error

PL/SQL procedure successfully completed.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> begin
  2          p1;
  3          p2;
  4  end;
  5  /
begin
*
ERROR at line 1:
ORA-06501: PL/SQL: program error
ORA-06512: at "OPS$TKYTE.P2", line 4
ORA-06512: at line 3

Only when PLSQL "ignores" the error and lets the client get it is the fact that
P2 caused the error there.

Rating: 4
Well, then what is the utility of dbms_utility.format_error_stack September 10, 2001
Reviewer: Obs
Well, then what is the utility of dbms_utility.format_error_stack  , where
should we use it , and why should we use it

You didnt say anything about the trace.

Followup:
It is not very useful.  Don't use it if you don't want to.  I pretty much never
use it.

DBMS_TRACE is OK in a debug environment but in "real" code the overhead is too
much.  Give it a try if you like.

The real answer here is to use exception handling.

Rating: 3
DBMS_TRACE is OK September 10, 2001
Reviewer: A reader
Can you give us an example and show how to put error information into tables
using dbms_trace , and then use the same for trouble shooting. This is very
important, becasue not many developers have used it .

Rating: 5
Tom, please tell us how to use dbms_trace , to trouble shoot with an example September 11, 2001
Reviewer: A reader

September 11, 2001 William -- Thanks for the question regarding "Locally Managed Tablespace and DBA_FREE_SPACE view", version Oracle 8.1.7
You Asked
Hi Tom,

I am using locally managed tablespaces in my database. Running
the query:

select fs.tablespace_name  tsname,
  df.tot_blks    tot,
  fs.free_blks   free,
  df.tot_blks - fs.free_blks used,
  nvl(seg.seg_blks, 0)   alloc,
  (df.tot_blks - fs.free_blks) - nvl(seg.seg_blks, 0) lost
from  ( select tablespace_name,
    sum(blocks) tot_blks
    from dba_data_files
    group by tablespace_name ) df,
  ( select tablespace_name,
    sum(blocks) free_blks
    from dba_free_space
    group by tablespace_name ) fs,
  ( select tablespace_name,
    sum(blocks) seg_blks
    from  dba_segments
    group by tablespace_name ) seg,
  dba_tablespaces ts
where  df.tablespace_name = fs.tablespace_name
and  df.tablespace_name = seg.tablespace_name (+)
and  df.tablespace_name = ts.tablespace_name
and  ts.extent_management = 'LOCAL'
/

I get the following results:

                        Total         Free         Used
Alloc         Lost
Tablespace             Blocks       Blocks       Blocks
Blocks       Blocks
---------------- ------------ ------------ ------------
------------ ------------
DYNDATA               192,000      163,840       28,160
24,576        3,584
STDATA                 38,400       37,104        1,296
1,280           16
TOOLS                   2,560        2,528           32
 16           16
USERS                   1,280        1,248           32
 16           16
STIDX                  12,800       12,784           16
  0           16
DYNIDX                 12,800       12,288          512
  0          512

The tablespaces have had objects created and deleted. My
question is why are there "lost blocks". I know that each
datafile uses 64K to maintain a bitmap of free blocks. I am
using 8K blocks.

Cheers
and we said...
Sounds like you are using uniform extent management and your
datafiles are not an even multiple + 64k of the extent size.
Consider for example (using your query):

tkyte@TKYTE816> create tablespace lm
  2  datafile 'c:\temp\lm.dbf'
  3  size 500k
  4  extent management local
  5  uniform size 400k;

Tablespace created.

So, in this tablespace, we allocate 400k extents.  Looking at
your query:

tkyte@TKYTE816> @a

TSNAME  TOT FREE USED ALLOC LOST
------ ---- ---- ---- ----- ----
LM       63   50   13     0   13

we've lost 13 blocks due to overhead.  Now, I have a 8k block
size so that is 8k*13 = 104k. 64k is bitmap overhead so that is
40k unaccounted for.  Well, that makes sense since 504k (the
real size of the datafile -- it has 63 blocks) MINUS 400k for an
extent is 104k MINUS 64k for the overhead is 40k.  We have 40k
we can never allocate to an extent.

Let's resize the file to be better suited to this tablespace:

tkyte@TKYTE816> alter database datafile 'c:\temp\lm.dbf' resize
864k;

Database altered.

tkyte@TKYTE816> @a

TSNAME  TOT FREE USED ALLOC LOST
------ ---- ---- ---- ----- ----
LM      108  100    8     0    8

There we go -- we have room for exactly 2 400k extents plus
64k for the bitmap -- minimal lossage

tkyte@TKYTE816> alter database datafile 'c:\temp\lm.dbf' resize
464k;

Database altered.

tkyte@TKYTE816> @a

TSNAME  TOT FREE USED ALLOC LOST
------ ---- ---- ---- ----- ----
LM       58   50    8     0    8

tkyte@TKYTE816> alter database datafile 'c:\temp\lm.dbf' resize
460k;

Database altered.

Same story here -- we have room for exactly 1 400k extent and
the 64k overhead.  If we try to go too small:

tkyte@TKYTE816> alter database datafile 'c:\temp\lm.dbf' resize
432k;
alter database datafile 'c:\temp\lm.dbf' resize 432k
*
ERROR at line 1:
ORA-03214: File Size specified is smaller than minimum required
Review & Followup
Rating: 4
WHAT IF ? September 11, 2001
Reviewer: A reader
WHAT IF THE TABLESPACE IS  TEMPORARY AND MANAGED LOCALLY. THE FREE SPACE DOESN'T
SHOW UP IN DBA_FREE_SPACE. IS THERE AN EQUIVALENT VIEW FOR TEMPORARY TS ?.

Followup:
You don't need a dba_free_space for temporary files.  Consider them to always be
"all used".  You use the dynamic performance view v$sort_segment and
v$sort_usage to see how the system is using them.

Space in temporary tablespaces is allocated and managed by the system itself in
memory -- not in the normal fashion.  It doesn't make sense to look at the
physically unallocated space in "temp" and say that is how much is free.  You
rather look at how much is allocated and in use in the v$sort_segment/usage
views and assume the rest is in fact "free"

Rating: 3
Scripts for freespace in locally managed temporary tables July 26, 2002
Reviewer: Dik Pater from The Netherlands
Hi Tom,
thanks for the lots of info on this site.
I use this query for getting the information concerning freespace in LM TEMP :

-- START
col size_temp_files format 99999 Heading "Size|Temp|Files"
col free_space_in_temp_files format 99999 Heading "Free|Space|In|Temp|Files"
col free_space_in_sort_segment format 99999 Heading "Free|Space|In|Sort|Segment"
col used_space_in_sort_segment format 99999 Heading "Used|Space|In|Sort|Segment"
col total_free format 99999 Heading "Total|Free"
select tsh.tablespace_name
,      dtf.omvang size_temp_files
,      tsh.free_space_space_header free_space_in_temp_files
,      nvl(ss.free_space_sort_segment,tsh.used_space_space_header)
free_space_in_sort_segment -- could be empty
,      nvl(ss.used_space_sort_segment,0) used_space_in_sort_segment
,
tsh.free_space_space_header+nvl(ss.free_space_sort_segment,tsh.used_space_space_h
eader) TOTAL_FREE
 from
( select tablespace_name, sum(bytes)/1024/1024 omvang from dba_temp_files
  group by tablespace_name ) dtf
,(
  select tablespace_name
 ,sum(BYTES_USED)/1024/1024 USED_SPACE_SPACE_HEADER
 ,sum(BYTES_FREE)/1024/1024 FREE_SPACE_SPACE_HEADER
 from v$temp_space_header
 group by tablespace_name
 ) tsh,
( select tablespace_name
 ,sum(USED_BLOCKS)/1024/1024            USED_SPACE_SORT_SEGMENT
 ,sum(FREE_BLOCKS)*par.value/1024/1024  FREE_SPACE_SORT_SEGMENT
 from v$sort_segment ss
 ,    v$parameter par
 where par.name = 'db_block_size'
 group by tablespace_name, value
 ) ss
where dtf.tablespace_name = tsh.tablespace_name
and   ss.tablespace_name (+)  = dtf.tablespace_name
/
-- END

Rating: 5
Excellent script September 17, 2003
Reviewer: MZ from MA, US
The script from Dik Pater is excellent!!!

Rating: 3
trying Dik Pater's script November 10, 2003
Reviewer: Fernando Sanchez from Madrid, Spain
I've tried Dik Pater's script, having a temporary tablespace  called TEMP with 2
tempfiles (one 600 Mb size and the other 400 Mb size) and I get:

TABLESPACE_NAME                SIZE_TEMP_FILES FREE_SPACE_IN_TEMP_FILES
FREE_SPACE_IN_SORT_SEGMENT USED_SPACE_IN_SORT_SEGMENT TOTAL_FREE
------------------------------ --------------- ------------------------
-------------------------- -------------------------- ----------
TEMP                                      1000                        0
           599,75                          0     599,75

I don't understand what I get, I guess SIZE_TEMP_FILES=1000 is OK, but what
about the others columns?

Can someone help me?

September 11, 2001 Chneih -- Thanks for the question regarding "Matrix Report", version 8i
You Asked
Hi Tom,

I'm doing this matrix report wherein I'll be counting the total number of
records based on the status per vendor and for the last 3 months from the
current date.

Here's the table
Table XYZ

Columns:   Date_enter      Status       Vendor
           ------------    --------    -------
            01-apr-01       C            RED
            02-apr-01       S            RED
            03-apr-01       S            RED
            21-apr-01       C            RED
            24-apr-01       R            RED
            31-mar-01       C            RED
            01-may-01       C            BLUE
            01-may-01       C            RED
            01-jun-01       R            RED
            03-jun-01       C            RED
            04-jun-01       C            RED
            05-jun-01       S            RED
            06-jun-01       C            RED
            09-jun-01       R            RED

Here's the report that I would like to have. Assuming sysdate is 10-jun-01.....

Vendor : RED    Total  Status       Status
                 Rec     C            R
April Total       5      2            1
May Total         1      1            0
Jun 1             1      0            1
Jun 2             0      0            0
Jun 3             1      1            0
Jun 4             1      1            0
Jun 5             1      0            0
Jun 6             1      1            0
Jun 7             0      0            0
Jun 8             0      0            0
Jun 9             1      0            1
Jun 10            0      0            0

How can I minimize the use of making a lot of UNIONS on my query?

Thanks in advance,
CL
and we said...
No need for any UNIONs in that query.  A simple DECODE (or CASE) will do it for
us:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select vendor,
  2             decode( trunc(months_between(:sys_date,date_enter)),
  3                                  1, trunc(date_enter,'mm'),
  4                                  2, trunc(date_enter,'mm'),
  5                                     trunc(date_enter,'dd') ),
  6             count(*) total_rec,
  7             sum(decode( status, 'C', 1, 0 )) status_c,
  8             sum(decode( status, 'R', 1, 0 )) status_r,
  9             sum(decode( status, 'S', 1, 0 )) status_s
 10  from t
 11  where months_between(:sys_date,date_enter) <= 2
 12  group by vendor,
 13             decode( trunc(months_between(:sys_date,date_enter)),
 14                                  1, trunc(date_enter,'mm'),
 15                                  2, trunc(date_enter,'mm'),
 16                                     trunc(date_enter,'dd') )
 17  /

VEND DECODE(TR  TOTAL_REC   STATUS_C   STATUS_R   STATUS_S
---- --------- ---------- ---------- ---------- ----------
BLUE 01-MAY-01          1          1          0          0
RED  01-APR-01          5          2          1          2
RED  01-MAY-01          1          1          0          0
RED  01-JUN-01          1          0          1          0
RED  03-JUN-01          1          1          0          0
RED  04-JUN-01          1          1          0          0
RED  05-JUN-01          1          0          0          1
RED  06-JUN-01          1          1          0          0
RED  09-JUN-01          1          0          1          0

9 rows selected.
Review & Followup
Rating: 4
<=2 September 11, 2001
Reviewer: mohammed Ahmed from Saudi Arabia
<=2 should be replaced with >=2

Followup:
Not if you want the LAST three months.

where months_between(:sys_date,date_enter) <= 2

that predicate will give you all the dates that are 0, 1, or 2 months BEFORE the
bind variable :sys_date -- which is what they requested.

Rating: 4
loop through columns May 19, 2003
Reviewer: A reader
I have cursor where I select n columns with the same data type. In proc. I make
loops through returned rows and I need some code for every column. How can I
make loop by number of columns. Is there the way to return number of columns.
Let's say
  for var_cur in my_cursor loop;
     for column_number in 1..n loop;

Thanks.

September 11, 2001 LOUIS -- Thanks for the question regarding "Hi tom", version 8.1.6
You Asked
Thanks for keeping us at amazed with your simple but yet
accurate answers. My problem is that I would like to set
up a job that execute every sunday at 12:01. I read your
book but it hasn't been clear to me how to do it. Thanks
a lot..

L. Lugo
MNR
and we said...
It's very similar to what is on page 1067 except the NEXT_DATE and INTERVAL
would be different. I'll assume that 12:01 is 12:01 am

declare
   l_job number;
begin
    dbms_job.submit( job => l_job,
                     what => 'your_procedure;',
                     next_date => trunc( next_day(sysdate,'SUN') ) + 1/24/60,
                     interval => 'trunc( next_day(sysdate,''SUN'') ) + 1/24/60'
);
end;

The NEXT_DAY function will find the next day AFTER the supplied date that is on
sunday (so, when it is evaluated on SUNDAY Sept 9, next_day(sysdate,'sun')
returns Sept 16'th

ops$tkyte@ORA8I.WORLD> select sysdate, next_day( sysdate, 'sun' )  from dual;

SYSDATE   NEXT_DAY(
--------- ---------
09-SEP-01 16-SEP-01

All we need to do is TRUNC that and add 1 minute to get 12:01 am.
Review & Followup
Rating: 4
Hi, Tom September 11, 2001
Reviewer: Queenie Hong from Toronto, Canada
I used a similar script to submit a job to run each month.  What I do now is to
add 30 days to make sure the job will be run every month (the first job was run
in the middle of the month).  How can I make the job run on the second of each
month?

Followup:
use an interval of:

'add_months( trunc(sysdate,''mm''), 1 ) + 1'

by taking the current run time (sysdate), and truncating it to the beginning of
the month, adding one month (gets the first day of next month) and then adding a
day -- you'll get the second of next month.

September 11, 2001 -- Thanks for the question regarding "Runing Procedure", version 8
You Asked
Hi Tom,

I have write a procedure as follow:

CREATE or REPLACE  PROCEDURE drop_table (i_table_name IN VARCHAR2) AS
  cid INTEGER;
  tab_name user_tables.table_name%type;

  CURSOR table_list IS
  SELECT table_name
  FROM user_tables
  WHERE table_name LIKE i_table_name;

BEGIN

  OPEN table_list;
  loop
    fetch table_list into tab_name;
    exit when table_list%notfound;

    cid := DBMS_SQL.OPEN_CURSOR;
    DBMS_SQL.PARSE(cid, 'DROP TABLE ' || tab_name, dbms_sql.v7);
    DBMS_SQL.CLOSE_CURSOR(cid);
  end loop;

  EXCEPTION
    WHEN OTHERS THEN
    DBMS_SQL.CLOSE_CURSOR(cid);
    RAISE ;
END drop_table;

But When I run in VFP, using "Execute drop_table('AAA%')", it return error:
"Invalid SQL Statement", But when I use the same command in Oracle WorkSheet,
"Execute drop_table('AAA%')", it works!!

Can u tell me why?

Best Regards,
Susanna
and we said...
I don't know what VFP is but...

"Execute foo"

in sqlplus is simply shorthand for:

begin foo; end;

you can see this by putting in something in error:

ops$tkyte@ORA8I.WORLD> exec not_a_procedure
BEGIN not_a_procedure; END;

      *
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00201: identifier 'NOT_A_PROCEDURE' must be declared
ORA-06550: line 1, column 7

See the error -- "begin not_a_procedure; end; ...."

VFP, whatever it is, does not understand "exec", use "begin drop_table('AAA%');
end;" and see what happens.
September 12, 2001 Subrata -- Thanks for the question regarding "Pinning data buffers to memory", version 8.1.6
You Asked
1.I know how to attach (pin) SQL/ packages to memory. Is there any way to attach
(pin) the data buffers to memory? I know about the hint CACHE, but hints are
suggestions. Oracle might ignore it. How do I know (which V$ view ), data from
which tables are pinned in memory?

2. Can SQL loader upload files from client?

Thanks
and we said...
1) you cannot pin a buffer in memory.  You can use a KEEP pool to increase the
probability -- HOWEVER......  If a buffer is hot, if it needs to be in the cache
-- it WILL be in the cache (thats the way the cache works).   If it does not
NEED to be in the cache (eg: you "pinning" it would be wasting a resource) it
will NOT be in the cache.

The CACHE hint won't be ignored and it only applies to a full scan.  Normally in
a full scan, the blocks hit are aged out of the cache very very fast (in order
to avoid a full scan from blowing out the buffer cache -- a full scan might
otherwise  wipe out all of the other blocks.  The CACHE hint just changes the
treatment of these buffers and puts them in the buffer cache as if they were
read using single block IO (they are not aged out fast).  It does not really
"cache" the table, it simply makes it more likely that blocks that will be
frequently accessed will be found in the cache.

2) yes.  sqlldr can be used over the network.
September 12, 2001 Vikas -- Thanks for the question regarding "Checksumming Concept & query resolution", version 8.0.5
You Asked
Hello! Tom,

1.Can u please give me some details about the concept of checksumming & how
Oracle Works on to check the checksumming of the blocks?Please provide relevent
examples to clear the concept.

2.If I have a table with rows like

Standard value col1     col2     col3     col4

&             'AND'      '&'      '&&'                                &
   'AND'      '&'                                          &             'AND'
                                                10TH          'TENTH'    'X'
'10TH'
10TH          'TENTH'    'X'                                          10TH
   'TENTH'                                                 11TH
'ELEVENTH' 'XI'   '11'     '11TH'                       11TH          'ELEVENTH'
'XI'   '11'                                  11TH          'ELEVENTH' 'XI'

                       & I wish to retain the top most row for for each standard
value. How to write a SQL query to get the results.

3. I have a query which gets the max no. of records from a table depending upon
the country & state

Select Max(Cnt) from (Select State,Count(*) Cnt from ba$addresses where country
= 'US' group by state)

What I wish is to get the name of the state also having maximum no. of records

4. Concept of Locally Managed tablespaces.Is this feature introduced in Oracle
8i.Please explain with relevent examples so that it becomes easy to understand.

Regards,

Vikas Khanna
Vkhanna@quark.stpm.soft.net
and we said...
1) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1094433279412
2) your example is not readable -- you'll need to format it so I can read it.
what is a "standard value"

3) one way is:

  1  select to_number(substr(max_str,1,instr(max_str,'/')-1)) cnt,
substr(max_str,instr(max_str,'/')+1 ) job
  2  from ( select max( to_char(cnt,'fm00000000009') || '/' || job ) max_str
  3           from ( select count(*) cnt, job
  4                    from emp
  5                   group by job )
  6*     )
scott@ORA817DEV.US.ORACLE.COM> /

       CNT JOB
---------- ----------------------
         4 SALESMAN

(pretend emp = ba$addresses and job = state.

4) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:733126913855
September 12, 2001 roland -- Thanks for the question regarding "restrict connections by application", version 805
You Asked
Hi,

I'd like to get all these toad users off our databases and restrict connection
with toad or other applications to a verry small list of people.

Is there a way to call a procedure after logon? or is there some kind of trigger
after logon on database?

here's the code I've tested and it works.

The only thing now is to call it first thing after logon.

declare
    v_user varchar2(25);
    v_auth_user varchar2(25);
    cursor c_toaduser is select sid,serial#
       from v$session
          where program like '%TOAD%'
           and username =v_user;
    dyn_cur number;
begin
    select user into v_user from dual;
    select auth_user into v_auth_user from auth_user
         where upper(auth_user)=upper(v_user);
--dbms_output.put_line(v_user||' '||v_auth_user);
EXCEPTION
when no_data_found then
for i in  c_toaduser loop
    dyn_cur :=dbms_sql.open_cursor;
        dbms_sql.parse(dyn_cur, 'alter system kill session'||
               i.sid||','||i.serial#||',dbms_sql.native);
            dbms_sql.close_cursor(dyn_cur);

end loop;
end;

this is the table definition I used:

CREATE TABLE AUTH_USER (
  AUTH_USER  VARCHAR2 (25))
 TABLESPACE USERS
   PCTFREE 10   PCTUSED 40
   INITRANS 1   MAXTRANS 255
 STORAGE (
   INITIAL 1024K NEXT 1024K PCTINCREASE 1
   MINEXTENTS 1 MAXEXTENTS 500 )
   NOCACHE;

thanxx
and we said...
In Oracle8i -- yes, there is a logon trigger.

In Oracle8.0 -- no, there is not.  You could use dbms_job to schedule a
recurring job to be executed every "n minutes" to look for these toad users and
kill them -- although there is NOTHING stopping these toad users from copying
toad.exe to fooling_you.exe or even sqlplus.exe and getting by you anyway.

btw: in 8.0, using:

   execute immediate 'alter system kill session ' || ....

is easier then dbms_sql.
September 12, 2001 gaurang -- Thanks for the question regarding "GOTO statement", version 8.1.6
You Asked
hi tom,

i am using GOTO statement. is it ok or not?
somebody advice me not to use that.

i am using in this way

 open c1;

loop
  << fetch_next >>

  fetch c1 into r1;

  exit when  c1%notfound;

  --check some thing
  if not_found then
   goto fetch_next;
  end if;
  .
  .
  .
  some processing.

end loop;

  etc..

Thanks
and we said...
it is considered a bad programming practice.  I don't really have a firm opinion
on it.  I would prefer to code:

for r1 in c1
loop
    -- check something
    if found then
        some processing
    end if;
end loop

it seems more clear (use implicit cursors as well -- easier to code, no open, no
fetch, no "exit when notfound", no close, no need to declare r1....)
September 12, 2001 George -- Thanks for the question regarding "how to sort in SP", version 8.1.6
You Asked
Hi Tom,

I have 2 questions to ask your help:

1. I need to get my results from a SP in certain order, It worked if my code is
like below and pass in a order by string (like 'containernumber'), BUT get a
error "ORA-00936: missing expression" if I pass in nothing ( like ' ') for the
orderbystring (I have default value).

2. I also tried using bind varialbe like this:
     ORDER BY :str';
    OPEN sum_cv FOR sql_statement USING  orderbystring;
the Sp is working, but the results are not sorted by the orderbystring.

Thanks in advance

George

// part of my code

create or replace package  transport2 AS
    PRAGMA SERIALLY_REUSABLE;
    TYPE sumCur IS REF CURSOR;
    procedure  pendingDeliveries (
        condition IN VARCHAR2 default null,
        orderbystring IN VARCHAR2 default 'containernumber',
        sum_cv IN OUT NOCOPY sumCur);
END;

CREATE OR REPLACE PACKAGE BODY transport2  AS
    PRAGMA SERIALLY_REUSABLE;
procedure  pendingDeliveries (
    condition IN VARCHAR2 default null,
    orderbystring IN VARCHAR2 default 'containernumber',
    sum_cv IN OUT NOCOPY sumCur) AS
    query_statement VARCHAR2(300);
    from_statement VARCHAR2(300);
    sql_statement VARCHAR2(2000);
    where_statement VARCHAR2(600);
  BEGIN
    IF party_type = 'transportcompany' then
        query_statement := ' ';
        from_statement := ' ' ;
        where_statement :=' '||condition ;
    END IF;
    sql_statement :='SELECT f.facilityCode,
    containernumber ' ||query_statement ||
 'FROM facility f,
        ...
    facilitysegment s ' || from_statement ||
 'WHERE  c.currentcontainertripid= ct.containertripid
      AND s.iscomplete = 0 ' || where_statement ||'
       ORDER BY ' || orderbystring;
    OPEN sum_cv FOR sql_statement;

END pendingDeliveries;
END;
and we said...
just code:

   if ( ltrim(orderbystring) is NOT null )
   then
        sql_statement := sql_statement || ' order by ' || orderbystring;
   end if;

to put the order by on before the open.

You cannot "bind" the order by like that.  You need a different plan for "order
by a" then you need for "order by b" -- bind variables are used when the plan
would be the same.
September 12, 2001 Jeff -- Thanks for the question regarding "Persistant Value", version 8.1.6
You Asked
Hi Tom

I would like to create a 'user logon' trigger that will set a variable that will
be persistant for the duration of the session.  The value must then be
accessible to all PL/SQL procedures that are subsequently executed during the
session.

I thought I could just set a global package variable, but it does not seem to
persist for subsequent procedure calls.

I realize that I can just create a temporary table and store the value there,
but the whole purpose of the exercise is to have this value stored in memory
(for performance reasons).

What do you suggest?

Jeff
and we said...
application contexts.  Thats what they do.

create or replace context my_ctx using my_procedure;

create or replace procedure my_procedure( p_name in varchar2, p_value in
varchar2)
as
begin
   dbms_session.set_context( 'my_ctx', p_name, p_value );
end;

and then call my_procedure from the on-logon trigger.  Now you can use:

   sys_context( 'my_ctx', 'some_variable_name' )

will retrieve the value.

See
http://osi.oracle.com/~tkyte/article2/index.html
and search for:

application context sys_context

on my site for more details.
Review & Followup
Rating: 5
September 12, 2001
Reviewer: A reader

September 12, 2001 kishan -- Thanks for the question regarding "Calling SP with PLSQL Tables indexed by char(1) parameters ", version 8.1.6.1.0
You Asked
Hello,
We have a simple stored procedure that we can't get it to work with Java. We are
using Oracle 8.1.7 driver and oracle 8i db(8.1.6.1.0) on NT4, with JDK1.3. The
stored procedure only has one parameter, PLSQL table indexed by char.
An error occurs when on call_proc.execute() line.

This is an error that we get:
java.sql.SQLException: ORA-06550: line 1, column 16:
PLS-00418: array bind type must match PL/SQL table row type
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

This sounds like a bug with Oracle 8.1.7 driver, but maybe we are doing
something wrong. Please help!

Thanks in advance.

(1). Here is the code:

/* package */
create or replace package temppack
is
Type CHAR_TBL IS TABLE OF CHAR(1)
INDEX BY BINARY_INTEGER;

END TEMPPACK;
/* stand alone procedure */
create or replace procedure testchar(ab out temppack.char_tbl)
is
begin
for i in 1 ..10
loop
ab(i):=i;
end loop;
end;

/* Sample code */

import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.driver.*;

public class testchar {
public static void main(String[] args)
throws SQLException
{
try
{
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn=
DriverManager.getConnection("jdbc:oracle:oci8:test/test@testdev");
OracleCallableStatement call_proc =(OracleCallableStatement)
conn.prepareCall("begin testchar(?);end;");

int elemSqlType = Types.CHAR;
int maxLen = 10;
int elemaxLen = 1;

call_proc.registerIndexTableOutParameter(1,maxLen,elemSqlType,elemaxLen);
call_proc.execute();
// access the value using JDBC default mapping
int a=0;
String[] values = (String[])
call_proc.getPlsqlIndexTable (1);
// print the elements

for (int i=0; i<values.length; i++)
System.out.println (values[i]);
call_proc.close();
}

catch (SQLException e)
{
System.out.println(e.toString());
}

}
}
and we said...
refer to
http://technet.oracle.com/docs/products/oracle8i/doc_library/817_doc/java.817/a83724/indexby1.htm#1059014
only JDBC types of NUMERIC and VARCHAR are supported (types.Char is not).

Apparently, support for tables of CHAR are not supported, you'll need to use a
table of VARCHAR.  If you have existing code that cannot be changed, you'll have
to use a block like this:

....
conn.prepareCall(
  "declare "+
  " temp_data temppack.char_tbl; "+
  " type vcArray is table of varchar2(1) index by binary_integer; "+
  " temp_data2 vcArray; "+
  "begin "+
  " testchar(temp_data); "+
  " for i in 1..temp_data.count loop temp_data2(i) := temp_data(i); end loop; "+
  " ? := temp_data2; " +
  "end;" );

int elemSqlType = Types.VARCHAR;
int maxLen = 10;
int elemaxLen = 2;
.....

also -- change your plsql test routine to loop to 9, not 10 to avoid a string
overwrite...

(note: binding to plsql table types is new with 817 and up OCI jdbc only)
September 12, 2001 Jaromir -- Thanks for the question regarding "Join a view with UNION", version 8.1
You Asked
Hi Tom!

A very simple question on the topic of view with union and join.

We have a UNION ALL view with more branches to relatively large tables.

The question is: can I perform an equi join on this view and a simple table and
expect that it will be performed as nested loops with index range access on all
tables.

Of course all relevant tables do have index on the join key!

Simple something like that:

SELECT *
FROM
  (select * from t1
   UNION ALL
   select * from t2
  ) x,
  t3 y
WHERE x.a = y.a

all tables t1 to t3 have index on column a
the aim is to get an index range (and not full scan) on t1 and t2 (t3 is no
problem)

Thanks

J.Nemec
and we said...
Ultimately, the optimizer will make the decision but if you have statistics on
the table and it appears that T3 should drive the query -- yes, it will.  Here I
made t1 and t2 much larger then t3 and it does:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t1 ( a int, b char(2000) );
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t2 ( a int, b char(2000) );
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t3 ( a int, b char(2000) );
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index t1_idx on t1(a);
Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index t2_idx on t2(a);
Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index t3_idx on t3(a);
Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_stats.set_table_stats( user, 'T1',
numRows => 10000000, numBlks => 5000000 );

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_stats.set_table_stats( user, 'T2',
numRows => 10000000, numBlks => 5000000 );

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_stats.set_table_stats( user, 'T3',
numRows => 10000, numBlks => 5000 );

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace on explain
ops$tkyte@ORA817DEV.US.ORACLE.COM> SELECT *
  2  FROM
  3    (select * from t1
  4     UNION ALL
  5     select * from t2
  6    ) x,
  7    t3 y
  8  WHERE x.a = y.a
  9  /

no rows selected

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=20144 Card=2000000000
   1    0   NESTED LOOPS (Cost=20144 Card=2000000000 Bytes=2230000000000)
   2    1     TABLE ACCESS (FULL) OF 'T3' (Cost=144 Card=10000 Bytes=1000000)
   3    1     VIEW
   4    3       UNION-ALL (PARTITION)
   5    4         TABLE ACCESS (BY INDEX ROWID) OF 'T1' (Cost=2 Card=100000
   6    5           INDEX (RANGE SCAN) OF 'T1_IDX' (NON-UNIQUE) (Cost=1
   7    4         TABLE ACCESS (BY INDEX ROWID) OF 'T2' (Cost=2 Card=100000
   8    7           INDEX (RANGE SCAN) OF 'T2_IDX' (NON-UNIQUE) (Cost=1

ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace off
September 12, 2001 oracle -- Thanks for the question regarding "dbmssql, partition wise join, , parallel query", version 8.1.7
You Asked
1With the advent of execute immediete command, hasnt dbms_sql package become
obsolete.

What is the use of dbms_sql package, apart from execute  immediate?

2.What is the most appropriate place to use pragma serially_reusable?

3.I have a 5 million row table, and my query is doing a full table scan. How can
I use parallel query in this context. What all is needed to set up parallel
query.

show me how to use parallel query , and when to use it.

4.How are tables scanned simultaneously while doing parallel query.

5.Give me an example of partition wise join.

6.Can I use a partition wise join while creating a view.
and we said...
1) NO, definitely NOT.

(if you want the entire store with the comparisions, I have a full chapter on
this topic in my book).

In short -- what happens when you don't know the number of columns you'll be
selecting? (hint: Native dynamic sql won't work).

What happens when the number of bind variables is not known until run time?
(see above)
and there are other cases.  DBMS_SQL is alive and well and still very very much
needed (and can be faster then native dynamic sql in various cases as well)

2) you only use this when you have a package that need not maintain a state
across calls to the database.   If you have package global variables and rely on
them retaining their values from call to call in your session -- you cannot use
this.  If you want the package to effectively "reset" itself each time you call
it -- you can.

3) alter table t parallel 10;   or use a parallel hint /*+ PARALLEL( t 5 ) */ in
the query.

4) we look at the data dictionary, figure out where the table is on disk, break
out ROWID ranges and give these ranges out to the various query slaves -- each
gets a non-overlapping section of the table to process.

5) It is sort of like partition elimination during a join.  If I have two tables
with two partitions each and I'm joining t1.x = t2.x and X is the partition key
-- I can simply join partition 1 of t1 to partition 1 of t2 and partition 2 of
t1 to partition 2 of t2 instead of joining partition 1 to t1 to partitions 1 & 2
of t2 and so on.

see also
http://technet.oracle.com/doc/oracle8i_816/server.816/a76994/parpart.htm#98285
6) a partition-wise join is an OPTIMIZER thing -- at query time.  It will not
affect the creation of a view (which simply stored query text, doesn't RUN it).
A query against a view can use partition wise joins.
September 12, 2001 Lisa -- Thanks for the question regarding "Compare initial_extent 7.3.4 vs 8.1.6", version 8.1.6
You Asked
Thanks Tom for your reply on other issues. Here I have another one:

Why Initial_extent size differ in version 7.3.4 vs version 8.1.6?
The data was using export/import method.
DB_block_size was defined as 2k in version 734 and 8k in 816

In Oracle734 we defined tablespace like this (from dba_tablespaces view)
SQL>  select * from dba_tablespaces where tablespace_name = 'DM_DOW_DOCBASE';

TABLESPACE_NAME                INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS
------------------------------ -------------- ----------- -----------
MAX_EXTENTS PCT_INCREASE STATUS    CONTENTS
----------- ------------ --------- ---------
DM_DOW_DOCBASE                          10240       10240           1
        121           50 ONLINE    PERMANENT

then we analyze a table and here is the result from user_tables:
SQL> select initial_extent, next_extent, blocks from user_tables
where table_name = 'DM_SYSOBJECT_S';
INITIAL_EXTENT NEXT_EXTENT     BLOCKS
-------------- ----------- ----------
         10240    16570368      15354

in Oracle816 we defined tablespace use local managed with uniform size:
SQL>select * from dba_tablespaces where tablespace_name = 'DM_DOW_DOCBASE';

TABLESPACE_NAME                INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS
------------------------------ -------------- ----------- -----------
MAX_EXTENTS PCT_INCREASE MIN_EXTLEN STATUS    CONTENTS  LOGGING   EXTENT_MAN
----------- ------------ ---------- --------- --------- --------- ----------
ALLOCATIO PLU
--------- ---
DM_DOW_DOCBASE                          81920       81920           1
 2147483645            0      81920 ONLINE    PERMANENT LOGGING   LOCAL
UNIFORM   NO

Again we analyze the same table, here is the attribute for initial_extent etc :
SQL> select initial_extent, next_extent, blocks from user_tables
where table_name = 'DM_SYSOBJECT_S';

INITIAL_EXTENT NEXT_EXTENT     BLOCKS
-------------- ----------- ----------
      33177600       81920       3264

QUESTIONs:
1. Why Oracle816 initial_extent is so large, while oracle734 is remain 10240 ?
2. The blocks are reduced from 3264(in 816) from 15354 (in 734), does it mean
the
   new database is more effecient in loading data from disk to Buffer Cache?
3. How do I determine the initial_extent to be more space effecient?

Thanks
and we said...
1) in the export, did you use compress=y ?? (the default).  If so, export
rewrote your initial extent to be as big as the existing table.

2) your block size is 4times LARGER, it still takes the same number of bytes
however.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:329017235004
for a discussion of the effects of different blocksizes.

3) with locally managed table spaces -- the extents are all the same size
regardless.  The initial extent really only tells us HOW MANY extents to
actually get.  You made the extents to be 80k in size regardless.  the "true"
initial extent is 80k.
Review & Followup
Rating: 4
September 12, 2001
Reviewer: Andrew from Calgary, AB Canada
with regards to 3). Tom, does that really means that with localy managed
tablespaces, if we fetch next and initial from user_tables and we see that those
are different, and we also know that sizing for the tablespace is UNIFORM, we
then know that this can't be right (because UNIFORM means that initial=next for
every segment within this tablespace)... so we then know that one of those
parameters (initial or next) is incorrect... and the wrong one is initial.
Correct? (so this initial is sorta ORACLE bug?)

Followup:
It is not a bug, it is the expected behavior.

In a dictionary managed tablespace, INITIAL means "this is how big I want the
initial extent to be".

In a locally managed tablespace, INITIAL means "this is how much space I want
you to allocate upon table creation -- its my INITIAL allocation".

The attributes are retained "as is" in the event you take an export of the
object from a LMT (locally managed tblspace) and import it later into a DMT
(dictionary...)

September 13, 2001 Randy -- Thanks for the question regarding "Overhead of many freelists", version 8.1.6
You Asked
I've just taken over a shop where there is a third-party replication product in
place, and the FREELISTS parameter is set to 40 on the tables.  I know that the
product does use multiple processes to apply the transactions on each target
(it's master to master), but I cannot justify 40 FREELISTS per table.  I am
still trying determin whether that was recommended by the third party product
support.

So... what would be the overhead associated with a very high number of
freelists? (I thought 40 was a lot)  Is there a number that makes you say
"that's crazy" *or* "that should handle any situation"?  (similar to your
suggestions on the number of extents in a LM TS).  I'm assuming I would only
need a number equal to the number of sessions used by the product.

Thank you.
and we said...
Well, 40 sounds high but it might not be.

The most serious side effect of this is that the space utilization in the table
is not as good as it could be.  If you have 40 lists and each list has 100
blocks on it (for example) and one session needs 101 blocks for new inserts --
it will NOT use the 3,900 blocks available on the other lists when it uses its
100 blocks -- it'll allocate more space from above the HWM mark.  In short -- a
table with lots and lots of freelists won't reuse space as effectively as a
table with less.

HOWEVER, a table with lots of freelists will permit a very high degree of
concurrency during inserts/updates that need more space.  There will be much
less serialization during space allocation and the results can be dramatic.

Now, if the INDEXES on this table don't have as many freelists -- you have a
problem there (you only mention the table -- make sure the indexes have that as
well).

In Oracle8i release 2 (816) and up, you can dynamically alter the objects to
adjust the freelists.  If you really don't like the 40, you can descrease it
anytime you want (and increase it again later).

In short, you would want as many freelists as you have concurrent, active
sessions inserting into the table (eg: if you have at most 5 active sessions --
5 to 10 freelists would be sufficient)
Review & Followup
Rating: 5
Exactly what I was looking for September 12, 2001
Reviewer: Randy E. from Austin, TX
Thanks, Tom.  I know this stuff is often times discussed in the docs, but
nothing beats hands-on seasoned experience.  The space usage info. is
particularly helpful and the kind of thing I was look for in your answer.

Rating: 5
September 13, 2001
Reviewer: A reader
what do you mean by

".  If you have 40 lists and each list has 100
blocks on it (for example) "

my understanding is that 1 freelist = 1 block
if you have 40 freelist that means 40 block in freelist

can u clearify please

September 13, 2001 shreevidya -- Thanks for the question regarding "using snapshot for datawarehousing", version 8.1.7
You Asked
hi tom,
i am badly stuck with these snapshots.i want to create snapshot on a table and
my query goes this way

select CAMPAIGN_ID, TXN_DATE, CUSTOMER_ID, CUSTOMER_NO, sum(txn_count)
txn_count, sum(pur_amt) pur_amt, sum(award_point) award_point
from CARD_CAMP_DAY_TXN
group by CAMPAIGN_ID, TXN_DATE, CUSTOMER_ID, CUSTOMER_NO

the base table i.e CARD_CAMP_DAY_TXN is going to have 40,000 records a day.now i
want my snapshot to do fast refresh programatically and this snapshot will be
heavily used for reporting purposes.

though i create these snapshots it refreshes only when i specify refresh option
as "complete". it does not do for "fast" option please help me!!

i have specified following values in init ora

job_queue_processes = 4
job_queue_interval = 10
open_links = 4

thanks in advance

regards
shreevidya
and we said...
See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76994/mv.htm#42194
it has the requirements for supporting fast refreshes of a single table
aggregate.  Most importantly, you need to have COUNT(*) in your Materialized
view as well as count(txn_count), count(pur_amt) and so on.

There are requirements for your materialized view log as well that are
documented there.
September 13, 2001 Michael -- Thanks for the question regarding "Index and Indexes", version 8.1.6.0
You Asked
Hi Tom,

I would like to ask questions about indexes.

Suppose I have a table t1 which has columns a, b, c and d.
Columns a and b are the primary keys of t1, and hence a primary key index is
built on them automatically.
If I qurey a sql likes "select a, d from t1 where b = ??", will the primary key
index (a, b) be used in that case.

Also, I want to know that can an index on two or more columns(e.g. c, d) be used
in the sql statement that containts part of the index in the where condition
(e.g. "select a, b from t1 where c = ??")?  Or do I need to build another index
(i.e. on column c only) for that query?

Thanks for you help in advance
Michael
and we said...
for:

... If I qurey a sql likes "select a, d from t1 where b = ??", ....

the answer is probably not -- using a hint you might be able to force it to FULL
SCAN the index to find the rows in the table but under normal circumstances --
it would not use that index.

For the second query you have -- we will most definitely make use of that index
on (c,d) to answer queries against C by itself.
Review & Followup
Rating: 3
Why indexed columns in primary key cannot be used seperately? September 13, 2001
Reviewer: Michael from HK
Tom,

Why is it yes in the second query but not in the first query?

Is it not allowed to be used seperately in PK index?

Followup:
In the first query, the user wants to get columns A, D from T.  there is an
index on (a,b).  The query is:  select a,d from t where b = ?

In order to use the index in this case, we would have to inspect EVERY index
entry (the index is sorted by A, not by B -- b=5 could be ANYWHERE in the
index).  Additionally -- since you want columns A, D as the output -- everytime
we find an index entry where b=?, we would then have to do a table access by
rowid to get the value for D.

It is most likely that rather then full scan the index and do single block IO to
retrieve the row, we would opt to full scan the table instead.  It is most
LIKELY...  It depends on the size, shape, volume and distribution of data.

It has nothing to do with the fact that it is a PK index, it is just an index
where the columns are not in the optimal ordering to be used for a particular
query.

For the second query -- the data in the index is sorted by C so a predicate like
"c=?" can be used efficiently against that index using an index range scan.

Rating: 4
Scanning composite index without predicate on index prefix column September 13, 2001
Reviewer: Padders from UK
Tom,

I believe 9i has index skip scan algorithm for this situation and that it
performs excellently. Can you point out any detailed documentation on skip scan?

Followup:
See
http://download-west.oracle.com/otndoc/oracle9i/901_doc/server.901/a87503/optimops.htm#51553
it works well if and only if the leading edge of the index (a in the example
above) has very few discrete values and the optimizer understands that.  For
example and index on (GENDER,EMPNO) where gender has the values 'M', 'F' and
EMPNO is unique.  A query such as:

select * from t where empno = 5;

might consider (in 9i) using that index on t to satisfy the query in a "skip
scan" method -- meaning the query will be processed conceptually like this:

select * from t where GENDER='M' and empno = 5
UNION ALL
select * from t where GENDER='F' and empno = 5;

In order to demonstrate this, I used the following script:

rop table t;

create table t
as
select decode(mod(rownum,2), 0, 'M', 'F' ) gender, all_objects.*
  from all_objects
/
create index t_idx on t(gender,object_id)
/

analyze table t compute statistics
for table
for all indexes
for all indexed columns
/

alter session set sql_trace=true;
select * from t t1 where object_id = 55;
alter session set sql_trace=false;

drop table t;

create table t
as
select chr(mod(rownum,256)) gender, all_objects.*
  from all_objects
/
create index t_idx on t(gender,object_id)
/

analyze table t compute statistics
for table
for all indexes
for all indexed columns
/

alter session set sql_trace=true;
select * from t t2 where object_id = 55;
alter session set sql_trace=false;

When the optimizer understands there are a few "sub indexes" by gender (as in
the first case), it will use a skip scan:

select *
from
 t t1 where object_id = 55

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0          7          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.01          0          7          0           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 23

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS BY INDEX ROWID T
      1   INDEX SKIP SCAN (object id 19845)

In the second case, there were 256 "sub indexes" and the optimizer properly
adjusted its query plan:

select *
from
 t t2 where object_id = 55

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.04       0.03          1        266          9           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.05       0.04          1        266          9           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 23

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS FULL T

As you can see -- in this case -- the skip scan did lots less work...

Rating: 4
Thank You. June 14, 2003
Reviewer: Christo Kutrovsky from Ottawa, ON Canada
Great example. Thanks you for showing it to us.

September 13, 2001 glenn -- Thanks for the question regarding "DB/system overhead regarding intermedia text ", version 8.1.7.0
You Asked
Hi Tom - Mike Frost (USPS) says howdy - he is in Luxemborg now.
> As system DBAs, we are seeing more applications asking for Intermedia Text.
We have placed sundry users on on segregated DBs with the intermedia option, but
they haven't done enough for us to gauge what kind of resource overhead is
involved in this application.  The question arises whether to create the
seperate software tree, create the DB w/intermedia option + bundle all the IT
users there OR make IT part of our standard build and just assign these apps to
the appropriate existing DB.  What specifically is the resource overhead with IT
and what strategy do you prefer?  Thanks
and we said...
Standard build -- it is just an index, it should be used by many different types
of applications in many different cases.

It can actually REDUCE resources.  It can answer queries efficiently using an
index that otherwise could bring a system to its knees.

I don't have a single database that doesn't have it going.
September 13, 2001 ls -- Thanks for the question regarding "ref cursor", version 8.1.6
You Asked
Hi

I would like to know what is the perfomance between declaring 11 cursors and
declaring one cursor of ref coursor type then generate those 11 cursors
dynamically
and we said...
Depends -- it might be no overhead.   It might be alot.

Let's say you have a stored procedure that is going to execute one of 11
queries.  You call this stored procedure ONCE per program execution (or very
very few times).

Using the ref cursor will have little or no impact on performance.

Now, let's say you call this routine 1,000 times and each query is executed
about 100 times.  Now the ref cursor introduces a great deal of overhead.  The
reason is that PLSQL will cache static cursors -- it will not really close them.
 PLSQL cannot cache ref cursors (they are dynamic, they are "pointers", they
cannot be cached open).  That means you'll do about 1,000 parses with the ref
cursor -- with the static cursors you'll have 11.

This can be huge.  Consider:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table run_stats ( runid varchar2(15),
name varchar2(80), value int );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace view stats
  2  as select 'STAT...' || a.name name, b.value
  3        from v$statname a, v$mystat b
  4       where a.statistic# = b.statistic#
  5      union all
  6      select 'LATCH.' || name,  gets
  7        from v$latch;

View created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> column name format a40
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> drop table t1;

Table dropped.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t1 ( x int );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2      type rc is ref cursor;
  3      l_cursor rc;
  4      l_x     number;
  5      l_start number;
  6  begin
  7      insert into run_stats select 'before', stats.* from stats;
  8
  9      l_start := dbms_utility.get_time;
 10      for i in 1 .. 1000
 11      loop
 12          for x in ( select * from t1 )
 13          loop
 14              null;
 15          end loop;
 16      end loop;
 17      dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
 18
 19      insert into run_stats select 'after 1', stats.* from stats;
 20
 21      l_start := dbms_utility.get_time;
 22      for i in 1 .. 1000
 23      loop
 24          open l_cursor for select * from t1;
 25          loop
 26              fetch l_cursor into l_x;
 27              exit when l_cursor%notfound;
 28          end loop;
 29          close l_cursor;
 30      end loop;
 31      dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
 32
 33      insert into run_stats select 'after 2', stats.* from stats;
 34  end;
 35  /
17 hsecs
37 hsecs

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select a.name, b.value-a.value run1,
c.value-b.value run2,
  2         ( (c.value-b.value)-(b.value-a.value)) diff
  3    from run_stats a, run_stats b, run_stats c
  4   where a.name = b.name
  5     and b.name = c.name
  6     and a.runid = 'before'
  7     and b.runid = 'after 1'
  8     and c.runid = 'after 2'
  9     and (c.value-a.value) > 0
 10     and (c.value-b.value) <> (b.value-a.value)
 11     and abs((c.value-b.value) - (b.value-a.value)) > 50
 12   order by abs( (c.value-b.value)-(b.value-a.value))
 13  /

NAME                                           RUN1       RUN2       DIFF
---------------------------------------- ---------- ---------- ----------
STAT...redo size                              23968      24060         92
STAT...opened cursors cumulative                 15       1014        999
STAT...parse count (total)                       15       1014        999
STAT...recursive calls                         1132       4131       2999
LATCH.library cache                            2434       8402       5968

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

Not only is it slower (due to the extra work) but look at the stats -- the ref
cursor does alot more work.  The LATCHES on the library cache are the *worst* --
they are what will limit scalability.

Now, we can "fix" much of this using session_cached_cursors -- it will help
avoid much of the overhead by adding a cursor cache for each session.  Running
the above test with session_cached_cursors = 100, we get:

NAME                                           RUN1       RUN2       DIFF
---------------------------------------- ---------- ---------- ----------
STAT...redo size                              23948      24044         96
STAT...opened cursors cumulative                 15       1014        999
STAT...parse count (total)                       15       1014        999
STAT...session cursor cache hits                  4       1003        999
STAT...recursive calls                         1132       4131       2999

which is better -- but it still does more work.
Review & Followup
Rating: 5
fantastic! September 14, 2001
Reviewer: A reader
Unbelievable example - I wish people were so crisp in there explanations.

Sudhir

September 13, 2001 Logo -- Thanks for the question regarding "How to change the value in GLOBAL_NAME table ", version 8.1.6
You Asked
Hi Tom,

SQL*Plus: Release 8.1.6.0.0 - Production on Thu Sep 13 17:08:36 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to:
Oracle8i Enterprise Edition Release 8.1.6.1.0 - Production
With the Partitioning option
JServer Release 8.1.6.1.0 - Production

SQL> select * from global_name;

GLOBAL_NAME
--------------------------------------------------------------------------------
INST816.US.ORACLE.COM

SQL> show parameter global

NAME                                 TYPE    VALUE
------------------------------------ ------- ------------------------------
global_names                         boolean FALSE
SQL> show parameter instance_name

NAME                                 TYPE    VALUE
------------------------------------ ------- ------------------------------
instance_name                        string  DVLP
SQL> show parameter db_name

NAME                                 TYPE    VALUE
------------------------------------ ------- ------------------------------
db_name                              string  DVLP
SQL>

Will it cause any problems if I set the GLOBAL_NAME as follows

update global_name
set global_name = 'DVLP.US.MYCOMPANYNAME.COM';

Do I need to change anything else?

Thanks in advance.
and we said...
Umm, you don't UPDATE a global_name like that.  You NEVER update any data
dictionary table -- never.

alter database rename global_name to dvlp.us.mycompanyname.com;

will work.  It will only affect OTHER databases that have database links to you
that do use GLOBAL_NAMES=TRUE.  their database link names that point to you will
have to change to accommidate this change.
Review & Followup
Rating: 5
GLOBAL_NAMES and SNAPSHOT_SITE September 13, 2001
Reviewer: Nelson from Santa Clara, CA USA
Thanks for your help.

Like you said, I did
alter database rename global_name to dvlp.us.mycompanyname.com;

SQL> select * from global_name;

GLOBAL_NAME
--------------------------------------------------------------------------------
DVLP.US.MYCOMPANYNAME.COM

SQL> SELECT NAME, SNAPSHOT_SITE from DBA_REGISTERED_SNAPSHOTS

NAME                           SNAPSHOT_SITE
------------------------------ ------------------------------
MSC_BIS_INV_DATE_MV            INST816.US.ORACLE.COM
MSC_BIS_RES_MV                 INST816.US.ORACLE.COM
MSC_BIS_RES_DATE_MV            INST816.US.ORACLE.COM
MSC_ATP_PLAN_SN                INST816.US.ORACLE.COM
MRP_SCHD_DATES_SN              INST816.US.ORACLE.COM
MTL_DEMAND_SN                  INST816.US.ORACLE.COM
BOM_RES_CHNGS_SN               INST816.US.ORACLE.COM
WIP_DSCR_JOBS_SN               INST816.US.ORACLE.COM
BOM_BOMS_SN                    INST816.US.ORACLE.COM
WIP_FLOW_SCHDS_SN              INST816.US.ORACLE.COM
MTL_SUPPLY_SN                  INST816.US.ORACLE.COM

Now, if I want the snapshot_site to be the same as the global_name, how do I do
that? The snapshots are internal (i.e. within the same database). Will it work
if I leave the snapshots as is? Or Do I pretty much have to drop and recreate
them?

Followup:
geez, thats the sort of info you should provide with the original question.

You are treating yourself as is you were a "remote database".  The snapshot site
(replication uses GLOBAL_NAMES=TRUE) is the global name

Put your global name BACK (rename it back) and rethink your need to rename those
global name changes.

You should use simple materialized views without database links when replicating
to "yourself".

September 13, 2001 Lilian -- Thanks for the question regarding "estimate space", version 8.1.6
You Asked
Hi Tom:

there is table called personlead, column personid is primary key, now i need to
add personid as foreign key that reference from master table person of our
application. there are over 350,000 records in table personlead, my question is:

1. can I estimate space that will be used before i add this foreign key?
2. which tablespace i should consern, data or index tablespace?

Thanks as always,
an
and we said...
a foreign key takes NO space.  It is a constraint, it creates no indexes, does
not use storage.

See
http://osi.oracle.com/~tkyte/unindex/index.html
for why you might want to INDEX the fkey after the fact however...
Review & Followup
Rating: 3
An September 14, 2001
Reviewer: A reader from Wilmington, DE
it clears my mind, thanks.

September 14, 2001 Dusan -- Thanks for the question regarding "Disabling PK constraint - how to preserve index definition", version 8.1.6
You Asked
Hi Tom,

Today I had to do nasty and unusual operation - I disabled PK. After enabling I
was surprised - associated index was created with default storage parameters, in
user's default tablespace - not as before (it was LOCAL index, in LMT
tablespace). Looking in documentation, the index assoc. with PK is dropped when
disabling of PK constraint - OK, but ....
Is it possible to disable/enable PK, UK with the previous index storage
definition?

Thanks,

Dusan
and we said...
When you enable the constraint, you may use the USING INDEX clause:

alter table t enable constraint t_pk using index tablespace some_tablespace;
Review & Followup
Rating: 2
That's what I did but ... September 13, 2001
Reviewer: Dusan from Lexington, MA USA
I had to find out somehow, somewhere, manually all details when enabling the
constraint.Find out the tablespace name where the index was stored, that the
index was local, and all other details.
It would be really nice if there was an option to disable PK, UK constraint
without dropping the index with all his storage definition.

Followup:
If you use deferrable constraints, you can keep the index in place.  With a
deferrable primary key constraint, we use a non-unique index which will not be
droppped. For example:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x int,
  2                                   constraint t_pk primary key(x) )
  3  /
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select index_name from user_indexes where
table_name = 'T';

INDEX_NAME
------------------------------
T_PK

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table t disable constraint t_pk;
Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select index_name from user_indexes where
table_name = 'T';

no rows selected

So, there the index was dropped.  Now we redo the create with a deferrable
constraint:

ops$tkyte@ORA817DEV.US.ORACLE.COM> drop table t;
Table dropped.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x int,
  2                                   constraint t_pk primary key(x) deferrable
initially immediate)
  3  /

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select index_name from user_indexes where
table_name = 'T';

INDEX_NAME
------------------------------
T_PK

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table t disable constraint t_pk;
Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select index_name from user_indexes where
table_name = 'T';

INDEX_NAME
------------------------------
T_PK

and the index remains.

Rating: 5
Excelent September 14, 2001
Reviewer: Dusan from Lexington, MA USA
Nevertheless - one more question:
Is it possible to modify PK's, UK's from not deferrable (by default) to
deferrable? I guess that it is not so trivial, due to different nature of
related indexes.

Followup:
You cannot alter a constraint to be deferrable (its a big change).  You have to
rebuild the constraint (drop/add).

September 14, 2001 Bhagat -- Thanks for the question regarding "insert and update in a single shot", version oracle 8.1.6
You Asked
Hello Tom,

How are you, Tom is there a way that if we do insert in the table and if this
insert fails "say duplicate key" it should automatically update all of the
values in the row, or other way if we update the table with some primary key and
if no data found it should automatically do the insert ?
waiting for response.

Regards
Bhagat Singh
and we said...
In Oracle9i there is a new merge command:
http://download-west.oracle.com/otndoc/oracle9i/901_doc/server.901/a90125/statements_916.htm#2080942
that does just this.

In 8i and before, you have to do it procedurally.  If you are using sqlldr, one
way you can do this that I've outlined in more detail with examples in my book
is to:

o load the data with errors=999999999999999999.  the "dups" will goto the bad
file

o create a temporary table with all of the same constraints as the "real" table
you are loading into
o load the bad file into this temporary table.  any records that go into the bad
file now are really "bad" records - they violate some constraint.

o update the "real" table with this temporary table data
September 14, 2001 Viji -- Thanks for the question regarding "Query the database....", version 7,8
You Asked
Hi,

I would like to ask a question regarding the Query of the system tables in
Oracle.

* I have a table with a Primary key & another table with a  Foreign key.
How do i know what is the Primary key field for my Foreign key field ? what is
the table I need to Query on ?

Next,
* Can a person using "Noaudit all" stop all the auditing being done by the
Admin, if he has the privilege to stop the Audit ?

Thanks,

Viji
and we said...
User_constraints and User_cons_columns

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table p ( x int primary key );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table c ( a int primary key, y
references p );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select a.constraint_name, decode(
a.constraint_type, 'P', 'Primary', 'R', 'Foreign' ), b.column_name
  2    from user_constraints a, user_cons_columns b
  3   where a.table_name in ( 'P', 'C' )
  4     and a.constraint_type in ( 'P', 'R' )
  5     and a.constraint_name = b.constraint_name
  6  order by a.constraint_name, b.position
  7  /

CONSTRAINT_NAME                DECODE( COLUM
------------------------------ ------- -----
SYS_C00918                     Primary X
SYS_C00919                     Primary A
SYS_C00920                     Foreign Y

for example.

Yes, a successful NOAUDIT can reverse the effects of an audit command.
Specifically

<quote sql reference manaul>
The NOAUDIT statement must have the same syntax as the previous AUDIT
statement. Further, it reverses the effects only of that particular statement.
Therefore, if one AUDIT statement (statement A) enables auditing for a specific
user,
and a second (statement B) enables auditing for all users, then a NOAUDIT
statement
to disable auditing for all users (statement C) reverses statement B, but leaves
statement A in effect and continues to audit the user that statement A
specified. For
information on auditing specific SQL statements, see the "AUDIT sql_statements"
on page 7-213.

</quote>
Review & Followup
Rating: 2
A little more clarification ! September 14, 2001
Reviewer: Viji from Bangalore
Hi,

Thanks for the response.
But, I still am unclear.

Refering to the Point 1, and as per ur answer, I HAVE TO KNOW THE TABLE WHICH
REFERENCES THE FOREIGN KEY. WITHOUT KNOWING THE TABLE NAME, I CANNOT RUN UR
QUERY. Consider a situation where in I do not know the table names, i.e I only
know the table name of my Foreign Key, but not the table name of the primary key
which references it.

So, my question still remains - If I do not know the table name of the Primary
key,(I have to & I know the table name of the Foreign key) but if I need to find
the Primary key that my Foreign key references, How do i do that ?

Hope this is not confusing. The question concept is simple. Knowing only the
table name of the Foreign key, how do i find out the NAME OF THE TABLE in which
my primary key lies.

Thanks.

Followup:
you should get the Server Reference, all of these views are documented there.
Once you know of the existence of the views, a good understanding of whats in
them will allow you to come up with these queries yourself
http://technet.oracle.com/doc/oracle8i_816/server.816/a76961/toc.htm
ops$tkyte@ORA817DEV.US.ORACLE.COM> select a.constraint_name, a.table_name,
  2         b.constraint_name, b.table_name
  3    from user_constraints a, user_constraints b
  4   where a.constraint_type = 'R'
  5     and a.r_constraint_name = b.constraint_name
  6  /

CONSTRAINT_NAME                TABLE_NAME                     CONSTRAINT_NAME
            TABLE_NAME
------------------------------ ------------------------------
------------------------------ ------------------------------
SYS_C00920                     C                              SYS_C00918
            P

Rating: 3
Use r_constraint_name column September 14, 2001
Reviewer: A reader
You can also use the r_constraint_name column of user_constraints view which
contains the primary key that the foreign key relates to. Then you can select on
table_name for the value you get in r_constraint_name by
using it in the constraint_name. For example:

select constraint_name, r_constraint_name
from user_constraints
where constraint_type = 'R'
and table_name = 'KNOWN_TABLE';

select table_name
from user_constraints
where constraint_name = '[r_constraint_name from above]';

Followup:
ummm -- check out the query right above your comment.  It does exactly what you
describe - only it does it in one query via a join.

September 14, 2001 Lisa -- Thanks for the question regarding "Rollback segments", version 8.1.6
You Asked
1.Is there any way we can dynamically re-size the small rollback
  segments ?
2.Is there is a quideline as to how many WRAPPING is bad, ie 5 or 10
   or more ?
3. After a new database is created, which method (or define in both)
   to use in init parameter -
   a. use rollback_segments = (rb1,rb2.....) or
   b. use transcation/transaction_per_rollback_segment

Thanks for your expertise.
and we said...
1) you can allocate more extents (or shrink them).  But otherwise you would
offline them, drop them and recreate them if you want to enlarge the size of the
extents.

2) well, its a function of how long your database is up.  I'd be more worried if
they didn't wrap -- that would indicate they are way too large!

It is not how OFTEN they wrap but how frequently and if you have hit the
ORA-01555 error.  If you do not hit this error and are happy with the size of
your RBS's -- they are fine

3) if you create public rollback segments you do not need to do a) otherwise you
do need to do a) just to bring them online at database startup.

you need not set either of b) in general.
Review & Followup
Rating: 5
max September 14, 2001
Reviewer: A reader
What is the max number of rollback segments can we have?
and
Can you give us the link to the document , which has all the database object
limits documented.

Followup:
from the Oracle Reference Manual:

Rollback Segments

Maximum number per database No limit; limited within a session by the
MAX_ROLLBACK_SEGMENTS initialization parameter

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76961/ch4.htm#4762
for other limits.

Rating: 3
Public and Private September 14, 2001
Reviewer: A reader
The Oracle Server manual mentions "If a database does not have the Parallel
Server option, public and private rollback segments are identical".

Hence it should not make any difference, whether its public or private if its
not OPS. So there is no need to specify them in the init.ora for single instance
dbs. Is that correct?

Followup:
A public rbs is onlined without having to mention it in the init.ora:

SVRMGR> connect internal
Connected.

SVRMGR> show parameter rollback_segments;
NAME                                TYPE    VALUE
----------------------------------- ------- ------------------------------
max_rollback_segments               integer 50
rollback_segments                   string  rbs_01, rbs_02, rbs_03, rbs_04

SVRMGR> create PUBLIC rollback segment PUBLIC_RBS tablespace users;
Statement processed.
SVRMGR> alter rollback segment PUBLIC_RBS online;
Statement processed.

SVRMGR> create rollback segment NOT_PUBLIC_RBS tablespace users;
Statement processed.
SVRMGR> alter rollback segment NOT_PUBLIC_RBS online;
Statement processed.

SVRMGR> select segment_name, status from dba_rollback_segs;
SEGMENT_NAME                   STATUS
------------------------------ ----------------
SYSTEM                         ONLINE
R00                            OFFLINE
RBS_01                         ONLINE
RBS_02                         ONLINE
RBS_03                         ONLINE
RBS_05                         ONLINE
RBS_04                         ONLINE
PUBLIC_RBS                     ONLINE
NOT_PUBLIC_RBS                 ONLINE
9 rows selected.

SVRMGR> shutdown
Database closed.
Database dismounted.
ORACLE instance shut down.

SVRMGR> startup
ORACLE instance started.
Total System Global Area                        238829728 bytes
Fixed Size                                          73888 bytes
Variable Size                                   142336000 bytes
Database Buffers                                 90112000 bytes
Redo Buffers                                      6307840 bytes
Database mounted.
Database opened.

SVRMGR> select segment_name, status from dba_rollback_segs;
SEGMENT_NAME                   STATUS
------------------------------ ----------------
SYSTEM                         ONLINE
R00                            OFFLINE
RBS_01                         ONLINE
RBS_02                         ONLINE
RBS_03                         ONLINE
RBS_05                         ONLINE
RBS_04                         ONLINE
PUBLIC_RBS                     ONLINE
NOT_PUBLIC_RBS                 OFFLINE
9 rows selected.

SVRMGR> show parameter rollback_segments
NAME                                TYPE    VALUE
----------------------------------- ------- ------------------------------
max_rollback_segments               integer 50
rollback_segments                   string  rbs_01, rbs_02, rbs_03, rbs_04

Notice how PUBLIC_RBS is onlined upon restart but the non-public ones are not.
In order to ONLINE the not_public_rbs we would have to add it to the init.ora or
do it manually.

Rating: 5
Cool; 2nd part also answers question about init<sid>.ora September 15, 2001
Reviewer: Harrison Picot from Haymarket, VA USA "Rome without the glitter"
Thanks Tom, I was going to ask a question about how commented out rbs in the
init file got started but (I think) you have answered that.  And maybe also why
the old initsid0.ora file is now gone.  Incidently our firm has started to give
your book to customers.  The more I read it, the more I am concerned that I may
one day hear: "Is it true that you gave "Expert one-on-one Oracle" to a customer
and didn't think it was a bribe?". So far, my answer is "It depends on how you
define the word 'bribe'" (actually, we started giving the books because loaned
books never came back anyway).

September 14, 2001 Denny -- Thanks for the question regarding "update top rows randomly", version 8.1.6
You Asked
Tom,

Let say I have 10 rows met my where condition. Now I just want to update the
first 3 rows. I understand I can use the rownum with building an index with the
columns in where clause. But it looks like the same 3 rows are updated every
time. Is it possible to do the update randomly among the 10 rows?

Thanks,
Denny
and we said...
Well, its a strange request but.... where I have "select empno from emp" you
will put your query (select out the primary key)...

scott@ORA817DEV.US.ORACLE.COM> update emp
  2     set ename = lower(ename)
  3    where empno in ( select empno
  4                       from (select empno
                                  from emp
                                 order by dbms_random.random )
  5                      where rownum <= 3 )
  6  /

3 rows updated.
September 14, 2001 Richard -- Thanks for the question regarding "Java basics....", version 8.1.6.2
You Asked
I have worked with PL/SQL and have done DBA work for quite some time now, and it
is becoming more and more evident that I need to expand my skills into the Java
world.  I would like to ask you if you could show us non-java folks some java
basics (specifically, using java stored procedures etc.).  I realize that this
can open up a huge can of worms, but if you could show us non-java folks (that
need to support an Oracle Database with Java stored procedures) a thing or two
to get started with, it would be appreciated.

Thanks and Best regards....Richard
and we said...
search for

create or replace java source named

on my site for some examples.  Additionally, I have a chapter on this in my
book.  Lastly:
http://technet.oracle.com/doc/oracle8i_816/java.816/index.htm
has the java stored procedure developers guide.
September 14, 2001 Van -- Thanks for the question regarding "What is the function used on a function-based index?", version 8i
You Asked
If I know someone has created an index that is function-based, what view can I
query to see what they used?
and we said...
ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( ename varchar2(25) );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index t_idx on t(upper(ename) );

Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec print_table( 'select * from
user_ind_expressions' );
INDEX_NAME                    : T_IDX
TABLE_NAME                    : T
COLUMN_EXPRESSION             : UPPER("ENAME")
COLUMN_POSITION               : 1
-----------------

PL/SQL procedure successfully completed.
Review & Followup
Rating: 5
Just what I needed to know - as always, thanks. September 17, 2001
Reviewer: A reader from Groton, CT

Rating: 5
Top Notch ! September 13, 2002
Reviewer: Mick Rice from Shannon, Ireland.
Hadn't been able to track this little nugget anywhere else....well done and
thanks !

September 15, 2001 Srinivas -- Thanks for the question regarding "Order of NULL/NOT NULL columns while creating table/Usage of Mixed case letters in procedures", version Forms 4.5/6i, Database 7.x/8.x
You Asked
1. Does ordering of columns, NOT NULL columns first and then null columns, have
any significance? If so, what are the advantages/disadvantages?

2. Does writing procedures single case, say all in capital letters or small
letters compared to mixed case, have any effect on performance (in forms and
stored procedures)?
and we said...
1) it can.  In Oracle, if the last column is NULL -- it consumes no space (else
it consumes 1 byte).  If the last two are NULL, they take no space, if the last
N are NULL they take no space.

Trailing NULL columns in a table can take ZERO bytes when NULL.  For this
reason, you would put the columns most likely to be null at the "end" of the
create table.

2) No, not at all.
September 15, 2001 Waseem -- Thanks for the question regarding "form_ddl is not working", version 2.0
You Asked
sir
i am making a form with two text iten + connect button.in the text items user
will enter login id and passward and when will press the connect button .forms
should connect to the specified user.
for doing tit i am using Form_ddl function which is not working.
regards
waseem
and we said...
form_dll is used to execute SQL like "create", "alter", "insert", "update",
"delete" and so on.

Connect is not sql at all.  forms_dll isn't for connecting.

See the LOGON builtin function.
September 16, 2001 -- Thanks for the question regarding "how to do it without ON DELETE CASCADE? ", version 8.1.6
You Asked
Tom:

create table dept( deptno int primary key);
create table emp(empno int primary key, deptno int references dept);
insert into dept values (10);
insert into dept values (20);
insert into emp values (100,10);
insert into emp values (101,10);
insert into emp values (102,20);
insert into emp values (103,20);

the requirement is write a script to remove a dept and all emp
belong to that dept.

the way i do it is
delete from emp where deptno=10;
delete from dept where deptno=10;
commit;

the problem is:
right after i delete from emp where deptno=10
somebody else may insert into emp values (104,10); and commit it;
so when i delete from dept where deptno=10;
it gives me error that child record found.

NO ON DELETE CASCADE is allowed in this case.
and we said...
use a deferrable foriegn key constraint on EMP.

set constraints all deferred;
delete from dept where deptno = 10;
delete from emp where deptno = 10;
commit;
Review & Followup
Rating: 4
Pls explain more September 15, 2001
Reviewer: Harish from India
Hi Tom,
  Can u tell  what does the statement "set constraints all deferred " do ?

Followup:
It makes it so that any constraint that is deferrable (to be checked at COMMIT,
not at the statement level) is in fact deferred.  For example to complete the
above answer:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table emp(empno int primary key,
deptno int references dept DEFERRABLE);

Table created.

....
ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from dept where deptno = 10;
delete from dept where deptno = 10
*
ERROR at line 1:
ORA-02292: integrity constraint (OPS$TKYTE.SYS_C00958) violated - child record
found

that won't work until we defer the constraints

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> set constraints all deferred;

Constraint set.

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from dept where deptno = 10;

1 row deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from emp where deptno = 10;

2 rows deleted.

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

Commit complete.

Rating: 4
Constaints September 16, 2001
Reviewer: A Reader from USA
Tom,

Once the TX is committed, the constrains become "immediate"
checking right. The rows that are in DEPT which have
corresponding rows in EMP , = will they be rolled back

Thanks.

Followup:
Once you commit -- the constraint state is back to the default (if they were
initially immediate -- they will be immediate again)

The rows that violate the constraint upon commit will not be rolled back unless
YOU roll them back.

September 16, 2001 -- Thanks for the question regarding "where are temporary LOB stored", version 8i
You Asked
In oracle 8i where are temporary LOB stored?

In user temporary tablespace?
In user default tablespace?
system tablespace?
in any other table space if does please specify
and we said...
They are stored in the temporary tablespace.
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76940/adl10tm3.htm#74192
...
September 16, 2001 mike -- Thanks for the question regarding "efficiency of HASH join", version 8.0
You Asked
Tom,
http://asktom.oracle.com/pls/ask/f?p=4950:8:126200::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:449420120409,%7Bhash%7D%20and%20%7Bjoin%7D
From your example,
You made sure TEMP is 'ready' for hugh sorting;
first query, we did not observe the effective/good of the HASH;
We did see the efficiency improved on the second one, which was very similar of
the first.

However, in the real world we do not have the luxury for the second one. How
could we make of it the first time?
Thanks
and we said...
Use TRUE temporary tablespaces (as the example was all about showing) - there
the overhead of physically allocating the space is gone once allocated.

This is just like using shared sql -- the first guy who parses a query will pay
the price of the hard parse.  The next guy won't.

In the real world, your temporary tablespace is a true temporary tablespace and
in 8i will be a LOCALLY MANAGED one as well (faster space allocation).  In the
real world - the space will be already allocated after the database is "warm".
The overhead is gone once the database is up and running. ( I was trying to
point out why you DON'T want to use a permanent tablespace for a temporary
tablespace ).


Subject | Article | Last Updated (East coast time)
Tom, kindly publish this thread , for condemning the terrorist attack | article only | Sep 17, 2001 07:50 am
Locking | article only | Sep 17, 2001 07:55 am
What is the recommend pct increase size of an OLTP application? | article only | Sep 17, 2001 10:38 am
User Auditing | article only | Sep 17, 2001 12:42 pm
Julian Date | article only | Sep 17, 2001 08:17 pm
decode() question | article only | Sep 17, 2001 08:19 pm
Usage of composite index during query | article only | Sep 17, 2001 08:27 pm
Next or previous valid date | article only | Sep 18, 2001 09:00 am
last business day | article only | Sep 18, 2001 09:05 am
Code size in a trigger | article only | Sep 18, 2001 09:20 am
How can I prevent certain clients to access database? | article only | Sep 18, 2001 11:19 am
What is 64 bit and 32 Bit. | article only | Sep 18, 2001 04:28 pm
Ora -10027 | article only | Sep 18, 2001 06:10 pm
Unrecoverable option in SQL Loader | article only | Sep 19, 2001 07:27 am
sqlplus, delete vs truncate, roles-roles-privileges | article only | Sep 19, 2001 07:46 am
Checking Datatypes in PL/SQL | article only | Sep 19, 2001 05:28 pm
Parallel Queries in Oracle 7.3.4 | article only | Sep 20, 2001 06:51 am
Native dynamic sql - Refcursor | article only | Sep 21, 2001 11:13 am
How to apply static SQL to temporary table in stored procedures ? - | article only | Sep 21, 2001 11:20 am
32 bit or 64 bit | article only | Sep 21, 2001 12:22 pm
v$sqlarea question | article only | Sep 21, 2001 02:01 pm
Easy way to find out the free space below High Water Mark for LOB segments | article only | Sep 21, 2001 02:04 pm
Performance of a Time Dimension View in DataWareHouses | article only | Sep 22, 2001 02:46 pm
Parallel Execution Option | article only | Sep 22, 2001 03:04 pm
DB Parameters | article only | Sep 22, 2001 03:08 pm
Transaction Volumes | article only | Sep 22, 2001 03:51 pm
Average functions without high and low values | article only | Sep 23, 2001 09:21 am
Using aggregates anywhere but first.. seems to be a problem.. | article only | Sep 23, 2001 09:56 am
dbms_random | article only | Sep 23, 2001 10:29 am
Outer Joins | article only | Sep 23, 2001 10:35 am
utl_file | article only | Sep 23, 2001 02:17 pm
row(s) 1 - 31 of 31
September 17, 2001 nag -- Thanks for the question regarding "Tom, kindly publish this thread , for condemning the terrorist attack", version 8.1.7
You Asked
Tom

I express my strongly hurt feelings, for what had happened today.
Let us pray for peace and progress, and hope those people who had done this,
will be punished.

Nag
and we said...
Review
      & Followup

      Rating: 5
A Cowardly
      Act  September 12, 2001
Reviewer:  Jameel

Terrorists cant win. They are in a minority. They need to understand that.

      Rating: 5
I
      agree.  September 12, 2001
Reviewer:  Reader,
      from Brazil

      Rating: 5
I totally
      agree  September 12, 2001
Reviewer:
      A reader
Tom , your observation's .......

          Followup:

still in a state of somewhat disbelief -- wanting to get home but unfortunately
I'm on the wrong side of the country right now and no chance of getting a flight
in the near term...

My heart and sympathy goes out to the people who lost someone yesterday.

      Rating: 5
I totally
      agree, let's pray for the victims. God bless us, God bless
      America  September 12, 2001
Reviewer:  Alan
       from USA

      Rating: 5
How are doing,
      and are you o.k.  September 14, 2001
Reviewer:
      Nag
Tom

Where are you now, and how are you doing.
I hope and wish , that you are comfortable whereever you are.

Kindly keep this thread on the first page, for a few days.
Let our feloow , asktom.com fans, express there feelings.
Kindly consider my request.

Nag

          Followup:

Still just trying to get home...

      Rating: 5
United We
      Stand  September 14, 2001
Reviewer:  American

I received this e-mail. I wanted to share it with others. It seemed like a good
thing to do.:

 Friday Night at 7:00 p.m. step out your  door, stop your car, or
step out of your establishment and light a candle.

We will show the world that  Americans are strong and united  together against
terrorism.

Please pass this to everyone on your e-mail  list.  We need to reach everyone
across the United States
quickly.

  The message: WE STAND UNITED - WE WILL NOT TOLERATE  TERRORISM!

Thank you.

      Rating: 5
Portugal are
      with America  September 15, 2001
Reviewer:  Rui
      Brito  from Portugal
Let´s do a DROP TERRORISM ...
I hope that all countrys are unified in this cause.

      Rating: 5
Tom, have you
      reached home  September 17, 2001
Reviewer:
      Thx  from USA
Hey

Let us all know that you are doing good.
Home must have felt sweeter, when you reached home, this time, right ?

Thx

          Followup:

Yes, I finally made it home on Saturday -- from a one day trip that turned into
a 5 day one...  It was good to get home, yes.

      Rating: 5
Lets Rename The
      Sun.  September 17, 2001
Reviewer:  Jim Oz
       from Australia
I've been trying to think of the best way to remember those
who died on 11/9/2001, a fitting memorial.

It needs to be something that the world can see
,last forever more and be untouchable by the vermin of the world.

For me I now call the Sun, September 11 ..
when I wake in the mornings and see the sun I remember those
who are now gone, may their memories warm the hearts of those left behind. Even
though the night brings darkness
the sun rays reflect on the moon, so even though
loved ones are not in our sight they are still guiding us.
The sun will shine on for a looooooong time yet.

If you like the idea then tell your friends.
If you know if we can get the sun renamed officially
then lets get a petition or something started.

      Rating: 5
Tom, keep this
      thread on the first page.  September 17, 2001

Reviewer:  Wells  from USA
Please dont let it go away. Let the asktom.com community express there support
for USA, from world over.

God Bless America.

      Rating: 5
Let's
      pray  September 17, 2001
Reviewer:  Reji
       from NJ, USA
Let us all pray for this nation who opened their arms and welcomed millions of
people around the world and we all came up in our lives because of the freedom
and support that we have received from this country.  How many nations in this
whole world give this kind of freedom and support?

Let's pray for the people who lost their relatives and friends - I also lost my
cousin and a very close friend. Let's also pray for this nation and the leaders
so that they will attain the wisdom to go after these individuals who did this
coward act.

My prayer and condolence to the entire nation !!!

May God Bless all of us.

R

      Rating:
      2
  September 17, 2001
Reviewer:  s
       from USA
Lot of Indian software professionals yet Indians are
targeted in the United states . Very unfortunate .

September 17, 2001 Mahesh -- Thanks for the question regarding
      "Locking", version 8.1.7

      You Asked
Hi,
Is it possible to manually release a lock without killing a session?
What is the use of package function DBMS_LOCK.RELEASE ?

      and we said...
No, the session must either COMMIT or ROLLBACK (killing it rolls it back).

DBMS_LOCK.RELEASE is used by a session to release a lock it has previously
allocated using DBMS_LOCK itself.  It is not for releasing "just any lock" -- it
can only release a user defined lock created by DBMS_LOCK in the same session.
Review &
      Followup

      Rating:
      3
LOCKS  September 17, 2001
Reviewer:
      kamal.P  from Singapore
Hi Mr.TOM...
Please let me know this..
Case 1:
i am locking the row after begin the transaction in procedural block and
releasing at the end.My procedure block contains
bulk inserts around 100000+ records,if multipe times the same procedure is
called all the procedures are in Q and executed successfully.
Begin
select seqno into a from prd_sequences where module='PO' for update of seqno;
passing this seqno to POID
inserts..................
................

COMMIT;

END;

Case 2:
Begin
select seqno  into a from prd_sequences where module='PO' for update of seqno;
commit;
passing this seqno to ID
inserts..................
................
COMMIT;
END;

from Case 2 i found poor performance of  database  insertions(if same procedure
is called 10 times with bulk inserts)
i am eagerly waiting for your advice.
Regards
Kamal.P

          Followup:

It is not readily clear why you are doing a SELECT FOR UPDATE here -- since as
soon as you commit, the lock is released.

The more frequently you commit, the slower you go.  A commit must wait for redo
log buffers to be syncronously written to disk.  Additionaly you generate MORE
REDO when you commit too frequently.

You want to COMMIT on TRANSACTIONAL boundaries.  When it makes sense to commit.
When you have done a logical unit of work.  A commit is not something you can
put here or there for no reason.

You NEVER commit for "performance" reasons or to "save" resources as it will
actually make you run slower and consume MORE resources.

September 17, 2001 SHANMUGAM -- Thanks for the question regarding
      "What is the recommend pct increase size of an OLTP application?", version
      8.1.7.0

      You Asked
Hi, Mr.Tom,

        I have system with large OLTP. Normaly 2 inserts per second. Also At
least I need 3 indexes over in that particular table.
Is any recommendations for pct increase size ? Can you help me? Is it possible
to decrease pct increase size after created the tablespace?

With best regards
shanmugam

      and we said...
pct increase = 0

I use ONLY locally managed tablespaces (LMT) with uniform extent sizes.  Extents
of different sizes are terrible -- don't like them at all.

Yes you can modify it:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x int ) tablespace system;
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table t storage ( pctincrease 0 );
Table altered.

(system is my ONLY dictionary managed tablespace, thats why I used it --
pctincrease is not even meaningful on an LMT)
Review &
      Followup

      Rating: 4
Pct
      Increase  September 17, 2001
Reviewer:
      Shanmugam  from Singapore
The Information is very useful to me.

September 17, 2001 Chandra -- Thanks for the question regarding
      "User Auditing", version 8.1.5

      You Asked
Hi Tom
I have a an application developed in Oracle 8.1.5 as backend and
D2k as Front end.Wherein Users get connected thru users defined in a table
called P_users.Where username,password,created_date,Mod_date are captured. And
when user gets connected to the application I want to know the user who is
inserting deleting and modifying the values
of a particular table.I could proceed thru Ur audit_pkg package ,but
i could not pass the user information like suppose username GCS gets
connected to the application ,i should be able to get the username and his
operations to the table ie has he inserted into the table or any updations done
to it.How could i achieve it.
Canu Please help

Gudala

      and we said...
Use an application context and have the procedure that verifies the
user/password set it.  Say your password routine is "check_password" currently,
you would:

create context my_ctx using check_password
/

and add this line of code:

   dbms_session.set_context( 'my_ctx', 'username', l_username );

to check_password (where l_username is the plsql variable that contains the
username).  Now you can use

   sys_context( 'my_ctx', 'username' )

in plsql, any query -- where ever -- to get the users name as you know them by.

September 17, 2001 oracle -- Thanks for the question regarding
      "Julian Date", version 8.1.7

      You Asked
Tom

I was going through some of the packages written by the developers who wrote the
application before me.

I see that they first convert a date passed into a procedure or function as
input parameter , into the julian format and then work onit. What is the
specific purpose.

In what circumstances a date is converted into Julian format.

What are the specific uses of a julian format date.

Thank you

      and we said...
I cannot tell you why they do that, you would have to ask them.  A julian date
is the number of days from a fixed point in time.

  1* select to_char( sysdate, 'j' ), to_char( to_date( 1, 'j' ), 'dd-mon-yyyy
AD' ) from dual
ops$tkyte@8.0> /

TO_CHAR TO_CHAR(TO_DAT
------- --------------
2452166 01-jan-4712 BC

so, its just the number of days since jan 1, 4712 BC.

Maybe they did it as a long winded way to truncate the time component:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select to_char( to_date(
to_char(sysdate,'j'), 'j' ), 'dd-mon-yyyy hh24:mi:ss' ) from dual;

TO_CHAR(TO_DATE(TO_C
--------------------
17-sep-2001 00:00:00

if so, trunc(date) would be easier.

Review &
      Followup

      Rating: 4
Different ways
      to truncate the time portion of a date  September 17, 2001

Reviewer:  A reader
So is Julien date used to truncate date component. Or rather, does the Julien
date does not contain component.

can you tell me different ways to truncate the time portion of a date. In oracle
9i do we have a separate datatype for time.

Where can I get a document listing 9i new features, sql, plsql, and database

          Followup:

A julian date is not used to truncate a time component of a date -- I was
hypothesizing that maybe that is what is might have been used for.

TRUNC is best for that.

See

http://download-west.oracle.com/otndoc/oracle9i/901_doc/index.htm
for 9i docs

      Rating:
      5
Example  September 17, 2001
Reviewer:
      A reader
Please give an example when a julian format is an absolute necessity.

Further, which is inexpensive and why

Truncing time using julian dagte
Truncing date suing trunc

          Followup:

It is never an absolute necessity.  It is a method of storing the date.  It is
no more or less functional then anything else.  It is an option.

trunc(dt) will be more efficient then to_date( to_char( dt, 'j' ), 'j' )

September 17, 2001 Sudhir -- Thanks for the question regarding
      "decode() question", version 8.1.7.2

      You Asked
Tom,

thanks for taking this question. basically I want a boolean expression in
decode. Say for example

if a>b then
 return a
else
 return b
end if

decode(a>b,100,200) was my thinking but I guess expression is not allowed there,
so I made it

decode( (a-b)/abs(a-b),1,a,-1,b)

I just found that you have already answered it

http://asktom.oracle.com/pls/ask/f?p=4950:8:126171::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:371900104221,%7Bdecode%7D

but how about following made up example:

if ((a>100 and b<200 and a>b and a/b>1.25) or (c is null)) then
 return a
else
 return b
end if

I think Access allows such boolean functions and I was looking for something
very similar without lot of sub-decodes and sign function calls which will cloud
the original expression.

Sorry if this is answered already

Thanks

Sudhir

      and we said...
Case statement

  1  select case  when 1 > 2 then '1 is greater then 2'
  2               else            '1 is not greater than 2'
  3         end
  4* from dual
sys@ORA817DEV.US.ORACLE.COM> /

CASEWHEN1>2THEN'1ISGREA
-----------------------
1 is not greater than 2

Available in 8.1.6 and up.

In PLSQL, you will have to either use a VIEW or a dynamicially opened ref cursor
to use CASE in SQL (until 9i when CASE is understood by plsql as well)

Review &
      Followup

      Rating: 5
Tom Thanks,
      that was surprising yet on the dot,   September 17, 2001

Reviewer:  A reader
However, it seems like Oracle could add expression in decode() to make it more
usable and powerful considering it already does so many things as it is.

Thanks

          Followup:

decode is depricated in favor of the ANSI SQL CASE statement which does all of
this and more....

      Rating: 5
An alternative
      approach  September 17, 2001
Reviewer:  Steve
      Baldwin  from Melbourne, Australia
How about writing a tiny function similar to the IIf of Access.

For example :

CREATE OR REPLACE FUNCTION IIf (
  iExpr  IN BOOLEAN,
  iTrue  IN VARCHAR2,
  iFALSE IN VARCHAR2) RETURN VARCHAR2 AS
BEGIN
  IF  iExpr THEN
    RETURN iTrue ;
  ELSE
    RETURN iFalse ;
  END IF ;
END ;

Then, to use it, the boolean expression can be as complex or simple as you like.
 The disadvantage is that it can only take true/false values, unlike an
'unlimited' number by using the case statement or decode function.  You can also
overload the function to make the True/False values other data types.

However, I agree with Tom.  Wait until you see the capabilities of CASE in 9i.
It's great.

          Followup:

That'll work in PLSQL but not SQL as SQL does not have a "boolean" type (you
cannot call a function and pass a boolean value in SQL).

September 17, 2001 Raj -- Thanks for the question regarding "Usage
      of composite index during query", version 8.1.6

      You Asked
Hi Tom,
I have a composite UNIQUE index on two columns of a table, say,
create unique index un_1 on table1(col1,col2).
I have a complex query with multiple joins that uses col1 in the where clause:

select * from ...,tableX,table1 where ... and tableX.col1 = table1.col1

My question is, during this search will the optimizer make use of the composite
index or would I have to create a separate duplicate index on table1.col1 to
make the query go faster.

Thanks very much,Tom.
Raj

      and we said...
It'll make use of the composite index (it has the ability to -- it might not,
could use a sort merge or a hash join or something else as well)

September 18, 2001 Prince -- Thanks for the question regarding "Next
      or previous valid date", version 8.1.6

      You Asked
Tom,

I have the following issue.

I have to get the 'mm/yyyy' part of date from one column and 'dd' part
from another column and cobine the both to for the result. When I do
this, the result could be an invalid date. In such case, I need to get
the next valid date.

Ex.
Col1 : 02/10/2000      -- mm/yyyy   --> 02/2000   -- a
Col2 : 10/31/2000      -- dd        --> 31        -- b

Res  : a oper b --> 02/31/2000

I want it to be either the previous or next valid date. In my case,
result has to be either '02/29/2000' or '03/01/2000'. Anyone will do.

Is this possible to do in SQL qry? If so, how?

Thanks,

      and we said...
Sure:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( c1 date, c2 date );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( to_date( '02/10/2000',
'mm/dd/yyyy' ),
  2                                             to_date( '10/31/2000',
'mm/dd/yyyy' ) );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( to_date( '10/31/2000',
'mm/dd/yyyy' ),
  2                         to_date( '02/10/2000', 'mm/dd/yyyy' ) );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select c1, c2,
  2               decode( sign( to_char(last_day( c1 ),'DD')-to_char(c2,'DD')),
  3                             -1, last_day(c1),
                                    trunc(c1,'month')+to_char(c2,'DD')-1 )
  4    from t;

C1        C2        DECODE(SI
--------- --------- ---------
10-FEB-00 31-OCT-00 29-FEB-00
31-OCT-00 10-FEB-00 10-OCT-00

Review &
      Followup

      Rating: 5
Good
      answer  September 01, 2001
Reviewer:
      Harrison  from Haymarket, VA USA
Sometimes I get the feeling that the question is so off the wall that the answer
will be "impossible" but it hardly ever is.  Anyway, it is worth it to me to
learn how it is done, even if I hope I never have that question (this one seems
to be "dealing with bad data", which always seems iffy).

      Rating:
      5
  September 04, 2001
Reviewer:  Helena
      Markova  from Bratislava, Slovakia

      Rating:
      3
  September 04, 2001
Reviewer:  vasu
       from chennai, TN INDIA

      Rating: 5
The power of
      SQL  September 04, 2001
Reviewer:  Matt
      Turner  from UK
One question I do have is why the USA favour the
date format mask mm/dd/yyyy over dd/mm/yyyy.
I have always been curious about this.

      Rating:
      5
Great  September 06, 2001
Reviewer:
      Shahzad  from TX,. USA
wohhhhh...

      Rating:
      5
Unbelievable  September 18, 2001
Reviewer:
      Akhilesh  from India
Tom

whenever yu do some sql like

select c1, c2,
  2               decode( sign( to_char(last_day( c1 ),'DD')-to_char(c2,'DD')),
  3                             -1, last_day(c1),
                                    trunc(c1,'month')+to_char(c2,'DD')-1 )
  4    from t;

You should also put a few sentences as to what the sql is doing.

Can you do that for us please.

          Followup:

I usually do...  Must have been in a rush that morning...

here I took the last day of column c1  "to_char(last_day(c1),'DD'" and compared
it to the day already in c2 "to_char(c2,'DD')".  I did this by subtracting.  If
the last day of c1 was LESS THAN the current day in C2 -- the "sign" of that
will be -1.

That is where the decode kicks in.  If the last day of C2 is LESS THAN the
current day in C1 -- we simply return the LAST_DAY(c1).  So for example, if C1
was FEB-2000, the last day is "29" for c1.  If c2 was JAN-30 then we have 29
being less than 30 and we return 29-FEB-2000 - not 30-feb-2000 (which would be
an invalid date).

On the other hand, if C2 was 15-jan-2000, then 29 is greater than or equal to 15
and the second part of the decode kicks in.  Here we take the month from c1 and
the day from c2 and put them together for the date.

September 18, 2001 play -- Thanks for the question regarding "last
      business day", version 8.1.7

      You Asked
Tom

define "last business day" for me.

last business day -- if today is a saturday, then yesterday is the last business
day for the week.
If today is is Monday then last friday is the last business day.

Yes, there is a table called t , which has all the holidays.
and then we are also given a list of all the holidays at the begining of the
year

*******

1.I want a function which will return me the last business day whenever I
execute it. How should I write it.

2.I want a function which will give the business day prior to the given date,
i.e. I send in a date as the paramete, and the function
should be smart enough to ignore weekends, holidays and return the previous
business day.

What is a Julien Date? what are other kinds of dates.

We want hear from  you, as to what you feel about the terrorist attack.

      and we said...
1)

the decode is your answer:

  1  select dt, to_char( decode( to_char( dt, 'dy'), 'fri', dt,
next_day(dt-7,'fri') ), 'Dy, DD-MON-YYYY' )
  2* from ( select sysdate+rownum dt from all_objects where rownum < 10 )
ops$tkyte@ORA817DEV.US.ORACLE.COM> /

DT        TO_CHAR(DECODE(T
--------- ----------------
14-SEP-01 Fri, 14-SEP-2001
15-SEP-01 Fri, 14-SEP-2001
16-SEP-01 Fri, 14-SEP-2001
17-SEP-01 Fri, 14-SEP-2001
18-SEP-01 Fri, 14-SEP-2001
19-SEP-01 Fri, 14-SEP-2001
20-SEP-01 Fri, 14-SEP-2001
21-SEP-01 Fri, 21-SEP-2001
22-SEP-01 Fri, 21-SEP-2001

9 rows selected.

2) ops$tkyte@ORA817DEV.US.ORACLE.COM> create table holiday ( h date );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select max(dt)
  2    from ( select sysdate-rownum dt
  3                     from all_objects
  4                    where rownum <= 25
  5             )
  6   where to_char(dt,'dy') not in ( 'sat', 'sun' )
  7     and not exists ( select NULL from holiday where h = trunc(dt) )
  8  /

MAX(DT)
---------
12-SEP-01

replace SYSDATE in the inline view with YOUR date

A julian date is the number of days from a fixed point in time.

  1* select to_char( sysdate, 'j' ), to_char( to_date( 1, 'j' ), 'dd-mon-yyyy
AD' ) from dual
ops$tkyte@8.0> /

TO_CHAR TO_CHAR(TO_DAT
------- --------------
2452166 01-jan-4712 BC

so, its just the number of days since jan 1, 4712 BC.

Review &
      Followup

      Rating:
      2
  September 13, 2001
Reviewer:
      A reader
Kindly explain the below query

  1  select dt, to_char( decode( to_char( dt, 'dy'), 'fri', dt,
next_day(dt-7,'fri') ), 'Dy, DD-MON-YYYY' )
  2* from ( select sysdate+rownum dt from all_objects where rownum < 10 )
ops$tkyte@ORA817DEV.US.ORACLE.COM> /

and in 2

why are you selecting from all_objects, what I am supposed to replace it with in
my code

          Followup:

They asked for the last business day -- the last friday before today.  I assumed
that if it was friday -- they wanted to return that day.

So, the decode( to_char(dt,'dy','fri', dt, next_day(dt-7,'fri') )

is the same as:

  if ( dt is friday )
  then
     return dt;
  else
     return the next friday that happens after dt-7;
  end if;

As for 2, use all_objects -- you just need any table with a couple of rows.

      Rating:
      1
play  September 13, 2001
Reviewer:
      play
by business day what I meant was, any weekday which is not a holiday.

          Followup:

Well, that is not what you said ;)

Just use the answser from #1 and expand on the answer using number two then.
Use the same exact technique  (eg: apply the concepts to a different problem).

ops$tkyte@ORA817DEV.US.ORACLE.COM> select max(dt)
  2    from ( select decode( to_char( sysdate, 'dy'), 'fri', sysdate,
next_day(sysdate-7,'fri') )-rownum+1 dt
  3                     from all_objects
  4                    where rownum <= 25
  5             )
  6   where to_char(dt,'dy') not in ( 'sat', 'sun' )
  7     and not exists ( select NULL from holiday where h = trunc(dt) )
  8  /

MAX(DT)
---------
07-SEP-01

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into holiday values ( '07-sep-2001' );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select max(dt)
  2    from ( select decode( to_char( sysdate, 'dy'), 'fri', sysdate,
next_day(sysdate-7,'fri') )-rownum+1 dt
  3                     from all_objects
  4                    where rownum <= 25
  5             )
  6   where to_char(dt,'dy') not in ( 'sat', 'sun' )
  7     and not exists ( select NULL from holiday where h = trunc(dt) )
  8  /

MAX(DT)
---------
06-SEP-01

Here we just generate a set of dates in the inline view (candidate dates)
starting with the previous friday (just like the original #1) and then back 25
days.  The where clause gets rid of weekends and holidays.  We keep the max date
from that and its the one we want.  Unless you have some 25 days of holidays --
this'll work.  If you are worried about that, use more rownums...

      Rating: 5
cant we use
      dual  September 13, 2001
Reviewer:
      A reader
Why cant we use dual instead of all_objects.
I dont think our team lead will allow us to make a reference to all_objects like
this.
Unless and untill we fully satisfy him, as to why we have to use any table
there.

          Followup:

Well, dual has how many rows??? one.

It won't work unless the table we select from has at least a couple of rows.

I urge you -- before you use this, please understand what it does.  Don't take
it "as is", please take the time to understand it, comprehend it.  If you do
that - it will be obvious that DUAL could not be used.

The entire purpose of using all_objects where rownum <= 25 is just to make up 25
rows.  We need to make a SET of dates from whence we will get the date we really
want.

Create your own table, put some rows in it.  Use that instead if you want.

(your team lead should get a life if they are into not letting you do things
like that.  why, why would they say "no, you cannot query all_objects".  that is
just silly.  Hopefully a 'team lead' would look at it, understand what it does
and say "hey, thats pretty cool", not "i'm afraid of all_objects -- don't do
it").

      Rating:
      4
Excellent  September 14, 2001
Reviewer:
      Jim  from Australia - but my thoughts and prayers are with the
      US
Another good one Tom!

Your comments re understanding your reply are valid.
I get the impression many people using your site
are simply hoping you will write their code for them!

      Rating:
      5
?  September 18, 2001
Reviewer:  Je
       from USA
and not exists ( select NULL from holiday where h = trunc(dt)

I guess instead of null, we can also select 1 or 'X'

Iam I right.

          Followup:

you could select *, sysdate, 1, 'x', 'hello world' -- whatever you want.  It is
not relevant.  Whatever you select is NOT USED, ignored, not part of the answer.

select NULL in a (not) EXISTS is to me the semantically correct way to say it --
I am in fact selecting NOTHING and nothing says nothing better then NULL.

September 18, 2001 Guru -- Thanks for the question regarding "Code
      size in a trigger", version 8i

      You Asked
Hi Tom,

   I would like to know whether there is any limitation on the size of code that
we can write in a trigger.
   In our application there is a form which contains a huge code in
When-Button-Pressed for a button.  It behaves little bit strange some times.  Is
the code limitation causing this strange behavior.

Regards,
Guru Prasad

      and we said...
There is no code limitation.

I find "large code" behaves strangely because it is hard to code, maintain and
understand.  The compiler itself has no issues with it -- we (humans) do.

I would recommend that if you believe the code to be large to break it up into
dozens of subroutines.  A trigger over 100 lines would "scare" me - I prefer to
have them fit on a screen (without having to page down).  Same with subroutines
-- they should be small, understandable and modular.
Review &
      Followup

      Rating: 4
Code size in a
      trigger  September 17, 2001
Reviewer:
      Nathan  from Singapore
Hi Mr.Tom,
Is it applicable for Database Triggers also?.

          Followup:

yes.

September 18, 2001 hahaer -- Thanks for the question regarding "How
      can I prevent certain clients to access database?", version 8.1.6

      You Asked
1. I have setup a standby database. And it's running well. But these days I am a
little worried. Once I wrongly configed my java program which made connection to
that standby box instead of the test one. Since the standby database was running
in managed standby mode, it couldn't accept the connection, and I thought the
standby would just reject it. But in fact, a lot of shadow processes respawned
at the server site, finally, the server ran out of resources(halt). I am worried
that if someone knows there is a standby box, he could easily make it down by
continually connecting to it(using jdbc connection pool). And  I tested, the
result supported my estimate. So Tom, how can I avoid this problem? I think I
can prevent other machines from connecting to the server except the main
database, but how can I do it? I also know the oracle connection manager can
route the connections, but if someone knows which server is hosting the
database, he can still hack it bypassing oracle connection manager. Is that
true?

2. We are running oracle8.1.6 on solaris platform, with rman backing up the
database. We want to restore it on a linux box, can we?

Thanks in advance!

      and we said...
1) see

http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/params.htm#478104
and look at the invited_nodes/validnode_checking

Another option would be to use a non-standard port (other then 1521 for example)
and not tell anyone what it is.

2) No, to go cross platform you must use SQLNet (dblink or sqlplus copy command)
or export/import.

datafiles are OS dependent.
Review & Followup

      Rating: 3
JDBC
      bug?  September 18, 2001
Reviewer:  Andrew
       from USA
I encountered a similar problem (using 8.1.5 JDBC drivers using connection
pooling to a Solaris server). Each refused connection for whatever reason (e.g.
wrong user/pass) resulted in an additional process on the server. "Max Oracle
connections exceeded" was the symptom. 8.1.7 JDBC drivers resolved the problem.

September 18, 2001 M. -- Thanks for the question regarding "What is
      64 bit and 32 Bit.", version 8.1.7

      You Asked
Hi Tom,

A silly question may be...

What is 32 bit Oracle and 64 bit Oracle. Does it have any thing with the
performance and any thing with the Installation.

Does it affect the application if you are using 32 bit or 64 bit? Which one is
better.

Thanks..

      and we said...
It is based on the chip (CPU) on your machine.  Most machine are 32bit machines
meaning a pointer is 32bits in length allowing us to address directly about 2-4
gig of RAM.

On a 64bit machine we can address alot more then that.  Oracle Magazine just had
an article on this feature this month.

See

http://www.oracle.com/oramag/oracle/01-sep/index.html?o51advice.html
for details.
September 18, 2001
      Mohammed -- Thanks for the question
      regarding "Ora -10027 ", version 8i

      You Asked
Hi Tom ,
 I had asked you this Question before , and I tried as you told me but,I still
have the same problem
I am using pl/sql to get the result from tables by using Cursur.
And I am using DBMS_out.Put_line

becouse the data i am retriving is quit large  I always get this error

ERROR at line 1:
ORA-20000: ORU-10027: buffer overflow, limit of 999999 bytes
ORA-06512: at "SYS.DBMS_OUTPUT", line 91
ORA-06512: at "SYS.DBMS_OUTPUT", line 58
ORA-06512: at line 24

I set serveroutput on size 999999 or bigger 1000000

Can you give soultion for this

And step by step for doing the soultion ,
I really Thank a bout all your helps
I am using the following SQL Statment

set serveroutput on size 999999
set echo off
set linesize 800

DECLARE
  cl_id number;

  cursor crInvoices is
    select bl.invoice_number, cn.client_id, bl.amount_due
    from bills bl, contracts cn
    where bl.bill_type = '2'
      and bl.status = '2'
      and bl.start_date between to_date ('01/04/2001 00:00:00', 'DD/MM/YYYY
HH24:MI:SS')
                            and to_date ('30/04/2001 23:59:59', 'DD/MM/YYYY
HH24:MI:SS')
      and bl.invoice_number is not null
      and bl.contract_id = cn.id;

   cursor crSubscribers is
     select sc.subscriber_id, sc.phone_number, sc.device_account
     from clients cl, subscriber_channels sc
     where cl.reference_id = cl_id
       and cl.id = sc.subscriber_id;

BEGIN
  for recInvoices in crInvoices loop
    cl_id := recInvoices.client_id;
      for recSubscribers in crSubscribers loop
        dbms_output.put_line (recInvoices.invoice_number||' '||
                              recInvoices.client_id||' '||
                              recSubscribers.phone_number||' '||
                              recSubscribers.device_account||'
'||recInvoices.amount_due);
      end loop;
  end loop;
END;
/

      and we said...
My recommendation here (dbms_output WON'T go above that -- you've hit the max)
is to use a simple query instead.

set heading off
set feedback off
set embedded on
set linesize 800
set trimspool on
spool data.txt
select  bl.invoice_number ||' ' ||cn.client_id || ' '||
        sc.phone_number || ' ' || sc.device_account
   from bills bl, contracts cn, clients cl, subscriber_channels sc
  where bl.bill_type = '2'
    and bl.status = '2'
    and bl.start_date
          between to_date ('01/04/2001 00:00:00', 'DD/MM/YYYY HH24:MI:SS')
              and to_date ('30/04/2001 23:59:59', 'DD/MM/YYYY HH24:MI:SS')
    and bl.invoice_number is not null
    and bl.contract_id = cn.id
    and cl.reference_id = cn.client_id
    and cl.id = sc.subscriber_id
/
spool off

that can be of unlimited size (never do procedurally what SQL was born to do)

Review &
      Followup

      Rating: 5
SQL Statment
      insted of having Ora -10027   September 19, 2001

Reviewer:  Mohammed E. Almoayed  from Yemen

Ok ,It Goes very Well I tried it and ,I really thank you
very much .

September 19, 2001 -- Thanks for the question regarding
      "Unrecoverable option in SQL Loader", version 8.1.6

      You Asked
Tom

I am loading data in a table using sql*loader.  Inorder to speed the process I
am going for UNRECOVERABLE option.  I have a doubt. What will happen once the
data is loaded in the table successfully will it be still in unrecoverable stage
?

What is the difference btw nologging and unrecoverable ?

Balaji

      and we said...
unrecoverable and nologging are the same.

The data will be loaded -- you should back up the affected tablespaces as soon
as possible.  If you do not and the media fails AFTER you load, but before you
back it up -- you will have to reload (and reapply and modifications you made)
Review &
      Followup

      Rating:
      3
  September 18, 2001
Reviewer:
      A reader
Will the archiver archive the data loaded in the tables, if there encounter no
media failure.

          Followup:

No, the archiver archives REDO and no REDO is generated for the UNRECOVERABLE
load. Hence the need to backup the tablespace ASAP after the load.  If you do
not, you will have to reload the data and re-perform the modifications.

      Rating: 3
some
      puzzle  September 18, 2001
Reviewer:  hahaer
       from China
When loading database in nologging mode while the database is running in an
archivelog mode, or the target table is not created in nologging mode, will redo
log will be generated?

          Followup:

If you do it unrecoverable -- no redo is generated, regardless of archivelog
mode.

from the server utilities guide:

Minimizing Use of the Redo Log
One way to speed a direct load dramatically is to minimize use of the redo log.
There are three ways to do this. You can disable archiving, you can specify that
the load is UNRECOVERABLE, or you can set the NOLOG attribute of the objects
being loaded. This section discusses all methods.....

      Rating:
      3
  September 19, 2001
Reviewer:
      A reader

September 19, 2001 Omer -- Thanks for the question regarding
      "sqlplus, delete vs truncate, roles-roles-privileges", version 8.1.7

      You Asked
Tom

From the sqlplus when I want to execute a function or procedure and there are a
lot of params

like

sqlplus>exec :z
:=pkg_my_pkg.the_best_function('sdfsdfsdfsfd',23324234,'sdfsdsdsdfdfs
fsdf','sdfsdfsdfdsf' ;

It is going on to the next line, if I hit enter after the first line, the
function tries to execute , and obviously returns an error.

I want it like this
sqlplus>exec :z :=pkg_my_pkg.the_best_function
('sdfsdfsdfsfd',
23324234,
'sdfsdsdsdfdfsfsdf',
'sdfsdfsdfdsf' ;

How can I achieve this

can I save the exec :z
:=pkg_my_pkg.the_best_function('sdfsdfsdfsfd',23324234,'sdfsdsdsdfdfs
fsdf','sdfsdfsdfdsf' ; , in a sql file, and do a start(file_name) from the
prompt, will the function get executed.

For the sake of my testing I dont want to type this statement again and again ,
nor I want to cut and paste, I want to save it in a file and run it, can I do
that, if so , how.

2.

Delete from t;
commit;

truncate table t;

which one of the above is faster and why.

But while truncating the session should have the table exclusively, what will
happen if the table is locked by another session, wouldnt the statement fail.
How should I handle this in the exception section , if Iam using method 2.

If Iam truncating a global temporary table would I encounter the above problem
while truncating.

3.I saw that role_sys_privileges, gives privileges for each role, I want to see
in one sql ,
the roles I have , the privileges assigned to those roles, and those privileges
which are assigned directly to me.

      and we said...
code:

SQL>begin
     :z :=pkg_my_pkg.the_best_function
      ('sdfsdfsdfsfd',
      23324234,
     'sdfsdsdsdfdfsfsdf',
      'sdfsdfsdfdsf' );
    end;
    /

instead of exec, that can span lines easily.

2) for a little data, delete will be.  for a lot of data, truncate will be.
delete generates redo and rollback entries for all rows deleted.  truncate does
not.

if the table is locked by another session truncate will fail -- truncate is DDL
and most DDL needs the table exclusively.

how you handle the exception is totally upto you.  Maybe you try again or maybe
not..  You tell me what you want to do here.

some people do:

   for i in 1 .. 100
   loop
   begin
      execute immediate 'truncate table t';
      exit;
   exception
      when others then if ( i=100 ) then RAISE; end if;
   end;
   end loop;

that'll try to truncate 100 times and exit when it succeeds.  if it fails 100
times, it just propagates the error out.

You should not hit this truncating a global temporary table as you affect your
extents only.

3) see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:853427230099
...

September 19, 2001 Surrinder -- Thanks for the question regarding
      "Checking Datatypes in PL/SQL", version 8i

      You Asked
I have a column of data type varchar2, which holds a range of data, ie
number,date and decimal. I need to check the data type of each record to
deltermine which of these data types it is. How do I do this ?

      and we said...
you could

create or replace function is_number( p_string in varchar2 ) return boolean
as
  l_data number;
begin
  l_data := p_string;
  return true;
exception
  when others then return false;
end;

do the same for a date/number(n,m) whatever -- if it converts, it was that type.
 If it raises an exception, it is not that type.

Review &
      Followup

      Rating: 5
Simplest
      way!!  September 19, 2001
Reviewer:
      A reader
.

      Rating:
      3
  September 20, 2001
Reviewer:
      A reader

September 20, 2001 Brian -- Thanks for the question regarding
      "Parallel Queries in Oracle 7.3.4", version 7.3.4

      You Asked
In 7.3.4, is there an initialization parameter (or parameters) that could be set
to tell Oracle to uses parallel queries whenever it sees fit? Can I set any
session parameter(s)?  Or do I have to specify parallelism on each table and/or
query?

What about 8.1.5 and 8.1.6?

Thanks !!!

... Brian

      and we said...
Automatic parallel query tuning is a feature of Oracle8i release 1 (815) and up

...
Automated Parallel Query Tuning

This enhancement simplifies tuning of parallel query (PQ) execution and provides
better system utilization. PQ users can simply specify that a query or table is
to be parallelized, and the system determines the optimal single user setting,
then reduce it based on the system utilization at the time the query starts
execution. There are four parts to this enhancement.

n Default settings are improved for degree and instances.
n There are improved defaults for initialization parameters when the user
intends to use parallel query.
n A multi-user adaptive degree algorithm is used to select an optimal degree of
parallelism based on system load.
n A load balancing algorithm evenly distributes the load across nodes in an
inter-node parallel query environment.

prior to that, you needed to set it up query by query or table by table.
Review &
      Followup

      Rating:
      5
  September 19, 2001
Reviewer:  Brian
      Davies  from Edmonton, Alberta, Canada

      Rating: 4
Hiding the
      complexity is good  September 19, 2001
Reviewer:
      Andrew  from CA, USA

      Rating: 3
Initialization
      parameters for parallel query  September 20, 2001

Reviewer:  A reader
Hi Tom,
Brian asked for initialization parameters but you didn't mention any. Which must
be set and which is useful to set in 8.1.6
Thanks
Brigitte

          Followup:

Well, I didn't mention any cause brian is on 7.3 and they are not relevant to
him (the auto tuning).

I would suggest one has a good understanding of what they are/what they do
BEFORE just turning them one.  I recomment you read the relevant chapters in the
server concepts manual and the admin guide.

If you are really "daring", you can just skip to the Server Reference,
initialization parameters.  These all start with PARALLEL_   (but it is strongly
encouraged to actually understand what this is all about, what will happen as a
result of setting them -- this is a big change to your server configuration
potentially.  Not something to just be "turned on")

September 21, 2001 Senthil -- Thanks for the question regarding
      "Native dynamic sql - Refcursor", version 8.1.5

      You Asked
Tom,

Here is an example...that i want to change one function to avoid redundant
information.

create or replace package p_ref_cursor  is
   type ret_ref_cursor is ref cursor;
end p_ref_cursor;
/

drop table "tab1";

create table "tab1" (no number, city varchar2(20));

insert into "tab1" values (1, 'Boston');
insert into "tab1" values (2, 'Chicago');
insert into "tab1" values (3, 'Atlanta');

drop table "tab2";

create table "tab2" (no number, city varchar2(20));

insert into "tab2" values (1, 'London');
insert into "tab2" values (2, 'Paris');

create or replace function "fun_tab1"(p_no in number)
return p_ref_cursor.ret_ref_cursor is
   l_cursor p_ref_cursor.ret_ref_cursor;
begin
   open l_cursor for select * from "tab1" where no <= p_no;
   return l_cursor;
end;
/

create or replace function "fun_tab2"(p_no in number)
return p_ref_cursor.ret_ref_cursor is
   l_cursor p_ref_cursor.ret_ref_cursor;
begin
   open l_cursor for select * from "tab2" where no <= p_no;
   return l_cursor;
end;
/

create or replace function get_data(p_table_name in varchar2, p_no in number)
return p_ref_cursor.ret_ref_cursor is
   l_cursor p_ref_cursor.ret_ref_cursor;
begin
   if p_table_name = 'tab1' then
      return "fun_tab1"(p_no);
   end if;
   if p_table_name = 'tab2' then
      return "fun_tab2"(p_no);
   end if;
end;
/

var r refcursor
exec :r := get_data('tab1', 10);
print r

exec :r := get_data('tab2', 10);
print r

and the output is...

        NO CITY
---------- --------------------
         1 Boston
         2 Chicago
         3 Atlanta

        NO CITY
---------- --------------------
         1 London
         2 Paris

For some reasons...we used to create tables and functions as a case sensitive
and also creates seperate set of independant functions and procedure for each
tables. now there is a master function(get_data)... that gets table name and
other values as a input parameter and calls corresponding functions. i am
allowed to change the master function to remove all redundant
information(if..thens...). i thought of using native dynamic sql but i couldnt.
Is it possible to use native dynamic sql...if so...could you please give me the
suggestions.

thanks,
senthil.

      and we said...
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace function
get_data(p_table_name in varchar2, p_no in number)
  2  return p_ref_cursor.ret_ref_cursor is
  3     l_cursor p_ref_cursor.ret_ref_cursor;
  4  begin
  5     open l_cursor for
         'select * from "' || p_table_name || '" where no <= :p_no' using p_no;
  6     return l_cursor;
  7  end;
  8  /

Function created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> variable r refcursor
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec :r := get_data('tab1', 10);
PL/SQL procedure successfully completed.

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

        NO CITY
---------- --------------------
         1 Boston
         2 Chicago
         3 Atlanta

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec :r := get_data('tab2', 10);
PL/SQL procedure successfully completed.

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

        NO CITY
---------- --------------------
         1 London
         2 Paris
Review & Followup

      Rating:
      4
Thanks...but,  September 21, 2001

Reviewer:  Senthil
Great answer. But i wonder is it possible to use a "Execute Immediate" in
get_data function. I gave a simple query in other two functions ("fun_tab1" &
"fun_tab2")...but in real time it might be having different SELECT
statements...would return more than one row based on different condition. And
also...the number of tables would increase and new functions will be added to
it. In that case...get_data function will grow and grow further...with
additional IF-THEN statements.

          Followup:

Not with the ref cursor it isn't possible.  You will get:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/2      PL/SQL: Statement ignored
5/65     PLS-00457: expressions have to be of SQL types

trying to bind a ref cursor type in dynamic SQL in PLSQL.

September 21, 2001 Michael -- Thanks for the question regarding "How
      to apply static SQL to temporary table in stored procedures ? -", version
      Oracle 8.0.5

      You Asked
Logic of my Oracle 8.0.5 stored procedures (sp) should be the
following:

Step 1
--------
Based on user input sp_1 creates huge temporary master table
as result of several joins. The temporary master table structure
is fixed and is known in advance,
only number of rows and data vary from user to user.

Step 2
-------
The all following user interactive  queries in this session
applied only against this temporary master table
and sp_2 will retrive the results.

This is multi-users application, therefore
I need to generate unique name for master table for every user.

For this reason looks like on Step 2 procedure sp_2
I can use only dynamic query  ( DBMS_SQL package )
and I can see performance degradation issues here.

Question :
How to use knowledge of temporary table structure only
( table name will be generated dynamically , may be based on
timestamp) in Oracle sp_2 to increase performance ?

How to apply static SQL to temporary table  in stored procedures
?

Regards, Michael Lubinsky.

      and we said...
Do not use a separate table for each user.  To your temporary
table simply add a column:

session_id  number default userenv('sessionid')

For example:

ops$tkyte@8i> create table t
  2  ( session_id number default userenv('sessionid'),
  3    a          number,
  4    b          number
  5  ) storage ( freelists 20 )
  6  /

Table created.

ops$tkyte@8i>
ops$tkyte@8i> create or replace view t_view
  2  as
  3  select a, b from t where session_id = userenv('sessionid')
  4  /

View created.

ops$tkyte@8i>
ops$tkyte@8i>
ops$tkyte@8i> insert into t_view values ( 1, 2 );

1 row created.

ops$tkyte@8i>
ops$tkyte@8i> select * from t_view;

         A          B
---------- ----------
         1          2

Your application will use t_view -- not T.  T will behave like a
session based temporary table -- when you log out, the rows
disappear.  No one else can ever see your data.

You will make sure to add SESSION_ID to any UNIQUE or PRIMARY
KEY constraint you have (as the first column in that
constraint).  You will index SESSION_ID if it is not part of a
some other index on the leading edge.

There are no concurrency issues with this approach -- no
blocking or locking out will take place.

You'll schedule a job to periodically "clean up" T (truncate or
delete from it where session_id not in ( select audsid from
v$session)).  Or the procedures can delete from it when done
with the data.

In Oracle8i, release 8.1 and up, you will replace t_view with a
GLOBAL TEMPORARY table which has all of the attributes of the
above but will not generate redo when acted on.

Review &
      Followup

      Rating: 4
how about
      rollback  September 21, 2001
Reviewer:
      A reader
Will a global temp table generate rollback?

          Followup:

Yes -- but very little.  In my book I go into lots of detail on this with
examples and such if you are interested.

It has to generate rollback - you have the ability to "rollback" operations on
temp tables just like anything else.

In general, it will generate rollback for inserts but the amount of rollback
generated is very very small for inserts.

For updates/deletes -- the amount of rollback increases of course but you
update/delete temp tables very very infrequently (delete should never be done
actually).  The update, as long as you update only the columns that need be
updated, will generate rollback equivalent to the columns you are modifying.

      Rating:
      5
then  September 21, 2001
Reviewer:
      A reader
delete should never be done
actually

Why shouldnt we delete from global temporary table's, why is it harmful.

          Followup:

It generates the most rollback (and hence the most redo log) information.

Temp tables are generally used to insert some data into ( very very little
rollback/redo ) and select data from (no rollback/redo).  If you need to empty
them you should truncate them (no rollback/redo) or make them on commit delete
rows and commit (no rollback/redo)

September 21, 2001 San -- Thanks for the question regarding "32 bit
      or 64 bit", version 8.1.5

      You Asked
Tom:

I wanna know:

1. What do you mean by 32 bit Oracle and 64 bit Oracle? Because
in so many Oracle documentation I found
"32 bit Oracle 7.x"
"64 bit Oracle 7.x"
"32 bit Oracle 8.x"
"64 bit Oracle 8.x"
also sometime in migration related documentaion I found people
are talking about 32 bit and 64 bit Oracle. What I thought
there is only one Oracle, I don't understand what is the
difference between 32 bit and 64 bit oracle. How this bit
concept is related to Oracle? May be you can through some light
on this issue.

2. Is there any known issue while migration from 8.0.x(8) to
8.1.x (8i). If yes, can you please let me know?

Thanks
San

      and we said...
1) 32bit Oracle is the Oracle that runs on all operating
systems.  It has a 4gig (or less, depending on OS) address
limit.  It uses 32bit pointers which are limited to 4gig.

Now, 64bit can address a much larger memory space.  It allows
for SGA's that are many 10's of gigabytes in size if you need
it.

It's just like the old days of the PC with "16 bit" and "32
bit"....

2) There are no "generic" gotcha's.  There will be issues with
upgrades.  Test Test Test.

Review &
      Followup

      Rating: 2
need compare
      data  September 20, 2001
Reviewer:  zhu chao
       from china.
hi, tom:
  i am faced with the choice of using 32bit or 64bit oracle on my 64 bit s80
machine.
  We did not need large memory support(the RAM is 4G),is it necessary for me to
choose 64bit Oracle?
  From metalink feedback, 64bit oracle is more buggy than 32bit:
 So far I have not recieved an excellent feedback after moving from 32bit to
64bit.
There could be some performance degradation after migrating to 64-bit from
32-bit OS. (From Metalink) ??
  Can u give me some instructions?
  Thanks so much!

          Followup:

Stay with 32bit then.  64bit gives you the ability to address lots of RAM -- you
don't need that.  64bit code can actually run slower then 32bit code on some
platforms (not familar with what an "s80" is personally).

      Rating: 4
Using 64 bit
      Oracle 8.1.7 on HP-UX 11.0  September 21, 2001

Reviewer:  sai  from US
We currently run 32 bit Oracle 8.1.6 on HP-UX 11.0 N CLASS
SERVER WITH 2GB RAM. I have just received the CDs for Oracle 8.1.7 and I was
planning to install the 64 bit version of 8.1.7. I read your feedback of slow
performance of 64 bit Oracle.
Do you recommend using 64 bit on HP-UX 11.0 , our environment is memory
intensive ?

          Followup:

With 8i -- it'll be your choice (with only 2gig of ram, either 32 or 64bit can
address it).

With 9i, you will be running 64bit as we no longer ship 32bit Oracle on HP.

September 21, 2001 Vinnie -- Thanks for the question regarding
      "v$sqlarea question", version 8.1.7

      You Asked
Tom,

I have multiple questions.

1.  I am running the following script :

create or replace procedure test2_load
as
    type numArray is table of number index by binary_integer;
    l_data    numArray;
    nrec    number := 200000;
    l_start number default dbms_utility.get_time;
    pragma    autonomous_transaction;
begin
    l_start := dbms_utility.get_time;
    for i in 1 .. nrec
    loop
        l_data(l_data.count+1) := i;
    end loop;
    dbms_output.put_line('# of Rows Inserted: '||l_data.count);
    forall i in 1 .. l_data.count
            insert into test
        (a,b,c)
            values
            (l_data(i),'12345678901234567892','12345678901234567892');

        insert into test
        (a,b,c)
               values
               (1,'12345678901234567892','12345678901234567892');

    commit;
    dbms_output.put_line( round((dbms_utility.get_time-l_start)/100 , 2 ) ||'
seconds...' );
    dbms_output.put_line(
ROUND(l_data.count/(round((dbms_utility.get_time-l_start)/100 , 2 )),2) ||'
/Second' );
    dbms_output.put_line(
ROUND((40*nrec)/(round((dbms_utility.get_time-l_start)/100 , 2 )), 2 ) ||'
Bytes/Second' );
end;
/
show errors

At the same time I am trying to capture the insert rate with another script:

select substr(sql_text,13,instr(sql_text,'(')-16) table_name,
rows_processed,
round((sysdate-to_date(first_load_time,'yyyy-mm-dd
hh24:mi:ss'))*24*60,1) minutes,
trunc(rows_processed/((sysdate-to_date(first_load_time,'yyyy-mm-dd
hh24:mi:ss'))*24*60)) rows_per_min
from v$sqlarea
where upper(sql_text) like 'INSERT INTO %'
and command_type = 2
and open_versions > 0;

I assumed the OPEN_VERSIONS attribute would tell me all sql that is currently
running.
But even after the first script is complete, open_versions still has a value of
1?  Shouldn’t this go to 0 as soon as the script has finished?

2. I am running RAID 0+1 with 2 LUN’s for my redo logs.
    LUN 1 redo01a, redo03a
    LUN 2 redo03a, redo03a

My question is, should I also let ORACLE multiplex these?
If so, is it ok to place them ALL on another disk ?

3. Is SQLLDR with direct=Y faster than using something like PRO*C with bulk
binds?

4. How much space would a column designated as number (22) take up?

      and we said...
1) nope, plsql caches cursors for it -- its very good about doing that.  Adds
immensely to performance.

You should use dbms_application_info.set_session_longops to do this sort of
work.  (my book has a pretty good section on using this if interested)

2) if they are mirrored and you trust the mirrors 1000%, you do not need to.  It
would not hurt to tri-plex them.  If the raid array returns a warning/message
when a write to one of the mirrors fails -- we might shut down the instance in
some cases.  If you have another log -- we won't (just write an alert message)

3) for large loads, yes, for a couple of rows, no.  OCI supports direct path
inserts in 8i however using a direct path API.

4) somewhere between 0 and 22 bytes.  Numbers are stored in a varying length
field.  It takes more space to store 9.00000009  then it does to store 10.

ask_tom@OSI816> select vsize( 9.00000009 ), vsize( 10 ) from dual;

VSIZE(9.00000009)  VSIZE(10)
----------------- ----------
                6          2
September 21, 2001 Tianhua -- Thanks for the question regarding
      "Easy way to find out the free space below High Water Mark for LOB
      segments", version 8.0/8i/9i

      You Asked
Hi Tom,

Thank you again for all you have done here.  I would like to know if there is an
way to find out the the free space below High Water Mark for LOB segments?

Thanks,

Tianhua

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
you can use my show_space script.  for example:

ops$tkyte@ORA817DEV.US.ORACLE.COM> CREATE TABLE "T" ("X" CLOB) ;
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> column segment_name new_val lob
ops$tkyte@ORA817DEV.US.ORACLE.COM> select segment_name from user_lobs where
table_name = 'T' and column_name = 'X';

SEGMENT_NAME
------------------------------
SYS_LOB0000018285C00001$$

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec show_space( '&lob', user, 'LOB' )
Free Blocks.............................0
Total Blocks............................3
Total Bytes.............................24576
Unused Blocks...........................1
Unused Bytes............................8192
Last Used Ext FileId....................1
Last Used Ext BlockId...................17710
Last Used Block.........................2

PL/SQL procedure successfully completed.

that shows there are 0 free blocks below the high water mark..

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2          l_data long default rpad( '*', 20000, '*' );
  3          l_clob clob;
  4  begin
  5          for i in 1 .. 100
  6          loop
  7                  insert into t values ( empty_clob() ) returning x into
l_clob;
  8                  dbms_lob.writeappend( l_clob, 20000, l_data );
  9          end loop;
 10          commit;
 11  end;
 12  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec show_space( '&lob', user, 'LOB' )
Free Blocks.............................0
Total Blocks............................433
Total Bytes.............................3547136
Unused Blocks...........................130
Unused Bytes............................1064960
Last Used Ext FileId....................1
Last Used Ext BlockId...................18123
Last Used Block.........................10

PL/SQL procedure successfully completed.

still 0 but there are now 403 blocks below the HWM, lets start freeing
some..

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from t where rownum <= 10;
10 rows deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec show_space( '&lob', user, 'LOB' )
Free Blocks.............................30
Total Blocks............................433
Total Bytes.............................3547136
Unused Blocks...........................130
Unused Bytes............................1064960
Last Used Ext FileId....................1
Last Used Ext BlockId...................18123
Last Used Block.........................10

PL/SQL procedure successfully completed.

Now there are 30 blocks below the HWM that are free -- able to be reused..

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from t where rownum <= 50;
50 rows deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec show_space( '&lob', user, 'LOB' )
Free Blocks.............................180
Total Blocks............................433
Total Bytes.............................3547136
Unused Blocks...........................130
Unused Bytes............................1064960
Last Used Ext FileId....................1
Last Used Ext BlockId...................18123
Last Used Block.........................10

PL/SQL procedure successfully completed.

and 180...

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from t;
40 rows deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec show_space( '&lob', user, 'LOB' )
Free Blocks.............................300
Total Blocks............................433
Total Bytes.............................3547136
Unused Blocks...........................130
Unused Bytes............................1064960
Last Used Ext FileId....................1
Last Used Ext BlockId...................18123
Last Used Block.........................10

PL/SQL procedure successfully completed.

and now all 300 blocks below the HWM (besides the original 3 that were used
even when the table is empty

Review &
      Followup

      Rating:
      4
  September 21, 2001
Reviewer:  Tianhua
      Wu  from Atlanta, GA
Thank you very much!  I also guess because of nature of LOB, the free space
inside block not on free list is less an issue than that for normal data.

          Followup:

A block is only on the freelist for a LOB when it is TOTALLY empty.  Space is
given to the lob using the CHUNK size.  So, if you have an 8k block size
database and use a 32k chunk -- space will be added and released from the lob 4
blocks at a time (even if you just write 1 byte to it)

September 22, 2001 JoseMartin -- Thanks for the question regarding
      "Performance of a Time Dimension View in DataWareHouses", version 8i

      You Asked
He are currently working in a DataWarehouse Development
and we have to create a generic Time Dimension.
Normally the way is creating a Table Dimension and insert programatically new
date records in the table.
we are thinking about another way of doing this.
Create the Next View will give More Performance and Space Gain than a
Traditional Table aproach ?

create or replace view DIM_TIME AS
SELECT    Thedate,
    TO_CHAR(Thedate,'RRRR') Year,
    TO_CHAR(Thedate,'Q') Quarter,
    TO_CHAR(Thedate,'MONTH') Month,
    TO_CHAR(Thedate,'DD') Day
from
    ( select to_date('01/01/2000','dd/mm/rrrr') + rownum Thedate
      from (select NULL from dual group by cube(1,1,1,1,1,1,1,1))
      WHERE Thedate<SYSDATE+1
      ORDER BY 1 ASC
    )

      and we said...
I would recommend against that, I would use a real table with real information.
Something you can create real DIMENSIONS to (used with materialized views and
query rewrite).

The view will not be faster then a "real table".
It'll affect our ability to perform a query rewrite.

Not a good idea in my opinion. (the space saved would be a teeny tiny drop in a
very large ocean in a data warehouse).

You might be interested in my chapter on materialized views in my book -- it
deals with the time dimension directly in there and shows the importance of
using DIMENSION database objects....  Also see:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76994/toc.htm
chapters 8 and 9.
Review & Followup

      Rating: 2
I like your
      technique  September 21, 2001
Reviewer:  Mikito
      Harakiri  from SF, US
Well, if being paranoic about performance, relational databases would never
invented in the first place.

Now, the question is if the mechanical job of building time dimension table
could be automated.

BTW, I was always wondering if it's possible to make unsafe queries in Oracle
and your query

select NULL from dual group by cube(1,1,1,1,1,1,1,1)

shows how close we can get to it.

Tom, do you happen to know if it's possible to make a query that opens a cursor,
starts extracting rows, and never quits? (We could put safe rownum<N
restriction, of course, but the question is if we could accomodate arbitrary big
N with the same unsafe inner query)

          Followup:

I'm not paranoid about performance -- and I don't really understand your
comments there -- but....

There is simply no reason to do something that would adversely affect
performance is there?  I mean -- why go OUT OF YOUR WAY to adversely affect
performance?  My job, as I see it, is to get the most out of the database, not
the least.  Do what you will....

Yes, the mechanical job of building a time dimension table can be automated.
DBMS_JOB would be used to add values every 6 months or something (alternatively,
you could just populate it out for the next 100 years if you wanted, or --
populate it when you load the data into the warehouse as most people do)

As for select NULL from dual group by cube(1,1,1,1,1,1,1,1) being "unsafe" -- i
fail to see your point again.  It will simply and deterministically, return 15
rows.  What is "unsafe" about that??  Maybe you don't understand how it works --
but that doesn't make it unsafe.

In Oracle9i you can use a pipelined function to create what appears to be a
table that returns as many rows as you ask it to.

It would look like this:

create or replace type virtual_table_type as table of number
/

create or replace function virtual_table( p_num_rows in number )
return virtual_table_type
PIPELINED    -- NOTE the pipelined keyword
is
begin
    for i in 1 .. p_num_rows
    loop
        dbms_output.put_line( 'going to pipe' );
        pipe row( i );
        dbms_output.put_line( 'done pipeing' );
    end loop;

    return; -- note return with no value!
end;
/

And then you can:

select * from TABLE( virtual_table(5) );

select * from TABLE( virtual_table(10) );

that would return 5 and then 10 rows repectively.

      Rating: 5
Original query
      doesn't run  September 21, 2001
Reviewer:
      Reader  from USA
Hi, Tom,

The original query:
create or replace view DIM_TIME AS
SELECT    Thedate,
    TO_CHAR(Thedate,'RRRR') Year,
    TO_CHAR(Thedate,'Q') Quarter,
    TO_CHAR(Thedate,'MONTH') Month,
    TO_CHAR(Thedate,'DD') Day
from
    ( select to_date('01/01/2000','dd/mm/rrrr') + rownum   Thedate
      from (select NULL from dual group by cube(1,1,1,1,1,1,1,1))
      WHERE Thedate<SYSDATE+1
      ORDER BY 1 ASC
    )

doesn't run, and error is:

WHERE Thedate < SYSDATE+1
      *
ERROR at line 10:
ORA-00904: invalid column name

I have to change to ( select to_date('01/01/2000','dd/mm/rrrr') + rownum <
sysdate+1 in order to make it run.

Thanks

          Followup:

I knew it wouldn't run -- I saw the concept and ignored the details.

      Rating: 5
Thanks TOM , i
      am thinking about that and reviewing your book  September
      21, 2001
Reviewer:  Jose  from Mcbo-Venezuela

I cant undertsend the really need for creating physicall time dimensions, and
not only for creating time dimensions
but numeric dimensions like meters magnitudes non-linear dimension etc...

      Rating: 5
unsafe
      queries  October 09, 2001
Reviewer:  Mikito
      Harakiri
I came across pipelining today and was going to put the note about unsafe
queries into codetips at oracle magazine, but see that you Tom got it faster.
Here is my interpretation:

CREATE TYPE DummyType AS OBJECT (
  dummy VARCHAR2(1)
);
/
CREATE TYPE DummyTypeSet AS TABLE OF DummyType;
/

CREATE or replace FUNCTION UNSAFE
  RETURN  DummyTypeSet PIPELINED IS
  --out_rec DUAL%ROWTYPE;
  out_rec DummyType := DummyType(NULL);
BEGIN
    loop
    out_rec.dummy := 'Y';
    PIPE ROW(out_rec);
    end loop;
END;
/
SQL>select rownum from TABLE(UNSAFE) where rownum < 10;

    ROWNUM
----------
         1
         2
         3
         4
         5
         6
         7
         8
         9

9 rows selected.

If I don't put the correct predicate, the query would return infinite table.

This unsafe query is much more elegant than cube(2,2,2,2...) or cartesian
products.

The term "unsafe" comes from Constraint Databases and it is basically about
difference operator vs. set
negation. The first one uses an explicit finite universe and the other uses an
implicit potentially infinite universe.

      Rating: 5
Correct
      Query  January 25, 2002
Reviewer:  Srinivasan
      Sankar  from Cambridge, MA USA
Hi Tom,
Can you please let me know the correct syntax for this DIM_TIME query to work?

I'll use this to populate TIME dimension table, say for eg. at the start of
every year.

Thx.........Srini

September 22, 2001 Brian -- Thanks for the question regarding
      "Parallel Execution Option", version 8.1.6

      You Asked
When I look at V$OPTION, I see a parameter named "Parallel Execution".  Is this
the "master switch" for allowing/disallowing parallel execution on a
(non-parallel) server?  On the instances I'm working with, it is always TRUE.
What would be the ramifications of setting it to FALSE (not that I want to)?

      and we said...
That is parallel query, not parallel server.

It enables a sql statement to be executed in parallel -- it will be true on all
Oracle EE (enterprise edition) releases, false on SE (standard) and true on PE
(personal).

You cannot set it to false, it is burned into the kernel itself, it is not
updatable.
Review & Followup

      Rating:
      5
  September 22, 2001
Reviewer:  Brian
      Davies  from Edmonton, Alberta, Canada

September 22, 2001 -- Thanks for the question regarding "DB
      Parameters", version 817

      You Asked
Hi Tom
I have a 6 cpu sun server on which my 817 database is running . The RAM is 4GB
and plenty of storage(500GB).

We run huge queries against our database that take forever to run. Im asked to
do some optimizations. Can you please express your opinions on the following:
1) How big should I size the db_block_buffer. The db is a 32 bit.
2) How many Redo log groups should I have and big should they be. Right now I
have 3 groups with 2 members each.
3)db_file_multiblock_read_count is right now 16 , any disadvt. if I make it 32.

Any other suggestions I should follow.
Appreciate your help.

Thanks
Steve

      and we said...
1) cannot answer that.  What is your current cache hit?  would increasing the
buffer cache even help (if you full scan 100 gig of data, I don't care how big
your buffer cache it - you cannot cache it on your system so no, upping the
buffer cache won't help).  how many users do you have? what else is on the
machine? etc etc etc.

there is no answer for this question without having lots more understanding
about the system itself.

2) if you are a query only system -- redo log size isn't going to affect your
performance.  redo logs are important for OLTP systems, not so much query only
systems.  Unless you see "checkpoint not complete, cannot allocate new log" or
"archival required" messages in your alert log should you look at this in your
case.

3) nope...

Suggestions -- read the tuning and designing for performance guide from cover to
cover.  Use the tools like statspack available to you.

http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/toc.htm
...
Review
      & Followup

      Rating: 4
DB
      parameters  September 26, 2001
Reviewer:
      Anil  from iNDIA
Hi Tom,
Can u give me recommended DB parameters for  16K(DB) Databse

September 22, 2001 sonja -- Thanks for the question regarding
      "Transaction Volumes", version 7.3.4.5

      You Asked
Bit of a stupid question....having only worked on established
databases I've never needed to work this out.
I can't find this info on Metalink or in any of my numerous
manuals.
I need to work out the transaction volumes thru my db btwn
backups (nightly), size of transactions per day, growth per day
and frequency.
I know I can work out frquency and volumes by number of
archivelogs produced daily and then possibly see if over a
number of weeks I'm producing an ever increasing number of
archivelogs.
Is that good enough? -It is oracle that are asking me for these
details.
Am I being too simplistic?
thanks

      and we said...
If you use the utilities:

$ORACLE_HOME/rdbms/admin/utlbstat
$ORACLE_HOME/rdbms/admin/utlestat

it'll capture much of this for you.  You would start the
collection with bstat.  1 day later, run estat to generate the
report.

One of the tidbits of data will be:

Statistic        TotalPer Transact    Per Logon    Per Second
---------- ----------- ------------ ------------ ------------
....
user commits     20026            1         6.49        11.97
user rollbacks      16            0          .01          .01
....

You'll also get lots more like redo blocks written, redo size,
number of IO's etc etc etc....

utlbstat/estat cannot be run across a "bounce" (shutdown and
restart) and don't forget to run utlbstat to restart the stats
collection again.

there is the number of transactions you've done.

Review &
      Followup

      Rating: 4
Transaction
      based on UTLBSTAT and UTLESTAT  September 22, 2001

Reviewer:  Phillip Bruce  from San Jose, CA

Tom,

   Thanks for answering the guys question but I'm running 8.1.7 and ran this
tool and came up with no user rollback.
Is there any reason for this?

          Followup:

Thats OK -- that just means none of your transactions "failed" or were rolled
back in the period of time you were monitoring the database.

Thats "good", perfect in fact.  rolling back is very expensive.

In 817, use STATSPACK instead -- much much better then estat/bstat.

September 23, 2001 Franco -- Thanks for the question regarding
      "Average functions without high and low values", version 8.0.6

      You Asked
I would like to know which is the best way to calculate average values without
including the lowest and the highest value.
Is there a sql function or should I write my own program?
Seems to me that it is a very common situation and so I believe that Oracle
already implemented something

tx
franco

      and we said...
select (avg(x) * count(x) - min(x) - max(x)) / ( count(x)-2 )
  from t

should get that.

Review &
      Followup

      Rating:
      5
Brilliant  September 18, 2001
Reviewer:
      A reader  from Switzerland

      Rating: 5
That is
      brilliant!!!  September 18, 2001
Reviewer:
      MaxU  from Munich, Germany

      Rating: 5
but, why not
      use sum(x) instead avg(x) * count(x) ?  September 20, 2001

Reviewer:  dulm  from BJ, China

          Followup:

sure, why not -- no reason -- avg*count = sum.

      Rating: 4
Very
      Smart  September 22, 2001
Reviewer:  Franco
       from Italy
But why not adding a sql function like;
select avg(x,NoExtremeValues | ExtremeValues)
from t
otherwise
select (sum(distinct x) - min(x) - max(x)) / ( count(distinct x)-2 )
from t
Extreme values can be repetead (very common for bid and ask values on stock
exchanges)
Thanks Tom and reviewers

          Followup:

Well, with 816 and up we can with the analytic functions, for example:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select x,
  2         first_value(x) over (order by x ) first,
  3         first_value(x) over (order by x desc NULLS last ) last
  4    from t
  5  /

         X      FIRST       LAST
---------- ---------- ----------
      1000          1       1000
      1000          1       1000
      1000          1       1000
      1000          1       1000
        50          1       1000
         1          1       1000
         1          1       1000
         1          1       1000
         1          1       1000

9 rows selected.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select avg(x)
  2    from ( select x,
  3                  first_value(x) over (order by x ) first,
  4                  first_value(x) over (order by x desc NULLS last ) last
  5             from t
  6         )
  7   where x <> first
  8     and x <> last
  9  /

    AVG(X)
----------
        50

After throwing out 1 and 1000 we are left with an average of 50...

In 8.0 and before, we could:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select avg(x)
  2  from t
  3  where x <> ( select max(x) from t )
  4    and x <> ( select min(x) from t )
  5  /

    AVG(X)
----------
        50

as well (this will work in 816 and up as well).

Which one performs better will be a matter of the question being asked.  In some
cases, the one with the subquery will be better.  In order to demonstrate this I
set up a small test:

create table t
as
select all_objects.*, object_id x from all_objects;

alter table t add constraint t_pk primary key(x);

analyze table t compute statistics
for table
for all indexes
for all indexed columns
/

And then ran two sets of equivalent queries against it:

select avg(x)
  from t
 where x <> ( select min(x) from t )
   and x <> ( select max(x) from t )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.09          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.07       0.06          0         39          4           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.08       0.15          0         39          4           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 35

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
  16841   FILTER
  16844    INDEX FAST FULL SCAN (object id 18322)
      2    SORT AGGREGATE
      1     INDEX FULL SCAN (MIN/MAX) (object id 18322)
      2    SORT AGGREGATE
      1     INDEX FULL SCAN (MIN/MAX) (object id 18322)

********************************************************************************

select avg(x)
  from ( select x,
                first_value(x) over (order by x ) first,
                first_value(x) over (order by x desc NULLS last ) last
           from t
       )
 where x <> first
   and x <> last

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.03          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.97       0.97          0         35          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.97       1.00          0         35          0           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 35

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
  16841   VIEW
  16843    WINDOW SORT
  16843     WINDOW BUFFER
  16843      INDEX FULL SCAN (object id 18322)

Here the subquery was much more efficient then the analytic function.  This is
due to the fact that the index could be used to very quickly answer the
subqueries and then the index could be used efficiently to answer the entire
query.  With the analytic function -- it was not as effective.  Changing the
question just a little -- to find the average of x with some other where clause
involved:

select avg(x)
  from t
 where x <> ( select min(x) from t where object_name like 'A%' )
   and x <> ( select max(x) from t where object_name like 'A%' )
   and object_name like 'A%'

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.11       0.10          0        738         45           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.11       0.11          0        738         45           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 35

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
    275   FILTER
    278    TABLE ACCESS FULL T
      2    SORT AGGREGATE
    277     TABLE ACCESS FULL T
      2    SORT AGGREGATE
    277     TABLE ACCESS FULL T

********************************************************************************

select avg(x)
  from ( select x,
                first_value(x) over (order by x ) first,
                first_value(x) over (order by x desc NULLS last ) last
           from t
          where object_name like 'A%'
       )
 where x <> first
   and x <> last

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.05       0.05          0        246         15           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.05       0.05          0        246         15           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 35

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
    275   VIEW
    277    WINDOW SORT
    277     WINDOW SORT
    277      TABLE ACCESS FULL T

Now the analytic function starts to become more effective -- since the index
was not nearly as useful this time.

      Rating: 5
response to the
      last review  September 23, 2001
Reviewer:
      raj  from india
good answer by tom.
but tom how did you generate the reports

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.09          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.07       0.06          0         39          4           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.08       0.15          0         39          4           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 35

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
  16841   FILTER
  16844    INDEX FAST FULL SCAN (object id 18322)
      2    SORT AGGREGATE
      1     INDEX FULL SCAN (MIN/MAX) (object id 18322)
      2    SORT AGGREGATE
      1     INDEX FULL SCAN (MIN/MAX) (object id 18322)

********************************************************************************

was it using set autotrace on or using tkprof and sqltrace.

          Followup:

Thats a tkprof report output.  See

http://asktom.oracle.com/~tkyte/tkprof.html
for all of the details.

September 23, 2001 Doug -- Thanks for the question regarding "Using
      aggregates anywhere but first.. seems to be a problem..", version 8.1.7

      You Asked
Tom - a lot of database work I do involves doing things that involve using a
select to generate a list of strings that I can then run.
When doing grants.. I (and probably everyone else) do things like..

select 'grant '||privilege||' on '||table_name||' to newuser;' from
user_tab_privs where grantee='someotheruser'..

This creates a nice spool file I can use when I try to setup grants to a new
user for example.

I run into trouble when I try to do something like:

select 'blahblah'||distinct(grantee) from user_tab_privs;

936-missing expression
Oracle doesn't seem to like distinct, avg, etc., in this kind of string context
unless the aggregate is first in the clause.  This applies to non concatenations
as well. (they're probably the same behavior.. in which case I may have diluted
this issue)
How to get around that?

I can do
select distinct(grantee)||'blahblahblah' from user_Tab_privs,
but not
select 'blahblahblah'||distinct(grantee)..

Thoughts?
Thanks,
Doug

      and we said...
distinct is a modifier to the keyword select -- the queries are:

select ALL .....
select DISTINCT ....

distinct is not a function.  you could

select distinct 'blah blah blah ' || grantee from ....

or...

select 'blah blah blah' || dist_grantee
  from ( select distinct grantee from user_tab_privs )
/

personally, I would use:

begin
  for x in ( select distinct grantee grantee from user_tab_privs )
  loop
    execute immediate 'grant blah blah blah ' || x.grantee;
  end loop;
end;
/

instead of the spool and run these days.  execute immediate makes it really easy
to do now without having to create a spool file.
Review &
      Followup

      Rating: 5
Cleared it
      right up  September 23, 2001
Reviewer:  Doug
      C  from CT, USA
Cleared things right up as ususal.

September 23, 2001 richard -- Thanks for the question regarding
      "dbms_random ", version 8.1.5

      You Asked
Tom,

When I tried to run the pl/sql code on page 439 of your book, I ran into a
number of problems.

1. the dbms_random package (which I knew nothing about before I saw your code)
was not installed on my 8.1.5 windows 2000 system. So I searched the rdbms/admin
dir and found dbmsrand.sql. When I installed it by hand I still had problems,
which I eventually resolved by installing both prvtoctk.plb and dbmsoctk.sql.

Do you have any idea why dbms_rand was not installed automatically? Is there
some optional Oracle feature that I didn't install which dbms_random piggybacks
onto?

2. After I got dbms_installed, I still couldn't get your code to work.
After reading the dbms_random documentation, I saw that dbms_random.initialize()
must be called in order for dbms_random.random to work.

How did you get your code to work without using dbms_random.initialize()?

3. The documentation for dbms_random says that dbms_random.random produces 8
digit integers. After running your code I got the following output

select * from t where rownum<20;

        C1         C2         C3         C4
---------- ---------- ---------- ----------
  43063845   43063845   43063845   43063845
 622214929  622214929  622214929  622214929
-1.525E+09 -1.525E+09 -1.525E+09 -1.525E+09
1132603487 1132603487 1132603487 1132603487
-1.545E+09 -1.545E+09 -1.545E+09 -1.545E+09
  49003024   49003024   49003024   49003024
1378296774 1378296774 1378296774 1378296774
 594469561  594469561  594469561  594469561
-1.471E+09 -1.471E+09 -1.471E+09 -1.471E+09
1419003991 1419003991 1419003991 1419003991
-1.946E+09 -1.946E+09 -1.946E+09 -1.946E+09
-1.486E+09 -1.486E+09 -1.486E+09 -1.486E+09
-951062562 -951062562 -951062562 -951062562
-1.762E+09 -1.762E+09 -1.762E+09 -1.762E+09
 568665466  568665466  568665466  568665466
1497842571 1497842571 1497842571 1497842571
2051839453 2051839453 2051839453 2051839453
-1.017E+09 -1.017E+09 -1.017E+09 -1.017E+09
-1.587E+09 -1.587E+09 -1.587E+09 -1.587E+09

Here we get 10 digit integers (consistent with 32 bit ints) as well as some
negative floating point numbers which look like overflows. Can you check on
this?

My guess is that the person who wrote the routine used 32 bit integer arithmetic
to produce a faulty implementation of a linear congruential generator.

Thanks.

Richard

P.S. A non-technical question. It appears that the questions you put up on your
website are just a subset of all the questions that you answer. It also appears
that at least some of the questions that are put up on a particular day were
submitted and answered weeks before. What is the relationship between the
questions you answer and those that make it to your website?

      and we said...
1) in 8.1.5, dbms_random was not installed by default, you would more easily
install this optional package by running catoctk.sql.  In 817 and up, its
installed in catproc.sql by default.

2) sorry about that.  they removed the need to call initialize in 816 -- I'll
ask them to file an errata sheet for that on the WROX web site.  We tested all
of the examples in 816 and 817 (the supported versions of Oracle at the time of
publication).  I didn't have time to go back to all of the earlier releases...

3) This is documentation bug 1386140, it actually generates random numbers from
8 to 10 digits and may be postive or negative.  If you:

sql> set numformat 99999999999

the numbers will "look normal".  The are just bigger then sqlplus's default
numeric format so it uses exponential notation.

If you see

http://www.oracle.com/oramag/oracle/01-sep/index.html?o51asktom.html
You'll find that new functionality awaits you in the latest release of the
dbms_random package.  Also of note is the addition of a better,
cryptographically secure, random generator in 9i in the dbms_obfuscation_toolkit
package -- designed to generate keys for encryption.

As for the non-technical question....

You are correct -- it is a subset.  In the last 21 months I have recieved 11,547
questions.  Of those, I have deemed 4,245 of them "publishable" (of general
relevance).  So, for every 1 question you see -- there are about 2 more you do
not.  The reasons for not publishing a question vary but by far the most
frequent reason is that my answer to a question with a subject like:

"What does input truncated in sqlplus mean?"

is typically answered with

Well, a simple search for "input truncated" on my site turned up this URL ....

(that is, they didn't bother searching for something easily found).

So, thats the relationship between questions asked and questions appearing here.
 I try to get back to every one that has asked a question (so if you don't hear
from me -- it typically means you typed your email address in WRONG).  I have
mechanisms in place to control the flow of questions so when I travel or have
off site customer visits -- I can shut off questions.  I try to answer
relatively fast (at least in the same day) and can only do that by controlling
the flow of questions.

As for "old questions" showing up as "new ones", that'll happen whenever I
update a question.  I keep two dates on all questions -- the time of submission
and the time I last updated it.  If someone makes a comment on an old question
and I feel I have something to add to it -- I'll comment on their comment.
That'll make the question appear back on the front page -- to be aged off as I
answer other questions.

Review &
      Followup

      Rating: 5
completely
      addressed all issues in a very timely manner. Thank
      you  September 23, 2001
Reviewer:  richard
      gostanian  from salem. nh

September 23, 2001 -- Thanks for the question regarding "Outer
      Joins", version 8.x

      You Asked
I have 2 tables:

table T1
=========
abc   10
def   20

table T2
========
abc   33
xyz   44

I need a single SQL statement to produce the output as follows:

abc   10      33
def   20     (null)
xyz  (null)   44

Thanks in advance.

      and we said...
The first three queries work in all releases (and undoutably there are other
ways to do this -- these are just the first three I came up with).  The fourth
is unique to 9i and up using the new "full outer join" syntax:

ops$tkyte@ORA9I.WORLD> select t1.x, t1.y, t2.y
  2    from t1, t2
  3   where t1.x = t2.x (+)
  4   union all
  5  select t2.x, to_number(null),  t2.y
  6    from t2
  7   where not exists ( select null from t1 where t1.x = t2.x );

X            Y          Y
--- ---------- ----------
abc         10         33
def         20
xyz                    44

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> select t1.x, t1.y, t2.y
  2    from t1, t2
  3   where t1.x = t2.x (+)
  4   union all
  5  select t2.x, t1.y, t2.y
  6    from t1, t2
  7   where t2.x = t1.x(+)
  8     and t1.y is null
  9  /

X            Y          Y
--- ---------- ----------
abc         10         33
def         20
xyz                    44

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> select t1.x, t1.y, t2.y
  2    from t1, t2
  3   where t1.x = t2.x (+)
  4   union all
  5  select t2.x, to_number(null),  t2.y
  6    from t2
  7   where x in ( select x from t2 MINUS select x from t1 )
  8  /

X            Y          Y
--- ---------- ----------
abc         10         33
def         20
xyz                    44

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> select nvl(t1.x,t2.x), t1.y, t2.y
  2    from t1 FULL OUTER JOIN t2 on t1.x = t2.x
  3  /

NVL          Y          Y
--- ---------- ----------
abc         10         33
def         20
xyz                    44

Review &
      Followup

      Rating:
      5
  September 23, 2001
Reviewer:
      A reader  from Chapel Hill, NC
The respone was amazingly prompt and detailed. Really appreciate the initiative
in offering the solution for 9i too.

September 23, 2001 -- Thanks for the question regarding "utl_file",
      version 8.17

      You Asked
I try to run the output of my stored procedure into a .txt file. I am in the
client machine. my operating system is NT. I also need to use DBMS_JObS package
to schedule a job to run in first day of every month (excluding holiday and
weekends).

My first question is How to dump my output of stored procedure into .txt file in
Client machine and NT os? IF I use utl_file I still need to use DBMS_output
package?

Second question is How can I schedule a job run in the first day of every month
(not in weekends and holiday)?

      and we said...
UTL_FILE can and will only write to files accessible on the server.  UTL_FILE is
run IN the database.

DBMS_JOB can and will only produce output on the server -- there is no way for
DBMS_JOB to create output on the client at all.  The job is running physically
on the server (both the client and the server part).

In order to dump the output of a stored procedure to a text file on NT you would
have to

1) run the stored procedure interatively using a tool like sqlplus.
2) have the stored procedure use dbms_output
3) issue "set serveroutput on size 1000000 format wrapped" or something
equivalent in sqlplus before running it.
4) issue "spool filename"
5) run the procedure

search for dbms_job on my site for examples of using dbms_job -- there are many.
 Also my book has a pretty good chapter on dbms_job as well.  One way to
accomplish what you want to do (run on the first "business day" would be to
allow the procedure to procedurally determine the next day it wants to run
itself using whatever complex logic you want.  For example, say your job is "P".
 Code P as :

create or replace procedure p( p_next_time OUT date )
is
begin
    p_next_date := your_complex_logic;
    .... your regular code here ....
end;

and schedule the job using:

declare
   l_job number;
begin
   dbms_job.submit( l_job, 'p(NEXT_DATE);', to_date( '01-oct-2001' ) );
end;
/

(this is explained in total detail in my book, see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1370203336551
for a good idea of who this works as well)

Review &
      Followup

      Rating: 3
Use
      nfftp...  March 07, 2002
Reviewer:  Siva
      Jonnala  from CA USA
Alternatively, you can spool the file to a text file and then have a OS job that
will remote copy the file from Server/Unix machine to NT machine...

Regards,
Siva


Subject | Article | Last Updated (East coast time)
Restructure Table | article only | Sep 24, 2001 08:05 am
How to compile pro*c which connects to 2 database | article only | Sep 24, 2001 08:27 am
Standby Database | article only | Sep 24, 2001 09:27 am
Returning CLOB from PL/SQL Function | article only | Sep 24, 2001 09:49 am
Missing stats after ALTER TABLE MOVE | article only | Sep 24, 2001 12:56 pm
Partitioning tables forces Cost Based Optimizer use during queries? | article only | Sep 24, 2001 01:07 pm
A few questions | article only | Sep 25, 2001 06:11 am
Rollback Segments | article only | Sep 25, 2001 06:23 am
List subscribers in advanced queue | article only | Sep 25, 2001 06:27 am
Contsraints/nested sql | article only | Sep 25, 2001 06:46 am
Date Conversion | article only | Sep 25, 2001 08:38 pm
Just some questions | article only | Sep 25, 2001 09:38 pm
SQL Reuse | article only | Sep 26, 2001 08:07 am
import delimited text file using utl_file | article only | Sep 26, 2001 06:41 pm
update of self referencing table | article only | Sep 27, 2001 08:20 am
Specifying schema name when creating ddl trigger | article only | Sep 27, 2001 10:22 am
partition questions | article only | Sep 27, 2001 02:13 pm
GRANT OBJECT PRIVILEGES FROM PACKAGES using dynamic sql | article only | Sep 27, 2001 04:15 pm
equality predicate on clob | article only | Sep 28, 2001 06:58 am
2 questions | article only | Sep 28, 2001 07:04 am
Import - extent question | article only | Sep 29, 2001 03:42 pm
UTL_FILE | article only | Sep 29, 2001 08:34 pm
definition of user defined roles | article only | Sep 30, 2001 12:55 pm
row(s) 1 - 23 of 23
September 24, 2001 Dudley -- Thanks for the question regarding "Restructure Table", version 7.3
You Asked
I just wonder if its possible to restructure the sequence of columns in a table?
example

TABLE_1
--------
FIRST_NAME
LAST_NAME
TEL
ADDRESS
CITY
ID

AND CONVERT INTO THIS

TABLE_1
--------
ID
LAST_NAME
FIRST_NAME
ADDRESS
CITY
TEL
and we said...
rename table_1 to table_1_TBL;

create view table_1 as select id, last_name, first_name, address, city, tel
from table_1_tbl;

do the grants on the view.

No one will be the wiser  -- they will not be able to tell the view apart from
the table.

short of that, dropping and recreating the table is the only way.  Note that it
would be considered a "bad" practice to rely on the order of the columns in the
table as that is an accidently side effect (that a select * or insert into
values just happens to use them in that order) and not really a defined
behavior.  Applications should ALWAYS use explicit column names in the selects
and insert statements.  ALWAYS.
September 24, 2001 -- Thanks for the question regarding "How to compile pro*c which connects to 2 database", version 8.0.6
You Asked
Hi Tom,
I have questions about pro*c compilation :

1. I need to compile a pro*c program which calls stored procedures from 2
different dbs. So I need to checks the sql semantics during compilation. I can
only define one userid as below:

PROC_ENV_FLAGS = sqlcheck=full userid=$(USERID)

So how can I pass in the other userid/passwd@dblink to the compiler?

2. To avoid having to create a makefile for each source file, How can I pass in
a source program as a parameter(cc_Common.pc) into the following makefile, eg.
make cc_Common.pc:

#setenv ORACLE_PROC_MAKEFILE $ORACLE_HOME/precomp/demo/proc/demo_proc.mk
#
#

ORACLE_PROC_MAKEFILE = $(ORACLE_HOME)/precomp/demo/proc/demo_proc.mk

#name of program I want to create
PROG = cc_Common

#list of .pc files I need to precompile/compile
SOURCE = cc_Common.pc

OBJ = cc_Common.o

.pc.c:
    $(PROC) $(PROCFLAGS) iname=$*

.pc.o:
    $(PROC)    $(PROCFLAGS) iname=$*
    $(CC) $(CFLAGS) -c $*

.c.o:
    $(CC) $(CFLAGS) -c $*

#$(TARGET): $(SOURCE) $(SOURCE:.pc=.c) $(SOURCE:.pc=.o)
#    $(CC) $(LDFLAGS) -o $(TARGET) \
#    $(SOURCE:.pc=.o) -L$(ORACLE_HOME)/lib $(PROLDLIBS)

include $(ORACLE_PROC_MAKEFILE)
USERID=ccdev/ccdev

#any settings I want to override at make time for ProC

PROC_ENV_FLAGS = sqlcheck=full userid=$(USERID)

#any setting I want to override at make time for CC
CC_ENV_FLAGS =

PROCFLAGS=ireclen=255 lines=yes $(PROC_ENV_FLAGS)
#    include=$(INCLUDE)

PROFLAGS=$(PROCFLAGS)

CFLAGS= -I. -g $(CC_ENV_FLAGS) $(INCLUDE)

install: $(TARGET)
    $(CP) $(TARGET) $(HOME)/lib

Thanks.
and we said...
1) you could create a "dummy" procedure by the same name in the one database.

Another method I like to use that allows you to fully bypass this sqlcheck step
(greatly increasing the speed with which you can compile your code) is to use
dynamic sql like this:

static void process( int data )
{
static int firstTime = 1;

int     x;
char    stmt[255];

    if ( firstTime )
    {
        strcpy( stmt, "begin p(:x); end;" );
        exec sql prepare s from :stmt;
        exec sql declare c cursor for s;
        firstTime = 0;
    }

    exec sql open c using :data;
}

Now you can call process over and over and over again and it'll execute your
procedure.  No need to sqlcheck=semantics.

the only restriction is -- no plsql tables in dynamic sql.  If you just use
scalars, this works nicely.

2) I use this makefile:
http://osi.oracle.com/~tkyte/proc_makefile/
and then a "procmk" script that is:
--------------------------------------------------------------------
SRC=`echo *.pc`
TGT=`pwd | sed 's".*/""'`

echo SRC = $SRC
echo TGT = $TGT
echo Remember you can set PROC_ENV_FLAGS to pass things to ProC
echo Remember you can set CC_ENV_FLAGS to pass things to CC

make -f /export/home/tkyte/bin/proc.mk "SOURCE=$SRC" "TARGET=$TGT"
--------------------------------------------------------------------

that just takes all of the .pc files in a directory, precompiles/compiles them,
builds the executable and names it after the directory you are working in.
Review & Followup
Rating: 3
How about calling a function which returns a value? September 24, 2001
Reviewer: Jesse
That works for calling a procedure. How about calling a function which returns a
value? Thanks.

Followup:
No problem -- its the same:

static void report( void )
{
static int firstTime = 1;

int     data;
char    stmt[255];

    if ( firstTime )
    {
        strcpy( stmt, "begin :x := f; end;" );
        exec sql prepare s2 from :stmt;
        exec sql declare c2 cursor for s2;
        firstTime = 0;
    }

    exec sql open c2 using :data;
    printf( "There are now apparently %d rows in T\n", data );
}

The using clause binds positionally and supports IN, IN OUT, and OUT parameters
to the anonymous block.

I used:

drop table t;

create table t ( x int );

create or replace procedure p( p_data in number )
as
begin
    insert into t values ( p_data );
end;
/

create or replace function f return number
as
    l_data number;
begin
    select count(*) into l_data from t;

    return l_data;
end;
/

to test the above routines with and called them like this:

main( argc, argv )
int argc;
char *  argv[];
{
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR   oracleid[50];
EXEC SQL END DECLARE SECTION;

    strcpy( oracleid.arr, USERID );
    oracleid.len = strlen(oracleid.arr);

    EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();
    EXEC SQL CONNECT :oracleid;
    printf("\nConnected to ORACLE as user: %s\n\n", oracleid.arr);

    process(1);
    report();
    process(2);
    report();
    process(3);
    report();

    /* Disconnect from ORACLE. */
    EXEC SQL COMMIT WORK RELEASE;
    exit(0);
}

running this shows me:

$ ./t

Connected to ORACLE as user: /

There are now apparently 1 rows in T
There are now apparently 2 rows in T
There are now apparently 3 rows in T

$ ./t

Connected to ORACLE as user: /

There are now apparently 4 rows in T
There are now apparently 5 rows in T
There are now apparently 6 rows in T

$ ./t

Connected to ORACLE as user: /

There are now apparently 7 rows in T
There are now apparently 8 rows in T
There are now apparently 9 rows in T

September 24, 2001 Yogesh -- Thanks for the question regarding "Standby Database", version 8.1.7
You Asked
What are the different ways do deploy standby database ?
and we said...
In 817 -- you can either deploy a managed standby where by the ARCH process
delivers redo log files over the network to another system (requires enterprise
edition) or you can move the archived redo log files yourself (non-managed
standby).

In either case, the standby database is running in "recovery mode" -- meaning it
is applying archives as they are recieved normally.

The standby database may be opened READ ONLY for queries and such in 8i.  When
the standby is opened read only, it is not applying archive redo log (eg: the
logs are being collected but not applied).

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76995/toc.htm
for all of the details.
Review & Followup
Rating: 4
Standby Database September 24, 2001
Reviewer: Yogesh Bhandarkar from INDIA, Pune
Many Thanx. Reply had given me a right direction, now I can start working on
these lines.

September 24, 2001 Brian -- Thanks for the question regarding "Returning CLOB from PL/SQL Function", version 8.1.7
You Asked
I have been through the documentation and I am still not clear on something that
is critical for me to understand before deploying into a production environment.

I have created the following function - the cursor query is just an example of
creating a small resultset so I can experiment with concatenating varchar2
values and return a single clob:

create or replace function testclob return clob
as
    v_clob clob;
begin
    dbms_lob.createtemporary(v_clob,FALSE,DBMS_LOB.CALL);
    dbms_lob.open(v_clob,dbms_lob.lob_readwrite);
    for val in (select 'abc' colalias from dual union
                select 'def' colalias from dual union
                select 'ghi' colalias from dual)
    loop
        dbms_lob.writeAppend( v_clob, length(val.colalias), val.colalias );
    end loop;

    return v_clob;
end;

Because I am actually returning the clob, I am not executing the following
within the function:

    dbms_lob.close(v_clob);
    dbms_lob.freetemporary(v_clob);

I test this from sql/plus as follows:

variable c clob
exec :c := testclob
print c

I get the expected result.  However, when I execute

select * from v$temporary_lobs

it seems that with each call I make within the same sql/plus session, the count
of nocache_lobs goes up instead of remaining at 1.

Bottom line, I have a java JDBC client that will be calling a function like the
above but the session will remain open between calls.  I need to make sure I
handle scope correctly so that memory usage doesn't grow over time.

How do I return the clob and have it free up appropriately?

Please help me understand my options in this kind of scenario.

Thanks - Brian
and we said...
From the application dev guide on LOBS:

<quote>
Note: The DBMS_LOB.CREATETEMPORARY procedure takes an
optional duration parameter. In PL/SQL, this duration parameter is
used only as a hint about the duration of the LOB data. PL/SQL
calculates the duration of the LOB data internally, taking into
account your hint. You do not have to specify the duration of the
LOB data!
</quote>

In your case, it is a good thing it does this -- since you return the LOB to the
client -- a scope of "CALL" is inappropriate for you.  The call is the call to
the function.  If PLSQL did not recognize you were returning the CLOB and
actually freed it as requested -- the caller would have nothing to print!

If your goal is to use one LOB per session you must either:

o free the LOB when you are done.  Just as you would close a file when you are
done reading it, or a cursor when you know you won't need it anymore

o use a single LOB in a package.

To use a single LOB in a package, you would code:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace package testclob_pkg
  2  as
  3
  4      function testclob( p_data in varchar2 ) return clob;
  5
  6  end;
  7  /

Package created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace package body testclob_pkg
  2  as
  3
  4  g_clob     clob;
  5
  6
  7  function testclob( p_data in varchar2 ) return clob
  8  as
  9  begin
 10      dbms_lob.trim( g_clob, 0 );
 11      for val in (select p_data colalias from dual union all
 12                  select ' abc' colalias from dual union all
 13                  select ' def' colalias from dual union all
 14                  select ' ghi' colalias from dual)
 15      loop
 16          dbms_lob.writeAppend( g_clob, length(val.colalias), val.colalias );
 17      end loop;
 18
 19      return g_clob;
 20  end;
 21
 22
 23  begin
 24      -- elaboration code, run once when package
 25      -- is first accessed in a sesion
 26      dbms_lob.createtemporary(g_clob,FALSE);
 27      dbms_lob.open(g_clob,dbms_lob.lob_readwrite);
 28  end;
 29  /

Package body created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from v$temporary_lobs;

no rows selected

ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2      l_clob clob;
  3  begin
  4      for i in 1 .. 10
  5      loop
  6          l_clob := testclob_pkg.testclob( 'loop ' || i  || ',' );
  7          dbms_output.put_line( dbms_lob.substr( l_clob, 250, 1 ) );
  8      end loop;
  9  end;
 10  /
loop 1, abc def ghi
loop 2, abc def ghi
loop 3, abc def ghi
loop 4, abc def ghi
loop 5, abc def ghi
loop 6, abc def ghi
loop 7, abc def ghi
loop 8, abc def ghi
loop 9, abc def ghi
loop 10, abc def ghi

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from v$temporary_lobs;

       SID CACHE_LOBS NOCACHE_LOBS
---------- ---------- ------------
        14          0            1

(don't use sqlplus variable commands to test this particular one -- sqlplus is
allocating its OWN lobs as well).
Review & Followup
Rating: 5
Excellent - clear and educational on multiple fronts September 24, 2001
Reviewer: Brian White from Rockville, MD USA
As with many questions on this forum, the answer highlights techniques that will
prove generally useful and is explained in a way that provides true education.
I've learned so much by reading Tom's new book in conjunction with reviewing the
questions answered in this forum.

Rating: 5
Very very Good Example! December 16, 2003
Reviewer: Olga from Vienna
Yes, Tom is great!

Reading Tom's Books and his web-site is better than any ocp course, i bet!
That's Oracle live and no pseudo science. I spent so much money for Oracle books
where the pages were full of nothing (like a HTML-Reference in a JAVA-Book), now
I chucked them away.

Many Thanks Tom!

September 24, 2001 James -- Thanks for the question regarding "Missing stats after ALTER TABLE MOVE", version 8.1.6
You Asked
Hi Tom,

I suspect a ALTER TABLE MOVE actually Drops the table at some
point as table statistics go missing. (Test Case results follow)

I have tried SQL_TRACE and LOG_MINER to verify my theory
Is there anyway you know that would tell me what Oracle is actually
running behind the scenes

Well done on a great book it has been VERY helpful.
I recommend it as a must have for anyone working with Oracle.

Regards

Jim

Connected to:
Oracle8i Enterprise Edition Release 8.1.6.0.0 - Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production

SQL> create table test_move as select * from dual;

Table created.

SQL>
SQL> analyze table test_move compute statistics;

Table analyzed.

SQL>
SQL> select to_char(last_analyzed,'DD-MON-YYYY HH24:MI:SS')
  2  from dba_tables
  3  where table_name = 'TEST_MOVE';

TO_CHAR(LAST_ANALYZE
--------------------
24-SEP-2001 13:50:52

SQL>
SQL> alter table test_move move tablespace t_various1;

Table altered.

SQL>
SQL> select to_char(last_analyzed,'DD-MON-YYYY HH24:MI:SS')
  2  from dba_tables
  3  where table_name = 'TEST_MOVE';

TO_CHAR(LAST_ANALYZE
--------------------

SQL>
and we said...
It does not drop the object (things would go totally invalid and they do not --
just indexes are marked unusable).

It drops the stats because things like the cluster factor of indexes would
change, the rows/block will change, the amount of chaining will change, the
number of blocks below the HWM will change, etc etc etc -- most of the stats
themselves are rendered invalid.
Review & Followup
Rating: 3
What does it do then ? September 24, 2001
Reviewer: James
Thanks...
The reason I thought a drop must be occuring is because
of a comment from Oracle Support found on Metalink

"The alter table move internally does a 'create table as select' which cannot be
used with long/long raw columns. "

If the table move actually does do a CREATE table AS SELECT
then surely something must get Dropped else there will be 2
copies of the table. Good point about the invalidation of objects though...

So was Oracle Support mistaken ? ...

Followup:
No, support is not mistaken and neither am I.  It just isn't really "dropping"
the table is all.  It creates a new copy into temp extents -- updates the data
dictionary to swap the temp extent with the permanent extents -- and then
removes the temporary extents (which were the OLD table extents).

It does not do a "drop", that would lose grants and everything else.

Rating: 3
What does it do then ? September 24, 2001
Reviewer: James
Thanks...
The reason I thought a drop must be occuring is because
of a comment from Oracle Support found on Metalink

"The alter table move internally does a 'create table as select' which cannot be
used with long/long raw columns. "

If the table move actually does do a CREATE table AS SELECT
then surely something must get Dropped else there will be 2
copies of the table. Good point about the invalidation of objects though...

So was Oracle Support mistaken ? ...

Rating: 5
That explains it September 24, 2001
Reviewer: James
Thanks Tom !

I think the action you is being shown in
the output from a log miner session !

September 24, 2001 -- Thanks for the question regarding "Partitioning tables forces Cost Based Optimizer use during queries?", version 8.0.5
You Asked
I restructured a table partitioning it. Generally speaking, after the change,
queries (from Business Objects) works faster and daily update jobs too.

One of the commonly used query results really slow. The instance optimizer goal
is RULE. No hints are used. As far as I know (instance DBA are another "parish")
nothing else has been changed (or should be so), but the query plan is
substantially different (worse) from the old one (pre-partitiong). Using SQL
TRACE the problem seems to be a change joining with a view. The old plan was
doing it with sort/merge (outer). The new one use nested loop (outer).

Providing up to date statistics change the explain plan (with extended use of
hashing) much improving the query perfomance.

The problem is that most of the accessed tables are central to a lot of
applications. All the appplications are "tuned" for RULE (or not but performance
are known) and a change to Cost Based Optimizer will require extra impact
analysis the customer would not do (at least not immediately).

I was not able to find an answer in the standard documentation, so here is my
question.

Does partitioning a table "forces" Oracle to use cost based optimizer accessing
that table?

Thank you.
Maurizio De Giorgi.
and we said...
Yes, almost every new feature (function based indexes, bitmap indexes,
partitioning, etc etc etc) added since version 7.3 of the database requires the
use of the COST based optimizer.  The Rule based optimizer is not being enhanced
to recognize these new features -- only the CBO.
Review & Followup
Rating: 2
I am really a bullhead September 24, 2001
Reviewer: Maurizio De Giorgi from ITALY
... "almost every new feature...requires the use of the COST based
optimizer."...

Does it means that Oracle will ONLY AND ALWAYS USE CBO instead of RBO when
accessing a partitioned table just because of partitioning?

Does it means this apply to every new features used?

Thanks.
Maurizio De Giorgi.

Followup:
Sorry -- i was not clear in the response.

A query against a partitioned table will use the CBO - regardless of any setting
- since the RBO doesn't understand anything about a partitioned table.  Just
like having a table with a default degree of parallelism > 1 will use the CBO
regardless of any other settings (since the RBO doesn't understand parallelism
either).

It does not apply to every new feature.  For example, the existence of a bitmap
index on a table does not force the CBO however in order to use the bitmap you
must be using the CBO.

Rating: 4
Such a shame. September 24, 2001
Reviewer: Maurizio De Giorgi from ITALY
I have always thought that in order to actually (and properly) use the new
features it must be used the CBO (setting the optimizer goal to CHOOSE, ALL_ROWS
or FIRST_ROWS or by using hints).

At the same time, I have always thought that using RULE as optimizer goal would
cause Oracle to default to RBO except in the cases expressly referenced in the
product documentation.

I would never thougth I was exchanging the symptoms with the causes.

I am seriously considering to devote my life to horse breeding.

Thank you for the clarification.

Followup:
Well, if you want to mince words -- it is true (in my mind anyway) that "in
order to actually use the new features, it must be used by the CBO".

In order to USE partition (not gain benefit from it -- just to USE it) you must
be using the CBO.  In RBO -- that partitioned table just does not exist.

September 25, 2001 -- Thanks for the question regarding "A few questions", version 817
You Asked
Hi Tom
I have been doing some research on using LMTs for my new DSS database. After
going through several of your articles on LMTs I have come to the following
conclusion:

I will create 3 Small,Medium and Large Locally managed data tablespaces with
Uniform Extents as follows:
64k extents
1m extents
128m extents

And Similarly for the Index Tablespaces.

My questions
1)So whenever I create any object in any of the above tblsps I dont have to
specify the Initial,next , minextents, maxextents and PCTIncrease. I only
specify the PCTUSED & PCTFREE depending on the object usage.

2)I also notice you recommend that extents in hundreds are acceptable but not
thousands . So how should I reorganize my table if its extents reach 1000s of
extents. In dict managed tblsps I export the table and import it back with
compress=y. Can I do the same with a table in a LMT?

3) Are there any issues with Importing from Dict managed tblsp to LMT and the
other way around?

Partitions
4)If I have to use partitions in my design can I partition some tables where I
expect huge historical data and leave other smaller lookup tables as non
partitioned?

5) I read the following somewhere:
If a partition is made on a column having Date datatype , its partition
description should use To_Date format ; otherwise partition pruning is not
possible.
What is the partition description being mentioned? And what is partition
pruning?

Java_pool_size

6)We are not storing java objects in the database. Our Java application accesses
the database for loading the GUI and for other functions. So should I allocate
java_shared_pool more than the minimum of one MB?When should the default 20MB be
allocated?

7)In one of your answers you have said
"The Java pool is a fixed amount of memory allocated for the JVM running in the
database."
Is it mandatory for us to install the JVM in 8.1.7 if we are not using the
database for storing java objects but just want to use the 817 version?

8) Since Im not using MTS ,RMAN etc. I am setting the large_pool_size to zero.
Since the large_pool is zero now Should I set values for
shared_pool_min_allocation and shared_pool_reserved_size?

Thanks
Steve
and we said...
1) correct.

2) even easier - ALTER TABLE want_to_reorg MOVE tablespace new_tablespace;  In
9i, this can be done online with the dbms_redefinition package as well (allowing
concurrent inserts/updates/deletes to take place whilst you move the object)

3) Watch out when you go from DMT to LMT.  There will be initial, next,
minextents and so on.  They are no totally ignored.  If the initial was 50meg
(due to compress=y or something on the export or just bad sizing) and you import
into an LMT with 1m extents - you'll get 50 1meg extents.  It'll use INITIAL to
grab so much space.  Same with maxextents -- it'll figure out how much space the
DMT would have grabbed and get that much (or more) in the LMT for you.

4) absolutely.

5) They are talking about RANGE partitions.  For example:

CREATE TABLE partitioned
( x int,
  y int,
  z DATE
)
PARTITION BY RANGE (z)
(
PARTITION part_1 VALUES LESS THAN(to_date('01-jan-1995','dd-mon-yyyy')),
PARTITION part_2 VALUES LESS THAN(to_date('01-jan-1996','dd-mon-yyyy')),
PARTITION part_3 VALUES LESS THAN(to_date('01-jan-1997','dd-mon-yyyy'))
);

the partition definition is in bold.

Partition pruning is also known as partition elimination.  It is when we look at
a query like:

select * from partitioned where z = to_date( '01-jan-1994', 'dd-mon-yyyy' );

here we can eliminate partitions part_2 and part_3 from consideration (prune
them)

6) the minimum will suffice if you do not use java yourself.  It is used when
you actually run java in database itself (java stored procedures, ejbs, etc)

7) it is not mandatory to install the jvm, no

8) let them default.  If you are not using things that do large memory
allocation (what those are for) you probably need not touch them.
Review & Followup
Rating: 4
reader September 25, 2001
Reviewer: Nikunj from India
about partitioned table

as u had given example on table partioning
if my some query used the date betweeen 2 or 3 months
i.e.

select * from partitioned where z between to_date( '01-jan-1994', 'dd-mon-yyyy'
) and to_date( '01-mar-1994', 'dd-mon-yyyy' );

then partion is recommanded or not ?

Followup:
Sure, that can take advantage of partition elimination -- that would be useful
with partitions.

Remember -- partitions are mostly about ADMINISTRATION.  Even if that particular
query did not benefit from partitioning, partitions may very well be called for.

September 25, 2001 -- Thanks for the question regarding "Rollback Segments", version 8.1.6.3.4
You Asked
Tom,

In the Oracle Performance Tuning Tips & Techniques book from Oracle Press by
Richard J. Niemiec, Chapter 10 states:

"It is a little known fact that Oracle uses rollback segments during the usage
of cursors--even if DML statements are not being issued from within the cursor
loop.  The rollback segments are being used as a type of work area as a cursor
loop is executed."  I am working on the implementation of a COTS product that
uses cursors very heavily.  Could you please confirm the information provided
and also provide further information on this?
and we said...
I think (not having the book and just having a single paragraph out of context)
Richard is talking about Multi-versioning and read consistency (hardly a "little
known fact" in my opinion is that is the case -- it is one of our cornerstone
features, something that truly sets Oracle apart from the other databases).

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c23cnsis.htm#17882
for the details.  If that is not the case, followup with more context from the
book...
Review & Followup
Rating: 3
Reader September 25, 2001
Reviewer: Reader from USA
Tom,

Could you give an explanation why Rollback is created
for select statement on remote database using database
links. It is usually only one block (used_ublk, used_urec
from v$transaction, 1 each)

Thanks

Followup:
It is setting up for a possible distributed transaction.

September 25, 2001 paul -- Thanks for the question regarding "List subscribers in advanced queue", version 8.17
You Asked
I need to enquire which agents (subscribers and publishers) are currently active
on any queue ?? I think Enterprise Manager shows some status but im not sure
and we said...
I asked our resident AQ experts Julie Wells and Derrick Lawson and they say:

Hi Tom,

In order to find all of the subscribers for a queue:

select * from AQ$aud$audit_qt_S;
select * from AQ$[QUEUE_TABLE]_S;

Any application or user that has enqueue privileges can publish messages to the
queue by invoking an enqueue call.  The database administrator has the option of
granting the system privileges ENQUEUE ANY QUEUE and DEQUEUE ANY QUEUE,
exercising DBMS_AQADM.GRANT_SYSTEM_PRIVILEGE and
DBMS_AQADM.REVOKE_SYSTEM_PRIVILEGE directly to a database user, provided that
the user should have this level of control. A developer can give rights to a
queue by granting and revoking privileges at the object level by exercising
DBMS_AQADM.GRANT_QUEUE_PRIVILEGE and DBMS_AQADM.REVOKE_QUEUE_PRIVILEGE.   These
privileges can be selected from the sys tables as follows:

select * from dba_sys_privs where grantee = 'THINKER';

GRANTEE                        PRIVILEGE                                ADM
------------------------------ ---------------------------------------- ---
THINKER                        DEQUEUE ANY QUEUE                        NO
THINKER                        ENQUEUE ANY QUEUE                        NO
THINKER                        MANAGE ANY QUEUE                         NO

If you have any more questions, please let us know.

Thanks!

Julie and Derrick
Review & Followup
Rating: 4
how do I schedule to all the site September 21, 2001
Reviewer: Ak from India
Hi,
  I have a queue and the data has to be propagated to 100 sites.i can set
job_queue_process=36(maximum).when i schedule to say, 4 sites and
job_queue_process 15 it works,gradually i increase it to 10 sites with same
number of job_queue_process..it doesn't work,again i change job_queue_process it
works...but my problem is i have too
many sites(more than 100),but oracle has limit of 36.so how
do i accomplish my work...can you guide me on this.
Thanks

regards
 ak

Followup:
I'm sorry but statements like "but it doesn't work" are really way too vague to
even guess at what the issue might be.

I recomend you contact support and open a TAR.  They will extract from you
sufficient information to formulate an answer.

Just fyi, in 9i, the job queue processes can go to 1,000 (but to propage to 100
sites you really only need 1 queue process, there is no reason why it would not
work with 1)

Rating: 3
job queue September 23, 2001
Reviewer: Ak from India
Hi tom,
   want i meant with the term "it doesn't work" is message
doesn't get propagated to all the sites.when i increase the
job_queue_process,it DOES WORK,which clearly means it has
something to do with job_queue_process.what i personally
believe is, when SNP0 takes up the job,after finishing it
should be free for next job...which it doesn't(i believe so).Likes wise it takes
up all the snp background process
assaigned.Can you comment something on this ..!!
Please let me know if you require any extra info..
Thanks

Regards
  Ak

Followup:
I'll have to suggest you contact support and open a TAR on this one.  It should
not matter whether you have 1 or 10 queue processes -- they should all get
propagated.  If they are not, there is either a configuration or setup problem
somewhere.

Rating: 2
simple example` September 24, 2001
Reviewer: A reader
Tom

Can you give a simple illustrated example , as you always do and display the use
of dbms_aq package.

you cant cover everything , we understand, but a simple example will help.

Followup:
AQ is somewhat bigger then a breadbox -- hard to get a concise, small example.
For this one, I'll suggest you look at the sample application found in
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76938/toc.htm
If you have a specific question about how something works in it, I'll be glad to
follow up.

The problem with a "small" AQ example is that you need a queue, a queue
producer(s) -- something to generate queue messages, a queue consumer, and so
on.  It gets big fast.

September 25, 2001 Brian -- Thanks for the question regarding "Contsraints/nested sql", version 8.1.6
You Asked
Tom,

Table:

a
-
id
text
email
date_joined

I am getting a bit bogged down with my SQL.

What I want to retrieve is the email, date_joined (which may be several), and
the ids of all people who have more than one entry in the the table (basing the
user to the be the same if the same email address is entered)

The following query returns me all people and the number os ids they have, but
when I try to see dates I start to get errors

SELECT upper(email), count(id) FROM a having count(id) > 1 group by upper(email)
order by 2 desc;

Also, can you explain why the following query is not correct?

SELECT count(distinct(email)) FROM a having count(members_id) > 1

This returns the same as:

SELECT count(distinct(email)) a;

Also,are the following a full list of all possible user constraint_types

P - primary key?
C - check?
R - foreign key?
U - unique ?

And what are their full meanings?
Are the dab constraint_types the same?

Thanks a lot

Brian
and we said...
Well, you would want:

select *
  from a
 where exists ( select NULL
                  from a a2
                 where a2.email = a.email
                   and a2.rowid <> a.rowid )

That'll find every row such that there is another row (different rowid) with the
same email.

As for why the two queries return the same answser -- it must be that every
email has more then one row with the same members_id (a new column just added to
the example)

As for the constraints -- I just answered that question in the last question.
Please try not to repeat questions like that...
September 25, 2001 Vasu -- Thanks for the question regarding "Date Conversion", version 8.0.4
You Asked
Hello Tom,

 Here is my problem, in my table the date data is in numeric format due to
number data type. I want to write an query which will retrieve one year back
data from today.
 I tried this query
 select ....
 from ...
 where
 to_date(a.eff_date,'yyyymmdd') between sysdate and (sysdate - 360)
 and ...

 But I am not getting the result which I am interested. NLS_DATE_FORMAT is
yyyymmdd.

 Could you please help me out in this?
Thanks,
Vasu
and we said...
your between variables are backwards.  It is "between LOW and HIGH", you have
"between HIGH and LOW"

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from dual where dummy between 'Z'
and 'A';

no rows selected

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from dual where dummy between 'A'
and 'Z';

D
-
X

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

btw: a better way might be:

select * from t
where eff_date >= to_number(to_char(add_months(sysdate,-12),'yyyymmdd'))

That is -- subtract 12 months from sysdate, turn THAT into the number and then
compare.  In this fashion, if there is an index on eff_date -- it can be used.
Review & Followup
Rating: 4
Nice One September 24, 2001
Reviewer: Vasu Kher from Louisville,KY,USA
It was a nice and very quick response. Thanks.

Rating: 3
Nicely done! September 24, 2001
Reviewer: Trevor from UK
I like the use of ADD_MONTHS function and a negative number.
The number of days in a year may not always be 365
but to my knowledge there has always been 12 months in year.

Rating: 5
September 24, 2001
Reviewer: A reader
My users can pass the date params into my function, in any format, but the
selects in my function need them only in dd-mon-yy , format,  (that too only the
date and not the time).

How should I make this happen

Followup:
TRUNC the date before you use it in the query.  The function TRUNC can remove
the time component for you.

Rating: 5
Interesting September 24, 2001
Reviewer: Thanks from USA
The default date format for my database is dd-mon-yy.

When ever the users pass date params to my functions and procedures , I first
convert them into dd-mon-yy format, and then use them.

One of my users is passing a date 5th september 01 , in the format dd/mm/yy i.e.
05/09/01, when I converting it to dd-mon-yy format it is becoming 09-may-01.
This doesnt work for us. There is no problem when he passes the date in mm/dd/yy
 i.e. 09/05/01 , it is resolving to 05-sep-01.

How can we resolve this.

as both the date and the month are below 12, we cannot effectively differentiate
, what is the intended month or date . How should we solve this.

How can we be sure of the intended month and date of the user, and

how can we make sure, that the date format is changed to dd-mon-yy, no matter in
which format the users passes in the date.

Followup:
Tell the user about the proper use of your function.  Unless you have a crystal
ball - there is no way to know that 05/09/01 is 5-sep-01 or 9-may-01 or even
1-sep-2005!

Rating: 5
Tom September 24, 2001
Reviewer: M from USA
 l_dt := to_char(trunc(p_dt),'dd-mon-yy');

In my select I have a condition like  the following

and to_char(TRUNC( d.e_dt),'dd-mon-yy')= l_dt

but this will supress the index on d.e_dt, how should I rewrite it , so that I
can make use of the index on d.e_dt

Thank you

Followup:
is
   l_dt date := trunc(p_dt);
begin

   ....
     and d.e_dt between l_dt and l_dt+1-1/24/60/60;
   ....

compare dates to dates and get all dates that fall in that day
(l_dt+1-1/24/60/60 is one day beyond l_dt minus 1 second, eg: 11:59:59 of that
day)

Rating: 5
Follow up to 'crystal ball' September 25, 2001
Reviewer: Thanks
"Tell the user about the proper use of your function.  Unless you have a crystal
ball - there is no way to know that 05/09/01 is 5-sep-01 or 9-may-01 or even
1-sep-2005!"

1. Our  function accepts a data parameter, which we then use find out the valid
previous working day, and then use the  date passed in and the previous working
day date, in doing some deletes and updates in 3 tables, and then return a ref
cursor, selecting the latest data joining the 3 tables.

Do you think converting the data passed , into a julian date will solve this
problem for good.

2.Iam curious to know the meaning, context of the phrase 'crystal ball' which
you used. I observe that you have a very good vocabulary.

Followup:
1) no not really, the user of your function must pass you valid data.  If your
procedure were to take a DATE as the input -- that would solve your problem.

You cannot yourself convert the data passed into a julian date -- if you could
do that, you could convert it into an Oracle date (back to square one, no way
for YOU to know what the input 05/04/03 is -- may 4th 2003 or mar 4th 2005 or
some other permutation.  Now, if they had to pass YOU a date -- then you are in
business!  They would have to TO_DATE their string and you know they know the
proper way to do it.

2) Sorry, "Crystal Ball" was a reference to the crystal ball people who claim to
be able to see into the future or past would use.  "I look into my crystal ball
and see great wealth coming your way"....

Unless you have the ability to read their mind, you need to have them send you
the data in the proper format.

Rating: 5
excellent March 25, 2003
Reviewer: mary from dover de
thanks once again for giving me exactly what I was looking for -- (select * from
t
where eff_date >= to_number(to_char(add_months(sysdate,-12),'yyyymmdd'))

September 25, 2001 Vikram -- Thanks for the question regarding "Just some questions", version 8.1.7
You Asked
1. STATSPACK

  a)    .___________._________.__________.
       SPS         JS         JE        SPS

  b)    .___________._________.__________.
       JS         SPS         SPS        JE

where JS - Job Start
      JE - Job End
      SPS - instant when Statspack.snap was run

Is case a), a better way to run statspack or case b)
if I want to track a particular Job ?
Will case a) be able to give me info about the job which was run in between
(Say, there is something wrong with the Job, induces a lot of I/O waits)

Does STATSPACK collect data over time ?
Or just gathers info at the instant when it is run ?

If it gathers info over time, is there any considerable overhead to performance,
when I run it during times when there is a lot of activity ?

2. In the Oracle manual for 8.1.7, they say that the LOG_BUFFER
can have a max of 500K or 128K * CPU_COUNT.
Is this true ?
I have 12 CPU's on my server, does this mean that I can only have a log_buffer
of around 1MB ? (I have enough RAM too)
What happens if it is more than this value ?
Also, later on in the manual, it says for a DB configured for parallel
activity, you can have a max of 3M to 5M !
and we said...
I prefer b myself if you are trying to tune "job".  It gets rid of the
"outlying" data that isn't really relevant.

Statspack collects stats at a point in time and then can "diff" the stats
between two points in time.  Looking at b) again -- the report you run that
compares the second with the first snapshot basically just "subtracts".  If at
the second snapshot you have done 1,000,000 IO's and at the first, you had done
900,000 -- the report will be able to tell you you did 100,000 IO's in the
observation period.

since it does it at a point in time, it does not affect runtime performance
other then when the snapshot is being taken.

2) it says:

<quote>
Default value: Operating system specific. Maximum: 500K or 128K * CPU_COUNT,
whichever is greater

Range of values: Operating system dependent
</quote>

The default value is the maximum of

a) 500k
b) 128k * cpu_count

The range of values ( the minimum to the maximum ) is OS dependent.  You can
have a redo log buffer of megabytes in size.
September 26, 2001 Hardenburg -- Thanks for the question regarding "SQL Reuse", version 8.1.5
You Asked
Is there a parameter in 8.1.5 for the optimizer to "reuse" the
plan for a sql statement that is ALMOST identical?  I seem to
remember hearing that as of 8i the optimizer could be told to
use the same plan if the only difference between statements was
case or spacing.

Thanks
and we said...
You are refering to a new 8.1.6 (not available in 8.1.5) feature
of "auto binding" where by the statements:

select * from emp where ename = 'KING'
select * from emp where ename = 'BLAKE'

will be rewritten to be:

select* from emp where ename = :SYS_BV

White space, case, etc -- are all still relevant.  It is useful
as a temporary fix for systems that did not use bind variables
in the first place as they should have.

See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/ch10_sha.htm#3667
for details.
Review & Followup
Rating: 5
why September 25, 2001
Reviewer: Sol
Why cant cursor_sharing param be considered as a permanent solution.

Followup:
for all of the details -- see my book.  I have the test cases, proofs if you
will, in there.

It can have unintended side effects -- for example:

ops$tkyte@ORA8I.WORLD> select substr( username, 1, 5 ) from all_users where
rownum=1;

SUBST
-----
SYS

ops$tkyte@ORA8I.WORLD> alter session set cursor_sharing=force;
Session altered.

ops$tkyte@ORA8I.WORLD> select Substr( username, 1, 5 ) from all_users where
rownum=1;

SUBSTR(USERNAME,1,5)
------------------------------
SYS

ops$tkyte@ORA8I.WORLD>

Hmm, why did that field go from 5 characters to much more?? (hint -- we actually
ran "substr( username, :bv1, :bv2 )"

Sometimes -- you do NOT want a bind variable for query optimization!

It is not as scalable as it SHOULD be.  If your application is creating queries
like:

select * from emp where empno = 1;
select * from emp where empno = 2;
select * from emp where empno = 3;
....

That means it is doing lots of:

   parse
   open
      fetch...
   close

It should:

   parse ONCE per program execution

   open
      fetch....

and probably NEVER close.  You are parsing way more then you should -- the fact
that cursor_sharing helps you proves to me that you are parsing more then you
should (else cursor sharing would NOT help you).

It is a patch, a bandage, a crutch.  It is not the correct, final solution.

Rating: 5
curious September 25, 2001
Reviewer: A reader
Hmm, why did that field go from 5 characters to much more?? (hint -- we actually
ran "substr( username, :bv1, :bv2 )"

You mean to say running substr( username, :bv1, :bv2 ) increased the charaters
to more than 5, why did it happen, how are bind variables responsible for that.

Followup:
It increased the maximum possible width of the field to the sql engine.  It sees
:bv1 and :bv2 -- NOT 1, 5 now.  So, it would report back to the client that this
string may in fact be very large.

What would this affect -- virtually every reporting tool out there.  Instead of
setting up a nice 5 character wide field -- they'll set up really big field.
Turning on cursor_sharing can effect many reporting tools as all of a sudden
various "fixed width fields" start coming back with radically different widths.
It can affect numbers -- eg:  "select 5.1 from dual" will describe differently
then "select :bv1 from dual" and strings in a bad way.

Rating: 4
Reader September 26, 2001
Reviewer: Reader from USA
Along the same line of discussion, I read in a book that,

New bodies of cursors are created if:
Bind threshhold differs greatly from prior executions
Optimzer plan changes as a result of bind variable supplied

execution1:
If value of NAME variable is 6 bytes, Oracle create bind information to cope up
with 50 bytes in that bind position
execution2;
If value of NAME is 200 bytes long. Oracle cannot reuse the
existing body ( body of the cursor which contains specifics
for the cursor, execution plan, bind variables etc.)- the runtime requiremnet
goes beyond the definition of current body. At this point Oracle will create a
new body to cater for - say 65 to 256 bytes bind variables. This leads to a
soft parse.

What is your insight on this theory

Thanks very much

September 26, 2001 JT -- Thanks for the question regarding "import delimited text file using utl_file", version 8.1.6
You Asked
I have seen your examples on using the function load_data. I have used it and it
works great. But, are there other ways to do something similar but not as
function/procedure? (not allowed to compile procedures and using sqlloader is
out of the question)

Thanks in advance.
and we said...
YOU'R KIDDING.  You paid lots of money for the database and you are not allowed
to use the tools.  Thats like installing Windows and having someone say "sorry,
you cannot use explorer, cmd.exe, or the right mouse button".  What is the
point.

You don't even want to know what I think about that.

Well, if you cannot create procedures, you must have some sort of draconian DBA
at work here -- how will you get them to enable utl_file for you???

You can use my code as an anonymous block.  If you see the code on:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:464420312302
you would change it to be:

define p_table &1
define p_cnames &2
define p_dir &3
define p_filename &4
define p_delimiter &5

begin
      l_input         utl_file.file_type;
      l_theCursor     integer default dbms_sql.open_cursor;
      l_buffer        varchar2(4000);
      l_lastLine      varchar2(4000);
      l_status        integer;
      l_colCnt        number default 0;
      l_cnt           number default 0;
      l_sep           char(1) default NULL;
      l_errmsg        varchar2(4000);
begin
    l_input := utl_file.fopen( '&p_dir', '&p_filename', 'r' );

    l_buffer := 'insert into ' || '&p_table' || ' values ( ';
    l_colCnt := length( '&p_cnames' )-
                    length(replace('&p_cnames',',',''))+1;

that is, change all of my inputs from things like p_dir into '&p_dir'.

Save that to a script and run it from sqlplus.
Review & Followup
Rating: 5
Great and quick response September 26, 2001
Reviewer: A reader from NY,NY
Thanks for the solution.

September 27, 2001 Marco -- Thanks for the question regarding "update of self referencing table", version 8.1.7
You Asked
Hi Tom,
we want to achieve the following behavior on a self referencing table(srt):
when an update is performed on a parent record column of a srt, we want this
column to be automatically set to this value on all child records.
Is there a way to do this?
Thanks Marco
and we said...
Nope, no way to do this "automatically".  triggers would be out of the question
due to the recurisive nature of this data and the fact the row level triggers
cannot update the table upon which they fire.

You'll need to write a procedure or a single update that does this update for
you.  You should be able to issue something like:

  update t
     set c = NEW_VALUE
   where primary_key in ( select primary_key
                            from t
                           start with id = :x
                          connect by prior id = parent_id );
Review & Followup
Rating: 5
Automatic Update may be Possible September 26, 2001
Reviewer: Chip from Denver, CO USA
Tom, possibly a set of triggers and a package could be
used to do this update automatically.

Before Statement Trigger:
  Increments package recursion counter -- NVL(counter,0)+1

Before Update Row Trigger:
  If package recursion counter = 1
     then copy update values to package table

After Statement Trigger:
  If package recursion counter = 1
     then update children (using values in package table)
          reset package recursion counter to 0
          delete all values in package table

The package is required so the table and recursion counter
are available to all triggers.  Adding a recursion counter
check to a mutating table work around could keep the
triggers from recursively executing too many times.

Followup:
I know all about mutating tables -- see
http://osi.oracle.com/~tkyte/Mutate/index.html
My concern here is that it is a hierarchy.  A parent has children, the CHILDREN
have children.  You have to recurse many layers of the hierarchy.

You would cascade to the first level of children and stop.  It needs to get the
parent, the child, the child of the child, the child of the child of the child,
and so on.

Not a good candidate for a trigger....

September 27, 2001 Raj -- Thanks for the question regarding "Specifying schema name when creating ddl trigger", version 8.1.6
You Asked
Hi Tom,
Based on one of your earlier tips, I can create a ddl without any problem using
the following code:

create or replace trigger ddl_trigger
  before ddl on scott.schema
  begin
      if ( user not in ('SYS', 'SYSTEM') )
      then
          raise_application_error( -20001,
                'You are not allowed to Create/Alter/Drop database objects.' );
      end if;
  end;
/

However when I change 'scott' to &1 and pass 'scott' on the command line like:

@cr_trig scott

the '.' between 'scott' and schema gets lost and I get the following error:

SQL> @cr_trig scott
old   2:   before ddl on &1.schema
new   2:   before ddl on scottschema
  before ddl on scottschema
                *
ERROR at line 2:
ORA-30506: system triggers cannot be based on tables or views

How can I make the schema name parameterized so that it is not hard coded?

THanks,
RaJ
and we said...
before ddl on &1..schema

It is a little known fact that &variable_names are optionally terminated by a
dot (so you can:

select '&1.Hello' from dual;

where as select '&1Hello' from dual; would have you have a variable 1hello...

Just use .. to get a . after a substitution variable.
Review & Followup
Rating: 3
Interesting September 27, 2001
Reviewer: Jacques from Cologne, Germany
One too remember:

Forgive me if this is a silly question but why would you want to use the & in a
trigger.

Followup:
they appear to be making a generic script that creates a DDL trigger in any
schema.  They would like to be able to run:

SQL> @scriptname scott
SQL> @scriptname demo

that would create a trigger in scotts schema and then demos schema -- making
those schemas unable to "drop/create/alter" their own objects.

Rating: 3
Interesting September 27, 2001
Reviewer: Jacques from Cologne, Germany
One to remember:

Forgive me if this is a silly question but why would you want to use the & in a
trigger.

September 27, 2001 richard -- Thanks for the question regarding "partition questions", version 8.1.5
You Asked
Tom,

On page 640 of your book you give some examples of queries on a partitioned
table. I understand why

   Select * from partitioned_table where b=1;

Cannot use either index when "part_2 unusable" is specified.

What I don't understand is why the optimizer doesn't choose a table scan instead
of producing an error with "no rows selected".

With a hint, I can force a table scan, but then a table scan would always be
performed. Don't you think the best behavior would be to use an index when
possible and a table scan otherwise?

Also, in the same chapter, you don't consider the possibility of OLTP
applications with sliding window requirements. But clearly there are such
applications. For example, suppose credit card transactions are continuously
entered into a table, which is queried and updated, but we only want to keep the
last 12 months of data in table. A partition by date suggests itself where we
slide off the oldest partition every month. But it seems like this is not an
ideal solution. A global unique index would be the right choice of index but
would have to be rebuilt each month. With millions of rows, this is bad. Local
indexes suffer from the problems you point out in your book, and thus are bad. A
non-partitioned table requires a massive delete each month, and thus is also
bad. What should one do?

Thanks.

Richard
and we said...
You can use the skip_unusable_indexes sesssion setting to have the index be
skipped:

..
SKIP_UNUSABLE_INDEXES = { TRUE | FALSE }
controls the use and reporting of tables with unusable indexes or index
partitions. SKIP_UNUSABLE_INDEXES is a session parameter only, not an
initialization parameter.

o TRUE disables error reporting of indexes and index partitions marked UNUSABLE.
Allows all operations (inserts, deletes, updates, and selects) to tables with
unusable indexes or index partitions.

Note: Statements that would normally use the unusable indexes or index
partitions may be compiled with suboptimal optimizer plans, occasionally
resulting in major degradation in response time and resource utilization.

.........

Yes, I agree with you -- I don't consider the possibility of a sliding window
with OLTP because it is not really there in 8i.  It is a really hard problem --
sort of like wanting your cake and eating it too.

You want the advantages of locally partitioned data with a globally partitioned
index.  We cannot get there from here.

I don't have the exact answer for you here since we would have to go into depth
given your specific requirements, maintenance windows and so on to architect a
solution specific to your needs.

I can say that in 9i, we can perform partition operations AND maintain the
global indexes.  The downsides in short to this are:

o extra redo generated in order to maintain the global indexes, redo that is not
present if you just drop the partition and rebuild NOLOGGING the indexes.

o the partition operation takes longer due to the indexes being modified.

The upsides are, you can do partition operations without making the indexes
unusable.
Review & Followup
Rating: 3
need more info September 27, 2001
Reviewer: richard gostanian from new hampshire
I tried setting skip_unusable_indexes=true in my sqlplus
session, but although the operation apparently succeeded
the select * from partitioned_table where b=1
still produced ORA-01502.

Could this be a bug in 8.1.5?

Also what dictionary table has all of the session parameters
and there settings?

Followup:
Yes, in 815 the following script won't work (805 as well)

drop table p;

create table p (i integer)
partition by range(i)
(partition p1 values less than (10),
partition p2 values less than (20),
partition p3 values less than (maxvalue));

create index l on p(i) local;
alter index l modify partition p1 unusable;

exec dbms_stats.set_table_stats( user, 'P', 'P1', numrows => 100000000, numblks
=>10000000 )
set autotrace on
select * from p where i < 2;
ALTER SESSION SET SKIP_UNUSABLE_INDEXES=TRUE;
select * from p where i < 2;
set autotrace off

In 816 and up, it will (the second query will execute after the ALTER SESSION)

Unfortunately, there is no table with the session parameters and their current
setting.

September 27, 2001 alvaro -- Thanks for the question regarding "GRANT OBJECT PRIVILEGES FROM PACKAGES using dynamic sql", version 7.3.4.0.0
You Asked
Hi Tom,

My question is :

I have a package that should do the following :
Supose there are users A,B and C, userA wants to grant object privileges on
userC's objects to userB. Is There any way to do that???

For example ...

userC has Table1 and Table2 and the userA must grant privileges on this tables
to userB.

userA would issue :  grant all on userC.table1 to userB;
                     grant all on userC.table2 to userB;

I'm using DBMS_SQL for doing it, I don´t know if there is another way to do it!

I've used dbms_sql (in a package) for creating roles and granting them to users
and I have not had problems ...  like this:

PROCEDURE CREA_DROP_ROLE(P_APLIC IN CHAR,P_GRUPO IN CHAR,P_ACCION IN CHAR) AS
  CURSOR_NAME INTEGER;
  R           INTEGER;
BEGIN
  CURSOR_NAME:=DBMS_SQL.OPEN_CURSOR;
  IF(P_ACCION='C') THEN
     DBMS_SQL.PARSE(CURSOR_NAME,'CREATE ROLE '||P_GRUPO,DBMS_SQL.NATIVE);
  ELSIF(P_ACCION='D') THEN

     DBMS_SQL.PARSE(CURSOR_NAME,'DROP ROLE '||P_GRUPO,DBMS_SQL.NATIVE);
  END IF;

  R:=DBMS_SQL.EXECUTE(CURSOR_NAME);
  DBMS_SQL.CLOSE_CURSOR(CURSOR_NAME);
  EXCEPTION
     WHEN OTHERS THEN
       DBMS_SQL.CLOSE_CURSOR(CURSOR_NAME);
  END;

My other question is Can I use DBMS_SQL or other package to create any synonym??
what rights should have the user who execute the package???

e.g

PROCEDURE CREA_SYNONYMS(P_USER1 IN CHAR,P_USER2 IN CHAR,P_OBJECT IN CHAR) AS
  CURSOR_NAME INTEGER;
  R           INTEGER;
BEGIN
  CURSOR_NAME:=DBMS_SQL.OPEN_CURSOR;
     DBMS_SQL.PARSE(CURSOR_NAME,'CREATE SYNONYM '||P_USER1||'.'||P_OBJECT||' FOR
'||P_USER2||'.'||P_OBJECT,DBMS_SQL.NATIVE);

  R:=DBMS_SQL.EXECUTE(CURSOR_NAME);
  DBMS_SQL.CLOSE_CURSOR(CURSOR_NAME);
  EXCEPTION
     WHEN OTHERS THEN
       DBMS_SQL.CLOSE_CURSOR(CURSOR_NAME);
  END;

Thanks for your help

Acueto
and we said...
Yes, you can do all of the above.

For usera to grant userc access to userb's objects, userb will have had to of:

  grant all on table to usera WITH GRANT OPTION;

Alternatively, since procedures execute with the privs of the DEFINER of the
package -- you could have userB create a procedure that does the grant and then
just grant execute on that procedure to userA.  userA can use that procedure to
grant on any of userB's objects (since it is really userB doing the granting!)

As for the synonym, you do not mention the error you are getting, but I'll
betcha it is ora-01031.  See
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for the reason and the solution.

Just a suggestion, you could save writing lots of code if you created:

create or replace procedure execute_immediate( p_sql in varchar2 )
is
    cursor_name     pls_integer default dbms_sql.open_cursor;
    ignore          pls_integer;
BEGIN
    dbms_sql.parse(cursor_name, p_sql, dbms_sql.native);
    ignore := dbms_sql.execute(cursor_name);
    dbms_sql.close_cursor(cursor_name);
exception
    when others then
         dbms_sql.close_cursor( cursor_name );
END;
/
Review & Followup
Rating: 4
September 27, 2001
Reviewer: Rana from Detroit , MI
Tom

What are the necessary privileges required mentioned in the link you have
provided for creating a synonym through dynamic sql. I have granted CREATE
SYNONYM privilege directly to the user and also select privilege on the
schema.table and still get the same error ORA-01031.

Thanks

Followup:
They only need CREATE SYNONYM (not even select on the table!).  You'll need to
provide an example like I have below to reproduce this error:

ops$tkyte@ORA9I.WORLD> create table t ( x int );
Table created.

ops$tkyte@ORA9I.WORLD> create user a identified by a;
User created.

ops$tkyte@ORA9I.WORLD> grant create session, create synonym, create procedure to
a;
Grant succeeded.

ops$tkyte@ORA9I.WORLD> @connect a/a
ops$tkyte@ORA9I.WORLD> set termout off
a@ORA9I.WORLD> set termout on

a@ORA9I.WORLD> create or replace procedure execute_immediate( p_sql in varchar2
)
  2  is
  3      cursor_name     pls_integer default dbms_sql.open_cursor;
  4      ignore          pls_integer;
  5  BEGIN
  6      dbms_sql.parse(cursor_name, p_sql, dbms_sql.native);
  7      ignore := dbms_sql.execute(cursor_name);
  8      dbms_sql.close_cursor(cursor_name);
  9  exception
 10      when others then
 11           dbms_sql.close_cursor( cursor_name );
 12                   RAISE;
 13  END;
 14  /

Procedure created.

a@ORA9I.WORLD>
a@ORA9I.WORLD> exec execute_immediate( 'create synonym t for ops$tkyte.t' );

PL/SQL procedure successfully completed.

now, perhaps you are trying a PUBLIC SYNONYM??  For that, you need the create
public syonym priv:

a@ORA9I.WORLD> exec execute_immediate( 'create public synonym t_pub for
ops$tkyte.t' );
BEGIN execute_immediate( 'create public synonym t_pub for ops$tkyte.t' ); END;

*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "A.EXECUTE_IMMEDIATE", line 12
ORA-06512: at line 1

a@ORA9I.WORLD>
a@ORA9I.WORLD> @connect /
a@ORA9I.WORLD> set termout off
ops$tkyte@ORA9I.WORLD> set termout on
ops$tkyte@ORA9I.WORLD> grant create public synonym to a;

Grant succeeded.

ops$tkyte@ORA9I.WORLD> @connect a/a
ops$tkyte@ORA9I.WORLD> set termout off
a@ORA9I.WORLD> set termout on
a@ORA9I.WORLD> exec execute_immediate( 'create public synonym t_pub for
ops$tkyte.t' );

PL/SQL procedure successfully completed.

Rating: 3
Intersting but can we take it a step ahead?? September 27, 2001
Reviewer: Pranav from USA
For example, if userDBA has just created a table in userA's schema with a
Procedure that goes like:
  CREATE OR REPLACE PROCEDURE PHARMACY_EXPENSE_Table
  AUTHID CURRENT_USER
  AS
  BEGIN
    execute immediate 'CREATE TABLE userA.Table1(..)'
    --WOULD LIKE GRANT HERE
  END;

And now in the same procedure wants to:
   GRANT SELECT ON userA.Table1 TO userB.

And the person to call this procedure has a DBA role.
The create table worked fine but I get an error when trying to give the GRANT:
   ORA-01031: insufficient privileges

Followup:
Yes, that is the defined, expected behavior here.  userDBA has NO ability to
grant on userA's tables.  Only USERA has that ability and they have not given it
to anyone.

If userDBA has, in addition to the create any procedure, drop any procedure
priv, the EXECUTE any procedure, they can:

execute immedate 'create procedure usera.grant_table1
                  as
                  begin
                     execute immediate ''grant select on table1 to userb'';
                  end;'
execute immediate 'begin usera.grant_table1; end;';
execute immediate 'drop procedure usera.grant_table1';

in the code.  That creates a procedure that runs as usera and can do the grant.

September 28, 2001 Mikito -- Thanks for the question regarding "equality predicate on clob", version 9i
You Asked
I've looked into 9i clob manual (wow, whole manual for one built-in datatype!)
and still have a question: What index technique can be used to make effective
clob comparison in a query like this:

select * from my_table where clob_column = another_clob;

I noticed that whenever I create a table with clob a unique index is created as
well. Is it a "clob" identity index?
and we said...
You cannot index a CLOB like that.  A clob is potentionally HUGE -- indexes
don't work on HUGE things.

We can index the CONTENTS of the clob using Oracle text (aka interMedia).

One method you can use would be to create an index on the checksum of the first
32k of the clob.  this checksum is "small".  We can use that to effectively
reduce the NUMBER of clobs we need to compare to.  We can index the checksum of
the CLOB and at runtime use a predicate like:

 where checksum(clob_column) = :checksum_of_thing_to_look_for
   and clob_column = another_clob

For example:

ops$tkyte@ORA9I.WORLD> create table t ( x int primary key, y clob );

Table created.

ops$tkyte@ORA9I.WORLD> create index t_idx on t(checksum(y));

Index created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> insert into t values (1,'hello world' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values (2,'goodbye' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values (3,'this is just a test...' );

1 row created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> set autotrace on
ops$tkyte@ORA9I.WORLD> select t.*
  2    from t
  3   where checksum(y) = checksum('hello world')
  4     and to_char(y) = 'hello world'
  5  /

         X Y
----------
--------------------------------------------------------------------------------
         1 hello world

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=FIRST_ROWS (Cost=1 Card=1 Bytes=2015)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=1 Card=1 Bytes=2015)
   2    1     INDEX (RANGE SCAN) OF 'T_IDX' (NON-UNIQUE) (Cost=1 Card=1)

Where I used:

ops$tkyte@ORA9I.WORLD> create or replace function checksum_str( p_str in
varchar2 ) return number
  2  as
  3     l_checksum varchar2(32);
  4     l_raw      raw(16);
  5  begin
  6
  7     l_checksum :=
  8            dbms_obfuscation_toolkit.md5( input_string=> p_str );
  9
 10     l_checksum := utl_raw.cast_to_raw( l_checksum );
 11
 12     return to_number( substr(l_checksum,1,16), lpad('x',33,'x') )+
 13            to_number( substr(l_checksum,17), lpad('x',33,'x') );
 14
 15  end;
 16  /

Function created.

ops$tkyte@ORA9I.WORLD> create or replace function checksum( p_lob in clob )
return number
  2  DETERMINISTIC
  3  as
  4     l_checksum varchar2(32);
  5     l_raw      raw(16);
  6  begin
  7
  8     l_checksum :=
  9            dbms_obfuscation_toolkit.md5( input_string=>
dbms_lob.substr(p_lob,32000,1) );
 10
 11     l_checksum := utl_raw.cast_to_raw( l_checksum );
 12
 13     return to_number( substr(l_checksum,1,16), lpad('x',33,'x') )+
 14            to_number( substr(l_checksum,17), lpad('x',33,'x') );
 15
 16  end;
 17  /

Function created.

as simple checksum functions.
Review & Followup
Rating: 5
cool! September 27, 2001
Reviewer: Mikito Harakiri
BTW, I was trying a similar thing

CREATE INDEX my_idx ON my_table (SUBSTR(clob_column,1,100));

and it didn't work

Rating: 4
explicit hash function in the equality predicate September 27, 2001
Reviewer: Mikito Harakiri
On pessimistic note, the ideal solution would avoid explicitly mentioning hash
function in the equality predicate -- it is physical access implementation
detail after all. I guess this is too much to ask from the optimizer today...

Rating: 3
no equality predicate on clobs September 27, 2001
Reviewer: Mikito Harakiri
Hmm... It took me a while to notice to_char function in your predicate.

There seems no equality predicate on clobs to begin with. CLOB manual says:

Non-Supported SQL Functionality for LOBs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The following SQL functionality is not supported for LOBs because the functions
are either infrequently used or have easy workarounds.
...
Operators: >, <, =, !=

Followup:
well, you seem to be getting less and less "happy" with this answer.

The fact is CLOBS are big, huge, not really things that you want to be doing
equals on -- you have to force it in some cases.

I would question why you need to do this -- compare clobs -- it will be slow,
the tips here will help you make it faster, more realistic....

Rating: 3
no equality predicate on clobs September 28, 2001
Reviewer: Mikito Harakiri
I'm collecting sql statements from huge ERP application. Most of the statements
are reasonably short, while the longest one is 30K bytes long. I need to be able
to identify identical statements, as I also would like to peek into V$SQL.
Therefore, I'm not comparing huge clobs at all.

Even if I would, knowing that todays database limits are somewhere under 1B
records, we can think of hash function that can make this comparison efficient.
This hash heed to have a range > 1B*1B in order to eleminate chances of
collision.

On the other hand, you are probably correct, naive literal comparison of clobs
woldn't get me too far. In my example, ignoring differences in the names of bind
variables would probably be better comparison criteria. Looks like for big
objects only user-defined equality makes sence.

Rating: 3
Another way of computing a checksum for anysize clob March 17, 2003
Reviewer: Yves Azie
create or replace and compile
java source named "GetChecksum"
as
import java.io.*;
import java.lang.*;
import java.security.*;

/**
 * This class takes in a clob, and computes
 * a unique hash value based on the md5 hash algorythm
 */
public class GetChecksum extends Object
{
   public static float get(oracle.sql.CLOB clobToCompute) throws Exception
   {
      BufferedReader clobReader = new
BufferedReader(clobToCompute.getCharacterStream());
      String s = null;
      StringBuffer sb = new StringBuffer();
      while ((s = clobReader.readLine()) != null) {
        sb.append(s);
      }
      clobReader.close();

      byte[] clobBytes = sb.toString().getBytes();
      MessageDigest md5 = MessageDigest.getInstance("MD5");
      byte[] clobResult = md5.digest(clobBytes);

      ByteArrayInputStream bytestream1 = new ByteArrayInputStream (clobResult);
      DataInputStream bytestream2 = new DataInputStream( bytestream1 );

      float clobFloat = bytestream2.readFloat();
      return clobFloat;
   }
}
/
show err

create or replace function checksum ( p_lob in clob )
return number
  DETERMINISTIC
  as
  language java
  name 'GetChecksum.get(oracle.sql.CLOB) return float';
/
show err

You may then use this function in SQL as follows:
select checksum(clobfield) from clobTable;

September 28, 2001 Kamini -- Thanks for the question regarding "2 questions", version 8.1.7
You Asked
Hi Tom

I have 2 questions

1. We can get all the rows that are different between 2 tables by using minus.
Is it possible to compare all the columns of 2 tables and display the column
values only that are different?  If possible could u please tell how?

2. Is it possible to access a collection by varchar2.  For e.g. if I have 3 rows
in a collection with the following values in the following order.
         COLOUR     QTY    COUNTRY
         ---------------------------
         RED        1000     AMERICA
         BLUE       1000     JAPAN
         GREEN      5000     INDIA
         YELLOW     9000     SAUDI

I know that I can access the 2 element in a collection by specitfying the
colllection(1).colour, collection(1).qty, collection(1).country.  But I want to
access the same by specifying collection('RED').QTY, COLLECTION('RED').COUNTRY.
Is it possible?  how?  If not possible could u please tell me any other way
access my resultset by a varchar2 key.

Thanks in advance
and we said...
(select 'in t1, not t2' where, t1.* from t1
 minus
 select 'in t1, not t2' where, t2.* from t2)
UNION ALL
(select 'in t2, not t1' where, t2.* from t2
 minus
 select 'in t2, not t1' where, t1.* from t1)

In order to display just the columns that are different, you would need to write
much more complex procedural code.

There are no varchar2 keys (yet -- planned for 9i release 2).  If you have
access to my book, I show how to do this with a hash table using dbms_utility in
any release of Oracle.
Review & Followup
Rating: 1
Rephrase the question for us September 26, 2001
Reviewer: A reader
Kindly rephrase the question for us. and what meaning does
'select 'in t1, not t2' where, t1.* from t1'  make, how does it get resolved.

What do you mean by a collection, -- a sqltype with multiple columns ?

Followup:
the query:

select 'in t1, not t2' where, t1.* from t1

simply selects every column in t1 (t1.*) and a constant that will be used to
tell us in the output WHERE the row came from.

Consider:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t1 ( x int );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t2 ( x int );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t1 values  (1);

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t1 values ( 2);

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t2 values ( 2);

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t2 values ( 3 );

1 row created.

  1  (select 'in t1, not t2' whence, t1.* from t1
  2   minus
  3   select 'in t1, not t2' whence, t2.* from t2)
  4  UNION ALL
  5  (select 'in t2, not t1' whence, t2.* from t2
  6   minus
  7*  select 'in t2, not t1' whence, t1.* from t1)
ops$tkyte@ORA817DEV.US.ORACLE.COM> /

WHENCE                 X
------------- ----------
in t1, not t2          1
in t2, not t1          3

note: i had to change where to whence -- sorry about that, the column alias
was wrong

That tells us clearly that the first row we see is a row that was in T1 but not
T2 and so on.

Rating: 3
Varchar2 keys September 27, 2001
Reviewer: kamini from INDIA
Hi tom

I dont' have access to your book.  Could u please explain in detail about the
workaround with hash_table using dbms_utility for accessing the collection by
Varchar2.

Thanks

Followup:
Sorry, its about 5 pages of code/explaination.  Too much to fit here.  Copyright
restrictions prevent me from posting it as well (i don't necessarily "own" the
text anymore)

I built a hash table type using the objects extension.  Basically, I used the
dbms_utility.get_hash_value to turn a string into a number (an index into a hash
table) and then wrote the routines to deal with hash collisions.

The source code is available for download from www.wrox.com -- however, the
details about how it works and such are only in the book.

September 29, 2001 lisa -- Thanks for the question regarding "Import - extent question", version 816
You Asked
I have a situation such as -
Exported file(from oracle.73 with compress=N) into oracle816 with
tablespace defined as
"EXTENT MANAGEMENT LOCAL UNIFORM SIZE 40K", with 200M datafile
(this part went in fine), run sql to check user_tables, some  with pretty large
extent, I run a user_tables here is few sample:

TABLE_NAME                     INITIAL_EXTENT NEXT_EXTENT
------------------------------ -------------- -----------
DM_STORE_S                              24576       40960
DM_SYSOBJECT_R                        1089536       40960
DM_SYSOBJECT_S                        5595136       40960  <-----
DM_TYPE_R                              196608       40960
DM_TYPE_S                               24576       40960
DM_USER_S                               24576       40960

after some application update, I then again export this tablespace
with compress=N to a dump, and again import into another
oracle816 database with local managed tablespace, can I

1: create tablespace with SAME  "extent management local uniform size 4oK"
   will oracle know how much to grab to satify the third  table above?
   (with large table, will data fit in without error ora-1658 or 1659 error?)
2. if ora-1658 error, how should I size my tablespace initial extent ?
or what imp parameter should I include ?
and we said...
with the locally managed tablespace and a 40k uniform extent size -- Oracle will
interpret the initial request of 5,595,136 as a request for 137 extents.  We
will use the INITIAL size as a request for X bytes of initial storage and
allocate enough uniformly sized extents to hold it.

As long as you have the space, you will not have a problem with any ORA errors
regarding that.
September 29, 2001 Wendy -- Thanks for the question regarding "UTL_FILE", version v7.3.4 on NT SERVER
You Asked
Dear Tom:
I tried to pull data from database to output to a flat file to
write a report,the procedure compiles ok(using
UTL_FILE.PUT_LINE), but when I execute it on my workstation, it
says that you have no permission on such directory(something
like that, I don't remeber the exact wording). So I went back to
check the Oracle doc, it says that you need to set it up on the
init.ora file, there is a parameter called UTL_FIEL_DIR. Now, I
have aquestion, since our database is on NT Server, if I Add the
paramter like UTL_FILE_DIR=D:\OUTPUT, then D:\Output is
referring the directory on the SERVER where the database
resides, will my procedure run on my WORKSTATION? What if I set
it up in the init.ora file like this: UTL_FILE_DIR=*?
If I can't run, does that mean that whenever I want run the
UTL_FILE, I need to run right out of the SERVER? That doesn't
sound right.
and we said...
A stored procedure will never run on your workstation.  A
stored procedure by definition runs on the SERVER.

UTL_FILE is capable of writing only to directories on the
server.  UTL_FILE cannot write to any directy the database
server cannot itself "see".  UTL_FILE is being executed by the
Oracle processes on the database machine.

You can run the procedure from your workstation but any output
it makes using UTL_FILE will always go onto the server.
Review & Followup
Rating: 4
no access to database servers September 28, 2001
Reviewer: A reader
Tom

We have no access to database servers, we only have access to the network
server.

I cannot access the utl file dir location which is on the database server.

How can I write a shell script utility which will copy all the files in the utl
file dir , to a location on the network server, from where we can pick up the
file.

Followup:
You could mount a disk on the server from the "network server".  UTL_FILE can
write to that.  If this is UNIX, this is trivial (just mount the disk).  If this
is NT, its more complex, see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:241814624807

Rating: 5
September 29, 2001
Reviewer: A reader from USA
You could mount a disk on the server from the "network server".  UTL_FILE can
write to that.  If this is UNIX, this is trivial (just mount the disk).

Iam inexperienced in unix, I need to explain to my dba the solution you have
suggested. kindly explain mouting the disk on the server from the network
server. I need to understand it totally before I go speak to  my dba.

Kindly take some pain to explain.

Thank you

Followup:
If you have a Unix DBA and he doesn't understand "I need you to mount this
network disk on the Unix box" -- you need a new Unix DBA.  They will understand
-- in "windows" terms, you are "attaching a network share".

September 30, 2001 mike -- Thanks for the question regarding "definition of user defined roles", version 8.0
You Asked
Tom,
How can we find out the definitions of the user defined roles?
ROLE_SYS_PRIVS and ROLE_TAB_PRIVS are only for Oracle defined roles, such as
DBA...

Thanks
and we said...
that's not true:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create role xxx;

Role created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> grant select on t to xxx;

Grant succeeded.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from role_tab_privs where role =
'XXX';

ROLE                           OWNER                          TABLE_NAME
            COLUMN_NAME
------------------------------ ------------------------------
------------------------------ ------------------------------
PRIVILEGE                                GRA
---------------------------------------- ---
XXX                            OPS$TKYTE                      T
SELECT                                   NO

It only provides information to ROLES which you have ACCESS to -- maybe that is
your issue?

If so, DBA_TAB_PRIVS and DBA_SYS_PRIVS can show you info about any role:

  1* select * from dba_tab_privs where grantee = 'XXX'
sys@ORA817DEV.US.ORACLE.COM> /

GRANTEE                        OWNER                          TABLE_NAME
            GRANTOR
------------------------------ ------------------------------
------------------------------ ------------------------------
PRIVILEGE                                GRA
---------------------------------------- ---
XXX                            OPS$TKYTE                      T
            OPS$TKYTE
SELECT                                   NO

Just treat the GRANTEE as a role -- which it can be....
Review & Followup
Rating: 3
Confusion September 30, 2001
Reviewer: A reader
Iam connected as scott

SQL> select * from session_privs
  2  /

PRIVILEGE
----------------------------------------
CREATE SESSION
ALTER SESSION
UNLIMITED TABLESPACE
CREATE TABLE
CREATE CLUSTER
CREATE SYNONYM
CREATE VIEW
CREATE SEQUENCE
CREATE DATABASE LINK
CREATE PROCEDURE
CREATE TRIGGER

PRIVILEGE
----------------------------------------
CREATE TYPE
CREATE OPERATOR
CREATE INDEXTYPE

14 rows selected.

SQL> select * from user_sys_privs
  2  /

USERNAME                       PRIVILEGE                                ADM
------------------------------ ---------------------------------------- ---
SCOTT                          UNLIMITED TABLESPACE                     NO

I expect to see the same results even in the second query, but I could not , can
you explain why

Actually, what I want is to check
1.what are the roles assigned to my schema,
2.and then what are the privileges assigned to my schema, 3.and then what are
the privileges assigned to  my schema which are not assigned to any role.

Further Tom

session_privs gives session privileges
v$mystat gives session statistics

what are some of the other kind of views which give specific information on the
schema and user.

Lastly,

is session_privs a table or a view, if it is a view how much it is not prefixed
with a v$, how many tables are there like session_privs which are not suffixed
with v$,and give useful information on the schema , the session and other useful
information.

Followup:
Easy -- session_privs show the privs in place in your session.  It looks like
SCOTT has the resource role which gives him the create table, create type, etc
priv.  SCOTT also has the UNLIMITED tablespace priv granted directly to him --
thats what you see in USER_SYS_PRIVS.

Consider:

scott@ORA817DEV.US.ORACLE.COM> select * from user_sys_privs;

USERNAME                       PRIVILEGE                                ADM
------------------------------ ---------------------------------------- ---
SCOTT                          ALTER SESSION                            NO
SCOTT                          ALTER TABLESPACE                         NO
SCOTT                          CREATE SNAPSHOT                          NO
SCOTT                          UNLIMITED TABLESPACE                     NO

scott@ORA817DEV.US.ORACLE.COM> @connect /
ops$tkyte@ORA817DEV.US.ORACLE.COM> grant create table to scott;

Grant succeeded.

ops$tkyte@ORA817DEV.US.ORACLE.COM> @connect scott/tiger
scott@ORA817DEV.US.ORACLE.COM> select * from user_sys_privs;

USERNAME                       PRIVILEGE                                ADM
------------------------------ ---------------------------------------- ---
SCOTT                          ALTER SESSION                            NO
SCOTT                          ALTER TABLESPACE                         NO
SCOTT                          CREATE SNAPSHOT                          NO
SCOTT                          CREATE TABLE                             NO
SCOTT                          UNLIMITED TABLESPACE                     NO

user_sys_privs shows those things granted directly to me, session_privs includes
privs from roles.

Ok, to see YOUR roles:

scott@ORA817DEV.US.ORACLE.COM> select granted_role from user_role_privs;

GRANTED_ROLE
------------------------------
PLUSTRACE
CONNECT
RESOURCE

To see YOUR privs --- user_sys_privs and user_tab_privs.

And then to see the privs assigned to your schema which are not assigned to a
role -- thats more complex.  The problem is a ROLE can have a ROLE can have a
ROLE can have a ROLE.  They are hierarchical.  If someone had the connect role
and someone granted "NEW_ROLE" to connect -- you would have to add up the privs
granted to connect and new_role.  Your best bet there might be a stored
procedure (although, if you have the priv granted directly to you --
user_sys|tab_privs -- whether you have that in a role as well or not isn't
really relevant, maybe you really don't need this bit of information anyway)

As for the last two things -- see the Oracle Reference Manual.  There are dozens
of USER_* views and V$ views, far far too many to enumerate here.  The are all
views.

Rating: 3
does not work for my case September 30, 2001
Reviewer: MIKE from Atlanta
The site DBA grant the role, RO_DBA, which is a 'read only' DBA.

SQL> select * from dba_role_privs where grantee='TOOLER';

GRANTEE                        GRANTED_ROLE                   ADM DEF
------------------------------ ------------------------------ --- ---
TOOLMAN                        RO_DBA                         NO  YES

SQL> select * from role_sys_privs where role='RO_DBA';

no rows selected

SQL> select * from role_tab_privs where role='RO_DBA';

no rows selected

SQL>

I do have the privs to read DBA views and the most of schemas' objects. But I
want to find out exactly what is RO_DBA.

Followup:
select * from dba_tab_privs where grantee = 'TOOLMAN';
select * from dba_sys_privs where grantee = 'TOOLMAN';

will tell you that.  Alternatively, log in as toolman and use the query from the
view I reference below...

Rating: 5
Why did you tell us September 30, 2001
Reviewer: TJ
Tom

Curiously, I have observed that previously you have advetised a couple of
queries to get the privileges granted to all the roles for a particular schema.

When we have something like session_privs, why do we need those queries.

If I want a list of my procedures which are running with definer rights on
underlying objects, and a list of procedures running with invoker rights on
underlying objects,  which views should I query, and how should I get them.

Followup:
I think you mean my user_role_hierarchy view:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:853427230099
That answers the question for any given user -- what are all of the possible
privs they might have.  Session privs only shows the privs in place at that
point in time (eg: in a procedure, you have a different set of rows in session
privs then when NOT in a procedure -- session privs changes as the schemaid
under which the procedure is running changes).  user_role_hierarchy shows all of
the privs for the currently logged in user regardless of the current schemaid.

Currently, this information does not seem to be exposed in the standard data
dictionary.  A view such as:

create or replace view dba_procedures
as
select owner,
       object_name name,
       object_id,
       object_type,
       created,
       last_ddl_time,
       status,
       (select decode( bitand(options,16), 16, 'INVOKER', 'DEFINER' )
          from procedure$
         where obj# = dba_objects.object_id ) auth_id
  from dba_objects
 where object_type in ( 'PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY' )
/

create public synonym dba_procedures for sys.dba_procedures
/

can be used in order to retrieve that however...

Rating: 3
still no work September 30, 2001
Reviewer: MIKE from atlanta
Sorry for a missleading:
The 'TOOLER' should be TOOLMAN, I changed it for did want to release the real
User schema. It is OK , i think now.

SQL> select user from dual;

USER
------------------------------
TOOLMAN

SQL> select * from dba_role_privs where grantee='TOOLMAN';

GRANTEE                        GRANTED_ROLE                   ADM DEF
------------------------------ ------------------------------ --- ---
TOOLMAN                        CONNECT                        NO  YES
TOOLMAN                        RESOURCE                       NO  YES
TOOLMAN                        RO_DBA                         NO  YES

SQL> select * from dba_tab_privs where grantee = 'TOOLMAN';

GRANTEE                        OWNER
------------------------------ ------------------------------
TABLE_NAME                     GRANTOR
------------------------------ ------------------------------
PRIVILEGE                                GRA
---------------------------------------- ---
TOOLMAN                        SYS
V_$RESOURCE_LIMIT              SYS
SELECT                                   NO

SQL> select * from dba_sys_privs where grantee = 'TOOLMAN';

GRANTEE                        PRIVILEGE                                ADM
------------------------------ ---------------------------------------- ---
TOOLMAN                        ANALYZE ANY                              NO
TOOLMAN                        RESTRICTED SESSION                       NO

SQL>

It is 8.0.6.
Just can not figure out of what the RO_DBA role is.

Followup:
select * from dba_tab_privs where grantee = 'RO_DBA';
select * from dba_sys_privs where grantee = 'RO_DBA';

Rating: 5
September 30, 2001
Reviewer: mike from Atlanta
These worked.
Do not know the reason for no found in
ROLE_SYS/TAB_PRIVS.


Subject | Article | Last Updated (East coast time)
session status killed. | article only | Oct 01, 2001 07:37 am
HELP REQUIRED with ORA-1031 in a procedure | article only | Oct 01, 2001 08:29 pm
Who is an Invoker , and Who is a Definer | article only | Oct 02, 2001 07:17 am
Dynamic PL/SQL - Error Handling | article only | Oct 02, 2001 08:07 am
Error messages in multithread | article only | Oct 02, 2001 10:08 am
Run os command from pl/sql | article only | Oct 02, 2001 10:41 am
Urgent -- seeing the entire view in sqlplus | article only | Oct 02, 2001 01:30 pm
Export/Import | article only | Oct 02, 2001 04:32 pm
when to modularize code by putting into procedures and functions | article only | Oct 05, 2001 11:47 am
Manipulate a long raw in PLSQL | article only | Oct 05, 2001 11:52 am
Questons | article only | Oct 05, 2001 12:01 pm
Want form to reconnect automatically following database restart | article only | Oct 05, 2001 12:02 pm
Problem with concatenation | article only | Oct 05, 2001 03:10 pm
Import failed | article only | Oct 05, 2001 03:38 pm
Multiple daily refresh of snapshots | article only | Oct 05, 2001 03:53 pm
Dedicate Background Process | article only | Oct 05, 2001 03:57 pm
Package header/body diff. 8i & 9i | article only | Oct 06, 2001 09:21 am
Long Tablespace | article only | Oct 06, 2001 04:50 pm
need truncate privilege to a user and it should have drop table privs. | article only | Oct 07, 2001 05:05 pm
RBO Vs CBO | article only | Oct 07, 2001 09:03 pm
row(s) 1 - 20 of 20
October 01, 2001 Al-KArim -- Thanks for the question regarding "session status killed.", version 8.1.6
You Asked
How to find the exact time oracle would take to rollback a session that is
marked to be killed?
and we said...
You can look at v$transaction (which can be joined to v$session by
v$session.taddr = v$transaction.addr) and measure how fast the used_ublk is
decreasing.  When thats zero -- its done.
Review & Followup
Rating: 4
Release of locks for a killed session October 01, 2001
Reviewer: Bhawna R from India
Hi,
Recently, somebody approached me with a situation where Oracle 8.0.5 was being
run in Dedicated Server mode, and when the user would kill his session using
Ctrl-alt-del, the session was not getting killed immediately. It would shown as
marked for killing, and till that time the locks held by the user will not be
released. My suggestion was to increase the value of CLEANUP_ROLLBACK_ENTRIES
parameter from the detault 20. How far will this affect ?
Another question, what are the pros and cons of MTS and Dedicated Server
architectures. I have to setup Oracle 8i for our client and have to decide
between the 2 modes. This above said application was running in MTS mode till
recently, but due to some block corruption, it was suggested by Oracle Support
to shift to DS mode. Our application is similar to this one. We have D2K client
forms along with EDI and RPC programs with a heavy database.

Putting my additional questions here, because I never get to ask you any
questions, you log is always full for us in India. I am a big fan of your site.

Followup:
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1058832409881
if the session was marked for kill and there were still locks, it was in the
early stages of cleaning up that session.  The locks are released in the "marked
for kill" status.

What is more likely is the client "went away" -- the session was dead from your
perspective but the database did not know it was dead.  TCP/IP won't tell us the
client on the other end is "dead" so we hang out waiting for a request from them
that will never come.

The solution -- enable dead client dedection (DCD) via Net8 (see the net8 admin
guide).  Using this, the server will "ping" the client and upon detecting no
response, it'll clean up the session.

As for "we can't ask questions from india".  I went through my logs recently (in
response to the claim from another person.  Over 13% of the people who ask
questions and put a location in -- are from India.  Now, that doesn't count
people who put "bombay" as their location -- I just looked for "india".  You are
not under-represented is what I'm trying to say...

Rating: 5
What about South Africans??? October 01, 2001
Reviewer: A reader from South Africa
I'm sure we are under represented too!!!  :-)

October 01, 2001 PERTISTH -- Thanks for the question regarding "HELP REQUIRED with ORA-1031 in a procedure", version 8i
You Asked
Dear Sir
(1) Question related Dynamic Sql
----------------------------------------------------------
procedure create or replace create_mytable is
begin
    execute immediate
    'create table bonus (name number)';
end if;
----------------------------------------------------------
When I execute above procedure, then it gives the error
'ORA : 1031  insufficient system previlage'.

I am Creating and executing this procedute from  system/manager
user.What steps I have to perform to call this procedure without
any errors.

(2) How can I call oracle database procedure/functions from D2K.

(Pertisth Mankotia)
and we said...
Either see
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
(roles are not enabled during the execution of a typical
procedure)

or create the procedure with invokers rights....

Here is an example that shows hows this all works:

tkyte@OSI1.WORLD> create or replace procedure create_mytable
  2  is
  3  begin
  4      execute immediate 'create table bonus (name number)';
  5  end;
  6  /
Procedure created.
That is your procedure as you wrote it basically...

tkyte@OSI1.WORLD> create table bonus (name number);
Table created.

tkyte@OSI1.WORLD> drop table bonus;
Table dropped.

So, the above shows I can in fact create a table directly in
SQL

tkyte@OSI1.WORLD> exec create_myTable
BEGIN create_myTable; END;

*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "TKYTE.CREATE_MYTABLE", line 4
ORA-06512: at line 1

But apparently NOT in plsql.   I could get myself granted
"CREATE TABLE" (not via a role) to fix that (me, the owner of
the procedure)

tkyte@OSI1.WORLD> set role none;
Role set.

tkyte@OSI1.WORLD> create table bonus (name number);
create table bonus (name number)
*
ERROR at line 1:
ORA-01031: insufficient privileges

That just proves that this is a role issue -- without roles, I
cannot create a table

tkyte@OSI1.WORLD> set role all;
Role set.

tkyte@OSI1.WORLD> create or replace procedure create_mytable
  2  AUTHID CURRENT_USER
  3  is
  4  begin
  5      execute immediate 'create table bonus (name number)';
  6  end;
  7  /
Procedure created.

So, now we use invokers rights, thats the AUTHID CURRENT_USER
statment above.  Now the procedure will run with the privs of
the user executing the query PLUS any and all roles they have

tkyte@OSI1.WORLD> exec create_myTable
PL/SQL procedure successfully completed.

and it works...
Review & Followup
Rating: 4
1031 Solution Pin Pointed Exactly May 07, 2001
Reviewer: Amol Joshi from StockHolm-Sweden
Thanks a lot for the solution with explanation :-)

Rating: 3
How should I overcome this error October 01, 2001
Reviewer: Benny
I have 2 schemas

1.test
2.test1

I have an object called  daily_stock_price in test, and I have a synonym called
test1_daily_stock_price , to access that object from test schema.

when Iam running describe or sql on test1_daily_stock_price , I am having no
problems. But now
I want to use  test1_daily_stock_price  in one of my functions which Iam
creating under schema test.

In this function Iam having a select on test1_daily_stock_price  like

select distinct col1.col2 from
test1_daily_stock_price
where col3='1234567'

but Iam getting the pls-00201 identifier test1.daily_stock_price  must be
declared.

then I added the clause authid current_user to the function
but it did not make any difference to, it is still returning the same error.

Create or replace function fn_function(var number)
returning varchar2 is
authid current_user

var2    VARCHAR2(10);
var3    VARCHAR2(10);
var4    VARCHAR2(10);

BEGIN

select distinct col1.col2 INTO VAR2, VAR3 from
test1_daily_stock_price
where col3='1234567'

---

SOME PROCESSING

--

RETURN VAR4;

END;

How should I overcome this error.

Followup:
I have a large chapter on this topic (invoker/definer rights) in my book if
interested.

What I believe is happening here is that you are calling this function from a
DEFINER rights routine.  Have you tried calling it directly (without calling it
from another Definer rights routine?)  That should work.

The issue you are hitting is that as soon as you entered that definer rights
routine, the effective userid changed and roles went away.  Until you EXIT out
of that definer rights procedure -- no roles.  You are back at the beginning
again.

Your solution -- GRANT SELECT on that base table to the owner of the function.

Rating: 3
The function is not even compiling- why October 01, 2001
Reviewer: Benny
test has select privileges on this test1 table, but still when I give authid
current_user , the function is not compiling in test schema.

[1]: (Warning) PLS-00201: identifier 'test1.daily_stock_price
must be declared

Followup:
I can only suggest you typed something in WRONG somewhere.  Here is an example
showing this works as expected:

ops$tkyte@ORA9I.WORLD> drop user test cascade;

User dropped.

ops$tkyte@ORA9I.WORLD> drop user test1 cascade;

User dropped.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> create user test identified by test;

User created.

ops$tkyte@ORA9I.WORLD> grant create session, create table to test;

Grant succeeded.

ops$tkyte@ORA9I.WORLD> alter user test quota unlimited on users default
tablespace users;

User altered.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> create user test1 identified by test1;

User created.

ops$tkyte@ORA9I.WORLD> grant create session, create synonym, create procedure to
test1;

Grant succeeded.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> @connect test/test
ops$tkyte@ORA9I.WORLD> set termout off
test@ORA9I.WORLD> set termout on
test@ORA9I.WORLD>
test@ORA9I.WORLD> create table daily_stock_price ( x int );

Table created.

test@ORA9I.WORLD> grant select on daily_stock_price to test1;

Grant succeeded.

test@ORA9I.WORLD>
test@ORA9I.WORLD> @connect test1/test1
test@ORA9I.WORLD> set termout off
test1@ORA9I.WORLD> set termout on
test1@ORA9I.WORLD>
test1@ORA9I.WORLD> create synonym test1_daily_stock_price for
test.daily_stock_price;

Synonym created.

test1@ORA9I.WORLD>
test1@ORA9I.WORLD> create or replace procedure p
  2  AUTHID CURRENT_USER
  3  as
  4  begin
  5          for x in ( select distinct * from test1_daily_stock_price )
  6          loop
  7                  null;
  8          end loop;
  9  end;
 10  /

Procedure created.

Try that in your own system. (hint: use my advice to "set role none" before
describing the object and tell me what happens then)

Rating: 4
Reader October 01, 2001
Reviewer: Reader from USA
When I perform
sqlplus internal or sql>connect internal as sysdba

and
SQL>select * from session_roles
I get no rows
SQL>select granted_role from dba_role_privs where
    grantee = 'SYS';
I  get 14 roles
SQL>set role all
SQL>select * from session_roles;
I get 14 roles

Are the roles belonging to 'SYS' user automatically assigned
to the session when logged in as 'SYS'

Thanks

Followup:
You are internal or sysdba at that point.  It is special, its magical, its
mystical.  It has all powers, it needs no roles -- it has every privelege.

Rating: 5
This one had me stumped April 11, 2002
Reviewer: Roger Williams from Charlotte, NC USA
But this fixed the problem.
You are a god!

October 02, 2001 omer -- Thanks for the question regarding "Who is an Invoker , and Who is a Definer", version 8.1.7
You Asked
Tom

This is a cabal question, but very important

Who is an invoker? Example for invoker
Who is a Definer ? Example for definer

My comphrehension of the concept:

If I use an object belonging to another schema over which I just select grant,
then Iam the Invoker of that object, where as , as Iam creating the procedure,
Iam also the definer.

Confusing, kindly clarify.
and we said...
well, invoker/definer rights only come into play with procedures/functions and
packages.

The invoker is the caller of the routine.  If I (tkyte) run a stored procedure
owned by you that supports invoker rights - I (tkyte) am the invoker and the
procedure will run its SQL as if I typed it in -- not you.

If I (tkyte) run a stored procedure owned by you that supports definer rights --
I am still the invoker HOWEVER the procedure will run with YOUR privs -- the
DEFINERS privs, not mine.

To add to this -- suppose the definer rights routine YOU wrote calls that
invoker rights routine.  Now, if I (tkyte) call your definer rights procedure --
it'll execute as you and when it calls the invoker rights routine the invoker
this time is YOU -- not me.  When we entered that definer rights routine -- that
definer becomes the invoker for all other calls (unless it calls another definer
rights routine in another schema -- then that schema becomes the invoker)

I've got a pretty good chapter on this topic that goes into this in great depth
in my book if you are interested.
Review & Followup
Rating: 3
misunderstanding October 01, 2001
Reviewer: A reader
Tom

We were under the impression that invokers rights allow you to compile and
execute a procedure even though the schema creating the procedure or function
has privileges over the underlying objects through roles, but not directly.

But your explanation tells us that this is not so.

So this means, if the schema doesnt have direct privileges over say  table T,
there is no way you can use that object in creating your sub program subprogram.

That is final.

Is it so?

Followup:
Invokers rights are compiled no differently then a definers rights routine,
the owner needs to have access to the underlying objects via a direct grant.  In
this respect, at compile time, invokers and definers rights routines are no
different.

(i go into this in great detail, with tons of examples and recommandations on
how to and how not to use this feature in my book if you are interested.  Some
40 pages on this topic alone)

It is only at RUNTIME that the behavior is different.  At runtime, an invokers
rights routine runs under the invokers rights -- much like an anonymous plsql
block (with differences, its not exactly the same).

There is no way using STATIC SQL to create that object, this is true.  But if
you look at:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1035431863958
You'll see that you can create a procedure that can access any object the
invoker can access.  This is what invokers rights routines excell at.  Writing
generic, reusable utilities that work on unknown sets of data using dynamic sql
(either via dbms_sql or using native dynamic sql).

October 02, 2001 Balasubramanian Rengasamy -- Thanks for the question regarding "Dynamic PL/SQL - Error Handling", version 8.1.7
You Asked
Hi Tom,

I have a procedure like this :

begin
   execute immediate '
         create or replace procedure p1
         as
         begin
            l_dummy := 100 ;
         end ; ' ;
exception
   when others then
   begin
      for v_err in (
         select *
         from user_errors
         where name = 'P1' )
      loop
         dbms_output.put_line(v_err.line || '/' || v_err.position
                     || ' ' || v_err.text) ;
      end loop ;
      end ;
end ;
/

In this procedure, i tried to create a procedure dynamically from PL/SQL. I know
the procedure name. So i can get errors from user_errors using the procedure
name. But i have to modify this procedure which will accept procedure text and
it will create. So i don't know the procedure name. How to handle this. i.e i
need a functionality like SHOW ERRORS in SQL*Plus.

Thanks
Bala.
and we said...
Well, SQL*Plus actually parses the command to find the name and type of object
being created -- you could do that OR you could just dump the errors for
anything that has errors and the errors were registered in say the last 5
seconds or so:

ops$tkyte@ORA8I.WORLD> begin
  2     execute immediate '
  3           create or replace procedure p1
  4           as
  5           begin
  6              l_dummy := 100 ;
  7           end ; ' ;
  8          dbms_output.put_line( 'No exception' );
  9  exception
 10     when others then
 11     begin
 12        for v_err in (
 13           select *
 14           from user_errors
 15           where name = (select object_name from user_objects where
last_ddl_time > sysdate-5/24/60/60 ) )
 16        loop
 17           dbms_output.put_line(v_err.line || '/' || v_err.position
 18                       || ' ' || v_err.text) ;
 19        end loop ;
 20        end ;
 21  end ;
 22  /
4/13 PLS-00201: identifier 'L_DUMMY' must be declared
4/13 PL/SQL: Statement ignored

PL/SQL procedure successfully completed.
Review & Followup
Rating: 4
Thanks October 02, 2001
Reviewer: Bala from Singapore
Hi Tom,

Thanks for immediate response.

October 02, 2001 Vincent -- Thanks for the question regarding "Error messages in multithread", version 8.0.5
You Asked
Tom,

I am working on a multithreaded application using multiple context in pro C
(working with Oracle 8.0.5 and Oracle 8.1.7).

I have a problem concerning error messages: I want to get the full error message
-using sqlglm()- but this function does not recover anything with multiple
sql_context (it works fine if there is only the default context).

Is there a way to get the full error message associated to a specific context?

Thanks,
Vincent
and we said...
Search for sqlglmt in the Pro*c guides and it'll point you to the
SQLErrorGetText function which accepts a CONTEXT.

sqlglm and sqlglmt are deprecated in favor SQLErrorGetText.
Review & Followup
Rating: 5
Exactly the information I was missing October 02, 2001
Reviewer: Vincent Vandemeulebrouck
The version of documentation installed on our server did not include the new
thread-safe function prototypes...
Thanks a lot

Vincent

October 02, 2001 Gaurang -- Thanks for the question regarding "Run os command from pl/sql", version 8.1.7
You Asked
hi tom,

I want to run OS command and i am following your code that
you answered previously.

i am running  this dbms_java for permission

I am using personal oracle on windows 98.

begin
        dbms_java.grant_permission
    ( user,
     'java.io.FilePermission',
     '/usr/bin/ls',
     'execute');

      dbms_java.grant_permission
        (user,
        'java.lang.RuntimePermission',
        '*',
        'writeFileDescriptor' );
end;
/
PL/SQL procedure successfully completed.

 I am getting this error message

SQL>  exec rc('dir');
java.security.AccessControlException: the Permission (java.io.FilePermission
<<ALL FILES>> execute) has not been granted by dbms_java.grant_permission to
SchemaProtectionDomain(SCOTT|PolicyTableProxy(SCOTT))
at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
at java.security.AccessController.checkPermission(AccessController.java)
at java.lang.SecurityManager.checkPermission(SecurityManager.java)
at
oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java
)
at java.lang.SecurityManager.checkExec(SecurityManager.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at Util.RunThis(Util:11)

PL/SQL procedure successfully completed.

Thanks

I am using personal oracle on windows 98.
and we said...
dir is not a program.  there is no "dir.exe"

You would have to run cmd.exe or command.exe or whatever and pass it "/c dir"
to have it run the command HOWEVER - i would advise strongly AGAINST that as you
would have to allow this user to run cmd.exe which in effect allows them to RUN
ANYTHING since they can just go "cmd /c anyprogram".

Try your tests with an actual "executable"
Review & Followup
Rating: 2
Why not just use the HOST function? October 02, 2001
Reviewer: A reader from Germany
Why not just use the HOST function in SQL*Plus instead of going through all the
trouble?

Followup:
Because the host command is a SQL*Plus, not a PLSQL command, and people want to
run programs from their stored procedures -- not using SQLPlus.

If you are using SQL*Plus, the host command is the proper way to do it.

If you need to run a command on the server via a stored procedure, SQL*plus does
not do it at all.

Rating: 4
October 02, 2001
Reviewer: A reader
hi tom,

can i run SQLLDR like

rc('SQLLDR XYZ/XYZ@ORACLE CONTROL= .. ')

Thanks

Followup:
yes.  sqlldr is a program so it can be run via this method.

Rating: 4
October 02, 2001
Reviewer: A reader
hi tom,

can i run SQLLDR like

rc('SQLLDR XYZ/XYZ@ORACLE CONTROL= .. ')

Thanks

October 02, 2001 Mohamed -- Thanks for the question regarding "Urgent -- seeing the entire view in sqlplus", version 8.1.5
You Asked
dear tom,

When i try to select the definition of a view (the column text
from the data dictionary view user_views) from
user_views only the first 2 lines of the SELECT clause
are displayed. I need to view the entire query associated
with the view. How can I? Please reply soon. It is very urgent.

regards,
rafi
and we said...
SQL> set long 50000
SQL> select text from all_views where ....;

SQLPlus defaults to a smallish "long" size -- you must set it
larger to see as much as you want.
Review & Followup
Rating: 2
buy a decent tool September 21, 2001
Reviewer: Mikito Harakiri from SF, CA
Since I started using SQLNavigator I never have to remember this ridicule.

Enter an object name in box <enter>. Select a view from the list <enter>. A view
definition is displayed with the syntax higlighted.

Rating: 4
Not being prompted October 02, 2001
Reviewer: A reader
I have saved the following script

-- Display the SQL text for a given view
COLUMN TEXT FORMAT A70
SET LONG 100000
SET PAGES 66
undefine 1
select text
from user_views
where view_name like upper('&1')||'%'

in a file called vtext

and from the sqlplus prompt when I give

@vtext or start vtext, Iam not being prompted to enter the view_name.

Why is this so ?

How should I solve this

Followup:
you are missing the trailing slash "/" or semi-colon ";" to actually run the
query.

put a slash in there.

Rating: 5
Recommendation for the previous poster October 02, 2001
Reviewer: Connor from Wee Scotland
You may as well put this "set long 5000" and anything else thats typically
needed in login.sql which will be run as soon as you connect to SQL Plus.  eg
set lines 120
set pages 99
set trimspool on
etc etc

October 02, 2001 Betty -- Thanks for the question regarding "Export/Import", version 8.1.7
You Asked
I am exporting from owner a, which has all of the tables in tablespace A.  I
want to import into owner b and use that owner's default tablespace B.  Can this
be done and if so how.

Thanks
and we said...
Yes, just make sure that

o B does not have the privilege "UNLIMITED TABLESPACE"
o B has a 0k quota on tablespace A
o B has a sufficient quota on tablespace B

then imp fromuser=a touser=b and the objects will be created in B's default
tablespace.

There will be issues with "multi-segment" objects like partitioned tables, IOTs
with overflow segments and tables with LOBS.  For them, this will not work.  You
will have to pre-create these tables in B's schema and import with ignore=y.
You can get the DDL you need to precreate them via:

imp full=y indexfile=temp.sql

temp.sql will have all of the CREATE TABLES you need -- just update the
tablespaces in them, run them and then

imp fromuser=a touser=b IGNORE=Y
October 05, 2001 omer -- Thanks for the question regarding "when to modularize code by putting into procedures and functions", version 8.1.7
You Asked
"Keep in mind that just calling a stored procedure or function involves
overhead, regardless of the complexity of the code being called."

What kind of overhead is being referenced in the above statement.

"In one instance  we had written a simple leap-year stored function called in
several places by a large SQL statement executed thousands of times in a batch
program.  We improved performance by well over an order of magnitude by
replacing the function calls with the actual leap-year calculation code.  While
this introduced additional redundant code to be concerned about from a
maintenance perspective, the performance benefits were so significant that it
was well worth it."

Iam not convinced with the above statement, didnt we learn that using functions
for oft repeated code is more beneficial. Tom kindly discuss the above statment.

"In cases where it would be possible to remove several SQL calls to the database
and “bundle” into a stored procedure, effectively moving the database access
from the  application code to the database itself, you should expect to see
performance improvements, especially in a slow network environment.  The idea is
to replace several calls to the database with one call to a stored procedure."

Can you give an ideal example for the above.

thank you
and we said...
The overhead of preparing stack space for the called procedure/function,
remembering where in the code you currently are (where to return to when its
done), jumping to the new code and setting up its state -- and then restoring
the state when you return.

Now, given the statement "in one instance ..... was well worth it".  I think
they were comparing:

select *
  from t
 where plsql_function(x,y) = something;

with

select *
  from t
 where (x+y/2) = something;

that is -- comparing calling a PLSQL function from SQL with just doing SQL.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1493455952998
for an example of this.  In that case, they may very will be correct (and they
could/should hide the redundant code via a SINGLE view that contains the
computation!)

HOWEVER, if the code was a plsql function being called by a plsql function --
that order of magnitude would be highly over estimated.  that is, if you have
code like:

 begin
     x := plsql_function(x,y);

     ....

     z := plsql_function(x,y);
  end;

you should probably NOT inline the code as they suggest.  Only inline the code
when you can choose between calling SQL from SQL vs calling PLSQL from SQL --
it'll naturally be much more efficient to do SQL in SQL.

As for the statement "In cases .... with one call to a stored procedure" -- all
they are saying there is that if you can put your transactions into a stored
procedure and do in ONE stored procedure call what would normally take N SQL
statements -- do it, eg, instead of coding in a client:

   delete from t where x = ?;
   update t2 set c = c*1.5 where y = ?;
   insert into t3 values ( ?, ?, ? );
   commit;

you should write a procedure that does the four and just call:

   begin proc( ?, ?, ?, ?, ? ); end;

from your application.
Review & Followup
Rating: 5
Tom, your opinion needed October 04, 2001
Reviewer: Omer
"One technique that has been shown to improve performance significantly in SQR
data conversion programs, is to replace the driving cursor with the use of an
array loaded with the ROWIDs that would have been selected by the driving
cursor. Then, the subsequent updates are performed using the ROWIDs in the
array. NOTE: This also eliminated "Snapshot too old " problems since there was
no SELECT statement open for a long period of time."

Tom do you support the above approach. In what situations we should consider the
above approach , apart from the one mentioned above.

Tom, you are a strong proponent of doing everything in SQL,  but what about the
i/o traffic  generated by these nested subqueries. What do you have to say about
the below

"
SQL statements with nested subqueries can create an enormous amount of i/o
traffic. Listing 1 is a correlated subquery where the outer query is executed
one time for each row returned by the inner query.  Listing 2 produces the same
result but at a fraction of the i/o as it queries the look up table (the
subquery of Listing 3) once, not once per each row.
update EMP
set sal = sal * 10
where exists
(select ‘x’ from DEPT
where DEPT.deptno = EMP.deptno)

Correlated SQL statement
Listing 3

DECLARE
cursor c1 is select deptno from dept;
work_deptno  number;
BEGIN
open c1;
loop
fetch c1 into work_deptno;
EXIT when c1%NOTFOUND
update emp
set sal = sal * 10
where deptno = work_deptno;
end loop;
END;
"

Tom, in what units can we measure the i/o trffic, is there a way we say that the
i/o traffic was units 100 etc.

Thank you

Followup:
for the first thing -- arrays of rowids - it depends on what you are doing.

If the entire thing could be replaced by an elegant UPDATE -- thats the right
answer.  If not, bulk collecting the data -- including the rowid, processing the
data in the arrays and bulk inserting/updating is the next best thing.

As for the second thing -- the nested subqueries -- they do not generate NETWORK
IO -- this example was talking logical IO.

The author should have considered:

update emp set sal = sal*10 where deptno in ( select deptno from dept );

which would have done less logical IO then the exists and would run faster then
writing your own procedural code.  What they've done in their example is sort of
"lie with statistics".  They show you the worst way to write that particular
query and then say "look procedural code is much better".  They should have
rewritten the query.  See:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:953229842074
for an UTTERLY long discussion on IN vs EXISTS and NOT IN vs NOT EXISTS.

You would use tkprof to analyze IO for a statement.  See
http://asktom.oracle.com/~tkyte/tkprof.html
for pointers.

Rating: 4
distinguish October 04, 2001
Reviewer: A reader
Distinguish between network io and logical io. What is the difference between
them.

Followup:
ummm -- network io = bits and bytes that go over the network, between client and
server.

logical io are cached reads from the buffer, instead of reading from disk, we
read from the buffer cache.

apples and oranges.

October 05, 2001 Subramanya -- Thanks for the question regarding "Manipulate a long raw in PLSQL", version
You Asked
Please could you tell me how to insert/
read from  the Long Raw column of
a table  using PL/SQL  ?
and we said...
If the LONG RAW is always 32k or less you can do this in plsql.
If it may exceed 32k in size, plsql *cannot* manipulate it in
any way shape or form.

If the long raw is 32k or less, you simply declare a variable of
type LONG RAW:

declare
    my_var long raw;
begin
    ....

and then you can select into it:

   ...
   select my_long_raw_column into my_var from T where condition;
   ...

To insert a long raw, you do the same as above, only use MY_VAR
in an insert statement.

In order to fully manipulate long raws, you must use a 3gl such
as VB or C/C++.  In Oracle8 release 8.0 and up, a new datatype
LOB is introduced.  PLSQL has full read-write access to a LOB
using the builtin DBMS_LOB package.  See
http://technet.oracle.com/doc/oracle8i_816/appdev.816/index.htm
if you would like
to read about that.
Review & Followup
Rating: 2
Manipulate a long raw in PL/SQL October 05, 2001
Reviewer: Harry
I have long raw wich are longer than 32k, so it is not useful to me.
I have bitmaps in a long raw column which have about 100k an i want them to copy
from table to another.
But I have no idea about how to do this.

Followup:
You must use a 3gl such as C, Java or even VB to do it.  As stated below, you
cannot use plsql.

You should use a blob in 8.0 and above -- incredibly flexible, this would be
trivial with a blob and SQL straight out.

October 05, 2001 -- Thanks for the question regarding "Questons", version 8.1.6
You Asked
Hi, Tom,

1. SQL> select decode(chr(0), null, 'NULL', 'NOT NULL') from dual;

DECODE(C
--------
NOT NULL

Why it is "not NULL", it is supposed to be 'NULL"?

2. Say i have a small flat file(only contain several to hundreds of rows), and i
want to strip out
the various columns from each row and put them into a table. THe format of each
row is like:

row format:   col1|S|TAB|col2|TAB|col3|S|S|S|TAB|col4...........
sample data:  1234       5678     aBDC           12/01/2001 05:09:23........

which col ---- the column name;
      S   ---- Space;
      TAB ---- Tab;

Each column have a value in it and i can determine the position by its "not
null" digit.
I can not use the SQLLODER for some reason, and i have transport the data to the
database side by
using PL/SQL table type. Now what is the most efficient way to strip things out
to each column and
put them into the corresponding column in the table? How many digits "TAB" will
occupy?

My logic is:

Suppose we have the whole data from flat file, and they are in PL/SQL table
"data"

FOR i IN data.FIRST .. data.LAST LOOP
  --each whole line of data(i).
  ?????  How to strip things out of the data(i)????
  ?????  What is the logic or function to strip each column out? ????
END LOOP;

Is the space ' ' or tab '    ' is NULL while we parsing them here in the loop?

3.

g_data is table of records(Table_name%ROWTYPE)

......
.....
FORALL i IN 1..g_data.count
        INSERT INTO T1 (g_data(i).col1, g_data(i).col2, g_data (i).col3,
g_data(i).col4 );

Why:PLS-00436, implimentation restrinction, can nor reference fields of BULK
In-BINd table of records?
And what is work around?

Thanks
and we said...
1) because chr(0) is a one character string.  It is not a NULL string.  Perhaps
you are confusing this with a NULL TERMINATOR in C.  You have a string whose
length is 1, it is most definitely NOT NULL.

2) I would replace the tabs with spaces

  data(i)  := replace( data(i), chr(9), ' ' );

Then I would use my delimited package to parse it out into words -- so I can get
the i'th word from the string
http://osi.oracle.com/~tkyte/SkipCols/index.html
(i know, thats a page about sqlldr, one of the packages on that page is my
delimited package you can use)

3) You can only array (bulk) insert tables of SCALARS -- not elements of tables
of RECORDS.

The workaround is

  for i in 1 .. g_data.count
  loop
      INSERT INTO T1 (g_data(i).col1, g_data(i).col2, g_data (i).col3,
g_data(i).col4 );
  end loop;
Review & Followup
Rating: 3
here's another approach September 26, 2001
Reviewer: A reader from new hampshire
Why not transform your file into something the loader can
deal with e.g. comma delimited columns. Perl is a great
language for such purposes.

Here's a Perl script that will comma delimit your data. In
case you are not familar with Perl, I commented everything.

#!/usr/bin/perl
while (<>)  # read stdin a line at a time
{  # the next command changes one or more occurances of
   # { \r\t\n\f} to a single comma
   s/\s+/,/g;
   s/,$//;       # removes comma at end of line
   $_ = $_."\n"; # appends newline
   print $_;     # write the transformed line to stdout
}

The script can take your file as a commandline arg and will write to stdout.
Just redirect stdout to another file and you're ready to use the loader. I'm
assuming your running on UNIX.

If your runing on Windows, you can still use Perl, but the script won't start
with #!/usr/bin/perl.

Followup:
loader can deal with the file above -- delimited by WHITESPACE.   It would be
possible to load the file using sqlldr without resorting to a "language" like
perl.

They said "I can not use the SQLLODER for some reason, " -- I assumed they mean
"I am NOT ALLOWED to use sqlldr for some reason".

If you use a ctl file lik:

LOAD DATA
INFILE *
INTO TABLE t
REPLACE
fields terminated by whitespace
(
col1, col2, col3, col4
)
BEGINDATA
1234    5678    aBDC    12/10/2001 05:09:23

where od -c shows us:

$ tail -1 t.ctl | od -c
0000000   1   2   3   4      \t   5   6   7   8  \t   a   B   D   C
0000020          \t   1   2   /   1   0   /   2   0   0   1       0   5
0000040   :   0   9   :   2   3  \n
0000047

that the data is delimited by whitespace as specified in the problem, we would
find:

ops$tkyte@ORA9I.WORLD> select * from t;

COL1       COL2       COL3       COL4
---------- ---------- ---------- --------------------
1234       5678       aBDC       12/10/2001

The one problem here is the date with the space and no quotes about it.  Thats
going to be an issue with anything however -- no way to tell the end of FIELD
from the middle of the field.

Rating: 4
comments on Tom's followup September 27, 2001
Reviewer: richard gostanian from new hampshire
Doesn't my comma-delimited transformed file handle the problem with date fields
without quotes? If not, you could
easily write a different perl script to put quotes around the date fields.

Followup:
You'd have to write a more instense parser -- you would turn the space in

12/01/2001 05:09:23

into a comma, effectively splitting the date from the time (just like I did).

I could "easily" do this in sqlldr as well -- the data they have is just not
"easy" to load. It was not designed with loading into a database in mind.

Yes perl could do this, yes sqlldr and plsql could do this.

Rating: 5
Only you know September 27, 2001
Reviewer: Reader from USA
Hi, Tom,

I hve solved the problem and thank you for your efficient reply.

Just don't quite understand why we still need "Replace" function in de_quote
function within the above link:

function de_quote( p_str    IN varchar2,
                   p_enc_by IN varchar2 ) return varchar2
  is
  begin
    return replace( ltrim( rtrim( p_str, p_enc_by ),
                    p_enc_by ),
                    p_enc_by||p_enc_by, p_enc_by );
  end de_quote;

is it handle the default '''' value? Please clarify.

Thanks again

Followup:
In a quoted string - the way to get a quote is to double up the quotes.

that function takes:   'How''s it going'
and returns:            How's it going

If you are loading quoted data with quotes -- this is important.

Rating: 4
File format changed October 03, 2001
Reviewer: READER from USA
Hi, Tom,

Thanks for your former reply, it is really help.

Regarding question 2), they have changed the file format a bit. They are using
ORACLE "spool" tool to generate the file and the delimitor between any two
columns are "irregular" space(s) ---- not fixed number of spaces between any of
the two columns, e.g.:

spool c:    est
select * from all_objects where rownum < 10;
And the file format will be the following, i need to read them in:
----<file start> ----
OWNER       OBJE_N Date              SUBOBJ  OBJECT <more>
----------- ------ ----------------- ------- ------ spaces
SYS         /10    02032001 12:23:00          17039 <more>
SYS         /100                               4648 <more>
SYS         /1032                             17019 <more>
SYS         /1                                 4164  spaces
SYS                                           10827  spaces
SYSTEMS                                       18532  spaces
SYSTEM      /1                                 7230  spaces
SYSTEM      /1                                17881  spaces
SYSTEM      /12                                6846  spaces

9 rows selected.

COSCMUSR@ipvdev> spool off
----<file end>----

Note: in reality, as noted in each line by "<more>" and "space" in the file,
there are more "spaces" padding to the right side of each line. How long for
each line of the result file? is it 256 characters? While i'm using the TextPad
editor, it shows to me that the length is 1001 characters for each line?

Question:
1) How i replace the "spaces" between two columns and by what as a delimitors in
order to use your package?
2) The time portion and date will be messed up after replacing? What is work
around?
3) How to filter(skip) the header, dotted lines and feedback portion(not real
data part) when reading the file line by line? I assump they don't know how to
set header or feedback off by sqlplus while generating the file by spool.
4) I will rtrim "spaces" in the last field after strip the  value off each line,
is it correct?

Thanks

Followup:
1) now that it is a fixed width file -- this is great.  Its easy to load this
directly with sqlldr.  consider a ctl file like:

LOAD DATA
INFILE 'ulcase2.dat'
INTO TABLE EMP

( EMPNO    POSITION(01:04) INTEGER EXTERNAL,
  ENAME    POSITION(06:15) CHAR,
  JOB      POSITION(17:25) CHAR,
  MGR      POSITION(27:30) INTEGER EXTERNAL,
  SAL      POSITION(32:39) DECIMAL EXTERNAL,
  COMM     POSITION(41:48) DECIMAL EXTERNAL,
  DEPTNO   POSITION(50:51) INTEGER EXTERNAL)

Just specify the start/stop positition.  The WIDTH of the file (1001) is a side
effect of them saying "set linesize 1000".  You should ask them to add a "set
trimspool on" in their script, then the file will only be as "wide" as it needs
be.

Also, add:

sqlldr .... SKIP=2 ....

to get rid of the headers (although they could just add:

set feedback off
set heading off
set embedded on

to get a "nice" flat file, no headers, no trailers, just data)

So, if they add:

set trimspool on
set feedback off
set heading off
set embedded on

(meaning you don't need skip=2) and you use the postition syntax, you are good
to go

Rating: 4
Opps -- no sqlldr, only file read October 04, 2001
Reviewer: READER from USA
Hi,

Thanks you for your valuable quick responds.

But i can not use sqlldr(some reason), it is multi-place excution process, and i
have to use TEXT.IO or other tool to read them line by line. So, given that
restriction, how do i do that as specified by the last question?

Thanks

Followup:
read a line and then

column1 := rtrim(substr(line, 1, 10 ));
column2 := rtrim(substr(line, 11, 20));
.....

a simple parse routine will break that right out by position.

Rating: 4
How is the position/length comes October 05, 2001
Reviewer: READER from USA
HI, Tom,

I know i'm keeping you "boring".

How the position  "1", and "10" of "substr(line, 1, 10 )" comes? Is it a guess
or based on my imported table column definition? I can not get it ahead of
reading, because they are from "Access" or whatever other database table, and
what about "SYSTME" length in the avove example is happened to be more than 10
like "SSSSSSYSTTTTEMMMMMMMMM"? please clarify.
Also, provied i can use the SQLLDR, where are the position "01:04" of
"POSITION(01:04)" and other positions coming from ? I think it is based on the
imported table "emp", right?

Thanks

Followup:
If you don't know the fixed length positions of the fields -- you'll have to
parse it yourself I guess.  I sort of assumed that whomever was feeding you the
files would be giving you fixed width files and a file layout.

If they are not -- you'll just have to "parse" around spaces.  something like
(i'll assume you have an "array" type -- a plsql table or collection type --
defined:

function parse_line( p_line in varchar2 ) return array_type
as
   l_data   array_type;
   l_line   long default p_line || ' ';
begin

   loop
      exit when l_line is null;
      l_data(l_data.count) := substr( l_line, 1, instr( l_line, ' ' )-1 );
      l_line := ltrim( substr(l_line, instr(l_line, ' ')+1 ) );
   end loop;

   return l_data;
end;

Now the returned array from that will have each "word" -- similar to the
delimited package i pointed you to.

the numbers I used were simply examples -- a demonstration of how to do it given
you knew the lengths.

October 05, 2001 Trevor -- Thanks for the question regarding "Want form to reconnect automatically following database restart", version 6.0
You Asked
I have a form that runs continuously in the background reading a table on the
database at regular intervals and sending an email for each record that is
found.

At present the form is closed down prior to bringing the database down for
backup purposes, and restarted again after the database has been brought back
up.  This is done overnight via NT Scheduler.  If the database crashes the form
has to be manually stopped and started.

I've tried to get the form to re-logon automatically but get the error
FRM-40029: Already logged on.  I've placed the Logout built-in before the Logon
but this doesn't seem to help.

The form can log itself back on if the session is killed, but fails when the
database is bounced.

Can you help please?

Database is Oracle8i Enterprise Edition Release 8.1.6.0.0
JServer Release 8.1.6.0.0

For info, the basic code is as follows:
When-New-Form-Instance Trigger
  :global.username := Get_Application_Property(USERNAME);
  :global.password := Get_Application_Property(PASSWORD);
  :global.connect_string := Get_Application_Property(CONNECT_STRING);

When-Timer-Expired Trigger  (every ten seconds)
begin
  select sysdate into :GLOBAL.dummy from dual;
exception
when others then
  logout; -- in case session still thought to be logged on !!
  logon(:global.username, :global.password||'@'||:global.connect_string, false);
end;
and we said...
Do you have any problems with doing this in the database instead?  in that
fashion, it'll only run when the database is up and there is no complex process
OUTSIDE of the database.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:255615160805
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1522605935209
for getting java mail loaded into the database (heck -- plsql with UTL_SMTP can
do this easily as well -- search for utl_smtp on my site for details)

I wouldn't do this in forms at all.

If you do do it in forms -- perhaps I would log out and log back in each time,
since its in the background that'll work out fine.

DBMS_JOB + a stored procedure is the way to do it though.

followup to comment

You haven't loaded java into the database.

$ORACLE_HOME/javavm/install/initjvm.sql

Review &
      Followup

      Rating: 4
Thanx - but now
      problem loading plsql.jar  June 27, 2001
Reviewer:
      Trevor  from London, UK
I encountered the error ORA-29540 when using UTL_SMTP and my dba attempted to
load plsql.jar, as per your reply to a previous question, with the following
result:

D:\>cd d:\orant816\plsql\jlib

D:\orant816\plsql\jlib>loadjava -user sys/sys plsql.jar
Error while retrieving errors for oracle/plsql/net/TCPConnection
    ORA-00904: invalid column name

Error while retrieving errors for oracle/plsql/net/InternetAddress
    ORA-00904: invalid column name

Error while creating resource META-INF/MANIFEST.MF
    ORA-29547: Java system class not available: oracle/aurora/rdbms/Compiler

loadjava: 3 errors

D:\orant816\plsql\jlib>

Can you please help!

      Rating:
      4
  October 05, 2001
Reviewer:  Trevor
       from London, England
After one or two problems the dba managed to load initjvm.sql and all is well,
thankyou.

An additional piece of information please..
Is it possible to include an attachment (eg. a txt file) with an email sent
using utl.smtp?  If so, how?

          Followup:

You would have to mime-encode it yourself.  The easiest way to send emails with
attachements is using the JavaMail API.  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:255615160805
for details.

      Rating:
      3
  October 06, 2001
Reviewer:
      A reader
My db is oracle 731, on vms-vax, client winNT4, forms5

my application, periodically (say 5 minutes) looking FTP server direcotry for
data files, transfer it to local pc, proceessing, posting new datafile into FTP.
This is my scnario. I'm using timer-expired trigger for this.

Here i had a problem. If the oracle server is down, then i need to restart my
form again. Is on-logon will workout for me, to logoff and logon?.

How can i overcome this?

October 05, 2001 Jacques -- Thanks for the question regarding
      "Problem with concatenation", version 8i

      You Asked
Hi Tom,

I have the following code that is falling over on concatenation operator with an
error saying that it thinks that the || symbol is a procedure or package and I'm
using the wrong arguments for it.

the line by itself executes fine - just when running it in a Begin end statement
does it give problems.

Normally I work with MSSQL and using a concatenation symbol in a procedure or
piece of code is not a problem - does Oracle handle it differently?

Here is the code

declare cursor tot_cur is
  select distinct substr(Gnac_NO,2)from  gnac_pool where is_Used =1;
  v_1 tot_cur%ROWTYPE;
  BEGIN
    open tot_cur;
    loop
     fetch tot_cur into v_1;
     exit when tot_cur%NOTFOUND;
     insert into gnac_pool values(get_acount(168),0,sysdate,'B'|| v_1 ,0);
    end loop;
  CLOSE tot_cur;
  END;

I'd appreciate any help you could give.

regards

jacques

      and we said...
you are trying to concatenate a record -- v_1 is a record type -- and
concatenation doesn't work with a record.

The proper way to code the entire thing above is:

insert into gnac_pool
select get_account, 0, sysdate, gname_no
  from ( select distinct 'B' || substr( gnac_no,2 )
           from gnac_pool
          where is_used = 1 ),
       ( select get_account(168) get_account, rownum
           from dual )
/

That'll do all of the work of your procedural code, only it'll do it faster and
easier.

In order to fix your procedural code, if for some reason you won't use the
insert/select statement, you need to:

declare
  ...
    select distinct substr( gnac_no, 2 ) X from ....
begin
    ...
    insert into ... , 'B' || v_1.x, 0 );
    ....

Review &
      Followup

      Rating:
      5
Thanks  October 08, 2001
Reviewer:
      Jacques
Thanks for a fast and good response.

jacques

October 05, 2001 -- Thanks for the question regarding "Import
      failed", version 8i

      You Asked
Hi,

 We are creating a test db using the full export dump of the dev db. The plan is
to take a full export dump of the dev, retrieve all the tablespaces information
(dynamically generate CREATE TABLESPACE script), create the test database,
create all the tablespaces using the script created after export from dev,
import.

 The import process reported errors ORA-01658 "unable to create INITIAL extent
for segment in tablespace ...". We are getting all the information to generate
the CREATE TABLESPACE script from the dev db.

 Heres the information we get from the dev db.
from  dba_data_files:
tablespace_name, file_name, FLOOR(bytes/1024)*1024 bytes,
increment_by,autoextensible,maxbytes

from dba_tablespaces:
tablespace_name,FLOOR(initial_extent/1024)*1024 initial_extent,
FLOOR(next_extent/1024)*1024 next_extent, min_extents, max_extents,
pct_increase, contents

The tables which failed had the tbs autoextend off.
Then why is it failing while import in test?

Thanx.

      and we said...
Well, when you export, make SURE you are not using compress=y (the default).
It'll ballon up your tablespaces.  The initial in the export is equal to the sum
of all ALLOCATED extents for the existing table.

Why not just take your backup of dev and restore it on test?  much much faster.

Also- an easier method would just be to create the tabespaces

create tablespace t
datafile 'foo' size 1m
autoextend on next 1m maxsize 2000m;

that way, they will grow to be just as big as you need them dynamically.
October 05, 2001 Ashwin -- Thanks for the question regarding
      "Multiple daily refresh of snapshots", version 7.3.4

      You Asked
Hi,

Just wanted to know how I can do a multiple daily refresh of a snapshot (or a
job for that matter). I know how I could refresh daily at a regular intervals
(every 2 hours etc). But not sure how I can daily refresh at different
predefined times (2am, 10am, 12pm, 5.30pm, etc).
Any pointers in that direction will be helpful. Oradocs did not seem useful for
this.

Thanks
Ashwin

      and we said...
You can write a function to compute the next and schedule the refresh job
yourself (this shows how to get a job to execute whenever you want according to
some algorithm):

ops$ora734@ORA734.WORLD> create snapshot s
  2  refresh complete
  3  as
  4  select * from scott.emp;

Snapshot created.

ops$ora734@ORA734.WORLD>
ops$ora734@ORA734.WORLD> declare
  2          l_job    number;
  3  begin
  4          dbms_job.submit( l_job,
  5                           'dbms_snapshot.refresh( ''S'' );',
  6                            next_date_function,
  7                           'next_date_function' );
  8          dbms_output.put_line( 'Job ' || l_job || ' submitted' );
  9  end;
 10  /
Job 5 submitted

PL/SQL procedure successfully completed.

ops$ora734@ORA734.WORLD>
ops$ora734@ORA734.WORLD> select job, what,
  2         to_char(next_date,'dd-mon-yyyy hh24:mi') next,
  3         to_char(sysdate,'dd-mon-yyyy hh24:mi') now
  4   from user_jobs;

       JOB WHAT                           NEXT              NOW
---------- ------------------------------ ---------------   ---------------
         5 dbms_snapshot.refresh( 'S' );  05-oct-2001 17:30 05-oct-2001 15:51

So, the next is 5:30pm since it is after 12pm but before 5:30pm....

October 05, 2001 Joe -- Thanks for the question regarding
      "Dedicate Background Process", version 8.1.7

      You Asked
On Unix, the database session generated background dedicated process like
following exeample: (DEV2 is the SID name)

#ps -ef| grep DEV2
.
.
oracle 25651  1  0   Oct 01 ?  0:30 oracleDEV2
(DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))

oracle 25643     1  0   Oct 01 ? 0:27 oracleDEV2
(DESCRIPTION=(LOCAL=no)(ADDRESS=(PROTOCOL=BEQ)))
.
.

Is anyway to find out these processes belongs to which database session? The
reason I ask this question is becase sometime after I kill one session in the
database, it still leave the Unix process that generated by the session on the
background holding the resource.

Thnaks,

Joe He.

      and we said...
before you kill it, run a query like this.  This gets the dedicated server and
client pid for YOUR session -- change it (line 5) to get it for THEIR session:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select a.spid dedicated_server,
  2             b.process clientpid
  3    from v$process a, v$session b
  4   where a.addr = b.paddr
  5     and b.audsid = userenv('sessionid')
  6  /

DEDICATED CLIENTPID
--------- ---------
1729      1728

ops$tkyte@ORA817DEV.US.ORACLE.COM> !ps -auxww | grep 1729
ora817    1729  0.2 16.2271088246320 ?        S 15:55:59  0:00 oracleora817dev
(DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))

ops$tkyte@ORA817DEV.US.ORACLE.COM> !ps -auxww | grep 1728
tkyte     1728  0.1  0.4 9552 5712 pts/7    S 15:55:59  0:00 sqlplus /

October 06, 2001 Mark -- Thanks for the question regarding
      "Package header/body diff. 8i & 9i", version 8.1.7

      You Asked
Tom:

Consider the following:

SQL> connect scott@cds2
Enter password:
Connected.
SQL> @get_version

PRODUCT                          VERSION
-------------------------------- --------------------------------
NLSRTL                           3.4.1.0.0
Oracle8i Enterprise Edition      8.1.7.2.1
PL/SQL                           8.1.7.2.0
TNS for 32-bit Windows:          8.1.7.2.0

4 rows selected.

SQL> create or replace package mtest as
  2  procedure aproc(p_in varchar2 default null);
  3  end;
  4  /

Package created.

SQL> create or replace package body mtest as
  2  procedure aproc(p_in varchar2 default 'abc') is
  3  begin
  4  null;
  5  end;
  6  end;
  7  /

Package body created.

SQL> show errors
No errors.

SQL> connect scott@cds1
Enter password:
Connected.
SQL> @get_version

PRODUCT                          VERSION
-------------------------------- --------------------------------
NLSRTL                           9.0.1.1.1
Oracle9i Enterprise Edition      9.0.1.1.1
PL/SQL                           9.0.1.1.1
TNS for 32-bit Windows:          9.0.1.1.0

4 rows selected.

SQL> create or replace package mtest as
  2  procedure aproc(p_in varchar2 default null);
  3  end;
  4  /

Package created.

SQL> create or replace package body mtest as
  2  procedure aproc(p_in varchar2 default 'abc') is
  3  begin
  4  null;
  5  end;
  6  end;
  7  /

Warning: Package Body created with compilation errors.

SQL> show errors
Errors for PACKAGE BODY MTEST:

LINE/COL
---------------------------------------------------------------------
ERROR
---------------------------------------------------------------------
2/17
PLS-00593: default value of parameter "P_IN" in body must match that of spec

SQL>

I understand the error message from 9i - I'm just wondering why I don't get the
same error message from 8i?

Thanks,

Mark

      and we said...
It was a bug -- the spec always determined what would actually be defaulted, the
body was ignored.  This bug was corrected in 9i so this programming error would
be detected by the compiler.

The spec and body must match exactly now.
Review &
      Followup

      Rating: 5
Designer
      Bug  October 07, 2001
Reviewer:  Mark A.
      Williams  from Indianapolis, IN USA
Tom:

I was looking for confirmation on this, as there is a bug (#1236289) in Designer
that is marked as fixed.  The problem is, the "fix" changed the default value
for a parameter in the package body only, and not in the package spec as well.
So, as you've pointed out, the package spec default value (which is apparently
incorrect) still "wins" over the changed package body default value.

I always appreciate your prompt responses and insight...

- Mark

October 06, 2001 Umesh -- Thanks for the question regarding "Long
      Tablespace", version 8.1.6.0

      You Asked
Hi Tom,

1. What is LONG tablespace type ? How do I make use of it?

2. </quote> "In the multithreaded server architectur , many users share a number
of server process. InOracle terms, youmay have 2000 users logged on to an Oracle
database ( In fact the Oracle database may have only 100 users(server processes)
logged on, but each server process is servicing 20 end users) " </quote>

I tried reading this from a tuning book never understood this as I am not aware
of multithreaded servers.. What is this 100 server process and 20 end users ??

3. </quote> An Indexing Check List
        Is the primary key unique? If yes , define an index ; indexes enforce
uniqueness </quote>

what does this mean ? Primary key has a unique index right? Already you have a
primary key Why shuld I create a unique index ?

      and we said...
1) there is no long tablespace type.  There is a LONG datatype provided for
backwards compatiblity with Oracle7.x.  You should not use LONG datatypes in 8.x
and up, you use the CLOB type instead.

2) see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c07procs.htm#18572
3) No, you should not define a unique index, you should add a primary key --
we'll add the PROPER type of index (if any is actually needed to be added) for
you.

You should add a primary key constraint, not an index, to have a primary key.

Indexes used to support primary keys may or may not be unique, we can use either
or.

October 07, 2001 Raja -- Thanks for the question regarding "need
      truncate privilege to a user and it should have drop table privs.",
      version 8.1.6

      You Asked
Need to have truncate privilege for one user at the same time user should not be
able to drop the table.  Is there any way to give privilege as mentioned above.
Appreciate your help on this.

raja.

      and we said...
This is what stored procedures are all about -- encapsulating privileges as
exactly the level you want them to be.

Have the owner of the table issue:

create or replace procedure truncate_the_table
as
begin
  execute immediate 'truncate table t';
end;

and grant execute on that procedure to whomever should have that ability (yes,
you can parameterize the table name if need be).

Review &
      Followup

      Rating:
      5
  September 10, 2003
Reviewer:
      A reader

October 07, 2001 Jayaraman -- Thanks for the question regarding
      "RBO Vs CBO", version 8.1.6.0.0

      You Asked
Hi Tom
Thanks for your earlier help on many issues......
I have used Oracle 7.3.4 and also Oracle 8.1.6. Now in the book by Mr.Niemic on
performance tuning, he has stated that in a query that selects from more than
one table the order of choosing the driving table is optimizer dependent. In
case of RBO it is the last table in the from clause and in the case of CBO it is
the first table in the from clause. He also states that using a hint the driving
table can be changed (/*+ ORDERED */).
Does it mean that whenever we use a hint then Oracle will process the query
based on CBO ? Is it applicable in version 7.3.4? If it is CBO then it would
expect the tables to have been analyzed and have statistics built on them. In
case the tables are not analyzed then will it result in poor performance?

Another tip in the book states that in case of 'OR' condition always use it with
a 'RULE' hint as otherwise it would result in a full table scan even though
indexes might be available. IS this specific to pre8i releases or all releases
of Oracle and is also RBO/CBO dependent? Kindly explain in detail.

What are the advantages/disadvantages of having a temporary tablespace as
'TEMPORARY' or 'PERMAMNENT'? Under what situation we should go for which?

Thanks a lot in advance as always and looking forward to your continued service
and guidance. BTW is your book 'Expert One on One' available in Seoul, S.Korea.
I need to buy it.....

With regards,
Ashok

      and we said...
No, I don't believe Mr Niemic would say "the CBO chooses the FIRST" unless he
was talking about the /*+ ORDERED */ hint.

Under the CBO, the order of the tables is quite simply "not relevant".  the
driving table is choosen from ANY of the tables in the from clause based on
statistics.  If you use the ORDERED hint, it uses them from left to right
(whereas the RBO uses them from RIGHT to LEFT -- perhaps he was contrasting
that).

When you use a HINT, CBO is used (unless of course, the hint is /*+ RULE */).
This is true in all releases of Oracle from 7.0 on up.  It *could* result in
poor query plans if the tables are not analyzed HOWEVER, with HINTS you are
telling it what the plan should be and if possible it typically uses your ideas,
hence, the plan will be as bad as you make it be.

As for the OR condition -- do what I would do, test the theory to destruction.
Its very easy to test these things out (i do it constantly).  I find him to be
wrong in this case with some simple tests (but I don't have his book, this
statement may be taken out of context so I cannot say "he is wrong", just that
what you paraphrase would be "wrong")

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t as select * from all_objects;

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table t add constraint t_pk primary key
(object_id);

Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze table t compute statistics
  2  for table
  3  for all indexes
  4  for all indexed columns;

Table analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace traceonly explain
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t where object_id = 5 or
object_id = 10;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=2 Bytes=194)
   1    0   INLIST ITERATOR
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=4 Card=2 Bytes=194)
   3    2       INDEX (RANGE SCAN) OF 'T_PK' (UNIQUE) (Cost=2 Card=2)

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace off

Now, I did that (in 7.x had to add more rows to T since all objects was only
about 1,000 rows back then, I just ran:

insert /*+ append */ into t select
 OWNER, OBJECT_NAME, OBJECT_ID+max_obj_id, OBJECT_TYPE,
 CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS
from t, ( select max(object_id)+50 max_obj_id from t )
/

to double its size) in versions 817, 806, 734, 716.  In ALL releases, the index
was used in various ways.  the inlist interator was a new 8.x feature, in 716
the plan was (predates autotrace in plus):

select *
from
 t where object_id = 5 or object_id = 10

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.05          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          4          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.01       0.05          0          4          0           0

Misses in library cache during parse: 1
Optimizer hint: CHOOSE
Parsing user id: 9  (ORA716)

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   HINT: CHOOSE
      0   CONCATENATION
      0    TABLE ACCESS   HINT: ANALYZED (BY ROWID) OF 'T'
      1     INDEX   HINT: ANALYZED (UNIQUE SCAN) OF 'T_PK' (UNIQUE)
      0    TABLE ACCESS   HINT: ANALYZED (BY ROWID) OF 'T'
      1     INDEX   HINT: ANALYZED (UNIQUE SCAN) OF 'T_PK' (UNIQUE)

show it has always used the index with OR's when it makes sense. (i despise
blanket statements, rules of thumb -- they are ALWAYS wrong as often as they are
right)

You should NEVER have a temporary tablespace with PERMANENT attributes -- never.
 Its slow, it adds overhead to the entire system.  SMON has to clean it up.  Its
a hassle to allocate space in.  Use TEMPORARY tablespaces for TEMP.

I'll ask wrox about the book in S. Korea, I'm not sure.
Review &
      Followup

      Rating:
      4
Lucid  October 07, 2001
Reviewer:
      Jayaraman Ashok  from Seoul, Korea
Thanks Tom for the quick response.


Subject | Article | Last Updated (East coast time)
Caluculating the total money due | article only | Oct 08, 2001 08:06 am
update data in multithreaded process | article only | Oct 09, 2001 07:54 am
export/import table mode | article only | Oct 09, 2001 08:12 am
daily database growth | article only | Oct 09, 2001 08:19 am
A simple Endless query | article only | Oct 09, 2001 03:14 pm
RULE on 806/816 | article only | Oct 09, 2001 08:13 pm
explicit versus implicit cursor | article only | Oct 10, 2001 08:21 am
data transfer | article only | Oct 10, 2001 09:56 am
database fundmental | article only | Oct 10, 2001 10:16 am
Problem while retreiving Records from the Nested Table........... | article only | Oct 10, 2001 11:19 am
How Oracle updates indexes? | article only | Oct 10, 2001 12:28 pm
Date Problems!! | article only | Oct 10, 2001 02:07 pm
HOW TO COMMIT SOME DMLS AND ROLLBACK OTHERS IN SAME TRANSACTION | article only | Oct 10, 2001 02:35 pm
to convert into 12876 to 12880,12874 to 12870 | article only | Oct 10, 2001 06:37 pm
select tables from a schema, order by size? | article only | Oct 10, 2001 06:42 pm
A query with a "group by" clause | article only | Oct 10, 2001 06:44 pm
Multiple lines merged into Continous lines... | article only | Oct 11, 2001 07:04 am
Parallel queries really work parallelly when there is one CPU and one disk and no partitions? | article only | Oct 11, 2001 07:10 pm
Where is the OCP Program Candidate guide? | article only | Oct 11, 2001 07:15 pm
Java classes in D2k 6i | article only | Oct 12, 2001 01:07 pm
Sessions | article only | Oct 12, 2001 01:34 pm
List and then Delete Rows | article only | Oct 12, 2001 03:09 pm
sql statement, sqlplus, and function | article only | Oct 13, 2001 01:29 pm
Analyze | article only | Oct 13, 2001 01:34 pm
Virtual Database | article only | Oct 13, 2001 03:13 pm
All the v$ views my schema has access to | article only | Oct 13, 2001 03:36 pm
how to get the partition size | article only | Oct 14, 2001 12:14 pm
In pl/sql i want to update morethan 100 tables at once using cursor and dynamic sql | article only | Oct 14, 2001 12:23 pm
Crash course in Number, Integer, smallint ? Confusion ... | article only | Oct 14, 2001 02:16 pm
A way to refer to all columns of a table in a trigger? Like A.*, sysdate from table A? | article only | Oct 14, 2001 02:28 pm
Redo Log Size | article only | Oct 14, 2001 06:29 pm
Partitionned Tables | article only | Oct 14, 2001 07:26 pm
row(s) 1 - 32 of 32
October 08, 2001 Sam -- Thanks for the question regarding "Caluculating the total money due", version 8.1.7
You Asked
Tom

Scenario:

Uncle Jim, has not been paid from Jan'1st of 2001.
Now uncle Jim doesnt even remember how much he has to be paid.

But he remembers the formula for computing the total bucks due to him, from his
greedy employer, who is extremely desirous of acquiring possessions, and all
this at the expense of poor uncle JIM.

The formula is

Hourly Rage:90 bucks per hour(my uncle Jim , works in the Information technology
Sector)

Number of hours per day:8 ( no overtime allowed)

Holidays: Except for Sundays and Saturday's he is given no other holidays.

Now uncle JIM ,  is desperate to know the money due to him as of today, i.e.
October 6th, 2001.

The catch is he wants to use our SQL to do that.

Can you please tell him and us , as to how to do this calculation in
SQL.

Sam
and we said...
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:185012348071
just select count(*) * 8 * 90 instead of just select count(*) to get the payout.
Review & Followup
Rating: 5
Need to Correct the Query October 08, 2001
Reviewer: Asif Momen from Riyadh
Hi Tom,

  The above query is just wonderful. But, you need to correct it. Instead of
using "rownum-1", you need to select only "rownum". The reason is, for the first
record "rownum-1" will return 0 and the Where Clause
to_char(to_date('&2')+rnum-1, 'DY') not in ('SAT', 'SUN') will evaluate for a
day before the range specified.

Lets take your example of 01-feb-2000 and 29-feb-2000. The Where Calsuse will
execute for 31-jan-2000. In the above case as 31-jan-2000 is neither a sunday
nor a saturday, the output no. of records is correct, but will fail if you
consider 01-may-2000 and 31-my-2000. for that matter any date range starting
from monday.

Regards,

Asif Momen

Followup:
Yes, you are correct, fixed the code above.  thanks for pointing that out!

October 09, 2001 Sudhir -- Thanks for the question regarding "update data in multithreaded process", version 8.1.7.2
You Asked
Hi Tom!

Thanks for your everlasting knowledge sharing!

I have a question:

Lets assume I have table t with columns c1, c2 etc.
Data is being entered into t by various processes. Similarly, let's say
processes p1 and p2 are actually reading the data entered in t and processing
it.

My question is what is the best/easiest way to achieve this?

For example

process p1:
select * from t where c1='Process now' for update;
update t set c1='Processing' where c1='Processing now';
do the processing ...
update t set c1='Processing done' where c1='Processing';
commit;

process p2:
select * from t where c1='Process now' for update;
update t set c1='Processing' where c1='Processing now';
do the processing ...
update t set c1='Processing done' where c1='Processing';
commit;

So how can this be accomplished without p1 and p2 stepping on each other as they
wake up randomly and run.

If some table column needs to be added that is ok as well.

Thanks for your help
Both
and we said...
This is a CLASSIC example of when you want to use messaging.

You are attempting to implement the classic "multiple consumers of a queue of
information in a database".

Instead of writing your own (which you will find to be extremely difficult at
best, especially in a highly concurrent fashion -- rdbms's were not designed to
do this queue processing), I suggest you use the builtin queueing mechanism
afforded by the AQ in Oracle.  See
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76938/toc.htm
this gives you queueing in the database, with multiple -- highly concurrent
queue consumer abilities.  You get many other things as well such as message
routing and prioritization and so on.

You clients will put messages in the queue (instead of inserting a row in a
table), your consumers will recieve the message, process the message and put
data into some other table (typically -- they can do whatever they like).
Review & Followup
Rating: 5
For long term I agree with you 100%, but for short term what is simple way October 06, 2001
Reviewer: A reader
if there is one.

If t.c1 is a numeric data then last digit of t.c1 will be handled by p1 if
between 0-5 else handled by p2. But this is very narrow solution

or if t.c1 is char then last char a-l by p1 remaining by p2.

You have brought to my attention AQ which I did not think in this context or new
much at all. This gives me more reason to know that. Thanks for that.

I am sure all readers appreciate your help. I know I do.

Followup:
It sounds like you are still in development (else you would have encountered
this)

This is the short term answer, use AQ.  I would strongly encourage you to NOT
use the undocumented feature connor alludes to as its behaviour is subject to
sudden change, it doesn't work with all sql queries, you don't know how it
works, and support won't touch it with a 10 foot pole if there is any issue
regarding it.

Rating: 5
SKIP LOCKED October 07, 2001
Reviewer: Connor from Wet Scotland
There is a "select for update skip locked" mechanism which allows to lock a
record after skipping over the ones already locked.  This can be helpful for
multiple consumers.

Followup:
sure there is -- AQ uses it.

It is undocumented.
It is not supported for external use.
It works only in special conditions (it is not a general purpose command).

I would still recommend using AQ since it is supported, has tons of other
features they would need to build themselves, and provides all of the
functionality they need "out of the box".

Rating: 5
Tom, we are in production but recently we are seeing some blocking locks October 07, 2001
Reviewer: A reader from cincinnati
between two processes I mentioned earlier.

select * from t for update -- this is ANSI I assume
select * from t for update skip locked -- this is not ANSI?

I suspect the design of the program was based on one of it running at a time,
but in reality to keep up with volume someone has run muliple daemons and thus
the problem. I guess the architect team will have to consider AQ to solve the
problem. I was trying to see if any other way exists around such problem.

Thank you

Followup:
It is not only "not" ANSI, it is

o not documented
o not supported
o not a good idea to use it.

If you don't believe me, please contact support and ask them if it is OK to use
this -- will you still be supported in your production application.

Ultimately, the decision is yours.  You have my opinion.  Technically, there is
no reason it would not work -- however, given the above points, I cannot suggest
you look at it.

Rating: 4
Tom, I totally agree with you! October 08, 2001
Reviewer: A reader
I do not wish to use undocumented processes at all.

Thank you

Rating: 4
What about managing it as a "todo list"? October 09, 2001
Reviewer: Maurizio De Giorgi from ITALY
I agree with Tom: AQ is definitely the solution.
Nevertheless, while reengineering the application, it could be useful a fast to
implement workaround.

Manage it as a todo list. Instead of "skip locked" use for update with "nowait"
and trap "already locked" exception.

What do you think Tom?

Followup:
Yes, you could:

create or replace function get_a_row return t%rowtype
as
    l_rec t%rowtype;
begin
    for x in ( select rowid rid from t )
    loop
    begin
        select * into l_rec
          from t
         where rowid = x.rid
           FOR UPDATE NOWAIT;

        return l_rec;

    exception
        when others then NULL;
    end;
    end loop;
    return NULL;
end;
/

that'll either return a record that is yours (locked) or NULL.

October 09, 2001 NP -- Thanks for the question regarding "export/import table mode ", version 8.1.6
You Asked
HI Tom,
Please let us know how to handle a large table say 2 million records and
increasing daily by 5,000 new  records and 1000 records updated , for export and
import.
I want to export it from database and want to import it other reporting
database.On daily basis it is very difficult task to export and import and
validate other objects based on that table,if table has to drop befroe import
,further import takes a very long time to complete.

Is there a way to export such table on incremental basis that can export only
the new records and the records that changed since the last export.so as things
can made simpler.

Thanks
NP
and we said...
Sounds like you want a read only snapshot (materialized view) that refreshes
once a day.

See:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76959/mview.htm#25269
it will pull over ONLY changes at the time of day you specify.
Review & Followup
Rating: 4
impact October 08, 2001
Reviewer: NP from Bkk
Hi Tom,
Yaa its help, but please explain its impact on storage ,performence or any
other.
As new records inserted and old gets updated ,snapshot log have to manage a long
list of all the changes. how to manage it over a long period of time.

In second option (not applied yet) ,is it possible or a solution to apply logs
of one data base to other as in case of Standby database.

Thanks NP

Followup:
Its not a "list of changes", its a HEAP of changes.  We insert a small record
into the log for each insert/update/delete.  We do not "organize" them, its a
simple small insert into a table.

When you refresh -- the heap of changes "goes away".  The heap of changes is
only as big as it needs to be to go from one refresh to the next.  If you modify
6000 rows a day (5k inserts, 1k updates) this table will have 6k rows in it max
-- at any point in time, if you refresh once a day.

A couple of points:

o 2 million records is not large, not at all.
o you add 1.8 million records a year if you are 24x7x365.  That is NOT large at
all.

You might be scared thinking these are large numbers, they really ARE NOT.

A standby database could be used if the secondary instance only needs to be
READ.  We support a READ ONLY standby database as well.

October 09, 2001 Ram -- Thanks for the question regarding "daily database growth", version 8.1.6
You Asked
Hi Tom,
Could u please explain how to check or estimate the size of databse growing
daily in production environment.
Thanks
Ram
and we said...
Depends on how you want to measure it.

Object by Object, use dbms_space to see the allocated vs used, perhaps "save"
that information by object into a table with a timestamp so you can report on
the growth of objects day by day.

Search this search for dbms_space to see an exmaple using it.

Aggregate level -- just query dba_datafiles and dba_free_space, again perhaps
saving the information in a table so you can report on it.  Search this site for
free.sql to get a good query for that.
October 09, 2001 -- Thanks for the question regarding "A simple Endless query", version 817
You Asked
Hi Tom
I have the following query that goes on fetching endlessly till I kill the
process.

select a.ord_id,a.pseg_id,a.cust_id,
b.prod_id, c.mod_id, d.ch_id, e.mkt_id, f.agg_id,
0,0,0,0,0,0,0
from a,b,c,d,e,f
where b.pseg_id=a.pseg_id and
d.oc_segid=a.oc_segid

Hash Join
  Table Access[Full]--B
  Hash Join
    Table access[Full]--D
    Merge Join[Cartesian]
      Merge Join[Cartesian]
         Merge Join[Cartesian]
            Table Access[Full]--C
            Sort[Join]
                Table Access[Full]--E
         Sort [Join]
            Table Access[Full]--F
      Sort[Join]
           Table Access[Full]--A

The problem with this query is that even though the tables it accesses & join
contain very few records but it fetches millions of records and keeps on going
on till it blasts the resources.First time I killed it had fetched 20 million
records, second time I killed it had over 100 million records. So this query
goes in a loop.
Can you please help me in solving this puzzle.
Number of Records:
A  - 1
B-  2062
C-   1
D-  1022
E-   1
F-  139

Thanks
and we said...
that query by its very definition generates:

292,923,596

records.  You join A(1 row) to B and  A(1 row) to D.

You have NO other join conditions.  Therefore, the database joins every row in B
with every row in D with every row in F

thats 2062 * 1022 * 139 = 292923596

It is doing exactly what you asked it to do.  Perhaps you need to post the
question you are trying to answer and we could help you find the query.

The query is not in a loop.  You just never fetched the last row.  You were
about 1/3 of the way there though.
Review & Followup
Rating: 5
Cartesian product October 09, 2001
Reviewer: Vikram from Phoenix
Also the Explain of the statement tells that it is generating a Cartesian
product.
For simple joins (without funtion joins), the explain plan is pretty reliable

October 09, 2001 mike -- Thanks for the question regarding "RULE on 806/816", version 806/816
You Asked
Tom,
The customer had exported/imorpted a instance from  8.0.6 to 8.1.6.
Some queries behave different on 816 as compared to 806 for
the RULE base.

As the following example.

1)Under 816 the logical reads 76260, as 2203479 under 806;
2)For the row counts
Under 816 was     54  SORT GROUP BY, as  2197586  under 806, please notice the
both returned 54 rows.

I think the problem in 2) caused a lot more logical reads, but
I can not figure out the reasons for the different.

Thanks

ON 8.0.6

SELECT GL_ACCT_NUM,SUM(DECODE(DB_CR_IND,'D',TRANS_AMOUNT,0))
TRANS_DR_AMT
,SUM(DECODE(DB_CR_IND,'C',TRANS_AMOUNT,0)) TRANS_CR_AMT
FROM AP_TRANS_REG
,SUM(DECODE(DB_CR_IND,'C',TRANS_AMOUNT,0)) TRANS_CR_AMT
FROM AP_TRANS_REG
WHERE GL_NOT_POSTED_IND IS NULL
AND ACCT_PERIOD >= '200000'
GROUP BY GL_ACCT_NUM

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.03       0.03          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        5    492.79     515.97      78137    2203479          0          54
------- ------  -------- ---------- ---------- ----------  ---------- ----------
total        7    492.82     516.00      78137    2203479          0          54

Misses in library cache during parse: 1
Optimizer goal: RULE
Parsing user id: 1883

Rows     Row Source Operation
-------  ---------------------------------------------------
2197586  SORT GROUP BY
2197586   TABLE ACCESS BY INDEX ROWID AP_TRANS_REG
2197587    INDEX RANGE SCAN (object id 133784)

---------------------------------------------------------------------------------
---------------

ON 816

SELECT GL_ACCT_NUM,SUM(DECODE(DB_CR_IND,'D',TRANS_AMOUNT,0))
TRANS_DR_AMT
,SUM(DECODE(DB_CR_IND,'C',TRANS_AMOUNT,0)) TRANS_CR_AMT
FROM AP_TRANS_REG
WHERE GL_NOT_POSTED_IND IS NULL
AND ACCT_PERIOD >= '200000'
GROUP BY GL_ACCT_NUM

call     count       cpu    elapsed       disk      query   current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.11       0.13          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        5    106.82     107.89      76258      76260          0          54
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        7    106.93     108.02      76258      76260          0          54

Misses in library cache during parse: 1
Optimizer goal: RULE
Parsing user id: 440

Rows     Row Source Operation
-------  ---------------------------------------------------
     54  SORT GROUP BY
2183806   TABLE ACCESS BY INDEX ROWID AP_TRANS_REG
2183807    INDEX RANGE SCAN (object id 89427)

********************************************************************************
and we said...
The report changed between 80 and 81 -- the rows column is the number of rows
flowing OUT of the step in 81, in 80 it was the number of rows flowing INTO the
step.  That explains the row counts.

As for the logical reads -- a  couple of things may account for that.

1) the 806 database -- was there concurrent updates/inserts/deletes that did not
take place in 8i during the test?  If so, you are seeing read asides to the
rollback segments.

2) the data in the 80 database might be less organized then the data in the 8i
database.  Analyze the index and look at the cluster_factor.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:913264544589
for an example.  In the 8i database, the data might be clustered better.

3) the data is massively chained/migrated in 80 and not so in 8i. Analyze the
table and list the chained rows to see how bad the table is.
Review & Followup
Rating: 5
Greeeeeeeeeeeeeeeeeeeeeeeat Service October 06, 2001
Reviewer: Rajeev Sharma from Seattle, Washington
I just saw this Site when searching for BLOB column upload and dowloads. Its the
most amazing site I have found on Oracle Help. Its Very well Organised, Context
Search is very good and on Top of it Quality of soutions offered is the best.

Rating: 5
October 07, 2001
Reviewer: mike from atlanta
the 806 is on NCR vs the 816 on HP. HP has more CPUs and higher clock speed. And
the database configures, such as db_buffers shared_pool etc, are the same. The
No. of current users were close and the activities were similar as the tests
occured.

Followup:
Then I would say it is purely based on the organization of the data.

Here is an example that shows this.  All of these tables have the SAME data,
they are just physically organized on disk differently:

ops$tkyte@ORA817DEV.US.ORACLE.COM> REM create table clustered
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM as
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM select * from all_objects
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM order by object_id
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM /
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM create unique index clustered_idx on
clustered(object_id)
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM /
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM create table not_clustered
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM as
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM select * from all_objects
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM order by dbms_random.random
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM /
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM create unique index not_clustered_idx on
not_clustered(object_id)
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM /
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM create table migrated
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM pctfree 0
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM as
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM select * from all_objects where 1=0
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM /
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM alter table migrated modify owner null;
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM alter table migrated modify object_name
null;
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM alter table migrated modify created null;
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM alter table migrated modify last_ddl_time
null;
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM insert /*+ APPEND */ into migrated
(object_id)
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM select object_id from clustered order by
object_id;
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM commit;
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM update migrated
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM set (owner,object_name,subobject_name,
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
object_id,data_object_id,object_type,created,
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM     last_ddl_time,timestamp,status,
temporary,
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM     generated, secondary ) =
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM (select
owner,object_name,subobject_name,object_id,
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM       data_object_id,object_type,created,
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM    last_ddl_time,timestamp,status,
temporary,
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM       generated, secondary
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM from clustered where object_id =
migrated.object_id )
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM /
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM create unique index migrated_idx on
migrated(object_id);
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze index clustered_idx compute
statistics;

Index analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze index not_clustered_idx compute
statistics;

Index analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze index migrated_idx compute
statistics;

Index analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select index_name, clustering_factor
  2    from user_indexes
  3   where index_name like '%CLUST%' or index_name like '%MIGRAT%';

INDEX_NAME                     CLUSTERING_FACTOR
------------------------------ -----------------
CLUSTERED_IDX                                231
MIGRATED_IDX                                  26
NOT_CLUSTERED_IDX                          16822

thats show the clustered_idx, with a factor near number of blocks, is "good".
The Migrated index looks good TOO -- but we'd have to analyze the table and list
the chained rows to see each row is migrated (and hence, its not as good as it
looks.  The not clustered index, with a factor near the number of rows, is not
"good".

The queries prove this out:

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec show_space( 'CLUSTERED' );
Free Blocks.............................0
Total Blocks............................256
Total Bytes.............................2097152
Unused Blocks...........................24
Unused Bytes............................196608
Last Used Ext FileId....................7
Last Used Ext BlockId...................5961
Last Used Block.........................40

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace traceonly
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from clustered where object_id > 0;

16883 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'CLUSTERED'
   2    1     INDEX (RANGE SCAN) OF 'CLUSTERED_IDX' (UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       2503  consistent gets
          0  physical reads
          0  redo size
    1864141  bytes sent via SQL*Net to client
     125305  bytes received via SQL*Net from client
       1127  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      16883  rows processed

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from not_clustered where object_id >
0;

16885 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'NOT_CLUSTERED'
   2    1     INDEX (RANGE SCAN) OF 'NOT_CLUSTERED_IDX' (UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      17987  consistent gets
          0  physical reads
          0  redo size
    1864393  bytes sent via SQL*Net to client
     125305  bytes received via SQL*Net from client
       1127  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      16885  rows processed

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from migrated where object_id > 0;

16883 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'MIGRATED'
   2    1     INDEX (RANGE SCAN) OF 'MIGRATED_IDX' (UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      34385  consistent gets
          0  physical reads
          0  redo size
    1864141  bytes sent via SQL*Net to client
     125305  bytes received via SQL*Net from client
       1127  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      16883  rows processed

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace off

Rating: 5
October 07, 2001
Reviewer: mike from atlanta
Here are the statistics on 806/816

The index 2 was used in the query.

on 806

toolman@dfpt.world> select t.table_name, t.num_rows,t.last_analyzed,
t.CHAIN_CNT, d.CLUSTERING_FACTO
R
  2  ,d.index_name
  3  from dba_tables t, dba_indexes d
  4  where t.owner=d.owner and t.table_name=d.table_name
  5  and t.table_name='AP_TRANS_REG'
  6  order by 5;

TABLE NAME              NUM_ROWS LAST_ANAL CHAIN_CNT CLUSTERING_FACTOR INDEX
NAME
---------------------- --------- --------- --------- -----------------
--------------------
AP_TRANS_REG             2054064 07-OCT-01         0                 0
AP_TRANS_REG_NDX7
                         2054064 07-OCT-01         0               126
AP_TRANS_REG_NDX6
                         2054064 07-OCT-01         0             71567
AP_TRANS_REG_NDX1
                         2054064 07-OCT-01         0            101664
AP_TRANS_REG_PK
                         2054064 07-OCT-01         0            159771
AP_TRANS_REG_NDX
                         2054064 07-OCT-01         0            165381
AP_TRANS_REG_NDX2
                         2054064 07-OCT-01         0            433191
AP_TRANS_REG_NDX5
                         2054064 07-OCT-01         0            544119
AP_TRANS_REG_NDX4
                         2054064 07-OCT-01         0            945116
AP_TRANS_REG_NDX3

On 816

TABLE NAME       NUM_ROWS LAST_ANAL CHAIN_CNT CLUSTERING_FACTOR INDEX NAME
--------------- --------- --------- --------- -----------------
--------------------
AP_TRANS_REG      2197990 07-OCT-01         0                 0
AP_TRANS_REG_NDX7
                  2197990 07-OCT-01         0               375
AP_TRANS_REG_NDX6
                  2197990 07-OCT-01         0             75494
AP_TRANS_REG_NDX1
                  2197990 07-OCT-01         0             82388 AP_TRANS_REG_PK
                  2197990 07-OCT-01         0            152321 AP_TRANS_REG_NDX
                  2197990 07-OCT-01         0            228418
AP_TRANS_REG_NDX2
                  2197990 07-OCT-01         0            476819
AP_TRANS_REG_NDX5
                  2197990 07-OCT-01         0            613830
AP_TRANS_REG_NDX4
                  2197990 07-OCT-01         0            783461
AP_TRANS_REG_NDX3

Followup:
Well,  not knowing what "index 2" is (you should really format things so they
are readable and be explicit -- i SUPPOSE you might mean AP_TRANS_REG_NDX2 -- in
which case the other information is "noise" and just in the way?)

An export import can do this as well. You've rebuilt the objects -- they are
phyiscally organized differently.

For example:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table dirty
  2  as
  3  select * from
  4    (select owner,object_name,subobject_name,
  5           object_id,data_object_id,object_type,created,
  6           last_ddl_time,timestamp,status, temporary,
  7           generated, secondary
  8      from all_objects
  9    union all
 10    select owner,object_name,subobject_name,
 11           -object_id,data_object_id,object_type,created,
 12           last_ddl_time,timestamp,status, temporary,
 13           generated, secondary
 14      from all_objects, (select 1 x from all_users where rownum <= 10 )
 15          )
 16   order by abs(object_id)
 17  /
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index dirty_idx on dirty(object_id)
  2  /
Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from dirty where object_id < 0
  2  /
168920 rows deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM> commit
  2  /
Commit complete.

ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace traceonly

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from dirty where object_id > 0;
16892 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'DIRTY'
   2    1     INDEX (RANGE SCAN) OF 'DIRTY_IDX' (NON-UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       6654  consistent gets
       1650  physical reads
     118020  redo size
    1865290  bytes sent via SQL*Net to client
     125416  bytes received via SQL*Net from client
       1128  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      16892  rows processed

ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace off

now, lets "export/import" it (create table as select is good enough for
this)

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table dirty_to_clean as select * from
dirty order by object_id;

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index dirty_to_clean_idx on
dirty_to_clean(object_id);

Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace traceonly
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from dirty_to_clean where object_id
> 0;

16892 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'DIRTY_TO_CLEAN'
   2    1     INDEX (RANGE SCAN) OF 'DIRTY_TO_CLEAN_IDX' (NON-UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       2506  consistent gets
        268  physical reads
          0  redo size
    1865290  bytes sent via SQL*Net to client
     125416  bytes received via SQL*Net from client
       1128  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      16892  rows processed

Its just the way the data is organized on disk, nothing more, nothing less.

You might consider however that retrieving that many rows via an index is
typically a BAD BAD thing, this query looks like it would benefit from a FULL
SCAN in any regards.

Rating: 4
thanks for your input October 08, 2001
Reviewer: mike from atlanta
I understand of your arguments, by these would not apply to my case.
* the import was full database.
* the statistics show no much different in terms of row chians and
cluster_factors

I understand that FTS might be better for the query, but that argument may not
relate/explain the hugh logical reads on the 806 for the current query.

Followup:
The IMPORT could do it.

My last example with the DIRTY table and the DIRTY_TO_CLEAN shows the before and
after effects of an exp/imp.

the DIRTY table represents the 8.0.6 table.  It has had lots of updates,
inserts, deletes done against it.

The DIRTY_TO_CLEAN table represents the 8.1.6 table -- nicely loaded, fresh,
less DML has been performed on it, blocks are nicely formatted, packed full of
data, better organized.

To me - this explains it.  Try this, on the 8.0.6 system -- rebuild that table.
See what happens.

Rating: 3
question October 08, 2001
Reviewer: mike from atlanta
On your import:
"
now, lets "export/import" it (create table as select is good enough for
                       this)

                       ops$tkyte@ORA817DEV.US.ORACLE.COM> create table
dirty_to_clean as select * from
                       dirty order by object_id;

"

looks like you added the "order by", I am not sure that was the same case you
doing a full database import? As I said the import was FULL import.

Followup:
I did that to ensure the two had the same cluster factor.  I used the same thing
on:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table dirty
  2  as
  3  select * from
  4    (select owner,object_name,subobject_name,
  5           object_id,data_object_id,object_type,created,
  6           last_ddl_time,timestamp,status, temporary,
  7           generated, secondary
  8      from all_objects
  9    union all
 10    select owner,object_name,subobject_name,
 11           -object_id,data_object_id,object_type,created,
 12           last_ddl_time,timestamp,status, temporary,
 13           generated, secondary
 14      from all_objects, (select 1 x from all_users where rownum <= 10 )
 15          )
 16   order by abs(object_id)
 17  /
Table created.

Ok, if you don't believe it, I'll do this then:

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

$ exp userid=/ tables=dirty

Export: Release 8.1.7.2.0 - Production on Mon Oct 8 16:10:04 2001
(c) Copyright 2000 Oracle Corporation.  All rights reserved.
Connected to: Oracle8i Enterprise Edition Release 8.1.7.2.0 - Production
With the Partitioning option
JServer Release 8.1.7.2.0 - Production
Export done in US7ASCII character set and WE8ISO8859P1 NCHAR character set
server uses WE8ISO8859P1 character set (possible charset conversion)

About to export specified tables via Conventional Path ...
. . exporting table                          DIRTY      16892 rows exported
Export terminated successfully without warnings.

$ exit

ops$tkyte@ORA817DEV.US.ORACLE.COM> rename dirty to hold;
Table renamed.

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

$ imp userid=/ full=y

Import: Release 8.1.7.2.0 - Production on Mon Oct 8 16:10:25 2001
(c) Copyright 2000 Oracle Corporation.  All rights reserved.
Connected to: Oracle8i Enterprise Edition Release 8.1.7.2.0 - Production
With the Partitioning option
JServer Release 8.1.7.2.0 - Production

Export file created by EXPORT:V08.01.07 via conventional path
import done in US7ASCII character set and WE8ISO8859P1 NCHAR character set
import server uses WE8ISO8859P1 character set (possible charset conversion)
. importing OPS$TKYTE's objects into OPS$TKYTE
. . importing table                        "DIRTY"      16892 rows imported
IMP-00015: following statement failed because the object already exists:
 "CREATE INDEX "DIRTY_IDX" ON "DIRTY" ("OBJECT_ID" )  PCTFREE 10 INITRANS 2 M"
 "AXTRANS 255 STORAGE(INITIAL 524288)                    LOGGING"
Import terminated successfully with warnings.

$ exit

ops$tkyte@ORA817DEV.US.ORACLE.COM> CREATE INDEX "DIRTY_IDX2"ON "DIRTY"
("OBJECT_ID" )  PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 524288);
Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace traceonly
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from dirty where object_id > 0;

16892 rows selected.

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'DIRTY'
   2    1     INDEX (RANGE SCAN) OF 'DIRTY_IDX2' (NON-UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       2505  consistent gets
         37  physical reads
          0  redo size
    1865290  bytes sent via SQL*Net to client
     125416  bytes received via SQL*Net from client
       1128  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      16892  rows processed

Rating: 4
I will try as you advised October 08, 2001
Reviewer: mike from atlanta

Rating: 3
tests on slightly different way inorder to illustrate the problem October 09, 2001
Reviewer: mike from atlanta
I used a different table/ query for the purpose of testing faster without loss
the general.
(I do not want to use the production tables
, but the simulation should be close to the orignal probelm).

$$$$ on 806/ NCR

toolman@dfpc>  create table t tablespace cefms as select * from dba_objects;

Table created.

toolman@dfpc> create index t_ndx on t (object_id) tablespace cefms_ndx;

Index created.

select owner, sum(object_id)
from t
where last_ddl_time is not null
and object_id < 100000000
group by owner

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        9      2.05       2.05        135       9288          0          76
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       11      2.06       2.06        135       9288          0          76

Misses in library cache during parse: 1
Optimizer goal: RULE
Parsing user id: 429  (TOOLMAN)

Rows     Row Source Operation
-------  ---------------------------------------------------
   9267  SORT GROUP BY
   9267   TABLE ACCESS BY INDEX ROWID T
   9268    INDEX RANGE SCAN (object id 33700)

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: RULE
   9267   SORT (GROUP BY)
   9267    TABLE ACCESS (BY INDEX ROWID) OF 'T'
   9268     INDEX (RANGE SCAN) OF 'T_NDX' (NON-UNIQUE)

********************************************************************************

$$$$ on the 816/ HP

toolman@dfhpo> create table t tablespace cefms as select * from dba_objects;

Table created.

toolman@dfhpo>  create index t_ndx on t (object_id) tablespace cefms_ndx;

Index created.

********************************************************************************

select owner, sum(object_id)
from t
where last_ddl_time is not null
and object_id < 100000000
group by owner

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        4      0.34       0.33        145       4357          0          29
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        6      0.34       0.34        145       4357          0          29

Misses in library cache during parse: 1
Optimizer goal: RULE
Parsing user id: 487  (TOOLMAN)

Rows     Row Source Operation
-------  ---------------------------------------------------
     29  SORT GROUP BY
   9877   TABLE ACCESS BY INDEX ROWID T
   9878    INDEX RANGE SCAN (object id 11939)

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: RULE
     29   SORT (GROUP BY)
   9877    TABLE ACCESS (BY INDEX ROWID) OF 'T'
   9878     INDEX (RANGE SCAN) OF 'T_NDX' (NON-UNIQUE)

********************************************************************************

Can you explain why the 806 has 9288 logical reads vs 4357 on the 816?
I believe that because row counts on 816 was 29 vs 9287 on the 806. I think
because of the different of 8i and 8.0. There was the improvement made on 8i on
that aspect.

Followup:
Ok, i did this test (8k blocksize):

set echo on

drop table t;

create table t ( x number, y varchar2(255) );

begin
    for i in 1 .. 10000
    loop
        insert into t values ( i, rpad( '*', 100, '*' ) );
    end loop;
end;
/
create index t_idx on t(x);

set arraysize 5000
alter session set sql_trace=true;
set termout off
spool /tmp/x
select * from t where  x > 0;
exit

where I varied the arraysize from 1 to 5000.  interesting results. Here they
are:

arraysize                        806          817
                               query        query
---------------------        --------    ----------
1 (really 2 apparently)        15013        10165
10                             11020         2172
100                            10121          373
1000                           10032          194
5000                           10024          178

So, it would appear the 8i has some optimizations in the number of times it gets
the block -- especially when combined with array fetching (sqlplus does 15 by
default).  Instead of getting the block for each hit in the index as 806 does --
it seems to keep the block during the processing of the array fetch (hence if it
needs to hit the same block N times in one array fetch, it only gets the block
ONCE).

Rating: 5
well done October 09, 2001
Reviewer: mike from atlanta

October 10, 2001 Mikito -- Thanks for the question regarding "explicit versus implicit cursor", version 9.0.1
You Asked
The syntax of implicit cursor is so much nicer than explicit one! However, in
the function below implicit cursor doesn't seem to be working:

CREATE or replace FUNCTION CONCAT_LIST( cur SYS_REFCURSOR )
  RETURN  VARCHAR2 IS
    ret VARCHAR2(32000);
    tmp VARCHAR2(4000);
BEGIN
    FOR c In cur LOOP
       ret := ret || ',' || c.text_field;
    END LOOP;
    /*loop
        fetch cur into tmp;
        exit when cur%NOTFOUND;
            ret := ret || ',' || tmp;
    end loop;*/
    RETURN ret;
END;
/

Am I missing something obvious?
and we said...
Implicit cursors are not only much "nicer", they are faster as well...

In any case, a REF CURSOR is the very definition of an EXPLICIT cursor.  A ref
cursor implies you are being explicit by definition.

An implicit cursor takes care of the OPEN, FETCH and CLOSE.

A ref cursor must be opened by you.  (its a pointer to a query).  Each time
you open it, it can point to a result set that is a different "shape" (number
and types of columns).  Therefore PLSQL cannot automate the FETCH component as
it does not know at compile time WHAT the result set looks like.

Since PLSQL cannot do the open (you must), fetch (it doesn't have enough info),
you must do this.  Hence, it is explicit.

The ref cursor gives you great flexibility -- at the cost of some extra code.
Review & Followup
Rating: 5
Well, maybe SYS_REFCURSOR is a little different? December 10, 2001
Reviewer: Sean M. Dillon from Reston, VA
Well, w/ SYS_REFCURSOR we don't have to OPEN the REF CURSOR but we do have to
close it (according to the DOC):

SQL> create or replace function concat_list( p_cur sys_refcursor )
  2    return  varchar2
  3  is
  4    l_ename  varchar2(20);
  5    l_return varchar2(32767);
  6  begin
  7    loop
  8      fetch p_cur into l_ename;
  9      exit when p_cur%notfound;
 10      l_return := l_return || ',' || l_ename;
 11    end loop;
 12    close p_cur;
 13    return l_return;
 14  end;
 15  /

Function created.

SQL> show error
No errors.
SQL>
SQL> col dname format a14
SQL> col names format a60
SQL> select d.dname,
  2         concat_list(CURSOR(select e.ename from emp e where e.deptno =
d.deptno)) names
  3    from dept d
  4  /
ACCOUNTING     ,CLARK,KING,MILLER
RESEARCH       ,SMITH,JONES,SCOTT,ADAMS,FORD
SALES          ,ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
OPERATIONS

SQL>
SQL> select distinct e1.job title,
  2         concat_list(CURSOR(select e2.ename from emp e2 where e2.job =
e1.job)) names
  3    from emp e1
  4  /
ANALYST        ,SCOTT,FORD
CLERK          ,SMITH,ADAMS,JAMES,MILLER
MANAGER        ,JONES,BLAKE,CLARK
PRESIDENT      ,KING
SALESMAN       ,ALLEN,WARD,MARTIN,TURNER

October 10, 2001 siva rama -- Thanks for the question regarding "data transfer", version 8.1.6
You Asked
Hi Tom

I have requirement like this:

I have two databases which r running in two different locations lets say CA, NY.
for example take dept table. I have 100 records in dept table of CA database and
1000 records at NY database (out of 100 records are same at both locations). Now
I wanted to update dept table of CA databse with 900 records of NY database. How
can I transfer the data from dept table of CA database to dept table of NY
database.

Regards

SivaRam
and we said...
Use database links to connect the two instances.

it would be easiest of course to:

begin
   delete from dept@ca;
   insert into dept@ca select * from dept@ny;
   commit;
end;

The effect would be the same as the slower running:

insert into dept@CA
select * from dept@NY d1
where not exists ( select null from dept@ca d2 where d2.deptno = d1.deptno );
Review & Followup
Rating: 2
Data Transfer October 10, 2001
Reviewer: V.C.Sekhar Parepalli from India
If I get the data in the format of export file, How can I get the same task
done?

Followup:
If you have the data in an export -- by far the easiest is:

drop user X cascade;
create user X ....

import the file.  It has all of the data, indexes, etc.

Everything else is "hard".  You would have to import the data into another
schema (hence you'll do the same amount of work) and then do the insert into ...
select.

Just do the full import and refresh the entire database.  Even better -- ask the
other guys to use transportable tablespaces so you can just attach datafiles
(very fast).

Rating: 2
Data Transfer October 10, 2001
Reviewer: PVC from India
In fact I have similar requirement where in which I am required to do with a
particular user (which may have more than 50 tables). Precisely I want to update
HO Database with the data obtained from Branch Office.

I got the data in the format of an export file from one of our branch. A copy of
the same is to be transferred to HO database on a regular basis.
Now, how can I transfer the data into HO database?

Note: There is no network connectivity between Head Office (HO) and to branch
office. I will get the export file through a floppy / CD / external storage
media.

How can I perform the task.

Early response is highly appreciable and thankful to you.

Rating: 3
use truncate instead of delete October 10, 2001
Reviewer: Mohammed Ahmed from Saudi Arabia
We can user truncate instead of delete which will be faster.

Followup:
maybe it will be -- maybe not.  It would be HARDER for me to explain that,
especially if they have foreign keys and such.

Here, I went for the simple, complete solution.

Rating: 4
Replication Technology October 10, 2001
Reviewer: Mohammed Esmael from Yemen
Weel,we are planing to use this technology in our Company,
Could you please tell me the benifit and side effect of using this Technology
,or any links about that .

October 10, 2001 -- Thanks for the question regarding "database fundmental", version 9i
You Asked
what do you advise me now the tech. for oracle database is changing
even sql,packeage,database release to make update for my career i found a lot of
future now add to oracle 9i database for a DBA where can i began to update .
and we said...
read the documntation.  Its what I do.  Just goto otn.oracle.com under
documentation, get it, read it.

start with the new features guide and then re-read (i assume you already have
read of course) the SERVER CONCEPTS MANUAL -- the most important doc out there.
Then re-read the docs that apply to your job (admin/developer/etc).  Again I say
re-read .....

I re-read them and find something new almost every time.
Review & Followup
Rating: 3
About your book October 10, 2001
Reviewer: A reader
I would like to buy your book 'one on one to Oracle',
could you tell me
1, In your book does it cover 9I?,
2, Does the contents gear to DBA or Developer use?

Followup:
1) the book covers upto Oracle8i release 3 (817).  I choose not to cover 9i as
yet (most people haven't even scratched the functionality of 8i ;)

99% of of it valid for 9i.  9i would just make it a longer book.

Gotta have something for a second edition!

2) It is for both.  The lines between those two jobs blur so much -- there is
tons of stuff in there for both people (at 1260 pages, there was enough room).
The DBA might not read the chapter on external procedures, then again, since
they are responsible for performance, security, setup, configuration, tuning,
etc -- maybe they BETTER read that chapter on external procedures to see what
they are, how they are, security implications and so on.

Rating: 5
ashraf gamal October 11, 2001
Reviewer: A reader

October 10, 2001 Khushru -- Thanks for the question regarding "Problem while retreiving Records from the Nested Table...........", version 8i
You Asked
While trying to Retrieve Rows from the Nested Table the order in which the row
are retrieved are not the same as what was inserted.. The order of retreival is
random in many cases.

Table Structure

DBA_8.1.7>desc nego_parm_set
 Name                       Null?    Type
-------------------------- -------- ---------------
 NEGOTIATION_ID            NOT NULL NUMBER(9)
 PARM_NO                   NOT NULL NUMBER(3)
 PTYPE                     NOT NULL NUMBER(1)
 PCMPROPTR                 NOT NULL VARCHAR2(2)
 PARM_VALUE_DESC_IDS       TYPEDEFI.TAB_PARM_VALUE_DESC_IDS /* Nested Table */
 PARM_MULTI_VALUE          TYPEDEFI.TAB_PARM_VALUE_IDS      /* Nested Table */

The two Nested table types are in the " TYPEDEFI " user  with a single column of
type "NUMBER(9)"

**********  Following rows we have inserted in the table.

SQL> insert into nego_parm_set ( NEGOTIATION_ID ,PARM_NO, PTYPE , PCMPROPTR,
PARM_MULTI_VALUE)
  2  values(15401,5,4,'<',(TYPEDEFI.TAB_PARM_VALUE_IDS(666,7,888))
);

1 row created.

 .
 .
Inserts and Deletes
 .
 .
 .
 .

SQL> commit;

Commit complete.

**************************
Here we are trying to retrieve the row which is inserted first with the
Negotiation_id = 15401

SQL> select * from nego_parm_set where negotiation_id=15401;

NEGOTIATION_ID   PARM_NO     PTYPE PC PARM_VALUE_DESC_IDS
-------------- --------- --------- --
---------------------------------------------------------------------------------
-------------------
         15401         5         4 <  TAB_PARM_VALUE_IDS(7, 888, 666)

************************************************************************
Observe the Order of Retreival is different then what was Inserted.
The problem is that I have written a lot of code on the assumtion that the order
of insertion and retreival is the same. DO I need to change the code that is
written using this assumtion.
and we said...
That is the very definition of a nested table -- the order is not preserved.
 That is one of their key attributes.  They are not arrays (that would
be a varray type).  They are tables and just like any table -- the data does NOT
come out in any specific order without an order by!

You need something to order by or you need to use a varray -- not a nested
table.

see
http://technet.oracle.com/doc/oracle8i_816/appdev.816/a77069/04_colls.htm#24205
<quote>
 Understanding Nested Tables

Within the database, nested tables can be considered one-column database tables.
Oracle stores the rows of a nested table in no particular order. But, when
you retrieve the nested table into a PL/SQL variable, the rows are given
consecutive subscripts starting at 1. That gives you array-like access to
individual rows.
</quote>
Review & Followup
Rating: 5
October 09, 2001
Reviewer: A reader
Apart from the fact that the size of the varrays is fixed, where as that of
nested tables is not, WHAT  are the other differences between the two(important
ones).

Followup:
(my book has lots of info on nested tables and their structure if you are
interested).

Nested tables are REAL tables.  They are a child table with a 16byte RAW foreign
key back to the parent table which has a hidden 16byte raw unique key added for
each nested table attribute.

VARRAYS are stored in blobs.  there are no keys added.  they are stored inline
upto about 4000 bytes and out of line otherwise.

Nested tables can be updated using sql.  I can update a single row of a nested
table.

Varrays are taken OUT of the database, modified and put back in.  No incremental
update/insert/delete.

Nested tables aren't stored or retrieved in any known order unless you use an
ORDER by.

Varrays, since they are just a blob, are stored "as is".

Nested tables can be SPARSE (i can delete an element using .delete in PLSQL)

Varrays are dense.  I cannot delete element 3.  I must "move" 4 to 3, 5 to 4 ...
and trim the collection to remove an element.

Rating: 3
Surprising October 09, 2001
Reviewer: Khushru F Doctor from Ahmedabad/Gujarat/India
Why does the database have to change the order of the data that I am storing.
When we access it is retrieved in the order in which it is stored.... Then can
you explain why the nested table data is not stored accordingly

Followup:
It doesn't change it.

Data is stored in HEAPS.  It just goes in and out.  Data in relational databases
never comes out in the order it went in.  A nested TABLE is a nested TABLE --
not an array.  An array has order, tables very very specifically do not.

We are not changing the order, there never was any order.  Various programming
evnironments give you the ILLUSION of order (they have to, they put it into a
data structure).  In the database, its just data in a table and data in tables
has no inherit order of first in, first out.

I just wrote an article on this topic (getting the "last row") in Oracle
magazine.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:912210644860
for the raw data.  Its just the way every relational database works.  Data is
not stored in any sort of fifo queue.

If you needed order, you needed to use a different datatype (varray, not nested
table) OR you needed to model something in the nested table that could be used
to order the data.

Rating: 4
Reader October 09, 2001
Reviewer: Reader from USA
During an update, the row will be updated in the same
block, IFF the free space (pct free) can fit the whole
row. Am I right. As long as the row is in the same block,
the row directory entry for this row remains the same, and so rowid does not
change. Am I right
<quote>
You might have extent #1 in file 55 and
extent #2 in file 2.   Extent 4 might start on block 555 of file 3, Extent 5
might start on block 2 of file 3.  Rowids are NOT sortable.
<quote>
rowids in extent#1 > in extent#4 > in extent#5 > in extent#2
Does this influence in any way the order of query output

Thanks

Followup:
No, not correct.

PCTFREE applies to inserts.  PCTFREE reserves X% of the block for subsequent
updates.  UPDATES will consume all of the space on the block (else why would we
save that space?)

The rowid for a row doesn't change when you update it except in 2 very special
cases.  If we MIGRATE a row -- the rowid does not change.  We always leave
the HEAD row piece on the original block and just point to where the row really
is.  We never change the rowid due to a row migration.

The only times a rowid will change due to an update are:

o you have a partitioned table, you have enabled row mevement, you update the
partition key and that update causes the row to physically move from one
partition to another.

o you have an IOT.  You update the primary key.  the UROWID (IOT's don't have
real rowids) will change.

Thats it.

As for the last q "Does this influence in any way the order of query output" I
would say "no".  The number of rows will be the same regardless of the physical
storage.  the values of the rows will be the same.  the order, since it is
INDETERMINATE unless you specify an order by -- is not relevant.

Rating: 4
Thanks For Calrifying the Basics October 09, 2001
Reviewer: Khushru F Doctor
The response to my response cleared a lot of my misconceptions. Can you go into
the technical details as to how the data is retrieved "what is the logic". Some
one explained that PCTFREE and PCTUSED influence the way in which the data is
retreived in some way..

Followup:
Well, I have a pretty good discussion on

o HEAP organized tables
o NESTED tables
o (every other type of table we have)
o PCTFREE and PCTUSED

In my book.  It takes much more space to cover this topic then is available
here.  I will recommend that as a resource.

In a nutshell:

data in a table is typically stored in a heap (IOTs, clusters, hash clusters
change that somewhat -- they force an ordering on the data by some KEY).  In a
heap -- data goes where it "fits".  We have lists of blocks that have free space
on them (freelists).  We have blocks that have never had data on them (blocks
above the high water mark (HWM)).  We have blocks that are full - no more
INSERTS can be done to them (but might have space free for UPDATES still --
pctfree controls that).

when you insert a row, we goto the freelist and try to find a block. If we find
a block there -- we use it.

So, lets say you start "clean" -- no rows.  You insert 10 rows.   The first 5 go
onto block 1, the next 4 onto block 2, the last one on block 3.

That means blocks 1 and 2 are "full" -- they are not on the freelist, we filled
them up.  Block 3 is one the freelist.  Blocks 4..n are above the HWM.

Now, you come back and update the first row.  You "shrank it".  The freespace on
that block increases and the block becomes a candidate for insertions again
(pctused controls this).  We put the block back onto the freelist.

Now, you come back later and insert a row.  It MIGHT end up on block 3, it MIGHT
end up on block 1, it MIGHT be so large as to not fit on either of 1 or 3 and
might end up allocating some blocks from above the HWM and go onto block 4.

If the row went onto block 1, it would come out "first" -- before rows on blocks
2 and 3, when you did the select * from that table.

This is what you are seeing with the nested table.  We are simply reusing space
that was released due to updates or deletes.

Rating: 4
Reader October 10, 2001
Reviewer: Reader from USA
I did a test to verify the order of rows output
o Created a table
  t2 (col1 number, col2 char(2000) default 'x');
o inserted 3 rows.
o allocated extent ( datafile size 8k);
o inserted 6 rows.

SQL> select dbms_rowid.ROWID_TO_RESTRICTED(rowid,1),x.col1 from t2 x;

DBMS_ROWID.ROWID_T       COL1
------------------ ----------
00000003.0000.000C          1
00000003.0001.000C          2
00000003.0002.000C          3
00000002.0000.000B          4
00000002.0001.000B          5
00000002.0002.000B          6
00000003.0000.000B          7
00000003.0001.000B          8
00000003.0002.000B          9

o deleted rows 2 and 3
o inserted rows 10, 11

SQL> select dbms_rowid.ROWID_TO_RESTRICTED(rowid,1),x.col1 from t2 x;

DBMS_ROWID.ROWID_T       COL1
------------------ ----------
00000003.0000.000C          1
00000003.0001.000C         10
00000003.0002.000C         11
00000002.0000.000B          4
00000002.0001.000B          5
00000002.0002.000B          6
00000003.0000.000B          7
00000003.0001.000B          8
00000003.0002.000B          9

select * from uet$ where ts# = 11;
segfile#  segblock# ext#, ts#, file#, block#, length
--------  --------- ----- --- ------ ------- --------
12        2         1     11  11     2       2
12        2         0     11  12     2       2

Since the ext# 0 is from file 12 (C), and ext# 1 from file 11 (B), the rows are
returned from file C before file B. Then it is ordered by block# and then row#s

I know, that you prefer us not to use sys.* objects, but
just understand the concept, is this supposition true

Thanks

Followup:
It returns the rows in the order of the EXTENTS.  It is all in how the extents
were allocated in order to the table.  That is the order of the rowids you are
seeing.

Extent 0 comes from file 12.  file 12 will be read before file 11 during a full
scan (all bets are off if you use partitions, parallel query, etc etc etc).

Point is -- DON'T rely on this behavior.  There is nothing saying "this will be
so forever".  If you need to have the data come out in some order -- ORDER BY is
the only way to do that.

October 10, 2001 Alla -- Thanks for the question regarding "How Oracle updates indexes?", version 8.1.7.1.0
You Asked
Our developers create tables and indexes first,
then they load data. Is it correct way? Does Oracle update indexes
on its own? Or indexes must be recreated after major load?
How do we make sure that indexes are up to date after a major load?

What does analyze table compute statistics? If I run it one DBA
told me it makes Oracle to use cost-based optimizer which is in
his opinion often is not making correct decisions.
He prefers using rule-based optimizer and avoids compute statistics unless he
absolutely have to use it. Is this a correct approach?

Thanks a lot

Alla
and we said...
Oracle will maintain the indexes during the load.  It does make sense in many
cases to disable/remove the indexes, bulk load and then build the indexes.  It
can be faster.

Unless you use the CBO you will be missing out on many Oracle features.  I
believe your one DBA is an old time DBA who has made their assumptions and bases
their opinions on software that is many years old.

without CBO you cannot

o use partitioning
o parallel query
o function based indexes
o bitmapped indexes
o index organized tables
o reverse key indexes
o star queries
o index fast full scans, index skip scans (and many other access paths!)
o desc indexes
o (and more -- the list gets longer and longer and longer with each release)

Buy a copy of Jonathan Lewis's "practical Oracle8i" for your DBA and give it to
them as a present.  Make sure they read it.  They'll be better for it.
Review & Followup
Rating: 5
Amazing... October 10, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Every day, I get amazed at and even upset with the number of so-called "Senior
DBAs" and "Database Cobsultants" with so rudimentary knowledge we have to
interact with. Not to mention "unbelievable" solutions to tasks they are
reasonably well-paid to accomplish.

Why don't they just take some courses or read a few books to be up-to-date in
this world where it's mandatory to catch up on the latest technology ? If one
doesn't have this profile, one's better switch careers.

Rating: 4
what privs needed for desc index? October 10, 2001
Reviewer: Sean from Atlanta
it does not work on 8.1.6

Followup:
sure it does.  You'll really need to provide an example.

tkyte@TKYTE816> create user a identified by a;
User created.

tkyte@TKYTE816> grant create session, create table to a;
Grant succeeded.

tkyte@TKYTE816> grant unlimited tablespace to a;
Grant succeeded.

tkyte@TKYTE816> @connect a/a

a@TKYTE816> create table  t( x int, y int );
Table created.

a@TKYTE816> create index t_idx on t (x DESC, y ASC );
Index created.

Rating: 4
I supposed you meant like to show the index definition October 10, 2001
Reviewer: Sean from Atlanta
as to a table/view...

DESC T

and

DESC t_idx

Followup:
Oh, there is no "describe indexname" command (we should all strive to be more
clear in our questions and statements....)

the USER_IND_COLUMNS view is there for that.

October 10, 2001 Hassan -- Thanks for the question regarding "Date Problems!!", version Oracle 7
You Asked
Tom,
     Coming back to the date datatype problems regarding Oracle
7, the earlier answers/suggestions that you gave me worked
pretty fine, specially fecthing the data from the database using
to_date function in the queries. I really appreciate that.
Recently, I have encountered another problem with the date
datatype which seems to be baffling me for the last week or so.
I'm using the queries with the to_date function for fecthing
records from the database with WHERE clause indicating specific
date values and most of the time the query runs fine, but I have
noticed that records which have hiredates in the years 1984 and
1985 does not return any results, although the records exist in
the table. I have even changed the system date to yesr 1999 and
after running the query the records are not fetched. Another
thing which I have noticed is that after altering the session
using the command:
     alter session
set nls_date_format='dd/mm/yyyy'
dates of years 1984 and 1985 have their century changed to 20
i.e, their date format becomes 2084 and 2085 respectively, which
is not in the case of other date values with years other than
1984 and 1985. Similar is the case with year 1994 and 1995!!!!

Why is this????

best regards

Hassan Ayub
and we said...
Someone entered the dates with the years 2084 and 2085.  These
dates are NOT 1984, 1985 -- they are in fact 2084 and 2085.

In Oracle7, the default date format is dd-mon-yy.  If I:

tkyte@ORA734.US.ORACLE.COM> create table t ( x date );

Table created.

tkyte@ORA734.US.ORACLE.COM> insert into t values ( '01-jan-85'
);

1 row created.

tkyte@ORA734.US.ORACLE.COM> select to_char( x, 'dd-mon-yyyy' )
from t;

TO_CHAR(X,'DD-MON-YYYY')
-----------------------------------------------------------------
----------
01-jan-2085

tkyte@ORA734.US.ORACLE.COM>

I can see that the date is in fact 2085, not 1985.  The sample
"scott/tiger" demobld.sql suffers from this problem.  If you run
demobld in a database whose date format is dd-mon-yy,  the emp
table will have these dates:

scott@ORA734.US.ORACLE.COM> select hiredate from emp;

HIREDATE
--------------------
17-dec-2080 00:00:00
20-feb-2081 00:00:00
22-feb-2081 00:00:00
02-apr-2081 00:00:00
28-sep-2081 00:00:00
01-may-2081 00:00:00
09-jun-2081 00:00:00
09-dec-2082 00:00:00
17-nov-2081 00:00:00
08-sep-2081 00:00:00
12-jan-2083 00:00:00
03-dec-2081 00:00:00
03-dec-2081 00:00:00
23-jan-2082 00:00:00

14 rows selected.

scott@ORA734.US.ORACLE.COM>

So, your data is incorrectly entered.
Review & Followup
Rating: 5
October 10, 2001
Reviewer: A reader
SQL> ed
Wrote file afiedt.buf

  1  select to_char(hiredate,'yyyy-month'),empno from emp
  2  group by  to_char(hiredate,'yyyy-month'),empno
  3* order by to_char(hiredate,'yyyy-month')
SQL> /

TO_CHAR(HIREDA      EMPNO
-------------- ----------
1980-december        7369
1981-april           7566
1981-december        7900
1981-december        7902
1981-february        7499
1981-february        7521
1981-june            7782
1981-may             7698
1981-november        7839
1981-september       7654
1981-september       7844

TO_CHAR(HIREDA      EMPNO
-------------- ----------
1982-december        7788
1982-january         7934
1983-january         7876

14 rows selected.

Note:I cannot remove this to_char(hiredate,'yyyy-month') the select

I want the output for everyyear to be shown with months displayed in order from
jan to dec, not mixed.

How can I do it.

The group by also has to stay, I want to achieve this without removing the group
by.

How can I do it.

Followup:
select *
  from ( select to_char(hiredate,'yyyy-month') hiredate,empno
           from emp
          group by to_char(hiredate,'yyyy-month'),empno
       )
 order by to_date( hiredate, 'yyyy-month' );
/

is one method.  do the group by and then put the date back and sort by it as a
date.

A better way is:

select to_char(hiredate,'yyyy-month'), empno
  from ( select trunc(hiredate,'month') hiredate,empno
           from emp
          group by trunc(hiredate,'month'),empno
       )
 order by hiredate
/

which gives the same results.

Rating: 5
problems with dates and date formats November 19, 2001
Reviewer: Nag
Talking about date problems and problems with date formats.
There are quite a few times when we run into format problems.

For example let take the following scenario

Lets say we a have string like 'adc_ytwc_15_oct_2001'

Lets have a variable lv_date which will contain a date value

Now when we need to substr the date part of the above string, convert it into
date and compare it to the date value.

More often than not we continoustly run into  ORA-01858: a non-numeric character
was found where a numeric was expected
- error

Will doing the substr from the start or end of the string, will it make a
difference.

In the example which I tried I tried  , substr('adc_ytwc_15_oct_2001', -11)  )

October 10, 2001 Claudio -- Thanks for the question regarding "HOW TO COMMIT SOME DMLS AND ROLLBACK OTHERS IN SAME TRANSACTION ", version 8.1.7.0.0
You Asked
Estoy tratando de armar un package que maneje una simulacion
esto deberia ser asi, un cursor principal que cicle por personas
luego simule unos pasos en varias tablas (para esto hace varios inserts y
updates en varias tablas).
Luego debo grabar los resultados de la simulacion en otras tablas en forma
agrupada pero sin grabar la simulacion propiamente dicha.
Luego hay que deshacer la simulacion.
Es decir necesito una transaccion dentro de otra, para poner un save point,
hacer la simulacion poner otro save point 2, grabar el resumen de la simulacion
(commit hasta el savepoint 2) y luego deshacer la simulacion (rollback al
savepoint 1)

Ejemplo simplificado
declare
cursor datos is
select n_id_persona from personas;
begin
for reg in datos loop
SAVEPOINT punto_llama;
--esta parte es un ej de la simulacion
insert into compras (n_id_persona, tipo_producto, precio)
values (reg.n_id_persona, 'A', 100);
insert into compras (n_id_persona, tipo_producto, precio)
values (reg.n_id_persona, 'A', 50);
insert into compras (n_id_persona, tipo_producto, precio)
values (reg.n_id_persona, 'B', 700);
--Fin de la simulacion

--Aca recogo los resultados de la simulacion
SAVEPOINT fin_simula;

insert into resu_simula (n_id_persona, tipo_producto, total)
select n_id_persona, tipo_producto, sum(precio)
from compras
where n_id_persona = reg.n_id_persona
group by n_id_persona, tipo_producto;

--Esta parte no se como hacerla
--WHO CAN DO IT
commit to save point fin_simula; --THIS IS NOT ORACLE

--Desago la simulasion
ROLLBACK TO SAVEPOINT punto_llama;
end loop;
end;

O sea la idea seria.
1)poner una marca M1
2)hacer cosas (insert, update, delete)
3)Poner una marca M2
4)Obtener datos de lo hecho entre M1 y M2 y grabarlo con un commit desde aca
hasta el punto M2
5)Volver todo atras lo hecho entre M2 y M1

Claudio.
and we said...
I think you might be interested in AUTONOMOUS_TRANSACTIONS.  They are not
exactly what you are asking for -- you'll need to modularize your example and
use stored procedures (each stored procedure can be an independent transaction)
but it can accomplish your goals.

See
http://osi.oracle.com/~tkyte/autonomous/index.html
for a quick overview of this technology.
Review & Followup
Rating: 1
October 10, 2001
Reviewer: A reader
USE ENGLISH

Followup:
porqué

PLSQL es universal, yo puede leerlo en cualquier lenguaje

(translation thanks to altavista, I speak English, C, Java, SQL and PLSQL (and
some other computer languages I'm not willing to own up to as they would date
me))

Rating: 4
Exelent October 11, 2001
Reviewer: Claudio Palmieri from Argentina
Ya implemente la solucion usando AUTONOMOUS_TRANSACTIONS. Funciono de mil
maravillas, muchas gracias

October 10, 2001 ajay -- Thanks for the question regarding "to convert into 12876 to 12880,12874 to 12870", version 8.1.5
You Asked
hi tom,

i would like to know is there any method to change it into

data is the following mode of numbers

12876
12874
12000
12222

i would like to round off to the multipes of ten, if the last number
is less than 5 make it to next lower of 10. or
if it is more than 5 than next higher of 10.

12880
12870
12000
12220

thanks
ajay
and we said...
ops$tkyte@ORA817DEV.US.ORACLE.COM> select round( 12876/10 ) * 10 from dual;

ROUND(12876/10)*10
------------------
             12880

just divide the column by 10, round, multiply the results by 10.  There you go.
Review & Followup
Rating: 3
Simple & Elegant October 10, 2001
Reviewer: Sanjay Raj from USA
Great

Rating: 2
Easier October 10, 2001
Reviewer: Kathy from Alexandria, Va
The round function will round to the right of the decimal point.  Looks more
clear to someone else

select round(12345,-1), round(12345,-2)
from dual

Returns
select round(12345,-1), round(12345,-2)
from dual

ROUND(12345,-1) ROUND(12345,-2)
--------------- ---------------
          12350           12300
1 row selected

Followup:
good point, thanks

Rating: 3
My favorite... October 10, 2001
Reviewer: David Thompson from Downers Grove, IL USA
I have always liked using the following for stuff like this:

Select
  ROUND(123456,-1)
from
  dual;

Followup:
good point, i slipped up on this one.  I came up with the hard answer ;)

Rating: 3
THANKS October 10, 2001
Reviewer: ajay from india
hi tom
thnaks for ur wonderful reply.

October 10, 2001 Bob -- Thanks for the question regarding "select tables from a schema, order by size?", version 8.1.7
You Asked
Is there a way to select all the tables in a schema, ordering them by the actual
data size (mB) that each table contains?
Bob Maggio
and we said...
If you analyze the tables,

select table_name from user_tables order by blocks;

that'll order by USED space.

otherwise, you can order by ALLOCATED space:

select segment_name from user_segments where segment_type = 'TABLE' order by
blocks;
Review & Followup
Rating: 5
Very good way to monitor your tables' size October 10, 2001
Reviewer: Abdal-Rahman Agha from Yemen
Its very useful information Tom. Also we can display the result in means of
bytes instead of blocks.

Please Tom, I am waiting for you to ask you very important question. When can I
do that?

Followup:
multiply blocks by your blocksize?  thats available in v$parameter if you don't
know what it is

show parameter db_block_size

I take about 20/30 questions a day -- catch as catch can.  Depends on the day as
well.  For example tomorrow (oct 11th) I'm speaking in Boston and then getting
on a plane -- I won't be taking many questions tomorrow.

October 10, 2001 -- Thanks for the question regarding "A query with a "group by" clause", version 8.1.7
You Asked
Hello Tom,

I would need your help to query a table with a  kind of "group by" clause

MY_TABLE :
  LOG_DATE : DATE
  KEY : VARCHAR2
  VALUE : NUMBER

Could you help me to write the following statement :

select KEY, <VALUE1> FIRST, <VALUE2> LAST from MY_TABLE group by KEY
... where <value1> is the oldest (MIN LOG_DATE) value and <value2> is the latest
value (MAX LOG_DATE)of the group

Thanks for your help (one more time...)

Marc
and we said...
Analytic functions RULE:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select distinct deptno,
  2       first_value(ename) over ( partition by deptno order by hiredate ),
  3       first_value(ename) over ( partition by deptno order by hiredate desc
                                                                  NULLS LAST )
  4   from emp
  5  /

    DEPTNO FIRST_VALU FIRST_VALU
---------- ---------- ----------
        10 CLARK      MILLER
        20 A          ADAMS
        30 ALLEN      JAMES

QED.
Review & Followup
Rating: 5
Group by Basics October 10, 2001
Reviewer: A reader
Why cant I use a column alias name in the group by clause, what is the reason
that prevents it.

When I user decode on my columns in the select clause, I can use the whole
decode statement in the group by, the same is not the case with 'case' feature ,
why?

Can I use columns not mentioned in the select clause  in my group by clause.

Followup:
The reason is just in the way SQL is processed.   The SELECT phase is DEAD LAST.
 Happens after all else is pretty much done.  So:

scott@ORA8I.WORLD> select decode( deptno, 10, 'a', 20, 'b', 30, 'c' ) d,
count(*)
  2    from emp
  3   group by d
  4  /
 group by d
          *
ERROR at line 3:
ORA-00904: invalid column name

but the solution is simple:

scott@ORA8I.WORLD> select d, count(*)
  2    from ( select decode( deptno, 10, 'a', 20, 'b', 30, 'c' ) d
  3             from emp ) e
  4   group by d
  5  /

D   COUNT(*)
- ----------
a          3
b          5
c          6

I do not understand your comment about 'CASE':

scott@ORA8I.WORLD> select case when deptno = 10 then 'a'
  2                          when deptno = 20 then 'b'
  3                          when deptno = 30 then 'c'
  4             end,
  5             count(*)
  6    from emp
  7   group by case when deptno = 10 then 'a'
  8                          when deptno = 20 then 'b'
  9                          when deptno = 30 then 'c'
 10                end
 11  /

C   COUNT(*)
- ----------
a          3
b          5
c          6

and yes, you can use columns not mentioned in the select clause

Rating: 5
RE: Can I use... October 10, 2001
Reviewer: Lester Burnhap from Orlando, FL
In regard to 'Can I use columns not mentioned in the select clause in my group
by clause.' in comment one... here's a novel idea - create a table, insert some
data, and try it.  Jeesh.

Rating: 5
October 10, 2001
Reviewer: A reader
The reason is just in the way SQL is processed.   The SELECT phase is DEAD LAST.

 Happens after all else is pretty much done.  So:

scott@ORA8I.WORLD> select decode( deptno, 10, 'a', 20, 'b', 30, 'c' ) d,
count(*)
  2    from emp
  3   group by d
  4  /
 group by d
          *
ERROR at line 3:
ORA-00904: invalid column name

Kindly elaborate the statement '''.   The SELECT phase is DEAD LAST.  Happens
after all else is pretty much done'''
in the light of the above query.

what is this pretty much which happens, what happens before the select phase.

How does the select phase being last , lead to the above query to fail.

Thank you

Followup:
The column D doesn't exist in the group by phase.  the SELECT part hasn't
happened yet.  So, D just isn't there when you group by.  The inline view I used
makes "d" visible to the group by -- we changed the order of things.

Rating: 5
October 10, 2001
Reviewer: A reader
Tom, can you please discuss with us what are the phases of a query.

Can you take a query using all the clauses possible and discuss the above
requested.

Rating: 4
May 14, 2003
Reviewer: sush from sj,usa
Hi Tom ..Below is the scenario.. using oracle 8.1.7 version.

SELECT cis.con_num,
       cc.gu_company_target_id
    FROM  install_site         cis
         ,parties               hp
         ,customers            cs
         ,company_mappings cccm
         ,companies        cc
   WHERE 1=1
     AND cis.con_num                    IN ( '1000026','1000027','1000028)
     AND cis.install_location_type_code = 'HZ_PARTY_SITES'
     AND hp.party_id                    = cis.party_id
     AND cs.source_customer_number      = hp.party_number
     AND cccm.cib_customer_id           = cs.cib_customer_id
     AND cccm.company_target_id         = cc.company_target_id
   GROUP BY cis.con_num ,cc.gu_company_target_id

When I run this query I get the following output.

1000026 1000
1000026 1001
1000027 1003
1000028 1004
1000028 1005

But basically I'm interested to get only 1000027 1003(result set) as it has only
one row.

Is there anyway to achieve it.Thanks

October 11, 2001 M. -- Thanks for the question regarding "Multiple lines merged into Continous lines...", version 8.1.7
You Asked
Hi Tom,

I have multi line comments of varchar2(4000). Is there any way to display in a
continous line and at the end it should become the second line and so on...

Suppose I have this data.

Feb 15, 2001 This Individual has quitted job. Rhonda
Can take short notice
Will be attending summer classes ... Brad.
 "   BLANK LINE   "

I want to display as

Feb 15, 2001 This Individual has quitted job. Rhonda Can take short notice Will
be attending summer classes ... Brad.

Any help is appreciated.
You know even in SQL Plus it displays the results as multi line ...

*******************************************************
I suppose it should be allright if returns first 4000 characters and even it
wouldn't have more than 2000 characters. Actually the comments are stored in a
separate table and about 5000 tables have the comments number, so all the
comments goes in one table.

How can we construct that function??? to return the lines formatted in a
continous lines.
 Thanks.
and we said...
Say the comments table looks like:

create table comments
( comment_id number,
  seq        number,
  text       varchar2(4000),
  primary key (comment_id,seq)
)

You can write a function:

create function get_comments( p_comment_id in number ) return varchar2
as
   l_data long;
begin
   for x in ( select text
                from comments
               where comment_id = p_comment_id
               order by seq )
   loop
     l_data := l_data || x.text;
   end loop;

   return substr( l_data, 1, 4000 );
end;

Now, you can select get_comments from a table...
Review & Followup
Rating: 1
My question is different. October 10, 2001
Reviewer: A reader
Hi Tom,

I suppose you did not get my question, I do have a function that returns the
text, but the problem is that the text is spanned on multiple lines, I want it
to be displayed on a single continous line(s).

Suppose user enters the comments through Oracle Developer Forms, and enters
multiple lines even short lines, but in the query and displaying in the report I
want it to be displayed as continous lines.

Suppose user enters Comments as

Feb 15, 2001 This Individual has quitted job. Rhonda
Can take short notice

Will be attending summer classes ... Brad.
 "   BLANK LINE   "

I want to display as

Feb 15, 2001 This Individual has quitted job. Rhonda Can take short notice Will
be attending summer classes ... Brad.

Followup:
I got the question -- you didn't tell me you had a function, that the line
breaks where still there.  I didn't know there were linefeeds and carriage
returns in there. You simply need to replace them with something else like a
space.

create function get_comments( p_comment_id in number ) return varchar2
as
   l_data long;
begin
   for x in ( select text
                from comments
               where comment_id = p_comment_id
               order by seq )
   loop
     l_data := l_data || translate( x.text, chr(13)||chr(10), '  ' );
   end loop;

   return substr( l_data, 1, 4000 );
end;

Rating: 5
Your Query is here. October 11, 2001
Reviewer: Asif Momen. from Riyadh
Hi,
   Actually when users are entering data they use the Enter key to jump on to
the next line which causes this situation.

Here goes your query.....

SQL> select 'This
  2  is
  3  on
  4  a
  5  multiline.'
  6  from dual;

'THISISONAMULTILINE.'
-----------------------
This
is
on
a
multiline.

SQL> select replace('This
  2  is
  3  on
  4  a
  5  multiline.', chr(10), ' ')
  6  from dual;

REPLACE('THISISONAMULTI
-----------------------
This is on a multiline.

Regards,

Asif Momen.

October 11, 2001 Ping -- Thanks for the question regarding "Parallel queries really work parallelly when there is one CPU and one disk and no partitions?", version 8.1.6
You Asked
Hi Tom,

I am using 8.1.6 on NT, one CPU and one physical disk, and no
partitioned tables. When I create tables with parallel option,
like degree of 5, and do the query on that table, would the
operation really run in parallel? If yes, is the performance
really better? Thanks, Ping
and we said...
The query would be executed with more then one process/thread.
The execution time may be improved -- even with one CPU.  I
would not go more then parallel 2 on a single CPU machine.  You
might notice a performance increase with parallel 2 since when
one thread is processing data it has read -- the other thread
may be waiting for the disk controller to return data it has
requested to be read.  That is, if you are using disks that do
their work independent of the system CPU (eg: SCSI vs IDE), you
may find that when one thread waits for data the other thread
can be processing data.

Parallel 5 on a single CPU might actually DEGRADE performance
since the OS now has to manage lots more things and the
probability of 4 of the 5 things "waiting" for something is low
(hence they will just be getting in eachothers way).

Benchmark it -- thats the only way to truly see for youself.
Review & Followup
Rating: 3
Thread October 11, 2001
Reviewer: A reader
Tom, does thread mean CPU, in the context you used

Summing up what you are concluding above.

One CPU will be reading the data,
where as the second CPU will be processing the data i.e. doing an insert or
update or delete.

Is that what you are trying to say.

If we are not using parallel then , I presume that the same CPU  has to read the
data, finish reading and then process it. ?

"
That is, if you are using disks that do their work independent of the system CPU

(eg: SCSI vs IDE), you may find that when one thread waits for data the other
thread can be processing data

"

what are you intending to convey , when you say ' if you are using disks that do
their work independent of the system CPU'  doesnt CPU AND DISK  have to be in
sync with what ever processing they are doing.

Can you make '(eg: SCSI vs IDE)' more  comprehensible, with there full forms
instead of abbrievations.

Followup:
thread means thread -- a thread of execution.  On NT you generally use "threads"
to multi-task.  On Unix you generally using processes to multi-task.

A cpu is a cpu.  It runs many threads/processes one after the other.

CPU's typically don't read the data (well, there are IDE drives but nobody uses
them for a database machine).  The drives have their own onboard processing
cabilities.

Whilst one process is off busy reading the disks -- the other process can hop on
the SINGLE cpu and munch the data it just read.  That is what I was trying to
say.

see
http://www.acc.umu.se/~sagge/scsi_ide/
(a simple search for "scsi ide" on google turned that up as the first
hit -- they are very very common acronyms)

October 11, 2001 Hardik -- Thanks for the question regarding "Where is the OCP Program Candidate guide?", version
You Asked
dear sir
i am a engineering graduate and i have completed a course in
Oracle and VB from SSI Ltd., Ahmedabad, Gujarat, India. i am
interest in doing OCP course.

i visited the oracle website and learnt that an "OCP Program
Candidate Guide" is available which provides complete
information
on the course.

i would like to know from where can this guide be made
available.
whom should i contact for this guide.

looking forward to an early and favorable response.

thanking you

sincerely

hardik d. shah
and we said...
Each track has its own guide.  If you goto
http://education.oracle.com/certification/index.html
for example and
follow the link to the Oracle8i DBA track (
http://education.oracle.com/certification/dba8i_track.html
 you'll see a
link for the Oracle8i DBA candidate guide.

It is these guides you are looking for.  You pick the track from
the first link above and get the requisite guide.
Review & Followup
Rating: 1
links do not work October 11, 2001
Reviewer: Kathy Burrows from Indianapolis, IN USA
I keep getting URL not found when trying to link to the certification guides.

Followup:
Well, this link:
http://education.oracle.com/certification/index.html
works (it redirected to the proper place).  Then just click on OCP tracks to see
all of the available stuff.  Sorry that it moved but its pretty easy to find
again from the first link.

October 12, 2001 bipin -- Thanks for the question regarding "Java classes in D2k 6i", version forms 6i
You Asked
Sir i 'm using java classes in my forms
but it is working in application server only but not able to get in
two tier system
and we said...
Java classes only work with a Java client.  They work in Developer Server or
using the web preview mode from the forms development environment which uses an
applet viewer.  Java classes in forms running in under MS Windows or x-windows
do not work.
October 12, 2001 Nag -- Thanks for the question regarding "Sessions", version 8.1.7
You Asked
Tom

As promised ( it was a gentle man's promise) Iam reducing the nubmer of
questions and posting only one question.

The following is all one question..

II.
My session is session A. Iam doing a huge insert of 2 million rows into
table T.
What will be the effect on

1.session b  which is trying to do another huge insert.
2.session c which is trying to do a light insert
3.session d which is trying to do a truncate of the table
4.session e which is trying to do a delete on the table
5.session f which is trying to do an update

6.On session A itself , which is also trying to update the table with
an another process.

7.session G which is trying to do a select on the table.

My session is session A. Iam doing a huge UPDATE of 2 million rows into
table T.
What will be the effect on

1.session b  which is trying to do another huge insert.
2.session c which is trying to do a light insert
3.session d which is trying to do a truncate of the table
4.session e which is trying to do a delete on the table
5.session f which is trying to do an update

6.On session A itself , which is also trying to update the table with
an another process.

7.session G which is trying to do a select on the table.

My session is session A. Iam doing a huge DELETE  of 2 million rows
into table T.
What will be the effect on

1.session b  which is trying to do another huge insert.
2.session c which is trying to do a light insert
3.session d which is trying to do a truncate of the table
4.session e which is trying to do a delete on the table
5.session f which is trying to do an update

6.On session A itself , which is also trying to update the table with
an another process.

7.session G which is trying to do a select on the table.

My session is session A. Iam doing a huge SELECT  of 2 million rows
into table T.
What will be the effect on

1.session b  which is trying to do another huge insert.
2.session c which is trying to do a light insert
3.session d which is trying to do a truncate of the table
4.session e which is trying to do a delete on the table
5.session f which is trying to do an update

6.On session A itself , which is also trying to update the table with
an another process.

7.session G which is trying to do a select on the table.

( believe me I conceived this whole as one question , the first time I thought
about it , I did not put together  a bunch of questions.)

Thank you
and we said...
o Big insert

1.session b  which is trying to do another huge insert.

if you have not configured multiple freelists, there may be some contention for
free space in the table, unnecessarily slowing down both insertions.

2.session c which is trying to do a light insert

see #1

3.session d which is trying to do a truncate of the table

no go.  truncate is DDL, its exclusive, it will time out waiting for the
resource.

4.session e which is trying to do a delete on the table

no problems (other then normal overhead due to consistent read mechanisms but
thats OK cause the alternative would be to disallow both operations from
happening at the same time)

5.session f which is trying to do an update

same as 4

6.On session A itself , which is also trying to update the table with
an another process.

huh?? do you mean an autonomous transaction?  if so, same as 4

7.session G which is trying to do a select on the table.

same as 4

o big update.

no different from a big insert.

o big delete

no different from a big update.

o big select

1.session b  which is trying to do another huge insert.

no problems (other then normal overhead due to consistent read mechanisms but
thats OK cause the alternative would be to disallow both operations from
happening at the same time)

2.session c which is trying to do a light insert

same as 1

3.session d which is trying to do a truncate of the table

could hit a problem, could get

select count(*) from big
*
ERROR at line 1:
ORA-08103: object no longer exists

4.session e which is trying to do a delete on the table

same as 1

5.session f which is trying to do an update

same as 1

6.On session A itself , which is also trying to update the table with
an another process.

still don't understand this one.

7.session G which is trying to do a select on the table.
no issue
Review & Followup
Rating: 4
Overhead October 12, 2001
Reviewer: A reader
no problems (other then normal overhead due to consistent read mechanisms but
thats OK cause the alternative would be to disallow both operations from
happening at the same time)

Tom, can you drill into the details othe above 'normal overhead' for consistent
read mechanisms.

Followup:
sure, see
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c23cnsis.htm#17882
it is the fact that when we hit a block whose contents have changed since your
statement (or transaction, depending on your isolation level) began, we do a
read aside to the UNDO information to reconstruct (rollback) that block as it
appeared when you began.  This extra logical (maybe physical) IO is added to
your query.

October 12, 2001 Tom -- Thanks for the question regarding "List and then Delete Rows", version 8.0.6
You Asked
Tom:

I need to list out rows in a table (spool them to a flat file) and then
immediately delete those I just spooled out.  There can be new rows coming into
the table while I'm doing this.

I don't think I should have to write PL/SQL to do this... I know I could write a
cursor, fetch, spool out, then delete "current of" each row, but this seems like
such a simple thing I'm hoping I could run a script to spool it out, save off
the highest insert timestamp (it is saved on each row) and then delete where
timestamp is less than or equal to that.  Or something like that.  Does that
make sense?  Do I need to lock the table or anything?  Should I save off the
timestamp right before or right after starting the spooling?  Note, there is
also a pkey on the table - an ID separate from the timestamp of insert.

Thanks very much for your help that is precise, thorough, tireless, correct,
clearly communicated, and, what sets it apart from those who answer on other
bulletin boards... without attitude.

Tom B.
and we said...
Well, lets say your primary key column is an increasing number and it is called
X.  The following will work for you:

column x new_val x
select * from t ORDER BY x;
delete from t where x < &x;
commit;

the column x new_val x will cause sqlplus to put the last fetched value of x
into a substitution variable &X we can use in the delete.  You just have to
remember to order by that column to make the highest one the last one.

If you use that timestamp -- there is the stick issues of:

o the substition variable would get dd-mon-rr by default (no time), you would
have to TO_CHAR the timestamp to get the date/seconds to make this work

o there is nothing stopping someone from inserting a row in the same second you
start querying data.  Your query won't see their insert for that second but your
delete would.  There is a small chance you would over delete.

the primary key would be a better choice in my opinion.
October 13, 2001 nag -- Thanks for the question regarding "sql statement, sqlplus, and function", version 8.1.7
You Asked
Tom

1. select  dname from dept where deptno=10;

2. create or replace function  tes1t( lv_deptno number)
return varchar2
is
lv_var varchar2(20);
begin
select  dname into lv_var from dept where deptno=lv_deptno ;
return lv_var;
end;

I will execute 1 again and again for 10 times, how times will the statement be
parsed when compared to 10 executtions.

I will execute 2 , 10 times, each time with different parameters( i.e. different
dept number)
how many times will the statement within the function be parsed  when compared
to 10 executions.

kindly take your own example if you want to.

and

what is the difference between executing a statment from the sqlplus prompt, and
executing from from within a function. The difference Iam talking about is in
terms of parsing , i.e.  how many times they will be parsed if I execute them
multiple number of times.

tom thank you
and we said...
I cannot answer this question without knowing the execution environment and how
it was programmed.

Lets say you are just using SQLPlus.  You can answer this easily your self by
running the script:

create or replace function  tes1t( lv_deptno number) return varchar2
is
  lv_var varchar2(20);
begin
  select  dname into lv_var from dept where deptno=lv_deptno ;
  return lv_var;
end;
/

alter session set sql_trace=true;
select dname from dept where deptno = 10;
select dname from dept where deptno = 10;
select dname from dept where deptno = 10;
select dname from dept where deptno = 10;
select dname from dept where deptno = 10;
select dname from dept where deptno = 10;
select dname from dept where deptno = 10;
select dname from dept where deptno = 10;
select dname from dept where deptno = 10;
select dname from dept where deptno = 10;

exec dbms_output.put_line( tes1t(10) );
exec dbms_output.put_line( tes1t(10) );
exec dbms_output.put_line( tes1t(10) );
exec dbms_output.put_line( tes1t(10) );
exec dbms_output.put_line( tes1t(10) );
exec dbms_output.put_line( tes1t(10) );
exec dbms_output.put_line( tes1t(10) );
exec dbms_output.put_line( tes1t(10) );
exec dbms_output.put_line( tes1t(10) );
exec dbms_output.put_line( tes1t(10) );

exit;

Then, a quick glance at the tkprof report will tell us:

select dname
from
 dept where deptno = 10

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse       10      0.00       0.00          0          0          0           0
Execute     10      0.00       0.00          0          0          0           0
Fetch       20      0.00       0.00          0         20          0          10
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       40      0.00       0.00          0         20          0          10

so that query was parsed and executed 10 times -- but that is a side effect of
SQLPlus.  Any good java/jdbc programmer or C programmer (any language goes here)
would have parsed the statement once and executed it ten times (and they would
of course have used BIND VARIABLES, not a constant!)

Looking at the second case, we see:

BEGIN dbms_output.put_line( tes1t(10) ); END;

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse       10      0.01       0.00          0          0          0           0
Execute     10      0.00       0.00          0          0          0          10
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       20      0.01       0.00          0          0          0          10

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 334  (OPS$TKYTE)
********************************************************************************

SELECT DNAME
FROM
 DEPT  WHERE DEPTNO = :b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute     10      0.00       0.00          0          0          0           0
Fetch       10      0.00       0.00          0         20          0          10
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       21      0.00       0.01          0         20          0          10

So here, again, since we used SQLPlus, the initial statement is parsed 10
times, executed 10 times (the call to dbms_output.put_line).  However the query
inside of the procedure is parsed only 1 time and executed 10 times (and it
makes proper use of a bind variable).  Here, PLSQL is silently caching our open
cursor for us, in the hopes we will reuse it (as we did).  This is just one of
the dozens of benefits of using a stored procedure -- it almost forces the use
of bind variables and it reused cursors extremely efficiently.

followup to comment one

If the application is correctly coded by the developer -- NO, it'll be parsed
once and executed 10 times.
Review & Followup
Rating: 5
another related question August 05, 2001
Reviewer: A reader
What if the sql is issued fro within an application, will it parse 10 number of
times?

Rating: 3
follow up to comment one August 06, 2001
Reviewer: Mark from USA
then are you suggesting that the sql be left alone, and that the function need
not be created  the place of repeated sql.

this is really concerning , becasue we were under the impression that, that oft
repeated same sql with different hard coded values for the where clause should
be put in a function , and calls should be made to the function.

can you give a detailed reply, as this is a very important thing which needs to
be cleared

Rating: 3
followup to comment one August 06, 2001
Reviewer: Mark from USA
WHAT DO YOU MEAN BY

"If the application is correctly coded by the developer "

can yu expand on this

Rating: 5
Nag October 12, 2001
Reviewer: Nag
"because SQLPlus uses only one cursor for your statements.  PLSQL caches and
keeps many cursors open for you.  PLSQL is optimized for running SQL and PLSQL
in the database.  SQLPlus is just a simple little interface."

PLSQL is optimized for running SQL and PLSQL
in the database.

Dont pl/sql and sql have separate engines.

Nag

(While trying to post this question to you I discovered that I posted a similar
question to you long back, I think I must have missed out on your response.)

Followup:
No, it is not that they have "separate engines" (there is but one database to
run your sql in here) - it is that they are apples and oranges.

SQLPlus is a command line interface, a small scripting tool.

PLSQL is a language, a programming environment.

They really cannot be compared.  One you write programs with (PLSQL) and with
the other you can run the programs or any sql you want.

October 13, 2001 Srini -- Thanks for the question regarding "Analyze", version 8.1.6
You Asked
Tom,
We have a datawarehouse database.  I do see performance improvements (especially
for big inserts) when the tables are analyzed. How often would you recommend
analyzing the tables? (I am currently doing once a week.  Would you recommend
that all the indexes be analyzed as well when the tables are analyzed.  Is there
a negative impacts on analyzing.

Thanks,

Srini
and we said...
How often does the data change?  In a datawarehouse, there are typically load
schedules.  I would be tempted to incorporate an analyze right after the load
and analyze all of the affected objects.

Our "rule of thumb" is "10% of the data is changed -- time to analyze".  Thats
the percentage we use with our MONITORING feature. So, its not a matter of TIME,
its a matter of change.

So, optimally -- you would incorporate it as part of your load and analyze the
affected objects.  If you want us to figure out what needs to be analyzed, see:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1260600445561
for info on the monitoring clause.
Review & Followup
Rating: 4
what is your 'MONITORING' feature? October 13, 2001
Reviewer: mike from atlanta
"Thats
    the percentage we use with our MONITORING feature"

Followup:
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1260600445561
(the link I have above) for info on monitoring.

October 13, 2001 Reddy -- Thanks for the question regarding "Virtual Database", version 8.1.6
You Asked
Hi tom

I heard from somebody about Viritual Database(s). What is Virtual Database and
How can I create, What is advantages of that.

Thanks in advance

Reddy
and we said...
do you mean a "virtual PRIVATE database"?

It is also known as fine grained access control or DBMS_RLS or row level
security.

See
http://osi.oracle.com/~tkyte/article2/index.html
also, I have a large section on this in my book
Review & Followup
Rating: 3
virutial database October 14, 2001
Reviewer: Reddy from Bangalore,India
Thank you very much Mr. Tom, It is very usefull, Most of the doubts has been
solved with your answer.

Regards

Reddy

October 13, 2001 Nag -- Thanks for the question regarding "All the v$ views my schema has access to", version Nag
You Asked
Tom

How can I know the list of all te v$views which my schema has been given access
to, how should I list them.

Nag
and we said...
select object_name
  from all_objects
 where object_name like 'V\_$%' escape '\';

That'll show the v_$viewname views (not the v$synonym_name) that you have access
to.  You can either query sys.v_$viewname or v$viewname at that point.
Review & Followup
Rating: 5
October 13, 2001
Reviewer: A reader
1.What does 'escape' do , and why are we using it here.

2.What is the difference between x$tables, v_$tables and v$tables?

Followup:
Normally, in a LIKE clause, % is a wildcard that matches 0, 1, or more of
anything.  _ in a like clause is a wildcard that matches exactly 1 of anything.

I wanted to find all things that started with V_$.  The like clause 'V_$%' would
find VA$X, as well as VB$X and V_$X.  The escape clause tells SQL that the
underscore is to be treated as a regular character -- not a wildcard.  In my
case, V\_$% would find V_$X but not VA$X.

x$ tables -- internal, undocumented tables.  Not for general use.  Go ahead and
query them but you are on your own as to figuring out their contents

v$synonym_name and v_$view_name.  For every V_$VIEW there is a corresponding
V$SYNONYM:

tkyte@TKYTE816> select object_name, object_type, owner
  2  from dba_objects where object_name = 'V$STATNAME';

OBJECT_NAME                    OBJECT_TYPE        OWNER
------------------------------ ------------------ ------------------------------
V$STATNAME                     SYNONYM            PUBLIC

tkyte@TKYTE816> c/V$/V_$/
  2* from dba_objects where object_name = 'V_$STATNAME'
tkyte@TKYTE816> /

OBJECT_NAME                    OBJECT_TYPE        OWNER
------------------------------ ------------------ ------------------------------
V_$STATNAME                    VIEW               SYS

You have to be granted access to the view v_$statname for the synonym v$statname
to be meaningful to you.

So, v_$statname is a view, v$statname is a synonym.

(thats why I looked for the views you have access to -- views you do not have
access to will not be visible to you in all_objects.  The synonym v$statname
might be there for you -- but the view will not.  Hence it is a way to see what
v$ views you have access to (look for the view, not the synonym to the view)

Rating: 4
October 13, 2001
Reviewer: A reader
v_$viewname views (not the v$synonym_name)

Does v$synonym_name give the synonyms for the views in
v_$viewname .

Is there any view in the database where you get the new features for a version,
and a view where we can get the license information.

Followup:
I don't understand what you mean by

Does v$synonym_name give the synonyms for the views in
v_$viewname .

As for new features -- no, we ship a new features guide with that..  There is no
list.

There is v$option to see whats enabled in your database.

October 14, 2001 justin -- Thanks for the question regarding "how to get the partition size", version 8.1.5
You Asked
hi tom
     to a partition table how can i get the size of the patitions size from data
dictionary? i need to find if the patition size is
too big.
and we said...
ops$tkyte@ORA817DEV.US.ORACLE.COM> CREATE TABLE t
  2  ( x int )
  3  PARTITION BY RANGE (x)
  4  (
  5  PARTITION part_1 VALUES LESS THAN(2),
  6  PARTITION part_2 VALUES LESS THAN(3)
  7  )
  8  /

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select partition_name, bytes, blocks, extents
  2    from user_segments
  3   where segment_name = 'T'
  4  /

PARTITION_NAME                      BYTES     BLOCKS    EXTENTS
------------------------------ ---------- ---------- ----------
PART_2                             524288         64          1
PART_1                             524288         64          1
October 14, 2001 Venkateswararao -- Thanks for the question regarding "In pl/sql i want to update morethan 100 tables at once using cursor and dynamic sql", version Oracle 8i
You Asked
My Lord Of Oracle U hav to save me by givng new power
U gav oracle we  win every day but u are not telling the secret.

The question is
i hav a user sisi
and got morethan 200 tables
each table has its own primary keys and foreign keys.
i want to update all table which has info  the patientid of other 's which was
wrongly entered.
the data spread in 82 tables.
i wrote cursor to get table name  for update
it is not allowing by giving the error for dynamic sql as it
was unable to for due to the constaraints.
create or replace procedure CHG_careevnts( x1 in varchar2 ,x2 in varchar2 )

AS
s_TableName VARCHAR2(40);
s_SqlStatement VARCHAR2(2000);
i_Count INTEGER;
iCursor INTEGER;
i_Execute INTEGER;
i_LineCount INTEGER;

CURSOR TableNamesCUR IS

SELECT DISTINCT TABLE_NAME

FROM ALL_TAB_COLUMNS

WHERE column_name LIKE 'CARE_EVENT_COUNTER'

AND TABLE_NAME not LIKE 'AUD_%' and

TABLE_NAME not LIKE 'V_%'

AND OWNER = 'SISI'

ORDER BY 1;

BEGIN
i_LineCount := 1;

OPEN TableNamesCur;

LOOP

FETCH TableNamesCur INTO s_TableName;

IF TableNamesCur%FOUND THEN

iCursor := DBMS_SQL.OPEN_CURSOR;

--*************************************************

-- SET SQL STATEMENT

s_SqlStatement := ' UPDATE SISI.' || s_TableName SET PATIENT_ID = 1006
,CARE_EVENT_COUNTER=11 WHERE PATIENT_ID= X1 AND CARE_EVENT_COUNTER=X2 ;

it is gining error here that it is unable to due to constraints
if i disable also it is unable to  do updation as the same key as foreign in
other tables.
-- PARSE STATEMENT

DBMS_SQL.PARSE( iCursor, s_SqlStatement, DBMS_SQL.NATIVE );

i_Execute := DBMS_SQL.EXECUTE( iCursor );

-- DBMS_SQL.FETCH_ROWS( iCursor );

DBMS_SQL.DEFINE_COLUMN( iCursor, 1, i_Count );

Loop

If DBMS_SQL.FETCH_ROWS( iCursor ) != 0 THEN

DBMS_SQL.COLUMN_VALUE( iCursor, 1, i_Count );

If i_Count > 0 THEN

DBMS_OUTPUT.PUT_LINE ( i_LineCount || ' - Table ' || s_TableName || ' has ' ||
i_Count || ' records');

i_LineCount := i_LineCount + 1;
End If;
Exit;
End If;
Exit;
End Loop;
-- CLOSE THE CURSOR
DBMS_SQL.CLOSE_CURSOR( iCursor );
ELSE
EXIT;
END IF;
END LOOP;
CLOSE TableNamesCur;
END CHG_careevnts;

Plz give me a solution to update all table which got the information
actually i hav to change the rong entry table info
example :patint id 500 info wrongly entered for the info of the patiend id 300 .
i want to change the info of patid 500 to that of patid 300
as patid 500  has info of 100 tabs
--
info wrongly entered for patid1 to be changed for patid2
in the same table of the user sisi which has the info in 100 tables.
and we said...
What you have to do, unless you created the constraints DEFERRABLE, is to
"clone" patient 500 to patient 300 -- do the update to the child -- and then
remove the 500 record.

That is, instead of UPDATING the parent -- you COPY the parent with the updated
value, then update the child.  You need to start at the "lowest" child that is a
parent for this to work and work your way back up the tree.

For example:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table p ( x int primary key , y date
);

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table c1 ( x primary key references p,
y date ) ;

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table c2 ( x references c1, y date ) ;

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into p values ( 100 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into p values ( 500 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into c1 values ( 100 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into c1 values ( 500 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into c2 values ( 100 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into c2 values ( 100 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into c2 values ( 100 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into c2 values ( 500 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into c2 values ( 500 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into c2 values ( 500 , sysdate );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> rem don't UPDATE p, clone it
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into p select 300, y from p where x =
500;

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> rem don't UPDATE c1, clone it
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into c1 select 300, y from c1 where x
= 500;

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> update c2 set x = 300 where x = 500;

3 rows updated.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> rem NOW we can nuke the c1/p records, don't
need them
ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from c1 where x = 500;

1 row deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from p where x = 500;

1 row deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from p;

         X Y
---------- ---------
       100 14-OCT-01
       300 14-OCT-01

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from c1;

         X Y
---------- ---------
       100 14-OCT-01
       300 14-OCT-01

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from c2;

         X Y
---------- ---------
       100 14-OCT-01
       100 14-OCT-01
       100 14-OCT-01
       300 14-OCT-01
       300 14-OCT-01
       300 14-OCT-01

6 rows selected.

Now, you might be interested in the code at:
http://osi.oracle.com/~tkyte/update_cascade/index.html
it can help you IF you can live within its constraints (which are all documented
there)
October 14, 2001 Doug -- Thanks for the question regarding "Crash course in Number, Integer, smallint ? Confusion ...", version 8.1.7
You Asked
Tom - I read somewhere that the oracle types integer and smallint were basically
allowed to allow ANSI compatability, but were really NUMBER under the covers.
Is this true?

Let's say I want to disallow the insert of any floating point number.
If I choose a NUMBER(10).. I can insert a floating point number although it is
converted to an integer under the covers. Now if I create tables using the
integer and smallint options and then describe them, I get NUMBER(38) with the
same basic results.

If I -
SQL> create table test (a integer);

Table created.

SQL> desc TEST;
Name                             Null?            Type
A                                                  NUMBER(38)

SQL>
Same thing - I can insert a floating point value like
insert into test values (124.34);

and get back 124 with no errors.

If I create a table with smallint - exactly the same thing.

Questions are:
1) Am I doing something wrong?
2) Is there really such a thing as integer and smallint other than to allow me
to use them
3) If I want a violation on the insert of a value with a floating point value,
i.e., anything on the right of the decimal other than zero, what type should I
use?
4) Here are a couple of links with info on smallint and integer one of which
discusses the unsigned option.. what's the point if they are really number(38)?
http://technet.oracle.com/doc/server.815/a67781/c10datyp.htm#649
http://technet.oracle.com/docs/products/oracle8i/htdocs/readme_rdbms.htm
Thanks --

      and we said...
It is true.  All number things are NUMBERS in Oracle.

The scale and precision should be considered EDITS, with the number 10, we have
no decimal places, hence, we'll round anything with decimal places upon input.

Integer and smallint are just numbers with no decimal places.

questions)

1) no
2) they are number(38)
3) just use a number (not number(x), just number) and have a check constraint
that verifies trunc(x) = x.

scott@ORA9I.WORLD> create table t
  2  ( x int,
  3     y number check ( trunc(y) = y )
  4  )
  5  /

Table created.

scott@ORA9I.WORLD> insert into t values ( 1.6, 2 );

1 row created.

scott@ORA9I.WORLD> select * from t;

         X          Y
---------- ----------
         2          2

scott@ORA9I.WORLD> insert into t values ( 2, 1.6 );
insert into t values ( 2, 1.6 )
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.SYS_C001632) violated

This would be true in ALL databases as far as I know.  It is not illegal in
general to assign a floating point number to an integer.  The underlying systems
convert the numbers.  In C for exmaple I can assign floats to ints and ints to
floats.  They just truncate (we round).

4) the first link doesn't mean anything in the context of signed/unsigned -- it
just explains the datatypes and mentions that int, integer, smallint are really
just number(38)'s.

The second link is referring to the external datatypes usable by SQLLDR.  If I
created a file in C using

unsigned int  x;

I would want to use the unsigned int in sqlldr -- telling sqlldr to interpret
the input data as an unsigned binary integer using the native integer
representation on that host platform (say a 32 or 64bit data area).

Review &
      Followup

      Rating: 5
Clears it right
      up again!!  October 14, 2001
Reviewer:  Doug
      Cowles  from Southbury, CT USA
This question has been bugging me for a while but has been on my low priority
list.  Very complete and thorough explanation.  One follow up question - Why
does Oracle allow you to use integer and smallint in the first place? Is it just
to allow conversion from other platforms?  If they really are numbers under the
covers, why have an integer and smallint?

          Followup:

one word (well, one acronym)

ANSI

it's in the standard.

      Rating:
      4
Reader  October 14, 2001
Reviewer:
      Reader  from USA
Tom,
Could you tell us a little bit about internal representation
of
select dump(1.6) from dual;
len=3;193,2,61
and
select dump(2) from dual;
len=2;193,3

Thanks

          Followup:

See

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c10datyp.htm#784
for the blurb on the internal format of numbers.  They are basically stored in
varying length byte strings the length of which varies based on the number of
digits (hence 1.6 takes more room than 2 does, more digits to save)

October 14, 2001 Doug -- Thanks for the question regarding "A way
      to refer to all columns of a table in a trigger? Like A.*, sysdate from
      table A?", version 8.1.7

      You Asked
I may have to place some triggers on some tables with many columns, but each
with a couple of extra fields.

I have a trigger that does the job like so:

create or replace trigger arct_extr_job
before insert on extr_job
for each row
declare
batchno NUMBER(3);
begin
select batch into batchno from intf_control;
insert into arc_Extr_job values (:new:kjobid,
:new.jobdate,:new,inhomedate1,:new:this,:new.that, batchno)..
END;

Essentially, this trigger archives a complete row including the batchno into an
archive table..

Problem is, I may have to do this for like 70-100 tables.
I'm wondering if there is a way to simply refer to all rows inside
a trigger.. like you can with an insert statement using an alias like

select A.*,'I',sysdate from atable A where . . . .
this way I can get all columns + a couple more without knowing what the columns
are..

Is there way to do a similar thing inside a trigger like..

insert into archivetable (:new.*, x, y, z)..

? Or am I stuck listing out all columns, even if there are 100.

Thanks,
Doug

      and we said...
see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:59412348055
and use that concept (use SQL to write your SQL -- to write your triggers).
Looks like they would be easier to generate in all cases -- as opposed to hand
coding each one.
Review & Followup

      Rating: 5
That'll
      work  October 14, 2001
Reviewer:  Doug
      Cowles  from CT, USA
Yes. I was hoping there was a way to refer to all columns but it's pretty
trivial to just code it all with SQL. Sometimes it's nice just to confirm what
you're observing.

Thanks Tom.

October 14, 2001 Shviaswamy -- Thanks for the question regarding
      "Redo Log Size", version 8.1.7. on NT

      You Asked
Oracle 8.1.7 on NT with 8 CPUs. Predominantly batch jobs. Databse size about 425
Gig. Running on No archive log.

Online redo log file size is 250 Meg. I have single member in the 5 groups.
Average - if I consider 24 Hr span - log switch time is about 1.5 min. No
significant log switch or any other log related wait events reported. Is it
necessary to increase the size of the online redo log files still - from the
point of view of performance?

TIA, TOM.

      and we said...
Running Noarchive means of course that some day you will have a 100% chance of
losing tons of data permanently.  Just so you are aware of that.  You will lose
data, you will lose data.  Its not that you might lose data, it is that you WILL
lose data.  100% chance.

ok, that aside...

A single member -- I now increase your odds of losing data to 1000%.  Maybe
more.  BAAAADDDD.  It is not a matter of IF, but rather WHEN you will lose data.

If your logs are switching every 1.5 minutes and you are not seeing any negative
wait events and you never see the message "checkpoint not complete cannot
allocate new log" in the alert log -- thats OK (the rest of it is bad IMHO, but
you don't need to fix the time between log switches)

Review &
      Followup

      Rating:
      5
  October 14, 2001
Reviewer:
      A reader
Tom,

Sorry that, I did not mention, it is a TEST bench. When we get on to Production,
I hope, it gets onto Archivelog. We used to get these messages and I increased
the size gradually from 5M. Thanks for your info.

          Followup:

Well, I would recommend you run TEST in archive log mode with multiple members
straight away.

You seem concened about performance, you'll want to test reality then and see
what happens.  archive log mode should not add any additional waits to your
system GIVEN you've spread the load out properly -- and given that you'll have
multiple members in the real world -- you need to have them as well and see what
impact they will have, how many devices you'll really need to support all of
this.

October 14, 2001 Anton -- Thanks for the question regarding
      "Partitionned Tables", version 8i

      You Asked
Hi Tom.

I have an existing app that is using Oracle RDBMS 7.3.4 and we are looking to
upgrade to 8i.

I have master/detail tables that would benefit enormously from using table
partitionning.  The master table stores 96 rows per day and holds today's date
and a batch number which is based on a sequence.  The detail table contains the
same batch number (for joining back to the master table), holds about 2000 rows
per batch number,  and we store about one million rows per day (many batches) in
the detail table (about 14 million rows in total).

I would like to range partition the detail table on date (as most searches are
date based), then sub-partition on batch number.  However, we only store the
date in the master table, not the detail table.  Do I have to add the date
column to the detail table to allow date range partitioning ?  I am not keen to
do this as it will require more storage and the date will only be used for date
range partitionning (ie. the date will have no other purpose in the detail
table).  Is there any other way (ie. can I cluster the master detail table and
use date range partitionning based on the cluster) ?

Thanks in advance.

      and we said...
Sounds more like you want to range partition the detail table by BATCH_NUMBER as
that is the key you use to join!  Partitioning it by date here would not make
sense since

1) you don't join by it.
2) its not in the child table.

So, let's say you do N batches a day.  N is some number with a finite range
(there are only so many minutes in a day).  given your numbers about 500 batches
a day (2,000 rows/batch * 500 batches = 1,000,000 rows).

Lets say you wanted to be able to support upto 99,999 batches a day (not
unreasonable).  Just make the batch_number be:

 to_char(sysdate,'j') || to_char( mod( batch_seq.nextval, 100000 ), 'fm00009' )

That way, you can range partition on the batch number, for exmaple any batch
number between:

245219700000 and 245219799999

is today, Oct 14'th.

Of course, you can come up with other techniques as well (eg:

(to_char(sysdate,'j')- 2452190) || to_char( mod( batch_seq.nextval, 100000 ),
'fm00009' )

which will give you a much smaller base number to work with -- today would be
700002 for example.

Or even

(to_char(sysdate,'j')- 2452190) || '.' || mod( batch_seq.nextval, 100000 )

which will give you numbers like:

7.1, 7.2, 7.3, 7.4.... for today.  Now the range becomes easy to define,
batch_number less than 8 -- thats 7, today.

but basically -- your partition key (and subpartition key!) will be batch_number
-- not the "date" form the master table (which is a piece of "implied" data but
is not used in any predicate against the details)...

Review &
      Followup

      Rating:
      5
Great!  October 14, 2001
Reviewer:
      Sean  from Atlanta

      Rating:
      5
Great!!  October 15, 2001
Reviewer:
      Thaha Hussain  from BAHRAIN
That was really a nice one!


Subject | Article | Last Updated (East coast time)
2 questions | article only | Oct 15, 2001 04:19 pm
escape ON|OFF | article only | Oct 15, 2001 08:45 pm
Excessive archive log generation during data load | article only | Oct 16, 2001 08:11 am
Copy From Command | article only | Oct 16, 2001 08:42 am
query for datatypes | article only | Oct 16, 2001 08:44 am
2 Questions | article only | Oct 16, 2001 10:55 am
recovery.. | article only | Oct 16, 2001 11:31 am
Use v$ tables in procedure | article only | Oct 16, 2001 08:41 pm
Some rollback questions... | article only | Oct 17, 2001 08:07 am
Obsolete views are active | article only | Oct 17, 2001 09:23 am
Returning data of user defined Type from a Procedure | article only | Oct 17, 2001 01:24 pm
Export/Import | article only | Oct 17, 2001 01:51 pm
Setup the Archive mode | article only | Oct 17, 2001 02:51 pm
Moving Long Raws using Java | article only | Oct 17, 2001 03:46 pm
Trigger Question | article only | Oct 17, 2001 06:54 pm
QUERY | article only | Oct 18, 2001 12:43 pm
Developer Report SRW error! | article only | Oct 18, 2001 06:22 pm
snapshots logging archive files even when set to nologging | article only | Oct 18, 2001 06:26 pm
trigger event | article only | Oct 18, 2001 06:40 pm
Indexes not being used | article only | Oct 19, 2001 07:53 am
Complicated If statement | article only | Oct 19, 2001 08:20 am
Can we use package variables in a SQL statement | article only | Oct 19, 2001 12:48 pm
select from simple sql | article only | Oct 19, 2001 12:51 pm
Finding the number of rows in each table by a single sql | article only | Oct 19, 2001 06:50 pm
jdbc substring can't update char columns | article only | Oct 19, 2001 08:09 pm
Few Questions | article only | Oct 20, 2001 08:21 am
Asking Abou your Book | article only | Oct 20, 2001 09:02 am
database | article only | Oct 20, 2001 02:11 pm
Automatic rounding of fractional number | article only | Oct 20, 2001 02:37 pm
Close "Opened Cursor" Manually and your new book | article only | Oct 21, 2001 09:10 am
maximum bandwidth of disk controller never hit... so does it matter where I put things? | article only | Oct 21, 2001 05:55 pm
resize the max extent size | article only | Oct 21, 2001 08:40 pm
row(s) 1 - 32 of 32
October 15, 2001 sami -- Thanks for the question regarding "2 questions", version 6i
You Asked
hi tom can u tell me how to send an email  from my applicationin form developer
plz can u tell me how to do y=that in details.
another thing can we send the canvas or the window as aparametre to a prpcedure
if so plz tell me how
and we said...
Well, it'll really depend on your email system in place.  there are dozens of
ways to do it.  I prefer to do it in the database myself
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:255615160805
You can also do it from forms using ole automation depending on the CLIENT
software you use and if you are using client/server forms
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:319216860351

As for passing windows and canvases -- you can always pass their NAMES as simple
strings.  You can also pass them as their native types.  There are no issues
there.
Review & Followup
Rating: 3
ole is not working with office 2000 October 15, 2001
Reviewer: A reader
i try but it is not working with office and windows 2000

Followup:
Ok, it works OK (ole from forms) -- its just that microsoft changes what you
must send to it.  I don't have a version for every version they have.  You would
need to find an OLE programmer to help you get it tweaked for Office/2k (and
then keep them on board for every dot release upgrade)

October 15, 2001 Beth -- Thanks for the question regarding "escape ON|OFF", version 8.1.6
You Asked
When you use a construct such as this:

select table_name
from all_tables
where table_name like 'XX\_%' escape '\';

must you have the SET ESCAPE option set to ON, or OFF, or the character.  I am
confused by the purpose of the SET ESCAPE option, as it seems that my statement
above only works with SET ESCAPE OFF
and we said...
SET ESCAPE is a sqplus'ism and does not affect the behavior of this command.

It does affect the behavior of SQLPLUS however.

ESC[APE] {\| c|ON|OFF}
Defines the character you enter as the escape character. OFF undefines
the escape character. ON enables the escape character. ON changes the
value of c back to the default "\".

You can use the escape character before the substitution character (set
through SET DEFINE) to indicate that SQL*Plus should treat the substi-tution
character as an ordinary character rather than as a request for
variable substitution.

It is not in anyway related to the "escape" in the sqlplus like clause.  What
you are seeing is sqlplus pre-processing your query.  It sees the "escape" from
set escape on and assumes it is an escape character and removes it!

Consider:

ops$tkyte@ORA717DEV.US.ORACLE.COM> set escape on
ops$tkyte@ORA717DEV.US.ORACLE.COM> show escape
escape "\" (hex 5c)
ops$tkyte@ORA717DEV.US.ORACLE.COM> select '\' from dual;

'
-

ops$tkyte@ORA717DEV.US.ORACLE.COM> select '\\' from dual;

'
-
\

ops$tkyte@ORA717DEV.US.ORACLE.COM> select '\\\' from dual;

'
-
\

ops$tkyte@ORA717DEV.US.ORACLE.COM> select '\\\\' from dual;

'\
--
\\

But the SQL "escape" character is totally different and can be any character:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t ( x varchar2(5) );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t values ( 'X_X' );

1 row created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select * from t where x like '%#_%' escape
'#';

X
-----
X_X
Review & Followup
Rating: 5
October 23, 2001
Reviewer: A reader
Thanks!
-Beth

October 16, 2001 Will -- Thanks for the question regarding "Excessive archive log generation during data load", version 8.1.6
You Asked
Hi Tom,

I am encountering a situation related to data loading and excessive
archive log generation. I am using Oracle 8.1.6 under Solaris 7.

I insert twice a week about 1 million rows in to a table whose columns are of
number datatype. The loading takes place vi a PL/SQL
script which handles some complicated business logic.  The average
row length of the table is about 30 bytes. Hence, approximately 30 MB worth of
data is loaded.

However, as soon as the loading script starts, there is a continuous log switch
and I observed more than 300 archive logs were created.
I am currently using 3 redo logs each 5 MB size.  That means 300x5
=1500 MB worth of archive log was generated during the 30/40 minute data load
process.

The problem is that because of this massive archive log generation the
filesystem suddenly may get full resulting
in database freeze. I have to keep a close manual watch during the process.
However, I need to make it an unattended automated dataload.

Questions:

1. What is the reason that loading of only 30 MB of data results in
more than 1500 MB archive log generation ?

2. Is there any paparemeter
or anything that will reduce the archive log generation.

3. How to
justify or quantify the amount of archive log generation based on
a certain volume of data or transactions.

Some folks have suggested I do the data load so minimal
archive logs are generated ( such as sqlloader direct path etc.).
However, I need to use the PL/SQL scripts for business reasons.
Also, sqlloader direct path will cause some problems like
invalid indexes if the sqlloader fails for some reason which
I want to avoid in our 24x7 production environment.

Thanks for your help and time.
Will
and we said...
1) you are logging the data changes and the rollback generated.  As well, the
indexes on this table will generate their own changes and their own rollback
which is also logged.

If you commit frequently, the amount of redo you generate goes UP as well (not
only that, but it runs slower overall).

2) no, but the techniques you use may affect this radically

3) do an insert with autotrace on in sqlplus and see the redo generated.

A possible solution for you is:

1) direct path load the data into a NOLOGGING table.
2) process the data from there into a GLOBAL TEMPORARY table (mininal redo
generated for inserts - very very little redo)
3) when all of the data is ready to go, alter your_table to nologging and

   insert /*+ append */ into YOUR_TABLE select * from global_temp_table;

and do it as one transaction.

That will certainly minimize the amount of redo generated to the bear minimum.
You will need to backup your database ASAP after this as the insert of the
million rows will not generate archive redo log and hence would not be
recoverable in the event of a media failure.  Using this technique, only the
changes to the indexes on your_table will generate log during this process.
Review & Followup
Rating: 4
Archive log October 15, 2001
Reviewer: Will Chakraborty from Atlanta
Your suggestions are very helpful

Rating: 3
"Excessive archive log generation during data load", version 8.1.6 October 16, 2001
Reviewer: A S Rathore from India
Since the data loading is done only twice a week and we are suggesting nologging
why not suggest drop/disable of index as well to optimize the entire operation.

Followup:
Because of the very clear statment:

"Also, sqlloader direct path will cause some problems like
invalid indexes if the sqlloader fails for some reason which
I want to avoid in our 24x7 production environment."

They need the indexes to be there all of the time by defintion.  If we dropped
them - the queries would suffer just a bit.  This approach detailed below
generates the minimum redo/archive given their constraints.

Rating: 5
Loading May 15, 2003
Reviewer: lakshmi from Bangalore India
Brilliant !!!

October 16, 2001 Yogesh -- Thanks for the question regarding "Copy From Command", version 8.1.7
You Asked
I need to copy some selected records from table A (Database 1) to table B
(Database 2), of course we can use Copy from command for doing this, but problem
is that the row contains BLOB data, which is not supported in COPY from, is
there any way to solve this problem ?
and we said...
insert into table_b
select * from table_a@remote_site where <condition>

just create a database link and do an insert into.
October 16, 2001 mohammad -- Thanks for the question regarding "query for datatypes", version 8.1.6.0
You Asked
Hi ! Tom,

Thank you very much for your service.

To-daya's scenerio is:
:dewadba> CREATE TABLE PARKS (GID VARCHAR2(32), SHAPE MSSYS.SDO_GEOMETRY);
CREATE TABLE PARKS (GID VARCHAR2(32), SHAPE MSSYS.SDO_GEOMETRY)
                                            *
ERROR at line 1:
ORA-00902: invalid datatype

1.In the context of above,I tried to find out all the datatypes supported  by my
system.But how to query was not known to me.Plz,tell me how.
2.How to include new datatype like SDO_GEOMETRY in the system?
and we said...
MSSYS is wrong, its MDSYS

scott@ORA8I.WORLD> select owner, type_name from all_types;

OWNER                          TYPE_NAME
------------------------------ ------------------------------
....
MDSYS                          SDO_POINT_TYPE
MDSYS                          SDO_ORDINATE_ARRAY
MDSYS                          SDO_ELEM_INFO_ARRAY
MDSYS                          SDO_GEOMETRY
......

that query shows you the types in your database above and beyond the standard
number, date, varchar2, ....
Review & Followup
Rating: 3
datatypes October 16, 2001
Reviewer: taha from Dubai
thanks Tom.

October 16, 2001 alan -- Thanks for the question regarding "2 Questions", version 8.1.6
You Asked
Hi Tom;

1. About SQL*LOADER - My question is, I have a table and it has indices and
foreign key constraints defined in it. If I load data on it using SQL*LOADER,
will ORACLE uses redo/undo logs and it will update the indices? If it does, then
I should disable constraints and drop the indices before loading to speed up my
loads.

2. Table Triggers - Is there a way to know which column on the table is being
updated, so that I can create a audit logs that would indicate that on this
table, this column was updated and will show the old and new values of the said
column.

thank you and more power.
and we said...
1) You need to read about conventional path and direct path loads:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76955/ch08.htm#4621
In conventional path mode, regular sql is used and redo/undo is generated for
everything.

In direct path mode, undo won't be generated for the table and depending on the
archivelog mode of the database and the logging mode of the table -- redo might
not be generated.

undo and redo for the indexes would be generated during the "merge" of the newly
loaded data and the existing index data.

You can disable constraints/indexes if the data does not need to be queried
whilst loading.

2)
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:59412348055
October 16, 2001 nitin -- Thanks for the question regarding
      "recovery..", version 8.1.7

      You Asked
Hi Tom.
      If my Database is running in NonArchive log mode and I don't have the Back
up suppose a situation arises when I lost my redo log files then can I recover
the Database?

thanx in advance.
Nitin

      and we said...
nope, you would be out of luck (unless the database was shutdown normal prior to
"losing" the log files).

Here are some facts:

o if you run in noarchive log mode, you WILL lose some data some day.  Not
"might", "WILL".  Whether that is acceptable to you is a matter of your system.
If you are a data warehouse, that might be acceptable (just reload the loaded
data since the last cold backup).  If you are an ordering system -- it would not
be.

o if you do not backup your database, you WILL lose your entire set of data some
day.  Not "MIGHT", "WILL".  Lose a log, lose system, lose some rollback -- any
of these would cause either partial or full lose of all data.

Review &
      Followup

      Rating: 4
Partial
      recovery in Archivelog mode  October 16, 2001

Reviewer:  Johan  from South Africa
Tom,

How can I perform partial recovery (up to a specific archived log file) when
running in Archivelog mode, but one or more archived log files were lost or
corrupted ?

Assume a hot backup is done at OS level with all read-write tablespaces in
backup mode and rman is not used.

          Followup:

if you lost an archived redo log file -- they best you'll be able to do is a
cancel based recovery UPTO the point right before the lost/corrupt redo log
file.

See

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/performi.htm#14614
...

October 16, 2001 William -- Thanks for the question regarding "Use
      v$ tables in procedure", version 8.1.6

      You Asked
Hi Tom,

  On page 455 of your book there is a query to obtain the server
processing id, "Select a.spid From v$process a, v$session b Where
a.addr = b.paddr And b.audsid = userenv('sessioned')". This query
runs fine independently but when I try to put it in a function
I can not get it complied. It seems that pl/sql does not regconize
v$.. kind of table. Please tell me if this is true. Thanks

Best reguards

William

      and we said...
see

http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
and then as the SYS user:

grant select on v_$process to YOUR_ACCOUNT;
grant select on v_$session to YOUR_ACCOUNT;

OR -- have someone who has those privs create that as a view and grant you
select on a view.

(v$process is a synonym to the VIEW v_$process, you grant on the view)
October 17, 2001 Andre -- Thanks for the question regarding "Some
      rollback questions...", version 8.1.6

      You Asked
Tom,

I have some questions regarding RBS's I have left unanswered for a long time. If
you can, please clarify...

1 - Oracle says that:
   . Inserts generate little rollback info, only the before image ROWID (???).
   . Update generate rollback info depending on the amount of updates (old data)
   . Deletes generate the most rollback info (old data)

What does not make sense to me is that regardless of how ONE data block is
"touched" by a DML, this operation will automatically create ONE before-image
rollback block, no matter if it's only one row via an insert or a coupe of rows
in this same block trough a delete. For example, if I insert one row, there will
be a rollback block for this data block. Likewise, if I delete one row, the same
will happen. As far as I am concerned, it's not the type of DML that will
indicate how much RBS blocks will be allocated, but the number of data blocks,
sonce RBS activity is a "reflection" of database transactions. Am I right ?

I see though V$TRANSACTION that no matter the DML operation, the number of RBS
blocks manipulated is the same number of blocks acted upon.

2 - Let us suppose two transactions are working on the data same block on
different rows. Will there be two copies of the same data block in the RBS ? How
does Oracle handles it when both commit or roll back, one after the other ?

Thanks again !

      and we said...
1) thats not accurate.  We put changed bytes plus some "accounting" (aka our
overhead) into the RBS.  Its not a block for block thing.  Consider (8k block):

ops$tkyte@ORA9I.WORLD> create table t ( x int, y char(2000), z char(200) );
Table created.

ops$tkyte@ORA9I.WORLD> insert into t values ( 1, 'a', 'b' );
ops$tkyte@ORA9I.WORLD> insert into t values ( 2, 'a', 'b' );
ops$tkyte@ORA9I.WORLD> insert into t values ( 3, 'a', 'b' );
ops$tkyte@ORA9I.WORLD> insert into t values ( 4, 'a', 'b' );
ops$tkyte@ORA9I.WORLD> insert into t values ( 5, 'a', 'b' );
ops$tkyte@ORA9I.WORLD> insert into t values ( 6, 'a', 'b' );

ops$tkyte@ORA9I.WORLD> select x, dbms_rowid.ROWID_BLOCK_NUMBER(rowid) from t;

         X DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
---------- ------------------------------------
         1                                 2058
         2                                 2058
         3                                 2058
         4                                 2059
         5                                 2059
         6                                 2059

6 rows selected.

the data is definitely on 2 blocks here, I made the rows so that 3/block fit.
Char's are always fixed length

ops$tkyte@ORA9I.WORLD> update t set y = 'b' where x = 1;
1 row updated.

ops$tkyte@ORA9I.WORLD> select used_ublk
  2    from v$transaction
  3   where addr = ( select taddr
  4                    from  v$session
  5                   where sid = ( select sid
  6                                   from v$mystat
  7                                  where rownum = 1 ) )
  8  /

 USED_UBLK
----------
         1

that updated block 2058

ops$tkyte@ORA9I.WORLD> update t set y = 'b' where x = 6;
1 row updated.

and that got 2059, but...

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> select used_ublk
  2    from v$transaction
  3   where addr = ( select taddr
  4                    from  v$session
  5                   where sid = ( select sid
  6                                   from v$mystat
  7                                  where rownum = 1 ) )
  8  /

 USED_UBLK
----------
         1

we've still only used 1 block of rollback

The number of blocks used is NOT the number of blocks acted on.  It is the
number of blocks needed to hold the changed bytes + our accounting information.

2) there will not be two copies of the block as we do not record the block.
there will be the undo information to restore the block -- different data for
each transaction (as they cannot possibly be mucking about with the same row!)

Review &
      Followup

      Rating: 5
Congratulations
      on an excellent explanation !  October 16, 2001

Reviewer:  Andre Whittick Nasser  from Brazil

I have to agree you are great, guys ! There's no such DBA resource on the
internet as your site ! A lot of things I learned were either wrong or
confusing.

In this case, my Oracle teacher emphisized that a rollback block is an exact old
COPY of the data block. Hence this mess...

Now I see I has another format... That was the confusion.

Now, it's very clear to me !

Thanks a lot again !

      Rating:
      5
"guys"  October 17, 2001
Reviewer:
      Connor  from UK
Just to give credit where credit is due - contrarary to popular opinion, AskTom
is exactly that...Ask Tom.  There is only one guy out there.

      Rating: 5
Sorry to
      disappoint you, Connor from UK...  October 17, 2001

Reviewer:  Andre Whittick Nasser  from Brazil

Quote from the AskTom Home Page:

" Information

  Welcome to Ask Tom! Ask Tom allows you to pose questions and get them answered
by experts. "

EXPERTS... (plural)

I cannot believe you are so naive to think there is only one guy out there to be
up-to-date on and answer ALL those nuts-and-bolts Oracle questions 24 hour a
day...

          Followup:

Well, let me fill you in on how this works.

In January 2000 I (singular) started doing AskTom.  In the beginning, they sent
email to me (they being Oracle Magazine).  They had a little form, and a perl
script to send the contents of that form to me.

Needless to say, that did not scale very well.  I didn't have the ability to
"shut it off", restrict the number of emails I got or anything.  Also, since it
wasn't in the database, there was no search, no way to publish tons of Q/A
efficiently on the web.

So, in May 2000 I wrote AskTom version 2.  It suited my needs, had the database,
search, control flow of questions -- everything I needed.  It worked very well.
We are still very singular here however -- just me.

Now, in my job i work on many things, asktom is one of them.  On another project
I'm affiliated with, they needed a support tool that could be used by multiple
users.  AskTom had most of the features (we have some simple workflow for
questions so I can defer them, ask for more info, get notified when they add
info and so on).  However, it was solely single user.  One guy got all of the
questions.

Hence came AskTom version 3, also known internally as "AskUs".

the interface you see here is this new software, the "AskUs" software (thanks to
Joel Kallman of Oracle for developing it and constantly adding new features as
we need them).  This is a somewhat customized version as I wanted to have the
AskTom logo and images here but basically 99% of it is the generic "AskUs"
application.

Hence (took a while to get here) the wording of some messages such as "and get
them answered by experts" or the "and we said...." you see in each Q/A.

My name is Tom (Tom Kyte).  I am the Tom behind AskTom.

I am one guy.

I honestly do answer 99.9% of all questions (i get help on Oracle Apps related
questions when I don't know the answer for example).  Out of the 12,000
questions I've recieved since Jan 2000, I have answered almost all of them
personally (and when I don't, I credit the person who helped me out, the most
frequent helpers are:

Joel "interMedia man" Kallman
Mark "Java Boy" Piermarini
Chris "webdb" Beck
Julie Wells & Derrick Lawson (the AQ connection)
Todd "I know Oracle Apps" Lesser

so, unless you see their names (or someone elses name), it was from me
There really is one guy answering these questions.  Honest.

      Rating: 5
I want to rate
      you 10, not 5...  October 17, 2001
Reviewer:
      Andre  from Brazil
Well, Tom... You really impressed me now. I can only compliment you on this
astonishing work you have been doing ! I imagine it takes a lot of brains,
study, organization, tech infra-structure, etc, etc to accomplish what you do !
I have known excellent professionals all over the world, but what you just told
is just amazing !

Congratulations again !

October 17, 2001 Raja -- Thanks for the question regarding
      "Obsolete views are active ", version 8.1.6

      You Asked
Dear Tom ,

The Oracle8i Migration  Release 2 (8.1.6)  A76957-01

Says

"
Static Data Dictionary Views Obsolete in Release 8.0

The following static data dictionary views became obsolete in
release 8.0
and are not available in release 8.0 and higher:

ALL_HISTOGRAMS  / DBA_HISTOGRAMS / USER_HISTOGRAMS   "

They are not only available and active but there are also
another set of identical
ALL_TAB_HISTOGRAMS / DBA_TAB_HISTOGRAMS / USER_TAB_HISTOGRAMS
with the same as columns as in the 'obsolote' views  .

WHICH SHOULD WE USE ?

Affly
Raja

      and we said...
$ grep -i ALL_HISTOGRAMS   cat*
catalog.sql:drop public synonym ALL_HISTOGRAMS
catalog.sql:create public synonym ALL_HISTOGRAMS for
ALL_TAB_HISTOGRAMS

ALL_HISTOGRAMS is not a view, it is a synonym pointing to
ALL_TAB_HISTOGRAMS in 8i....

Use ALL_TAB_HISTOGRAMS.  the synonym is for backwards
compatibility.

Review &
      Followup

      Rating: 3
Other
      histogram-related views  October 17, 2001

Reviewer:  Andre  from Brazil
I am a bit confused as to the histograms views. My questions:

1) I see *_TAB_HISTOGRAMS has columns: ENDPOINT_NUMBER
ENDPOINT_VALUE
ENDPOINT_ACTUAL_VALUE
What are these in fact ?

2) *_TAB_COLUMNS has some columns regarding stats collection. What are these
columns and what effect do they have on histograms, or are these columns only
for general (non-histogram) statistics ?

Thanks a lot again !

          Followup:

The columns of the views are described in the Oracle8i reference manual.

ENDPOINT_NUMBER        NUMBER         Histogram bucket number
ENDPOINT_VALUE         NUMBER         Normalized endpoint value for this bucket
ENDPOINT_ACTUAL_VALUE  VARCHAR2(1000) Actual (not normalized) string value of
the
                                      endpointfor this bucket.

User_Tab_columns has some histogram related stuff (NUM_BUCKETS for example is
the number of historgram buckets you asked for when you analyzed).  Most are
"column" level stuff -- num_nulls, low/high values, etc.

October 17, 2001 Rajesh -- Thanks for the question regarding
      "Returning data of user defined Type from a Procedure", version 8.1.6

      You Asked
I have a requirement where I have to use a REF CURSOR to return the Cursor from
a Procedure back to the calling application which is Java based. I don't want to
create a package for that procedure otherwise I can declare that cursor type in
the package specification and use it in the package body. Can I use a Standalone
procedure/Function to accomplish this thing ? OR DO I HAVE TO HAVE A PACKAGE TO
ACCESS REF CURSORS ?

      and we said...
You need at least one package:

create or replace package types
as
  type rc is ref cursor;
end;
/

and then your standalone procedures can use:

create procedure p( p_cursor in out type.rc )
is
begin
.....

#1, you need at least one package spec in order to define the ref cursor type.

#2, packages are the ONLY THING you should be using in real production code, you
should avoid standalone procedures and functions at all costs.

Review
      & Followup

      Rating: 5
PERFECT
      Response  July 02, 2001
Reviewer:  Rajesh
       from Piscataway, NJ
I found the response I was looking for. I look forward to post more questions
like this again which are not clearly specified in the books or manuals.

      Rating:
      3
  October 17, 2001
Reviewer:  Behen
       from Cananda
"2, packages are the ONLY THING you should be using in real production code, you

should avoid standalone procedures and functions at all costs."

Tom, kindly dont leave it open ended like that , explain WHY?

          Followup:

nag --

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:286816015990
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:309816708253
...

October 17, 2001 Betty -- Thanks for the question regarding
      "Export/Import", version 8.1.7

      You Asked
I need to export only the structure from an owner and then import into another
owner to create the tables, indexes, and etc.  I know how to do this, however I
am moving to a locally-managed tablespace and would like the initial extent to
be 64K.  What I need to know is how to move structure from one owner to another
with different storage clause.

Thank you Tom

      and we said...
What you would have to do is:

exp

imp .... INDEXFILE=temp.sql ....

edit temp.sql and use that to create the DDL, that file will have the create
index and create table statements.

Another option:

1) exp compress=n
2) imp into whatever type of "scratch" tablespace you want
3) see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:47812348053
for how to generate a script to MOVE all of the objects of one user from one
tablespace to another.  Using this, you could simply automate the rewrite of the
storage clause.

Now that I think about it -- option two is the easy way -- just create a dummy
tablespace, import into it, move the objects and then drop that tablespace.
October 17, 2001 lisa -- Thanks for the question regarding "Setup
      the Archive mode", version Oracle8i Standard Edition 8.1.6

      You Asked
I tried to setup my database in archive log mode. When I added the following
three lines in init ora file, shutdown the oracle and
re-start the oracle, the oracle won't start and did not give any additional
info, it just simply won't start. I have checked the
dest and format they all seem fine.
As soon as I comment back these three lines, startup the oracle, it starts.

Could you think of any reasons why it won't pickup the archive mode ?

log_archive_start = true
log_archive_dest_1 = "location=d:\Oracle\oradata\Edm4i\archive"
log_archive_format = %%ORACLE_SID%%T%TS%S.ARC

I tested the setting archive mode in my locally created 8.1.6 database, it works
fine.
my steps are:
1.shutdown the database
1. modify the init file to include the above 3 lines
2. startup the database in startup mount
3. alter database archivelog
4. alter database open
5. alter system switch logfile

      and we said...
multiple archive destinations are available only with Oracle8i EE.  You are
using the log_archive_dest_1 which is only available with EE, not SE.

See the Oracle8i Server Reference:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76961/ch180.htm#41715
for details, there it instructs you to use log_archive_dest with SE.
Review &
      Followup

      Rating: 5
Excellent
      !!  October 17, 2001
Reviewer:
      A reader
You are right in the money!

The SE init file should come with LOG_ARCHIVE_DEST instead of it pre-packaged
with :
#LOG_ARCHIVE_DEST_1

Oh well ....
I learned ....

October 17, 2001 -- Thanks for the question regarding "Moving Long
      Raws using Java", version 8.1.6

      You Asked
We are moving/copying several tables containing long raw columns from one schema
to another using java. Is there an efficient way of coding this in java for
performance? Do have any samples you can provide?

Thanks in advance.

      and we said...
well, you want efficient and easy?

exp .... tables=t
imp .... fromuser=old_schema touser=new_schema

thats efficient and easy.

Java -- that'll take some code (sigh, it always does in java)....

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:238014476571
for a getting started on that.  It does long raw to blob but its much the same
for long raw to long raw.
Review & Followup

      Rating: 2
Cant get it
      running (LONGRAW to LONGRAW with Java)  December 13, 2001

Reviewer:  Michael Dimitriadis  from Graz, Austria

Since there is no getBinaryOutputStream-Method for the LONGRAW-column I could
find no way to get an OutputStream for writing to the LONGRAW-column as in your
example for writing to a BLOB-column. I tried to get around with updateBytes but
this worked in 8.1.6.2 and did not work in 8.1.7.2 (ORA-01461 if ByteArray is
larger than 4000 Bytes).
Any advice? Please!!!

October 17, 2001 Cesar -- Thanks for the question regarding
      "Trigger Question", version 8.1.6

      You Asked
I have this table

   data_month
   -----------------------------
   month             not null number(3)
   value             not null number(10,2)

I need something like this

   ...
   v_update := 0;
   begin
     insert into data_month
       (month, value)
     values
       (v_month, v_value);
   exception
     when dup_val_on_index then
       v_update := 1;
     when others then
       null;
   end;
   if v_update > 0 then
     begin
       update data_month
         set value = value + v_value
       where month = v_month;
     exception
       when others then
         null;
     end;
   end if;
   ...

but with SQL Loader... Is it possible?

Thanks!!!

      and we said...
What I would do:

1) load the table data_month and specify errors=99999 and a bad file.

2) load the bad file into another table after you are done (these are your dups)

3) update data_month set value = ( select value from temp_table where
temp_table.month = data_month.month ) where month in ( select month from
temp_table );

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1615330671789
to see how this is reduced to a single SQL command without even using sqlldr in
9i...
Review
      & Followup

      Rating: 4
Ok,
      but...  October 16, 2001
Reviewer:  Cesar
      Salas  from Veracruz, Mexico
Exists other way to do it, maybe a trigger?

          Followup:

Yah, you could do it view a view and instead of trigger but it would be somewhat
slower...

ops$tkyte@ORA9I.WORLD> create table t ( x int primary key, y varchar2(25) );

Table created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> create or replace view v as select * from t;

View created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> create trigger v_trigger
  2  INSTEAD OF INSERT on V
  3  begin
  4          insert into t values ( :new.x, :new.y );
  5  exception
  6          when dup_val_on_index then
  7                  update t set y = :new.y where x = :new.x;
  8  end;
  9  /

Trigger created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> insert into t values ( 1, 'hello' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values ( 2, 'hello' );

1 row created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> REM here is the "load"
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> insert into v
  2  select 1, 'goodbye' from dual
  3  union all
  4  select 3, 'hello' from dual
  5  /

2 rows created.

ops$tkyte@ORA9I.WORLD> select * from t;

         X Y
---------- -------------------------
         1 goodbye
         2 hello
         3 hello

      Rating:
      4
Slow?  October 17, 2001
Reviewer:  Cesar
      Salas  from Veracruz, Mexico
very very slow?
or only a little more slow?
I will use this process only one time at month (but with a huge volume of data)

          Followup:

Huge volume of data would lead me towards my first approach but only a benchmark
would tell you the truth.

      Rating: 5
The last
      question  October 17, 2001
Reviewer:  Cesar
      Salas  from Veracruz, Mexico
Ok, if I use a 'view' and an 'instead trigger', how can I use the 'view' in SQL
Loader?

I was trying with 'INTO database.my_view' but doesn't work.

Thanks!!!

          Followup:

darn.  I did it in 817

LOAD DATA
INFILE *
INTO TABLE OPS$TKYTE.V
REPLACE
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY "'"
trailing NULLCOLS
(x,y)
begindata
1,4
3,5

I just did that and it works for me.  I tried in 816 and sure enough, ORA-04043
object does not exist.

Sorry, I would go with the first method I suggested I guess.

      Rating:
      5
End  October 17, 2001
Reviewer:  Cesar
      Salas  from Veracruz, Mexico
Yes, now my problem is the version.

Anyway thank you very much, you are brilliant!!!

October 18, 2001 GREEN -- Thanks for the question regarding
      "QUERY", version 8.1.6

      You Asked
HI tom,
I run a query on a table which was set up by the other people
SELECT count(*)
     FROM h_summary
        WHERE ROWNUM <=1
          AND (d_code, d_number)
        IN (SELECT d_code, d_number
            FROM f_WORK)
 the result is as follows

 COUNT(*)
---------
        1
BUT  I RUN THE FOLLOWING COMMANDS
SQL > DESC  F_WORK
D_TITLE_CODE                            NOT NULL VARCHAR2(4)
D_NUMBER                                NOT NULL NUMBER(3)

SQL >SELECT d_code, d_number  FROM f_WORK
SELECT d_code, d_number
       *
ERROR at line 1:
ORA-00904: invalid column name

It is very clear that the f_work table has different fileds.
so my question is why the first query can run successfully ?
what is the potential possibility ?
Thanks in advance
green

      and we said...
That query looks bad.

If h_summary has at least 1 row and f_work has at least 1 row, the answer will
ALWAYS be one.

It is running a correlated subquery.  d_code and d_number are columns from
h_summary -- not f_work.

This might make it more clear:

SELECT count(*)
     FROM h_summary
        WHERE ROWNUM <=1
          AND (d_code, d_number)
        IN (SELECT H_SUMMARY.d_code, H_SUMMARY.d_number
            FROM f_WORK)

See, its running the subquery with the values from the OUTER query.  And of
course (d_code,d_number) in ( select H_SUMMARY.d_code, H_SUMMARY.d_number from
f_work) is ALWAYS true as long as f_work has at least 1 row.

I think the original query is probably wrong.  If it is not wrong, it would be
more efficient as simply:

select count(*)
  from dual
  where exists ( select null from h_summary )
    and exists ( select null from f_work );

Review &
      Followup

      Rating:
      5
supper!!  November 24, 2001
Reviewer:
      Sean  from Atlanta

October 18, 2001 Cerina -- Thanks for the question regarding
      "Developer Report SRW error!", version 2.5.5.0.12

      You Asked
Hope all is well with you.
 I have to use SRW.Do_SQL to dynamically create a table through
Reports. I've issued a very simple statement in the before
parameter form trigger (just as the help stuff says) . The
statement is SRW.DO_SQL('create table x (yyy number)'); I've
tried this even with no other objects except a dummy boilerplate
text in the layout.
The stupid thing gives me the foll error
         REP-1425: 'beforepform'; Error running DO_SQL package-
'Error describing bind variables ORA-01003: no statement
parsed'.
I don't have ANY bind variables.........rep ver 2.5.5.0.12
    This stuff has 2 work have just a day to make it work!
PLEASE HELP.
Regards,
Cerina

      and we said...
this is a issue in reports 2.5 with do_sql.  After it parses --
it is trying to describe the statement but you don't describe
DDL.  If you look you should find that the table is in fact
created.  So, one workaround is to use an exception block to
catch and ignore this specific error.  Another is to use the
DBMS_SQL package -- if you create a stored procedure in your
database such as:

create or replace procedure execute_immediate( p_sql in varchar2
)
is
    cursor_name     pls_integer default dbms_sql.open_cursor;
    ignore          pls_integer;
BEGIN
    dbms_sql.parse(cursor_name, p_sql, dbms_sql.native);
    ignore := dbms_sql.execute(cursor_name);
    dbms_sql.close_cursor(cursor_name);
END;
/

you can then call

execute_immediate( 'create table x ( yyy number )' );

You should be aware that the stored procedure will execute with
the PRIVS OF THE OWNER of the procedure, not the caller (unless
you have Oracle8i and use "invokers rights").  therefore, the
owner of that procedure will need to have CREATE TABLE granted
directly to them -- NOT via a role.  See

http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for more info on what I mean by that.

Review &
      Followup

      Rating:
      4
ora01003  October 18, 2001
Reviewer:
      A reader
Tom

I am doing a simple update from my delphi program, and Iam getting the following
error- ora01003- no statement parsed.

The explanation for that says ..

A host language program call referenced a cursor with no associated parsed SQL
statement. A SQL call (for example, OSQL3) must be used to pass a SQL statement
to Oracle and to associate the statement with an open cursor. A cursor must
already have an associated SQL statement if referenced in any of the following
calls: DESCRIBE, NAME, DEFINE, BIND, EXECUTE, and FETCH.

Action: Do the SQL call, for example, OSQL, to pass the required SQL statement
before referencing the cursor.

Why Iam I getting the error and how should I overcome to.

          Followup:

No idea, in this case, it is most likely a bug in the delphi application
environment -- something they are doing.  I would suggest contacting the makers
of delphi and see if they have any open issues on this.

      Rating: 4
Addition to the
      above question  October 18, 2001
Reviewer:
      A reader
I dont encounter this error often,  and when I encounter, I recompile my
excutable, and then I will not get this error for quite some time.

October 18, 2001 Tamara -- Thanks for the question regarding
      "snapshots logging archive files even when set to nologging", version
8.1.6

      You Asked
We have a snapshot that downloads 36 meg of data daily. When we created this
snapshot, it did not update the archive files at all, because we stated no
logging on the create of the materialized view/snapshot. However, during the
daily refresh of the data the archives are being written to. Since this data can
be recreated by selecting it from the remote site, we don't want anything to be
logged during the refresh of the data. This will speed up the refresh and use
less disk.

Our question is: how do we get the materialized view/snapshot to stop logging
all the inserts when it refreshes the data daily?

CREATE MATERIALIZED VIEW testVIEW1
  PCTFREE 0 PCTUSED 99
  NOLOGGING
  STORAGE (INITIAL 2M NEXT 2M PCTINCREASE 0)
   TABLESPACE PMBP01 PARALLEL
   REFRESH COMPLETE NEXT TRUNC(sysdate,'dd') + 1 + 5/24
   USING ROLLBACK SEGMENT BIG_R02
   AS
SELECT
    field1,
    field2
FROM testview1@remote.world C
/

      and we said...
The only way to get "nologging" would be to do total refreshes.

You might not care about recoverability however, we need to be protected in the
event of a system crash in the middle of a refresh.  If we lost power during a
refresh, upon recovery we would be incapable of restoring the snapshot to a
consistent point in time.

Nologging happens only for very very specific operations (initial creates, mass
APPENDS, truncates, rebuilds).  It never happens for transactions.
Review &
      Followup

      Rating: 4
nologging
      during refresh  October 12, 2001
Reviewer:  June
      Chen  from USA
It is very helpful as we ran into same situation.

However, it is still somehow unclear about 'total refreshs' mentioned in the
reply. Is it same as 'complete refresh', stated in the example code? or does it
mean that 'drop snapshot...create snapshot' procedure?

thanks.

          Followup:

I mean schedule a procedure that does something like:

begin
   execute immediate 'truncate table t';

   execute immediate 'drop index t_idx1';
   ... (all other indexes) ...

   insert /*+ append */ into t
   SELECT field1,field2
     FROM testview1@remote.world C;

   commit;

   execute immediate 'create index t_idx1 on t(field1) nologging';
   ....
end;

and schedule that as a job instead of using a snapshot (materialized view) using
dbms_job directly.

      Rating: 4
what if
      snapshot gets created in NOLOGGING tbspace  October 17, 2001

Reviewer:  June Chen  from USA
thanks for the quick followup comment. It is considerable workaround to get rid
of redos during snapshot refreshs.

However, what if we create snapshots in NOLOGGING tablespace, and in addition,
specify 'complete refresh' with 'NOLOGGING' for each simple snapshot? snapshot
will be truncated anyhow during complete refresh.

I am asking this question just because we ran into once with filling up rollback
segments and it will involve massive code change for the suggested workaround.

thanks in advance for any comment.

          Followup:

the snapshot refresh after the truncate is logged.  It is a simple transaction
and everything transactional is logged like that.

      Rating: 3
testing result
      is opsite to ...  October 18, 2001
Reviewer:
      June Chen  from US
I did a test, where I did 4 complete refresh snapshots individually, VS.
complete refresh for a group for these 4 snapshots, with sql_trace on, and
NOLOGGING on individual snapshot. It turned out that:

group refresh did exactly what you described before, which is 'delete
...insert..' operations;

however, after individual complete refresh did 'truncate', following operations
is 'insert /*+ append */' which should generate minimum log only.

what I see is what I get, isn't it?

thanks!

          Followup:

that'll generate the redo for the indexes however.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t as select * from all_objects
where 1=0;

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> set autotrace traceonly statistics;
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> insert /*+ append */ into t select * from
all_objects;

16952 rows created.

Statistics
----------------------------------------------------------
         71  recursive calls
         51  db block gets
      77973  consistent gets
          0  physical reads
       4520  redo size
        995  bytes sent via SQL*Net to client
        834  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          3  sorts (memory)
          0  sorts (disk)
      16952  rows processed

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> create index t_idx on t(object_name);

Index created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> alter index t_idx nologging;

Index altered.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> insert /*+ append */ into t select * from
all_objects;

16953 rows created.

Statistics
----------------------------------------------------------
        306  recursive calls
       2571  db block gets
      78230  consistent gets
        289  physical reads
    3068380  redo size
        997  bytes sent via SQL*Net to client
        834  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          7  sorts (memory)
          1  sorts (disk)
      16953  rows processed

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> set autotrace off

so, it'll still generate considerable redo ( as most snapshots have indexes on
them ).

      Rating: 4
thanks for all
      the tips  October 19, 2001
Reviewer:  June
      Chen  from US
Thanks for all the tips during this chain review session. It is great to
understand scenario behind.

October 18, 2001 Sushant -- Thanks for the question regarding
      "trigger event", version 8.1.5

      You Asked
1)Is it possible to fire a trigger the moment the time is 12.am.

2)in a ddl trigger which is something is lik this create or replace trigger tr
after create on database......

   what iam doing is is just adding a row ina table saying a create statement is
fired.
what i want is it should show what type of an object was created say a table or
view or sequence .how do i trap what object was created.

3)
  i have a normal (emp table) as provided by oracle .

i want the output somewhat lik this

 empno   ename   sal   empno   ename   sal  empno   ename   sal
101      aaaa   2222   102      rrr   3333  103      rttt   2666
104      gggg   5555   104      fff   7777  105      yytt   7777

4)
In a table say i have 50 rows how do i get the rows between the 15th and 45th
row or say from 15throw to 50th row

      and we said...
1) close to 12am, it will not be assured to be exactly 12am.

See dbms_job in the supplied packages guide.

2) see chapter 14 of your application developer guide for 815, it lists all of
the System Defined Event Attributes such as:

dictionary_obj_type VARCHAR(20)

 Type of the dictionary object on which the DDL operation occurred.

INSERT INTO event_table ('This object is a ' || sys.dictionary_obj_type);

dictionary_obj_name   VARCHAR(30)

 Name of the dictionary object on which the DDL operation occurred.

INSERT INTO event_table ('Changed object is ' || sys.dictionary_obj_name');

dictionary_obj_owner  VARCHAR(30)

Owner of the dictionary object on which the DDL operation occurred.

INSERT INTO event_table ('object owner is' || sys.dictionary_obj.owner');

3) not really possible in sql, you need a report writing tool to massage the
data after you fetch it.

4)

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:127412348064
...
Review
      & Followup

      Rating: 3
reply to
      question 3  October 18, 2001
Reviewer:  mike
       from Indianapolis, IN
Tom, I have not tested this statement, but I think it would produce the desired
results.

SELECT a.empno
      ,a.ename
      ,a.sal
      ,b.empno
      ,b.ename
      ,b.sal
      ,c.empno
      ,c.ename
      ,c.sal
FROM  (SELECT rownum rn, empno, ename, sal
       FROM   emp
       ORDER  by empno) a
     ,(SELECT rownum rn, empno, ename, sal
       FROM   emp
       ORDER  by empno) b
     ,(SELECT rownum rn, empno, ename, sal
       FROM   emp
       ORDER  by empno) c
WHERE  MOD(a.rn,3) = 1
  AND  MOD(b.rn,3) = 2
  AND  MOD(c.rn,3) = 0
  AND  a.rn = b.rn + 1
  AND  a.rn = c.rn + 2
ORDER  by a.empno;

          Followup:

well, you would need some outer joins AND the inline views need work.  Here is
your concept:

scott@ORA717DEV.US.ORACLE.COM> SELECT a.empno
  2        ,a.ename
  3        ,a.sal
  4        ,b.empno
  5        ,b.ename
  6        ,b.sal
  7        ,c.empno
  8        ,c.ename
  9        ,c.sal
 10  FROM  (select rownum rn, a.*
 11           from (SELECT empno, ename, sal
 12                   FROM   emp
 13                  ORDER  by empno) a
 14        ) a,
 15        (select rownum rn, b.*
 16           from (SELECT empno, ename, sal
 17                   FROM   emp
 18                  ORDER  by empno) b
 19        ) b,
 20        (select rownum rn, c.*
 21           from (SELECT empno, ename, sal
 22                   FROM   emp
 23                  ORDER  by empno) c
 24        ) c
 25  WHERE  b.rn(+) = a.rn + 1
 26    AND  c.rn(+) = a.rn + 2
 27    and  mod(a.rn,3) = 1
 28  ORDER  by a.empno;

     EMPNO ENAME      SAL      EMPNO ENAME      SAL      EMPNO ENAME      SAL
---------- -------- ----- ---------- -------- ----- ---------- -------- -----
      7369 A          800       7499 ALLEN     1600       7521 WARD      1250
      7566 JONES     2975       7654 MARTIN    1250       7698 BLAKE     2850
      7782 CLARK     2450       7788 SCOTT     3000       7839 KING      5000
      7844 TURNER    1500       7876 ADAMS     1100       7900 JAMES      950
      7902 FORD      3000       7934 MILLER    1300

But, while this is technically FEASIBLE, I deemed it as impractical (sometimes,
I just have to say "no, you don't really want to do that").

there are other ways to do it as well using decode, group bys and in 8i r2 (816)
and up -- using analytic functions....

October 19, 2001 Tripti -- Thanks for the question regarding
      "Indexes not being used", version 8.1.6

      You Asked
Hi Tom,

I want to find out the indexes not being used for quiet sometime.

We would also like to find out the list of all redundant indexes. i,e, I find
that we have one index on column C1,C2 and another index on the same table as
C1,C2,C3.

In my view first index is redundant. Pls correct if I am wrong.

Thanks

      and we said...
In Oracle9i (and not before) there is a "monitoring" command for an index
that'll tell you when it was last used to answer a query.

Prior to that, it is very difficult to correctly ascertain this.  If you have my
book, I outline a method to do this using query plan stability (a side effect of
capturing the query plans).

As for finding redudant indexes -- bear in mind, they might not be redudant.
c1,c2 might be enforcing a unique constraint whereas c1,c2,c3 is there for
performance.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t ( a int, b int, c int );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> create index t1_idx on t(a);

Index created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create index t2_idx on t(a,b);

Index created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create index t3_idx on t(a,b,c);

Index created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> column table_name format a5
ops$tkyte@ORA717DEV.US.ORACLE.COM> column index_name format a8
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select a.table_name, a.index_name,
b.index_name, a.columns, b.columns
  2  from
  3  ( select substr(table_name,1,30) table_name, substr(index_name,1,30)
index_name,
  4    max(decode(column_position, 1,     substr(column_name,1,30),NULL)) ||
  5    max(decode(column_position, 2,', '||substr(column_name,1,30),NULL)) ||
  6    max(decode(column_position, 3,', '||substr(column_name,1,30),NULL)) ||
  7    max(decode(column_position, 4,', '||substr(column_name,1,30),NULL)) ||
  8    max(decode(column_position, 5,', '||substr(column_name,1,30),NULL)) ||
  9    max(decode(column_position, 6,', '||substr(column_name,1,30),NULL)) ||
 10    max(decode(column_position, 7,', '||substr(column_name,1,30),NULL)) ||
 11    max(decode(column_position, 8,', '||substr(column_name,1,30),NULL)) ||
 12    max(decode(column_position, 9,', '||substr(column_name,1,30),NULL)) ||
 13    max(decode(column_position,10,', '||substr(column_name,1,30),NULL)) ||
 14    max(decode(column_position,11,', '||substr(column_name,1,30),NULL)) ||
 15    max(decode(column_position,12,', '||substr(column_name,1,30),NULL)) ||
 16    max(decode(column_position,13,', '||substr(column_name,1,30),NULL)) ||
 17    max(decode(column_position,14,', '||substr(column_name,1,30),NULL)) ||
 18    max(decode(column_position,15,', '||substr(column_name,1,30),NULL)) ||
 19    max(decode(column_position,16,', '||substr(column_name,1,30),NULL))
columns
 20      from user_ind_columns
 21     group by substr(table_name,1,30), substr(index_name,1,30) ) a,
 22  ( select substr(table_name,1,30) table_name, substr(index_name,1,30)
index_name,
 23    max(decode(column_position, 1,     substr(column_name,1,30),NULL)) ||
 24    max(decode(column_position, 2,', '||substr(column_name,1,30),NULL)) ||
 25    max(decode(column_position, 3,', '||substr(column_name,1,30),NULL)) ||
 26    max(decode(column_position, 4,', '||substr(column_name,1,30),NULL)) ||
 27    max(decode(column_position, 5,', '||substr(column_name,1,30),NULL)) ||
 28    max(decode(column_position, 6,', '||substr(column_name,1,30),NULL)) ||
 29    max(decode(column_position, 7,', '||substr(column_name,1,30),NULL)) ||
 30    max(decode(column_position, 8,', '||substr(column_name,1,30),NULL)) ||
 31    max(decode(column_position, 9,', '||substr(column_name,1,30),NULL)) ||
 32    max(decode(column_position,10,', '||substr(column_name,1,30),NULL)) ||
 33    max(decode(column_position,11,', '||substr(column_name,1,30),NULL)) ||
 34    max(decode(column_position,12,', '||substr(column_name,1,30),NULL)) ||
 35    max(decode(column_position,13,', '||substr(column_name,1,30),NULL)) ||
 36    max(decode(column_position,14,', '||substr(column_name,1,30),NULL)) ||
 37    max(decode(column_position,15,', '||substr(column_name,1,30),NULL)) ||
 38    max(decode(column_position,16,', '||substr(column_name,1,30),NULL))
columns
 39      from user_ind_columns
 40     group by substr(table_name,1,30), substr(index_name,1,30) ) b
 41  where a.table_name = b.table_name
 42    and b.columns like a.columns || '%'
 43    and b.columns <> a.columns
 44  /

TABLE INDEX_NA INDEX_NA COLUMNS              COLUMNS
----- -------- -------- -------------------- --------------------
T     T1_IDX   T2_IDX   A                    A, B
T     T1_IDX   T3_IDX   A                    A, B, C
T     T2_IDX   T3_IDX   A, B                 A, B, C

Review &
      Followup

      Rating:
      3
  October 18, 2001
Reviewer:
      A reader
Hi Tom,

It would be great if you can send me the name of your book with all details and
ISBN no.

I would definitely like to take a look. Believe me I was not aware that you have
written any book

          Followup:

just goto
http://asktom.oracle.com/
the book is right there on my home page -- big and bold with my face on it.

      Rating: 3
Type of
      index  October 19, 2001
Reviewer:
      A reader
To remove the option of doubt whether indexes where created for uniqueness can
we not use INDEX_TYPE.

How can the query be written then?

          Followup:

No you cannot -- unique / non-unique is not a pre-req for an index used for
unique constraints.  We can (and do) use non-unique indices as well.

In any case -- rewriting the query above to skip UNIQUE indexes, if that is what
you want, is a pretty easy exercise (left to the reader)

October 19, 2001 Kim -- Thanks for the question regarding
      "Complicated If statement", version 8.1.6

      You Asked
Hi Tom, I have a complicated (for me) query situation. I would like to update a
column based on the availability of other values in the other columns.

TABLE A HAS:
col1 col2 col3 c0l4  col5 col6  Grade
10   9    8    7     6    5
     9    8    7     6    5
          8    7     6    5
               7     6    5

If col1 is available and it is between 8 and 10 then place 'High' in
column Grade, if it is between 5 and 7 then place 'Average', if it is between 1
and 4, then place 'Low'... however, if col1 is null then use the value in col2,
... if col1 and col2 are null, the use col3... and so on...

I am stuck on what to use, decode? case? do a pl/sql with if statements? I'm
sure you have seen this and have an easy solution. Thanks in advance

      and we said...
In 8i, nvl(nvl(nvl( is what we use:

ops$tkyte@ORA9I.WORLD> select
  2  nvl(col1,nvl(col2,nvl(col3,nvl(col4,nvl(col5, col6))))),
  3  case
  4    when nvl(col1,nvl(col2,nvl(col3,nvl(col4,nvl(col5, col6))))) between 8
and 10
  5        then 'High'
  6    when nvl(col1,nvl(col2,nvl(col3,nvl(col4,nvl(col5, col6))))) between 5
and 7
  7        then 'Average'
  8    when nvl(col1,nvl(col2,nvl(col3,nvl(col4,nvl(col5, col6))))) between 1
and 4
  9        then 'Low'
 10    else 'Not Known'
 11  end
 12  from t;

NVL(COL1,NVL(COL2,NVL(COL3,NVL(COL4,NVL(COL5,COL6))))) CASEWHEN
------------------------------------------------------ ---------
                                                    10 High
                                                     9 High
                                                     8 High
                                                     7 Average

In 9i, we can use coalesce instead -- and to demonstrate the new SEARCHED case
as well I'll use that:

ops$tkyte@ORA9I.WORLD> select
  2  coalesce(col1,col2,col3,col4,col5,col6),
  3  case coalesce(col1,col2,col3,col4,col5,col6)
  4    when 10 then 'High'
  5    when     9 then 'High'
  6    when     8 then 'High'
  7    when     7 then 'Average'
  8    when     6 then 'Average'
  9    when     5 then 'Average'
 10    when     4 then 'Low'
 11    when     3 then 'Low'
 12    when     2 then 'Low'
 13    when     1 then 'Low'
 14    else 'Not Known'
 15  end
 16  from t;

COALESCE(COL1,COL2,COL3,COL4,COL5,COL6) CASECOALE
--------------------------------------- ---------
                                     10 High
                                      9 High
                                      8 High
                                      7 Average
Review &
      Followup

      Rating:
      5
Super!  October 19, 2001
Reviewer:
      Kim  from NJ,USA
Right on the mark.

October 19, 2001 Arvind -- Thanks for the question regarding "Can
      we use package variables in a SQL statement", version 8.1.7

      You Asked
Hi Tom,
Is there any way to use Package Variables in a SQL statement? Currently I am
using it through package functions which returns the value of these variables.
Becausen directly id we use any package variable , it gives error.If you have
any other idea then please let me know. Any help would be appreciated.
Example:

Here CCSICODE is a package and AO_CVCS_MASTER_CLIENT is variable in that package

SQL> select ccsicode.AO_CVCS_MASTER_CLIENT
  2  from dual;
select ccsicode.AO_CVCS_MASTER_CLIENT
                *
ERROR at line 1:
ORA-00904: invalid column name

Here CCSIFNCT is package and AO_CVCS_MASTER_CLIENT  is a function whicg returns
CCSICODE.AO_CVCS_MASTER_CLIENT
SQL> select ccsifnct.AO_CVCS_MASTER_CLIENT from dual;

AO_CVCS_MASTER_CLIENT
---------------------
                    3

Thanks in advance.
Arvind

      and we said...
In "regular sql" -- sql outside of sql in plsql -- you cannot reference a
package variable you can only invoke a function.

To get the advantage AND performance of bind variables and to avoid the high
cost of calling the function from sql, simply use an application context.  See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
for an example.
October 19, 2001
      bipin -- Thanks for the question regarding
      "select from simple sql", version 8i

      You Asked
sir ,
i want to print 100 records from simple database table dual

i want to generate 100 days query from simple

select date from dual

what is the sol'n if my date is increasing from previous to next by one month

i want to get

01-jan-2001
01-feb-2001
01-mar-2001
..........

100 times

same if 1000 or more to replicate the date

      and we said...
Well, you would need to have 100 rows.  Dual has one.  So, you cannot use dual.

I use all_objects myself.  It generally have thousands of rows.

select sysdate+rownum from all_objects where rownum <= 100;

In 9i, we can use pipelined functions to create this virtual table concept:

create or replace type virtual_table_type as table of number
/

create or replace function virtual_table( p_num_rows in number )
return virtual_table_type
PIPELINED    -- NOTE the pipelined keyword
is
begin
    for i in 1 .. p_num_rows
    loop
        pipe row( i );
    end loop;

    return; -- note return with no value!
end;
/

and then:

select * from TABLE( virtual_table(5) );

returns 5 rows and:

select * from TABLE( virtual_table(10) );

returns 10 and so on, as many as you like.
October 19, 2001 rajesh -- Thanks for the question regarding
      "Finding the number of rows in each table by a single sql ", version 8i

      You Asked
hi tom

i have a databse with 125 tables. i can find the total  number  of tables of the
database by the sql
select * from tab; now i would like to know the number of rows in each table of
my database  with out
executing select count(*) from...; each time.

please help me

sincerely
rajesh

      and we said...
Well, if you are doing things correctly, you are using the cost based optimizer
and statistics are generally up to date.

The most efficient way to get a very good "ball park" number would be:

select table_name, num_rows from user_tables;

The most inefficient way is to actually count the rows in real time. This can be
done with a function:

create or replace
function get_rows( p_tname in varchar2 ) return number
as
    l_columnValue    number default NULL;
begin
    execute immediate
       'select count(*)
          from ' || p_tname INTO l_columnValue;

    return l_columnValue;
end;
/

select user, table_name,
       get_rows( user||'.'||table_name) cnt
  from user_tables
/

but be prepared to wwwwwwaaaaaiiiiiittttttt......

Review &
      Followup

      Rating:
      4
  October 19, 2001
Reviewer:
      A reader
hi tom

i have midified get_rows

FUNCTION GET_ROWS ( p_tname in varchar2,p_own in varchar2 ) return number
as
    l_columnValue    number default NULL;
begin
    execute immediate
       'select count(*)
          from ' ||p_own||'.'||p_tname
          INTO l_columnValue;

    return l_columnValue;
end;

i only want to get row count if count(*) > 0

and i am getting error

  1  select * from (SELECT  user, table_name,
  2           get_rows( table_name,'SIEBEL') cnt
  3        from all_tables WHERE OWNER = 'SIEBEL')
  4* WHERE   cnt > 0
SQL> /
         get_rows( table_name,'SIEBEL') cnt
         *
ERROR at line 2:
ORA-00942: table or view does not exist
ORA-06512: at "SBLINT.GET_ROWS", line 5
ORA-06512: at line 1

thanks

          Followup:

Well, its obvious -- Its trying to query some SIEBEL CRM tables and my code
refuses to touch their stuff (thats a joke ;)

Anyway, see

http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
you must have access via a role.  Try adding:

function get_rows .... return number
AUTHID CURRENT_USER
as
   ....

to let it run with invokers rights and roles.  That should solve it.

      Rating: 3
Get
      Rows  October 19, 2001
Reviewer:  Ping Cui
       from Cincinnati, OH
Hi Tom,

  Love your column. Just one comment. In order to be
able to use

select table_name, num_rows from user_tables;

to get the row numbers. You may have to perform table
'analyze' operation against all tables. For example,

select 'analyze table ' || table_name || '  compute statistics;' from
user_tables;

Run 'analyze' statements

select table_name,num_rows from user_tables;

Ping

          Followup:

Well, I'd use dbms_stats to analyze but .... yes, that is true, you need to
analyze the tables.

I tried to infer that with my opening statement:

"Well, if you are doing things correctly, you are using the cost based optimizer

and statistics are generally up to date. ...."

      Rating:
      3
Printing  October 19, 2001
Reviewer:
      Citrus  from Ruh
Hi Tom,

  I'm one of your fans and keep collecting your replies. While printing the
questions, everything prints fine, but your Followup answers are truncated from
the right, so I need to take a pen and complete the missed info. Could you
please make it printable on A4.

Thanking you

          Followup:

I'll see what they can do with regards to that.

October 19, 2001 Danielle -- Thanks for the question regarding
      "jdbc substring can't update char columns", version 8.1.7

      You Asked
Tom,
I tried to update a column with char type using preparestatement.setString
method as following:

pstmt = conn.prepareStatement("UPDATE rawpropmap SET rawpropmapname = ? WHERE
rawpropmapname = ? ");
pstmt.setString(1, "new");
pstmt.setString(2, "test");
pstmt.executeQuery();  // or pstmt.executeUpdate();

rawpropmapname is char(50). "update" fails without errors.

The same thing happens with "delete from rawpropmap where rawpropmapname = ?"),
but it works with "insert" though.
I used the same code on varchar2 type columns, it works fine with update.
I saw you instructed to use
pstmt.setString(1, " "+'new');
pstmt.setString(2, " "+'test');

in one case. I tried it as well and got error of
orcl_jdbc.java:96: unclosed character literal
            pstmt.setString(1, " "+'new');
                                   ^
orcl_jdbc.java:96: ')' expected
            pstmt.setString(1, " "+'new');

I think I have to pad the string with spaces to the length of char, but that is
too troublesome. And even I try "UPDATE rawpropmap SET rawpropmapname = 'test'
WHERE RTRIM(rawpropmapname,' ') = 'new';", sqlplus hangs there. Is it because
update and rtrim on the same column? Is there any simpler way to handle it?

Thanks for your time,
Danielle

      and we said...
couple of things

1) an update that updates zero records is 100% successful.  It is not an error,
it is NOT a failure, to update zero rows.  You should not expect any error,
warning or message.

2) Char datatypes are blank padded.  If you compare a char to a varchar2, you
MUST make sure the varchar2 is padded itself!

I would recommand AGAINST using the char type to store data in 100% of the
cases.  there is no time I would use a char type ever.  A char is simply a
varchar2 that is blank padded to the max length.

To correct your current issue you could:

 update rawpropmap set rawpropmapname = ? WHERE rawpropmapname = rpad(?,50)

Before you get too far down this path, I would:

alter table t modify rawpropmapname varchar2(50);
update t set rawpropmapname = rtrim(rawpropmapname);

and just use varchars from now on in.

October 20, 2001 Mohammed Asif -- Thanks for the question
      regarding "Few Questions", version 8.0.5

      You Asked
Hi Tom,

1)  Here are two queries which bring the same data, could you put a light on
performance of both the queries,

The structure of empl is

SQL> desc empl
 Name                            Null?    Type
 ------------------------------- -------- ----
 NO                                       NUMBER(3)
 SAL                                      NUMBER(10,2)
 ST_DATE                                  VARCHAR2(8)
 END_DATE                                 VARCHAR2(8)

 Select * from empl, dual
Where -sal = decode (dummy (+), 'X', -1, -1)
And rownum <=2;

Select -1*top_sal from (select -1*sal top_sal from empl group by -1*sal)
Where rownum <= 2;

And why is the explain plan of Query 1 shows Sort Join for both the table's
(empl & dual).

2) When I select Sysdate from my client, Will it bring me the server date or SCN
date and why?

3) How to find out the table size? (I mean how much(bytes) data is stored in it)

Regards,

Momen.

      and we said...
well, in 8i and up, we would just:

select * from ( select sal from emp order by sal desc ) where rownum = 1;

which would read an index (if one exists) on sal and return the answer
immediately.

In 8.0 I would suggest that BOTH of the above "tricks" are just that -- tricks
that rely on side effects that do NOT have to happen in general

1) group by does NOT have to sort.  I can give you many examples where it does
not sort

2) the join on the decode does NOT have to sort merge join, it could do other
things as well.

I would not recommend either trick.  In 8.0 you should code:

select sal from emp order by sal desc;

and fetch just the FIRST row.  That is the only reliable, bug free way to do it.

Both queries performance is pretty miserable here.  They apply functions to SAL
(negation) and hence preclude any indexes (8.0 doesn't have function based
indexes).  They will read and sort every row in emp -- they both perform poorly.

If asked to provide a query that returns the "highest sal" as a single row I
would be tempted to code:

select sal from emp where sal = ( select max(sal) from emp ) and rownum = 1;

At least then, if there were an index on SAL, it could use it to find the
MAX(sal) and then to find the sal's that have that max sal.

2) if you select sysdate from dual, that'll be sysdate on the server.  The SCN
is a number, not a date (be horrible about daylight savings if it were a date)

3) see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:231414051079
...
Review &
      Followup

      Rating: 3
Thank
      You  October 20, 2001
Reviewer:  Asif
       from Riyadh
Thanks a lot for a quick reply.

October 20, 2001 Mohammed -- Thanks for the question regarding
      "Asking Abou your Book", version 8i

      You Asked
hi  Tom ,
I forget to Ask you about if your New Book  will help me to build
new Application in Oracle like Securty Methods or any other Advices to build
Good Application .

Thank you,
 very Much

      and we said...
See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:596547219224
I would say definitely yes, it will help you build new applications.
Review &
      Followup

      Rating: 4
buying Tom
      Book  October 20, 2001
Reviewer:  Mohammed
      Al-moayed  from Yemen
whereas here in Yemen Thire is no big BookStore to Sell Computer Books ,but I
will Buy it as soon As posible
fromany Where in The world ;)

      Rating: 4
buying Tom
      Book  October 20, 2001
Reviewer:  Mohammed
      Al-moayed  from Yemen
whereas here in Yemen Thire is no big BookStore to Sell Computer Books ,but I
will Buy it as soon As posible
fromany Where in The world ;)

      Rating: 4
buying Tom
      Book  October 21, 2001
Reviewer:  Mohammed
      Al-moayed  from Yemen
whereas here in Yemen Thire is no big BookStore to Sell Computer Books ,but I
will Buy it as soon As posible
fromany Where in The world ;)

October 20, 2001 siva rama -- Thanks for the question regarding
      "database", version 8.1.6

      You Asked
Hi Tom

1. I am working on a Product development which includes Finance & Accounts,
Sales, Production, Payroll, and more modules called together as EMS (Enterprise
Management System) using VB and Oracle 8i technologies of database size more
than 650 GB. In fact Prodocut basis development exposure is first time to me. In
this scenario I sugested one database per each company. because the solution is
meant for group of companies. what is your comments on this? Am I correct?
or is there any best practice in industry to meet the requirement.

2. Can you give me the differences between SQL server to Oracle 8i. Why I am
asking like this is recently my clients are asking for SQL server instead of
oracle. But we suggested and preferred Oracle is the best.

Regards

SivaRam

      and we said...
1) one database period.  put all of the companies you want in there.  Use fine
grained access control so that company A cannot see company B's data

This is what we Oracle do with our hosted online service.  One database, as many
companies as we can cram in there.  The less databases you have, the less stuff
you have to manage.

see

http://osi.oracle.com/~tkyte/article2/index.html
more info in my book if you are interested.

2) The short list is simply this.  Oracle8i is available on every platform of
any worth.  It always has been, always will be.  5 years ago, NT stood for NOT
THERE.  Unix was king.  Go back 5 more years.  Unix was just becoming cool, VAX
VMS ruled, mainframes were starting to be considered that old stodgy technology
(remember, PCs were still just starting to appear everywhere then as well).  5
Years before that -- mainframes rules, mini computer systems just starting out.

Now, fast forward 5 years from now.  To paraphrase a famous comercial "where do
you want to be".  In 5 years, I'll betch windows is not the place - it'll be
replaced by some new hardward/software combo and then where are you?  you are
with a database that limits you to exactly one OS -- their OS.

That is the major, #1 difference between us and them.  If your customer feels
windows is the flatform of the 21st century..... and always will be, I guess its
a safe choice.  If they look at history, really look at it, they might begin to
feel a little different.

October 20, 2001 Keval -- Thanks for the question regarding
      "Automatic rounding of fractional number", version 8.1.6

      You Asked
Hi,

by default oracle inserts data after rounding of if required... for eg. my table
field is havin defination like number ( 1 ) and if i try to insert value as 9.9
then it will make it 10 and then insert into the database instead i want to
truncate the extra digit... how do i do that?

/********************************
SQL> create table my_tab ( field_name number (1) );

Table created.

SQL> insert into my_tab values ( 9.5 );
insert into my_tab values ( 9.5 )
                          *
ERROR at line 1:
ORA-01438: value larger than specified precision allows for this column

SQL> c/5/4
  1* insert into my_tab values ( 9.4 )
SQL> /

1 row created.

SQL>

***********************************/
Pls. help me to change the setting by which i can allow users to insert values
like 9.5 in the datbase without using 'trunc' function

Thanx in anticipation

      and we said...
You will have to use the trunc function OR create the table with just a NUMBER
column and use a trigger to edit it:

scott@ORA806.WORLD> create table t ( field_number number );
Table created.

scott@ORA806.WORLD> create trigger t_trigger
  2  before insert or update on t
  3  for each row
  4  declare
  5    tmp number(1);
  6  begin
  7     tmp := trunc(:new.field_number);
  8     :new.field_number := tmp;
  9  end;
 10  /

Trigger created.

scott@ORA806.WORLD>
scott@ORA806.WORLD> insert into t values ( 9.9 );

1 row created.

scott@ORA806.WORLD> insert into t values ( 10 );
insert into t values ( 10 )
            *
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: number precision too large
ORA-06512: at "SCOTT.T_TRIGGER", line 4
ORA-04088: error during execution of trigger 'SCOTT.T_TRIGGER'

scott@ORA806.WORLD>
scott@ORA806.WORLD> select * from t;

FIELD_NUMBER
------------
           9

Review &
      Followup

      Rating: 3
What about
      number(1,0)?  October 20, 2001
Reviewer:  Doug
      Cowles  from CT, USA
SQL> create table a (a number(1,0));
Table created.
SQL> insert into a values (1);
1 row created.
SQL> insert into a values (1.9);
1 row created.
SQL> select * from a;
A
----
1
2
SQL>

That rounds it.  Truncate doesn't round.. No?

          Followup:

that doesn't do what they asked to do:

"...and if i try to insert value as 9.9
then it will make it 10 and then insert into the database instead i want to
truncate the extra digit."

yours rounds, they want trunc

      Rating: 1
I wanted to
      change the settings of Oracel  October 22, 2001

Reviewer:  Keval Shah  from India
I have got n number of tables and n number of columns which is having datatype
as number and i wanted to change the setting for all of them at 1 shot.
Thanx anyway to responding my question.

October 21, 2001 Peter -- Thanks for the question regarding "Close
      "Opened Cursor" Manually and your new book", version 8.1.6

      You Asked
Hi Tom:

1)
If we detect cursor leak (e.g. user not close of callablestatement in the java
code).

Using:
select a.value, b.name from v$mystat a, v$statname b where a.statistic# =
b.statistic# and a.statistic#= 3

How can we manually  close "opened cursor" outside of the application without
“kill a session”?

2)Please talk about your new book!

Thanks,
Peter Cheng

      and we said...
1) Sorry but you cannot.  Just as you could not close open files this program
leaks.  The program itself must fix its behavior.  It would be a disaster to
close some cursor before the program would actually be done with it -- how can
you tell from "outside" that the cursor is obsolete?  In any case, we have no
facility to do that.

2) My book comes out in June 2001.  It is about Developing in Oracle.  It is
geared towards both the DBA and the Developer with more of a developer slant.
It is what I believe everyone programming against Oracle needs to know (or at
least be aware of)..  I cover the architecture of Oracle (the files, the memory,
the processes).  From there I go onto Locking and concurreny controls -- how
transactions work, what happens with redo and rollback.  Then I cover all of the
different types of tables you can have (heap, IOT's, nested, object relational,
b*tree clustered, hash clustered) and index types.  Then we look at utilities
such as imp/exp and SQLLDR -- trying to answer the frequently asked questions,
info the utilities guide doesn't necessarily cover.

Application Tuning and Optimizer plan stability are covered next.  My approach
to tuning is a little different I think.  You won't see "buffer cache hit ratio"
mentioned once -- but you'll know how to make sense of the Oracle trace file and
tkprof reports by the time you are done.  I focus on application tuning (whereas
most other books seem to focus on database instance tuning).  I find 80% or more
of the payback in tuning comes from there -- that is where I start.

The next section of the book goes into advance sql features where I discuss and
show how to use

o analytic functions
o materialized view
o partitioning
o autonomous transactions
o dynamic sql (from a plsql point of view)

The I get into extensibility:

o intermedia text
o C based external procedures
o Java external procedures (java stored procs)
o Using object relational features

And finally some security related topics:

o Fine Grained Access control
o N-Tier authentication
o Invokers/Definers rights procedures (what it means and when to use them)

The last part is a pretty large appendix where I cover many of the supplied
packages -- not in the sense that the supplied packages guide covers them, i
expect you'll refer to that for the list of all functions and their
inputs/outputs -- rather here I show how I use them, covering only the packages
I find relevant (and haven't already covered earlier).  About 18 packages in
all....

Review &
      Followup

      Rating:
      5
  May 07, 2001
Reviewer:  Bala
       from Florida USA

      Rating:
      5
  May 07, 2001
Reviewer:  Bala
       from Florida USA

      Rating:
      5
  May 07, 2001
Reviewer:  Peter
       from Gaithersburg, MD USA
Good Jobs and Thanks for your efforts.

      Rating:
      5
Excellent  July 01, 2001
Reviewer:
      Narendra  from Thailand
Hi Tom
Congratulations ,Really you are doing a great job,keep it up.
Awaiting your next Book .

      Rating: 4
Your
      Book  August 20, 2001
Reviewer:  R.Ganguli
       from Detroit , USA
Tom,

I finished your book, and it cleared up many of my doubts, it's one of the best.
I am going to go through it a second time. Why don't you write a book for the
DBA's with more details on the internals, latches , File Systems , RAIDs etc.

Thank you
Ran

          Followup:

Have you read Jonathan Lewis's book -- its pretty great:

http://www.amazon.com/exec/obidos/ASIN/0201715848
...

      Rating: 3
Book
      details  October 21, 2001
Reviewer:
      Abdal-Rahman Agha  from Yemen
I still have no info about your book. Please, can write specific details about
your book so that I can request it from the bookshop that has it. e.g, the ISBN,
the Title, the Price, the Bookshop that is the book available in.

Thanks.

          Followup:

just goto
http://asktom.oracle.com/
A link into amazon that provides all of the above is there (well, except for the
bookshop, I don't know what bookshops there are in Yemen)

October 21, 2001 Doug -- Thanks for the question regarding
      "maximum bandwidth of disk controller never hit... so does it matter where
      I put things?", version 8.1.7

      You Asked
I wish I could provide a lot of detail but here's the situation -
A disk containing redo logs is in a stripe set that also contains both data and
indexes (of different databases).  According to absolutely every single piece of
Oracle lore out there, regardless of RAID configuration etc., you should try to
put redo on there own disks or at least a fast write type of arrangement.

Here's the counter argument I'm hearing:
If the I/O on the disk never reaches the maximum bandwith possible according to
spec.. who cares?

Your thoughts?

      and we said...
Ok, you have a ticket counter.  Say at the airport.  There is a premier line
(frequent fliers).  The theoretical throughput of this line is 100
passengers/hour.  There is the non-premier line capable of the same.

Now, there are more non-premier than premier arriving at the counters.

When the premier line is empty, they pull from the non-premier line.  But, it
seems, every time they pull from the non-premier line, three premier members
immediately queue up and have to wait for the non-premier member to finish
before they get attention.

It is slow at the airport, we are only doing 100 passengers/hour even though we
have the capacity for 200.  We are no where near the maximum bandwidth, yet our
premier members are slowed down, forced to wait for non-premier members.  There
is still a line, just a steady stream of customers, always a backlog.

c/premier/redo/ in the above and see if that doesn't make sense.

True, you have not hit capacity but the one thing that makes you serialize AND
wait (LGWR writes) are going slower then they COULD (should).

Log writes are the one thing your foreground process must wait for.  When you
commit, you wait for LOG writes.  The other files (data datafiles like rollback,
table data, indexes, etc) are done in the background by DBWR, you don't WAIT for
those normally (well, if your buffer cache is really full you might).

So, even though you aren't hitting the theoretical max on your disks, you are
introducing contention (and contention will prevent you from EVER hitting the
max!!!  It is a circular argument here.  the max throughput is achievable via
dust free laboratory environments with largish sequential writes.  Random IO --
takes it way way down).

There is my counter argument.  You should still strive to isolate your logs and
archives from the rest of the system.

Not saying you have a bad situation, just that the argument that you haven't hit
the limit of the disks doesn't mean a whole lot.
Review &
      Followup

      Rating:
      4
Interesting  October 21, 2001
Reviewer:
      Doug Cowles  from CT, USA
Sounds like what your saying is - just because you haven't hit the maximum
capacity of the controller doesn't mean you're not slowing things down.  I'm
going to puruse this further.

          Followup:

Anytime you have a shared resource, you might have to wait for it -- even if its
not at capacity.  What you should do is measure your wait events and see if you
are waiting for LGWR to do its job.

(yes, that is what I was saying, you do not have to be at capacity to cause a
wait, you just need to be sharing the resource with someone you don't have to be
sharing the resource with)

      Rating: 4
Excellent
      Response  November 15, 2001
Reviewer:
      Pichaimani Balasubramanian  from San Jose, CA
Hi Tom,
   Thanks for hitting the home run and putting the things in
proper perspective.

October 21, 2001 shan -- Thanks for the question regarding "resize
      the max extent size ", version 8.1.7.0

      You Asked
How to increase the maximum extent size of  a Particular table?
How do you calculate the max extent size in ditctionary managed table spaces?

      and we said...
The max extent size is fixed for all objects at 2gig. The biggest extent you can
have is 2gig in size.

If you mean change the max extents (the max number of extents an object can
have), you do that via an alter statement:

alter table t storage (maxextents 5);

Tables in LMT's have unlimited max extents, you cannot alter that.


Subject | Article | Last Updated (East coast time)
email | article only | Oct 22, 2001 07:47 am
session_problem | article only | Oct 22, 2001 09:18 am
SHOW command doesn't work everywhere | article only | Oct 22, 2001 11:30 am
Question on Database Data Encryption | article only | Oct 23, 2001 09:19 am
Inserting values into Table containing ref to the object type. | article only | Oct 23, 2001 09:24 am
Password protection | article only | Oct 24, 2001 12:02 pm
clob vs bfile | article only | Oct 24, 2001 12:04 pm
updates and undo-redos | article only | Oct 24, 2001 03:23 pm
Snapshot too old X read only tablespaces | article only | Oct 25, 2001 07:58 am
Free Space in Rollback Segments | article only | Oct 25, 2001 08:00 am
Unique index | article only | Oct 25, 2001 08:01 am
Reordering part of a group by within a group by? | article only | Oct 25, 2001 08:31 am
Snapshot too old on snapshots | article only | Oct 25, 2001 10:56 am
Viewing fractions of a second in a date field. | article only | Oct 25, 2001 12:19 pm
Dirty reads... | article only | Oct 25, 2001 01:24 pm
How to display word size? | article only | Oct 25, 2001 07:18 pm
Problems with import of repository objects dump | article only | Oct 25, 2001 07:25 pm
Conversion of image types | article only | Oct 25, 2001 08:21 pm
Performance tuning with where statement | article only | Oct 26, 2001 03:11 pm
SQLPLUS Report with compute sum function | article only | Oct 26, 2001 03:25 pm
dbms_obfuscation_toolkit.desencrypt | article only | Oct 26, 2001 06:16 pm
About remove constant | article only | Oct 27, 2001 03:55 pm
Oracle Database Security | article only | Oct 27, 2001 06:16 pm
How to Optimize Delete | article only | Oct 28, 2001 02:50 pm
row(s) 1 - 24 of 24
October 22, 2001 -- Thanks for the question regarding "email", version 8i
You Asked
dear

i have a table and i need when this table updated i recive email
i have oracle 8i 8.1.7 and the server is windows 2000 and i have
another server with exchange server but i am not the admin for exchange server
but so how can i use also i need to receive email when
the database is down ??

best reg
and we said...
Well, the database won't be "recieving" mail.  You can have a process running in
the database (scheduled via dbms_job so that it runs every N minutes to look for
mail) that will retrieve the mail from some server.

You can accomplish this with a java stored procedure and the java mail api.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:255615160805
it shows how to SEND mail -- but the java mail api fully supports reading mail
(it just shows you the concepts you can use).

When the database is down, your job will not run, hence the mail will be saved
in the exchange server until the database is up and your jobs once again start
running.
Review & Followup
Rating: 5
Useful October 22, 2001
Reviewer: Rajendra Prasad N
People will gets knowledge when they open their minds .
excellent site

Rating: 4
good answer October 22, 2001
Reviewer: ashraf

Rating: 3
not recive through database October 22, 2001
Reviewer: A reader from kuwait
no my question is i need to recieve email through my outlook when the database
is down or the resource for the database is low (memory,tablespace,...)

Followup:
then your question makes no sense to me.  doesn't sound like a database problem
to me -- if it is running totally outside of the database, when the database is
down or otherwise unavailable.  Sounds like a windoze programming exercise.

Rating: 3
October 22, 2001
Reviewer: A reader
when  i tar to load activation8i.jar i get:
--------------------------------------------------
    ORA-29552: verification warning: at offset 12 of javax.activation.Activation
DataFlavor.<init> resolved FIELD<null> cannot Access java.awt.datatransfer.DataF
lavor.class$java$io$InputStream
verifier is replacing bytecode at javax.activation.ActivationDataFlavor.<init>:1
2 by a throw
at offset 12 of javax.activation.ActivationDataFlavor.<init> resolved FIELD<null
> cannot Access java.awt.datatransfer.DataFlavor.class$java$io$InputStream
at offset 18 of javax.activation.ActivationDataFlavor.<init> resolved FIELD<null
> cannot Access java.awt.datatransfer.DataFlavor.class$java$io$InputStream
verifier is replacing bytecode at javax.activation.ActivationDataFlavor.<init>:1
8 by a throw
at offset 18 of javax.activation.ActivationDataFlavor.<init> resolved FIELD<null
> cannot Access java.awt.datatransfer.DataFlavor.class$java$io$InputStream
at offset 30 of javax.activation.ActivationDataFlavor.<init> resolved FIELD<null
> cannot Access java.awt.datatransfer.DataFlavor.class$java$io$InputStream
verifier is replacing bytecode at javax.activation.ActivationDataFlavor.<init>:3
0 by a throw
at offset 30 of javax.activation.ActivationDataFlavor.<init> resolved FIELD<null
> cannot Access java.awt.datatransfer.DataFlavor.class$java$io$InputStream

skipping : javax/activation/MimeTypeParseException is already resolved
skipping : javax/activation/DataHandler$1 is already resolved
skipping : javax/activation/DataHandlerDataSource is already resolved
----------------------------------------------------------
add classpath for translator.zip

what is the wrong

Rating: 1
Solution: Monitoring database thro' mail updates October 25, 2001
Reviewer: Sanjeev from Kuwait
As I understand from the problem interpreted in the followup comment:
You can user Oracle Tools (like Enterprise manager) and configure them in such a
way that they can talk to your Outlook mailing system thro' SNMP.

Following is one example in which I receive a mail from the OEM about the
selective database activities (DB Shudown, startup, Space problems etc.)
==========================================================
Service=prod
Node=db1

Result=Tablespace TEMP is 90.87% full.  189160 KBytes of free space remain.
Status=CRITICAL
Timestamp=21-Oct-01 8:32:48 PM
Test=Tablespace Full

Result=Event test "Database UpDown" is cleared
Status=CLEARED
Timestamp=20-Oct-01 11:46:05 PM
Test=Database UpDown

Result=Event test "Maximum Extents" is cleared
Status=CLEARED
Timestamp=15-Oct-01 10:50:47 AM
Test=Maximum Extents

Result=Event test "Archive Full" is cleared
Status=CLEARED
Timestamp=18-Sep-01 1:40:59 PM
Test=Archive Full

October 22, 2001 Nikhil -- Thanks for the question regarding "session_problem", version 8
You Asked
Hi TOM
Once Again I am here to get help from u.
I am developing a user monitoring system , In which i want to maintain the
statistics of database users i.e. when a user logged in , through which
application,terminal,and when that user logged out. In my case there may be
several simultaneous instances of the same user.
Eg.

username   application     machine         login        logout
scott     oracleforms    term2     19-oct-2001 12:40:50   19-oct-2001 12:42:55
scott     oracleforms    term3     19-oct-2001 11:40:50   19-oct-2001 13:40:55
sys       sql        SERVER     19-oct-2001 09:30:50   19-oct-2001 17:42:55
I tried V$session but through that we can only get login and other information
but ,I could'nt get logout information.
I also tried  dbms_session package in after logon database trigger to get unique
session_id,
but that id is not same as i  got during logout for the same session.
ps help me out .
As i have tried a lot.
Details regrding my working enviornment
    forms 6
    oracle 8i release 8.1.7
Thanx with regard
shamim
and we said...
Use built in auditing -- see the sql reference (audit command) and the admin
guide for details.

It'll capture this for you without any code on your part whatsoever.

You can use "log on" and "log out" triggers as well but you would be writing the
code youself (which is always a bad thing if the system will just do it for you)
October 22, 2001 Bob -- Thanks for the question regarding "SHOW command doesn't work everywhere", version 8.1.7
You Asked
Is there a special option to have the SHOW command work as below:

SQL> show pagesize
pagesize 24
works

SQL> show sga
unknown SHOW option "sga"
doesn't work on all machines. I have set serveroutput=on. Just that some
machines accept that and some don't. (Machines are on different subnets) Any
different params need to be set? Seaching SHOW in the oracl docs comes up with
too many non relevant hits.
Bob Maggio
and we said...
you must have a mixture of 8.0 sqlplus clients (didn't do this command) and 8.1
clients (does do this command).

As a precursor to removing svrmgrl from 9i, all svrmgrl functionality had to be
moved into sqlplus.   commands like:

o startup
o shutdown
o show sga
o show parameter parameter_name

were implemented in the 8i release of sqlplus.
Review & Followup
Rating: 4
Why "reviews" is not turned on all the time? October 22, 2001
Reviewer: A reader from Santa Clara, CA USA
Tom,

Some of the times I don't see the feedback option "Was this response helpful to
you? Let us know!" at the bottom of your answers. It prevents me from sending my
feedback to those questions.

What could be the reason? Does "reviews" also counted towards your
accept-10-questions-and-turn-off logic?

Needless to say, like countless others I learn a lot new and interesting things
from your web site. Hope Larry Ellison recognizes your long lasting and
invaluable contribution.

Thanks so much.

October 23, 2001 Priya -- Thanks for the question regarding "Question on Database Data Encryption", version 8.1.7
You Asked
Hello ,
      We have the following requirement . The website is a b2b portal that uses
the Oracle Database , which stores some really secure data . Now the need is to
ensure optimum security at the Db level .  There was a suggestion,saying that
the data could be encrypted and stored . Though a nice one , my first thoughts
were those of the encryption decryption proceesses ,which i guess has to be done
thru the application .
Now , my question is whether this is possible and if so is this the best method
.No user other than the system administrator should be able to see the encrypted
data directly (by using the decryption procecss) in the database ,so I guess we
need some encryption . Also please note that only some data need to be secure
,the other data can well be seen directly .Also is this possible in any direct
ways in Oracle 9i , we have the software .

Also I would like to know about the On-Delete-cascade functionality,the code
that runs behind the same .

Thanx in advance
Priya
and we said...
search my site for

dbms_obfuscation_toolkit

(or get my book, I have a chapter on this very topic).  We have builtin
encryption in 8i.  You can do single, double or triple key DES encryption in the
database.

Key management -- now that is totally upto you.  You have to figure out

a) how to generate the keys
b) where to store the keys (and DON'T lose them!)

One delete cascade just issues a recursive sql statement that deletes from the
child table for you.
Review & Followup
Rating: 3
Encryption Methods October 23, 2001
Reviewer: Mohammed Al-moayed from Yemen
Well,what are the side effect of Using Encryption Methods
Doese it reduce time of retreving Data , or ...
and, if   I tried to Use Personal Method of Coding The data
Does it Possible  to program it Like Using Haffmen Code
or better to use dbms_obfuscation_toolkit than any other way

Followup:
Think about it

o encryption is cpu intensive.  Yes, this will affect your DML including
retrieval.

I do not know what the "personal method of coding" means.  I suppose you mean
"if i wrote my own".  The Huffman code is a compression algorithm and while it
is true that compression is a very very very weak form of encryption -- it won't
stop anybody (you need no keys to decode compressed data).

You need to determine what your goals are, how secure the data must be.  That
will naturally point you to the proper algorithm to use.

Rating: 4
Don't forget the FK indexes... October 24, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
As to ON DELETE CASCADE, don't forget to index the FK column to prevent high
locking levels on the child table.

October 23, 2001 Farhad -- Thanks for the question regarding "Inserting values into Table containing ref to the object type.", version 8.1.6
You Asked
Hi Tom,
   Thanks for the answer on querying of records. Well this time
I want to know that how will I insert the records in to the
table conatining the column containing reference to object type?

    The script is:
create type address as object
(city varchar2(20),
 street varchar2(20),
 zipcode varchar2(10))
/
Type created...

create type person_t as object
(name varchar2(30),
 home_addr ref address)
/
Type created.
Now I create table named Person of object person_t.
I also create the table of address called addr and insert
records into addr.

I would like to know how to insert the record into person table?

  Hoping for your prompt reply.

 Thanks,
 Farhad.
and we said...
One way or the other -- you'll need to find a way to get a
single row back from the address table.  Looking at your address
type -- it'll be hard as the "primary key" of that object looks
to be the whole row.

In any case, I'll show you how to do this procedurally and using
just SQL.  Here are the types & tables:

ops$tkyte@DEV816> create type address as object
  2  (city varchar2(20),
  3   street varchar2(20),
  4   zipcode varchar2(10))
  5  /

Type created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> create type person_t as object
  2  (name varchar2(30),
  3   home_addr ref address)
  4  /

Type created.

ops$tkyte@DEV816>
ops$tkyte@DEV816>
ops$tkyte@DEV816> create table person of person_t
  2  /

Table created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> create table addrs of address
  2  /

Table created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> insert into addrs values
  2  ( address( 'here', '123 main street', 12345 ) );

1 row created.

Now, to create a person and assign an address using just SQL,
I would code an insert like this:

ops$tkyte@DEV816> insert into person
  2  values
  3  ( person_t( 'Tom', (select ref(A)
  4                        from addrs A
  5                       where A.city = 'here' ) ) );

1 row created.

ops$tkyte@DEV816>
ops$tkyte@DEV816> select p.name, deref( p.home_addr )
  2    from person P
  3  /

NAME
------------------------------
DEREF(P.HOME_ADDR)(CITY, STREET, ZIPCODE)
-----------------------------------------------------------------
-----------------------------------
Tom
ADDRESS('here', '123 main street', '12345')

Note how I used a subquery in the insert to find just the row
I wanted for the insert itself.  I can insert a ref of an
already retrieved row as well.  For example:

ops$tkyte@DEV816> declare
  2          l_ref   ref address;
  3  begin
  4          insert into addrs a values
  5          ( address( 'there', '456 center rd', 78901 ) )
  6          returning ref(a) into l_ref;
  7
  8          insert into person
  9          values ( person_t( 'Lori', l_ref ) );
 10  end;
 11  /

PL/SQL procedure successfully completed.

ops$tkyte@DEV816> select p.name, deref( p.home_addr )
  2    from person P
  3  /

NAME
------------------------------
DEREF(P.HOME_ADDR)(CITY, STREET, ZIPCODE)
-----------------------------------------------------------------
-----------------------------------
Tom
ADDRESS('here', '123 main street', '12345')

Lori
ADDRESS('there', '456 center rd', '78901')
Review & Followup
Rating: 4
but why p.home_address.street not works October 23, 2001
Reviewer: Kamaljeet from New castle, UK
How can i select street name using select query???

Followup:
ops$tkyte@ORA8I.WORLD> l
  1  select p.name, p.home_addr.street
  2*   from person P
ops$tkyte@ORA8I.WORLD> /

NAME                           HOME_ADDR.STREET
------------------------------ --------------------
Tom                            123 main street
Lori                           456 center rd

why indeed?  it does for me.

October 24, 2001 -- Thanks for the question regarding "Password protection", version 8.1.6
You Asked
Is there any way to prevent UNIX Root user to access Oracle database?
and we said...
Nope.

Root is special, magic.  If you are root, you can do anything.  (heck, even if
we could prevent them from logging on -- there would be NOTHING to stop them
from stealing the datafiles themselves, installing them elsewhere and opening
the database over there).

If you don't trust root, you have a serious problem.
Review & Followup
Rating: 5
Thanks!! October 22, 2001
Reviewer: Bhawana from USA

Rating: 3
password October 23, 2001
Reviewer: A reader
is there any way when the user first time log on the database from developer
2000 or sql or other application to force him to change the password

Followup:
You could set up their password to use password aging and have them be in the
"grace" period from the very start.  it would not make them change it right away
but within the first N days (where you define N).  See chapter 21 of the admin
guide for details on "Password Management Policy"

Rating: 5
password file October 23, 2001
Reviewer: A reader
I have a next problem with password file:
the default location of password file is $ORACLE_HOME/dbs/orapw. I have more
than one oracle instance on my host and I want to create one password file for
each instance in another directory:
orapwd file=/SID1/admin/oraSID1pwd passwort=orasid1.
Than I start install_db script and have an error:
ORA-01990: error opening password file '/oracle/ora81700/dbs/orapw'
What I make wrong? I want not to share one password file from different
instance..

Followup:
The file name and location is OS dependent.

on solaris for example, its in $ORACLE_HOME/dbs.  Its name is orapw$ORACLE_SID

You see -- the SID is part of the filename (supporting >1 instance with their
own password file).  See the admin guide for YOUR platforma for details.

Rating: 5
password file October 24, 2001
Reviewer: A reader
Tom, but I want to have my password file in another directory as
$ORACLE_HOME/dbs. What means option file of the orapwd utility? Is it not for
the location of my new password file?
I have Solaris. Can I use the simbolic link from ORACLE_HOME/dbs to my
/$ORACLE_SID/admin directory?

Followup:
symbolic links then, just like the init$ORACLE_SID.ora has to be in
$ORACLE_HOME/dbs, this does too.

The file option of the orapwd utility simply tells that utility the NAME of the
file you want to create.  You need to supply it the correct and proper name
($ORACLE_HOME/dbs/orapwd$ORACLE_SID) so it knows what password file to create.

You can put it elsewhere, but you'll be having a symbolic link to it in
$ORACLE_HOME/dbs.

Rating: 4
This is not really so... October 24, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
In fact, there are some ways to bypass root's sovereignty in the UNIX world
nowadays. Some third party companies are developing tools like SeOS (now
PLATINUM Access Control) by MEMCO. In addition to segmenting superuser access to
UNIX and NT machines (SeOS stands for Security for Open Systems) and expanding
its array of security features, it is begining to be incorporated into several
well-established environments like Tivoli and natively in some versions of UNIX.
Some of these tools are not so new, some dating back to the early 90's. Please
see
http://www.checkpoint.com/press/1996/memco.html
http://www.platinum.com/products/sysman/security/press/alist.htm
http://www.platinum.com/products/sysman/security/press/sec_pack.htm
Hoping to clarify...

          Followup:

This stops people who shouldn't have root from getting root.  But If I got root
- it wouldn't stop me from doing root things (which is what the original
question is about).

This does not stop legimately authorized "root" people from doing "root" things.
 It protects against unauthorized root usage.

So, I still say "got root, you got Oracle (and anything else on the machine)".
This software (seos) is designed to prevent root access by those not supposed to
have it. (i didn't see anything in there that said this prevents "inside jobs"
which is what this question is trying to prevent.

      Rating: 4
... More about
      SeOS  October 24, 2001
Reviewer:  Andre Whittick
      Nasser  from Rio de Janeiro, Brazil
A quote from the link below...

SeOS prevents the abuse of root privileges and unauthorized user access,
allowing legitimate users to work uninterrupted, and maintaining the
confidentiality and integrity of critical business data and applications. SeOS
security policies are consistently enforced and managed across mixed Unix
systems, including HP-UX, IBM AIX, SunOS, SunSolaris, AT&T MP-RAS and Sinix.
Support for Windows NT is planned in the second half of 1997.

SeOS Secured! hardens FireWall-1 by implementing a proactive security policy
that protects all FireWall-1 resources. SeOS Secured! protects the processes,
configuration files, data files, audit files and administrative utilities.
Access is limited to specific users with specific rights—avoiding accidental or
malicious abuse by Unix root users. All security-sensitive events are audited
and tamper-proof.

http://www.checkpoint.com/press/1997/memco9704.html
Note: I've heard there are similar free/shareware tools. If it is of your
interest, check it out.

      Rating: 4
... followup on
      SeOS followup  October 24, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
Tom,

The issue is that, at least in highly controlled environments where I have
worked, root tasks can ( and should ) be completely segregated. That is, no one
should be allowed to have supreme root authority. With SeOS-like stuff you can
"distribute" this authority to the appropriate personnel, allow/disallow access,
etc.

Actually, the root password "did not exist". I just overemphisized this because
we worked on a double-custody basis, where the root password was hash-generated
by computer, broken into two pieces, two different people would get each piece
and put them into two different vaults.

Of course, whenever necessary, we had to enter single-user mode or whatever for
administrative tasks. We had to log into UNIX from the console: Two other people
(not those from the first part) would get each password half from the vault,
unsealing each envelope. Then the first person would enter the first half and
the second person would enter the second half. And... abracadabra... we were in
! There should be at least two other people accompanying you in maintenance
tasks in production.

Only at this point would there be a REAL root in the system -- controlled,
audited.

Even the "segregated" people in daily tasks would have to use maker-and-checker
tools. Any administrative tasks had to be approved by a second party.

That's security...

On the other hand: impact on productivity, that's the price we (rather, the
company) had to pay. Being financial, mission-critical systems, it was quite
understandable...

Thanks again !

October 24, 2001 SUDHAKAR -- Thanks for the question regarding
      "clob vs bfile", version 8.1.6

      You Asked
i want to know the which type is best for storing the xml document type in
database in performance point of view. we are using front end java to store and
retrieve the document stored in the database. pl.explain me the performance of
both the types and which is preferable.

thanks in advance

      and we said...
Only one of these types stores an XML document in the database -- a CLOB.

A bfile is a pointer to an external file.

We do not back them up, we do not make sure they don't accidently get erased, we
provide read only access to them.

If data integrity, backup and recovery is a little bit important, a clob is the
only way to go.

Both will "read" at about the same speed (never noticed a difference myself)

I personally always go for the clob, puts everything in the database.
Review &
      Followup

      Rating:
      4
Best  October 24, 2001
Reviewer:  Rakesh
      Soni  from India
I want it that way.But sir please tell me the book which you often refer in your
answers alongwth the author name & publisher too.

          Followup:

see

http://www.amazon.com/exec/obidos/ASIN/1861004826/
...

October 24, 2001 krish -- Thanks for the question regarding
      "updates and undo-redos", version db 817

      You Asked
Read some time ago somewhere that if an update statement really does not update
any column (== setting the existing value), oracle db is smart enough not to
carry out the update and generate any undo/redos. Is it true?

Thanks,

KU

      and we said...
false.

It has to do the update -- in order to lock the data, fire the triggers, supply
the old/new values, validate constraints.  It is rather blind as to the values,
it just does what its told to.

Some TOOLS (eg: forms) can be told to only update what has changed instead of
each and every column on the screen (default behavior).  Maybe that is what you
were thinking of.

See how the redo increased with each column we add:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t as select * from all_objects;

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> set autotrace on statistics
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> update t set owner = owner;

16990 rows updated.

Statistics
----------------------------------------------------------
          2  recursive calls
      17409  db block gets
        238  consistent gets
        232  physical reads
    4223700  redo size
       1150  bytes sent via SQL*Net to client
        851  bytes received via SQL*Net from client
          6  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
      16990  rows processed

ops$tkyte@ORA717DEV.US.ORACLE.COM> update t set owner = owner, object_name =
object_name;

16990 rows updated.

Statistics
----------------------------------------------------------
          0  recursive calls
      17531  db block gets
        237  consistent gets
          0  physical reads
    5087332  redo size
       1011  bytes sent via SQL*Net to client
        834  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
      16990  rows processed

ops$tkyte@ORA717DEV.US.ORACLE.COM> update t set owner = owner, object_name =
object_name,
  2                           object_id = object_id, last_ddl_time =
last_ddl_time,
  3                           timestamp = timestamp;

16990 rows updated.

Statistics
----------------------------------------------------------
          0  recursive calls
      17717  db block gets
        237  consistent gets
          0  physical reads
    6724032  redo size
       1012  bytes sent via SQL*Net to client
        923  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
      16990  rows processed

Review &
      Followup

      Rating: 4
What about
      rollback segments ?  October 24, 2001
Reviewer:
      Andre Whittick Nasser  from Rio de Janeiro, Brazil
In the above examples where the before image is like the after image, are undo
blocks generated as usual, only "by chance" are the data the same ?

          Followup:

Undo blocks are generated "as usual" as the following shows:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t as select * from all_objects;

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> update t set owner = owner;

16990 rows updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select used_ublk
  2    from v$transaction
  3   where addr = ( select taddr from v$session where sid =
  4                     ( select sid from v$mystat where rownum = 1 )
  5                );

 USED_UBLK
----------
       202

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> update t set owner = owner, object_name =
object_name;

16990 rows updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select used_ublk
  2    from v$transaction
  3   where addr = ( select taddr from v$session where sid =
  4                     ( select sid from v$mystat where rownum = 1 )
  5                );

 USED_UBLK
----------
       465

ops$tkyte@ORA717DEV.US.ORACLE.COM> update t set owner = owner, object_name =
object_name,
  2               object_id = object_id, last_ddl_time = last_ddl_time,
  3               timestamp = timestamp;

16990 rows updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select used_ublk
  2    from v$transaction
  3   where addr = ( select taddr from v$session where sid =
  4                     ( select sid from v$mystat where rownum = 1 )
  5                );

 USED_UBLK
----------
       821

ops$tkyte@ORA717DEV.US.ORACLE.COM> commit;

Commit complete.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> update t set owner = rpad( '*',
length(owner), '*' );

16990 rows updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select used_ublk
  2    from v$transaction
  3   where addr = ( select taddr from v$session where sid =
  4                     ( select sid from v$mystat where rownum = 1 )
  5                );

 USED_UBLK
----------
       202

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> update t set owner = rpad( '*',
length(owner), '*' ),
  2               object_name = rpad( '*',length(object_name), '*' );

16990 rows updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select used_ublk
  2    from v$transaction
  3   where addr = ( select taddr from v$session where sid =
  4                     ( select sid from v$mystat where rownum = 1 )
  5                );

 USED_UBLK
----------
       465

ops$tkyte@ORA717DEV.US.ORACLE.COM> update t set owner = rpad( '*',
length(owner), '*' ),
  2               object_name = rpad( '*',length(object_name), '*' ),
  3               object_id = -object_id, last_ddl_time = last_ddl_time-1,
  4               timestamp = rpad( '*', length(timestamp), '*' );

16990 rows updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select used_ublk
  2    from v$transaction
  3   where addr = ( select taddr from v$session where sid =
  4                     ( select sid from v$mystat where rownum = 1 )
  5                );

 USED_UBLK
----------
       821

So, regardless of whether we updated the column to itself or to something else
-- the same amount of undo is generated.

October 25, 2001 Andre -- Thanks for the question regarding
      "Snapshot too old X read only tablespaces", version 816

      You Asked
Hi Tom.
If i have a query that frequently raise the error ORA 1555, then I
get the tablespace names of all the tables that the query uses.
So, I put them READONLY. Is it guaranteed that the error ORA 1555 will not be
generated ?

Another question: is it a good idea perform a
select * from ... all tables involved in the process before execute the query ?

Regards,
André.

      and we said...
No, it will not be assured.  Relevant facts for following test:

o db_block_buffers 300
o block size 8k

We'll show how a query against a table in a READ ONLY tablespace can get the
ora-1555 quite easily in an active system (which you must have).

tkyte@TKYTE816> create table t tablespace users unrecoverable as select * from
all_objects;

Table created.

tkyte@TKYTE816> create table small( x int, y char(500) ) tablespace tools;
Table created.

tkyte@TKYTE816> insert into small values ( 0, null );
1 row created.

tkyte@TKYTE816> commit;
Commit complete.

tkyte@TKYTE816> create rollback segment rbs_small
  2  tablespace tools
  3  storage ( initial 1k next 1k minextents 2 maxextents unlimited )
  4  /
Rollback segment created.

tkyte@TKYTE816> alter rollback segment rbs_small online
  2  /
Rollback segment altered.

tkyte@TKYTE816> begin
  2      commit;
  3      set transaction use rollback segment rbs_small;
  4      update t
  5         set object_type = lower(object_type);
  6      commit;
  7      execute immediate 'alter tablespace users read only';
  8
  9      for x in ( select * from t )
 10      loop
 11          for i in 1 .. 20
 12          loop
 13             set transaction use rollback segment rbs_small;
 14             update small set x = x+1, y = x;
 15             commit;
 16          end loop;
 17      end loop;
 18  end;
 19  /
begin
*
ERROR at line 1:
ORA-01555: snapshot too old: rollback segment number 10 with name "RBS_SMALL"
too small
ORA-06512: at line 9

(the above is a side effect of the delayed block cleanout)....

The solution is to have rollback segments that are sized correctly for your
entire system -- NOT just for the write components of the system.

You need to size RBS given the system -- read and write, not just write.

You should use equi-sized rollback segments (do NOT have a "big one" and then
other small ones).  the probability of the ora-1555 is in direct proportion to
the size of your SMALLEST rbs.  The largest only helps writes -- does nothing
for the reads.

It would not be a good idea to "select * from all tables" -- it would be good to
size rollback properly for the system as a whole.

In almost 15 years, I've never once hit this in a properly sized system.  I've
fixed lots of systems that hit this (by sizing RBS correctly for them).
Rollback is not something to skimp on or undersize.

Review &
      Followup

      Rating:
      3
  October 25, 2001
Reviewer:  Sagi

Hi Tom !

I agree with u in terms of Sizing the RBS properly.  But then how do we exactly
determine the exact size of the RBS. If you could explain it with an example
then it would be helpful for many of us.

Thanx in Adv.

          Followup:

You need to determine the longest running query you have.

You need to determine the length of the longest running transaction you do.

You need to ensure you have sufficient rolllback permanently (not that it can
GROW but rather that it is permanently allocated) so that you do not wrap in the
perdiod of time that is larger then the above two numbers.

Most people size for their insert/update/delete transactions.  They forget about
sizing for the read transactions.  You can monitor the v$ tables to see when and
how fast your RBS wrap.  You need to determine how much rollback you generate in
a period of time.  Say you generate X blocks of undo in 1 minutes.  You have a
long running query that takes 15 minutes.  You need to have more then 16 * X
blocks of undo configured.

In 9i, this is simplified as you may use an UNDO tablespace instead of rollback
segments.  Here you configure a retention period (how long do you want to keep
undo) and it sizes itself.

October 25, 2001 Thiruvaiyaru -- Thanks for the question regarding
      "Free Space in Rollback Segments", version 8.1.6

      You Asked
Tom,

How can I find the amount of space used and the amount of free space left over
in Bytes for each rollback segment ?

Thanks,
T

      and we said...
You can sum up the used_ublk column in v$transaction to see how much of an rbs
is currently being used at that point in time:

select b.segment_name, sum(c.used_ublk)
  from dba_rollback_segs b, v$transaction c
 where b.segment_id = c.xidusn
 group by segment_name
/

Now, its hard to say how much "free space" there is -- cause we will not reuse
an extent in an RBS as long as 1 block is used in it.  For example, say you have
an RBS with 5 extents and each extent has 100 blocks.  In extent 1, a small 1
row update is using the first block in that extent.  They did not commit.  Over
time, we used extents 2, 3, 4, 5.  Now, we'd like to reuse extent 1 but we
cannot since there is 1 active block in there (sum(used_ublk) in v$transaction
is 1).  We have 499 unused blocks, 1 used block -- we are forced to extent the
rbs anyway.
Review & Followup

      Rating: 4
Used space in
      rollback  October 24, 2001
Reviewer:  Logan
       from Santa Clara, CA 95051.
Tom,

1) I understand the RBS logic. But in the last line you are saying "We have 499
unused blocks, 1 used block -- we are forced to extent the rbs anyway."

Why should the rollback extend when blocks 2,3, 4 and 5 are free (499 unused
blocks 4*100 + 1*99)? I don't get it.

2. A General question about your postings. I am reposting it verbatim since I
didn't get any response.

Some of the times I don't see the feedback option "Was this response helpful to
you? Let us know!" at the bottom of your answers. It prevents me from sending my
feedback to those questions.

What could be the reason? Does "reviews" also counted towards your
accept-10-questions-and-turn-off logic?

Needless to say, like countless others everyday I learn a lot of new and
interesting things from your web site. Hope Larry Ellison recognizes your long
lasting and invaluable contribution.

Thanks so much.

          Followup:

1) first of all -- it is not that blocks 2, 3, 4, and 5 are free -- it is that
extents 2, 3, 4, and 5 (each having 100 blocks) are unused but (in this case)
UNUSABLE since extent #1 is still active.  We use rollback segments in a
circular buffer.  We use extent 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ..... over and
over.  If we are in extent five and need more space, we will try to use extent
#1.  If that is still active -- we must extend the rollback segment itself.  I
can demonstrate this fairly easily.  In one session I execute:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create rollback segment rbs_demo
  2  tablespace dict_managed
  3  storage ( initial 1k next 1k maxextents 50 minextents 5 )
  4  /

Rollback segment created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> alter rollback segment rbs_demo online
  2  /

Rollback segment altered.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> drop table t;

Table dropped.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t ( x int );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> set transaction use rollback segment
rbs_demo;

Transaction set.

ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t values (1);

1 row created.

Now, leave that session open -- we are using a teeny tiny bit of the first
extent in rbs_demo with our insert (we are using 1 block).  Now, open another
session and execute:

ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t select object_id from
all_objects where rownum <= 1000;

16990 rows created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> commit;

Commit complete.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> begin
  2    loop
  3         execute immediate 'set transaction use rollback segment rbs_demo';
  4         update t set x = x+1;
  5         commit;
  6         dbms_output.put_line( 'updated....' );
  7    end loop;
  8  end;
  9  /updated....
updated....
updated....
updated....
updated....
updated....
updated....
updated....
updated....
updated....
updated....
updated....
updated....
updated....
updated....
begin
*
ERROR at line 1:
ORA-01562: failed to extend rollback segment number 7
ORA-01628: max # extents (50) reached for rollback segment RBS_DEMO
ORA-06512: at line 4

ops$tkyte@ORA717DEV.US.ORACLE.COM> select used_ublk from v$transaction;

 USED_UBLK
----------
         1

See, we are using 1 block of RBS data -- we did a couple of updates successfully
(so we know our update takes LESS then 50 extents of data to accomplish) yet we
eventually ran out of rbs since we had that one block used in extent 1 -- we
added 45 extents and eventually ran out of extents to add.  All because of that
sole uncommitted transaction.

2) I cannot imagine any circumstance under which the "feedback option" would not
appear unless you were perhaps on a slow network and the last bit of the page
didn't come over (or you hit stop or something).  Its always there.  I never
turn that off.

      Rating:
      5
#2  October 24, 2001
Reviewer:  J
       from MA
Happens all the time to me also.
The arrow buttons on search/archive also don't show.

Hold down the mouse and highlite everything and
automagically (;)) they appear

Thanks for all the info Tom..

      Rating: 3
Negative used
      space in rollback?  October 25, 2001
Reviewer:
      Joachim Rupik  from Warsaw, Poland
Hello Tom,

What does it mean when used_ublk is negative value?

Regards,
Joachim Rupik

          Followup:

see the second comment in

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1612650665417
...

October 25, 2001 Jacques -- Thanks for the question regarding
      "Unique index", version 8.1.7

      You Asked
Hi Tom,

I have the following issue which is causing some confusion.
I was trying to update my comments table (com$) with comments exported out of
another database. however I keep getting a constraint error on the Index saying
that there are duplicate values which there are not.
Induvidually the columns contain duplicates but this should not matter as the
two columns combined does not contain any.
Originally the table had a uniqe index on but I removed this in order to get my
values in - now it does not want to go back on. I'm sure no duplicates exist
when the two columns are combined

Any ideas?

Thanks

Jacques

SQL> desc com$
 Name                            Null?    Type
 ------------------------------- -------- ----
 OBJ#                            NOT NULL NUMBER
 COL#                                     NUMBER
 COMMENT$                                 VARCHAR2(4000)

SQL> select * from com$ where OBJ# = COL#;

no rows selected

SQL> CREATE UNIQUE INDEX I_TESTUNIQUE ON SYS.COM$ (OBJ#,COL#);
CREATE UNIQUE INDEX I_TESTUNIQUE ON SYS.COM$ (OBJ#,COL#)
                                        *
ERROR at line 1:
ORA-01452: cannot CREATE UNIQUE INDEX; duplicate keys found

      and we said...
Arg!  I cannot believe you are doing this.

Stop what you are doing IMMEDIATELY.

You never (eg: as in NEVER) update the data dictionary.  Totally forbidden.
Don't do it.  Bad....

I cannot believe you DROPPED A CONSTRAINT on the oracle data dictionary.  (i
really truly cannot believe it.  I'm stunned)

That aside, what you have done is 100% ILLOGICAL as well.  The obj# of table T
in one database will not be the obj# of the table T in another database.
Your comments will be assigned randomly to tables (or to no table at all -- just
cause obj# 5 exists in db1 doesn't mean that obj# 5 exists in db2 or that it has
the same number of columns).

That aside aside -- the unique constraint is on obj#, col# -- its not there to
say obj# <> col# -- it is there to say that if you have obj# 5, col# 1 -- you
can have but one row.  It must be that you some comments already in the database
you imported into (you do, they are on the data dictionary) and now you have a
TOTAL MESS.

I don't know what to tell you -- you need to undo what you've done as you have
corrupted the data dictionary itself.  Many tools (eg: exp) will be comprimised
and may not work at all as you have damaged the logical integrity of the com$
table by doing what you have done.

Contact support.
Review & Followup

      Rating: 5
Oh my
      god.....  October 22, 2001
Reviewer:  Connor
       from UK
I dread to think of how dropping users is being done on this database :-(

To transfer comments, you could easily build a script to do it:

select 'COMMENT ON COLUMN '||table_name||'.'||column_name||' is '||comments||';'
from user_col_comments

select 'COMMENT ON TABLE '||table_name||' is '||comments||';'
from user_tab_comments

or similar - spool it out to file on your database and run it against the
other...

Updating com$... sheesh

      Rating:
      4
Oh?  October 22, 2001
Reviewer:
      Jacques  from Cologne, Germany
No need to call support just yet - It's a test system.

I appreciate what you are saying about corrupting the dictionary.
Here's what I've done and why:

1.) ORA-01779: cannot modify a column which maps to a non key-preserved table. -
This is the error I recieve when I try and update a comment via the
ALL_COL_COMMENTS" view.

2.) The resolution on Metalink is to modify the underlaying tables.
Here is the link:
http://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=NOT&p_id=38646.1
OK maybe I took a bit of a liberty by applying this resolution to the dictionary
but I have more than a thousand columns to comment and to do it manually.....
well I can't type all that fast. - not really an option.

I've found the problem since and I admit it was due to my stupidity where I had
a duplicate in the import file which has been rectified and the index has been
restored as a unique one. Hoever I'd appreciate any other suggestions you might
have for bringing in comments in a situation like this.

Thanks

Jacques

          Followup:

See Connor's comments above (sorry, I should have mentioned the comment command)

      Rating: 4
here is the
      code  October 22, 2001
Reviewer:  Jacques
       from Cologne, Germany
OK here is the code that did it:
As you can see all the objects aready existed in the database the were just
commented.
So I joined a couple of tables in order to match the right comment to the right
object id and column id and viola it all seems to be hanging together fine and
all my comments are there.

Please let me know if there is something insanely stupid which i have missed but
I think I'm safe as I did not bring in any new object just commented existing
ones.

Jacques

insert into com$ select  c.obj#,c.col#,j.discription
from col$ c,jump_dis j
where obj# in
 (select obj# from sys.obj$@test817 where Owner# = 26)
 and type# = 2 and c.name = j.col_name

          Followup:

The insanely "stupid" thing is you are updating the data dictonary tables!!!

stop doing that.

See Connors comments above for how to move the comments properly.

      Rating:
      3
Reader  October 22, 2001
Reviewer:
      Reader  from USA
BTW, to find if there are multiplt tuplets ( in this case obj#,col#), I would
usually, spool the output to a file
(ex: comments.lst), and use the unix
command uniq -c,
%cat comments.lst |uniq -c |sort -nr
This will show the multiple occurrences

hth

          Followup:

well, not that you should every even THINK about updating the sys. tables... but

wouldn't:

select obj#, col#, count(*)
from sys.com$
group obj#, col#
having count(*) > 1;

be a whole lot easier then pulling the data OUT of the database?  The database
is sort of built to do this sort of stuff.

      Rating: 3
DML on
      catalog  October 23, 2001
Reviewer:  Mikito
      Harakiri
Add 'instead of' trigger on 'user_col_comments' that will issue dynamic 'COMMENT
ON COLUMN' statement if you prefer 'insert/delete' on catalog to DDL.

Instead of crying "you must not touch SYS tables", why doesn't oracle simply
disallow anybody to connect as SYS?
SYSTEM would be allowed to read SYS tables but not to update them. That way you
_enforce_ the policy. The database is sort of designed to handle this sort of
stuff.

          Followup:

I'm not crying -- I'm stating fact.  If anyone is so inclined to update the data
dictionary directly -- they are totally on their own.  Period, end of
conversation.

Using that instead of trigger -- not a good idea (you should try things before
suggesting them perhaps?)

ops$tkyte@ORA717DEV.US.ORACLE.COM> create trigger t_trigger
  2  instead of update on sys.user_tab_comments
  3  begin
  4  null;
  5  end;
  6  /
create trigger t_trigger
               *
ERROR at line 1:
ORA-04089: cannot create triggers on objects owned by SYS

SYS is like root.  What you suggest is like saying "instead of crying when root
does an rm -rf /* and wipes out every file in the file system, why doesn't Unix
just disallow anybody to login as root??"

Would not make much sense would it.  If the administrators of the system are so
inclined to destroy their system, there is nothing we can do to stop them --
other then educate them (which is what I'm trying to do here).

      Rating: 5
Manipulating $
      tables  October 25, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
As far as I remember, the only cases when the user "should" interact directly
with the $ tables are:

- Moving the AUD$ table out of the SYSTEM tablespace;

- Exporting/Importing OL$ and OL$HINTS -- in this case these are not even under
SYS, but in the OUTLN schema.

Correct me if I am wrong...

          Followup:

Correct, you MAY do that.  That is supported and supportable.  Moving AUD$ is to
be done with care and the guidance of support.

October 25, 2001 Doug -- Thanks for the question regarding
      "Reordering part of a group by within a group by?", version 8.1.7

      You Asked
Tom - can you help with this?  A developer is looking for a query that groups
information and then sort of reorders parts of within the group later. There's a
table I created (as a test) with some data that makes the case.  I'll explain
just after this what he's looking for - this is just setup.

SQL> create table events (eventid NUMBER, startdate DATE, enddate DATE,
eventtype varchar2(20),description varchar2(100));

Table created.

SQL> insert into events values
(1,to_date('10-16-01','MM-DD-RR')to_date('10-18-01','MM-DD-RR'),'Group
Trade','Update New York Sales Mission');

1 row created.

SQL> insert into events values(2,to_date('10-28-01','MM-DD-RR'),
to_date('10-31-01','MM-DD-RR'),'Group Trade','OMCA Convention');

1 row created.

SQL> insert into events values (3,to_date('10-20-01','MM-DD-RR'),
 to_date('10-21-01','MM-DD-RR'),'Consumer Shows','Showcase Weekend');

1 row created.

SQL> insert into events values (4,to_date('10-26-01','MM-DD-RR'),
 to_date('10-28-01','MM-DD-RR'),'Consumer Shows','Long Island Ski
Shows');

1 row created.

SQL> commit;

Commit complete.

SQL> insert into events values (5,to_Date('11-02-01','MM-DD-RR'),
 to_Date('11-04-01','MM-DD-RR'),'Consumer Shows','Albany Ski Show');

1 row created.

SQL> commit;

Now what he's looking for - is data in this format (using just SQL): (This is
more data than I'm using for the example but we don't need that much for a test
case)

-- - - - - - - - - - --------------------------------------
October 2001
  Group Trade
    Oct. 16-18, Upstate New York Sales Mission (Record as entered into
table above)
    Oct. 28-31, OMCA Convention/Marketplace, Canada

  Consumer Shows
    Oct. 20-21, Showcase Weekend, Belmont Race Track, Long Island
    Oct. 26-28, Long Island Ski Show

November 2001
  Consumer Shows
    Nov. 2-4, Albany Ski Show
    Nov. 9-11, Washington D.C.  Ski Show
    Nov. 15-18 or 19, Cleveland Ski Show

  International Shows
    Nov. 8, Promotions as U.S. Embassy, London
    Nov. 12-15, World Travel Market, London

  ----------------------------------------------------
In other words, grouped by month, and then by the eventtypes containing the
earliest start date of eventtypes in that month and then the descriptions in
alphabetical order.(I assume if they have the same start date).

So I didn't quite get this:
This was my first crack:

select
to_char(startdate,'Month,RRRR'),eventtype,startdate,enddate,description
from events
group by
to_char(startdate,'Month,RRRR'),eventtype,startdate,enddate,description
order by
to_date(to_char(startdate,'Month,RRRR'),'Month,RRRR'),eventtype,startdate,descrip
tion

This gives me something like:

TO_CHAR(STARTD EVENTTYPE            STARTDATE ENDDATE
-------------- -------------------- --------- ---------
DESCRIPTION
----------------------------------------------------------------
October  ,2001 Consumer Shows       20-OCT-01 21-OCT-01
Showcase Weekend

October  ,2001                      26-OCT-01 28-OCT-01
Long Island Ski Shows

October  ,2001 Group Trade          16-OCT-01 18-OCT-01
Update New York Sales Mission

October  ,2001                      28-OCT-01 31-OCT-01
OMCA Convention

November ,2001 Consumer Shows       02-NOV-01 04-NOV-01
Albany Ski Show

The problem is, Group Trade should come first because it has an Oct-16 start
date which is earlier than the Consumer shows that comes out on top (within
October anyway)

So then I tried this:

select to_char(startdate,'Month,RRRR')
A,eventtype,startdate,enddate,description
 from events
group by to_char(startdate,'Month,RRRR')
,eventtype,startdate,enddate,description
order by
to_date(to_char(startdate,'Month,RRRR'),'Month,RRRR'),first_value(eventtype)

over (partition by to_char(startdate,'Month,RRRR') order by startdate
),startdate,description
/

A              EVENTTYPE            STARTDATE ENDDATE
-------------- -------------------- --------- ---------
DESCRIPTION
----------------------------------------------------------------------
October  ,2001 Group Trade          16-OCT-01 18-OCT-01
Update New York Sales Mission

October  ,2001 Consumer Shows       20-OCT-01 21-OCT-01
Showcase Weekend

October  ,2001                      26-OCT-01 28-OCT-01
Long Island Ski Shows

October  ,2001 Group Trade          28-OCT-01 31-OCT-01
OMCA Convention

November ,2001 Consumer Shows       02-NOV-01 04-NOV-01
Albany Ski Show

Not knowing a lot about analytical functions, I just gave it a shot.  This puts
the Group Trade first as it should be, but the other group trade should be
underneath it, rather than under the Consumer Shows, the organization is broken
- I'm actually "closer" with the first attempt.

I hope this makes sense - so it looks like we want to group and order data, but
almost assign criteria about how to order "sub-groups" right in the middle of
what we're doing.  Also, SQL only.

Can you help?

Thanks.

      and we said...
Yes, we can do this.  What you want (need) is:

the startdate truncated down to the month in a sortable fashion (never sort by
to_char(date) unless the format you use is YYYYMMDD or YYYYMMDDHH24MISS --
everything else sorts alphabetically -- april comes before january).

The eventType sorted by startDate for a month.  We'll use a "trick" there,
selecting the MIN( start_date || eventType ) to get that.  We need this to order
by.

The date range.

The description.

We can do this as:
ops$tkyte@ORA717DEV.US.ORACLE.COM> column description format a30
ops$tkyte@ORA717DEV.US.ORACLE.COM> break on month skip 1 on eventType
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select to_char(Month,'Month YYYY') month,
  2         substr( eventType, 9 ) eventType,
  3         when,
  4         description
  5    from ( select trunc(startdate,'Month') Month,
  6                  ( select min(to_char(startDate, 'YYYYMMDD') || eventType)
  7                      from events e2
  8                     where e2.startDate between trunc(e1.startDate,'Month')
  9                             and add_months(trunc(e1.startDate,'Month'),1)
 10                                      -1/24/60/60
 11                       and e2.eventType = e1.eventType
 12                  ) eventType,
 13                  to_char( startDate, 'Mon. DD' ) || '-' ||
 14                               decode( to_char(endDate,'MON'),
 15                                       to_char(startDate,'MON'),
                                                  to_char( endDate, 'DD' ),
 16                                       to_char(endDate, 'Mon. DD' ) ) when,
 17                  description
 18             from events e1
 19            order by 1, 2, 3
 20          )
 21  /

MONTH          EVENTTYPE            WHEN            DESCRIPTION
-------------- -------------------- --------------- ---------------------------
October   2001 Group Trade          Oct. 16-18      Update New York Sales
                                                    Mission
                                    Oct. 28-31      OMCA Convention
                                    Oct. 28-Nov. 01 Tom Added this to test month

                                                    boundary

               Consumer Shows       Oct. 20-21      Showcase Weekend
                                    Oct. 26-28      Long Island Ski Shows

November  2001 Consumer Shows       Nov. 02-04      Albany Ski Show

6 rows selected.

Review &
      Followup

      Rating:
      5
Awesome  October 25, 2001
Reviewer:
      A reader
I love coming to this wonderful place

      Rating: 5
Very
      Impressive  November 16, 2001
Reviewer:
      Doug  from CT, USA
I'm the guy who asked the question - I've been meaning to put aside some time to
learn from this.. phenomenal.. sorry it took so long to indicate my
appreciation.  This query is great and there are some very clever tricks in it.

      Rating: 3
Can I also get
      the months of no events like ...  February 06, 2002

Reviewer:  Vijay Chandra Sekhar Parepalli  from
      India, Hyderabad
This is very good. I also would like to have a month wise report of the
same..the difference I need from what that is given here is that if there are no
events in a particular month, I need to get the same notified by a string like
'No Events' ' for eg: The events are present from January to April excepting
March, I need to get the name of the March Month also reporting that there are
no events in that particular month.

      Rating: 5
can we use
      analytical functions  April 09, 2002
Reviewer:
      A reader
and make it more simple...

Can analytical functions reduce the numbers of lines in this query...

thank you

October 25, 2001 Andre, from Brazil -- Thanks for the question
      regarding "Snapshot too old on snapshots ", version 817

      You Asked
Hi .
I cant understand why the error ORA 1555 can happen on a query that uses just
snapshots.
I am sure that the replication finished as 04:00 am, and i ran the query a few
minutes ago and
happened the the ORA 1555 . Could you explain it ?
Tks.

      and we said...
Do you have my book?  I cover this exact case with examples.  See also:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:895410916429
it demonstrates an ORA-01555 against a table which is in a READ ONLY TABLESPACE
showing how this can happen.

It still boils down to -- you must size the rbs for the size of your longest
running query AS WELL AS the duration of your transactions.  You cannot size RBS
just for inserts/updates/deletes.

Your rbs are too small, wrap too fast and you are seeing the effects of that.
Review &
      Followup

      Rating:
      4
Reader  October 25, 2001
Reviewer:
      Reader  from USA
regarding

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:895410916429
1. In DB buffer pool is there a checkpoint queue besides
   3 data structures LRU chains, Dirty list and Cache
   buffer chains. If not, what would track the 10% limit
   of buffers to be revisited and not wait for delayed
   block clean out
2. In case of delayed block clean out, if process can not
   find the UBA that has been used for the update, what is
   the logic for block to be Upper Commited
3. Is there a guide line to tune fast_start_io_target or
   log_checkpoint_interval in conjunction with buffer
   pool size to alleviate ORA-1555

Thanks

          Followup:

1) there is a session list that is allocated by your session when you do a
transaction.  It is a list of block addresses you modified that will grow to
hold as many block addresses as we need (upto 10% of the buffer cache).  It is
not a copy of the blocks, just a small entry that says you modified block "x"

2) I don't understand what you are saying here.  what is "upper committed"

3) not that I am aware of.  to alleviate ora-1555, size your rbs appropriately.
The problem is with the dirty blocks -- getting dbwr to write them out won't
clean them out any more then letting them sit in the buffer cache would.

      Rating:
      5
Reader  October 25, 2001
Reviewer:
      Reader  from USA
Sorry, I'll try to be clearer

2. "upper bound commit SCN" is the RBS assigns during
   block clean out, which is the earliest possible SCN
   that can be rolled back withou finding the
   actual "commit SCN".

   If a TX tries to consistent read a data block and find
   from the RBS that ITL shows "upper bound commit SCN",
   will TX considers it sufficiently consistent or it
   will error ORA-1555.

   I think it will error ORA-1555 because delayed block
   clean out only releases the locks. Your comments please

3.
<quote>
FAST_START_IO_TARGET (available only with the Oracle Enterprise Edition)
specifies the number of I/Os that should be needed during crash or instance
recovery. It gives you more precise control over the duration of recovery than
DB_BLOCK_MAX_DIRTY_TARGET. When you set this parameter, DBW n writes dirty
buffers out more aggressively
<quote>
range of values : 1000 to all the buffers in cache

Very small value for this parameter will result in fast
recovery time; however it will writes blocks to disk soon
enough to interfere with 10%(buffer pool) value.
would it not?

Thanks

          Followup:

2) you want to get my book.  I go over this.  In any case, a delayed block clean
out doesn't "release locks", a commit does that.  the block clean out -- cleans
out the block (the locks were long ago released).  The cases for the 1555 take
more then a paragraph to answer -- I have to point you to other material.

3) it doesn't matter how fast the blocks are getting to disk -- they are dirty
and dbwr doesn't clean them.  Regardless of whether a process reads the block
from the buffer cache or from disk - the contents would be the same, the
conditions the same.  In fact, having a very small value can increase the
occurence of the 1555, they faster you write them the higher the odds that some
dirty blocks you would have cleaned upon commit will not be in the buffer cache
and you won't be able to clean them.

October 25, 2001 David -- Thanks for the question regarding
      "Viewing fractions of a second in a date field.", version 8i

      You Asked
Hi Tom,

I was wondering, is there any way to look at fractions of a second when
selecting a timestamp date field?  I would presume when one compares two such
fields, using < or >, fractions of a second are used, but can you actually
select the timestamp so as to view the fractions using an Oracle date format?

TIA

David Wison.

      and we said...
In 8i and before, the DATE type has a resolution of 1 second.  There are no
fractional seconds stored.  When using <, >, the comparision is down to the
second.

In 9i, there is a new datatype "timestamp" that supports fractional seconds.
Review &
      Followup

      Rating: 5
"Viewing
      fractions of a second in a date field.", version 8i  October
      25, 2001
Reviewer:  David Wilson  from Toronto

Short, clear and to the point.

October 25, 2001 Vikram -- Thanks for the question regarding
      "Dirty reads...", version 8.1.7

      You Asked
Can I force a session to do dirty reads ?
By setting a parameter in a session or by using a hint in Oracle 8.1.7
like they claim can be done in DB2 ?

Suppose, in some cases I dont care if I get the most recent updated records or
not.

That is, instead of scanning through an undo block, read the Data block directly.

      and we said...
No, dirty reads are not a feature, they are a weak attempt to get around a
limitation.

search for

dirty read

on my site to read about this "feature".  If you feel you have a real need for a
dirty read -- explain to me what you need to do and I'll tell you how to do it.
Dirty reads are not necessary (they are evil).

Review &
      Followup

      Rating: 5
Now I am
      curious ...  October 25, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
Tom, you shouldn't have said that... kidding...

I've never heard you could do that in Oracle.

I'm aware it's a really nasty, "dirty" thing to do.

Suppose I want to know the changing value of my balance in a banking system
during a transaction peformed by another user, between his DMLs.

How to implement it ?

Thanks a lot !

          Followup:

When i said I would show you how to do it -- i didn't mean to do a "dirty read",
what I meant was I would tell you how to accomplish the business objective you
needed to satisfy.  Most of the times, this is coming from people who want to
count the rows their app has loaded so far -- for them, the answer is to stick
some calls to dbms_application_info into their load program.  Not only can they
monitor the load progress this way -- its INFINITELY faster since they don't
actually have to count the rows!

In your case, you would get the WRONG answer -- you would get an answer that
NEVER existed at any point in TIME if you did a dirty read!!

Lets say that other transaction was moving $500 from savings to checking.  So
you issue: "select sum(bal) from accounts where account_owner = 'TOM'".

You read the checking balance, they update the saving account and decrement
$500, you now read the savings (dirty read) -- you report back that you have 500
less dollars then you EVER had -- ever.  In this case, movement of money between
accounts will result in your getting totally erroneous answers.

Your balance has not changed until they commit or rollback.  This is a bad
example.  Do you have a case where you really believe you need a dirty read?

      Rating: 5
Continuing with
      the followup...   October 25, 2001
Reviewer:
      Andre Whittick Nasser  from Rio de Janeiro, Brazil
Very interesting... thanks for the attention and sorry for my "sick" curiosity,
I must admit.

But... carrying on with the banking system example...

Let us suppose that I, as a bank employee, want to track and hunt down each
atomic DML operation in the transaction you just mentioned via dirty reads.

Just to emphisize: This would, as you like, be an extreme, atypical,
speculative, philosophical and metaphysical example. Say... for auditing
purposes.

Transaction:
1) Subtract 500 from my savings account;
2) Add 500 to my checking account.

I imagine using something like LogMiner, or value based-auditing (through
triggers) to implement this mechanism.

Maybe the problem with LogMiner is that I will only have an after image of the
modifications, because I cannot use it "on the fly". That is, I cannot track the
changes ONLINE like that, but with triggers I could set up some "dynamic" change
tracking.

Is my line of thought ok ?

          Followup:

As a bank employee -- things would be happening so fast, you could not.  To you
-- it wouldn't matter whether you got dirty reads or not since things are
happening SO fast (bank transactions are tiny, fast, furious).

This would not give you auditing at all -- it would give you an instant,
incorrect, view of the database.  You could not use this as any part of an
"audit" trail at all.

If you wanted to track down each atomic DML operation and see the before and
after effects of it -- Log Miner does that (and more).  It could be useful for
auditing (especially in 9i) since it records everything.  its not a poke in the
dark like a dirty read would be.

So, in short, I disagree with your thought since a bank employee cannot be fast
enough (nor would any piece of software) to use a dirty read to "audit" (it
would have to be looking everywhere all of the time at everything -- every bit
and byte in the database).

A trigger can do this.
Auditing can do this.
Log miner post-facto can do this. (and audit analysis is pretty much always
post-facto).

Those would be the solutions to this problem, NOT a dirty read.

      Rating: 5
Continuing with
      the followup...   October 25, 2001
Reviewer:
      Andre Whittick Nasser  from Rio de Janeiro, Brazil
Very interesting... thanks for the attention and sorry for my "sick" curiosity,
I must admit.

But... carrying on with the banking system example...

Let us suppose that I, as a bank employee, want to track and hunt down each
atomic DML operation in the transaction you just mentioned via dirty reads.

Just to emphisize: This would, as you like, be an extreme, atypical,
speculative, philosophical and metaphysical example. Say... for auditing
purposes.

Transaction:
1) Subtract 500 from my savings account;
2) Add 500 to my checking account.

I imagine using something like LogMiner, or value based-auditing (through
triggers) to implement this mechanism.

Maybe the problem with LogMiner is that I will only have an after image of the
modifications, because I cannot use it "on the fly". That is, I cannot track the
changes ONLINE like that, but with triggers I could set up some "dynamic" change
tracking.

Is my line of thought ok ?

      Rating: 5
Now I
      see...  October 25, 2001
Reviewer:  Andre
      Whitick Nasser  from Rio de Janeiro, Brazil
Sorry Tom,

Only now did I understand that the problem is not knowing that the other
transaction performed a DML operation, but WHEN it might have ocurred.

You can never tell.

If you use LogMiner, for example, you see each entry with timestamp, user, etc.

When you do a dirty read, you don't know whether the DML op was done or not.

I think this is it !

October 25, 2001 Jeff -- Thanks for the question regarding "How to
      display word size?", version 8.1.6.0.0

      You Asked
Is there a way to display what word size is being used?  If I go
into a shop with databases already installed, how do I tell if
8.1.6 is running 32-bit or 64-bit?

Thanks!
-jw

      and we said...
Well, it should be in the sqlplus banner:

SQL*Plus: Release 8.0.5.0.0 - Production on Fri May 19 14:58:14
2000
(c) Copyright 1998 Oracle Corporation.  All rights reserved.
Connected to:
Oracle8 Enterprise Edition Release 8.0.5.2.1 64bit -
Production
With the Partitioning and Objects options
PL/SQL Release 8.0.5.2.0 - Production

SQL*Plus: Release 8.1.5.0.0 - Production on Wed Apr 5 11:08:44
2000

(c) Copyright 1999 Oracle Corporation.  All rights reserved.
Connected to:
Oracle8i Enterprise Edition Release 8.1.5.0.0, 64-bit -
Production
With the Partitioning and Java options
PL/SQL Release 8.1.5.0.0 - Production

but a select on v$type_size would probably clue us in as well
(this is on 32bit):

sys@8i> select * from v$type_size;

COMPONEN TYPE     DESCRIPTION                       TYPE_SIZE
-------- -------- -------------------------------- ----------
S        EWORD    EITHER WORD                               4
S        EB1      EITHER BYTE 1                             1
S        EB2      EITHER BYTE 2                             2
S        EB4      EITHER BYTE 4                             4
S        UWORD    UNSIGNED WORD                             4
S        UB1      UNSIGNED BYTE 1                           1
S        UB2      UNSIGNED BYTE 2                           2
S        UB4      UNSIGNED BYTE 4                           4
S        SWORD    SIGNED WORD                               4
S        SB1      SIGNED BYTE 1                             1
S        SB2      SIGNED BYTE 2                             2
S        SB4      SIGNED BYTE 4                             4
S        BOOLEAN  BOOLEAN                                   4
S        FLOAT    FLOAT                                     4
S        DOUBLE   DOUBLE                                    8
S        SIZE_T   SIZE_T                                    4
S        PTR_T    PTR_T                                     4
K        KDBA     DATABASE BLOCK ADDRESS                    4
K        KTNO     TABLE NUMBER IN CLUSTER                   1
K        KSCN     SYSTEM COMMIT NUMBER                      8
K        KXID     TRANSACTION ID                            8
K        KUBA     UNDO ADDRESS                              8
KCB      KCBH     BLOCK COMMON HEADER                      20
KTB      KTBIT    TRANSACTION VARIABLE HEADER              24
KTB      KTBBH    TRANSACTION FIXED HEADER                 48
KDB      KDBH     DATA HEADER                              14
KDB      KDBT     TABLE DIRECTORY ENTRY                     4
KTE      KTECT    EXTENT CONTROL                           44
KTE      KTECH    EXTENT CONTROL                           72
KTE      KTETB    EXTENT TABLE                              8
KTS      KTSHC    SEGMENT HEADER                            8
KTS      KTSFS    SEGMENT FREE SPACE LIST                  20
KTU      KTUBH    UNDO HEADER                              16
KTU      KTUXE    UNDO TRANSACTION ENTRY                   40
KTU      KTUXC    UNDO TRANSACTION CONTROL                104
KDX      KDXCO    INDEX HEADER                             16
KDX      KDXLE    INDEX LEAF HEADER                        32
KDX      KDXBR    INDEX BRANCH HEADER                      24

38 rows selected.

Review &
      Followup

      Rating: 1
32 or 64-bit
      ?  September 13, 2001
Reviewer:  Neil
      McLaughlin  from UK
Not all banners display this information. What are you supposed to look at in
v$type_size to determine the architecture?

          Followup:

stand corrected on that....

      Rating: 3
32 or 64
      bit  September 13, 2001
Reviewer:  fz
       from NJ, USA
My database1 with 32-bit (confirmed by sqlplus banner) and database2 with 64-bit
(confirmed by banner) both give that eword has type_size=4.

On the other hand, we can find out if 32 or 64 bit by:
file $ORACLE_HOME/bin/oracle

          Followup:

I don't have a 64bit instance at my disposal right now -- someone care to post
the output of v$type_size in total here?

      Rating: 3
32 or 64
      bit  September 13, 2001
Reviewer:  fz
       from NJ. USA
Here is what from my db:

SQL*Plus: Release 8.1.6.0.0 - Production on Thu Sep 13 11:27:22 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Enter password:

Connected to:
Oracle8i Enterprise Edition Release 8.1.6.0.0, 64 bit - Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production

SQL> select * from v$type_size;

COMPONEN TYPE     DESCRIPTION                         TYPE_SIZE
-------- -------- -------------------------------- ------------
S        EWORD    EITHER WORD                                 4
S        EB1      EITHER BYTE 1                               1
S        EB2      EITHER BYTE 2                               2
S        EB4      EITHER BYTE 4                               4
S        UWORD    UNSIGNED WORD                               4
S        UB1      UNSIGNED BYTE 1                             1
S        UB2      UNSIGNED BYTE 2                             2
S        UB4      UNSIGNED BYTE 4                             4
S        SWORD    SIGNED WORD                                 4
S        SB1      SIGNED BYTE 1                               1
S        SB2      SIGNED BYTE 2                               2
S        SB4      SIGNED BYTE 4                               4
S        BOOLEAN  BOOLEAN                                     4
S        FLOAT    FLOAT                                       4
S        DOUBLE   DOUBLE                                      8
S        SIZE_T   SIZE_T                                      8
S        PTR_T    PTR_T                                       8
K        KDBA     DATABASE BLOCK ADDRESS                      4
K        KTNO     TABLE NUMBER IN CLUSTER                     1
K        KSCN     SYSTEM COMMIT NUMBER                        8
K        KXID     TRANSACTION ID                              8
K        KUBA     UNDO ADDRESS                                8
KCB      KCBH     BLOCK COMMON HEADER                        20
KTB      KTBIT    TRANSACTION VARIABLE HEADER                24
KTB      KTBBH    TRANSACTION FIXED HEADER                   48
KDB      KDBH     DATA HEADER                                14
KDB      KDBT     TABLE DIRECTORY ENTRY                       4
KTE      KTECT    EXTENT CONTROL                             44
KTE      KTECH    EXTENT CONTROL                             72
KTE      KTETB    EXTENT TABLE                                8
KTS      KTSHC    SEGMENT HEADER                              8
KTS      KTSFS    SEGMENT FREE SPACE LIST                    20
KTU      KTUBH    UNDO HEADER                                16
KTU      KTUXE    UNDO TRANSACTION ENTRY                     40
KTU      KTUXC    UNDO TRANSACTION CONTROL                  104
KDX      KDXCO    INDEX HEADER                               16
KDX      KDXLE    INDEX LEAF HEADER                          32
KDX      KDXBR    INDEX BRANCH HEADER                        24

38 rows selected.

          Followup:

Ok, here is a way to do this on Unix ports:

$ cd $ORACLE_HOME/bin
$ file oracle

That should tell you whether it is a 64 or 32 bit executable.

      Rating:
      2
Reader  September 14, 2001
Reviewer:
      Chirag  from India
my sql plus can't show me 64bit - Production

so its run on 32 bit ?

SQL*Plus: Release 8.0.6.0.0 - Production on Fri Sep 14 15:32:21 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to:
Oracle8i Enterprise Edition Release 8.1.6.0.0 - Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production

SQL> select * from v$type_size;

COMPONEN TYPE     DESCRIPTION                      TYPE_SIZE
-------- -------- -------------------------------- ---------
S        EWORD    EITHER WORD                              4
S        EB1      EITHER BYTE 1                            1
S        EB2      EITHER BYTE 2                            2
S        EB4      EITHER BYTE 4                            4
S        UWORD    UNSIGNED WORD                            4
S        UB1      UNSIGNED BYTE 1                          1
S        UB2      UNSIGNED BYTE 2                          2
S        UB4      UNSIGNED BYTE 4                          4
S        SWORD    SIGNED WORD                              4
S        SB1      SIGNED BYTE 1                            1
S        SB2      SIGNED BYTE 2                            2
S        SB4      SIGNED BYTE 4                            4
S        BOOLEAN  BOOLEAN                                  4
S        FLOAT    FLOAT                                    4
S        DOUBLE   DOUBLE                                   8
S        SIZE_T   SIZE_T                                   4
S        PTR_T    PTR_T                                    4
K        KDBA     DATABASE BLOCK ADDRESS                   4
K        KTNO     TABLE NUMBER IN CLUSTER                  1
K        KSCN     SYSTEM COMMIT NUMBER                     8
K        KXID     TRANSACTION ID                           8

COMPONEN TYPE     DESCRIPTION                      TYPE_SIZE
-------- -------- -------------------------------- ---------
K        KUBA     UNDO ADDRESS                             8
KCB      KCBH     BLOCK COMMON HEADER                     20
KTB      KTBIT    TRANSACTION VARIABLE HEADER             24
KTB      KTBBH    TRANSACTION FIXED HEADER                48
KDB      KDBH     DATA HEADER                             14
KDB      KDBT     TABLE DIRECTORY ENTRY                    4
KTE      KTECT    EXTENT CONTROL                          44
KTE      KTECH    EXTENT CONTROL                          72
KTE      KTETB    EXTENT TABLE                             8
KTS      KTSHC    SEGMENT HEADER                           8
KTS      KTSFS    SEGMENT FREE SPACE LIST                 20
KTU      KTUBH    UNDO HEADER                             16
KTU      KTUXE    UNDO TRANSACTION ENTRY                  40
KTU      KTUXC    UNDO TRANSACTION CONTROL               104
KDX      KDXCO    INDEX HEADER                            16
KDX      KDXLE    INDEX LEAF HEADER                       32
KDX      KDXBR    INDEX BRANCH HEADER                     24

38 rows selected.

SQL>

          Followup:

See the comment above, goto the oracle home for the database and issue:

file oracle

and see what it says.

      Rating:
      2
  September 16, 2001
Reviewer:
      lamriN  from Qatar
My oracle 816 server is on Windows NT4 pc.

Sqlplus bannar shown as follows:

SQL*Plus: Release 8.0.6.0.0 - Production on Thu Sep 16 11:21:38 1999

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to:
Oracle8i Enterprise Edition Release 8.1.6.0.0 - Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production

Then i found oracle.exe file at oraclehome\bin.
c:\>oracle
Hit any key to exit server: l

c:\>

Here also i didn't get any info regarding 32/64 bit.

Hope that 'file oracle' is unix command. How can i check the same in NT?.

Please enlighten us.

          Followup:

thats easy.  NT = 32bit.  64bit coming in the future but right now, you have
32bit.

      Rating: 3
It doesn't work
      in Compaq digital Unix  October 25, 2001
Reviewer:
      Lucy  from NY, USA
I have Oracle 8.1.6.0.0 installed in Compaq Tru64 Unix, the sqlplus doesn't tell
me anything about the 32 or 64 bits, when I do "file oracle", it shows me
$ file oracle
oracle: COFF format alpha dynamically linked, demand paged setuid executable or
object module not stripped - version 3.13-12

Nothing there neither, how can I find out my db is 32 or 64 bits?

Thanks

          Followup:

Oracle software running on Compaq Tru64 is always 64-bits software.
The data returned by server manager or file oracle will not show info about
64-bits.

      Rating: 3
HP Unix and
      Oracle 8.1.7  October 25, 2001
Reviewer:  Sanjay
      Raj  from USA
I tried running
$file oracle
and this is what I go

$ file oracle
oracle:         PA-RISC1.1 shared executable dynamically linked -not stripped

It still does not show 32 or 64 bit??

          Followup:

Two ways:

1. Go to the Installer and check the file $ORACLE_HOME/orainst/README.FIRST.

2. Type the following:

file oracle

If ELF-64 format is returned, the installed Oracle is the 64-bit release.

(you have 32bit)

      Rating: 2
As far I
      know...  October 25, 2001
Reviewer:  Harri
       from Finland
32bit is never mentioned in banners and only sometimes in file-command output.
64 bit is mentioned always in banner but not necessarily by file-command if OS
and oracle are always 64bit in that environment(like True64 Unix).

Examples:

True64Unix, 64bit os, 64bit oracle (always)
Oracle7 Server Release 7.3.4.5.0 with the 64-bit option - Production
$ file oracle
oracle: COFF format alpha demand paged setuid setgid executable or object module
not stripped - version 3.11-10
---
Solaris8, 64bit os, 32bit oracle:
Oracle9i Enterprise Edition Release 9.0.1.1.0 - Production
$ file oracle
oracle:         ELF 32-bit MSB executable SPARC Version 1, dynamically linked,
not stripped
---
HP-UX 11, 64bit os, 32bit oracle:
Oracle7 Server Release 7.3.4.4.0 - Production
$ file oracle
oracle:         PA-RISC1.1 shared executable dynamically linked -not stripped
--
Solaris8, 64bit os, 64bit oracle:
Oracle8i Enterprise Edition Release 8.1.6.1.0 - 64bit Production
$ file oracle
oracle:         ELF 64-bit MSB executable SPARCV9 Version 1, dynamically linked,
not stripped

October 25, 2001 Alex -- Thanks for the question regarding
      "Problems with import of repository objects dump", version Designer 6i

      You Asked
Dear Tom.
I'm trying to import into Designer6i (with repository object
Navigator) repository objects dump which was created in
Designer6.0, but exp utility was from 8i client (I think I have
tried exp utilities of all possible versions).
I'm getting error message CDI-22582
and this error log file of imp:

---------------------------------
Connected to: Oracle8i Enterprise Edition Release 8.1.6.1.0 -
Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production

Export file created by EXPORT:V08.01.06 via conventional path
import done in CL8MSWIN1251 character set and CL8KOI8R NCHAR
character set
import server uses CL8KOI8R character set (possible charset
conversion)
export server uses CL8MSWIN1251 NCHAR character set (possible
ncharset conversion)
. importing DESPB's objects into DESPB
IMP-00033: Warning: Table "XTSYS_EXPORT_OBJECTS" not found in
export file
IMP-00033: Warning: Table "XTSYS_IMPORT_IRID_MAPPING" not found
in export file
IMP-00033: Warning: Table "XTSYS_IMPORT_IVID_MAPPING" not found
in export file
IMP-00033: Warning: Table "XTSYS_TABS_EXPORTED" not found in
export file
IMP-00033: Warning: Table "XTSYS_RM$REPOSITORIES" not found in
export file
Import terminated successfully with warnings.

------------------------------------------

I must say I am quite new to Designer.
What am I doing wrong?

Thank you.

Sincerely yours, Alex.

      and we said...
From Designer 6.0 to 6i, applications are migrated, not
upgraded.  The data model from 6.0 to 6i is so different, that
only a 6.0 to 6i migration with both versions up and running was
practical.  The significant advancement in functionality related
to Oracle Repository (now the foundation for Designer) which
includes the new advanced SCM/Versioning capabilities is one
reason there is such a change in the repository structure.  The
old-style option for upgrading applications is not available
when moving to 6i.

The following is an excerpt from the Designer6i installation
manual.

To use a repository from a release of Oracle Designer earlier
than 6i, you must migrate the data in it from a live Release
2.1.2 or Release 6.0 repository (this is the "source
repository") into a Release 6i repository that you have already
created (this is the "target repository").

Pre-1.3.2 repositories must initially be upgraded to 1.3.2, then
to 6.0, then migrated to 6i. 1.3.2 or 2.1 or 2.1.1 repositories
must be upgraded to 6.0, then migrated to 6i.  2.1.2 or 6.0
repositories may be migrated directly to 6i.

Review &
      Followup

      Rating:
      3
  September 26, 2001
Reviewer:
      A reader
Hi Tom
I am trying to import from a database(817, WE8ISO8859P1) on NT to a database
(817 US7ASCII) on unix.
I am getting the same error.
Export file created by EXPORT:V08.01.07 via conventional path
import done in US7ASCII character set and US7ASCII NCHAR character set
export client uses WE8ISO8859P1 character set (possible charset conversion)
export server uses WE8ISO8859P1 NCHAR character set (possible ncharset conversio
n)
IMP-00033: Warning: Table "S_LOC" not found in export file

WHen I try to do a show=Y with indexfile option , I see the table is out there ,
but my import is failing . Any Clues what might be wrong?
Thanks

      Rating: 5
Very very
      thanks Dear Tom.  October 25, 2001
Reviewer:
      Alaa Abou El Reigal  from Egypt-Cairo
Dear Tom.

Its 1 time I visit your site its A WOANDERFULL
put may u pls tell me how I aske a Quit. if i wana do so
Thanks Alot
Alaa Reigal

          Followup:

I need to add a page about this I guess.

I'm one guy.  I take about 20/30 questions a day when I'm taking them (my
average is 18 a day for the last 22months -- every day).

I answer every one (if you don't here from me, you typed your email in wrong in
all probability).

I like to answer them in a timely fashion.  Hence I take them 10 at a time and
then it shuts off.  I usually do a set in the morning, I do a set in the
afternoon, I do a set before I go home.  I live on the east coast of the US so
the times are relative to that.  Sometimes, I do another set (like tonight) at
home.  So, the best time to ask are 9am, 1pm, 5pm and 10pm east coast time
(GMT-5).

When I'm taking them, the link is available on
http://asktom.oracle.com/
When I'm not, the link just isn't anywhere (and don't try to bookmark the submit
question -- that won't work)

      Rating: 5
Delete
      workArea  July 28, 2003
Reviewer:  Atul
       from India
Hi Tom,

I have create a work-area in designer 6i also created containers in the
work-area and imported some objects in this work area..

Now i want to drop this work area and create new one..
While deleteing and after creating new work-area..
Objects still refers to old work-area..

How to completely drop work-area??

Thanks,
Atul

October 25, 2001 Jeffrey -- Thanks for the question regarding
      "Conversion of image types", version 8.1.6

      You Asked
Is there a way in which I can insert an image to the database in one specific
format? What I want to do is convert a TIFF image into a JPG image previously to
the insert. This, because I plan to read the file from the database and display
it in a browser. Is there a way way in which I can achieve this without using a
third party software?

      and we said...
see

http://technet.oracle.com/doc/oracle8i_816/inter.816/index.htm
and read about the interMedia Audio, Image and Video stuff.  The intermedia
image capabilities include this image format conversion in the database.
Review &
      Followup

      Rating: 4
Exactly what I
      needed  November 02, 2001
Reviewer:  Jeffrey
      Castro  from Honduras
This was exactly what I needed. Documentation and examples.

October 26, 2001 Keith -- Thanks for the question regarding
      "Performance tuning with where statement", version 8i

      You Asked
I have been looking fro documentation on which statement within the WHERE clause
is executed first within any SQL Statement.  As you know - depening on which one
is executed would tell users which of the high degrees of complexity to use
first.  For example,

Select name, address, email
FROM USER_PROFILE
WHERE NAME like 'K%' AND
      USER_ID > 100 ;

In this case the user id is the primary key and would be indexed rather than the
name which is just a regular varchar2 field.  If the second statement within the
WHERE clause is executed first - then the statement would go faster than if the
first statement was executed.

Can you please let me know what you think.
Thank you - Keith

      and we said...
I think -- this is the job of the optimizer!

The order of evaluation of the where clause in a SQL statment is purposely
"undefined".  We can (and in fact do) change the order of evaluation whenever we
feel like it.

The optimizer looks at the predicate, analyzes the available access paths,
chooses the appropriate indexes and executes the query.  You just write the
query, it does the rest.

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1299201885045
for example -- there is a query that depending on the optimizer mode and
settings evaluates the predicate differently.

So, just put them in any order, the optimizer will take care of the rest.  This
is true for the CBO (which is the only mode you should be running in in 8i).
With the RBO, there is occasionally some advantage to putting the most selective
predicates LAST.

Review &
      Followup

      Rating: 4
Right
      Indexes  October 25, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
Would you comment on what indexes would be appropriate to set up to improve
performance in the statement above ?

How would composite indexes work in this case ?

Can you give some examples ?

Thanks again !

          Followup:

Well, it depends on the skew of the data of course.  Looking at the predicate we
have:

name like 'K%' and user_id > 100;

An index on any of

name
user_id
name, user_id
user_id, name

would/could be used.  However, if a large pct of the rows in this table
satisfied "user_id > 100", the indexes with user_id on the leading edge are not
very efficient.  Same would hold true for "name like 'K%'".

Only if one of the two was selective would it be efficient, and then that column
should be on the leading edge in this case (it is NOT true that the most
selective items should be on the leading edge in general!!!)

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t1
  2  as
  3  select object_name name, object_id user_id, created from all_objects
  4  /

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create index t1_idx1 on t1(name,user_id);

Index created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create index t1_idx2 on t1(user_id,name);

Index created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t2
  2  as
  3  select decode( mod(rownum,2), 0, 'K', 'A' ) || substr(name,2) name,
  4             200-user_id user_id,
  5             created
  6    from t1
  7  /

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create index t2_idx1 on t2(name,user_id);

Index created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create index t2_idx2 on t2(user_id,name);

Index created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select sum( case when name like 'K%' then 1
else 0 end ) K_cnt,
  2             sum( case when user_id > 100  then 1 else 0 end ) hundred_cnt,
  3             count(*) cnt
  4    from t1
  5  /

     K_CNT HUNDRED_CNT        CNT
---------- ----------- ----------
        12       16871      16965

ops$tkyte@ORA717DEV.US.ORACLE.COM> select sum( case when name like 'K%' then 1
else 0 end ) K_cnt,
  2             sum( case when user_id > 100  then 1 else 0 end ) hundred_cnt,
  3             count(*) cnt
  4    from t2
  5  /

     K_CNT HUNDRED_CNT        CNT
---------- ----------- ----------
      8482          93      16965

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> alter session set sql_trace=true;

Session altered.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select /*+ index( t1 t1_idx1 ) */
count(created)
  2    from t1
  3   where name like 'K%' and user_id > 100;

COUNT(CREATED)
--------------
            12

ops$tkyte@ORA717DEV.US.ORACLE.COM> select /*+ index( t1 t1_idx2 ) */
count(created)
  2    from t1
  3   where name like 'K%' and user_id > 100;

COUNT(CREATED)
--------------
            12

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select /*+ index( t2 t2_idx1 ) */
count(created)
  2    from t2
  3   where name like 'K%' and user_id > 100;

COUNT(CREATED)
--------------
            38

ops$tkyte@ORA717DEV.US.ORACLE.COM> select /*+ index( t2 t2_idx2 ) */
count(created)
  2    from t2
  3   where name like 'K%' and user_id > 100;

COUNT(CREATED)
--------------
            38

Now, tkprof will show us:

select /*+ index( t1 t1_idx1 ) */ count(created)
  from t1
 where name like 'K%' and user_id > 100

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0          2          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.01          0          2          0           1

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
     12   INDEX RANGE SCAN (object id 21913)

********************************************************************************

select /*+ index( t1 t1_idx2 ) */ count(created)
  from t1
 where name like 'K%' and user_id > 100

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.06       0.09         95         96          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.07       0.09         95         96          0           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 52

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
     12   INDEX RANGE SCAN (object id 21914)

Here, name is very selective (12 out of 17,000 start with K). So, when we use
the index on (NAME,USER_ID), we do very very little IO.  It is very fast to
identify the rows where name starts with K, look to see if the user_id is > 100
and then access the table using t1_idx1.

Now, when we use t1_idx2, we see it is somewhat (lots) less efficient.  USER_ID
is not very selective when it comes to the predicate "user_id > 100".  Virtually
EVERY row satisfies that -- hence we end up reading the entire index in this
case.  We get the same answer, we just had to do 45 times the work

Onto the next case...

select /*+ index( t2 t2_idx1 ) */ count(created)
  from t2
 where name like 'K%' and user_id > 100

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.03       0.03          0         51          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.04       0.03          0         51          0           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 52

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
     38   INDEX RANGE SCAN (object id 21916)

********************************************************************************

select /*+ index( t2 t2_idx2 ) */ count(created)
  from t2
 where name like 'K%' and user_id > 100

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          2          3          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.00          2          3          0           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 52

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
     38   INDEX RANGE SCAN (object id 21917)

Reversing the selectivity of the data (with regards to this particular
predicate) reverses the situation.  When name like 'K%' is not very selective
(we made about 1/2 of the rows start with K), we find we do more work then the
other query.  Its simply the converse

So, what did we learn from this?  Actually not as much as you think.  We learned
that for this SPECIFIC PREDICATE we could over analyze the data and come up with
the perfect index.  However, this is not the only predicate we must be concerned
with, there will be others.  You really have to look at all of the questions you
will be asking of this table to figure out the proper indexing scheme.

      Rating: 5
Perfect !!! Too
      bad I cannot rate you 10  October 26, 2001

Reviewer:  Andre Whittick Nasser  from Rio de
      Janeiro, Brazil
Brilliant explanation!

Being more of a production, nuts-and-bolts guy, I am sometimes somewhat confused
as to this kind of subtleness.

No doubt I will bookmark this page !

Thanks a lot !

      Rating:
      3
  October 26, 2001
Reviewer:  Denis
      Quinn  from Ottawa, Canada
Tom,  I know this is not the place to ask questions, but...
Where do I go to ask a question??
I can't find any place to ask a question on your site.

Thank you

      Rating: 5
excellent!!! --
      but when to go for bitmap indexes  October 26, 2001

Reviewer:  nk  from india
that is a brilliant answer!!!

i also heard about bitmap indexes..
can you tell me with an example when to go for bit map indexes and their benefit
over
normal indexes

          Followup:

Even better, I can point you to two references

http://technet.oracle.com/doc/oracle8i_816/server.816/a76994/indexes.htm#97322
and my book -- click through on

http://asktom.oracle.com/
both cover this topic in detail.

      Rating: 4
Great
      explanation Tom :)  November 14, 2002
Reviewer:
      Chris
Thx it give me enlighment on indexing policy...:)

October 26, 2001 lok -- Thanks for the question regarding "SQLPLUS
      Report with compute sum function", version 8.1.6

      You Asked
Dear tom,

i am working with SQLPLUS for generating report. Now, i am facing a
problem with the command "Compute sum".

My report format is as below:

ItemGroup Purchase Val.  Closing Stock Val. Sales Val.  Stock Ratio
--------- -------------- ------------------ ----------- ------------
A1        500            1000               10000       0.1
A2        100            200                500         0.4

Total     600            1200               10500       0.5

The formula for stock ratio is : closing stock value/sales value

For the report total, i was using compute sum. But for the stock ratio total,
how can i make it to become 1200/10500 instead of summing up of 0.1 and 0.4?

I hope you can understand what i am asking.

Thx for u in advance first.

Lok

      and we said...
Instead of using SQLPlus to compute -- use SQL:

scott@ORA717DEV.US.ORACLE.COM> create table t ( itemgroup varchar2(5),
purchase_val number,
  2                   close_stock_val number, sales_val number );

Table created.

scott@ORA717DEV.US.ORACLE.COM>
scott@ORA717DEV.US.ORACLE.COM> insert into t values ( 'A1', 500, 1000, 10000 );

1 row created.

scott@ORA717DEV.US.ORACLE.COM> insert into t values ( 'A2', 100, 200, 500 );

1 row created.

scott@ORA717DEV.US.ORACLE.COM>
scott@ORA717DEV.US.ORACLE.COM>
scott@ORA717DEV.US.ORACLE.COM> select
  2   decode( grouping(itemgroup), 1, 'Total:', ItemGroup ) Itemgroup,
  3   sum(purchase_val) "purchase val",
  4   sum(close_stock_val) "close val",
  5   sum(sales_val) "sales val",
  6   sum(close_stock_val)/sum(sales_val) "ratio"
  7    from t
  8   group by rollup( itemgroup );

ITEMGR purchase val  close val  sales val      ratio
------ ------------ ---------- ---------- ----------
A1              500       1000      10000         .1
A2              100        200        500         .4
Total:          600       1200      10500 .114285714

the group by rollup can do this for us.
Review &
      Followup

      Rating: 5
SQLPLUS Report
      with compute sum function  November 15, 2001

Reviewer:  Patty O'Rourke  from Cumberland, RI USA

This is EXACTLY what I was having trouble doing!

THANKS!

October 26, 2001 William -- Thanks for the question regarding
      "dbms_obfuscation_toolkit.desencrypt", version 8.1.7.0

      You Asked
I was wondering if you would be kind enough to elaborate on the following three
questions.

1. Do you happen to know what MODE the procedure uses such as ECB, CFB, or OFB?
2. Do you happen to know what initialization vector the procedure uses or does
the function use the ECB mode which does not require one?
3. Has the procedure been certified against the DES standard?

Thanks in advance.

      and we said...
I didn't but I know the guy who wrote it so.... I asked him and he says:

1. The procedure uses CBC mode.
2. The IV is fixed.
3. The procedure uses the DES algorithm and, thus, complies with the standard.

Review &
      Followup

      Rating:
      5
  October 26, 2001
Reviewer:
      A reader
Can you explian about CBC ,DES  etc stff?
what does it mean

Thanks

          Followup:

search google for ecb cfb ofb

DES is the data encryption standard.  ecb et. al. are algorithms you can use
with it.

October 27, 2001 Om -- Thanks for the question regarding "About
      remove constant", version 8.1.6

      You Asked
Hi Tom,

Thanks very much for the quick response.

I wonder if I could have a chat with you that would have solved
our problem with in few seconds.I really hope some day you will
introduce chat feature also in your ( THE MOST IMPORTANT SITE
FOR ALL DBA's) site.

Refering to the ORACLE ERROR 0RA 04031 and fragmentation and your
function and making the idea of making use of triggers to pin
the objects.

As You said We should always make use of bind variables as it
executes faster as compare to the statements where we do not
make use of bind variables.

Q1) Can you please take a more specific example as how a statement can be
altered to make use of bind variable.

Q2) I made use of

SELECT SQL_TEXT FROM V$SQLAREA WHERE ROWNUM < 5

to get few samples for you

These are as follows

  UPDATE   CNST_QUEUE   SET      PROCESS = -1     ,USER_ID =
 'A101675'     ,DATE_QUEUED = sysdate  WHERE      AWB_PREFIX
 = '125'  AND      AWB_NUMBER  = 67557405  AND      AWB_SUFF
IX  = '  '  AND      PROCESS = 1 AND      USER_ID = 'A101675
'

  UPDATE   CNST_QUEUE   SET      PROCESS = -1     ,USER_ID =
 'A101675'     ,DATE_QUEUED = sysdate  WHERE      AWB_PREFIX
 = '125'  AND      AWB_NUMBER  = 68221156  AND      AWB_SUFF
IX  = '  '  AND      PROCESS = 1 AND      USER_ID = 'A101675
'

  UPDATE   CNST_QUEUE   SET      PROCESS = -1     ,USER_ID =
 'A105722'     ,DATE_QUEUED = sysdate  WHERE      AWB_PREFIX
 = '125'  AND      AWB_NUMBER  = 67557405  AND      AWB_SUFF
IX  = 'A '  AND      PROCESS = 1 AND      USER_ID = 'A105722
'

  UPDATE   CNST_QUEUE   SET      PROCESS = -1     ,USER_ID =
 'A105722'     ,DATE_QUEUED = sysdate  WHERE      AWB_PREFIX
 = '125'  AND      AWB_NUMBER  = 67557416  AND      AWB_SUFF

SQL_TEXT
------------------------------------------------------------
IX  = '  '  AND      PROCESS = 1 AND      USER_ID = 'A105722

How can I Introduce bind variables in these statements ?

I may be sending a wrong SAMPLE as I feel I should apply
your remove constant function and then send few SQL statements
I will be doing that after posting this to you.

Just saw that you can accept Questions and I thought let me
not waste any more time and grab some more Info from you.

Warm Regards,
Om

      and we said...
q1) In your case -- you are NOT using bind variables (i recommend you get my
book if you can.  I cover this topic literally to death in there proving time
and time and time again their importance)

Taking your update statement here:

 UPDATE   CNST_QUEUE   SET      PROCESS = -1     ,USER_ID =
 'A101675'     ,DATE_QUEUED = sysdate  WHERE      AWB_PREFIX
 = '125'  AND      AWB_NUMBER  = 67557405  AND      AWB_SUFF
IX  = '  '  AND      PROCESS = 1 AND      USER_ID = 'A101675
'

that SHOULD (must be) recoded in the application to be:

update cnst_queue set process = :b1, user_id = :b2, date_queued = sysdate,
 where awb_prefix = :b3
   and awb_number = :b4
   and awb_suffix = :b5
   and awb_process = :b6
   and user_id = :b7;

and bind in those values.  How you do that differs from language to language and
environment to environment but they ALL support it.  You MUST do this.

I can assure you that at least 90% of your database execution time is spent
PARSING and OPTIMIZING that update -- 10% is spent actually DOING it.  If you
use bind variables -- very little time will be spent parsing (you can get that
statement to execute in 1/10 of the time).  Not only that -- but the concurrency
and scalability of your database will go WAY up.

This is the root cause of your issues, this must be fixed -- no questions about
it.

Use the script at

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1163635055580
to find the offending statements and run it every day to ensure no new ones
accidently creep into the system!
October 27, 2001 Abdal-Rahman -- Thanks for the question regarding
      "Oracle Database Security", version 8, 8i

      You Asked
Hi Tom,

  Thank you very much for replying to my quetions. Now, I have very important
question concerning the database security. You know that no one can access the
database unless he is already being granted the necessary priveleges to do
specific thing, and that is meaning the database is secured from unauthorized
users and no one can enter the database without knowing the password for that
user. But there is something strange and dangerous in the same time. That is, I
can use the ORADIM or ORAPWD utility to change the INTERNAL password without
asking me from the old one. And after I create a new password for INTERNAL, I
can access any portion of the database, or I can change any other user
properties because INTERNAL has very high privilege as he has SYSDBA role.

  Please, tell me if my understanding is correct and how can I feel my database
is secured enough. Is there any way to protect my database from something like
that I inform you above? I know that I can use O/S authentication method and
that my user should be registered from outside the O/S. But also this is not the
ideal method to protect my database.

Thanks.
Best regards,
   Abdal-Rahman Agha.

      and we said...
You use OS security to protect the password file.  Secure that file using NT
security.  Right now, you must have the permissions wide open on that file.
Protect it the same way you would any confidential file.

October 28, 2001 Rakesh -- Thanks for the question regarding "How
      to Optimize Delete", version 8i

      You Asked
Hi Tom,

I would like to aks you 2 problems regarding optimizing Delete statements.

Case I) There is table T1 with >10 millions rows and would like to perform a
delete after 10-15 minutes, as we are loaing this table after 15 minutes via
sqlloader.

Delete from T1
where T1.Col1 = T2.Col1 and
       T1.Col2= T2.Col2
Where Col1 and Col2 are unique keys in T1 and only columns of T2.

Case II) There are 8 tables we are perfroming delete and these 8 tables have >
10 millions rows in each one of them.
There is one Driving table D1 which gets loaded after 10 minutes or so and based
on that we need to perform delete from the corresponsinf 8 tables. D1 has around
1000 Records for each load after 15 minutes.

Delete from T1 where T1.C1= D1.C1
Delete from T2 where T2.C1= D1.C1
Delete from T2 where T3.C1= D1.C1

Delete from T4 where T4.C1 = D1.C1 and
                     T4.C2 = D1.C2

Delete from T5 where T5.C1 = D1.C1 and
                     T5.C2 = D1.C2

Delete from T6 where T6.C3 in (Select C3 from T4
                               where T4.C1 =D1.C1 and
                                     T4.C2=D1.C2)
Delete from T7 where T7.C3 in (Select C3 from T4
                               where T4.C1 =D1.C1 and

Delete from T4 where T4.C1=D1.C1 and
                     T4.C2 =D1.C2

For each row to be deleted from d1 there are
T1= 1 row
T2= 30 rows
T3= 30 Rows
T4= 1 rows
T5= 5 Rows
T6= 40 rows
T7 = 40 rows
T8= 1 row

I really appreciate your help on this as currently I wrote this using
conventional opening a cursor on D1 and looping thru and opening another cursor
inside the main loop on T4 for T6 and T7, but th e whole process takes 15-30
minutes and that is not acceptable and causing troubles.

Thanks & Regards,
Rakesh

      and we said...
Well, I like this plan:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t1
  2  ( col1 int,
  3    col2 int,
  4    data char(2000),
  5    constraint t1_pk primary key(col1,col2)
  6  );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t2
  2  ( col1 int,
  3    col2 int,
  4    constraint t2_pk primary key (col1,col2)
  5  );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> exec dbms_stats.set_table_stats( user, 'T1',
numrows=>10000000, numblks => 1000000 );

PL/SQL procedure successfully completed.

ops$tkyte@ORA717DEV.US.ORACLE.COM> exec dbms_stats.set_table_stats( user, 'T2',
numrows=>1000, numblks => 10 );

PL/SQL procedure successfully completed.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> set autotrace on
ops$tkyte@ORA717DEV.US.ORACLE.COM> delete from t1 where (col1,col2) in ( select
col1, col2 from t2 );

0 rows deleted.

Execution Plan
----------------------------------------------------------
   0      DELETE STATEMENT Optimizer=CHOOSE (Cost=1 Card=1000000 Bytes=52000000)
   1    0   DELETE OF 'T1'
   2    1     NESTED LOOPS (Cost=1 Card=1000000 Bytes=52000000)
   3    2       INDEX (FAST FULL SCAN) OF 'T2_PK' (UNIQUE) (Cost=1 Card=1000
Bytes=26000)
   4    2       INDEX (UNIQUE SCAN) OF 'T1_PK' (UNIQUE)

That says it'll read the index on T2 (few rows) and do an index read into T1
(big table) and find and delete the rows in t1.

The "conventional method" of opening a cursor and proceduralling processing the
deletes is in my opinion the WRONG way.  It is very rare (but there are cases)
that code you write procedurally can run faster then a single delete statement.

Just do the delete straight out using sql -- don't write code to do it..
Review &
      Followup

      Rating: 3
How to Optmizie
      Delete  October 28, 2001
Reviewer:  Rakesh
      Arora  from San Ramon, CA ,94583
Thanks for the reply Tom.
So If I get it correctly I should be using staright Delete from these  tables
but how doI write it for the two different cases as I asked Case I and Case II.

I really appreciate if you could give me the sql for these two cases.

Once again thanks for your quick response.

Rakesh

          Followup:

I fail to see any difference between case 1 and case 2.

what are the specific differences you feel need addressing?  All I see are two
cases where you need to delete data in one table based on values from another
table?


Subject | Article | Last Updated (East coast time)
regarding the host naming | article only | Oct 29, 2001 10:31 am
Inline update rules | article only | Oct 29, 2001 10:59 am
skipping batch jobs on holidays using dbms_job | article only | Oct 29, 2001 03:31 pm
private rollback segments in ops | article only | Oct 29, 2001 04:35 pm
Day to day issue concerning moving data from prod to dev | article only | Oct 29, 2001 09:05 pm
Reg :- Forms_ddl('select 1 from emp') | article only | Oct 29, 2001 09:21 pm
convert range partition table back to nonpartition table | article only | Oct 30, 2001 08:25 am
reteriving oracle error numbers in java.. | article only | Oct 30, 2001 08:40 am
Re: populate unique sequnce number corresponding the order of query result | article only | Oct 30, 2001 10:05 am
Function and chained rows | article only | Oct 30, 2001 11:17 am
Using Parallel on create index causes fragmentation | article only | Oct 30, 2001 12:21 pm
Group By Quarter, using a DATE field | article only | Oct 31, 2001 07:29 am
granting access to v$tables | article only | Oct 31, 2001 08:20 am
Oracle9i: Limiting output with Bind Variables, Object Types, and DBMS_XMLQuery | article only | Oct 31, 2001 01:18 pm
querries about SQL/Sql*Plus | article only | Oct 31, 2001 01:25 pm
how does this check constraint work | article only | Nov 01, 2001 03:07 pm
Some BLOB Questions | article only | Nov 01, 2001 03:27 pm
Space Issues | article only | Nov 01, 2001 03:45 pm
FGAC and batch jobs | article only | Nov 01, 2001 04:24 pm
Import/Export between UNIX and NT | article only | Nov 02, 2001 07:26 am
Data Replication | article only | Nov 03, 2001 08:54 am
Are stored procedure really smarter than anonymous block in context of soft parsing. | article only | Nov 04, 2001 11:50 am
Is it possible to find column name from column number in ORDER BY clause? | article only | Nov 04, 2001 04:01 pm
Java Pool in Oracle 8i | article only | Nov 04, 2001 10:20 pm
row(s) 1 - 24 of 24
October 29, 2001 madoure -- Thanks for the question regarding "regarding the host naming", version 8i
You Asked
hi,

i am using the oracle 8i database. i wanted to know what is the host naming
method is used for my client and database. to know it, i have opened the
sqlnet.ora. in that the names.directory_path entry is having two naming methods
namely TNSNAMES and HOSTNAME.

my question is : how and why these two host methods are used at a time. how it
will be resolved between the two during connections.
why only one is not used.

the entry is shown as names.directory_path = (TNSNAMES, HOSTNAME)
and we said...
see
http://technet.oracle.com/doc/oracle8i_816/network.816/a76933/namingcf.htm#475293
for details.

Basically it is saying:

when you get a connection string "scott/tiger@database"

take the word database and first goto the TNSNAMES.ora file and try to resolve
if.  If you cannot resolve it via the tnsnames.ora file, then use the HOSTNAME
based approach and try to resolve it that way.

You can list many different ways to try and resolve names and they will be tried
in the order you list them.
Review & Followup
Rating: 3
naming methods October 31, 2001
Reviewer: Muthu from India
ya.. it's good.

October 29, 2001 Dan -- Thanks for the question regarding "Inline update rules", version 8.1.7
You Asked
Do you have or know of a good resource for details about the rules that govern
inline updates, I guess that it is tied to PCTFREE in some way but the exact
details would be great.

We have several tables that are updated very frequently and I am a trying to
limit the amount of chaining and migration that is caused.

Do you have any scripts that could be run that tell you which tables are have
experenced the most migration and hence may benifit from a change of storage
clause.

Thanks
and we said...
The rules are very simple (i go over them in detail in my book if you are
interested, including a discussion on chaining/migrating).

A block will continue to accept new rows until the free space on it would fall
below PCTFREE.  So, if you have an 8k block, as soon as about only 800 bytes are
left -- that block will no longer accept insertions.  The remaining 800 bytes
will be used to accomidate updates.

When you update a row on the block, if that row can fit on the block still -- it
will.  If you had a block with 800 bytes free but you add 900 bytes to the row
(so the row will still fit on a database block -- just not THIS database block),
Oracle will migrate the row.  We move the entire row to a new block leaving
behind our forwarding address.  This row is "migrated".

If you update a row on a block and cause the row to become larger then would fit
on ANY single block -- we will chain this row.

Migrated rows can be "fixed".  Chained rows -- truely chained rows ( bigger the
a block ) cannot be fixed, they are just too large.

In order to determine how many rows are chained/migrated, you simply use the
analyze table list chained rows command to get them all.

If you search for:

analyze table list chained rows

on my site, you'll get some articles on this topic that will be of interest to
you as well.
October 29, 2001 Naveed -- Thanks for the question regarding "skipping batch jobs on holidays using dbms_job", version 8.1.6
You Asked
( New text added at end if 1st paragraph )
We are currently using the dbms_job package to schedule a job that should run
every night Monday through Friday except on holidays. We can schedule it
properly to run on weekdays, but how can we tell it to skip holidays ( for
example not to run for Thanksgiving, Xmas and New Years ). We presently don't
have any way to tell from the database if a certain date is a Holiday, but
someone from our team said that we could setup a table, but we would have to
maintain it anually to remove last years holidays, and add this years because
they are know only after the first of the year.

I consulted Expert one-on-one Oracle( Appendix A ), and found that we can setup
like below to skip Saturday and Sunday,

declare
     l_job number;
begin
     dbms_job.submit( job => l_job,
                      what => 'process_work_day_data;';
                      next_date => trunc( sysdate) + 1 + 1/24,
                      interval => 'trunc(sysdate + decode( to_char(sysdate, 'd'
), 6, 3, 1 ) + 1/24' );
end;
/

This would run 1:00 am M - F, but would not skip holidays. Do we need a
scheduling package of some sort? Any recommendations?
Thanks alot.
and we said...
Yes, you would have to setup and maintain your own table of holidays -- some
don't move (christmas), some do (thanksgiving)... Nothing I can do there.

Read on in the dbms_job chapter where I describe "custom scheduling".  This is
an exmaple of a next_date that is too hard to compute using a simple select from
dual as dbms_job would do.

You will add a parameter p_next_date IN OUT date to your procedure
process_work_day_data.  It can then procedurally determine the next time it'll
run.  For exmaple it could be as easy as:

....
as
  ...
  l_cnt number;
begin
    p_next_date := trunc(sysdate);
    loop
         p_next_date := p_next_date+1;
         if ( to_char(p_next_date,'Dy') not in ( 'Sat', 'Sun' ) )
         then
              select count(*) into l_cnt
                from holidays
               where dt_col = p_next_date;

              if ( l_cnt = 0 )
              then
                  EXIT;  -- the loop, we found our day!!
              end if;
          end if;
    end loop;
    p_next_date := p_next_date+1/24;
    ......

That'll start p_next_date at sysdate+1.  If that is NOT sat or sun AND we cannot
find that day in the holidays table -- we exit out of the loop and add 1 hour.
Else, we go and add 1 day and try again (and again) until we find a day that is
not sat/sun and not in the holidays table.
October 29, 2001 Tony -- Thanks for the question regarding "private rollback segments in ops", version 8.17
You Asked
 Hi, Tom:

I would like to ask you a question about private rollback segment in parallel
server.
I have 2 nodes of ops and each has several private rbs defined in its init.ora
file. (RBS0,2,4,6… for prod1 database and RBS1,3,5,7… for prod2 database).
However, when I startup one instance in a node, it always bring all rollback
segment online, then I startup another instance, I would get  ORA-01545:
rollback segment '3' specified not available. I have to alter rollback segment
offline for all private rbs in 2nd  instance in 1st node to successfully startup
the 2nd instance. How can I setup the RBS, so when I startup one instance, it
only brings its private rbs online?

Thank you very much

Put it this way, we have 2 parallel instance prod1 and prod2.
Prod1 has private RBS 0,2,4,6 defined in initprod1.ora and prod2 has
private RBS 1,3,5,7 defined in initprod2.ora.When I startup prod1, it bring all
RBS onlinle( not only RBS0,2,4,6 but RBS1,3,5,7), so I tried to startup prod2 I
got ORA-1545 error saying RBS 1,3,5,7 not aviable. I have to alter RBS 1,3,5,7
offline in prod1 first then i can startup prod2. If I startup prod2 first, the
same situation happens, I have to alter RBS0,2,4,6 offline to be able to start
prod1.

The question is, how I can setup private RBS so it only bring its private rbs
online, so i don't need to offline other instatance's rbs
to start the database.

Thanks for your response,the additional info is as following:

SQL> select segment_name, owner from dba_rollback_segs;

SEGMENT_NAME                   OWNER
------------------------------ ------
SYSTEM                         SYS
R0                             PUBLIC
R01                            PUBLIC
R02                            PUBLIC
R03                            PUBLIC
R04                            PUBLIC
R05                            PUBLIC
R06                            PUBLIC
R07                            PUBLIC
R08                            PUBLIC
R09                            PUBLIC

SEGMENT_NAME                   OWNER
------------------------------ ------
R10                            PUBLIC
R11                            PUBLIC
R12                            PUBLIC
R13                            PUBLIC
R14                            PUBLIC
R15                            PUBLIC
R16                            PUBLIC
R17                            PUBLIC
R18                            PUBLIC
R19                            PUBLIC
R20                            PUBLIC

That was issued in my 1st instance prod1.
and we said...
Those are all PUBLIC rollback segments.  When created, you created them with

create public rollback segment.....

Private rollback segments are owned by SYS -- PUBLIC by PUBLIC.

All PUBLIC rollback segments are onlined by every instance.

You need to drop them and recreate them as PRIVATE rollback segments.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create PUBLIC rollback segment public_rbs
  2  tablespace users;
Rollback segment created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create rollback segment private_rbs
  2  tablespace users;
Rollback segment created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select segment_name, owner from
  2  dba_rollback_segs where segment_name like '%RBS';

SEGMENT_NAME                   OWNER
------------------------------ ------
PUBLIC_RBS                     PUBLIC
PRIVATE_RBS                    SYS

so, make them be owned by SYS.
Review & Followup
Rating: 4
public vs private October 29, 2001
Reviewer: Benny from Irvine
Is there a preference in OPS to use private or public
rollback segments?

Followup:
private for sure.  you want each instance to have their own set.

October 29, 2001 Nag -- Thanks for the question regarding "Day to day issue concerning moving data from prod to dev", version 8.1.7
You Asked
Tom

I need to move data from production to development very frequently.
We do not have any database links set up for some reason (security accoring to
our dba), so there is no way I can just select the data from production and
insert them into the related tables in dev.

Every time, I have to call up the dba to do the needful i.e. either refresh the
data in dev, or do a CTAS in dev using the select of the data I require from
prod.

This is leading to a lot of delays, and also the dba's consider this as a pain,
as require data again and again from production at very frequent intervals.

I have select access in prod, and all the privilegs in dev. I dont have access
to the database server. I only have access to the unix server i.e. the network
server through which I connect to the database.

1.Now how should I handle this. Is there a way where I can select data from the
production and insert them into my tables in dev.
2.Can I copy the data to excel worksheet and then insert into my tables from
there.
3.cumbersome and clumsy but still- how can I dynamically create a insert into
statement using the data spooled into a file from production.

Believe me, this is proving to be a show stopper, and Iam feeling lost, waiting
for hours together.

Kindly, remove this hurdle for me by provinding your valuable suggestions and
solution.

Nag
and we said...
Well, after reading the first paragraph, I'd say "get a new DBA".  Guess they
don't know how to setup a database link for you that supports read only access.
Time to get a new DBA.

If you have select access in prod and you have the TNS connect string -- what is
stopping you from creating a database link yourself??  Its easy.

short of that, have you looked at the sqlplus copy command -- its really cool
for doing this.
http://technet.oracle.com/doc/oracle8i_816/sqlplus.816/a75664/ch816.htm#1013063
as a last ditch, you can use my flat utility:
http://osi.oracle.com/~tkyte/flat/index.html
to use sqlplus to unload data in sqlldr format for reloading...
Review & Followup
Rating: 4
Remote Export/Import October 29, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
I would suggest that you use your client-side Export tool to unload the data,
and import it in the database using Import. If you have your Oracle networking
environment set up, like tnsnames.ora and sqlnet.ora, you can use this in your
command-line prompt:

exp yourname/password@development file=myfile.dmp
imp yourname/password@production file=myfile.dmp

This can be done in the same OS session in any coonfigured machine, since its a
remote operation and myfile is in the same directory.

This will dump your schema from development and load it into production. For
example, you could use the tables clause to move specific tables and associated
objects. As a DBA, you could do a full export of your database.

Take a look at the utilities guide for other options. Here are some:

ROWS=N would copy only table definitions.

IGNORE=Y would transport only de data, if the existing table already exists (but
take care to delete the table before importing, because otherwise, your import
data would be appended to the existing rows).

Use CONSISTENT=Y to get a snpshot of all the objects. Or else there will be only
a table-by-table read consistency. CONSISTENT=Y in a very DML-intensive system
might cause a "snapshot too old" error. Since you are in development, this
parameter should not be a problem.

Rating: 5
Andre - how would this work? October 30, 2001
Reviewer: Lester Burnham from Orlando, FL USA
The question states that the user needs to refresh data in DEV from PROD, not
data in PROD from DEV as your example shows.  Besides, the user only has
'select' privilege in PROD.  What if the owning schema in prod is not this
user's schema (as would be guaranteed)?  How would this user export another
user?  Also, how could this user import a dump file into the PROD database as
would be required by your example?

Rating: 5
April 05, 2002
Reviewer: A reader

October 29, 2001 RAGUPATHI -- Thanks for the question regarding "Reg :- Forms_ddl('select 1 from emp')", version 6i
You Asked
Hi Tom,

How to use SELECT statement in FORMS_DDL.
Pls give example.

Thanks
Raghu.K
and we said...
you cannot, it doesn't make sense.  forms_ddl only executes DDL and DML (like
inserts/updates/deletes).  It has no facility for "output"

You want to look at any of:

o exec_sql
o dbms_sql
o create_group_from_query (my favorite, array fetches -- efficient -- and easy
to do )
October 30, 2001 ted -- Thanks for the question regarding "convert range partition table back to nonpartition table", version 816
You Asked
thomas,

what is best way to convert table with  partitions back to non-partition table .

exchange allows me convert one partition to a nonpartition table. when I tried
to exchange next partition I received oracle error.

suppose I have a1, a2, a3 partition, how can I convert all 3 partitions into an
identical layout nonpartition table A without
using export/import.

thnx in advance
ted chyn
and we said...
In Oracle8i your choices are:

CREATE TABLE as SELECT, drop old, rename new

exp/imp

CREATE TABLE and then INSERT /*+ APPEND */ and then drop old rename new.

Merge the partitions so its a single partition table, then exchange, then drop
old rename new.

They all involve rebuilding the object totally with some downtime.

In Oracle9i, you'll be able to achieve this entire operation online, with a
couple of seconds of downtime using the online redefinition facility.
Review & Followup
Rating: 4
October 30, 2001
Reviewer: A reader

October 30, 2001 T.S.V.S. -- Thanks for the question regarding "reteriving oracle error numbers in java..", version 8.1.5
You Asked
Hi Tom,

We are developing reports in Servlets. In this we are handling Oracle errors
through exception. i.e., It is handling both Oracle error code and message. I
want to handle only Oracle error code because I want to give "End User Friendly"
message instead of Oracle message. Pl. give me any suggestion in this.

Thanks
Kishore
and we said...
sounds like you know what you want to do -- you have easy access to the error
code, now you need some way of turning that into a user friendly error.

In my experience, this is an exercise in futility.  Here is why:

o if you are EXPECTING an error, like a duplicate value on index, you would have
an exception handler specifically for that.  When you get it, you deal with it
-- be it via a nice message to the user or by doing something else.

o if you are NOT expecting an error, how the heck can you make it a "friendly"
error message beyond "Hey, something totally unexpected occurred, we failed.
sorry".  For example, if you are doing that insert and get

01629, 00000, "max # extents (%s) reached saving undo for tablespace %s"
// *Cause:  Save undo for the offline tablespace at max extents
// *Action: Check the storage parameters for the system tablespace. The
//          tablespace needs to be brought back online so the undo can be
//          applied .

What "friendly" message could you put up for that??  Or any of the other
unexpected ones?

What I'm trying to say is there are two types of errors you will get:

1) ones you expect.  You catch and handle EACH of these in your try/catch block
individually.  You can put up a message specific to the error (cause you were
expecting it -- you know the likely cause) or you can handle it (cause if you
get a dup val on index you should update for example)

2) ones you do not expect.  These should just be reported as "hey, totally
unexpected error happened.  We've emailed the admins the details.  Sorry, try
again later"

(i won't even comment on writing reports in raw java using servlets when so many
off the shelf packages exist to do that without writing much code.  seems a step
back into the past -- writing reports with cobol or rpg instead of a report
writing tool....  i guess i did just comment on it after all)
Review & Followup
Rating: 1
December 03, 2002
Reviewer: A reader

October 30, 2001 pauline -- Thanks for the question regarding "Re: populate unique sequnce number corresponding the order of query result", version 8.1.5
You Asked
Tom,
Your new policy is neccessary to setup. I fully understand it. To provide the
best answers to us, you spent much much personal time even at the weekend and
holiday. I can imagine now you put the kids on the bed and turn back to answer
our questions. If you always overload like this way, it is not good for your
health and family life.
But I have to bother you now. Is there any way to populate the unique
sequence number which corresponding the order of the query result.
For example, if query result are:
LOT_ID   FIRST_NAME
--------------------
1        Linda
2        Pauline
4        Amy
5        Jiff
7        Tom
11       Bill

I want to polulate a unique sequence number for this query. Something
like:

NUM LOT_ID   FIRST_NAME
------------------------
1   1         Linda
2   2         Pauline
3   4         Amy
4   5         Jiff
5   7         Tom
6   11        Bill

The query result will be changed but the sequence number will always
start from 1 and corresponding the first row in the result set,and the next
number corresponding the second row in the result setetc,etc.

Thanks in advance.

Pauline
and we said...
not in a single sql statement but:

ops$tkyte@ORA815.US.ORACLE.COM> create table t as select -1 num, ename, empno,
sal from emp;

Table created.

ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM> declare
  2          type ridArray is table of rowid index by binary_integer;
  3          l_rowids   ridArray;
  4          l_nums     dbms_sql.number_table;
  5          cursor c is select rowid from t order by sal;
  6  begin
  7          open c;
  8          fetch c bulk collect into l_rowids;
  9          close c;
 10
 11          for i in 1 .. l_rowids.count
 12          loop
 13                  l_nums(i) := i;
 14          end loop;
 15
 16          forall i in 1 .. l_rowids.count
 17                  update t set num = l_nums(i) where rowid = l_rowids(i);
 18
 19  end;
 20  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM> select * from t;

       NUM ENAME           EMPNO        SAL
---------- ---------- ---------- ----------
         1 SMITH            7369        800
         8 ALLEN            7499       1600
         4 WARD             7521       1250
        11 JONES            7566       2975
         5 MARTIN           7654       1250
        10 BLAKE            7698       2850
         9 CLARK            7782       2450
        12 SCOTT            7788       3000
        14 KING             7839       5000
         7 TURNER           7844       1500
         3 ADAMS            7876       1100
         2 JAMES            7900        950
        13 FORD             7902       3000
         6 MILLER           7934       1300

14 rows selected.

would do it.
Review & Followup
Rating: 4
Great October 30, 2001
Reviewer: A reader
That is great method by using rowid and number_table concepts.

But is there some condition restrict us from doing:
select ronum, a.*
from (select * from scott.emp order by sal) a ?

Tell me what the condition forbid us to do that and maybe i'm not fully
understanding the question.

Thanks

Followup:
They wanted a column to permanently record that rownum.   Yours would select it
but not make it permanent.

You need an update somewhere.

Rating: 4
October 30, 2001
Reviewer: Pauline from NY,U.S.A
Thanks for the quick response and it is really useful.

October 30, 2001 RAMASUBBAN -- Thanks for the question regarding "Function and chained rows", version 8.1.6
You Asked
Hi Tom,

1)We have a table(lookup) which contains all the countries in the world.This is
a standard ISO list.
We get country data from legacies with different styles of country names for
example
If the country listing in the country table is South Korea,
we get 'KOREA SOUTH-REP. OF'.
We have a process where these records gets rejected because it is not in the
lookup table.
I wanted to know how to find out/define or set rules like if country attribute
has 'KOREA SOUTH-REP. OF' then change it to 'SOUTH KOREA' as per the lookup
table.Can it be done using a soundex function or any other function to see if
the particular portion of the string occurs(In this case,there is a difference
between North Koea and South Korea).

2)With your suggestion on the chained rows,I had analysed the tables and found
that one of my tables(350 columns) has chained rows.The size on almost most of
the rows is less than the 8k blocksize limit.
The question is what kind of performance improvement I could expect if I back
them up,delete and reinsert them into the table as per your earlier suggestion.
Why are these rows chained inspite of them not having long/raw datatypes and
less than 8k.Can blocksize be increased?Please advice.

Thanks in Advance for your answer.

Bala
and we said...
1) I do not see any intuitive or builtin way to do this.  SOUTH KOREA is very
different from KOREA SOUTH-REP. OF

The easiest thing I can think of is to start creating a table of known common
exceptions and what they should be.  At first this is a manual process -- you
must input SOUTH KOREA -> KOREA SOUTH-REP. OF but after a while, it becomes
automated as you cover all of the known cases.

2) Ahh, should have mentioned that but tables with sooo many columns are very
rare.

That table will always be chained, nothing you can do.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1353802937791
for why.
Review & Followup
Rating: 3
October 30, 2001
Reviewer: A reader
Thanks Tom

October 30, 2001 Dennis -- Thanks for the question regarding "Using Parallel on create index causes fragmentation", version 8.1.6.3
You Asked
Hi Tom.

We are using a 'good' storage management policy, in that all objects in one
tablespace are the same size (we use tablespace defaults as opposed to
specifying them).  The sizes we use are 160 KB, 5120 KB (5 MB), and 160 MB.

We have been switching indexes to be nologging and parallel to improve speed of
creation.  Recently we had an index tablespace causing update jobs to abort
because it could not create temp segments in the index tablespace.  The only way
we found to 'fix' the problem (after dropping tablespace and data files several
times) was to create the indexes as noparallel, after which a quick scan of
dba_free_space showed only one big contiguous memory chunk.  When we had
recreated with parallel (no dml operations ongoing), dba_free_space revealed all
kinds of fragmentation.

A quick check of the other tablespaces reveals some 160 KB tablespaces
fragmented, all but one 5 MB tablespace fragmented (one has 5 MB holes, but
that's what we want to see), and the 160 MB tablespaces don't appear to be
fragmented (hard to tell because we didn't use a tablespace size divisible by
160, so the holes could be at the end of the file...).  The tablespace that blew
up however, was a 5 MB tablespace (this tablespace has indexes on smaller tables
than the 'perfect' 5 MB does).

When using parallel, it does not appear that the 'temp' segment sizes not held
to the 'boundaries' determined by our extent sizes.  Instead of finding a bunch
of 'usable holes' that were the same size as our extents, we found many little
holes that were unusable.  The TAR we had opened suggested doing a tablespace
coalesce after each create index.  Their reasoning was that the extents were
being allocated faster than smon could coalesce (since we use PCTINCREASE 0).
This failed to work however, and still left the tablespace full of holes.

Will using Locally Managed Tablespaces force these temp segments when using
parallel to be the size we need?  I don't know if we are getting fragmentation
because the parallel thread is writing to a whole bunch of 'non-sequential'
areas, or if it is writing sequentially, and not following the sizing we would
like.

I guess if I didn't confuse you (since I'm confused now after typing this) the
real questions I have are the following.

1.  Using Parallel seems to cause fragmentation.  In a no parallel index, the
'temp' segments are the same size as an actual extent, and so we get no
fragmentation.  Does parallel not follow the same standard, and instead write a
bunch of little segments that it converges back into one 'normally' sized extent
when the sorting is done?

2.  Does locally managed have the ability to keep the tablespace from being
fragmented by controlling how big the temp segments are and making sure they
write on the extent boundaries?  (I haven't been able to test this yet, and
actually got in to submit questions so here you go).

3.  Is the fragmentation causing behaviour of parallel normal?  The TAR we had
seemed to expect that it would happen, and didn't seem surprised.  I've never
seen anything saying parallel would cause fragmentation, so just kinda curious
here.

Thanks for your help.  Hope you're booking some time off this holiday season
already.  If you need it, I have some pictures of the dba_free_space tucked away
in a few places (not sure I saved them all, but I know I have at least one - the
one that I did an alter tablespace coalesce after each and every create index,
as the TAR suggested).

Dennis
and we said...
This is a side effect of parallel -- it does extent trimming.  See
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c22paral.htm#8399
it talks of this extent trimming.  SQLLDR direct path loads do the same.  It can
mess up your NEXT extent allocation as well.

LMTs with UNIFORM will solve this 100%.
Review & Followup
Rating: 5
That was exactly what I wanted to hear October 30, 2001
Reviewer: Dennis from Missouri, USA
Thanks Tom!  I didn't know anything about the trimming, but that explains my
'tiny' bit of data tablespace fragmentation that I was seeing (but not worrying
about yet).  You killed two birds and I only wanted one, so I am very
appreciative and happy.  Thank you very much.  The LMT and 9i upgrade is coming
up soon for us, and now that you've answered my question, I can not worry about
this.  If needed, we can switch some tablespaces a little early, or
'temporarily' use no parallel.

Thanks so much.
Dennis

October 31, 2001 Greg -- Thanks for the question regarding "Group By Quarter, using a DATE field", version 8.1.6 E.E.
You Asked
Tom,

Thanks for all your help in the past.

My question is:  if you were going to extract information from a table using a
DATE type field, but you wanted to group by quarter, how would you go about it?

E.G.

SELECT COUNT(*)
  FROM table_t
 WHERE date_d >= beginning_of_fiscal_year
   AND date_d <= end_of_fiscal_year
GROUP BY ??????????

For an extra twist, let's say that the fiscal year begins on November 1 and ends
October 31 in the following calendar year.
and we said...
so qtr 1 is months 11, 12, 1
       2 is months 2, 3, 4
       3 is months 5, 6, 7
       4 is months 8, 9, 10

very simple, clear way is:

group by decode( to_number(to_char(date_d,'mm')),
                 11, 1, 12, 1, 1, 1,
                  2, 2,  3, 2, 4, 2,
                  5, 3,  6, 3, 7, 3,
                  8, 4,  9, 4,10, 4 );

cooler but more obscure way is:

group by trunc(mod( to_number(to_char(date_d,'mm'))+1, 12 )/3)+1

for example:

ops$tkyte@ORA8I.WORLD> select date_d,
          trunc(mod( to_number(to_char(date_d,'mm'))+1, 12 )/3)+1
  2    from ( select add_months(sysdate,rownum) date_d from all_objects where
rownum <= 12 )
  3  /

DATE_D    TRUNC(MOD(TO_NUMBER(TO_CHAR(DATE_D,'MM'))+1,12)/3)+1
--------- ----------------------------------------------------
30-NOV-01                                                    1
30-DEC-01                                                    1
30-JAN-02                                                    1
28-FEB-02                                                    2
30-MAR-02                                                    2
30-APR-02                                                    2
30-MAY-02                                                    3
30-JUN-02                                                    3
30-JUL-02                                                    3
30-AUG-02                                                    4
30-SEP-02                                                    4
30-OCT-02                                                    4

12 rows selected.
Review & Followup
Rating: 5
Amazing work with DATE fields October 30, 2001
Reviewer: Greg Kliewer from Toronto, ON, Canada
Thanks Tom.  Both of these solutions will address my problem.  Typically, I find
the mathematics around DATE fields particularly confusion when designing
queries.  And you're never without a helpful recommendation.

Rating: 5
Excellent October 30, 2001
Reviewer: Sanjay Raj from USA
I also use this in some of my canned queries. But I use the date manipulation
not the DECODE. Which do U think is better performance wise. I am running 8.1.7
on HP UX and the tables have more than 10 million records ( Not Partioned).
Thanks

Followup:
decode is very fast....

select trunc(mod( to_number(to_char(date_d,'mm'))+1, 12 )/3)+1,
       count(*)
  from t
 group by trunc(mod( to_number(to_char(date_d,'mm'))+1, 12 )/3)+1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      3.55       3.54        122        250         15           4
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      3.55       3.55        122        250         15           4

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 61

Rows     Row Source Operation
-------  ---------------------------------------------------
      4  SORT GROUP BY
 135784   TABLE ACCESS FULL T

********************************************************************************

select decode( to_number(to_char(date_d,'mm')),
                 11, 1, 12, 1, 1, 1,
                   2, 2,  3, 2, 4, 2,
                 5, 3,  6, 3, 7, 3,
                8, 4,  9, 4,10, 4 ),
       count(*)
  from t
 group by decode( to_number(to_char(date_d,'mm')),
                 11, 1, 12, 1, 1, 1,
                   2, 2,  3, 2, 4, 2,
                 5, 3,  6, 3, 7, 3,
                8, 4,  9, 4,10, 4 )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      1.80       1.80          0        250         15           4
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      1.80       1.80          0        250         15           4

Rating: 4
Quaetrly grouping of data October 30, 2001
Reviewer: shamim from New delhi, India
HI Tom,
It was a very fantastic query , THanx a lot for helping oracle community.

Rating: 5
Alternate Way October 31, 2001
Reviewer: Muthukumaran Nirmalkumar from Qatar
Hi Tom,

How about to give the solution by using the date format 'Q'.

Here is my query using 'Q' format. Let me know is't correct way and want to know
the performance issues.

SCOTT@ORAN.QTEL.COM.QA> select count(*),decode(
to_number(to_char(hiredate,'mm')),
  2                   11, 1, 12, 1, 1, 1,
  3                    2, 2,  3, 2, 4, 2,
  4                    5, 3,  6, 3, 7, 3,
  5                    8, 4,  9, 4,10, 4 ) qtr_11
  6                     from emp group by decode(
to_number(to_char(hiredate,'mm')),
  7                   11, 1, 12, 1, 1, 1,
  8                    2, 2,  3, 2, 4, 2,
  9                    5, 3,  6, 3, 7, 3,
 10                    8, 4,  9, 4,10, 4 );

 COUNT(*)    QTR_11
--------- ---------
        7         1
        3         2
        2         3
        2         4

SCOTT@ORAN.QTEL.COM.QA> select
count(*),mod(to_char(add_months(hiredate,11),'Q'),4)+1 qtr_ll from emp
  2  group by mod(to_char(add_months(hiredate,11),'Q'),4)+1;

 COUNT(*)    QTR_LL
--------- ---------
        7         1
        3         2
        2         3
        2         4

SCOTT@ORAN.QTEL.COM.QA>

Followup:
There is most likely an infinite number of ways to accomplish this.  Yes, yours
most likely works as well.  You are just shifting the month into the proper
quarter.  The mod and +1 is not necessary as 'Q' returns a number between 1 and
4 already, we just need to shift the month by a different amount.

If we compare yours with one that skips the MOD and +1 we'll find:

select count(*),
       mod(to_char(add_months(date_d,11),'Q'),4)+1
from t
group by
       mod(to_char(add_months(date_d,11),'Q'),4)+1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      2.59       2.59          0        244          5           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      2.59       2.59          0        244          5           1

select count(*),
       to_char(add_months(date_d,-10),'Q')
from t
group by
       to_char(add_months(date_d,-10),'Q')

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      1.26       1.26          0        244          5           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      1.26       1.26          0        244          5           1

That to_char(add_months(date_d,-10),'Q') is the least CPU intensive approach.

October 31, 2001 Mikito -- Thanks for the question regarding "granting access to v$tables", version 901
You Asked
I have one specific question: how to grant an select from v$sql to user, say,
scott?

You are generally very good at explaining things; so, in general, what is an
access path to the objects? What security tables jump in between and control
what is accessible and what is not? How would I trace along this path what
particular privilege/role grant is missing?
and we said...
As the user SYS (or when connected as INTERNAL or "AS SYSDBA" both of which are
SYS) you would:

grant select on v_$sql to scott;

(v$sql is a synonym that points to the view v_$sql).  If you want, you can:

grant select on v_$sql to SOMEONE with grant option;

then, that someone will have the ability to grant on that object to any other
user (you won't need SYS)

Basically, in order to access an object you need to have a role or direct priv.
You would look in DBA_TAB_PRIVs or USER_TAB_PRIVS.  If you want to see ALL roles
and privs you have, see:
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:853427230099
also check out
http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for a caveat with regards to roles in procedures.
Review & Followup
Rating: 5
_ difference October 31, 2001
Reviewer: A reader
Aha! My mistake was that even knowing about both v$sql and v_$sql I was issuing
grant against the synonym...

October 31, 2001 Kristi -- Thanks for the question regarding "Oracle9i: Limiting output with Bind Variables, Object Types, and DBMS_XMLQuery", version Oracle9i
You Asked
Tom,

I am still getting an error when I try to limit the XML output.  I changed my
call from dbms_xmlgen to dbms_xmlquery and added a bind variable like you
suggested, but I think the difference in your example is that your caseno is not
part of a hierarchical set of object types like mine is.  Mine is a few levels
deep inside the various object types and so it doesnt know what the column
actually is.  I am guessing this is because I am selecting from a view that is
actually 2 columns, (pk & CasePartyAddress16_ntabtyp).  The CaseNo exists in the
fil_case16 object type which is 2 object type levels deep..  Ok so where do I go
from here?

Thanks in advance for the help!
Kristi

Here is the error:

declare
*
ERROR at line 1:
ORA-29532: Java call terminated by uncaught Java exception:
oracle.jdbc.driver.OracleSQLException: ORA-00904: invalid
column name
ORA-06512: at "SYS.DBMS_XMLQUERY", line 255
ORA-06512: at "SYS.DBMS_XMLQUERY", line 264
ORA-06512: at "SYS.DBMS_XMLQUERY", line 254
ORA-06512: at "KRISTI.FN_GETXML", line 16
ORA-06512: at line 4

Here is the ddl...
----------------------------------------------------------------------
-- Table ddl pulled from oem
----------------------------------------------------------------------
CREATE TABLE "KRISTI"."ENT_ADDRESS" ("PK" VARCHAR2(38 byte) NOT
    NULL, "UT" VARCHAR2(38 byte) NOT NULL, "PKPARENT"
    VARCHAR2(38 byte) NOT NULL, "PARENTENTCODE" VARCHAR2(3 byte)
    NOT NULL, "PKFILE" VARCHAR2(38 byte), "USERID" VARCHAR2(38
    byte) NOT NULL, "REF_ADDRESSTYPE_ID" NUMBER(38) NOT NULL, "ADDRESS1"
    VARCHAR2(60 byte) NOT NULL, "ADDRESS2" VARCHAR2(60 byte), "ADDRESS3"
    VARCHAR2(60 byte), "ADDRESS4" VARCHAR2(60 byte), "CITY"
    VARCHAR2(30 byte) NOT NULL, "REF_STATEPROVINCE_ID"
    NUMBER(38) NOT NULL, "ZIPPOSTALCODE" VARCHAR2(10 byte),
    CONSTRAINT "PK_ENT_ADDRESS" PRIMARY KEY("PK")
    USING INDEX
    TABLESPACE "INDX"
    STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
    2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
    PCTFREE 10 INITRANS 2 MAXTRANS 255)
    TABLESPACE "USERS" PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS
    255
    STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
    2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
    LOGGING;

CREATE TABLE "KRISTI"."ENT_PARTY" ("PK" VARCHAR2(38 byte) NOT
    NULL, "UT" VARCHAR2(38 byte) NOT NULL, "PKPARENT"
    VARCHAR2(38 byte) NOT NULL, "PARENTENTCODE" VARCHAR2(3 byte)
    NOT NULL, "PKFILE" VARCHAR2(38 byte), "USERID" VARCHAR2(38
    byte) NOT NULL, "REF_PARTYTYPE_ID" NUMBER(38) NOT NULL, "FIRSTNAME"
    VARCHAR2(30 byte) NOT NULL, "MIDDLENAME" VARCHAR2(30 byte), "LASTNAME"
    VARCHAR2(30 byte) NOT NULL,
    CONSTRAINT "PK_ENT_PARTY" PRIMARY KEY("PK")
    USING INDEX
    TABLESPACE "INDX"
    STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
    2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
    PCTFREE 10 INITRANS 2 MAXTRANS 255)
    TABLESPACE "USERS" PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS
    255
    STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
    2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
    LOGGING ;

CREATE TABLE "KRISTI"."FIL_CASE" ("PK" VARCHAR2(38 byte) NOT NULL,
    "UT" VARCHAR2(38 byte) NOT NULL, "USERID" VARCHAR2(38 byte)
    NOT NULL, "CASENO" VARCHAR2(10 byte) NOT NULL, "SHORTTITLE"
    VARCHAR2(30 byte) NOT NULL, "REF_CASETYPE_ID" NUMBER(38) NOT
    NULL, "REF_DISPOSITIONTYPE_ID" NUMBER(38), "REF_DISPOSITIONSTAGE_ID"
    NUMBER(38), "FILINGDATE" DATE NOT NULL, "DISPDATE" DATE, "REF_OFFICIAL_ID"
    NUMBER(38), "CAS_OFF_FIRSTNAME" VARCHAR2(10 byte), "CAS_OFF_LASTNAME"
    VARCHAR2(20 byte),
    CONSTRAINT "PK_FIL_CASE" PRIMARY KEY("PK")
    USING INDEX
    TABLESPACE "INDX"
    STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
    2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
    PCTFREE 10 INITRANS 2 MAXTRANS 255)
    TABLESPACE "USERS" PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS
    255
    STORAGE ( INITIAL 64K NEXT 0K MINEXTENTS 1 MAXEXTENTS
    2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1)
    LOGGING ;

CREATE TABLE temp_clob_tab(result CLOB);

create table sxmsg(pk varchar(38));

------------------------------------------------------------------
--Inserts needed
--------------------------------------------------------------------
insert into sxmsg(pk) values(1001);

INSERT INTO "KRISTI"."FIL_CASE" ("PK" ,"UT" ,"USERID" ,"CASENO" ,"SHORTTITLE"
,"REF_CASETYPE_ID" ,"REF_DISPOSITIONTYPE_ID" ,"REF_DISPOSITIONSTAGE_ID"
,"FILINGDATE" ,"DISPDATE" ,"REF_OFFICIAL_ID" ,"CAS_OFF_FIRSTNAME"
,"CAS_OFF_LASTNAME" )
VALUES ('1001' ,'1' ,'Bob' ,'A245' ,'Test Case' ,1 ,1 ,1 ,sysdate ,sysdate ,1
,'George' ,'Smith'  );

INSERT INTO "KRISTI"."ENT_PARTY" ("PK" ,"UT" ,"PKPARENT" ,"PARENTENTCODE"
,"PKFILE" ,"USERID" ,"REF_PARTYTYPE_ID" ,"FIRSTNAME" ,"MIDDLENAME" ,"LASTNAME" )

VALUES ('501' ,'1' ,'1001' ,'CAS' ,'1001' ,'1' ,1 ,'Bob' ,'T' ,'Jones'  )

INSERT INTO "KRISTI"."ENT_ADDRESS" ("PK" ,"UT" ,"PKPARENT" ,"PARENTENTCODE"
,"PKFILE" ,"USERID" ,"REF_ADDRESSTYPE_ID" ,"ADDRESS1" ,"ADDRESS2" ,"ADDRESS3"
,"ADDRESS4" ,"CITY" ,"REF_STATEPROVINCE_ID" ,"ZIPPOSTALCODE" )
VALUES ('2' ,'1' ,'501' ,'1' ,'1001' ,'1' ,1 ,'124 Main Street' ,'Apt. B' ,''
,'' ,'Denver' ,3 ,'80201'  )

-------------------------------------------------------------------
-- Object Types
----------------------------------------------------------------------
CREATE or REPLACE TYPE ent_address16 AS OBJECT(
    "@Ref_AddressType_ID" NUMBER(38),
    "@Address1" VARCHAR2(30),
    "@Address2" VARCHAR2(30),
    "@Address3" VARCHAR2(30),
    "@Address4" VARCHAR2(30),
    "@City" varchar2(30),
    "@Ref_StateProvince_ID" number(38),
    "@ZipPostalCode" VARCHAR2(10)
 );
/

CREATE OR REPLACE TYPE sys_ent_address16 AS OBJECT(
    "@PK" VARCHAR2(38),
    "@UT" VARCHAR2(38),
    "@PKParent" VARCHAR2(38),
    "@ParentEntCode" VARCHAR2(3),
    "@PKFile" VARCHAR2(38),
    "@UserID" VARCHAR2(38),
    "Col" ent_address16
 );
/

CREATE OR REPLACE TYPE ent_party16 AS OBJECT(
    "@Ref_PartyType_ID" varchar2(38),
    "@FirstName" VARCHAR2(30),
    "@MiddleName" varchar2(30),
    "@LastName" varchar2(38)
 );
/

CREATE OR REPLACE TYPE sys_ent_party16 AS OBJECT(
    "@PK" VARCHAR2(38),
    "@UT" VARCHAR2(38),
    "@PKParent" VARCHAR2(38),
    "@ParentEntCode" VARCHAR2(3),
    "@PKFile" VARCHAR2(38),
    "@UserID" VARCHAR2(38),
    "Col" ent_party16,
    "Ent" sys_ent_address16
 );
/

--
-- ------- CaseNo exists in this type -------
--
CREATE OR REPLACE TYPE fil_case16 AS OBJECT(
   "@CaseNo" varchar2(10),
   "@ShortTitle" VARCHAR2(30),
   "@Ref_CaseType_ID" Number(38),
   "@Ref_DispositionType_ID" Number(38),
   "@FilingDate" Date,
   "@DispDate" Date
 );
/

CREATE OR REPLACE TYPE sys_fil_case16 AS OBJECT(
    "@PK" VARCHAR2(38),
    "@UT" VARCHAR2(38),
    "@UserID" varchar2(10),
    "Col" fil_case16,
    "Ent" sys_ent_party16
 );
/

CREATE OR REPLACE TYPE CasePartyAddress16_ntabtyp AS TABLE OF sys_fil_case16
/

CREATE OR REPLACE TYPE sxmsg16 AS OBJECT(
   pk VARCHAR2(38),
   CasePartyAddr CasePartyAddress16_ntabtyp
 );
/
-------------------------------------------------------------------
-- View: CaseParty Address
-------------------------------------------------------------------
CREATE OR REPLACE VIEW CasePartyAddress OF sxmsg16
WITH OBJECT IDENTIFIER (PK)
AS SELECT s.pk,
     CAST( MULTISET(
       SELECT sys_fil_case16(sc.pk, sc.ut, sc.userid,
         fil_case16(c.caseno, c.shorttitle, c.ref_casetype_id,
c.ref_dispositiontype_id, c.filingdate, c.dispdate),
         sys_ent_party16(sp.PK, sp.UT, sp.PKParent, sp.parentEntCode, sp.pkfile,
sp.userid,
         ent_party16(p.Ref_PartyType_ID, p.FirstName, p.MiddleName, p.LastName),
         sys_ent_address16(sa.PK, sa.UT, sa.PKParent, sa.parentEntCode,
sa.pkfile, sa.userid,
         ent_address16(a.ref_addresstype_id, a.address1, a.address2, a.address3,
a.address4, a.city, a.ref_stateprovince_id, a.zippostalcode))))
       FROM fil_case sc, fil_case c, ent_party sp, ent_party p, ent_address sa,
ent_address a
       WHERE sc.pk = s.pk and sc.pk = c.pk and sp.pkparent = c.pk and sp.pk =
p.pk and sa.pkparent = p.pk and sa.pk = a.pk)
       AS CasePartyAddress16_ntabtyp)
   FROM sxmsg s;

-------------------------------------------------------------------
-- Function: Fn_GetXML
-- Selects from / Calls:  CasePartyAddress (pk, CasePartyAddress16_ntabtyp)
-- Error: is on WHERE d.CaseNo because CaseNo is part of fil_case16 Object type
-----------------------------------------------------------------
CREATE OR REPLACE FUNCTION FN_GETXML(p_CaseNo in varchar2) return clob
AS
   qryCtx DBMS_XMLQUERY.ctxHandle;
   result clob;
BEGIN
 qryCtx := DBMS_XMLQUERY.newContext('
            SELECT CasePartyAddr "FileGet"
            FROM CasePartyAddress d
            WHERE d.CaseNo = :a'
            );

 -- Bind the variable 'a' to p_caseno
 DBMS_XMLQUERY.setbindvalue(qryCtx, 'a', p_CaseNo);
 DBMS_XMLQUERY.setRowTag(qryCtx, NULL);
 DBMS_XMLQUERY.setRowSetTag(qryCtx, 'Msg');
 result := dbms_xmlquery.getxml(qryCtx);

 return result;

 EXCEPTION
   WHEN NO_DATA_FOUND THEN
      RAISE_APPLICATION_ERROR(-20000, 'No Records Found.....');

 End FN_GETXML;
/

CREATE OR REPLACE PROCEDURE printClobOut(result IN OUT NOCOPY CLOB) is
xmlstr varchar2(32767);
line varchar2(2000);
begin
  xmlstr := dbms_lob.SUBSTR(result,32767);
  loop
    exit when xmlstr is null;
    line := substr(xmlstr,1,instr(xmlstr,chr(10))-1);
    dbms_output.put_line('| '||line);
    xmlstr := substr(xmlstr,instr(xmlstr,chr(10))+1);
  end loop;
end printClobOut;
/

---------------------------------------------------------------------------------

-- Call the function to get the xml result where CaseNo=A245
-- I think this fails because the CaseNo is wrapped inside another type..??
---------------------------------------------------------------------------------

set pagesize 2000;
set linesize 120;
set long 4000;
set serveroutput on;
declare
   result_output clob;
begin
   result_output := fn_getxml('A245');
   printClobOut(result_output);
end;
/
and we said...
You're correct, the CaseNo attribute is embedded in the FIL_CASE16 type. If you
just put the entire query in your newcontext call, you can add the caseno where
clause in the cast(multiset query, and get your answer properly:

SQL> CREATE OR REPLACE FUNCTION FN_GETXML(p_CaseNo in varchar2) return clob
  2  AS
  3    qryCtx DBMS_XMLQUERY.ctxHandle;
  4  BEGIN
  5    qryCtx := DBMS_XMLQUERY.newContext('
  6  select s.pk,
  7         cast(multiset(
  8           select sys_fil_case16(
  9                    sc.pk, sc.ut, sc.userid,
 10                    fil_case16(c.caseno, c.shorttitle, c.ref_casetype_id,
 11                      c.ref_dispositiontype_id, c.filingdate, c.dispdate) ,
 12                    sys_ent_party16(sp.pk, sp.ut, sp.pkparent,
sp.parententcode, sp.pkfile,
 13                      sp.userid, ent_party16(p.ref_partytype_id, p.firstname,
p.middlename,
 14                                   p.lastname) ,
 15                      sys_ent_address16(sa.pk, sa.ut, sa.pkparent,
sa.parententcode, sa.pkfile, sa.userid,
 16                        ent_address16(a.ref_addresstype_id, a.address1,
a.address2, a.address3,
 17                          a.address4, a.city, a.ref_stateprovince_id,
a.zippostalcode))))
 18             from fil_case sc, fil_case c, ent_party sp, ent_party p,
ent_address sa,
 19                  ent_address a
 20            where sc.pk = s.pk and sc.pk = c.pk and sp.pkparent = c.pk and
sp.pk =
 21                  p.pk and sa.pkparent = p.pk and sa.pk = a.pk and c.caseno =
'''|| p_CaseNo ||''')
 22               as casepartyaddress16_ntabtyp) "ent"
 23    from sxmsg s');
 24
 25   DBMS_XMLQUERY.setRowTag(qryCtx, NULL);
 26   DBMS_XMLQUERY.setRowSetTag(qryCtx, 'Msg');
 27   return dbms_xmlquery.getxml(qryCtx);
 28   EXCEPTION
 29     WHEN NO_DATA_FOUND THEN
 30        RAISE_APPLICATION_ERROR(-20000, 'No Records Found.....');
 31
 32   End FN_GETXML;
 33  /

Function created.

SQL> declare
  2     result_output clob;
  3  begin
  4     result_output := fn_getxml('A245');
  5     printClobOut(result_output);
  6  end;
  7  /

| <?xml version = '1.0'?>
| <Msg>
|    <PK>1001</PK>
|    <ent>
|       <ent_ITEM PK="1001" UT="1" UserID="Bob">
|          <Col CaseNo="A245" ShortTitle="Test Case" Ref_CaseType_ID="1"
Ref_DispositionType_ID="1"
FilingDate="10/31/2001 9:25:51" DispDate="10/31/2001 9:25:51"/>
|          <Ent PK="501" UT="1" PKParent="1001" ParentEntCode="CAS"
PKFile="1001" UserID="1">
|             <Col Ref_PartyType_ID="1" FirstName="Bob" MiddleName="T"
LastName="Jones"/>
|             <Ent PK="2" UT="1" PKParent="501" ParentEntCode="1" PKFile="1001"
UserID="1">
|                <Col Ref_AddressType_ID="1" Address1="124 Main Street"
Address2="Apt. B" City="Denver"
Ref_StateProvince_ID="3" ZipPostalCode="80201"/>
|             </Ent>
|          </Ent>
|       </ent_ITEM>
|    </ent>
| </Msg>

PL/SQL procedure successfully completed.

The only problem with this particular solution, however, is that we're not using
bind variables in the newcontext query. This will ultimately cause performance
problems in a production application due to excessive parsing and storage of the
MANY COPIES that query in the SGA.

The reason why we're not using bind variables is because there is a bug in the
XDK when using bind variables in a "cast(multiset" query.

Also, you can use the XSL transformation we discussed earlier to format the
resulting XML document, if need be. (ref:
http://asktom.oracle.com/pls/flows/f?p=4950:8:227453::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:1827993798549,
)
Review & Followup
Rating: 5
That worked October 31, 2001
Reviewer: Kristi Richardson from Denver, CO
I am wondering how long it will take to get a patch so that I can use the bind
variables inside a CAST though.  What is the best way to find out when this bug
is/will be fixed?

Followup:
Support is your best avenue of approach for getting info on the bug. It's
bug#2088771, and I used the following test case to reproduce it:

SQL> create or replace type employee_t as object(
  2  empno number, ename varchar2(10), favorite_color varchar2(10))
  3  /
SQL> create or replace type employee_list_t as table of employee_t
  2  /
SQL> create table emps( empno number, ename varchar2(10), favorite_color
varchar2(10));
SQL> insert into emps values ( 10,'chris','plaid' );
SQL> insert into emps values ( 20,'bill','hazel' );
SQL> insert into emps values ( 30,'sergio','silver' );
SQL> variable c clob
SQL> declare
  2    qryctx dbms_xmlquery.ctxhandle;
  3  begin
  4    qryctx := dbms_xmlquery.newcontext('
  5              select cast(multiset(
  6                     select e.empno,e.ename,e.favorite_color
  7                       from emps e
  8                      where e.favorite_color = :COLOR) as employee_list_t)
"emps"
  9                from dual');
 10
 11    dbms_xmlquery.setbindvalue(qryctx, 'COLOR', 'plaid');
 12    :c := dbms_xmlquery.getxml(qryctx);
 13  end;
 14  /
declare
*
ERROR at line 1:
ORA-29532: Java call terminated by uncaught Java exception:
@ oracle.jdbc.driver.OracleSQLException: ORA-00907: missing
right parenthesis
ORA-06512: at "SYS.DBMS_XMLQUERY", line 255
ORA-06512: at "SYS.DBMS_XMLQUERY", line 264
ORA-06512: at "SYS.DBMS_XMLQUERY", line 254
ORA-06512: at line 12

If I hear anything I'll follow up with you, but again, Oracle Support will be
able to help you get info about bug priorities, timelines, patches, etc.

October 31, 2001 murlidhar -- Thanks for the question regarding "querries about SQL/Sql*Plus", version 8.1.5
You Asked
Hi Mr. Tom,

How R U?

This is Murlidhar, System Analyst.  Since last
6 Years I am using Oracle as backend (7.1/8/8i)

I am a Oracle Magazine reader & very very happy
that I am upgrading my knowledge. (Especially on
PL/SQL).

I have some querries about SQL/Sql*Plus.

I hope U will help me out.

1) Is there any way to prompt in SQL*Plus
   present working schema name ? (shall prompt
   user whenever connected to another schema).

   ex. : if connected to system then system>
         if connected to sys then sys>

   as in Unix pwd (present working directory)

2) Is there any way to set default Buffer width
   before login ?
   Bcauz, every time login, buffer width has to
   be changed.

3) Is there any way to create table temporarily
   for the logged in session without permanently
   creating table in the tablespace to avoid
   fragmentation. This data I want to use to do
   some work around. As soon as logged out, the
   created table shall not exist.

Anxiously awiting your quick response.

Thanking You,

With Warm Regards

Murlidhar
and we said...
Just a reminder to all -- please check your email address when you ask a
question.  If you leave off the domain, I cannot get in touch with you!

1)
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:446220075876
and
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:928829365838

2) you can setup a login.sql with SET commands.  If you set the environment
variable SQLPATH to point to the directory where you put the login.sql file,
plus will run it everytime you startup.

3) global temporary tables.  The table structure will exist (the definition of
the table) but the extents are allocated in temporary segments.

search for global temporary on my site for info.
Review & Followup
Rating: 3
March 24, 2001
Reviewer: murlidhar s mallya from Ahmedabad, Gujarat, India

Rating: 4
Read Tom's book! October 31, 2001
Reviewer: Lewis from Sioux Falls, SD, USA
I would suggest you read Tom's book Expert One-On-One before asking any
questions like this. The anwsers are there already!

November 01, 2001 sushant -- Thanks for the question regarding "how does this check constraint work", version 8.1.5
You Asked
i hav a check constraint on a date column

something lik this

create table datecheck(
  dt    date  check(dt between to_date('10-jan-99','dd-mon-yyyy')
                     and to_date('10-dec-99', 'dd-mon-yyyy')));

 if i give dd-mon-yy the constraint doesnt get created.

  the check constraint gets created if i use the way created above.

but whenever i try to enter the date it doesnt allow me to enter any of the
dates whether '10-jan-1999' or '10-jan-99' or '10-jan-2099'

but if i create the table say lik this

create table datecheck(
  dt    date  check(dt between to_date('10-jan-1999','dd-mon-yyyy')
                     and to_date('10-dec-1999', 'dd-mon-yyyy')));

everything works fine  . and the constraint works properly
and we said...
99 is a valid year with YYYY -- it is the perfectly valid year 0099 (99 AD).
You have a check constraint that says to accept dates only in the year 99.

It will not accept a check constraint with just 'YY' because the interpretation
of that constraint would be different if you created it in one century versus
the other (eg: in 1995, 'YY' applied to '99' is 1999.  In 2005, 'YY' applied to
'99' is 2099 -- its ambigous)

The year 2000 should have shown us all that using 2 character years is a BAD
idea, anywhere.

The constraint worked properly in all cases above -- you just didn't specify the
correct year with '99' (it did exactly what you told it to do)
November 01, 2001 Yong -- Thanks for the question regarding "Some BLOB Questions", version 8.1.5
You Asked
Hi, Tom,

I've been using your p procedure very happily. It cuts a long
string into pieces, unlike dbms_output.put_line:

procedure p(p_str in varchar2)
as
l_str long default 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;

Now I want to combine this with your

select
utl_raw.cast_to_varchar2(dbms_lob.substr(blob_col,2000,1))
from blobtable;

That is, I want to show *all* content of a BLOB column on
screen, in spite of its garbage-looking nature. Note I
want to see *all* not just the first 2000 characters.
(BTW, you said we can substr the first 4000. On my 8.1.5
database, I can only substr 2000, not 2001 or beyond.)

In fact, if there's a way to extract BLOB content into a file
in the file system, preferably using UTL_FILE, that would be
even better. Less importantly, is there any way to load a
binary file into BLOB using SQL*Loader? The Oracle manual for
SQL*Loader gives an example of loading CLOB which won't work
on BLOB for me. It's the example 5-13 at
http://technet.oracle.com/doc/oracle8i_816/server.816/a76955/ch05.htm
I like to use LOBFILE but I don't think I can use TERMINATED
BY EOF.

Thank you very much.

Yong Huang
yhuang@indigopool.com
and we said...
do this to get the first 4000:

ps$tkyte@8i> create or replace function blobtochar( p_blob in
blob ) return varchar2
  2  as
  3  begin
  4     return
utl_raw.cast_to_varchar2(dbms_lob.substr(p_blob,4000,1));
  5  end;
  6  /

Function created.

ops$tkyte@8i> select blobtochar(resume) from emp;

beyond 4000, cannot do it -- best we could do is write a stored
procedure to dump some blobs but only upto 1,000,000 bytes of
them.  Beyond that -- no go.  SQL won't let you go >4,000.

so, in sqlplus the ability to see the entire blob is not
available.

As for writing the file to the OS, not using UTL_FILE.  UTL_FILE
will not do a binary file.

Do you have a C compiler? what is your OS? Do you have Pro*C
Use Ask Tom to ask this if you want to persue it please...  I
can post an example of getting a lob to a file using an extproc.
 Java would work as well.

An example of using sqlldr to load a binary file is as follows.
You do use the terminated by EOF since you want to load the
entire file (load until EOF).  EOF is not a ^D or ^Z -- its "the
end of file".

I wrote a small C program:

void main()
{
int i;

        for( i = 0; i < 1000; i++ )
                printf( "%c", i%256 );
}

and ran it into allbytes.dat:

$ ./test > allbytes.dat

Then, I altered EMP to have a column "resume" of type blob and
using the following CTL file:

LOAD DATA
INFILE *
INTO TABLE EMP
REPLACE
FIELDS TERMINATED BY ','
( EMPNO    INTEGER EXTERNAL,
  ENAME    CHAR,
  JOB      CHAR,
  MGR      INTEGER EXTERNAL,
  SAL      DECIMAL EXTERNAL,
  COMM     DECIMAL EXTERNAL,
  DEPTNO   INTEGER EXTERNAL,
  RES_FILE FILLER CHAR,
  "RESUME" LOBFILE (RES_FILE) terminated by eof NULLIF RES_FILE
= 'NONE'
)

BEGINDATA
7782,CLARK,MANAGER,7839,2572.50,,10,allbytes.dat

loaded the data.  Now, in sqlplus I can see:

ops$tkyte@8i> select dbms_lob.getlength(resume) from emp;

DBMS_LOB.GETLENGTH(RESUME)
--------------------------
                      1000

it loaded all 1,000 bytes (and we know that it did not stop at
^D or ^Z since I put every ascii character in there).  Using
DUMP I can see that the data was input correctly:

  1* select dump(
utl_raw.cast_to_varchar2(dbms_lob.substr(resume,300,1)) ) from
emp
ops$tkyte@8i> /

DUMP(UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR(RESUME,300,1))
------------------------------------------------------------
Typ=1 Len=300: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,1
8,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,3
8,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,5
8,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,7
8,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,9
8,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113
,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128
,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143
,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158
,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173
,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188
,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203
,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218
,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233
,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248
,249,250,251,252,253,254,255,0,1,2,3,4,5,6,7,8,9,10,11,12,13
,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33
,34,35,36,37,38,39,40,41,42,43

All of the ascii codes are sequential from 0 on up -- as I
expected.  I get out what I put in.
Review & Followup
Rating: 3
SQL*Loader and BLOB October 31, 2001
Reviewer: Jo Sat from DC USA
Tom..Thanks for very detail answer.  I think to make it most useful, it would be
helpful if you could also explain the last 2 lines of the control script: the
RES_FILE ...
Thanks so much

Followup:
Sorry, thought that was somewhat obvious:

 DEPTNO   INTEGER EXTERNAL,
  RES_FILE FILLER CHAR,
  "RESUME" LOBFILE (RES_FILE) terminated by eof NULLIF RES_FILE = 'NONE'
)

BEGINDATA
7782,CLARK,MANAGER,7839,2572.50,,10,allbytes.dat

RES_FILE is a filler -- its not a column in the table I am loading.  Its just
there to hold whatever data is in the input load file (allbytes.dat in this
example).

RESUME is a LOB.  We are using the SQLLDR datatype
LOBFILE(sqlldr_variable_with_name_of_file) to cause the file named in RES_FILE
to be loaded into the LOB for us.  The file is a simple one, terminated by EOF,
not some file to be parsed specially...  If we loaded a record in the data input
stream with NONE were I have allbytes.dat -- the LOB would be NULL.

Rating: 3
Helpful response, but why is UTL_FILE so lame? November 01, 2001
Reviewer: Frustrated from USA
Your answer is very helpful. However, I marvel
every time I use UTL_FILE and realize how crummy it
really is. Why can't it read/write files of arbitrary
line lengths and file sizes? I breathe PL/SQL and write
Java with much less skill and efficiency. Yet silly restrictions in the
libraries given to PL/SQL force me elsewhere. The one or two C programs from
your site that
I've seen make use of Microsoft header files, which compels
me to install a Microsoft compiler, which I don't have. *sigh* Why can't I use
what I have -- Oracle?

Followup:
Well, UTL_FILE comments aside for a moment -- I'm at a loss to find a single
article on my site with a "windows only" header?  I write everything on Unix and
have to port it to NT.  Can anyone point me to an article here that has Windows
specific C and no Unix counterpart? (i searched for "include h" -- and couldn't
find one).

I'm somewhat insulted on that one ;)

To read anyfile, of any size and type -- BFILES with the dbms_lob pacakge work
great.  To write files -- it is true that UTL_FILE can only:

o create lines upto 32k in length.
o do TEXT IO -- no binary IO.
I don't have any solution for this beyond doing it in Java or C.  Fortunately,
these limits do not impact us very frequently.

November 01, 2001 Kasturi -- Thanks for the question regarding "Space Issues", version 8.1.6
You Asked
Hello Tom,

The below is the output of show_space.sql in my database for a table.

SQL> exec show_space('TABLE1');

Free Blocks.............................3
Total Blocks............................520
Total Bytes.............................2084864
Unused Blocks...........................25
Unused Bytes............................102400
Last Used Ext FileId....................8
Last Used Ext BlockId...................72325
Last Used Block.........................140

PL/SQL procedure successfully completed.

SQL> column segment_name new_val lob
SQL> select segment_name from user_lobs
  2  where table_name = 'TABLE1';

SEGMENT_NAME
------------------------------
SYS_LOB0000034916C00004$$

SQL> exec show_space('&lob',user,'LOB');
Free Blocks.............................41149
Total Blocks............................437343
Total Bytes.............................1791356928
Unused Blocks...........................25855
Unused Bytes............................105902080
Last Used Ext FileId....................8
Last Used Ext BlockId...................363494
Last Used Block.........................17345

PL/SQL procedure successfully completed.

The Block size is 4K and the chunk size of the LOB column is also 4K.
I have around 8000 rows in the TABLE.  My question is if the last used block is
17345 and unused blocks = 25855 and 41149 free blocks where are the remaing
blocks??????? Why does this situation arise inspite of my chunk size being equal
to 1 block size?

Q2) both my lob segment and table segments are on the same tablespace. ALTER
TABLE ... MOVE with new storage specifications has table level options. How do i
handle this LOB SEGMENTS???? If i were to handle LOB segments sizing only.

Thanks.
and we said...
Your lob segment is most likely in multiple extents.  You might have extents in
file 8, file 9, file 2, file N.  Even if all extents are in file 8 -- you might
have an extent from block 100000 to 100050, 500 to 600, 15000 to 18000.  This is
just telling you how far into the last extent you are.

You might want to ignore the "Last used".  It is just helpful in identifying
where the high water mark really physically exists (its in file 8 at that block
-- block 363494+17345)

This is normal and does not reflect on the space utilization at all-- last used
does not reflect on the space used.  There would only be a correlation between
the two if the object was in a single extent.

q2) this shows how:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x int, y clob );
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select object_type, object_name,
  2         decode( status, 'INVALID', '*', '' ) status,
  3             decode( object_type,
  4    'TABLE', (select tablespace_name from user_tables where table_name =
object_name),
  5    'INDEX', (select tablespace_name from user_indexes where index_name =
object_name),
  6    'LOB', (select tablespace_name from user_segments where segment_name =
object_name),
  7                                  null ) tablespace_name
  8  from user_objects a
  9  order by object_type, object_name
 10  /

OBJECT_TYPE  OBJECT_NAME                    S TABLESPACE_NAME
------------ ------------------------------ - ------------------------------
LOB          SYS_LOB0000018544C00002$$        SYSTEM

TABLE        T                                SYSTEM

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table t move tablespace p1_s1 lob(y)
store as ( tablespace p2_s2 );

Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select object_type, object_name,
  2         decode( status, 'INVALID', '*', '' ) status,
  3             decode( object_type,
  4                      'TABLE', (select tablespace_name from user_tables where
table_name = object_name),
  5                      'INDEX', (select tablespace_name from user_indexes
where index_name = object_name),
  6                      'LOB', (select tablespace_name from user_segments where
segment_name = object_name),
  7                                  null ) tablespace_name
  8  from user_objects a
  9  order by object_type, object_name
 10  /

OBJECT_TYPE  OBJECT_NAME                    S TABLESPACE_NAME
------------ ------------------------------ - ------------------------------
LOB          SYS_LOB0000018544C00002$$        P2_S2

TABLE        T                                P1_S1
Review & Followup
Rating: 4
Chunk Size Estimations September 24, 2001
Reviewer: Kasturi from US
Hello Tom,

Thanks for the reply. I was trying to find out why this particular table is
taking so much of space in the database with just 8000 rows in it.

So I used

alter table move ...
lob(y) store as (CHUNK 1024)... because the lob segment is storing email
attachments in it. But How do i really estimate what the perfect size of the
chunk is? But i cannot do this in a production environment.

Finally my question is How do i size a table with lob columns in it.

Followup:
the chunk size is always an even multiple of the blocksize..  If you have a 4k
block -- the minimum chunk is 4k.  chunks are allocated in blocks -- the data
from one lob will be on a block all by itself -- no other lob will be on the
same block, ever.

If the lobs are so small, smaller then 4000 bytes, you can have them stored
inline  .

In order to estimate the perfect chunk size you would need to know exactly how
big your data was.  In order to use the least space, use a chunk size that is
your blocksize.

To size a table -- see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:406873025890
...

Rating: 4
Varchar2 to CLOB migration October 31, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Tom,

We are changing some character columns to CLOB columns. We are aware of the
TO_LOB() function.

Regarding space management, we know about the ENABLE/DISABLE STORAGE IN ROW and
STORAGE clauses, as well as the behavior regarding 4000-byte issues.

The problem is that varchar2 is self-managed in terms of compression and
expansion.

However, with LOBs, it seems I have to approaches as to shrinking:

a) When the LOB is in-line, it will only shrink it by using the DBMS_LOB.TRIM
procedure.

b) When it's out-of-line, I must regard the LOB as any other segment, having to
explicitly deallocate extents.

Questions:

1) Am I correct as to a) and specially b) ?

2) I did not find a way to do this explicit deallocation. How is it done ?

3) Is there a chance that CLOB data will be "scattered" along it, so that there
will be "holes", as when I delete rows from a table ?

4) In the latter case, should I reorganize the data ? How to do it ?

Thanks for your holy patience !

Followup:
You don't need to_lob() to go from varchar2 to CLOB.  I simple update or insert
will do it.  In 9i, an even simplier "alter table modify" will do it.

Think of a LOB just like an OS file (the underlying mechanisms are really a file
system!).  When you write to a file and make it grow to 100m, it'll be 100m --
you can seek all over it and change bits and bytes here and there but its a 100m
file.  If you want to "shrink" it you can, if you want to grow it you can.  But
changing the DATA within has no effect on the size.  A lob is exactly the same
in this regards.

You have to use trim or set it equal to a different lob or string all together:

DOC>create table t ( user_id int, username clob );
DOC>
DOC>insert into t select user_id, username from all_users;
DOC>*/
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select user_id, username, dbms_lob.getlength(username)
from t where user_id = uid;

   USER_ID USERNAME                       DBMS_LOB.GETLENGTH(USERNAME)
---------- ------------------------------ ----------------------------
     46612 OPS$TKYTE                                                 9

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> update t set username = rpad('*',4000,'*') where user_id
= uid;

1 row updated.

ops$tkyte@ORA8I.WORLD> select user_id, dbms_lob.getlength(username) from t where
user_id = uid;

   USER_ID DBMS_LOB.GETLENGTH(USERNAME)
---------- ----------------------------
     46612                         4000

ops$tkyte@ORA8I.WORLD> update t set username = user  where user_id = uid;

1 row updated.

ops$tkyte@ORA8I.WORLD> select user_id, dbms_lob.getlength(username) from t where
user_id = uid;

   USER_ID DBMS_LOB.GETLENGTH(USERNAME)
---------- ----------------------------
     46612                            9

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> declare
  2          l_data varchar2(30000);
  3  begin
  4          l_data := rpad( '*', 30000, '*' );
  5          update t set username = l_data where user_id = uid;
  6  end;
  7  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> select user_id, dbms_lob.getlength(username) from t where
user_id = uid;

   USER_ID DBMS_LOB.GETLENGTH(USERNAME)
---------- ----------------------------
     46612                        30000

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> declare
  2          l_data varchar2(30000);
  3  begin
  4          l_data := rpad( '*', 3000, '*' );
  5          update t set username = l_data where user_id = uid;
  6  end;
  7  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> select user_id, dbms_lob.getlength(username) from t where
user_id = uid;

   USER_ID DBMS_LOB.GETLENGTH(USERNAME)
---------- ----------------------------
     46612                         3000

for example.  In plsql you can manipulate upto 32k of the lob like a string in
816/817.  it was 4000 bytes before that.

dbms_lob.trim is the way to explicitly "deallocate" the lob data (but you seem
to have found that already ?)

There is no chance of lob data being scattered.  It is allocated in chunks,
chunks are added at the "end" and as you trim back -- those chunks are freed.
You never "erase the middle" of a lob, you trim the end of it off.

Rating: 5
What about out-of-line LOBs ? October 31, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Thanks for your enlightment.

But, what about, say, a CLOB segment in a LOB_DATA tablespace ?

DBMS_LOB.TRIM() only works on in-line LOBS. Let us suppose it has INITIAL 1M and
NEXT 1M. It can grow up to 4GB. If I look for it in DBA_SEGMENTS, there it is,
so it is a segment, all right.

For example, if I continually update this CLOB column with bigger amounts of
data, the segment will grow.

Imagine there are "tons" of LOBS all around my database, always growing.
Varchar2s don't "overflow". CLOBS stop short only at 4 gigs and are more prone
to crowd my DB.

What is the best way to manage this expantion ? How can I deallocate the extra
extents ?

Followup:
where did you get the idea that dbms_lob.trim works on in-line lobs only?

ops$tkyte@ORA717DEV.US.ORACLE.COM> CREATE TABLE t       (x int, y clob)
  2  LOB ("Y") STORE AS (TABLESPACE "SYSTEM" DISABLE STORAGE IN ROW )
  3  /

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> declare
  2          l_data varchar2(32000) default rpad( '*',32000,'*' );
  3  begin
  4          insert into t values ( 1, l_data );
  5  end;
  6  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select x, dbms_lob.getlength(y) from t;

         X DBMS_LOB.GETLENGTH(Y)
---------- ---------------------
         1                 32000

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> begin
  2          for x in ( select * from t )
  3          loop
  4                  dbms_lob.trim( x.y, 2 );
  5          end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA717DEV.US.ORACLE.COM> select x, dbms_lob.getlength(y) from t;

         X DBMS_LOB.GETLENGTH(Y)
---------- ---------------------
         1                     2

The segment will not grow (well, it'll grow big enough to hold the lob and the
pctversion for the lob but thats it).  It will not grow wildly.  You can setup
very simple tests to see this.

CLOBS are ONLY as big as their length -- you divide your chunksize and take the
ceil of that to figure out how much space they are using.  Say its 65k with a
chunksize of 16k -- you will have 5 chunks of 16k allocated to hold that clob.
If you make the clob grow -- it'll use that much, if you trim it -- it'll GIVE
back the space onto the free list for this segment.

Clobs MAX OUT at 4 gig, they don't stop short.

I don't no where you are getting your information from but its wrong.  Its
managed just like a table -- if you insert rows and we grow the table, then you
delete them -- the space goes onto the freelist and will be used for the next
insert.  Clobs segments aren't much different from table or index segments in
this regards.

Rating: 4
Varchar2 to CLOB migration (contd) November 01, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Tom,

Sorry, I think I mixed up the concepts "internal" and "in-line". Below is an
extract from the Reference Guide:

TRIM Procedure
This procedure trims the value of the ***internal*** LOB to the length you
specify in the newlen parameter. Specify the length in bytes for BLOBs, and
specify the length in characters for CLOBs.

By internal, I understand LOBs stored in database tablespaces, as opposed to
LOBs kept in OS filesystems -- these would be "external".

So, ok, I can "trim" the LOB explicitly.

But, sorry about insisting... How to avoid LOBs staying too big ?

I'll try to give a clearer example of what I am thinking of.

Ok, you showed me that the "length" of the CLOB varies according to the length
of the string stored therein.

"abcd" --> length=4
"12345678901234567890" --> length=20
"x" --> length=1

But this metric is more of a "logical" nature.

If I insert, say, 1 meg, the CLOB will grow -- creating extents -- and the only
thing I can do to release space is by "trimming" it.

What I was looking for is some form of behavior like what happens to rollback
segments, which (should) srihnk when allocated space is not necessary any longer
-- which, in "logical" terms is what VARCHAR2 is supposed to do.

We here cannot afford (or would prefer not) to keep track of a LOB that is big
because some time in the past it contained a 2-gig string but now holds only ten
bytes.  In this case, it would maintain the old size (2 gigs) and the only thing
I could possibly do is a TRIM. Right ?

In sum, the expectation of us living-dead geeks in this cold dark office facing
sunny Copacabana beach is that the CLOB's  behavior would approach as much as
possible that of a humble VARCHAR2.

Thanks again !

Followup:
You can release the space back to the freelist for the segment not only by
trimming it but by:

o deleting the row
o setting the lob locator to empty_clob or null
o pointing the lob locator to new data.

I'm not getting whats so hard to see here.  Its just like rows in a table.  you
insert them, they take space.  You delete them and the block will go onto the
freelist for the table segement.

You insert a clob, it takes space from the lob segment.  You change their size
in any number of ways and their free space will go onto the freelist for that
segment.

If you HAD a 2gig lob and it is now a 2 byte lob, you will have 2gig free in
that log  segment for subsequent lobs that come along (ANY lob in that table
will reuse that space).

Look at it this way:  If you HAD a 2gig table and it is now a 2 byte table, you
will have 2 gig free in that table segment for subsequent inserts and updates
that come along...

You don't NEED trim.  If you

   update t set lob_col = 'xx' where id = 5

(using BIND variables of course in place of xx and 5) and lob_col used to be
2gig, and it is now 2 bytes -- thats it, it shrunk, space released, done deal,
over and out.

(so if you treat it like a varchar2 as I demonstrated over and over, you got
what you want)

OTOH if you:

   select lob_col into l_clob from t where id = 5 for update;

   dbms_lob.write( l_clob, 2, 1, 'xx' );

AND you want it to be 2 bytes (think about it, just because you wrote 2 bytes
doesn't mean the clob should be 2 bytes)  you will now need to trim it.
However, the comparision with the varchar2 is long gone, you've already used
dbms_lob.write.  Think how annoying it would be if dbms_lob.write trimmed the
data -- it would be *wrong*.

The cool thing is -- if you disagree, just write your OWN dbms_lob_write
subroutine that does exactly what you want.  No muss, no fuss.

Rating: 4
Varchar2 to CLOB migration (contd) November 01, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Tom, me again....

In the process of migrating varchar2's to CLOBS, I would not like to lose the
contents of the old varchar2 fields.

I am using a test database, and this will run on a production environment,
although there is little data in it -- not a "critical" issue.

What do you think of this ?

ALTER TABLE T ADD ( AUX CLOB );

UPDATE T SET AUX=TEXT; -- TEXT is the old varchar2 column

ALTER TABLE T DROP COLUMN TEXT;

ALTER TABLE T ADD ( TEXT CLOB );

UPDATE T SET TEXT=AUX;

ALTER TABLE T DROP COLUMN AUX;

I think the only major "collateral" effect of this is the new position of the
column.

( Tired of saying "thanks"... Obrigado ! -- that's in Portuguese ! )

Followup:
yes, that will work however since MOST programs (pre-oracle9i) will have to be
changed to some degree to accomidate the clob -- you might consider renaming the
column (skipping that last add and update).

Rating: 5
Varchar2 to CLOB migration (contd) November 01, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Tom,

I wrote a script for the review above:

-- Start of Script ----------------------------

set serveroutput on size 10000
set feedback off
set termout off
spool change_clob.sql

begin
for rt in ( select table_name,column_name, data_length
        from user_tab_columns
        where data_type='VARCHAR2' and
            data_length=4000 ) loop

dbms_output.put_line('-- Tabela '||rt.table_name||' / Coluna:
'||rt.column_name);

dbms_output.put_line('ALTER TABLE '||rt.table_name||' ADD ( AUX CLOB );');

dbms_output.put_line('UPDATE '||rt.table_name||' SET
AUX='||rt.column_name||';');

dbms_output.put_line('ALTER TABLE '||rt.table_name||' DROP COLUMN
'||rt.column_name||';');

dbms_output.put_line('ALTER TABLE '||rt.table_name||' ADD ( '||rt.column_name||'
CLOB );');

dbms_output.put_line('UPDATE '||rt.table_name||' SET
'||rt.column_name||'=AUX;');

dbms_output.put_line('ALTER TABLE '||rt.table_name||' DROP COLUMN AUX;');

dbms_output.put_line('--');

end loop;

end;
/

spool off
set feedback on
set termout on

-- End of Script ----------------------------

I know I could have used EXECUTE IMMEDIATE, but I had to have an output script
generated.

Extract from output script:

--

-- Tabela TB_TVG_TLN_FA_CLUBE / Coluna: DE_TXT_FA_CLUBE_TXT

ALTER TABLE TB_TVG_TLN_FA_CLUBE ADD ( AUX CLOB );

UPDATE TB_TVG_TLN_FA_CLUBE SET AUX=DE_TXT_FA_CLUBE_TXT;

ALTER TABLE TB_TVG_TLN_FA_CLUBE DROP COLUMN DE_TXT_FA_CLUBE_TXT;

ALTER TABLE TB_TVG_TLN_FA_CLUBE ADD ( DE_TXT_FA_CLUBE_TXT CLOB );

UPDATE TB_TVG_TLN_FA_CLUBE SET DE_TXT_FA_CLUBE_TXT=AUX;

ALTER TABLE TB_TVG_TLN_FA_CLUBE DROP COLUMN AUX;

--

-- Tabela TB_TVG_TLN_FA_CLUBE / Coluna: DE_INFO_ADIC_FA_CLUBE_TXT

ALTER TABLE TB_TVG_TLN_FA_CLUBE ADD ( AUX CLOB );

UPDATE TB_TVG_TLN_FA_CLUBE SET AUX=DE_INFO_ADIC_FA_CLUBE_TXT;

ALTER TABLE TB_TVG_TLN_FA_CLUBE DROP COLUMN DE_INFO_ADIC_FA_CLUBE_TXT;

ALTER TABLE TB_TVG_TLN_FA_CLUBE ADD ( DE_INFO_ADIC_FA_CLUBE_TXT CLOB );

UPDATE TB_TVG_TLN_FA_CLUBE SET DE_INFO_ADIC_FA_CLUBE_TXT=AUX;

ALTER TABLE TB_TVG_TLN_FA_CLUBE DROP COLUMN AUX;

The rest of the script ran ok, but I got:

ALTER TABLE TB_TVG_TLN_FA_CLUBE DROP COLUMN DE_INFO_ADIC_FA_CLUBE_TXT
*
ERRO na linha 1:
ORA-00955: name is already used by an existing object

ALTER TABLE TB_TVG_TLN_FA_CLUBE ADD ( DE_INFO_ADIC_FA_CLUBE_TXT CLOB )
                                      *
ERRO na linha 1:
ORA-01430: column being added already exists in table

UPDATE TB_TVG_TLN_FA_CLUBE SET DE_INFO_ADIC_FA_CLUBE_TXT=AUX
                                                         *
ERRO na linha 1:
ORA-00932: inconsistent datatypes

After that, I have:

anasser@GLBVIG> desc TB_TVG_ENT_EPISODIO
 Nome                                                        Nulo?    Tipo
 ----------------------------------------------------------- --------
------------------------------
 CD_EPISODIO_ID                                              NOT NULL NUMBER(38)
 CD_SITE_ID                                                  NOT NULL NUMBER(38)
 DE_TITULO_EPIS_TXT
VARCHAR2(100)
 DT_EXIBICAO_EPIS_DATE                                                DATE
 DE_RESUM_EPIS_DESTAC_TXT
VARCHAR2(2000)
 CT_PUBLICADO_REG
VARCHAR2(1)
 DT_PUBLICADO_DATE                                                    DATE
 DE_TXT_COMPLT_EPIS_TXT                                               CLOB

I tried to look it up, but I got no clue...

Do you any idea what might be wrong ?

Followup:
don't know whats happening to you -- you are altering a totally different table
then you describe and all.  I ran this and it worked just dandy:

ops$tkyte@ORA717DEV.US.ORACLE.COM> @test
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> drop table t;

Table dropped.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t ( x int, text varchar2(4000)
);

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t values ( 1, 'hello world' );

1 row created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> set echo off
ops$tkyte@ORA717DEV.US.ORACLE.COM> @change_clob
ops$tkyte@ORA717DEV.US.ORACLE.COM> -- Tabela T / Coluna: TEXT
ops$tkyte@ORA717DEV.US.ORACLE.COM> ALTER TABLE T ADD ( AUX CLOB );

Table altered.

ops$tkyte@ORA717DEV.US.ORACLE.COM> UPDATE T SET
  2  AUX=TEXT;

1 row updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM> ALTER TABLE T DROP COLUMN
  2  TEXT;

Table altered.

ops$tkyte@ORA717DEV.US.ORACLE.COM> ALTER TABLE T ADD ( TEXT
  2  CLOB );

Table altered.

ops$tkyte@ORA717DEV.US.ORACLE.COM> UPDATE T SET
  2  TEXT=AUX;

1 row updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM> ALTER TABLE T DROP COLUMN AUX;

Table altered.

ops$tkyte@ORA717DEV.US.ORACLE.COM> --
ops$tkyte@ORA717DEV.US.ORACLE.COM> set echo off

Rating: 5
Andre - Bug November 01, 2001
Reviewer: A MetaLink User from USA
Andre:

Check out bug #1769244 in MetaLink... it may be relevant.

November 01, 2001 Naveed -- Thanks for the question regarding "FGAC and batch jobs", version 8.1.6
You Asked
We have an application which will have FGAC at the database level. We also need
to provide for batch process job which must not have FGAC on the database.

The solution we adopted was to have views of all the tables, and apply FGAC to
these. The batch job will work on the tables directly, and the application will
run off the views.

Was this the right approach? We did this because we thought that since the batch
process has access to entire data set, the extra predicate clause which FGAC
provides will slow down processing.

Thanks alot.
Naveed.
and we said...
You could have just run the batch jobs as "BATCH_USER" and had the predicate
policy function have code like:

   if ( user = 'BATCH_USER' )
   then
      return null;
   else
      logic that currently exists
   end if;

just as easily.
Review & Followup
Rating: 4
predicate clause October 24, 2001
Reviewer: Naveed Amin Khan from West Des Moines, IOWA
We were concerned about the return NULL which would be added to every query.
Would this not have any impact on performance?

Thanks again.

Followup:
No, not any measurable impact.

If you are worried about it -- benchmark it (it is in fact what I would do).
Remember

1) it only affects the first parse of the query in a session
2) it returns no predicate so the run time execution of the query is totally
unaffected

Your way will work as well.  In 9i, there is a new system privelege as well that
you can grant to a user to disable FGAC all together.  That will be another
option for you in the future.

Rating: 3
Sorry - what FGAC? October 24, 2001
Reviewer: Doug from CT, USA
Sorry - what FGAC? I'm pulling an acronym blank.

Followup:
FGAC = Fine Grained Access Control

Aka VPD = Virtual Private database
Aka DBMS_RLS = Row Level Security

See
http://osi.oracle.com/~tkyte/article2/index.html
for examples.

Rating: 4
October 25, 2001
Reviewer: jose from NJ USA
Impementing the VPD, does it slow down the system since it dynamically add the
predicate?

After implementiong VPD(FGAC), we have found that some of the indexes are not
used and the performace is really bad and also functions like count(*) ,
min(value) etc work on some tables ignoring the VPD predicate  but the select
columns adhere to the VPD predicate.
Is it a bug?

Followup:
VPD byitself will NOT slow down the system.

The queries you generate using VPD may not perform as well as the queries you
generated BEFORE VPD.

See:
http://osi.oracle.com/~tkyte/article2/index.html
for how this all works conceptually (or I have a large chapter on this in my
book).

Now, a query like:

select * from emp, dept where dept.deptno = emp.deptno;

Might be processed using VPD as:

select *
  from ( select * from emp where <your condition> ) emp,
       ( select * from dept where <your condition> ) dept
 where dept.deptno = emp.dept;

If that query run without VPD goes slow -- the query with VPD will go slow.  You
just must tune to make sure the rewritten queries are ABLE to use the indexes
you have in place.  Just rewrite your query with the predicates in inline views
like I did -- disable FGAC and see how they perform.  If they go slow then,
they'll go slow later with VPD!  That is all VPD does -- it rewrites the queries
with inline views.

As for it being ignored, I'll say it simply "I don't believe you".  You are
making some mistake or have some misunderstanding somewhere.  If you post a test
case that proves your point, I'll tell you why its doing what it is doing.

Rating: 3
aggregate function problem October 26, 2001
Reviewer: jose from NJ US
I had started aTAR - 1635851.995 for the VPD problem.
here is the code I sent for that TAR

CLT21197_QUERY@PMIM> select * from rp_run_control;
no rows selected

CLT21197_QUERY@PMIM> select count(*) from rp_run_control;
COUNT(*)
----------
39
CLT21197_QUERY@PMIM> select min(clt_client_id) from rp_run_control;
MIN(C
-----
84486
CLT21197_QUERY@PMIM> select min(clt_client_id) from rp_run_control where
clt_client_id = '84486';
MIN(C
-----
84486
CLT21197_QUERY@PMIM> select * from rp_run_control where clt_client_id =
'84486';
no rows selected
CLT21197_QUERY@PMIM>

I have the list of steps I have taken to enable the VPD.
Please check the TAR on metalink for those details.

Followup:
I've looked at you example and think your specific issue stems from the code:

 10          IF SYS_CONTEXT('USERENV','SESSION_USER') = 'COMMON'
 11             OR SYS_CONTEXT('USERENV','SESSION_USER') = 'SYSTEM'
 12             OR SYS_CONTEXT('USERENV','SESSION_USER') = 'CLTCROSS_APP'
 13             OR SYS_CONTEXT('USERENV','SESSION_USER') = 'DBLOGIN'
 14             OR SYS_CONTEXT('USERENV','SESSION_USER') = 'CLTCROSS_QUERY'
 15          THEN
 16              v_predicate := NULL;

Now you didn't give a full test case or really good directions on how to run it
(eg: create this as this user and that as this other user and run this query as
this user type of stuff) so I was not able to reproduce but I believe the issue
is in the above.

I like to fully instruement my FGAC policies with LOTS of debug so I can turn on
a trace and see what they are doing (see
http://osi.oracle.com/~tkyte/article2/index.html
for a simple debug package to do that).  Odds are -- depending on the code path
-- sys_context( 'userenv', 'session_user' ) is NOT returning what you expect.
The reliable way to use that would be:

   select sys_context( 'userenv', 'session_user' ) into l_session_user
     from dual;

   if ( l_session_user in ( 'USER1', 'USER2', ...... ) )
   then
          return null;
   else
          ......

You want to force a context switch to the RDBMS kernel to ensure the USERENV
context is set correctly.

Make that subtle change (and add LOTS of debug) and see what happens.  If it
persists, please feel free to post here a FULL test case (specs AND bodies, full
create users, connect statements to install the code and tell us who runs what
and when -- the WHOLE thing we can just run)

Rating: 3
aggregate problem November 01, 2001
Reviewer: jose from NJ usa
I implemented VPD on 4 instances. Everything works fine except on one. I have
problem with the aggregate function on 10 tables. I droped one of the tables and
recreated and populated with the same data. The VPD works fine on that table.
But I just can't go on recreating tables.
What could be the problem for the recreated table to work fine? Is there a view
or dd table where I could look to find which table has the policy set. and what
policy (instead of goind thru the code to implement the VPD).

You want to force a context switch to the RDBMS kernel to ensure the USERENV
context is set correctly.

the AFTER LOGON trigger should be setting the context right?
howelse should I be doing it?

after debuging, I still have the problem with 9 tables with the aggregate
function.

With regard to system performance being slow, I am getting the data ready and
also the trace files (tkprof) .

Followup:
select sys_context( 'userenv', 'variable') into l_varible from dual;

that is what i meant by "You want to force a context switch to the RDBMS kernel
to ensure the USERENV context is set correctly."

Make sure by debugging you mean adding DEBUG statements into your code, dump
everything out -- the values of all of the variable.  I don't want a tkprof
trace -- you need to dump your program state.  print out the where clause you
are returning and all variable values that lead you to that decision.

November 02, 2001 M -- Thanks for the question regarding "Import/Export between UNIX and NT", version 8i
You Asked
I did a export from our UNIX(Solaris) 8i database. I would like to know if I can
use this exp data file to do a import into a NT 8i database.

More general question: Can we do a export/import between different platform
oracle databases if assume they are same version ?

Thanks for your help.
and we said...
Yes, export dmp files are portable.  Make sure to BINARY ftp them!

You can go to/from NT/Unix/OS390/whatever.
Review & Followup
Rating: 3
November 02, 2001
Reviewer: Nikunj Thaker from Ahmedabad, India
i can't get

 Make sure to BINARY ftp them!

Followup:
If you ftp a file from UNIX to NT -- NT will mess it up by turning all linefeeds
(ascii 10) into carriage return/linefeeds (ascii 13/ascii 10).  The file will be
a different size and contain different data.  It will be corrupt.  Going the
other way from NT to Unix, you will find the cr/lf pairs become lf's.

In order to not have this happen, you issue:

ftp> binary

before sending or recieving a binary file.  Now no such conversion takes place.

November 03, 2001 Sriram -- Thanks for the question regarding "Data Replication", version 8.1.6
You Asked
Hi Tom ,

I follow your column Regularly. It provides wonderful guidance to all us DBA's.

My question is I have Two databases (Ver 8.1.6)in winNT . one is the Master
database and the other is the slave database. I want to keep the slave database
in synch with the master ( All new inserts,updates,deletes from master come to
slave ) .Also I want to make insert ,update, delete  in the slave database which
will be restricted to slave database itself.

Let us say master table has tables t1,t2,t3,t4..... tn . The copy site will have
exactly same tables t1,t2,,,,tn. I want all new transactions from master
replicated in the copy site with the catch that the data in copy site can be
altered (insert ,update, delete in tables t1,,,,tn in copy site ).

can I use Data Replication for this . If yes please let me know how to do it.

Thanks

Sriram
and we said...
You can copy T1... TN from master to "slave".

If "slave" modifies them - these changes MUST be propagated to master.

"slave" can have OTHER tables -- tables other then t1, ... tn and it can read
and write these tables independent of "master".

That is what you would do, copy t1...tn for READ only and have other tables you
use for your writes on "slave" since you do not want them to goto master.

You could achieve what you wanted if you reveresed the roles.  If master became
slave and slave become the master then:

o you would add a column to each each, this column would be maintained via a
trigger, the trigger would put in the global database name in this column --
either COPY_SITE or MASTER_SITE

o the copy site would copy "select * from t1 where originating_site =
'COPY_SITE'"

o Now, any row inserted on the COPY_SITE would be only on copy_site.  rows
inserted on master_site and copy_site would be on the master site

In that fashion you can do what you want.  You just need to reverse the flow.
November 04, 2001 Subrata -- Thanks for the question regarding "Are stored procedure really smarter than anonymous block in context of soft parsing.", version 8.1.6
You Asked
PL/SQL caches the parse tree of Stored procedure for the life span of a session,
but this caching does not occur in case of anonymous block. This results in soft
parsing of SQL statements for anonymous block.
Consider a long session within which a analyze is performed which gathers new
statistics which in turn affects the optimization plan of SQL statements. Does
it mean than PL/SQL which cached the parse-tree "smartly" for stored procedure
has the risk of using stale execution plan?

Could you please explain in more in-depth about what actually happens during
soft-parse. I have explored your site but I expect to learn more indepth about
it.

Thanks
and we said...
who says?  Every time you execute a stored procedure you BY DEFINITION are doing
an anonymous block!

Also, query plans are not part of the "parse tree" for PLSQL -- they are stored
separately in the shared pool.  PLSQL executes SQL in the same way Java with
JDBC or Pro*C with embedded SQL would.  If you run a procedure, PLSQL will
submit the SQL text to the database engine for parsing and compilation and all.
If you do something to invalidate the plan, the cursor will be invalidated in
the cursor cache just like any other cursor would be. It'll not be using a
"stale" plan.  It'll be using the same plan one would use if they submitted the
sql from the sqlplus command line.

Soft parsing is just a faster "hard parse".  We take the sql query, generate the
hash for it (hash the text into a number), find the statements in the shared
pool that have that hash  and then compare the remaining bits of the environment
with the query found in the shared pool (making sure the settings for things
like sort_area_size, optimizer_goal, and so on are the same -- so the plan is
reusable, making sure the security attributes are the same -- so we have access
to the data, making sure the objects referenced are the same (eg: "select * from
t" run by you might be accessing a different table the "select * from t" run by
me).  So, we do less work when we only have to soft parse (we can skip
optimization for exmaple) but we still do lots of work (and thats why you want
to soft parse instead of hard parse but you still want to soft parse as little
as possible)
November 04, 2001 Milos -- Thanks for the question regarding "Is it possible to find column name from column number in ORDER BY clause?", version 8.0.6.0.0
You Asked
Hi. Let's say I have a PL/SQL stored procedure, where I use variable Cquery.

[1]  cQuery :=
     'SELECT first_column, second_columnd, third_column
      FROM table
      WHERE '||condition||'
      ORDER BY first_column';

cQuery is passed to another procedure, which writes HTML table, and where
I want to sort data by user-specified parameter "number_of column". User
clicks column title in HTML table, this procedure is called and data is
sorted by that column, as shown in [2].

[2]  new_cQuery := 'SELECT FROM ('||cQuery||') ORDER BY '||number_of_column;

My question is:
*Is there any way to obtain column name from  number_of_column  in ORDER BY
clause?*

I ask this because I noticed a problem.
Let's say I have to set HTML link and print it to output, like this.

cQuery :=
'SELECT ''<a href="proc?par=''||age||''">''||name,
        nick,
        address
FROM table
WHERE '||condition||'
ORDER by nick';

Now, if user wants data to be sorted by name, he clicks it, parameter
number_of_column=1 is passed to a procedure, where I use query [2]. In this
way, data will not be sort by name, but by  everything before first comma,
more precisely by   '<a href="proc?par='||age||'">'||name,   and I want
it to be sorted by first_column TYPE, not by this whole string.

Any ideas, suggestions?
Thanks.
and we said...
Getting the name here wouldn't help you at all.

See, if the query is:

'SELECT ''<a href="proc?par=''||age||''">''||name,
        nick,
        address
FROM table
WHERE '||condition||'
ORDER by 1';

Well, the first column in that query is NOT "name" its that big string.  We have
no way to tell you "you want to sort by the name column".  For example -- both
AGE and NAME are in that string -- two different database columns.  Why wouldn't
we return to you AGE instead of NAME ?

So, you see there is no way for us to tell you you want to sort by name cause
there is nothing in that query that indicates you want to sort by name!  Also,
if you alias the column:

select empno || ' ' || ename ename from emp order by ename

that won't help either -- that'll sort by "empno || ' ' || ename", not by ename
itself cause ename no longer exists (you renamed it).

you'll need to modify your generic routine to take not only a QUERY but a list
of column titles (probably already are) and a list of corresponding fields to
order by.

Eg: you might pass:

Employee Name|Nickname|Home Address  (column headings)
name|nick|address                    (column names)

Now, when they pass the number_of_column to you, you take that number and that
string and do this:

scott@ORA806.WORLD> variable cnames varchar2(30)
scott@ORA806.WORLD> variable number_of_column number
scott@ORA806.WORLD> exec :cnames := '|name|nick|address|'; :number_of_column :=
2;

PL/SQL procedure successfully completed.

  1  select substr(:cnames, instr(:cnames,'|',1,:number_of_column)+1,
  2         instr(:cnames,'|',1,:number_of_column+1)-
instr(:cnames,'|',1,:number_of_column)-1)
  3*                       from dual
scott@ORA806.WORLD> /

SUBSTR(:CNAMES,INSTR(:CNAMES,'|'
--------------------------------
nick

so, that returns what you really want to order by.

I have to say though, I'm really concerned by what I see here.  There is no
chance you are using bind variables!!!!  None at all!!!  That is horrible, I
hope you don't use this very often, it will kill your performance, your
scalability and your chances for success long term!  You really should rethink
your approach.  Generic code is great, when it doesn't KILL performance (which
this will)
November 04, 2001 Bathula -- Thanks for the question regarding "Java Pool in Oracle 8i", version Oracle8i(Version 8.1.5)
You Asked
Hi,
We do not have any peace of code which has ben written in Java that is we used
exclusively SQL and PL/SQL for application development. My query is as we do not
have any java component in our application do we need to main the java_pool in
the
database? following are the values form init.ora file.
Shared_pool_size=46926848,
large_pool_size=35389440 and
java_pool_size=20971520

Expecting a early reply.

Thanks & rgds
Mallik
and we said...
The java_pool_size must be set to 1meg (1048576) at a minimum.

Even if you do not use java -- we do internally in some places.  So, while you
do not need 20m as you have perhaps -- you will need at least 1meg.
Review & Followup
Rating: 3
java pool size November 04, 2001
Reviewer: Ak from India
Hi tom,
  can You tell me what exactly You will be using it
"INTERNALLY...AS YOU SAID" even if my application doesn't usees JAVA ???

THANKS
  REGARDS
    AK

Followup:
if you use certain services in the database, for example the supplied package
UTL_TCP, you will be using the java engine.

You might not code java, but some things are in java in the database. that is
what I meant.

Rating: 3
i set java_pool_size=0 in init.ora file November 05, 2001
Reviewer: Simone from Italy
I Set java_pool_size=0 in init.ora file.Startup database.Database start and the
value of java_pool_size is 32768 bytes. Why does this value is out of range
(1Mb-1Gb)?

Rating: 5
And more so in 9i November 05, 2001
Reviewer: Connor from UK
You'll see *more* Java in 9i (for example, on create-table triggers and the
like, which needed a java pool of more than 1m), so factor that in when sizing
your database parameters

Cheers
Connor

Rating: 5
The future of Java and Oracle... November 05, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Tom,

I would like to ask you some "phylosophical" questions regarding Java in the
database.

We saw OODBMS object types being introduced in Oracle8. After that, in 8i there
was Java in the database, with JVM, Java Beans, IIOP, etc. Besides, we can
"publish" this Java code into PL/SQL function/procedure format. Some people I
know and I myself have a feeling that this mixture of both languages "as is" is
somewhat of a "dity" piece of code.

In most high-budgets projects I follow up, I notice project analysis being
carried ou using an OO approach, like UML, but the database design winds up in
relational model.

Questions:

1) What do you beleive will be the trend of Java and PL/SQL in the database ?
PL/SQL is a simpler to user, but more poweful language. Do you think they will
"live together" in the database and decision upon which language to use will be
a project decision -- like speed of development (PL/SQL) X code power (Java) ?

2) Do you share the vision that PL/SQL will be deprecated in a future version of
Oracle and development will be mainly done in Java ? Or at least it will take
the place of PL/SQL as the "native" Oracle language, with the PL/SQL engine
being a legacy component ? For example, the java pool might incorporate the
importance of today's shared pool ? It is important to notice that Java HR's
will be more expensive, harder to find especially because of the language
complexity.

3) (Other Topic) I was thinking of buying your book, based on the degree of
excellence of what is discussed here. Does your book cover 9i ? If not, are you
planning another edition ?

Thanks for your attention !

Rating: 5
Continuing ... November 05, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
4) When do you think OO databases will be more  consolidated and more "accepted"
be the marketplace ? Do you think the relational model will persist still a long
time ?


Subject | Article | Last Updated (East coast time)
ROLLBACK SEGMENT ALLOCATION | article only | Nov 05, 2001 08:31 am
Encryption Key Protection ,,, | article only | Nov 05, 2001 08:43 am
Select by Group with different Date | article only | Nov 05, 2001 09:14 am
Options for restoring an individual table | article only | Nov 05, 2001 01:11 pm
SQL update in one statement | article only | Nov 05, 2001 06:34 pm
PLS-00231 | article only | Nov 05, 2001 06:37 pm
Deferrable Constraints | article only | Nov 05, 2001 06:44 pm
Primary Key vs no primary key | article only | Nov 06, 2001 08:07 am
How to re-open a closed database without shutdown DB ? | article only | Nov 06, 2001 12:46 pm
Concurrent users in the database. | article only | Nov 06, 2001 03:41 pm
Contention | article only | Nov 06, 2001 07:48 pm
extent sizing | article only | Nov 06, 2001 07:53 pm
Package variable inside sql statement | article only | Nov 06, 2001 08:19 pm
Qestions about chapter 21 of your book | article only | Nov 07, 2001 06:38 am
Length function | article only | Nov 07, 2001 06:40 am
How can I get a users password | article only | Nov 07, 2001 06:43 am
Mass Loading BLOBs into a database | article only | Nov 09, 2001 10:23 am
Opening a database after close | article only | Nov 09, 2001 10:37 am
Cursor in Sql Plus | article only | Nov 09, 2001 11:26 am
Reset rownum | article only | Nov 09, 2001 01:20 pm
how to compare two reports content | article only | Nov 09, 2001 01:25 pm
Date Conversion | article only | Nov 09, 2001 02:33 pm
Trigger for Alter Table | article only | Nov 09, 2001 04:57 pm
"Session based synonyms" under Oracle 9i? | article only | Nov 09, 2001 05:16 pm
HTML form in PL/SQL | article only | Nov 10, 2001 09:23 pm
Passing array from C to plsql | article only | Nov 11, 2001 10:03 am
Does ASkTom search dialog have a bug? | article only | Nov 11, 2001 10:24 am
raise_application_error and order by in a sequence and vsize | article only | Nov 11, 2001 12:31 pm
Object Relational Database Management | article only | Nov 11, 2001 05:19 pm
row(s) 1 - 29 of 29
November 05, 2001 paul -- Thanks for the question regarding "ROLLBACK SEGMENT ALLOCATION", version 8.0.5
You Asked
Thanks in advance for accepting this question
I have a rollback tablespace of 128m with 16 rollback segments (optimal size
4m,initial 2m, next 2m,min 2,max 121)
I am trying
to run the following cursor loop
DECLARE
  casenum char(8);
  counter number := 0;
  CURSOR DEL_LOOP is
  select sfam_case_num from sfam_family
  where mod(to_number(substr(sfam_case_num,3,6)),7)+1 = 1;
BEGIN
   set transaction use rollback segment RB01;
   open DEL_LOOP;
    LOOP
    FETCH DEL_LOOP into casenum;
    exit when DEL_LOOP%notfound;
    delete from sfam_family
      where sfam_case_num = casenum;
    counter := counter +1;
    if counter = 500
    then
     commit;
    counter := 0;
   end if;
      END LOOP;
    commit;
end;
The first 64m of the tablespace is taken up by the 16 rollback segments with an
optimal size of 4m
Executing  the cursor  with (if counter line @ 500 ) causes about 30m of
rollback to be created before the commit
Some where in the 3rd trip through the loop I can not create any more rollback
extents because I have exceded the tablespace
After each commit the next trip through the loop assigns a new rollback segment
but does not shrink the old one
It appears to me that a rollback segment is not shrunk until it is assigned
again and because I have 15 to go through
before I will resuse that segment I always excede the tablespace.
If  I change the (if counter line to 50) this creates less than 4m of rollback
which allows me to wrap through the 16 rollback segments without increasing the
tablespace
My question...    Is there any way I can either shrink the rollback segments
after the commit or force the same rollback segment to be used with each new
delete transaction
and we said...
Yuck -- i don't like your approach to rollback segment management.

First -- 4m is probably way too small here for rbs, 2 extents, way way small.  I
personally like to run with 10 or more 25m rollback segments that each have 25
1meg extents and can grow to 121 or so meg in size.  I never use "optimal",
preferring to shrink them myself if need be.

Second, using "use rollback segment" is (in my opinion) a terrible thing to do.
It means you are trying to skimp on rollback -- thinking you can "save some
resource".  In fact, it always leads to the sort of heartburn you are
experiencing now in my experience.

You don't really want what you are asking for either.  Lets say you were
successful and you forced the RBS to shrink.  Weeelllll you are committing in a
cursor for loop AND the cursor you are committing across is a query against the
table you are modifying.  You will have released the rollback data YOU YOURSELF
need in order to complete the query.  In order to get the consistent read on the
SELECT against SFAM_FAMILY, you will most likely need the rollback data you are
generating.  If we did release it -- instead of running out of rollback -- you
would get an ORA-01555.

If you have access to my book -- i go into this topic in great detail, the whole
redo/rollback process,  ora-01555, and so on.  committing in a cursor for loop
is a sure fire way to do it.  Or search for ora-01555 on this site to read about
it.

here is your "quicky fix" (but I don't like it, should just size RBS for the
jobs you do and be done with it.)

  loop
       set transaction use rollback segment rb01;
       delete from sfam_family
        where mod(to_number(substr(sfam_case_num,3,6)),7)+1 = 1
          and rownum <= 500;

       exit when sql%rowcount = 0;
       commit;
  end loop;
That'll delete 500 cases at a time, using the same rbs that you grow to 30 meg
each time.  It does not keep any cursors open across the commit, hence it won't
be "ora-1555'ing" itself either.
November 05, 2001 Venkatesh -- Thanks for the question regarding "Encryption Key Protection ,,,", version 8.1.7
You Asked
Hello ,
            We are trying to partially encrypt data in our database , for that
reason I propose to use the encryption toolkit that comes along
with Oracle .Here is the example .

declare
var1 varchar2(220);
var2 varchar2(255);
begin
for c in (select * from pass) loop
var2:=rpad(c.password,(trunc(length(c.password)/8)+1)*8,chr(0));
--dbms_output.put_line(length(var2));
dbms_obfuscation_toolkit.desencrypt(input_string=>var2,key_string=>'asdf%&^&%&@#a
sdf',encrypted_string=>var1);
update pass set enc_pass=var1 where username=c.username;
end loop;
end;

Similarly I have a function that decrypts the data .

My question , how do I protect this key thats supplied to the function . Any
user can very well get to the Function Text from the User_source View and simply
decrypt the data . The encryption Decryption process will be handled thru the
Application(JSP in this Case) , so when I am going to call this functin thru the
Application , the call shall have the KEY too . This way access to the encrypted
data becomes very transparent, one can always open the JSP code to look into the
Key Value. Can U please suggest ways of using this encryption process the proper
way .
Can U please send me some links on implementing SSL in the database .

One more question

select * from emp e where comm = (select comm from dept d where
e.deptno=d.deptno);
At first this query looked incorrect to me , but it works .
Can U please explain ?
Thanx As always

R.Venkatesh
and we said...
wrap the code.  Look up the WRAP utility in the PLSQL guide, its documented
there.  It will obscure the code.  The key will be there, but you won't be able
to point to it and say "look, there is the key".

for example, if you put this into test.sql:

create or replace procedure p
as
var1 varchar2(220);
var2 varchar2(255);
key  varchar2(255);
begin
  key :=
   chr(97) || chr(115) || chr(100) || chr(102) || chr(37) || chr(38) ||
   chr(94) || chr(38) || chr(37) || chr(38) || chr(64) || chr(35) ||
   chr(97) || chr(115) || chr(100) || chr(102);

for c in (select * from pass) loop
var2:=rpad(c.password,(trunc(length(c.password)/8)+1)*8,chr(0));
dbms_obfuscation_toolkit.desencrypt(input_string=>var2,key_string=>key,encrypted_
string=>var1);
update pass set enc_pass=var1 where username=c.username;
end loop;
end;
/

and then issue

wrap iname=test.sql

and edit test.plb, you will not be able to get the key back out (that is your
key).

See the ASO network guide for SSL info.
http://technet.oracle.com/doc/oracle8i_816/network.816/a76932/toc.htm
That correlated subquery is just fine -- it returns every row in emp that has a
row in dept.  It is like you code:

  for x in ( select * from EMP )
  loop
         for y in ( select X.COMM from dept where dept.deptno = X.DEPTNO )
         loop
            if ( X.COMM = Y.COMM ) -- well, of course it will, they are the same
            then
                output X
            end if;
          end loop
  end loop;

You just did a correlated subquery -- just like you "passed" e.deptno to the
subquery, you passed e.comm as well.
Review & Followup
Rating: 5
Storing the Keys in the Database December 09, 2003
Reviewer: Paddy McKenna from N Ireland
Tom,

I have read the section in your book regarding Key Management (Storing the Keys
in the Same Database).  I have a requirement to hold credit card details, these
need to be encrypted in the database.  I am also going to store the Key in the
same database.  Have you got a worked example I can use as a template to build
this as securely as possible

Versions
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production

Thanks

November 05, 2001 Selvakumar -- Thanks for the question regarding "Select by Group with different Date", version 8.1.7
You Asked
Hai Tom ,
           I wants to populate the data on hourly basis ,
I have two Scenario
  1. Between hrs from (24 hrs format) 7 to 19

  2. Between hrs from (24 hrs fromat) 19  to 7

     The 7 to 19 is 12 hrs and 19 to 7 is another 12 hrs.

   This my querry :

select to_char(created_on,'DD-MM-YYYY HH24') , count(*)  from mes_item_details
where to_Date(created_on) = '03-AUG-2001'
and   to_char(created_on, 'HH24') Between 7 and 19
group by to_char(created_on, 'DD-MM-YYYY HH24')

TO_CHAR(CREAT   COUNT(*)
------------- ----------
03-08-2001 17         12
03-08-2001 18         16

   Is it possible to do everything in one querry. My worry is second Scenario ,
is different date , i need 12 output from every Scenario , Because 12 hrs for
every Scenario.

Advance thanks for your valuable solution.

Thanks
With regards
Selva
and we said...
tkyte@TKYTE816> create table t ( dt date );

Table created.

tkyte@TKYTE816> begin
  2      for i in 1 .. 24
  3      loop
  4          for j in 1 .. i
  5          loop
  6              insert into t values ( sysdate + i/24 );
  7          end loop;
  8      end loop;
  9  end;
 10  /

PL/SQL procedure successfully completed.

tkyte@TKYTE816> select count(*) from t;

  COUNT(*)
----------
       300

tkyte@TKYTE816>
tkyte@TKYTE816> select case
  2           when to_char( dt, 'hh24' ) between 7 and 19
  3              then '0700-1900'
  4              else 'the rest'
  5         end,
  6         count(*)
  7    from t
  8   where dt between trunc(sysdate) and trunc(sysdate)+1-1/24/60/60
  9   group by case
 10              when to_char( dt, 'hh24' ) between 7 and 19
 11              then '0700-1900'
 12              else 'the rest'
 13            end
 14  /

CASEWHENT   COUNT(*)
--------- ----------
0700-1900         55
the rest          50

(use BETWEEN instead of where to_Date(created_on) = '03-AUG-2001', that would
be:

where created_on between TO_DATE('03-aug-2001') and
TO_DATE('04-aug-2001')-1/24/60/60

that'll let you use indexes and avoid the implicit conversion)
Review & Followup
Rating: 3
select by group November 05, 2001
Reviewer: Selvakumar from singapore
This is very useful.

November 05, 2001 Lynn -- Thanks for the question regarding "Options for restoring an individual table ", version 8.1.7.2
You Asked
Hi Tom,

  I'm new to RMAN and trying to determine the best way to restore a single
table.  I have multiple tables in each tablespace.  RMAN's TSPITR restores the
ENTIRE tablespace, which I don't want to do.  I want the ability to restore only
a given table.  Currently I take hot backups and nightly exports.  I use the
exports if I have to restore an individual table.

  In your opinion, what is the best method to restore a single table?

   Thanks.
and we said...
If the export trick works for you -- it is the path of least resistance.  If you
need more current information then that, what you do is:

o restore system/rollback and the affected tablespace to another machine
o point in time recover that table up to the point of failure
o export it

It *should* be a very rare occasion to have to restore a single table (eg:
someone accidently dropped it) -- perhaps the process that is causing you to
have to do this needs to be looked at?
November 05, 2001 Larry -- Thanks for the question regarding "SQL update in one statement", version 8.1.7.2.0
You Asked
Hello Tom,
Could you tell me how to write this as a single query?  I have a table with
these columns: dispensed_drug number(10), prescribed_drug number(10),
projected_cnt number(11), factor number(9,8).  The factor for each row is
calculated by dividing the projected_cnt of that row, by the sum of the
projected_cnt for that distinct dispensed_drug.

For instance, if I had two rows of data for dispensed_drug 123 and the first
projected_cnt was 500 and the second was 100, the factor for the first would be
0.833333 (500/600), and 0.16666667 (100/600) for the second row.................

Pretty trivial, I know, but I'm trying to come up with the cleanest single query
that will do the update in one step.

Thank for your help,
Larry
and we said...
ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t ( dispensed_drug int,
prescribed_drug int, projected_cnt int, factor number );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t values ( 123, 123, 500, null );

1 row created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t values ( 123, 123, 100, null );

1 row created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t values ( 456, 456, 1500, null
);

1 row created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t values ( 456, 456, 1100, null
);

1 row created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> update t
  2     set factor = (select t.projected_cnt/sum(t2.projected_cnt)
                        from t t2
                       where t2.dispensed_drug = t.dispensed_drug );

4 rows updated.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select * from t;

DISPENSED_DRUG PRESCRIBED_DRUG PROJECTED_CNT     FACTOR
-------------- --------------- ------------- ----------
           123             123           500 .833333333
           123             123           100 .166666667
           456             456          1500 .576923077
           456             456          1100 .423076923
Review & Followup
Rating: 4
November 06, 2001
Reviewer: Larry Manns from Phoenix, AZ USA
Very concise and to the point.  I'll be able to use this type of update in many
of my upcoming queries.   Thank you very much!

November 05, 2001 Nag -- Thanks for the question regarding "PLS-00231", version 8.1.7
You Asked
Tom

Iam trying to use a function( which is part of a package) from within my sql
statement, and Iam getting the error

pls-00231: function name may not be used in SQL

But when I remove it from the package and create it invidudually , it is working
fine.

Can you kindly let me know as why pls-00231: function name may not be used in
SQL occurs and how we should trouble shoot it.

thank you
and we said...
Is the function in the specification.  If not, it is not visible to sql.
Consider:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create or replace package my_pkg
  2  as
  3          procedure p;
  4
  5  end;
  6  /

Package created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> create or replace package body my_pkg
  2  as
  3
  4  function f return number
  5  is
  6  begin
  7          return 1;
  8  end;
  9
 10
 11  procedure p
 12  is
 13  begin
 14          for x in ( select f from dual )
 15          loop
 16                  dbms_output.put_line( 'Yes' );
 17          end loop;
 18  end;
 19
 20  end;
 21  /

Warning: Package Body created with compilation errors.

ops$tkyte@ORA717DEV.US.ORACLE.COM> show errors
Errors for PACKAGE BODY MY_PKG:

LINE/COL ERROR
-------- -----------------------------------------------------------------
14/13    PL/SQL: SQL Statement ignored
14/20    PLS-00231: function 'F' may not be used in SQL
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> create or replace package my_pkg
  2  as
  3          procedure p;
  4          function f return number;
  5  end;
  6  /

Package created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> alter package my_pkg compile body;

Package body altered.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> exec my_pkg.p
Yes

PL/SQL procedure successfully completed.

Until the function is "exposed" the SQL engine cannot see it.
November 05, 2001 Keith -- Thanks for the question regarding "Deferrable Constraints", version 8.1.7
You Asked
I Recently implemented constraints on a system as follows:

i) All primary keys were not declared as being not deferrable.
ii) All foreign keys were declared as being deferrable initially deferred.

The reasoning behind having the primary keys as not being deferrable was due to
uniqueness not being enforced until commit time, and I get the impression that
lookups using the index on a deferrable Constraint will be slower than the
lookups using the index on a normal constraint because uniqueness is not
enforced on deferrable constraints.

The reasoning for having the foreign keys as being deferrable,initially deferred
 was to allow for easier programming in the application. There was no need to
alter the constraints to be deferred or to worry about the order of inserts into
the tables.

Is this a sensible guideline to follow for using deferred integrity constraints
and we said...
With primary keys -- if you set them to be deferrable but initiallly deferred
what will happen is that they are validated right away but are enforced using a
non-unique index (to allow for dups temporarily).  You would use deferrable
primary keys only when you needed the functionality (eg: when refreshing a
snapshot -- the snapshot must have deferrable primary/unique constraints).

With foreign keys -- i think it is a totally bad idea to have them initially
deferred.  Many applications sort of assume a commit will succeed always.  Also,
in an application, entering data in the proper order should be trivial.  It is
nice to have the deferrable however to allow for an infrequent update cascade or
to do a load in any order.  I just think having them deferred by default is so
out of the ordinary it would be asking for trouble.
Review & Followup
Rating: 3
FYI, a scenario of using deferrable constraint November 06, 2001
Reviewer: Frank from USA
1)any department should has employee
2)any employee should be assigned to a department
so, employee table has a FK links to the department table, and another check
constraint should be added to department table to ensure there should be some
employee in this department. It's kind of dead lock idea, each one depends on
the other one. You cant insert new department, coz there is no employee. On the
other hand, u cant insert new employee belongs to this new department, coz the
department hasnt been and cant be added. So the check constraint can be a
deferrable constraint, which solves this delimma.

November 06, 2001 Ringo -- Thanks for the question regarding "Primary Key vs no primary key", version 816
You Asked
Tom,

Do I have to specify the primary key and foreign key on creating table? I have a
production DB running ok but withour specify any constraints on primary or
foreign key so far.

Is it a bad habbit?  I am thinking of add back all these primary key or foreign
key constrainst but not sure if it is wroth to do so.

Apprecicate your help in this regard
and we said...
Well, nows a really bad time to ask -- "i'm in production", its a tad late isn't
it.

Yes, in my opinion its a terrible habit.  It means you have all of your logic in
your applications.  It means you have a very closed system, the only way to get
data in or out is via your application.

You do realize in a mulit-user database, especially one that supports
multi-versioning and read consistency, its almost impossible for you to enforce
primary and foriegn key constraints.  I would not be surprised if you have bad
data in the database.

Don't mess with your production system, take a copy of it, implement the proper
features in the database, test it to death and then have another roll out.
November 06, 2001 Lisa -- Thanks for the question regarding "How to re-open a closed database without shutdown DB ?", version 816
You Asked
While in database, I did:
SQL> alter database close;

Database altered.

< change the init ora file to increase db_block_buffers from 3200 to 4000 >
SQL> alter database open;
alter database open
*
ORA-01531: a database already open by the instance
<message of 1531- Action: If you wish to open a new database on the instance,
first shut down and then restart the instance and retry the  operation >
In order to pickup the new DB_BLOCK_BUFFERS size,

1. How can I re-open the current database without shutdown and then startup the
database?

2. In a 24X7 environment, if I want to change some parameter and make it
available, do I
have to bounce the database? Is there any way not to shutdown and make the
change in init ?

Thanks.
and we said...
1) You have to shutdown.  You can issue an alter database OPEN once per
instance.  You can use "startup force" after making the modifications.

2) Many parameters are changable on line and every release adds more (eg: in 9i,
you can resize the shared pool and buffer cache online).  If you query
v$parameter, you'll see which are modifiable online and which require a restart.
Review & Followup
Rating: 3
No Sessions Connected. November 06, 2001
Reviewer: Ganesh Raja from Dubai, UAE
Hi Tom,

I am using Oracle 817 on NT. when i Try to Close my Database using the alter
Database Close it says it can do it only with no sessions conected.

I checked my v$session and i get Lot of Sessions with No Programs and Type as
user Connected ...

What are these sessions and what are their uses.

Regards,
Ganesh R

Followup:
They are the job queues.

alter system set job_queue_processes=0;

and try again.

Rating: 5
Please Clarify November 06, 2001
Reviewer: A reader from Houston
It seems that alter database close then ( do maintenance work here) ,shutdown
the db and startup again is equal to use:
shutdown db then startup mount (do maintenance work here).
it is just the different option. Is my thinking right ?

Followup:
alter database close
do work
startup force

is the same as

shutdown
startup mount
do work
alter database open

yes.

November 06, 2001 Olajuwon -- Thanks for the question regarding "Concurrent users in the database.", version 8.1.7
You Asked
Tom,

First I Would like to thankyou for all your work, I have found help in quite a
few of them.

Q - I am auditing the logon and logoff of users in a DB. The information is
captured in sys.aud$. By using the view dba_audit_sessions I can tell when a
user has logged on or off.

My problem is, I would like to determine over lapping connections for users (i.e
if a user is logged on more than once) within a specified time.( i.e every
10mins or 15mins or 30 mins for the current day).

I have tried to use information from doc id 1887385074621 but could not get the
result I want.

What I am looking for is something of:

username  Count(*) Time
UserA      10      10:00 - 10:05
UserB       2      10:00 - 10:05

Thanks in advance.

Regards
OlaJ
and we said...
This query does it for any given hour

sys@TKYTE816> select a.username, count(*) cnt
  2    from ( select *
  3             from dba_audit_session
  4            where (timestamp <= to_date( trunc(sysdate) + 13/24 ) and
  5                   logoff_time >= to_date( trunc(sysdate) + 13/24 ) )
  6               or (timestamp between to_date( trunc(sysdate) + 13/24 ) and
  7                                  to_date( trunc(sysdate) + 13/24 ) + 1/24 )
  8         ) a,
  9         ( select to_date( trunc(sysdate) + 13/24 ) + ((rownum-1)*5)/24/60
clock
 10             from all_objects
 11            where rownum <= 12
 12         ) b
 13   where ( a.timestamp <= b.clock and a.logoff_time >= b.clock  )
 14      OR ( a.timestamp between b.clock and b.clock+5/24/60 )
 15   group by a.username
 16  /

USERNAME                              CNT
------------------------------ ----------
SYS                                     1
SYSTEM                                  1
TKYTE                                   5

I did 1pm on TODAY for example.

Play with the trunc(sysdate) + 13/24 ) to get a different hour.

Play with to_date( trunc(sysdate) + 13/24 ) + 1/24 on line 7 to get more then 1
hour

and so on....
Review & Followup
Rating: 5
Excellent November 06, 2001
Reviewer: Abdal-Rahman Agha from Yemen
That is what I am looking for too. Thank you Tom. There is a column in the
Dba_Audit_Session view informing the reason code of failure of user connection.
Where can I find the meanings of these codes.

Followup:
The returncodes are simply ORA-XXXXX numbers.  You can use sqlerrm to get the
meaning, for example:

tkyte@TKYTE816> connect tkyte/foo
ERROR:
ORA-01017: invalid username/password; logon denied

Warning: You are no longer connected to ORACLE.

tkyte@TKYTE816> connect tkyte/tkyte
Connected.

tkyte@TKYTE816> select username, returncode
  2  from dba_audit_session
  3  where timestamp > sysdate-2/24/60;

USERNAME                       RETURNCODE
------------------------------ ----------
TKYTE                                   0
TKYTE                                1017  <<<== here is our failure
TKYTE                                   0

tkyte@TKYTE816> set serveroutput on
tkyte@TKYTE816> exec dbms_output.put_line( sqlerrm( -1017 ) );
ORA-01017: invalid username/password; logon denied

PL/SQL procedure successfully completed.

and there is the reason.
tkyte@TKYTE816>

Rating: 5
thats a perfect query November 06, 2001
Reviewer: raju from us
thats a perfect query

another security releated question is

i have seen people writting CUDS(CREATE UPDATE DELETE SELECT) packages to make
the DML operations on their tables, instead of directely accessing the tables.
they say it is for the security
reasons. i don't understand how? i think you can answer

Followup:
Sure, this is SEMI related to the original question....

With a procedure to do inserts, we can do some procedural logic before and after
the insert takes place.  We can audit (perhaps using an autonomous transaction),
we can validate the data using whatever logic, we can make sure we approve of
what is being done.

We grant execute on this package -- the user cannot log into SQLPlus and do an
insert, they must execute the procedure.  The procedure can check to see what is
calling it and if it doesn't like what it sees -- it doesn't have to execute.

You could achieve a similar level of protection with triggers -- a before insert
trigger can look to see who is doing what and when and do the same checks, a for
each row trigger can do likewise at the row level to validate.

Rating: 5
Concurrent users in the database November 06, 2001
Reviewer: Olajuwon from UK
Excellent. I have also learnt new things from your script. I have no choice now
I must get your book.

OlaJ

Rating: 5
November 06, 2001
Reviewer: Abdal-Rahman Agha from Yemen
Thanks TOM.

November 06, 2001 Hui -- Thanks for the question regarding "Contention", version 8.1.7
You Asked
Tom,

I have two indexes that are about 350MB each and they are currently in the same
tablespace and do get a lot of hits at the same time.

Would there be any advantage in performance if I put them in separate
tablespaces?

Thanks.
and we said...
Hui Kang -- if you see this -- your email is totally bogus, that is why you
don't hear from me, it bounces every time.  Use a real email (i don't spam,
promise)

the short answer is "no", "maybe", "yes"

What you need to do is look at that IO on your system.  If the disks you have
are all getting hit evenly, the answer is "no".

If you see hotspots the answer is maybe -- if they are on the hot disk and they
cause the hotness of the disk and the new tablespace you create is on another
disk -- they might fix it, yes.

Its easy to find out -- just use v$filestat to see your IO, see if these disks
are hot and others are not.  Then create a new tablespace and:

alter index iname rebuild online tablespace new_tablespace;

and it'll be moved for you -- online.
Review & Followup
Rating: 4
Just a note November 09, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Maybe you are running on a RAID storage. You do not say.

If you have a JBOD (Just a Bunch of Disks), that is what Tom just said.

If you have a RAID, you have a "black box" with a bundle of related disks in
this fashion:

RAID 0 (Only striping, no mirroring) - The storage "automatically" distributes
data access. Do not worry about performance. Worry about losing your data.

RAID 1 (Only mirroring, no striping) - Do as Tom says. Altough you have
mirrorred disks, data acceess is not "scattered".

RAID 0+1 (Mirroring AND striping) - Just like RAID 0, just don't worry (too
much) about crashing one of the disks, because you have an exact copy of it on
another disk.

RAID 3 and RAID 5 (Striping with parity, distributed (5) or not (3) ) - You have
striping, like RAID 0. Additionally, you must have at least three disks, where
one of them stores the "parity" of the remaining disks. So, if any one chashes
the RAID system can reconstruct the lost one by applying a XOR function on the
other disks and creating an image on the replaced one. Beware: Because of the
parity calculation, data writes are slower.

There are many variations of RAID, but these are the basic ones.

RAID can be implmented by software, typically NT & UNIX (slower and cheaper) or
harware, EMC, Network Appliances (faster and expensive).

Take a look at this article in Orace Magazine, for more information on this
issue:
http://www.oracle.com/oramag/oracle/00-May/index.html?o30avail.html

Hope this helps !

November 06, 2001 Hui -- Thanks for the question regarding "extent sizing", version 8.1.7
You Asked
Tom,

This is a follow up of a question I asked you a day ago, which I have not
received an answer for, but have thought about it more.

You seem to really like sizing the initial and the next extents the same size.
We have a lot of these scenario's...Here is on example.

A table that we have has approximately 3 gigs of data.  The person who initially
sized the table sized the intial and next extents way to small to where we had
over 25,000 extents being allocated.

We are upgrading to Oracle 8.1.7 and are trying to solve some of these problems.

A Co-worker suggest that we should at least size the initial extent to the
maximum 2 gigs and have the next be 512MB because we know that the table will
always be at least 3 gigs and will continue to grow.
He is also a believer that multiple extents are bad.

I suggested that we should have the initial and the next the same sizes of about
256MB or 512MB.  My main defense being to eliminate fragmentation of freespace.

Is one of us right, or both of our ideas pretty much lead to the same
performance results?

Thanks.
and we said...
Hui Kang, if you see this, you are using a bogus email -- use a real one, I
won't spam you.  I'm not ignoring you, I just cannot contact you.

Your coworker needs to present a scientific test case before I or anyone can
take him/her seriously.

Your coworker is wrong.  period.  end of discussion.  I've had alot of it on
this site (about multiple extents).  It is a myth.  Many extents is OK.

I suggested something smaller, like 128meg  -- maybe even 64m

128 = 24extents
 64 = 48extents

The problem with the above is you would not be able to use LMTs (locally managed
tablespaces) and you really really want to!  initial=next all of the way.

The other problem is a 512meg extent would mean you preallocate 511 meg way
before you need it.  64m means you grow slower.  You have more time to buy more
disk ;)

If you use LMTS -- fragmentation of free space is physically impossible -- every
free extent can be used and reused!  no fragmentation by definition.
Review & Followup
Rating: 5
And (to continue to flog a dead horse...) November 07, 2001
Reviewer: Connor from Glasgow
Smaller extents actually *help* in reporting and capacity planning.  You see a
more timely and more accurate changes to the database size (without having to
resort to 'complex' dbms_space scripts), which aids in decision making for more
disks etc etc

Rating: 4
November 07, 2001
Reviewer: A reader
In previous versions of oracle (Oracle 5) multiple extents DID cause performance
problems.  Loved your book (and also asktom column) by the way.  ( I did do a
test at the time but no longer have Oracle 5.)

Rating: 4
Notes on extents November 09, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
In fact, dynamic allocation used to be a problem in dictionary-managed
tablespaces: ( From the Oracle8i Designing and Tuning for Performance on-lie
book  )

" Avoid dynamic extension in dictionary-mapped tablespaces. "

As to the number and size of extents:

" For dictionary-mapped tablespaces, do not let the number of extents exceed
1,000. If extent allocation is local, then do not have more than 2,000 extents.
Having too many extents reduces performance when dropping or truncating tables.

Larger extents tend to benefit performance for the following reasons:

Blocks in a single extent are contiguous, so one large extent is more contiguous
than multiple small extents. Oracle can read one large extent from disk with
fewer multiblock reads than would be required to read many small extents.
Therefore, make sure that the extent size is a multiple of
DB_FILE_MULTI_BLOCK_READ_COUNT.

Segments with larger extents are less likely to be extended.

You cannot put large segments into single extents, because of file size and file
system size limitations. When you enable segments to allocate new extents over
time, you can take advantage of faster, less expensive disks.

For a table that is never full-table scanned, it makes no difference in terms of
query performance whether the table has one extent or multiple extents.

The performance of searches using an index is not affected by the index having
one extent or multiple extents.

Using more than one extent in a table, cluster, or temporary segment does not
affect the performance of full scans on a multi-user system.

Using more than one extent in a table, cluster, or temporary segment does not
materially affect the performance of full scans on a dedicated single-user batch
processing system, if the extents are properly sized and if the application is
designed to avoid expensive DDL operations.

If extent sizes are appropriately matched to the I/O size, then the performance
cost of having many extents in a segment is minimized.

For rollback segments, many extents are preferable to few extents. Having many
extents reduces the number of recursive SQL calls to perform dynamic extent
allocations on the segments. "

Hoping to clarify.

November 06, 2001 Arvind -- Thanks for the question regarding "Package variable inside sql statement", version 8.1.7
You Asked
Hi tom,
  I asked you a question some days back regarding use of package variable in a
sql statement and your asnwer was :

"In "regular sql" -- sql outside of sql in plsql -- you cannot reference a
package variable you can only invoke a function."

Now I am using the same sql inside a plsql block and it is working fine.
Example:
SQL> DECLARE
  2  T NUMBER;
  3  BEGIN
  4  SELECT CCSICODE.AO_CVUG_BILL_TO INTO T FROM DUAL;
  5  DBMS_OUTPUT.PUT_LINE(T);
  6  END;
  7  /

1
PL/SQL procedure successfully completed.

SQL> SELECT CCSICODE.AO_CVUG_BILL_TO FROM DUAL;
SELECT CCSICODE.AO_CVUG_BILL_TO FROM DUAL
                *
ERROR at line 1:
ORA-00904: invalid column name

Can you please explain me this.

Thanks in advance.
Take care
Arvind Kapil.
and we said...
Yes, inside of plsql, it is working as a bind variable -- that sql is rewritten
to something like:

select :bv1 from dual;

if you use sql_trace and tkprof (
http://asktom.oracle.com/~tkyte/tkprof.html
 you'll see this rewrite.  In plsql all
plsql variables are rewritten as bind variables.  In "regular" sql -- outside of
plsql -- they are just simply not visible.
Review & Followup
Rating: 4
Great November 07, 2001
Reviewer: Reader from mumbai
I Was Aware That Packaged Variable Was Not Accesible From "Regular SQL" But Was
Available From PL/SQL.

The Above Explanation Provided The Reason For It.

Thanks Tom For Simple And Clear Explanation.

Ur Jst Gr8

November 07, 2001 William -- Thanks for the question regarding "Qestions about chapter 21 of your book", version 8.1.6
You Asked
Hi Tom,

   I have tried example 2 (using application contexts) in chapter 21 of your
book. It works exactly as what we expected. Now I have two questions. In the
hr_predicate_pk package all the functions take two
arguments (p_schema and p_object) but they are never used within the
functions. What are the purpose of these two arguments ? On page 933
the insert_delete_function has a printing mistake. When predicate string is
assinged to a variable it should be g_ins_del_pred rather than g_upd_pred.
Thanks a lot.

Best regards

William
and we said...
The p_schema and p_object are sent in the event you want to have one procedure
that deals with many tables:

  if ( p_schema = 'SCOTT' )
  then
         if ( p_object = 'DEPT' )
         then
               return this_predicate;
         elsif ( p_object = 'EMP' )
         then
               return the_other_predicate;
         end if;
  elsif ( p_schema = .....)

and so on.

You are correct on the errata, will have them post that on the WROX web site.
Review & Followup
Rating: 4
November 06, 2001
Reviewer: William from Ontario Canada
Thanks for your explanation. It is my favorite chapter. As a developer I used to
implement a lot of security control
logic in front end. Now I know how to implement the logic in
database. This chapter is very useful and handy too.

Rating: 4
WROX website? November 06, 2001
Reviewer: Doug from CT, USA
Where's that?

Followup:
www.wrox.com

November 07, 2001 Balasubramanian -- Thanks for the question regarding "Length function", version 8.1.7
You Asked
Hi Tom,

I find the length of a 99 digit number in two ways.
Case 1 : I find the length of this number without converting to char.
Case 2:  I find the length of this number with converting to char.

But both gives different result. But for small digit numbers it gives the same
result. Can you explain whis happens ?

SQL> select
length(17112245242814131137246833888127283909100000000000000000000000000000000000
0000000000000000000000000) case1
  2  from dual
  3  /

CASE1
----------
40

SQL> select
length('1711224524281413113724683388812728390910000000000000000000000000000000000
00000000000000000000000000') case2
  2  from dual
  3  /

CASE2
----------
99

Thanks,
Bala
and we said...
Sure, you are doing an IMPLICIT conversion from NUMBER to STRING in case 1.  You
gave a number (and numbers in Oracle have 38 digits of precision).  That is a
valid number but the DEFAULT string representation of that is:

  1* select to_char(
171122452428141311372468338881272839091000000000000000000000000000000000000000000
000000000000000000 ) from dual
ops$tkyte@ORA717DEV.US.ORACLE.COM> /

TO_CHAR(17112245242814131137246833888127
----------------------------------------
1.7112245242814131137246833888127284E+98

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

So, you got the length of that NUMBER when depicted as a string.

In the second case, you never had a number -- you had a STRING that could have
contained "how now brown cow" just as easily as the ASCII characters that
represent digits you used.  You measured the length of a string.

You compared an apple (the number) to a toaster oven (the string).  There is no
way to compare these two as they are wholly different.
Review & Followup
Rating: 4
That was a Good one. November 06, 2001
Reviewer: Ganesh Raja from Dubai, UAE
By the way ... How do u calculate the Amount of bytes that a Number Field of Say
10 precision takes internally.

I Wentthru the Concepts guide butit is a bit confusing....

Regards,
Ganesh R

Followup:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c10datyp.htm#784
gives the formula:

ROUND((length(p)+s)/2))+1

which is just wrong and doesn't really even make any sense!  Bummer.. Going back
to 7.3 I find:

Taking this into account, the column data size for a particular numeric
data value NUMBER (p), where p is the precision of a given value (scale
has no effect), can be calculated using the following formula:

1 byte              (exponent)
FLOOR(p/2)+1 bytes  (mantissa)
+ 1 byte            (only for a negative number where
                     the number of significant digits is
                     less than 38)
====================
number of bytes of data

For example:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t ( x number(11) );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> begin
  2          for i in 1 .. 11 loop
  3                  insert into t values ( rpad('9',i,'9') );
  4          end loop;
  5          insert into t values ( 0 );
  6          for i in 1 .. 11 loop
  7                  insert into t values ( '-'|| rpad('9',i,'9') );
  8          end loop;
  9
 10  end;
 11  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select x, vsize(x), 1 + floor(10/2) + 1 + 1
  2  from t;

         X   VSIZE(X) 1+FLOOR(10/2)+1+1
---------- ---------- -----------------
         9          2                 8
        99          2                 8
       999          3                 8
      9999          3                 8
     99999          4                 8
    999999          4                 8
   9999999          5                 8
  99999999          5                 8
 999999999          6                 8
9999999999          6                 8
1.0000E+11          7                 8
         0          1                 8
        -9          3                 8
       -99          3                 8
      -999          4                 8
     -9999          4                 8
    -99999          5                 8
   -999999          5                 8
  -9999999          6                 8
 -99999999          6                 8
-999999999          7                 8
-1.000E+10          7                 8
-1.000E+11          8                 8

23 rows selected.

Shows the actual vs max size for each number..

      Rating: 5
That Wasreal
      fast ...  November 06, 2001
Reviewer:  Ganesh
      Rja  from Dubai, UAE
Tom that is okay but still Why do u Say p is 10 and not 11.

what is the logic behind this Calculation.

Regards,
Ganesh R

          Followup:

my example used 11, use 10 if you would like.

      Rating: 3
I guess it
      should be....  November 06, 2001
Reviewer:
      Sarada Priya  from Kuala Lumpur, Malaysia
I guess Tom should use floor(11/2) and not floor(10/2) since in the example he
has used NUMBER(11). Tom, Please put your feeback.

          Followup:

correct, typo on my part.  changes not the answer as floor(10/2) = floor(11/2)

      Rating: 3
What Was the
      logic  November 06, 2001
Reviewer:  Ganesh
      Raja  from Dubai, UAE
Hi Tom,

What is the Logic behind your calculation. And also comment on priya's
statement.

Regards,
Ganesh R

          Followup:

it was a typo, sorry.

November 07, 2001 Zhuo -- Thanks for the question regarding "How
      can I get a users password", version

      You Asked
    Thank you for your last good idea.Today I meet two
questions.Would you help me?
1.How can I find the Oracle users's password?(Which table is
the users's password included?)
2.How can I know the authority of the Oracle users?

      and we said...
You cannot.  The password is not stored in clear text, in fact
the password is not stored at all.

Passwords are stored much in the way unix stores them.  We
create a digest of the users password using their USERNAME,
PASSWORD and a 'salt' (some key of data).  These strings are
hashed together to form a fixed length 'digest' (big hex
string).  This string is what is stored.  To validate that a
user is allowed to log in -- we take the username and password
they provided, combine that with the salt and do the hash
(digest) again.  we compare the results -- if they are equal --
you can get in.  if not, you cannot get in.

these digests are NOT reversible -- they are one way.  given a
username, password we can get a digest.  Given a digest and a
usernme -- we cannot determine the password.

This digest is visible to you in the DBA_USERS view.

             DBA_COL_PRIVS
             DBA_ROLE_PRIVS
             DBA_SYS_PRIVS
             DBA_TAB_PRIVS

has that information.

Review &
      Followup

      Rating: 2
A little
      contradiction...  November 07, 2001
Reviewer:
      Rithin
Hi,

I was just browsing thru ur answer...

<Quote
http://technet.oracle.com/doc/server.804/a58397/ch1.htm#987>
"...If you issue the ALTER USER command to change the password after connecting
to the database, both the password stored in the data dictionary and the
password stored in the password file are updated."

<End quote>

Tom, my question -

U have said in ur answer  -
" .... You cannot.  The password is not stored in clear text, in fact the
password is not stored at all. "

Doesn't ur answer contradict the Oracle Tech documentation ? You r saying that
Password is not stored in database at all , but the documentation says something
else...

Can u explain...

regards.

          Followup:

The "hashed" password, the "digested" password is stored.

The actual password (eg: the TIGER in SCOTT/TIGER) is not stored -- a HASH of
TIGER is stored.

So, the hashed password is stored.  No contradiction as I read it.

      Rating: 5
Just a
      note  November 07, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
Just opposed to what many books and people erroneously say, Oracle passwords are
not "encrypted". In fact, they are "hashed", as Tom pointed out.

Take care of that, there is a subtle difference.

An encrypted piece of data can -- by definition -- be "decrypted", that is, be
brought back to its original form.

Hash data cannot ! The algorithm Oracle uses is called "one-way hash", meaning
the original, clear-text password cannot be recovered.

Hoping to help !

      Rating: 3
Related
      link  November 07, 2001
Reviewer:  Andrew
       from USA
http://govt.oracle.com/~tkyte/Misc/su.html

      Rating: 3
related link
      again...  November 07, 2001
Reviewer:
      andrew  from usa
The URL didn't come out...
govt.oracle.com/~tkyte/Misc/su.html

November 09, 2001 Shawn -- Thanks for the question regarding "Mass
      Loading BLOBs into a database", version Oracle 8.1.6

      You Asked
Hi,
I have posed this question to many different Oracle people and
lists, but have not recieved a solution yet.

I am using Oracle 8.1.6, with the Intermdedia Cartridge, and Web
Agent and Clipboard.  I am trying to load images into my
database table using sqlldr. The images are mass scanned in to a
file system directory.  Once the images are in a specific
directory, I need to load these images into the database table.
 I am able to use sqlldr to upload bfiles, but what I actually
need to load are BLOBs. Can anyone tell me what I need to do to
use sqlldr to upload BLOBs? I have read all of Oracle's
documentation on sqlldr, and they claim that you can load blobs,
but don't say how to do it. The table that I am trying to load
to is named example13, and the field "image" is defined as
ordsys.ordimage. Any help would be greatly appreciated!

Also, is there a  better way to get a large number of images
into the database?
Thanks,
Shawn

---control file starts here----

LOAD DATA
INFILE example13.dat
INTO TABLE EXAMPLE13
FIELDS TERMINATED BY ','
( EMPNO INTEGER EXTERNAL,
ENAME CHAR,
JOB CHAR,
MGR INTEGER EXTERNAL,
SAL DECIMAL EXTERNAL,
COMM DECIMAL EXTERNAL,
DEPTNO INTEGER EXTERNAL,
RES_FILE FILLER CHAR(60),
"IMAGE" BFILE(CONSTANT "ORDIMGDIR", RES_FILE)
)
---control file ends here----

      and we said...
given a table:

create table image_load(
  id number,
  name varchar2(255),
  image ordsys.ordimage
)
/

you can use the following .ctl file to load the table

LOAD DATA
INFILE *
INTO TABLE image_load
REPLACE
FIELDS TERMINATED BY ','
( "ID"    INTEGER EXTERNAL,
  "NAME"    CHAR,
  file_name FILLER CHAR,
  "IMAGE" column object
  (
    source column object
    (
      localdata LOBFILE (file_name) TERMINATED BY EOF
                NULLIF file_name = 'NONE'
    )
  )
)

BEGINDATA
1,CLBECK,my_image.gif
2,TKYTE,tom_image.gif
3,CLBECK,NONE
4,TKYTE,another_tom_image.gif

After all the data is loaded, you will probably want to
setproperties on all the images so

begin
  for c in ( select * from image_load ) loop
    c.image.setproperties;
  end loop;
end;
/

would do that.

Review &
      Followup

      Rating: 1
loading images
      using lob  November 09, 2001
Reviewer:
      RAGHUNATH A  from Bangalore India
When creating the table  given in the example i get an error message saying
"ordsys.ordimage" invaid datatype

what needs to be done

          Followup:

You need to have Oracle interMedia installed and configured

http://technet.oracle.com/doc/oracle8i_816/inter.816/index.htm
You can just use a BLOB if you like as well.

November 09, 2001 Abdal-Rahman -- Thanks for the question regarding
      "Opening a database after close", version 8/8i

      You Asked
Hi Tom,
  Can you explain the following?

SVRMGR> alter database close;
alter database close
*
ORA-01093: ALTER DATABASE CLOSE only permitted with no sessions connected
SVRMGR> alter system set job_queue_processes=0;
Statement processed.
SVRMGR> alter database close;
Statement processed.
SVRMGR> alter database open;
alter database open
*
ORA-01531: a database already open by the instance

SVRMGR> select * from dba_users;
select * from dba_users
              *
ORA-01219: database not open: queries allowed on fixed tables/views only

How can I open the databse after closing?

Thanks.

      and we said...
You can open a database ONCE per instance.

the instance must be shutdown in order to do another open.

You can:

alter database close;
-- do stuff
startup force;

or

shutdown
startup mount
-- do stuff
alter database open

The choice is yours, the effects are the same.  the way to open a database that
has been closed is to shut it down and start it up again.

Review &
      Followup

      Rating:
      4
Thanks  November 09, 2001
Reviewer:
      Abdal-Rahman Agha  from Yemen
   Thank you very much Tom. I was thinking that I could get the database open
back again after it has been closed without shut it down.

November 09, 2001 Nag -- Thanks for the question regarding "Cursor
      in Sql Plus", version 8.1.7

      You Asked
Tom

From your earlier discussions, it is clear taht sqlplus can open only a single
cursor at a time, where as pl/sql can open multiple cursors.
One of the questions I have is when I give a sql in sqlplus, a cursor is used
for the purpose of executing the query.

Now how do we close this cursor, and how do we know that the cursor has been
closed.How do we confirm that the cursor has been closed.

Further , with pl/sql , we explicityly close the cursors, when using regular
cursors, and in case of using the for loop to open the cursor it is done
automatically i.e. it is closed automatically.

Now how do we close the cursor in case of a ref cursor. What will happen if we
dont close a ref cursor.

thank you

      and we said...
You do not worry about the SQLPlus cursor -- SQLPlus worries about that cursor,
it is sqlplus's resource -- not yours.  It will handle all of the details
regarding it.  You cannot influence it.

With a ref cursor -- you just close it.

...
   open l_cursor for select * from dual;
    ....

   close l_cursor;
...

If it is sent back to tha client, like JDBC, pro*c, oci, etc .... THEY perform
the close.

In general, if you do not close a ref cursor -- you will "leak" cursors and if
you leak enough of them, you'll run out eventually.
Review &
      Followup

      Rating: 5
Where should I
      close the ref curosor in the following case,or   November
      09, 2001
Reviewer:  Nag
1.Where should I close the ref curosor in the following case,or is it
automatically closed,

function test ( params )  is

rc refcursor;

lv_rc rc;

begin

open rc for

Select column list

from

(select same set of columns
from same set of from same tables
where different conditions
union

select   same set of columns
from same set of from same tables
where different conditions
union

select same set of columns
from same set of from same tables
where different conditions
union
select
same set of columns
from same set of from same tables
where different conditions)

return rc;

end test;

2.and

What is the adverse impact of not closing cursors or ref cursors. Can you
demonstrate it.

          Followup:

1) well, your syntax is a bit of a mess - you use rc where you mean lv_rc and
you don't have the return type but I get the gist of it.

As I said in the answer:

...
If it is sent back to tha client, like JDBC, pro*c, oci, etc .... THEY perform
the close.
......

the CLIENT, whomever that is, whatever GETS the ref cursor back, is responsible
for closing it.

2) I told you what the exact impact is:

....
In general, if you do not close a ref cursor -- you will "leak" cursors and if
you leak enough of them, you'll run out eventually.
......

when you run out, you run out -- cannot open more, get errors and fail.

November 09, 2001 Cesar -- Thanks for the question regarding "Reset
      rownum", version 8.1.6

      You Asked
Hi Tom, how are you?...

Question... I have this table:

CUSTOMERS
------------------------------------------
ID                   number(10)
VERSION              varchar2(10)
AMOUNT               number(12,2)

and I need only 2 records by customer...

Example

ID             VERSION               AMOUNT
---------------------------------------------------
1              1                     456
1              2                     600
1              3                     500
1              4                     20
2              1                     46
2              3                     70
3              1                     80
3              4                     400
3              5                     200
3              7                     90
4              6                     10

RESULT

ID             VERSION               AMOUNT
---------------------------------------------------
1              1                     456
1              2                     600
2              1                     46
2              3                     70
3              1                     80
3              4                     400
4              6                     10

Which two recors? First...

Thansk!

      and we said...
select id, version, amount
  from ( select id, version, amount,
                row_number() over ( partition by id order by <whatever> ) r
            from customers )
 where r <= 2;

for example, to get the first two hired emps by deptno:

  1  select ename, hiredate, deptno
  2    from ( select ename, hiredate, deptno,
  3                 row_number() over ( partition by deptno order by hiredate )
r
  4             from emp
  5         )
  6   where r <= 2
  7* order by deptno, hiredate
scott@ORA717DEV.US.ORACLE.COM> /

ENAME      HIREDATE      DEPTNO
---------- --------- ----------
CLARK      09-JUN-81         10
KING       17-NOV-81         10
A          17-DEC-80         20
JONES      02-APR-81         20
ALLEN      20-FEB-81         30
WARD       22-FEB-81         30

6 rows selected.

Review &
      Followup

      Rating:
      3
Problem...  November 09, 2001
Reviewer:
      Salas  from Mexico
I forgot it, I can't use it... I get this message

ERROR at line 1:
ORA-00439: feature not enabled: OLAP Window Functions

What can I do?

          Followup:

Well, you can use something like this then:

scott@ORA717DEV.US.ORACLE.COM> select ename, hiredate, deptno
  2    from emp
  3   where 2 > ( select count(*)
  4                   from emp e2
  5                  where e2.deptno = emp.deptno
  6                    and e2.hiredate < emp.hiredate )
  7   order by deptno, hiredate
  8  /

ENAME      HIREDATE      DEPTNO
---------- --------- ----------
CLARK      09-JUN-81         10
KING       17-NOV-81         10
A          17-DEC-80         20
JONES      02-APR-81         20
ALLEN      20-FEB-81         30
WARD       22-FEB-81         30

6 rows selected.

It'll be much slower then using the analytic functions of course as the
correlated subquery will take a bit longer to execute for each row but depending
on your result set size, may work just fine.

      Rating: 5
Ok,
      but  November 09, 2001
Reviewer:  Salas
       from Mexico
Thanks for the answer, but How can I enable analytic functions?

          Followup:

They are an advanced feature available with Oracle EE and PE (enterprise and
personal).  I have to assume you have standard.

November 09, 2001 lok -- Thanks for the question regarding "how to
      compare two reports content", version 8.1.6

      You Asked
Dear Tom,

     I don't know whether my question should be asked in here or not. But i
really need your kindly help.

     I have two SQL, one is tuned, the other is not, both of them are expected
to be generated the same result report.

     I ran them in parallel, and finally, each of them has generated a text
report for me. But it is very time consuming for me to check whether these two
sql reports generated the same result or not.

    My question is: Is there any utilities or functions in SQL*PLUS that can
help me to check whether both reports are the same or not?

    I hope you can answer my question and thx you in advance..

Lok

      and we said...
Well, thats a really bad way to test that they are in fact the SAME.

Just because it returns the same answer with the existing data does not mean
it'll always return the same answer given different data!

You must understand how the queries work -- write them out in psuedo code --
understand what they do -- then prove they are the same.

For example, many people assume these two queries are interchangable:

select *
  from t1
 where not exists ( select NULL
                      from T2
                      where t2.x = t1.x );

select * from t1 where x NOT IN ( select x from t2 );

Using your method of "see if they return the same answer if they do they are the
same" -- I might be WRONG:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t1 ( x int );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t2 ( x int );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t1 values ( 1 );

1 row created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select *
  2    from t1
  3   where not exists ( select NULL
  4                        from T2
  5                        where t2.x = t1.x );

         X
----------
         1

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select *
  2    from t1
  3   where x NOT IN ( select x from t2 );

         X
----------
         1

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> insert into t2 values ( NULL );

1 row created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select *
  2    from t1
  3   where not exists ( select NULL
  4                        from T2
  5                        where t2.x = t1.x );

         X
----------
         1

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select *
  2    from t1
  3   where x NOT IN ( select x from t2 );

no rows selected

You see -- sometimes they return the same answer, sometimes they do not.  You
have to understand how each is processed and compare them.  Obviously in this
case we learn that NOT IN and NOT EXISTS are not interchangeable -- but
understanding how they work we can make them so.  If we wanted to replace NOT
EXISTS with NOT IN, we just must code:

  1  select *
  2    from t1
  3*  where x NOT IN ( select x from t2 WHERE X IS NOT NULL )
ops$tkyte@ORA717DEV.US.ORACLE.COM> /

         X
----------
         1

Now they are the same.

So, I could show you how to compare the two query results but that would be bad
-- you still would not know.

(hint: create table temp1 as <query1>
       create table temp2 as <query2>

       select * from temp1 MINUS select * from temp2;
       select * from temp2 MINUS select * from temp1;

       select count(*) from temp1;
       select count(*) from temp2;

if either of the minus queries returns data - you don't have your answer.  If
the counts are different -- you don't have your answer.  If you get no rows back
from the minus and the counts are the same you just DON'T KNOW if you don't have
the answer!

Review &
      Followup

      Rating: 4
how to compare
      two reports content  November 06, 2001
Reviewer:
      lok  from Hong Kong
thx a lot, tom
you give me a clear and professional solution!!
and your reasons are clear and strong!
thx.

      Rating: 5
ORA-01723:
      zero-length columns are not allowed  November 09, 2001

Reviewer:  Nag
Tom

I want create a table with a select which has unions( and I have used nulls in
the selcts, for some columns)

I need to compare the results of the above select with the results of an another
select.

I am trying to do what you have suggested above(in the hint).

But Iam getting the following error

ORA-01723: zero-length columns are not allowed

I have reproduced the error Iam facing with a small example.

SQL> CREATE TABLE TEST5
  2  AS SELECT  to_number(null) TESTCOL,EMPNO,ENAME FROM EMP;
AS SELECT  to_number(null) TESTCOL,EMPNO,ENAME FROM EMP
           *
ERROR at line 2:
ORA-01723: zero-length columns are not allowed

How should I resolve this create the table.

Thank you

          Followup:

Nag -- please, as the review screen says really big in red

"Please do not use this to ask a question."

If the follow/review is on topic -- relates to the original question, has some
remote relevance to the question -- I'll be glad to answer it, to clarify my
response, to add content.

If the question is totally off topic, as this clearly is, I'm not going to.
Please don't do this anymore.  I have limited time to work on this site, I have
a formal process for submitting questions.  You know how it works (you have
asked perhaps more questions then any other individual).  Please use it
properly.

      Rating:
      5
  November 09, 2001
Reviewer:  Nag

Tom

I was using the solution you provided and ran into the problem  which I posted.

But , I get your point.

Iam sorry , I will post with more restraint and responsibility.

Thanks for your patience, and thanks for being there for us.

November 09, 2001 Betty -- Thanks for the question regarding "Date
      Conversion", version 8.1.7

      You Asked
I have a table1 -
table1
num_date number(10)
num_time number(10)

Is there any way to change num_date from data type number to data type date.
The field contains 20010101.  This table was created from a different source.

Thanks

      and we said...
you can:

alter table table1 add dt_date date;

update table1 set dt_date = to_date( num_date, 'yyyymmdd' ), num_date = NULL;
alter table table1 drop column num_date;

If the column name must stay the same -- you will then:

rename table1 to table1_table;
create view table1 as select ...., dt_date NUM_DATE, .... from table1_table;

revoke grants on table1_table;
grant grants on table1;

No one will be the wiser..... (thats how to rename a column)
Review &
      Followup

      Rating:
      5
DBA  November 09, 2001
Reviewer:
      Betty  from FL
This will be a great help.

      Rating: 4
How about
      adding and dropping the same column  November 09, 2001

Reviewer:  Arup Nanda  from Norwalk, CT, USA

Instead of creating a view, I suggest the following to rename a column. After
you issued alter table table1 drop column num_date, issue

alter table table1 add (num_date  date);
update table1 set num_date = dt_date;
commit;
alter table table1 drop column dt_date.

Now your table should look like

num_time number(10)
num_date date

Please note the sequencing of the fields will be different. If that is a
problem, you have to use a view.

          Followup:

well, i like to do as little work as possible.  Your approach would generate
more log.  If you do the update like this:

udpate table1 set num_date = dt_date, dt_date = null;

you would avoid migrating many rows as the table briefly has two
num_date/dt_date columns.

But yes, your approach will work as well -- if the table is sufficiently small,
no problem.  On a large table, it would double the time to accomplish the task

November 09, 2001 partha -- Thanks for the question regarding
      "Trigger for Alter Table", version 8.1.6

      You Asked
Tom,

I want's to write a trigger which will insert a record with
username,timestamp,action,table_name,schema_name,sql_statement,machine_name when
ever any body alter's the table Structure or drop the table.

I know i can use logminer but, i want's to implement this only on two or three
tables.

Thanks in Advance.

      and we said...
See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:429876477891
in 9i you can get the TRIGGERING statement but not before.  In 9i a new event
attribute "ora_sql_txt" was added.
Review &
      Followup

      Rating: 5
Trigger for
      Alter or Create table  November 09, 2001
Reviewer:
      A reader
Best one.

November 09, 2001 Andrew -- Thanks for the question regarding
      ""Session based synonyms" under Oracle 9i?", version 9.0.1.x

      You Asked
I am involved in the development of a complex application that accesses Oracle
9i through a middle tier.  End users of the application all login to Oracle
through a single Oracle account but are uniquely identified within the
application.  End users have varying "roles" within the application, which in
turn determine the database views and tables each user can access.  In some
cases, these "roles" only provide access to subsets of the columns in various
base tables.  Database views are used to enforce the necessary column level
security.  The application has no knowledge of these views.  When the
application queries a table, I would like to have the query to use the
appropriate view, based on the privileges associated with the current user
session.  I understand the use of login triggers and Oracle 9i "secure
application roles" to set user privileges at a session level.  These application
roles will be used to determine which views and tables a given user session is
granted access to during session login.

QUESTION:  Based on the explanation above, is there a way to have Oracle use the
appropriate view when the application submits a query against a table?
Conceptually, I would like to implement something like "session based synonyms."

The views and tables are not owned by the Oracle login account.  All views will
contain field types and ordering to match their base tables.  Restricted columns
will typically return something like NULL.  The system will serve hundreds of
users and potentially thousands of tables.

Thanks for any suggestions you can offer.  Your book is exceptional!!

      and we said...
Ok, here is a method -- I'll warn you up front however that SYNONYMS and VIEWS
in a very very very large system add overhead (everything does).  You'll want to
be aware of that.  But....

We'll create two schemas A and B.  They will have SYNONYMS and nothing else
(they cannot even select from the tables they have syonyms on!)

We'll create a third schema, single_acct -- this is your application schema.

Using the "set current_schema", we can get "select * from t" to query totally
different tables, consider:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create user a identified by a;
User created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create user b identified by b;
User created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create user single_acct identified by
single_acct;
User created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> grant create session, create synonym to a;
Grant succeeded.

ops$tkyte@ORA717DEV.US.ORACLE.COM> grant create session, create synonym to b;
Grant succeeded.

ops$tkyte@ORA717DEV.US.ORACLE.COM> grant create session to single_acct;

Grant succeeded.

ops$tkyte@ORA717DEV.US.ORACLE.COM> @connect scott/tiger
ops$tkyte@ORA717DEV.US.ORACLE.COM> set termout off
scott@ORA717DEV.US.ORACLE.COM> set termout on
scott@ORA717DEV.US.ORACLE.COM>
scott@ORA717DEV.US.ORACLE.COM> create or replace view v1
  2  as
  3  select ename, empno, decode(0,1,1,to_number(null)) sal
  4    from emp
  5  /
View created.

scott@ORA717DEV.US.ORACLE.COM> grant select on v1 to single_acct;
Grant succeeded.

V1 cannot see SAL, it'll see NULL everytime

scott@ORA717DEV.US.ORACLE.COM> create or replace view v2
  2  as
  3  select ename, empno, sal
  4    from emp
  5  /
View created.

scott@ORA717DEV.US.ORACLE.COM> grant select on v2 to single_acct;
Grant succeeded.

V2 can see sal, everytime

scott@ORA717DEV.US.ORACLE.COM> @connect a/a
scott@ORA717DEV.US.ORACLE.COM> set termout off
a@ORA717DEV.US.ORACLE.COM> set termout on
a@ORA717DEV.US.ORACLE.COM> create synonym emp for scott.v1;
Synonym created.

If you use a.emp, you get scott.v1 = NO SALARY

a@ORA717DEV.US.ORACLE.COM> @connect b/b
a@ORA717DEV.US.ORACLE.COM> set termout off
b@ORA717DEV.US.ORACLE.COM> set termout on
b@ORA717DEV.US.ORACLE.COM> create synonym emp for scott.v2;
Synonym created.

if you use b.emp, you get scott.v2 = SALARY

b@ORA717DEV.US.ORACLE.COM> @connect single_acct/single_acct;
b@ORA717DEV.US.ORACLE.COM> set termout off
single_acct@ORA717DEV.US.ORACLE.COM> set termout on
single_acct@ORA717DEV.US.ORACLE.COM>
single_acct@ORA717DEV.US.ORACLE.COM> alter session set current_schema=A;
Session altered.

single_acct@ORA717DEV.US.ORACLE.COM> select * from emp where rownum < 5;

ENAME           EMPNO        SAL
---------- ---------- ----------
A                7369
ALLEN            7499
WARD             7521
JONES            7566

Here EMP = A.EMP = SCOTT.V1 = no salary...

single_acct@ORA717DEV.US.ORACLE.COM> alter session set current_schema=B;
Session altered.

single_acct@ORA717DEV.US.ORACLE.COM> select * from emp where rownum < 5;

ENAME           EMPNO        SAL
---------- ---------- ----------
A                7369        800
ALLEN            7499       1600
WARD             7521       1250
JONES            7566       2975

#now, EMP = B.EMP = SCOTT.V2 = SALARY

I recommend you consider doing this in your middle tier however -- you are most
likely using JDBC with Java - in which case, all SQL is dynamic anyway -- just
"glue" the right view name in there in the app -- have the ROLE be part of the
viewname itself:

create view CLERK_v1 as...
create view ADMIN_v1 as ...
create view USER_v1 as ...

and in your jdbc app:

  query = "select * from " + their_role + "_v1 where ....";

depending on the scale of your application, this could make a difference down
the road.  See

http://www.ixora.com.au/newsletter/2001_05.htm#synonyms
for a little background on that.
Review &
      Followup

      Rating: 4
Additional
      Details  November 12, 2001
Reviewer:  Andy
      Zitelli  from Costa Mesa, CA USA
Dear Tom:

Thanks for your detailed response.  I had previously investigated using ALTER
SESSION SET CURRENT_SCHEMA.  It is not yet clear whether this solution will be
workable in our situation but I am carefully reconsidering this based on the
details you provided.

I should fill in a couple of added details.  The project I am working on
involves broad enhancements to a large legacy system.  The middle tier is
outside of my control so the solution to our problem must be implemented in the
database.  To further confuse things, end users may be granted several system
roles simultaneously.  This can result in the possibility that a single user
will simultaneously be granted access to two different subsets of columns on the
same table.  It is not yet clearly defined what should happen in these cases.  I
am concerned with the potential for a combinatorial explosion in the number of
required views and schemas required to support this.  Are there any other
approaches you suggest I investigate?  Again, thanks for all your help!

Andy Zitelli

November 10, 2001 Munzer -- Thanks for the question regarding "HTML
      form in PL/SQL", version 8i

      You Asked
Tom:

I have an oracle web application using PL/SQL procedures that generates HTML
using htp package.

If i want to create a html screen that generates the user's input in display
mode basically confirming what he entered as:

Name:  Tom Cruise
Order:  1001
Item  Description  Qty
1      gloves       10
2      clubs         20

How would you generate this?  Would you select the record from the database
after inserting and commiting it and set up a cursor to display it in a table
tags?

Also, If I want to desig a form to update an existing record, would you also
write in PL/SQL a procedure that selects the record and then
read the results into several <input > tags?

Thank you in advance for your great answer.

      and we said...
Well for the first part, I must have a procedure like:

procedure p( p_name in varchar2, p_item in <some array type>,
                                 p_desc in <some array type>,
                                 p_qtry in <some array type> )
as
....

So I would just INSERT the data and whilst inserting, print it out --eg:

  insert into order_tab ( name, order )
  values ( p_name, order_seq.nextval ) returning order into l_order;

  htp.p( 'Name: ' || p_name || '<br>' );
  htp.p( 'Order: ' || l_order || '<br>' );

  for i in 1 .. p_item.count
  loop
     insert into order_details_tab ( item, description, qtr )
     values ( p_item(i), p_desc(i), p_qty(i) );
     htp.p( ..... );

as for #2, updating an existing record -- i would

a) read the record out
b) store ALL fields in hidden input items
c) create a form with ALL field in text items

so that the accepting procedure can get the OLD record and the NEW record and
can do an update like:

   update t
       set c1 = p_new_c1, c2 = p_new_c2, ....
     where c1 = p_old_c1 and c2 = P_old_c2 and ......;

if that updates zero records -- someone else updated the record (you lose)..
(you need to ALWAYS select the primary key for this to work of course)
November 11, 2001 Manish -- Thanks for the question regarding
      "Passing array from C to plsql", version 8i

      You Asked
the problem is that i am passing an array from my pro*c program to
oracle and the array when reaches the procedure all its elements becomes
null!!
the array in pro*c before the EXEC SQL block is absolutely fine and has
all the elements, i've seen this by printing the elements. also after
the end-exec i.e. after the call to the procedure the array is fine(this
array is an IN OUT parameter. but eithin the pl/sql block and in the
procedure also the array elements become null.though amazingly the
arry.count indicated that the NUMBER of elements received is correct.
but unfortunately they become null!!
i've wracked all my brain but still don't know why it is happening!
the code is somewhat like
pro*c
-----------
EXEC SQL BEGIN DECLARE SECTION;
int dimension;
varchar ps_store[100][4];
EXEC SQL ARRAYLEN ps_store(dimension);
EXEC SQL END DECLARE SECTION;
i'm accesiing the array in pro*c as follows
strcpy((char *)ps_store[ll_ctr].arr,"0030");
ll_ctr++;
strcpy((char *)ps_store[ll_ctr].arr,"0032");
ll_ctr++;
strcpy((char *)ps_store[ll_ctr].arr,"0034");
ll_ctr++;
strcpy((char *)ps_store[ll_ctr].arr,"0035");
here printing the array elements gives correct values!!
the call to procedure is as follows

EXEC SQL EXECUTE
DECLARE
error_message VARCHAR2(255);
error_no NUMBER;
relations_exist VARCHAR2(1);
return_code BOOLEAN;
BEGIN
return_code := NRD_SP_CNV_DELETE_RECORDS.VAL_STYLE (:ps_store,
:pl_step_id,
:pl_time,
error_no,
error_message);
if return_code = TRUE
then
whatever....
END;
END-EXEC;
now the pacakge code is like
declarations
TYPE STORE_ARRAY IS TABLE OF VARCHAR(4) INDEX BY BINARY_INTEGER;
FUNCTION VAL_STYLE
(i_store_in IN OUT STORE_ARRAY,
i_step_id IN NUMBER,
i_time IN NUMBER,
val_error_no IN OUT NUMBER,
val_error_message IN OUT VARCHAR2) RETURN BOOLEAN;
now i access the elements as usual in this array
i_store_in(i)
but all these are null!!!
i am unable to solve this problem.

Could you explain me how to achieve this.

      and we said...
actually it is not 100% fine, you have defined it as:

varchar ps_store[100][4];

now a varchar is really a struct with a length and a array of data, like this:

struct { unsigned short len; unsigned char arr[4]; } ps_store[100];

(although pro*c might padd out the arr element to more then 4) so, technically
your code:

strcpy((char *)ps_store[ll_ctr].arr,"0030");

is copying 5 bytes into a 4 byte variable (don't forget the NULL terminator).
Varchar's are NOT null terminated.  The piece of the code you are TRULY
forgetting is:

ps_store[ll_ctr].len = strlen( ps_store[ll_ctr].arr );

you've never set the length field and it's my guess they are init'ed to zero --
hence the length as far as pro*c is concerned is 0 bytes (they are NULL).

Additionally, I cannot tell (since I don't have all of the code) if you are
filling in all 100 array elements or not, I only see 4 of them -- that can be a
problem as well.

The code more properly would be:

static void process( void )
{
int     i;

varchar ps_store[100][5];
int     nelems;
/* use arraylen so we can constrain the size of the array dynamically
   at run time.  If I fill in N array elements, that's all that will
   be sent, otherwise pro*c will ALWAYS send 100 elements */
exec sql arraylen ps_store(nelems);

varchar msg[4000];
short   msg_i;

    for( i = 0; i < 10; i++ )
    {
        sprintf( ps_store[i].arr, "%04d", i );
        ps_store[i].len = strlen( ps_store[i].arr );
        /* make sure to set that LENGTH attribute!!!
    }
    nelems = 10;

    /* note that for VARCHARS that come OUT of a plsql block,
       we must set the max length.  using a null indicator here
       as well */
    msg.len = 4000;
    msg_i   = -1; /* null */

    exec sql whenever sqlerror do sqlerror_hard();

    /* now lets test it... */
    exec sql execute
    declare
        type array is table of varchar2(4) index by binary_integer;
        l_data array;
        l_msg  varchar2(4000);
    begin
        l_data := :ps_store;
        for i in 1 .. l_data.count
        loop
            l_msg := l_msg || chr(10) ||
                     'l_data(' || i || ') = ' || l_data(i);
        end loop;
        :msg:msg_i := l_msg;
    end;
    end-exec;

    if ( !msg_i )
         printf( "%.*s\n", msg.len, msg.arr );
    else printf( "message was NULL\n" );
}

The output from this is:

l_data(1) = 0000
l_data(2) = 0001
l_data(3) = 0002
l_data(4) = 0003
l_data(5) = 0004
l_data(6) = 0005
l_data(7) = 0006
l_data(8) = 0007
l_data(9) = 0008
l_data(10) = 0009

showing that it works.
Review & Followup

      Rating: 4
Great
      answer  November 12, 2001
Reviewer:  Joel
       from Columbus, OH USA
Thanks, Tom

November 11, 2001 Rich -- Thanks for the question regarding "Does
      ASkTom search dialog have a bug?", version ?

      You Asked
Hi Tom,

I did a search on ASK Tom for: COMMENT ON TABLE
and got the following error:

ORA-20000: interMedia Text error: DRG-10800: query failed: ORA-06508: PL/SQL:
could not find program unit being called
Debug:
begin declare l_hits number; begin l_hits := ctx_query.count_hits(
'ASK_TOM.SEARCH_IDX', v('F4950_P7_CLEAN_CRITERIA'), FALSE ); if l_hits > 0 then
htp.bold( v('F4950_P7_CLEAN_CRITERIA') ); htp.br; htp.bold('Approximately ' ||
l_hits || ' records found.'); end if; end; end;

ORA-20001: Report Error: ORA-20001: Error executing cursor: ORA-29902: error in
executing ODCIIndexStart() routine ORA-20000: interMedia Text error: DRG-50857:
oracle error in drdmlpo ORA-00904: invalid column name ORA-30576: ConText Option
dictionary loading error ORA-00904: invalid column name

Any ideas what I did wrong?

I do have a question: How do I do the following using
EXECUTE IMMEDIATE

COMMENT ON TABLE emp IS 'my comments go here...';

I can't seen to get the above to work with EXECUTE IMMEDIATE.

Thanks,
Rich

      and we said...
We were doing an upgrade yesterday and hadn't yet upgraded intermedia.  Its
working again.

you would:

  execute immediate 'comment on table emp is ''my comments go here'' ';

use '' for a ' in a string literal.
Review &
      Followup

      Rating:
      4
  January 25, 2002
Reviewer:
      A reader

November 11, 2001 sushant -- Thanks for the question regarding
      "raise_application_error and order by in a sequence and vsize", version
      8.1.5

      You Asked
1)
i am having a raise_application_error in my after insert trigger
for each row
i am also having a insert into another table in my before insert
trigger for each row

but the problem is when ther is a insert into the table
even befor the before row level trigger is fired the
raise_application_error of the after row level trigger fires
and ther is no actual insert into the second table.

why raise_application_error fires even before the insert

2)

select vsize(384838),vsize('orange_tabby'),vsize(sysdate)
from dual;

the output is
4 12 8

i understand how 12 and 8 have arrived. but can
how is  4  arrived

3)

in the user_sequences view we hav an order_flag column.

we can create sequence say
create sequence sn
start with 1
increment by 2
maxvalue 100
minvalue 1
cycle
cache 1
order

how does the order clause work in the sequence

      and we said...
1) Oh but the insert did happen (and then UN-happened).  This is easy to see:

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t ( x int );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create table t2( x int );

Table created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> create or replace trigger t_bifer
  2  before insert on t for each row
  3  begin
  4      insert into t2 values ( :new.x );
  5  end;
  6  /

Trigger created.

ops$tkyte@ORA717DEV.US.ORACLE.COM> create or replace trigger t_aifer
  2  after insert on t for each row
  3  begin
  4      raise_application_error( -20001, 'Serious error' );
  5  end;
  6  /

Trigger created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> create or replace trigger t2_aifer
  2  after insert on t2 for each row
  3  begin
  4      dbms_output.put_line( 'Someone inserted ' || :new.x || ' into t2' );
  5  end;
  6  /

Trigger created.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> set serveroutput on
ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> begin
  2      insert into t values ( 1 );
  3  end;
  4  /
Someone inserted 1 into t2
begin
*
ERROR at line 1:
ORA-20001: Serious error
ORA-06512: at "OPS$TKYTE.T_AIFER", line 2
ORA-04088: error during execution of trigger 'OPS$TKYTE.T_AIFER'
ORA-06512: at line 2

See how the message "someone inserted 1 into t2" is there -- the insert DID take
place however, it was UNDONE since the TRIGGERING STATEMENT itself failed!

This is to ensure the ACID properties (atomicity, consistency, isolation and
durability) that are vital to a database.

Since the triggering INSERT failed -- so do all SIDE EFFECTS of that insert.
Think about it -- it would be bad if they didn't (yes, I understand sqlserver
lets them stay -- thats why you NEED to rollback in a trigger with them.  I also
find this to be the worst of the worst ways to do it).

That insert fired from the trigger is all part of the same triggering statement,
either they ALL succeed, or they ALL fail.  Otherwise you have absolutely NO
CLUE as to what parts worked and what parts didn't and must rollback the entire
transaction (as sqlserver would have you do).  Here just this statement and its
side effects fail -- you can recover from this and you decide whether the entire
transaction fails or succeeds.  The database is left in some known, consistent
state from which you can move forward from.

Now, if this other insert needs to persist (eg: it is an audit trail, you want
to audit failed attemps as well as successful ones), you can use an autonomous
transaction.  See

http://osi.oracle.com/~tkyte/autonomous/index.html
or I have a large chapter on this (and many other things Oracle) in my book.

2) It is because numbers are stored in a packed decimal like format -- 2
digits/byte, sign byte and exponent.  Here you have 6 digits (3 bytes) and one
for the rest.  4bytes of storage.

3) straight from the sql language manual:
...
ORDER
guarantees that sequence numbers are generated in order of request. You may want
to use this clause if you are using the sequence numbers as timestamps.
Guaranteeing order is usually not important for sequences used to generate
primary keys. ORDER is necessary only to guarantee ordered generation if you are
using Oracle with the Parallel Server option in parallel mode. If you are using
exclusive mode, sequence numbers are always generated in order.
......

so, it only applies with OPS (RAC in 9i) -- a multi-instance configuration of
Oracle.  If you are not using OPS -- its meaningless.  If you are using OPS and
use ORDER on the create sequence -- make SURE you need it as it decreases
performance as the nodes in the cluster must work together to generate ordered
sequences.
November 11, 2001
      -- Thanks for the question regarding
      "Object Relational Database Management", version 8.1.6

      You Asked
Hi Tom,
  I want your opinion on how you would handle this project. The hardware and
software is already pre-set. EMC for storage on SRDF
and  oracle 8.1.6 on a e6500 8 cpus. There would be  table
   A=500 Million records
   B=200 Thousands records
   C=100 Million records
   D= 50 Million records

  Table A,B,C,D are related to each other. Meaning to get an information i need
to relate them together, based on the key.

business objective :
     To access a record set and deliver it within 10 seconds. A records set
could return around 5000 records. The concurrent
connection at a given time waiting for a response would be
around 1000 users.

I have this option :
   relational - use table partitioning .
   object relational - and use table partitioning.

 I have no experience on object relational tables, one object table
could be as big as 500GB ( combining table A,B,C,D ).
   Could the business objective can be met using this appoach ?
   How about management ? Is there are known gotchas, problem etc ?
   Is there are lot of companies out there using it ? and the scale
   is as big as this one ?

 Another question :
    When creating a tablespace, how come it takes to long example
 10 GB, takes one hour on a mirrored disk. On EMC, on a SRDF, it would
 take 1 GB per hour. Assuming we just building a tablespace for
 500 GB on SRDF. It would take 500 hrs, is there something wrong in  the process
or there is a way to resolve this issue.

Thanks and more power to this site.

      and we said...
Well, objects will add some overhead - there will be hidden columns and such.
You would be using nested tables probably -- which won't really cluster the
data, just makes it appear as if it were a single object (its not -- its stored
in 4 separate tables with system generated primary/foreign keys.

I would be tempted to say "don't use objects if raw performance is your
criteria".

One concept to look at -- a CLUSTER.  Its a method of storing data from more
then one table on the same block -- it sort of pre-joins the data physically --
you would cluster the above data by a single cluster key.  Not knowing how
a,b,c,d are related to eachother -- its hard to give you more info.  If you are
interested -- in my book i have a pretty good chapter on the ins and outs of the
various table types -- I could see uses for CLUSTERS and/or index organized
tables here to speed up retrieval.

Table partitioning won't play here for performance -- you won't be full scanning
anything, no trickly partition wise joins -- just straight forward stuff. that
doesn't mean you won't make use of partitioning, just that it probably won't
affect your performance very much at all.

As for the tablespace creation - we write each block, you are basically saying
the EMC+SRDF is pretty dog slow if it takes 1 hour to write 1 gig -- just wait
till you goto LOAD the data!  Perhaps you could turn off the SRDF part (or get a
faster network) whilst doing this part and let EMC resilver the remote mirror in
the background later?

In any case, what you can do is

o create the tablespace with one small datafile (fast)
o issue "alter tablespace t add datafile '/.......' size .....;"  from many
sessions in parallel, they can each add a datafile in parallel.

In that fashion, you can kick off many sessions adding N gig datafiles.
However, if the network for SRDF is the bottleneck -- thats not going to help
you very much!  You would need a bigger pipe.


Subject | Article | Last Updated (East coast time)
IF statement in SQL*Plus | article only | Nov 12, 2001 09:38 am
rebuild index for locally managed tablespace with AUTOALLOCATE option | article only | Nov 12, 2001 11:54 am
recovering a session after shutdown | article only | Nov 12, 2001 01:07 pm
Large rollbacks in the system | article only | Nov 12, 2001 03:50 pm
Row deleted value...using execute immediate. | article only | Nov 12, 2001 06:34 pm
consitent read | article only | Nov 13, 2001 10:18 am
Email Through Oracle. | article only | Nov 13, 2001 12:53 pm
Move indexes thru re-build | article only | Nov 13, 2001 12:55 pm
A SQL statement | article only | Nov 13, 2001 01:01 pm
SQL PLUS REPORTS | article only | Nov 13, 2001 01:25 pm
Allocating a large initial extent | article only | Nov 13, 2001 02:12 pm
google discussion forum | article only | Nov 14, 2001 11:06 am
PL/SQL from html | article only | Nov 14, 2001 11:15 am
Why do I loop after the NOTFOUND? | article only | Nov 15, 2001 06:44 am
customize sqlplus prompt in unix | article only | Nov 16, 2001 08:04 am
Column references in Fine Grained Access Control | article only | Nov 16, 2001 08:26 am
Circular Reference Error | article only | Nov 16, 2001 09:37 am
Sql Help | article only | Nov 16, 2001 09:57 am
Partitioning the Non-partitioned table | article only | Nov 16, 2001 04:39 pm
Passing array of BLOBs from PL/SQL to Java? | article only | Nov 16, 2001 04:44 pm
Temporary Table vs single query | article only | Nov 16, 2001 07:43 pm
Getting out of wait | article only | Nov 17, 2001 10:14 am
Why Dont you Write a Book for DBA's Also ??? | article only | Nov 17, 2001 10:49 am
Executing dbms_space | article only | Nov 17, 2001 10:53 am
Calling Export from Pl/sql using C external proc. | article only | Nov 17, 2001 01:08 pm
Is there any difference in intention between "even" releases and "odd" ones? | article only | Nov 17, 2001 04:22 pm
A question | article only | Nov 18, 2001 03:24 pm
To access the other Database other Oracle | article only | Nov 18, 2001 03:38 pm
Physical Properties, Relational properties, Object properties | article only | Nov 18, 2001 04:57 pm
row(s) 1 - 29 of 29
November 12, 2001 Alan -- Thanks for the question regarding "IF statement in SQL*Plus", version 8.0.6.0.0
You Asked
Hi Tom!

I want to use an IF statement in a .SQL with use the BEGIN/END to do something
like this (it's just an example):

IF &1 = 1 THEN
   SELECT * FROM EMP;
ELSE
   SELECT * FROM DEPT;
END IF;

If I enter 1 then SQL*Plus shows this result:
     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM
DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ----------
----------
      7369 SMITH      CLERK           7902 17/12/1980        800
   20
      7782 CLARK      MANAGER         7839 09/06/2081    2548,19
   10
      7839 KING       PRESIDENT          0 17/11/2081       3000
   10
....

Otherwise it shows:
    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

If the only way is by using BEGIN/IF/DBMS_OUTPUT it's bad for me!!!

And another question is how can I exit from a .SQL !?
PS: This question is most valid if there's an answer to the first one!
Like this:

IF &1 = 1 THEN
   RETURN;
END IF;

Thanks a lot!

Regards,

Alan
and we said...
why is it bad for you?  It would look like this:

=====================================================
set autoprint on
variable x refcursor

begin
        if &1 = 1 then
                open :x for select ename, hiredate from emp where rownum < 5;
        else
                open :x for select * from dept;
        end if;
end;
/

whenever sqlerror exit
exec if &1 = 1 then raise_application_error( -20000, 'Goodbye' ); end if;
whenever sqlerror continue
=====================================================

Now when I run this I see:

scott@ORA717DEV.US.ORACLE.COM> @test 0
old   2:        if &1 = 1 then
new   2:        if 0 = 1 then

PL/SQL procedure successfully completed.

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

PL/SQL procedure successfully completed.

scott@ORA717DEV.US.ORACLE.COM> @test 1
old   2:        if &1 = 1 then
new   2:        if 1 = 1 then

PL/SQL procedure successfully completed.

ENAME      HIREDATE
---------- ---------
A          17-DEC-80
ALLEN      20-FEB-81
WARD       22-FEB-81
JONES      02-APR-81

BEGIN if 1 = 1 then raise_application_error( -20000, 'Goodbye' ); end if; END;

*
ERROR at line 1:
ORA-20000: Goodbye
ORA-06512: at line 1

Disconnected from Oracle8i Enterprise Edition Release 8.1.7.2.0 - Production
With the Partitioning option
JServer Release 8.1.7.2.0 - Production

which is pretty much what you wanted...
Review & Followup
Rating: 5
Cool, thanks November 09, 2001
Reviewer: A reader from Switzerland

Rating: 4
Great! November 12, 2001
Reviewer: Alan Rech from Caxias do Sul, RS Brazil
Thanks Tom!!!

The answer to the fisrt question is exactly what I need...
But in the second, it'll not work when you have a script that mixes PL/SQL with
SQL*Plus commands...

Best regards,

Alan

Followup:
what I do then is something like:

set serveroutput on
set feedback off
spool temp.sql
begin
   if ( something )
   then
         dbms_output.put_line( 'host ..... ' );
   else
         dbms_output.put_line( 'prompt nothing to do here, skipping host' );
   end if;
end;
/
spool off
@temp

Rating: 4
Re: Follow-up November 12, 2001
Reviewer: Alan Rech from Caxias do Sul, RS Brazil
This is a good alternative! I'll try it...

Thanks again.

[]'s

Alan

November 12, 2001 Branka -- Thanks for the question regarding "rebuild index for locally managed tablespace with AUTOALLOCATE option", version 8.1.7
You Asked
We have a locally managed tablespace with AUTOALLOCATE option. I know that you
do not recommend this option, but it is not my decision. We were loaded a large
amount data from a legacy system into an Oracle database.
The Oracle DBA responsible for the database is complaining that we have to many
extents for indexes in our tablespace, and that I have to rebuild indexes. (She
is not complaining about the tables.)
I did not set any storage parameters when I was creating indexes and tables,
because as I understand it, there is no reason to set parameters for indexes and
tables with the AUTOALLOCATE option for tablespace.
My question, does it make sense if I now set storage parameters for all indexes
to be the same for initial and next extent:

alter INDEX PK_DEPT rebuild
storage ( initial 1M next 1M
 minextents 1 maxextents 500)

This is list first 10 order by number of extents (DESC)

NAME                           MB        NUM
---------------------- ---------- ----------
I0000220                      416        123
I0000460                      408        122
PWIAPPCH                      376        118
PWIAPPWN                      320        111
I0000224                      304        109
PK_APPL_MA                    200         96
I0000462                      168         92
MA_FK_MA_CD                    96         83
I0000733                       88         82
BBBH                           88         82
and we said...
No problems there -- thats great.  I'd leave them be.

I see NOTHING the would indicate a rebuild should be considered.

Ask the DBA for SCIENTIFIC proof that many extents are bad, they won't be able
to give you any.

Here, this is from my system:

  1  select *
  2  from ( select segment_name, segment_type, extents, trunc(bytes/1024/1024)
mbytes
  3  from dba_segments
  4  order by 3 desc
  5  )
  6* where rownum <= 20
ops$tkyte@ORA8I.WORLD> /

SEGMENT_NAME                   SEGMENT_TYPE          EXTENTS     MBYTES
------------------------------ ------------------ ---------- ----------
SYS_LOB0000096267C00009$$      LOBSEGMENT               3624        906
SYS_LOB0000123455C00009$$      LOBSEGMENT               2350       1175
IDL_UB1$                       TABLE                    1828        214
SOURCE$                        TABLE                    1360        265
WWV_DOCUMENT$                  TABLE                    1160       1160
T_HR_LOCATIONS                 TABLE                     389         97
T_HR_LOCATIONS                 TABLE                     388         97
MAILPKG_LOG                    TABLE                     375        187
IDL_UB2$                       TABLE                     333         39
WWV_FLOW_ACTIVITY_LOG1$        TABLE                     316        158
I_SOURCE1                      INDEX                     268         52
DR$WWC_PEOPLE_PROFILE_IDX$I    TABLE                     244         61
IMAGE_HOLD                     TABLE                     241        120
AA_AQ_FK_I                     INDEX                     215         53
ARGUMENT$                      TABLE                     192         22
LA_PK                          INDEX                     189         47
PPR_ISSUES                     TABLE                     176          7
LA_LQ_FK_I                     INDEX                     176         44
WWV_FLOW_DATA                  TABLE                     169         84
PROJECT_REPORTS_TEXT           TABLE                     151          5

20 rows selected.

And I'm not losing a wink of sleep.
Review & Followup
Rating: 5
rebuild index for locally managed tablespace with AUTOALLOCATE option November 12, 2001
Reviewer: Branka Todorovic from US
Thank you for help.

November 12, 2001 Jay -- Thanks for the question regarding "recovering a session after shutdown", version 8.1.7
You Asked
Tom

I have written a system that loads data into a data warehouse (Oracle 8.1.7)
using jobs (or processes). There are about 30 different jobs at the moment, some
take a few minutes to run and some take a few hours. Each job is controlled by a
job controller that performs commits at certain points, keeping track of its
status. This is so that if there is an error at some point, the job will fail
(recorded by the job controller), we can fix the error and the controller will
resume the job from the last successful commit point – particularly useful on
the long jobs.

My problem is this: The DBAs perform cold backups (using shutdown abort, which I
don’t agree with, but I’m not the DBA, I can’t change that), sometimes these
occur when a job is running. The result of this is that once the database has
been brought backup, rolled forward and then rolled back again to the last
commit point, it leaves the job status in the RUNNING state. The session that
was running the job is no longer active so it just sits like this, which is
wrong. I need to update the status to FAILED and run the job again – it will
pick up from the last commit point correctly. If, however, the session is killed
before the backup, then a ‘your session has been killed’ exception is raised and
the job controller handles it correctly, logs the error (exception) and sets the
status to FAILED (it also sends an email to the operator telling them what has
gone wrong). All that is needed then is to run the job again.

Is there anyway that the backup procedure can either:
1)    Resume the session that was running the job after the database comes back
up.
2)    Raise an exception (like the kill session) before shutting down.
3)    Or perhaps I could write a check_job_statuses job that runs at database
startup and kicks off all jobs that have been left in the RUNNING state again.
Not sure how to get this to run at startup – is there an ON_DATABASE_STARTUP
trigger type thing?
4)    Any other way of doing this cleanly that you can think of.

1 other (wee) thing:
1)    When doing data loads some information (dimensional and other reference
data) is queried millions of times. I get a good performance gain if I load the
data into variables (plsql tables) and create functions on that to return my
information. The actual table is only queried once for the active session. I
don’t care about changes to the underlying table data during the session. Is
there a neater way of achieving this performance gain? (my method is approx 10
times faster).

Your expert advice would be greatly appreciated on this.

Regards
Jay
Scotland
and we said...
My expert advice --

get REAL DBA's who do only HOT backups which are as easy to do as COLD backups
and better for the system overall (nothing worse then a cold SGA).

#3 is possible but it will involve the help of your overly helpful DBA's -- you
can write a database startup trigger.  Yes there is an on startup trigger you
can use (see the application developers guide, the chapter AFTER triggers on
system events).

#4 is possible as well -- don't see a column to RUNNING.  Use V$SESSION to
signify that a job is running.  You can use:

   dbms_application_info.set_client_info( 'running job' );
   dbms_application_info.set_action( THE-JOB-ID-YOU-ARE-RUNNING );

Then, to find jobs that are runnable, instead of querying:

   select * from your_job_table where status = 'NOT RUNNING'

you'll

   select * from your_job_table where status = 'NOT RUNNING'
     and job_id not in ( select action from v$session where
                         client_info = 'running job' );

That way, when the system crashes (due to a backup), your v$session entries
disappear and when you restart your job processor -- it'll automatically restart
these jobs.

I like #4 best -- you can go a step further and use
dbms_application_info.set_session_longops (if you have my book -- i go into
detail on this) to allow you to easily monitor the process of your long running
jobs using the v$tables (and even let the DBA's monitor it -- they could see
"hey", this'll finish soon, lets wait)

As for the other "wee" thing -- I would need an example of what you are doing
exactly in order to say -- how you were doing it and how you ARE doing it -- in
order to comment.
Review & Followup
Rating: 3
The wee thing November 12, 2001
Reviewer: Jay from Scotland
Firstly, I take it that #1 is not possible, i.e. we can't 'save' a session as is
and start start it back up again on start up. Other comments very useful,
especially the REAL DBAs bit, but that's out of my hands.

Secondly, here's a small example to illustrate the 'wee' thing:
Here's a package with a couple of functions to return TRUE or FALSE on whether a
flag is set on a table to say whether a form is foreign (all exception handling
removed for clarity):
-----------------------------------
CREATE OR REPLACE PACKAGE ref_dat IS

PROCEDURE load_ref_data;
FUNCTION form_is_foreign(in_form_type IN VARCHAR2) RETURN BOOLEAN;
FUNCTION form_is_foreign_old(in_form_type IN VARCHAR2) RETURN BOOLEAN;
END ref_dat;
/

CREATE OR REPLACE PACKAGE BODY ref_dat AS

TYPE r_form_type IS RECORD
   (code VARCHAR2(20)
   ,foreign_flag VARCHAR2(1));
TYPE t_form_type IS TABLE OF r_form_type INDEX BY BINARY_INTEGER;
dat_form_type t_form_type;

FUNCTION form_is_foreign (in_form_type IN VARCHAR2) RETURN BOOLEAN AS

BEGIN
   FOR x IN 1 .. dat_form_type.COUNT
   LOOP
      IF dat_form_type(x).code = in_form_type THEN
         RETURN dat_form_type(x).foreign_flag = 'Y';
      END IF;
   END LOOP;
END form_is_foreign;

FUNCTION form_is_foreign_old (in_form_type IN VARCHAR2) RETURN BOOLEAN AS

   l_flag VARCHAR2(1);

BEGIN
   SELECT foreign_form_flag
   INTO   l_flag
   FROM   ref_form_types
   WHERE  code = in_form_type;
   RETURN l_flag = 'Y';
END form_is_foreign_old;

PROCEDURE load_ref_data IS

CURSOR c_foreign_form IS
   SELECT code
         ,foreign_form_flag
         ,rownum
   FROM   ref_form_types;

BEGIN

FOR v_foreign_form IN c_foreign_form
LOOP
   dat_form_type(v_foreign_form.rownum).code         := v_foreign_form.code;
   dat_form_type(v_foreign_form.rownum).foreign_flag :=
v_foreign_form.foreign_form_flag;
END LOOP;

END load_ref_data;

BEGIN

   load_ref_data;

END ref_dat;
---------------------------------------
The two functions form_is_foreign and form_is_foreign_old both return the same,
but if I call them 1000's of times, we can see that form_is_foreign out performs
the old one. The question was: Is there a better way of acheiving the same
performance gain?

Jay

Followup:
What is the output of:

SQL> variable x varchar2(25)
SQL> exec :x := 'SOME_VALID_VALUE'   -- please supply the value for me
SQL> set autotrace on
SQL>  SELECT foreign_form_flag
        FROM   ref_form_types
       WHERE  code = :x;

If you don't know about AUTOTRACE, see:
http://osi.oracle.com/~tkyte/article1/autotrace.html
for a quick HOWTO.

Rating: 3
wee thing continued November 13, 2001
Reviewer: jay bostock from Scotland
Right, here's what you asked for:

PIP> exec :x := 'FP10'

PL/SQL procedure successfully completed.

PIP>  set autotrace on
PIP> SELECT foreign_form_flag
  2          FROM   ref_form_types
  3         WHERE  code = :x;

F
-
Y

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=7)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'REF_FORM_TYPES' (Cost=1
          Card=1 Bytes=7)

   2    1     INDEX (UNIQUE SCAN) OF 'FT_PK' (UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          1  rows processed

Now, I need to take this a little further, in this simplified case, the
performance gains are small - it runs approx a third faster than the 'old' one.
If however I introduce a where clause into the original query (as might be used
with DATE_FROM, DATE_TO columns) or simply to look at a subset of the data, the
performance gains increase hugely:

  1  DECLARE
  2     Y NUMBER;
  3  BEGIN
  4  FOR X IN 1 .. 100
  5  LOOP
  6     Y := PAC.DUMMY_INFO_OLD('XX','X','XX');
  7  END LOOP;
  8     dbms_output.put_line(to_char(y));
  9* END;
PIP> /
999

PL/SQL procedure successfully completed.

 real: 136656
PIP> ed
Wrote file afiedt.buf

  1  DECLARE
  2     Y NUMBER;
  3  BEGIN
  4  FOR X IN 1 .. 100
  5  LOOP
  6     Y := PAC.DUMMY_INFO('XX','X','XX');
  7  END LOOP;
  8     dbms_output.put_line(to_char(y));
  9* END;
PIP> /
999

PL/SQL procedure successfully completed.

 real: 40

The autotrace of the query for this one is:

  1  SELECT p.some_info
  2  FROM   dummy_info p
  3  WHERE  p.1_info = 'X'
  4  AND    p.2_info = 'XX'
  5  AND    p.3_info = 'XX'
  6  AND    p.more_info like 'Dummy%'
  7* AND    date_to is NULL
PIP> /

PRESCRIBER_ID
-------------
        27580

 real: 1022

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (FULL) OF 'DUMMY_INFO'

Statistics
----------------------------------------------------------
          7  recursive calls
          1  rows processed

I guess what we're saying here is that if I need to query many times on this
table then I should have an index on the pertinent column, although my method
does get round this.

November 12, 2001 Prince -- Thanks for the question regarding "Large rollbacks in the system", version 8.1.7.2
You Asked
Tom,

I am monitoring the DB instance with Statspack and have a large percentage of
Rollback per transaction (and user rollbacks)

Rollback per transaction %:   80.16

Is there anyway to find, which applications are getting many of these rollbacks?
Or what causes these rollbacks? (say by setting some events or by any other
means)

Thanks,
and we said...
I can tell you exactly what causes them -- your applications are issueing them
on purpose.  The "cause" -- you'd have to ask the guys who wrote the app why
they rollback (extremely expensive operation i might add)

The "who", thats a little harder to track down.  You can run a query such as:

select a.username, b.value
 from v$session a, v$sesstat b
where a.sid = b.sid
  and b.statistic# = ( select statistic#
                         from v$statname
                        where name = 'user rollbacks'
                     )
  and b.value > 0
/

from time to time (capturing whatever you need from v$session to determine the
application).
Review & Followup
Rating: 4
Will just a simple rollback (say, immeditaely after commit) has any overhead? November 12, 2001
Reviewer: Prince..
I got the answer from the devp team. They have a exit function (OCIRollback) in
the application which is called during every exit (normal or abnormal) from the
application (php).

This most of the time does not rollback any work. (just like commit and then
immediately rollback)

Now, my question is will this have any overhead, if it is not really doing any
rollback (as the work is already commited)?

November 12, 2001 Senthil -- Thanks for the question regarding "Row deleted value...using execute immediate.", version 8.1.7
You Asked
Tom,

Here is the detail. I am trying to delete rows dynamically, using execute
immediate. If i dont use begin...end block, then i am able to get the rows
processed(deleted) information. But, if i use begin...end block, i am not able
to get that. Is there any workaround to get the rowcount...or am i doing wrong
somewhere...

thanks,
senthil.

nobeginblock.sql:
set serveroutput on
declare
   v_rowcount      number := 0;
   v_exec_rowcount number := 0;
   v_commit_rowcount number := 0;
begin
   execute immediate 'delete from t';
   v_exec_rowcount := sql%rowcount;
   commit;
   v_commit_rowcount := sql%rowcount;
   dbms_output.put_line('v_exec_rowcount ' || v_exec_rowcount);
   dbms_output.put_line('v_commit_rowcount ' || v_commit_rowcount);
end;
/

withbeginblock.sql:
set serveroutput on
declare
   v_rowcount      number := 0;
   v_exec_rowcount number := 0;
   v_commit_rowcount number := 0;
begin
   execute immediate 'declare r number; begin delete from t; commit; end;';
   v_exec_rowcount := sql%rowcount;
   commit;
   v_commit_rowcount := sql%rowcount;
   dbms_output.put_line('v_exec_rowcount ' || v_exec_rowcount);
   dbms_output.put_line('v_commit_rowcount ' || v_commit_rowcount);
end;
/

With nobeginblock...

SQL> drop table t;

Table dropped.

SQL> create table t as select object_name, object_type from user_objects where
rownum < 11;

Table created.

SQL> select count(*) from t;

  COUNT(*)
----------
        10

SQL> @nobeginblock
v_exec_rowcount 10
v_commit_rowcount 10

PL/SQL procedure successfully completed.

SQL> select count(*) from t;

  COUNT(*)
----------
         0

SQL> @nobeginblock
v_exec_rowcount 0
v_commit_rowcount 0

PL/SQL procedure successfully completed.

Now, withbeginblock...

SQL> drop table t;

Table dropped.

SQL> create table t as select object_name, object_type from user_objects where
rownum < 11;

Table created.

SQL> select count(*) from t;

  COUNT(*)
----------
        10

SQL> @withbeginblock
v_exec_rowcount 1
v_commit_rowcount 1

PL/SQL procedure successfully completed.

SQL> select count(*) from t;

  COUNT(*)
----------
         0

PL/SQL procedure successfully completed.

SQL> @withbeginblock
v_exec_rowcount 1
v_commit_rowcount 1

PL/SQL procedure successfully completed.
and we said...
sql%rowcount is the row counter from the last IMPLICIT cursor.

In your "begin" example, the last IMPLICITY cursor is the "begin ..... end;" --
sql%rowcount isn't even really MEANINGFUL for that.

You can code:

ops$tkyte@ORA817DEV.US.ORACLE.COM> drop table t;

Table dropped.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t as select * from all_objects
where rownum <= 10;

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2     v_rowcount      number := 0;
  3     v_exec_rowcount number := 0;
  4     v_commit_rowcount number := 0;
  5  begin
  6     execute immediate 'declare r number; begin delete from t; :x :=
sql%rowcount; commit; end;'
  7       using OUT v_exec_rowcount;
  8     commit;
  9     v_commit_rowcount := sql%rowcount;
 10     dbms_output.put_line('v_exec_rowcount ' || v_exec_rowcount);
 11     dbms_output.put_line('v_commit_rowcount ' || v_commit_rowcount);
 12  end;
 13  /
v_exec_rowcount 10
v_commit_rowcount 2

PL/SQL procedure successfully completed.

SQL%rowcount is ONLY valid immediately AFTER an insert/update/delete -- getting
it after commit is not meaningful (commit doesn't touch it).  You need to get it
RIGHT after the DML you want to get the counts from.
Review & Followup
Rating: 5
November 12, 2001
Reviewer: A reader
Great...now it was clear to me, thanks.

Rating: 5
Very good example November 13, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

November 13, 2001 Sushil -- Thanks for the question regarding "consitent read", version 8.0.5
You Asked
Hi Tom,

I am facing error 1555 while trying to lots of update in a for loop
after reading values from few diff tables.

I have searched through most of your ans regarding 1555.

I have got a fair amount of understanding about this error as I
had faced a lot earlier but at present my query is bit different.
I start my pl/sql block with begin(main)
Here first I open up a cursor named c1 which is not having any dynamic variables

in its where clauses.

then I open that cursor in a for loop i.e. for x in c1 loop.
Now i insert into a table a single row, none of the tables used in cursor
definition.I make a commit hereitself.

Then i start with one more begin inside for loop to do a select statement for
fetching some values into variables and then
an insert with exception and come out of that begin

Now i go for some simple validations and then start with one more begin and
after a update (single row) and committing that update i come out of that begin.

Now i have one more update and i do a commit;
Loop ends here and then the main block also ends.

If I make one rollback segment with say initial 400K and next 400k
and minextents 3 and maxextents 500 and assign that rollback segment to this
transaction.

I can see wraps but no extends on this rollback segment.Also the
processing goes on for approx 50,000 rows and then it breaks with ORA-01555.

My Question is why does transaction break after 50,000 rows and that too when
wraps have been about 120 on that segment with no extends.
If it was to be due to rollback extent being over written then what makes it
happen after the extent being over written for 40 times and not at first
instance.

As far as processing of this transaction is concerned i have done it in my
production with more no of rollback segments and without error ORA-01555.

Please explain me the error occurance after 120 wraps and no extends and also
even after commiting at almost every update or insert.

There is no other transaction active while I am running this transaction.

Tks ,
Sushil.
and we said...
Basically -- your rollback segments are just too darn small -- committing like
this is the cause of your ora-1555.  You are probably in this case seeing the
effects of block cleanouts.

Here is an example of a 1555 on a READONLY tablespace for example!
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:895410916429
It is the same thing you are hitting.

It just happens to happen at 120 wraps cause we hit some data at that point that
we need rollback for and its simply not there anymore.

For the prior 50k rows -- we didn't or we did and the rollback we needed was
still found in the cache.

Your rollbacks with 400k and minextents 3 are WAY too small.  My small databases
start with

initial=1m=next
minextents=25
maxextents=255

Using "set transaction use rollback segment" only makes the problem WORSE (you
seem to be doing everything possible to CAUSE this to happen!).  I hate that
command.  By using that you are causing that single rbs to wrap even more (i use
it to demonstrate HOW to get 1555's -- I never use it for anything else).

Please -- just size your RBS reasonably, use equi-sized extents - stop using
"set transaction use rollback segment"
Review & Followup
Rating: 4
delayed cleanout November 13, 2001
Reviewer: Kamaljeet from New Castle
Tom ,
I have a doubt here.
In the following answer
http://asktom.oracle.com/pls/ask/f?p=4950:8:257295::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:275215756923,%7Bora%7D%20and%20%7B1555%7D
After stage-3 of example can some other transaction use slot number 3 of
transaction table ?
If so then what happens to the data block. Why i am asking this is if some
transactions uses changed data block then it revisits the transaction block to
make a change to data block.
But what if the transaction slot is overwritten. Then in what state the data
block is in? Changed Unchanged or what? How oracle deals with it.?

Followup:
Yup.

The block is "changed" -- the SCN is what tells us that -- so we'll roll the
block back (which will restore the transaction slot to "pre-stage-3") and we can
roll that block back and so on -- getting the block to what it was right at the
time we started our transaction.

November 13, 2001 Parag -- Thanks for the question regarding "Email Through Oracle.", version 8.1.7
You Asked
Hi Tom :

How are U . I have writtern one procedure for sending Email through Oracle. This
Code is working fine. I am able to send Mail with CC option. On that code , I
wan't some further enhancement. They are as follow.

1. I  am unable to send BCC. ( I need BCC option also)
2. If i am giving wrong Email address which is nopt exist then ,
Procedure should give some Error.
3. I need Sent Confirmation also. If abc is sending mail to xyz then after
sending mail , abc should get send receipt.
4. I need Read Confirmation also. That when xys will read the email , abc should
get read receipt.

Please gothrough the code & let me give ur feedback on same.

CREATE OR REPLACE PROCEDURE mail
  (
  sender      IN VARCHAR2,
  recipient   IN VARCHAR2,
  ccrecipient IN VARCHAR2,
  subject     IN VARCHAR2,
  message     IN VARCHAR2
  ) IS

  crlf VARCHAR2(2):= UTL_TCP.CRLF;
  connection utl_smtp.connection;
  mailhost VARCHAR2(30) := 'MyMailHost.com';
  header VARCHAR2(1000);

BEGIN

  -- Start the connection.

  connection := utl_smtp.open_connection(mailhost,25);

  header:= 'Date: '||TO_CHAR(SYSDATE,'dd Mon yy hh24:mi:ss')||crlf||
     'From: '||sender||''||crlf||
  'Subject: '||subject||crlf||
       'To: '||recipient||crlf||
       'CC: '||ccrecipient;

  -- Handshake with the SMTP server

  utl_smtp.helo(connection, mailhost);
  utl_smtp.mail(connection, sender);
  utl_smtp.rcpt(connection, recipient);
  utl_smtp.rcpt(connection, ccrecipient);
  utl_smtp.open_data(connection);

  -- Write the header

  utl_smtp.write_data(connection, header);

  utl_smtp.write_data(connection, crlf ||message);
  utl_smtp.close_data(connection);
  utl_smtp.quit(connection);

EXCEPTION
  WHEN UTL_SMTP.INVALID_OPERATION THEN
    dbms_output.put_line(' Invalid Operation in SMTP transaction.');
  WHEN UTL_SMTP.TRANSIENT_ERROR THEN
    dbms_output.put_line(' Temporary problems with sending email - try again
later.');
  WHEN UTL_SMTP.PERMANENT_ERROR THEN
    dbms_output.put_line(' Errors in code for SMTP transaction.');
END;

SQL>  execute mail(' "Parag" ','xyz.com','abc.com','Thanks Tom' , 'Tom is my
last hope for any Oralce Problem...');

PL/SQL procedure successfully completed.

Tom : Thaks a Lot.

Regards
- Parag
and we said...
You need to get a book on SMTP and learn the SMTP protocol (a network protocol).
 For example, sending a BCC is simple -- you just RCPT the person and DON"T put
them in a CC: or TO: record.  Thats how the "bcc" works -- you just don't list
them in the to or cc!  (you can put whatever you want in the to and cc fields --
they are just simple strings after all, they don't do anything to help send the
mail - the RCPT does that).

As for the email not existing -- you'll need to talk to your network guys and
have them configure the smtp server to do that -- note that you would not be
able to use this smtp server then to send email to tkyte@us.oracle.com -- you
cannot confirm "me".

A send reciept -- thats just a CC.  Just cc abc (or bcc them)

Return reciepts -- that you'll have to dig out the specs for the CLIENT SOFTWARE
you use.  The client does that.  You'll NEVER get a return reciept from me, I
disable that right away.  The "protocol" for doing that is 100% dependent on the
client and how it decided to implement that (if at all)
Review & Followup
Rating: 5
Email November 13, 2001
Reviewer: Ashokkumar from USA,JPMORGAN,NY
Tom
Vey Good Response

Can u suggest me a way to send xls file as an attachment using utl_smtp .(XLS
Stored as a blob in the database)(Pure pl/sql no java)

Followup:
Well, you are ALREADY using java!!! UTL_SMTP uses UTL_TCP and UTL_TCP in 8i is
Java.

See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1739411218448
it shows howto with a SIMPLE html attachment-  a binary file would be more
involved (you would have to write a base 64 encoder to encode the XLS file and
so on)

Since ALL of this code works in Java out of the box -- i would suggest you use
Java for doing this!  Its really easy.

Rating: 4
Problem with SMTP transaction January 25, 2002
Reviewer: Nishant Manchanda. from Tokyo,Japan.
Hi Tom,
I tried the procedure written by Mr.Parag.There is some problem relating to SMTP
transaction at my end.It displays the error handled in the exception.Please tell
me what has to be done for SMTP connection.
Thanking you,
regards,
Nishant Manchanda.

November 13, 2001 Lisa -- Thanks for the question regarding "Move indexes thru re-build", version 734 Sun Ultra
You Asked
In oracle 734 database, I have imported a user account from another database.
In Soruce db, the data is in one tablespace (ie. data_segs 200m) and index is in
another tablespace (ie. index_segs 200m), when I imported into target database,
it all got into one tablespace (data_segs) (400m). So I use the ALTER INDEX
rebuild method to move them into new index_segs for the new user account. I
checked  'select segment_name, segment_type, tablespace_name from user_segments'
and saw they are reside in the proper tablespaces.

Since the index has been stored in new index tablespace now, I tried to reduce
the size of data tablespace to 200m, but got ora-03297: file contains 6121
blocks of data beyond requested RESIZE value.
My question is:
The index data once created in data_segs, after rebuild into index_segs, what
happened
to these space in data_segs, are they empty ? can they reusable for later data
input?
Thanks your your help.
and we said...
Think of a datafile like a stack.  You put into this one tablespace data like
this:

table1
index on table 1
index on table 1
table 2
index on table 2
table 3
index on table 3
index on table 3
index on table 3
table 4
index on table 4

Now, you moved the indexes, you are left with:

table1
<free space>
<free space>
table 2
<free space>
table 3
<free space>
<free space>
<free space>
<free space>
table 4
<free space> <<<<<<<<<<<<<------------ this is the ONLY free space you can
                                       actually release -- table 4 is in the way

if you like, you can use this script which I call "maxshrink"

set verify off
column file_name format a50 word_wrapped
column smallest format 999,990 heading "Smallest|Size|Poss."
column currsize format 999,990 heading "Current|Size"
column savings  format 999,990 heading "Poss.|Savings"
break on report
compute sum of savings on report

column value new_val blksize
select value from v$parameter where name = 'db_block_size'
/

select file_name,
           ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) smallest,
           ceil( blocks*&&blksize/1024/1024) currsize,
           ceil( blocks*&&blksize/1024/1024) -
           ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) savings
from dba_data_files a,
     ( select file_id, max(block_id+blocks-1) hwm
         from dba_extents
        group by file_id ) b
where a.file_id = b.file_id(+)
/

column cmd format a75 word_wrapped

select 'alter database datafile ''' || file_name || ''' resize ' ||
           ceil( (nvl(hwm,1)*&&blksize)/1024/1024 )  || 'm;' cmd
from dba_data_files a,
     ( select file_id, max(block_id+blocks-1) hwm
         from dba_extents
        group by file_id ) b
where a.file_id = b.file_id(+)
  and ceil( blocks*&&blksize/1024/1024) -
          ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) > 0
/

-----------------------------------------------------

it'll create a report that shows how small your files can possibly be given the
data they have in them and generates the ALTER's to do it.

The space in the tablespace is free, subseqent creates, extends and so on will
use it.
Review & Followup
Rating: 4
Reader November 12, 2001
Reviewer: Reader from USA
Tom,

There had been some known bugs when resizing to lower
value in way back Oracle 7. Is it very very safe to resize to a lower size for
Production Databases in 8.1.6+ and up.
If the file is resized to a value below HWM, it will
just error out and would not cause any corruption, is it
true

Thanks

Followup:
It is safe -- the only issue I was aware of was on a control file rebuild in 7.2
-- it was fixed in 7.3.3 and up.

You cannot resize below the HWM, it will (always has) error out right away.

Rating: 4
November 13, 2001
Reviewer: Tianhua Wu
I remember there is a bug in 7.3 for datafile resizing.  It will cause the
datafile corrupted.  But I could not recall the detail though.  But I do
remember it is fixed in Oracle 8.

Followup:
I believe you might be talking about AUTOEXTENSION, where by a file that was
less than 2gig attempted to autoextend beyond 2gig but the support for large
files was not there.  It won't affect a shrink, and is controlled by setting the
maxsize on autoextensible datafiles.

Rating: 5
Excellent November 13, 2001
Reviewer: Lisa from TX
By running the script Tom provided, I can resize to 265M.
I choose to resize to 300M(leave some room) and successful.

Tom said "The space in the tablespace is free, subseqent creates, extends and so
on will use it."
Please clarify my thinking:
1.Rebuild index is like drop index from tablespace A and move them to tablespace
B ?
2. Rebuild index leave the original tablespace fragemented, and the only way for
tablespace A to compress data is by export/import the data ?

Followup:
1) correct, exactly

2) well, if you use equi-sized extents -- its not "fragmented" as each extent
can be reused.  If your indexes were sizable -- you just need to "alter
tablespace coalesce" and that will combint adjancent free extents into one big
free extent to be doled out as people need it.  You probably are not overly
fragmented here.

Rating: 4
November 13, 2001
Reviewer: Tianhua Wu from Atlanta, Ga
Here is what I find in Metelink (Note:1023229.6) for 7.3.2:

311905
Data file resizing may create problems (corruption) when using multiple
dbwriters. When a slave dbwr process tries to write to a file it has not
written to before it gets a copy of the File Identification Structure cloned
from the master dbwr. All slaves will share this FIB.  If a resize operation
occurs then a call is made to refresh the size information in the FIB. However
this update does not reach the slaves who are looking at an old STALE version
of this structure.

Followup:
Great -- thats easier then me guessing, corrected in all supported releases of
Oracle.

November 13, 2001 Ping -- Thanks for the question regarding "A SQL statement", version 8.1.7
You Asked
Hi Tom,

I have two tables, A and B, with the same structure, each of them has a unique
key. I want to select some columns from A where the key in A does not exist in
table B already. I want it in a select statement --I don't want to use minus to
generate a temp table first.

I know I can do something like:

select    RTRIM(GLH_TRAN_ID_NUM)       ,
        RTRIM(GLP_TRAN_ID_NUM)       ,
        RTRIM(ACCOUNT),
        RTRIM(ACTION_FLG)
from A
WHERE    GLP_TRAN_ID_NUM IN
    (SELECT GLP_TRAN_ID_NUM FROM A MINUS SELECT GLP_TRAN_ID_NUM FROM B);

I don't know how slow will that be -- A will have couple thousand records and B
has 50,000.

Do you have better way?

Thanks,

Ping
and we said...
Well, a minus wouldn't work here best AND a minus does not imply a temp table at
all.  In any case:

select *
  from a
 where NOT EXISTS ( select null from b where a.glp_tran_id = b.glp_tran_id )
/

is one way,
select *
  from a
 where glp_tran_id_num NOT IN ( select glp_tran_id_num
                                 from b )
/

is another and

select a.*
  from a, b
 where a.glp_tran_id_num = b.glp_tran_id_num(+)
   and b.glp_tran_id_num is null
/

Try them in that order...
Review & Followup
Rating: 4
A SQL Statement November 13, 2001
Reviewer: A reader
Could you please comment on "minus" as why it is not the best way to acomplish
this. Is it because minus will involve
two select statements? Thanks

Followup:
The minus just is not the most efficient way -- you have to create the "diff"
between B and A and then join the "diff" to A.

We can just look at A and find those rows NOT in B.

Most of the approaches below involve "two" queries if you count the subquery as
a query.

Rating: 4
November 13, 2001
Reviewer: Tianhua Wu from Atlanta, GA
Do you need to concern the null value when you compare the NOT IN and NOT EXIST
clause?

Followup:
If GLP_TRAN_ID_NUM is a primary key (i assumed it was, I now see you said
"unique" key) -- it will be NOT NULL.

If it can have nulls, you will need to code:

select *
  from a
 where glp_tran_id_num NOT IN ( select glp_tran_id_num
                                 from b where glp_tran_id_num is NOT NULL )
/

November 13, 2001 RAMASUBBAN -- Thanks for the question regarding "SQL PLUS REPORTS", version 8.1.6
You Asked
Tom,

I have a report to be generated like this in sql plus

City changes
company name   address  city state
xxx             xxxx     xxxx
xxxx            xxxx     xxxx

Adress changes
company name   address  city state
xxxx           xxxx     xxx  xxx
xxx            xxxx     xxx  xxx

For example if there is no address change I would like to have a message 'NO
address Change'.That is if the query does not return any rows.
How would you proceed?

Thanks
Bala
and we said...
You can use a method like this:

drop table address_changes;

create table address_changes( company_name varchar2(5), address varchar2(5),
city varchar2(5), state varchar2(5) );

insert into address_changes values ( 'comp1', 'addr', 'city', 'va' );
insert into address_changes values ( 'comp1', 'addr', 'city', 'va' );
insert into address_changes values ( 'comp1', 'addr', 'city', 'va' );

define msg="NO Address data selected"
column junk new_val msg
column junk noprint

select company_name, address, city, state, '' junk
  from address_changes
 where company_name = 'comp1'
/
prompt &msg

define msg="NO Address data selected"
column junk new_val msg
column junk noprint

select company_name, address, city, state, '' junk
  from address_changes
 where company_name = 'comp2'
/
prompt &msg

Here, the trick is -- msg contains some text we'll print out after every query.
If a column named JUNK is fetched from the database, its value will be placed
into this substitution variable.  We'll just add a "'' junk" to our query -- and
set it to not print.  If we fetch at least one row -- the msg is blanked out.
No rows -- message persists.  If you run this, you'll see:

COMPA ADDRE CITY  STATE
----- ----- ----- -----
comp1 addr  city  va
comp1 addr  city  va
comp1 addr  city  va

no rows selected

NO Address data selected
Review & Followup
Rating: 4
November 13, 2001
Reviewer: A reader
Tom,

Works fine and Thanks a lot.

Regards

November 13, 2001 Daryl -- Thanks for the question regarding "Allocating a large initial extent", version 8.1.7
You Asked
Tom,

This is a follow up on my last question that I asked.  We have a handful of
tables that are at least 3 gigs of data, and they are truncated monthly and bulk
loaded by an import in a single nights event.  You said to use uniform extents.

What's the disadvantage by initially grabbing 2 gigs and having the next extent
64M since we know that the tables are always going to be at least 3 gigs.

If there is no disadvantage...would I have to use the autoallocate option in the
create tablespace SQL for locally managed tablespaces?
Then, do I also have to clarify a PCTUSED and PCTFREE.

How does the SQL look for using the AUTOALLOCATE option?

Thanks.
and we said...
The disadvantage if you would not be using LMT's and I love LMT's and use
nothing but LMT's.

You would have to use a dictionary managed tablespace and that just is not the
future of tablespaces.  Especially in 9i when we do to freelists what we did to
tablespaces (automatic space management that obsoletes freelists, freelist
groups and pctused in the way LMTS obsoleted pctinc, initial, next, and
minextents)

You could not use autoallocate -- there you have NO control over the extent
sizes, there is some magical and wholly undocumented method we use ( i cannot
firmly figure it out myself ).
November 14, 2001 rd -- Thanks for the question regarding "google discussion forum", version 8.1.7
You Asked
Tom

I remember in some of your answers,where in you referred to discussion forums on
Google where in you took part in discussions,
can you give some details.

In fact can you give the details of all the places on web, where you are
involved in discussions  or any other stuff.

thank you
and we said...
I hang out here (obviously) and many times can be found lurking on the usenet
newsgroups (with tons of other people).

See
http://groups.google.com/googlegroups/deja_announcement.html
to sign up there, some first class people out there answering questions.
Review & Followup
Rating: 5
You did not tell us about Netsys.com November 14, 2001
Reviewer: A reader
Tom

Do you also do Oracle discussions on Netsys.com.
Can you give a complete list of discussion forums where we can find your
discussions.

Thank you

Followup:
I've never heard about netsys.com -- it's not database related.

I hang out here (obviously) and on the USENET newsgroups

comp.database.oracle.server
comp.database.oracle.tools
comp.database.oracle.misc

all available on google.

November 14, 2001 Munzer -- Thanks for the question regarding "PL/SQL from html", version 8i
You Asked
Tom:

If I have an HTML form with several "submit" buttons that should do different
things.  E.G. a button to update and save a record, a button to show details
about a record and a button to search for new record.

Each button runs a different PL/SQL stored procedure and creates a new form.

Since, after you submit a form you can only run one procedure defined in the
action attribute how can you run these three different ones with each button
press.

Also, can you run a PL/SQL procedure from a hyperlink on a HTML list?

Thank you
and we said...
Well, you can use javascript to run different procedures but the approach I
typically take is to run ONE procedure that decides which procedure to actually
run.  I name the BUTTON so I can tell what button was pressed:

<form action=my_pkg.foo method=post>
<input type=text name=field1><br>
<input type=text name=field2><br>

<input type=submit name=button value=Insert>
<input type=submit name=button value=Update>
</form>

create package my_pkg
as
   procedure foo( button in varchar2, field1 in varchar2, field2 in varchar2 );
end;
/

create package body my_pkg
as
   procedure do_insert( field1 in varchar2, field2 in varchar2 )
   is
   begin
         ...
   end;
   procedure do_update( field1 in varchar2, field2 in varchar2 )
   is
   begin
         ...
   end;

   procedure foo( button in varchar2, field1 in varchar2, field2 in varchar2 )
   is
   begin
          if ( button = 'Insert' ) then do_insert( field1, field2 );
          elsif ( button = 'Update' ) then do_update( field1, field2 );
          else htp.bold( 'somethings wrong' );
          end if;
   end;
end;
/

Running a plsql routine from a hypertext link is simple:

<a href=/dad/plsql/my_pkg.foo?button=Insert&field=hello&field2=world>
click me to insert hello world
</a>
Review & Followup
Rating: 3
howto question November 14, 2001
Reviewer: Igor from France
How should I setup my environment to try this
example? (I don't know how HTML form could see
DB package)

                           Igor

Followup:
You need to have OAS or iAS.  If you have either of these, you simply need to
setup and configure the PLSQL cartridge/module.

see
http://technet.oracle.com/docs/products/ias/doc_library/1022doc_otn/index.htm
...

November 15, 2001 Jim -- Thanks for the question regarding "Why do I loop after the NOTFOUND?", version 8i
You Asked
Admitted newby to plsql and this may be a classic example of where I should use
the select instead of the explicit cursor.  Read the thread on that discussion
but still don't understand the problem I see in my logic.  Here is close to what
it looks like:

SELECT A.EID FROM GEO_STREET_NAMES A
  2  WHERE A.EID  = 51;

       EID

----------

        51

SQL> declare
  2  STR_ID NUMBER(9);
  3  CURSOR ACursor IS
  4   SELECT A.EID FROM GEO_STREET_NAMES A
  5   WHERE A.EID  = 51;
  6  BEGIN
  7  OPEN ACursor;
  8  LOOP
  9      FETCH ACursor INTO str_id;
 10      DBMS_OUTPUT.PUT_LINE('STREET # :' || STR_ID);
 11  EXIT WHEN ACursor%NOTFOUND;
 12      DBMS_OUTPUT.PUT_LINE('LAST STREET # :' || STR_ID);
 13  END LOOP;
 14  END;
 15  /
STREET # :51

LAST STREET # :51

STREET # :51

PL/SQL procedure successfully completed.

SQL>

As you can see from the first select, there is only one row.  Yet from the
displays, it appears to loop twice.  This is why I am experiencing a perplexing
end-of-file problem.  I need/use several variables from the fetch so I was told
I couldn't use the implied cursor.  I apologize if this is too basic a question
but would appreciate the assistance.
and we said...
It does loop two times.

Once to fetch the record.
The second one hits the no data found.

You have to find no data in order to get no data found!

You always will code:

open c;
loop
    fetch c into ...;
    EXIT WHEN C%NOTFOUND;

    process fetched record
end;
close c;

If you want to code performant, easy to read code that will run faster and be
easier to maintain then the above, you will simply code:

begin
    for x in ( select a.eid from geo_street_names a where a.eid = 51 )
    loop
       dbms_output.put_line( .... );
    end loop;
end;
/

thats it -- no declares, no cursors, no open, no close - just you and your code,
short, sweet, simple, fast.
Review & Followup
Rating: 4
November 13, 2001
Reviewer: Jim Powell from Dallas, TX USA

Rating: 3
Question on explicit vs. implicit November 14, 2001
Reviewer: Chaim Moshe Tessler from Israel
Based on your answer would there be an example
when you would recommend an explicit cursor
and not implicit cursor ?
(When for example to implicit cursor(s) close ?)

Followup:
I use explicit cursors ONLY when I *have* to.

That is -- when using a REF CURSOR.

Otherwise I never ever use them.  Takes more keystrokes, runs slower.  Don't see
the benefit in them.

Rating: 5
Less key storess , Yes , but .... November 14, 2001
Reviewer: Nag
Tom

From your indepth discussions on explicit and implicit cursors, I infer that

When we explicitly open and close a cursor then it is explicit.

When the cursor is opened and closed implicitly then it is an implicit cursor.

I accept that implicit cursors lead to less key strokes. But the amount of time
taken to open and close a cursor should be very little. Is that such a huge
benefit, that you always ( and very adamantly) write off explicit cursors.

Followup:
Well, why don't we try it and see?

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x int );
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 1 );
1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> commit;
Commit complete.

ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2      l_start number;
  3
  4      cursor c1 is select * from t;
  5      n      number;
  6  begin
  7      l_start := dbms_utility.get_time;
  8      for i in 1 .. 1000
  9      loop
 10          open c1;
 11          loop
 12              fetch c1 into n;
 13              exit when c1%notfound;
 14          end loop;
 15          close c1;
 16
 17          -- now lets simulate a SELECT into as well
 18
 19          open c1;
 20          fetch c1 into n;
 21          if ( c1%notfound ) then raise NO_DATA_FOUND; end if;
 22          fetch c1 into n;
 23          if ( c1%found ) then raise TOO_MANY_ROWS; end if;
 24          close c1;
 25
 26      end loop;
 27      dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
 28
 29      l_start := dbms_utility.get_time;
 30      for i in 1 .. 1000
 31      loop
 32          for x in ( select * from t )
 33          loop
 34              null;
 35          end loop;
 36
 37          select * into n from t;
 38      end loop;
 39      commit;
 40      dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
 41  end;
 42  /
54 hsecs
42 hsecs

PL/SQL procedure successfully completed.

Ok, so what we have is:

o it takes more code to write explicit cursors
o it is more error prone, you must remember to open them, close them
o you have to declare all of the variables all of the time (nothing
  like a cursor for loop for ease of programming if you ask me)
o they are measurably slower

Well, I haven't found anything good to say about them.  I'm a polarized sort of
guy -- far too many people believe the total opposite, that EXPLICIT cursors are
the only way to program.  I'm on a crusade to put that myth to rest, along with
the myths that

o more then a single digit number of extents is bad (false)

o the most discriminating fields should be on the leading edge of an index
(depends)

o you don't need to understand the database, its just a black box (totally
false)

o explicit cursors are faster then implicit (provably false)

and so on.
I figure people are going to pick one or the other here -- implicit or explicit.
 They should pick implicit, period, plain and simple.

Rating: 5
Implicit Vs. Explicit cursors. November 14, 2001
Reviewer: Scott Watson from Montreal, Canada
Very interesting Tom, but I needed to prove this to myself and therefore called
on dbms_profiler to see what it had to say.

Explicit
 47.853066        cursor c1 is select * from t;
                  n      number;
                  begin
  1.1920017           for i in 1 .. 1000
                      loop
   .48333280              open c1;
                          loop
 84.425063                   fetch c1 into n;
  1.3781577                  exit when c1%notfound;
                          end loop;
  1.1353816               close c1;
                          -- now lets simulate a SELECT into as well
   .52310376              open c1;
 37.182641                fetch c1 into n;
   .47884312              if ( c1%notfound ) then raise NO_DATA_FOUND; end if;
 27.758576                fetch c1 into n;
   .72809931              if ( c1%found ) then raise TOO_MANY_ROWS; end if;
  1.1030756               close c1;

Implicit

 78.293107         for x in ( select * from t )
                   loop
  1.4356460            null;
                   end loop;

 62.485708         select * into n from t;

Yup, implicit cursors are faster, however, if we remove the time to declare the
cursor the times are pretty close.  I wonder why this overhead exists on the
cursor c1 definition but not on the for loop?  Any insights?

Thanks for the information.

Followup:
Well, the cursor declare is not really "executed" -- its the act of explicitly
opening, closing and fetching that adds time indirectly to it.

The cursor definition takes really 0 seconds -- nothing (its just a definition
after all).  Its the code that opens/closes and touches it that indirectly
appear to add time to that line.

Note that you cannot remove the time to "define" the cursor as then you wouldn't
have an explicit cursor test!

Rating: 5
Implicit always better ?? November 15, 2001
Reviewer: jeroen from Singapore
Hi Tom,

About explicit cursors, you say it is just "you and your code".
Suppose that "in the real world" you are working with a team of developers,
where some are better than others in optimizing SQL.
Than you could have one package containing all the explicit cursors (whose
functionality is strictly defined and cannot change on account of a single
programmers needs), and any number of procedures using them.
I think that would be wonderful for your parse ratios, and you would also be
saving a lot of duplicate work, and making the code very maintainable in case of
changes in table structures.
It is obvious this scenario is dependent on good coordination of team efforts,
but I would say there are benefits to this approach.
Would you agree about this, or is this also a myth ?

Kind regards,

Jeroen

Followup:
Great -- you can still use them implicitly (some people might call those 'views'
might they?)

scott@ORA817DEV.US.ORACLE.COM> create or replace package tuned_queries
  2  as
  3          cursor c1 (p_ename in varchar2 ) is
  4          select ename, empno from emp where ename like p_ename;
  5  end;
  6  /

Package created.

scott@ORA817DEV.US.ORACLE.COM>
scott@ORA817DEV.US.ORACLE.COM> create or replace procedure p
  2  as
  3  begin
  4          for x in tuned_queries.c1( '%A%' )
  5          loop
  6                  dbms_output.put_line( x.ename || ',' || x.empno );
  7          end loop;
  8  end;
  9  /

Procedure created.

scott@ORA817DEV.US.ORACLE.COM>
scott@ORA817DEV.US.ORACLE.COM> exec p
A,7369
ADAMS,7876
ALLEN,7499
BLAKE,7698
CLARK,7782
JAMES,7900
MARTIN,7654
WARD,7521

PL/SQL procedure successfully completed.

Not nearly as readable -- since the query isn't there (must cross reference) and
you do lose the performance edge (they are more or less the same now), but the
coding ease is still there.

Perhaps I would consider getting some views in place or training people on how
to write SQL better.  I find most people, when given the tools (eg: access to
tkprof and a lesson on how to use the results) are more then willing to make
their sql go faster...

So you have the option of

o using packaged cursors
o using views

short of training...

(this is not a myth, however I think it can be greatly impacted by giving people
access to the tools they need.  I would say probably 80% or more of sites have
NEVER HEARD of tkprof (lack of training), and of those that have heard of it the
DBA's have draconian rules the prohibit access to the tool!! (amazes me each and
every time))

November 16, 2001 ted -- Thanks for the question regarding "customize sqlplus prompt in unix", version 8.1.6
You Asked
thomas, how do i make connect.sql visible in unix.
I have connect.sql in $ORACLE_HOME/sqlplus/admin. when I am
in this directory, @connect worked. If I am in a different unix
directory @connect does not work with error message stating
connect can not be found.
thnx ted
===
attached last reply from you.

What I do is use a login.sql file to set the prompt upon login.

I've trained myself to use:

SQL> @connect

instead of

SQL> connect

where connect.sql is:

connect &1
@login

in that way, the prompt is accurate.  If you are ever confused,
just run

SQL> @login
and we said...
set your SQLPATH environment variable:

SQLPATH=/export/home/tkyte/src/sqlstuff

we'll look in the current working directory AND the sqlpath
directory for scripts.
Review & Followup
Rating: 5
connect.sql suggestion November 16, 2001
Reviewer: Chip Briggs from Denver, CO USA
To transparently preserve the sql buffer contents while
connecting to a different database, I use this connect.sql:

SET TERMOUT OFF
SAVE afiedt.buf REPLACE
CONNECT &1
@login
GET afiedt.buf NOLIST

Followup:
I like that one -- i added it already, very nice touch.

Rating: 5
November 16, 2001
Reviewer: Tianhua Wu from Atlanta, GA
I love both of the tips.

November 16, 2001 Tomas -- Thanks for the question regarding "Column references in Fine Grained Access Control", version 8.1.7
You Asked
This question is out of curiosity rather than a problem :)

I have implemented Fine Grained Access Control and it was quite easy
and it works really well. However, the other day I started thinking
about how it "really" works.

Let's say I have a table, numtab, with just one column, numcol, and
a policy function that perhaps returns a predicate like
  'numcol = 4'

If I do a
  select * from numtab;
this will, according to your article, be translated into
  select * from ( select * from numtab where numcol = 4 );

OK, fine. Now, what if I do a join with another table, texttab, that
also has a column called numcol?
  select * from numtab n, texttab t where n.numcol = t.numcol;

How is the naming conflict resolved? The predicate just mentions
numcol and that exist in both numtab and texttab.

Is there any way of seeing the modified statement that is actually
executed against a table with a policy? I looked in both v$sqlarea
and v$sqltext but could only find the original statement.

Thanks for a great service

Tomas Albinsson
Stockholm, Sweden
and we said...
Well, the query:

 select * from numtab n, texttab t where n.numcol = t.numcol;

will be rewritten as:

 select *
   from (select * from numtab where numcol = 4 ) n,
        texttab t
  where n.numcol = t.numcol;

so, there is no ambiguity -- in the inline view, there is only one NUMCOL --
that from the numtab table itself.  The texttab table isn't in scope yet.

You cannot see the modified statement -- it is rewritten at a lower level and is
not visible.
Review & Followup
Rating: 5
November 14, 2001
Reviewer: Tomas Albinsson from Stockholm, Sweden
Thanks for a good and fast answer.

I guess you're not allowed to see the final statement as it
might be a security risk.

Kind regards

Tomas Albinsson

Rating: 4
There is a way November 16, 2001
Reviewer: Georg Feinermann from Germany
Hi Tomas,

I asked Oracle support how to make the result statements visible and they gave
the following answer (I am using 8.1.6):

ALTER SESSION SET EVENTS '10730 TRACE NAME CONTEXT FOREVER, LEVEL 1';

which will create a trace file including the full (resolved) SQL string. It's
not very convenient (e.g. a resolution of a complex view based on many tables
each with RLS), but it could be helpful.

I hope, this will help

Followup:
I do not publish the undocumented here.  Events are releasable by support only
(thats the rule).  But -- since you put it here, there is nothing i can do about
it ;)

thanks....

Rating: 5
when using a subquery August 24, 2003
Reviewer: Mark Wooldridge from Vienna VA
It seems like a subquery can cause problems if the subquery contains a column
with the same name as the table it is applied to.  For example, if the predicate
returned is 'exists (select null from numtab_acl a where a.numcol = numcol).  If
one was expecting this would only return rows from numtab when the value of
numcol is in numtab_acl. They would be incorrect.

To solve this problem I alais the subquery table and use the parent table name
for columns that have the same name as columns in my subquery table. This works
because of the elegant way Oracle rewrites the query - using an inline view.

The predicate should be 'exists (select null from numtab_acl a where a.numcol =
numtab.numcol)'  This works even if the original table was aliased since the
alias would be on the inline view.

Example.

create table numtab_acl
(numcol  number)
/

Given the following query
select *
  from numtab bb
/

would be rewritten as

select *
  from (select *
          from numtab
         where exists (select null
                         from numtab_acl a
                        where a.numcol = numtab.numcol)) bb
/

Hope this helps all those implementing their own RLS/FGAC.

Mark Wooldridge

November 16, 2001 Munzer -- Thanks for the question regarding "Circular Reference Error", version 8I
You Asked
Tom:

I have two tables that I try to create:

Users
--------
User_ID
User_Name
Password
Group
Warehouse_ID  (Foreign key to Warehouse(warehouse_ID)

Warehouse
---------
Warehouse_ID
Name
Address
User_ID (Foreign Key to Users(User_ID)
Creation_Date

Problem is I get oracle error when I try to create the tables because they are
dependent on each other.  Is there any way around it?

Shall I create the foreign key constraints separately after table creation?
and we said...
There are two ways to do this basically, both are demonstrated below:

ops$tkyte@ORA9I.WORLD> drop table t1 cascade constraints;
Table dropped.

ops$tkyte@ORA9I.WORLD> drop table t2 cascade constraints;
Table dropped.

ops$tkyte@ORA9I.WORLD> create schema authorization ops$tkyte
  2  create table t1( x int primary key, y int references t2 )
  3  create table t2( y int primary key, x int references t1 )
  4  /
Schema created.

ops$tkyte@ORA9I.WORLD> drop table t1 cascade constraints;
Table dropped.

ops$tkyte@ORA9I.WORLD> drop table t2 cascade constraints;
Table dropped.

ops$tkyte@ORA9I.WORLD> create table t1 ( x int primary key, y int );
Table created.

ops$tkyte@ORA9I.WORLD> create table t2 ( y int primary key, x references t1 );
Table created.

ops$tkyte@ORA9I.WORLD> alter table t1 add constraint t1_fk_t2 foreign key(y)
references t2;
Table altered.

The create schema is nifty -- it allows you to gather up many DDL statements
into one atomic statement, either ALL tables create or NO tables create.  You
can use tables, views and grants in the create schema statement.
Review & Followup
Rating: 5
Pretty cool November 16, 2001
Reviewer: Doug from CT, USA
Didn't know that one

Rating: 5
"create schema ..." is good but... September 22, 2003
Reviewer: Xuequn Xu
Why it can only take "create table", "create view" and "grant"? I wanted to
group "create index" and maybe other stuff under "create schema" but it errored
out.

November 16, 2001 Menaka -- Thanks for the question regarding "Sql Help", version 8.0.5.0.0
You Asked
Hi Tom,

Need help with a sql query

I have table ord with two columns col1 , col2 the data in the column looks like
below
col1    col2
A         B
B         A
C         D
E         F
F         E

I need a SQL which produces the following output..with out using decode or rowid
or rownum....
Col1   Col2
A        B
C        D
E        F

Basically i am eliminating the Rows which has got reverse entry..like B and A ,
F and E...

Please help me in this query ??

Thanks,
Menaka
and we said...
ops$tkyte@ORA815.US.ORACLE.COM> select *
  2    from t
  3   where NOT EXISTS ( select null
  4                        from t t2
  5                       where t2.col1 = t.col2
  6                         and t2.col2 = t.col1
  7                         and t.col1 > t2.col1 );

C C
- -
A B
C D
E F
November 16, 2001 Krish -- Thanks for the question regarding "Partitioning the Non-partitioned table", version 8.0.5
You Asked
Tom - could you tell me how to do the partitioning for a
non-partioned table without exporting and creating the table
from
the scartch.
Can I use ALTER TABLE STATEMENT?? I am getting errors....

 ERROR - INVALID DATA TYPE

ALTER TABLE table_name ADD PARTITION BY RANGE(field_name)
 (PARTITION partition_name VALUES LESS THAN
     (TO_DATE('04-APR-1999', 'DD-MON-YYYY'))
       TABLESPACE tablespace_name,
  PARTITION partition_name VALUES LESS THAN
     (TO_DATE('04-JUL-1999', 'DD-MON-YYYY'))
       TABLESPACE tablespace_name,
  PARTITION partition_name VALUES LESS THAN
     (TO_DATE('03-OCT-1999', 'DD-MON-YYYY'))
       TABLESPACE tablespace_name,
  PARTITION partition_name VALUES LESS THAN
     (TO_DATE('02-JAN-2000', 'DD-MON-YYYY'))
       TABLESPACE tablespace_name) NOCACHE
/

Please advise.

Thanks,
Krish
and we said...
You cannot alter a table and turn it into a partitioned object.
The entire object must be recreated -- every row will go into
some new space.

You can either

o create new_table as select ....
  drop old_table
  rename new_table to old_table

o exp old_table
  drop old_table
  create old_table with partitions
  imp old_table ignore=y

this object must be recreated.
Review & Followup
Rating: 5
syntax November 16, 2001
Reviewer: Nag
Tom

I have a regular table t, I need to change it into a partitioned table.

we want to do a 'create new_table as select ....' and change it into a
partitioned table.

can you kindly gives us an exmaple of doing the same.

It is presumably being difficult to get the syntax from teh wire diagram for
create table.

Thank you

Followup:
create table ....;

insert /*+ append */ into table select * from old_table;

would be easiest.  however, the wire diagram for this is easy -- subquery goes
dead last.

ops$tkyte@ORA817DEV.US.ORACLE.COM> CREATE TABLE t(
  2  COLLECTION_YEAR     ,
  3  COMPOUND_NUMBER     ,
  4    constraint HIST_PART_RANGE_LOCPREINDX_PK PRIMARY KEY(COLLECTION_YEAR,
COMPOUND_NUMBER)
  5    deferrable initially immediate
  6    using index local
  7    storage ( MINEXTENTS 1 MAXEXTENTS UNLIMITED PCTINCREASE 0 )
  8  )
  9  STORAGE ( MINEXTENTS 1 MAXEXTENTS UNLIMITED PCTINCREASE 0 )
 10  PARTITION BY RANGE (COLLECTION_YEAR) (
 11    PARTITION PART_95 VALUES LESS THAN (1996) ,
 12    PARTITION PART_96 VALUES LESS THAN (1997) ,
 13    PARTITION PART_97 VALUES LESS THAN (1998) ,
 14    PARTITION PART_98 VALUES LESS THAN (1999) ,
 15    PARTITION PART_99 VALUES LESS THAN (2000) ,
 16    PARTITION PART_00 VALUES LESS THAN (2001) ,
 17    PARTITION PART_01 VALUES LESS THAN (2002) )
 18  as
 19  select to_number(to_char(created,'YYYY')), object_id from all_objects where
rownum < 10
 20  ;

Table created.

Rating: 5
Got it November 16, 2001
Reviewer: Nag
Followed the wire diagram carefully, and got it . Feels Good.

SQL> ed
Wrote file afiedt.buf

  1  cREATE TABLE EMP1
  2  PARTITION BY RANGE(HIREDATE)
  3  (PARTITION P1 values less than (MAXVALUE) )
  4   AS SELECT ENAME,SAL,HIREDATE
  5* FROM EMP
SQL> /

November 16, 2001 Daryl -- Thanks for the question regarding "Passing array of BLOBs from PL/SQL to Java?", version 8.1.7
You Asked
In Appendix A of your book, you have some excellent code samples showing how to
use the JavaMail API to send an email message with a single binary attachment
(word processor document, etc.). The code given uses a Java Stored Procedure,
coupled with the PL/SQL interface.

However, you left passing arrays of BLOBs as "an exercise for the reader". I've
looked through the Oracle documentation for Java programming in the database,
and I just can't seem to fit enough of the different pieces together to send an
array (i.e., a PL/SQL table) of BLOBs to a Java stored procedure. My particular
application needs the ability to send multiple attachments. Can you flesh this
out a bit?

Thanks for the helpful answers in this forum and the really great stuff in the
book.
and we said...
Well, whats the fun of leaving exercises for the reader if I end up having to do
them anyway!!! :)

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace type blob_arr as table of
blob
  2  /
Type created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace and resolve java source
named "BlobArray" as
  2  import java.io.*;
  3  import java.lang.*;
  4  import oracle.sql.*;
  5  import oracle.jdbc.driver.*;
  6  import java.sql.*;
  7
  8  public class BlobArray {
  9    public static void doWork(oracle.sql.ARRAY blobs) throws Exception {
 10      DriverManager.registerDriver(new OracleDriver());
 11      Connection conn = DriverManager.getConnection("jdbc:oracle:kprb:@");
 12      conn.setAutoCommit(false);
 13      OracleResultSet rs = (OracleResultSet) blobs.getResultSet();
 14      PrintStream os = new PrintStream(System.out);
 15
 16      for (int i = 0; rs.next(); i++) {
 17        BLOB b = rs.getBLOB(2);
 18              int length = (int) b.length();
 19              int bufferSize = b.getBufferSize();
 20              byte[] buffer = new byte[bufferSize];
 21              InputStream is = b.getBinaryStream();
 22
 23              while ((length = is.read (buffer,0,bufferSize)) != -1) {
 24          os.write(buffer, 0, length);
 25              }
 26
 27              os.println();
 28        os.println("===========================");
 29      }
 30
 31      os.println();
 32      os.println("JAVA PART IS DONE");
 33      os.flush();
 34    }
 35  }
 36  /

Java created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace procedure
DUMP_BLOB_ARRAY(p_blobs in BLOB_ARR)
  2  as language java name 'BlobArray.doWork(oracle.sql.ARRAY)';
  3  /

Procedure created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> set serveroutput on size 10000
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_java.set_output(10000)

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2    blobs blob_arr := blob_arr();
  3    l_msg varchar2(255);
  4    l_amt binary_integer;
  5  begin
  6    for i in 1..3 loop
  7      l_msg := 'This would be binary data for message #' || i;
  8      l_amt := length(l_msg);
  9      blobs.extend(1);
 10      DBMS_LOB.CREATETEMPORARY(blobs(i), FALSE);
 11      DBMS_LOB.OPEN(blobs(i), DBMS_LOB.lob_readwrite);
 12      DBMS_LOB.WRITE(blobs(i), l_amt, 1, UTL_RAW.CAST_TO_RAW(l_msg));
 13    end loop;
 14
 15    DUMP_BLOB_ARRAY(blobs);
 16
 17    for i in 1..3 loop
 18      DBMS_LOB.FREETEMPORARY(blobs(i));
 19    end loop;
 20  end;
 21  /
This would be binary data for message #1
===========================
This would be binary data for message #2
===========================
This would be binary data for message #3
===========================
JAVA PART IS DONE

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
Review & Followup
Rating: 5
Thanks November 16, 2001
Reviewer: Daryl
This is a very helpful response. In the book, a short pointer like "You'll have
to use a collection type in the database" would've gotten me going. Or, can I
use a PL/SQL table for this (where no CREATE TYPE is done)?

Followup:
Ok, point taken....  I understand.

In the Java Stored procedure chapter, it demonstrates how to pass collections
(arrays in a sense) back and forth.  there I demonstrate string, dates, numbers
-- not significantly different from blobs.

The collection must be a SQL type.  Using the 817 THICK JDBC drivers -- it is
possible to have java send to PLSQL an PLSQL tabletype -- but there is no
corresponding binding the other way.

Rating: 5
January 02, 2004
Reviewer: A reader

November 16, 2001 Anne -- Thanks for the question regarding "Temporary Table vs single query", version 8i
You Asked
From an earlier Question/Answer you write ...

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Question:
5.Will there be any performance improvement using global temporary tables? can
you give an example where using a global temporary tables improves performance?

Answer:
5) depends on what you are doing.  I don't use them or "intermediate" result
sets myself as many people are brain washed into doing from experiences with
SQLServer and the like.  I do the work in a single query.  .....
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

This intriques me.  I have a procedure that needs to return a cursor which, if
done in one pass, looks to me like it will be hideously long.  The concept of
using an "intermediate" result and updating that seems like the only way to
ensure that it doesn't execute parts more times than necessary.  My simplified
example:

Transaction Table:
part_no   varchar2(10)
qty_sold  number(8)
tran_date date
price     number(8,2)
*  table could have 200,000 rows; 25 unique part_no's

I need to return a cursor in a stored procedure that contains one row for each
unique part_no (ie 25 rows) and contains
1. part_no
2. Total qty_sold
3. Last price that the part was sold for

I can't think of how to do that in one query, much less ensure that the "last
price" isn't searched for 200,000 times.  Can you tell me the BEST way to do
this, considering that we are dealing with a Data Warehouse on the backend?

Thanks
and we said...
Here is a trick i use when I need to get data like "the last price that the part
was sold for".  Assume I have data loaded up (your 200,000 rows)

DOC>create table t ( part_no varchar2(10),
DOC>                                 qty_sold  number,
DOC>                                 tran_date date,
DOC>                                 price     number );
DOC>declare
DOC>        l_part_no varchar2(10);
DOC>begin
DOC>        for i in 1 .. 25
DOC>        loop
DOC>                l_part_no := dbms_random.string( 'a', 10 );
DOC>                for i in 1 .. 8000
DOC>                loop
DOC>                        insert into t values ( l_part_no,
DOC>                                          dbms_random.value( 1, 1000 ),
DOC>                                          sysdate-dbms_random.value(1,1000),
DOC>                                          dbms_random.value( 1, 1000 )/2 );
DOC>                end loop;
DOC>        end loop;
DOC>end loop;
DOC>/
DOC>
DOC>
DOC>*/

I run a query like this:

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select part_no, qty,
to_number(substr(max_price,16)) price
  2  from (
  3  select part_no,
  4             sum(qty_sold) qty,
  5             max( to_char( tran_date, 'yyyymmddhh24miss') || '/' || price )
                                                                      max_price
  6    from t
  7   group by part_no
  8           )
  9  /

PART_NO           QTY      PRICE
---------- ---------- ----------
BH\rgPdOAm 4015218.21 317.848247
DMtESN`BZF 3970748.25 280.408863
Ebo`gDiSFF 3954301.05 480.440545
Efro\CGFP\ 3989586.15 110.796655
FbDPCVV[U\  3967964.1 151.394533
Lm\Mkq[``Z 4006725.73 318.423974
MQdAFaWPIo 4023327.35 461.226982
U[i[NJRtd] 4009448.18 278.874234
UtNAQfemYP 3981840.55 376.057365
V[fLTRoElp 4006070.01  282.55744
VrBkkS``ii  3990596.6 444.806519
XH\sFTDKm] 3997581.06 264.543268
YhC[acePi] 3983697.35 108.051863
[OpPOBTbj_ 4016994.35 401.426913
_VTgLDjhht 3994016.41 357.018348
d[oeF_jngA 3996627.73 198.383359
eKDCh_RrqO 3954680.99 174.840716
i`NHiYRaKc 4027057.86 213.274092
kaNZgBcREr 4043014.26  219.62832
kjLm`kTIB_ 3998182.66 365.428061
l`LFbDU_MV 3999645.75 73.9165855
nLRRT`PWaV  4005948.4 386.140121
oILFqpKJKV  3991702.4 250.929279
qOZloLfQCN 4025751.88 359.500798
rolRAmEstl 4013841.69 288.579791

25 rows selected.

What I did was glue the TRAN_DATE and PRICE together into a string that sorted
properly -- take the MAX (gives the max tran_date) and substr back out the
price.

Makes one pass at the table, on my system, tkprof says:

select part_no, qty, to_number(substr(max_price,16)) price
from (
select part_no,
       sum(qty_sold) qty,
       max( to_char( tran_date, 'yyyymmddhh24miss') || '/' || price ) max_price
  from t
 group by part_no
     )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        3      4.89       4.88          0       1870          6          25
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        5      4.90       4.89          0       1870          6          25

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 63

Rows     Row Source Operation
-------  ---------------------------------------------------
     25  VIEW
     25   SORT GROUP BY
 200000    TABLE ACCESS FULL T

little less then 5 seconds on my machine -- and no double reads of any data....
Review & Followup
Rating: 5
Bravo November 16, 2001
Reviewer: Mark from Ca
short, sweet and elegant. very helpful.

Rating: 5
Temporary table vs single query November 19, 2001
Reviewer: Anne C Murphy from Exton, PA USA
This is exactly what I needed and saves hours of work, and wasted time from
going down the wrong path.
Thank you so much.

Rating: 5
absolute March 30, 2002
Reviewer: bala from India
crisp,great.........

November 17, 2001 jitender -- Thanks for the question regarding "Getting out of wait", version 7.3.4
You Asked
Hi Tom,
   My question is if a transaction 'A' is waiting to get a lock
on a few rows of a table which is presently held by another txn
'B' is there a possibility that the txn 'A' waits for the lock
for some "time" and if it is not able to aquire it it comes out
of the wait ie I want to know if there is any parameter which we
can set so that the txn waits for so many  seconds and comes out
of the wait state ?
and we said...
No, you can either

o wait indefinitely.
o not wait at all.

You already know how to wait indefinitely... To not wait, you
would

"select * from T where .... FOR UPDATE NOWAIT"

the rows.  You'll get an ORA-54 if they are already locked by
someone.
Review & Followup
Rating: 5
November 16, 2001
Reviewer: Nag
select * from T where .... FOR UPDATE NOWAIT

Tom, if we do the above, the problem is that if the required rows are already
locked by someone else, then my process will fail. May be that is the reason why
nowait option is very scarcely used.

1.When the above said error happens , is it possible to find out which process
or application or user has blocked those rows, and throw an exception giving the
information to the user.

2.Do  you recommend the use of nowait option.

Followup:
Scarcely used?  Hardly.  Every single forms application on the planet uses it
thousands, millions of times.  It is heavily used.

It is not used by applications that have "lost update" issues (bugs) perhaps but
in many properly written programs, it is used heavily.

What would you have your process do?  If the rows are locked by another session
-- you can either wait, OR you can not wait.

It is totally your choice -- do you want to wait?  do you want to not wait --
you decide.  In the END you better make sure you don't overwrite someone elses
changes (the major use of select for update is to lock the row before you let
the client change it to prevent others from doing the same).

No, it is not really possible to find the session, you can find all candidate
sessions.

Yes, I recommend using nowait when its appropriate.

Rating: 4
Third choice --- Can wait November 16, 2001
Reviewer: A reader from Reader
Hi,

In our application, we can do for example a "loop", say 1000
times to "select .... from .... for update no wait", and handle the
exception(just do nothing) within the loop, if the lock is finished with 1000
loops, then it will succeed and break the loop to continue next step in the
process; Otherwise, it will fail after 1000 times and then stop the whole
process. Of course, we need to measure the time to execute the whole process in
order to determine the loop times. All this stuffs are for the purpose of
increasing "automatical concurrency".

Tom, please comment on that.

Thanks,

Followup:
why do it 1000?  why not do it twice, sleep a second in between?

Not understanding your exact process and needs, I cannot really comment on how
best to attack your problem.  I personally would not loop 1,000 times for
anything.

Rating: 5
9i facility November 17, 2001
Reviewer: Connor from Scotland
I believe 9i has a timeout setting now.

select * from MY_TABLE for update WAIT 5

Followup:
indeed:

ops$tkyte@ORA9I.WORLD> select * from emp for update wait 5;
select * from emp for update wait 5
              *
ERROR at line 1:
ORA-30006: resource busy; acquire with WAIT timeout expired

thanks for pointing that out Connor...

Rating: 4
9i good but..... November 17, 2001
Reviewer: A reader from China
Not all of the people need/have to update to 9i right now, loop or sleep still
be a good choice to work around for the version below 9i.

November 17, 2001 Ganesh -- Thanks for the question regarding "Why Dont you Write a Book for DBA's Also ???", version 8.1.7
You Asked
Hi Tom,

Just got your book and the indian Reprint is out.

That was one great Book which i am going to read back to back.

It gives too many insights into how oracle works.

But....

You have skipped lot of topics which may have been useful for the DBA.

Quoting the subject again ... Why dont you write a book for DBA's.

People out there would surely agree.....

Regards,
Ganesh R
and we said...
Well, because frankly -- I'm more of a developer who just happens to know alot
about the database -- enough to be a DBA, but thats not where my strong
interests are.

Have you read Jonathan Lewis's book?
http://www.amazon.com/exec/obidos/ASIN/0201715848/
It is written in a very similar style as mine but is written from the DBA's
perspective.  It find it very nice that amazon for example is selling them as a
pair because in my opinion they go well together.  Mine is 100% relevant to the
DBA but written from more of a developers perspective.  His is 100% relevant to
the developer but written from more of a DBA perspecitive.  That makes them the
perfect pair (that and his is the only Oracle book aside from the docs that I've
actually read more then once -- well, I read mine more then once but..)
Review & Followup
Rating: 5
The common conflict November 17, 2001
Reviewer: Doug from CT, USA
This is what I like about the combination of Jon and Tom's book.  I also like
Jon Lewis's book.  I have never been to a DBA class where there are not
pejorative remarks made by someone about "those developers" and the things they
try on "our database" with lots of chuckles in the background.  I have also
never hung with good developers where there are complaints about the
restrictions placed on them by "those DBAs".   I like to try to bridge the gap -
be a little of both if possible.  I think a lot of projects lose a lot of time
due to this common conflict.

Rating: 5
Will read Yours more than Once. November 17, 2001
Reviewer: A reader
Will Read Yours More than once for sure ... Too many Concepts in the First
Chapter ...

Too GOOD !!!!

The same problem as your book it is not available as a Indian Reprint and it is
getting published by Some Singapore Publisher..

So will have to wait for some one to come from singapore ...

Thanks tom for the Insight.

Regards,
Ganesh R

Rating: 5
Jonathan v/s Tom November 18, 2001
Reviewer: Parag from India
He'y Tom :

I am sure that If U and Jonathan will write one book covering both Developer's
as well as DBA aspect , Hope that Number for reader for that books will me more
then 1 Million.

Waiting for ur next book on Oralce 9i.

Rating: 5
From a philosophical standpoint... November 18, 2001
Reviewer: Connor from Glasgow
Thats why its so funny nowadays when you see terms such as the "DBA group" and
"Developer group" - offices where for reasons of administrative efficiency, the
developers never get to talk to the DBA's and vice-versa.  Then they wonder why
quality has gone out the window :-)

November 17, 2001 Tho -- Thanks for the question regarding "Executing dbms_space", version 8.1.5
You Asked
Hi, Tom!
I follow an example in Oracle manual to run dbms_space.free_blocks procedure:
SQL>execte dbms_space.free_blocks('SCOTT','EMP','TABLE',1,:free_blocks);
and:
SP2-0522: Bind variable "FREE_BLOCKS" not declared.
Do i have to declare it first?
I'm not good at PL/SQL. Please give out an example.
Thank you.
and we said...
You might search for

dbms_space.free_blocks

I have some routines that use them pre-packaged for you.

This is really a sqlplus q -- not a plsql one.  you would:

variable free_blocks number
execute dbms_space.free_blocks('SCOTT','EMP','TABLE',0,:free_blocks);
print free_blocks

(use 0, not 1 btw in the free_blocks call)
Review & Followup
Rating: 4
Good One. November 18, 2001
Reviewer: Parag from India
Good Going Tom.

Rating: 3
Thank you November 18, 2001
Reviewer: Tho Nguyen from Vietnam

November 17, 2001 Sudee -- Thanks for the question regarding "Calling Export from Pl/sql using C external proc.", version 8.1.6
You Asked
Hi Tom,

Is there anything wrong with these steps,
the exp does not create a .dmp file.

Thanks

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>

  __declspec(dllexport) void sh(char *);

  void sh( char *cmd )
  {
  int num;

  num = system(cmd);
  }

CREATE LIBRARY shell_lib is 'C:\oracle\extproc\shell.dll';

  create or replace procedure shell (
  cmd IN char)
  as external
  name "sh"
  library shell_lib
  language C
  parameters (
  cmd string);

exec shell('C:\oracle\ora81\bin\exp userid=system/manager
file=C:\oracle\extproc\test.dmp full=y rows=N');
and we said...
Ok, this is easily solved.  What I'll do however is show you the steps I went
thru to diagnose this.

Step 1, after building the example, I tested it with something "non-oracle" --
to eliminate that from the mix.  I have a program "touch.exe" which when
executed simply updates the timestamp on a file in the OS and if the file does
not exist, it creates hence.

Hence I ran "exec shell( c:\bin\touch c:\temp\test.dat" );"

Sure enough, the file test.dat appeared -- proving the extproc itself functions.

Then I tried export -- sure enough, that DID NOT work.

Step 2, lets capture the output.  In order to diagnose this (and in order to be
able to verify the export actually WORKED) we need to capture the output.  Using
SYSTEM, the easiest way is:

tkyte@TKYTE816> host erase \temp\exp.log
tkyte@TKYTE816> begin
  2      shell( 'c:\oracle\bin\exp userid=scott/tiger ' ||
  3               ' file=c:\temp\test.dmp tables=emp 2> \temp\exp.log' );
  4  end;
  5  /

PL/SQL procedure successfully completed.

that would not only run our command but it would also redirect stderr to a file
we can look at. When I ran that, I saw clearly what the issue was:

tkyte@TKYTE816> host type \temp\exp.log

Export: Release 8.1.6.0.0 - Production on Sat Nov 17 13:02:35 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

EXP-00056: ORACLE error 12560 encountered
ORA-12560: TNS:protocol adapter error
EXP-00000: Export terminated unsuccessfully

So, it is simply not able to connect (it in fact was running exp -- you just had
no way to see the output from exp and now you do).  So, once we have that -- we
can go the next step.  Well, I would really like to see the environment cause
12560 is almost always an environment issue.  At this point, I stop running exp
and just run SET to see whats the environment looks like:

tkyte@TKYTE816> host erase \temp\exp.log

tkyte@TKYTE816>
tkyte@TKYTE816> begin
  2      shell( 'command /c set > \temp\exp.log' );
  3  end;
  4  /

PL/SQL procedure successfully completed.

tkyte@TKYTE816> host type \temp\exp.log
COMSPEC=C:\WINNT\SYSTEM32\COMMAND.COM
ORACLE_SID=extproc
ALLUSERSPROFILE=C:\DOCUME~1\ALLUSE~1
COMMONPROGRAMFILES=C:\PROGRA~1\COMMON~1
COMPUTERNAME=TKYTE-DELL
JSERV=C:\oracle9i/Apache/Jserv/conf
NUMBER_OF_PROCESSORS=1
OLAP_HOME=C:\oracle9i\olap
OS=Windows_NT
OS2LIBPATH=C:\WINNT\system32\os2\dll;
PATH=C:\oracle\bin;C:\oracle9i\bin;C:\orant\bin;C:\oracle9i/bin;C:\oracle9i\Apach
e\Perl\
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 8 Stepping 3, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=0803
PROGRAMFILES=C:\PROGRA~1
PROMPT=$P$G
SYSTEMDRIVE=C:
SYSTEMROOT=C:\WINNT
TEMP=C:\WINNT\TEMP
TMP=C:\WINNT\TEMP
USERPROFILE=C:\DOCUME~1\DEFAUL~1
WV_GATEWAY_CFG=C:\oracle9i\Apache\modplsql\cfg\wdbsvr.app

Well, there is the problem in this case -- we are using the EXTPROC service, so
the ORACLE_SID is in fact "extproc".

At this point, we have a couple of choices, two of which I have below - one we
can use Net8:

tkyte@TKYTE816> host erase \temp\exp.log

tkyte@TKYTE816>
tkyte@TKYTE816> begin
  2      shell( 'c:\oracle\bin\exp userid=scott/tiger@tkyte816 ' ||
  3               ' file=c:\temp\test.dmp tables=emp 2> \temp\exp.log' );
  4  end;
  5  /

PL/SQL procedure successfully completed.

tkyte@TKYTE816> host type \temp\exp.log

Export: Release 8.1.6.0.0 - Production on Sat Nov 17 13:05:36 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to: Oracle8i Enterprise Edition Release 8.1.6.0.0 - Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production
Export done in WE8ISO8859P1 character set and WE8ISO8859P1 NCHAR character set

About to export specified tables via Conventional Path ...
. . exporting table                            EMP         14 rows exported
Export terminated successfully without warnings.

The other is to run more than one command:

tkyte@TKYTE816> host erase \temp\exp.log

tkyte@TKYTE816>
tkyte@TKYTE816> begin
  2      shell( 'set ORACLE_SID=tkyte816 && ' ||
  3                   'c:\oracle\bin\exp userid=scott/tiger@tkyte816 ' ||
  4               ' file=c:\temp\test.dmp tables=emp 2> \temp\exp.log' );
  5  end;
  6  /

PL/SQL procedure successfully completed.

tkyte@TKYTE816> host type \temp\exp.log

Export: Release 8.1.6.0.0 - Production on Sat Nov 17 13:08:45 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to: Oracle8i Enterprise Edition Release 8.1.6.0.0 - Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production
Export done in WE8ISO8859P1 character set and WE8ISO8859P1 NCHAR character set

About to export specified tables via Conventional Path ...
. . exporting table                            EMP         14 rows exported
Export terminated successfully without warnings.

And there you go (you can get the ORACLE_SID you need from v$instance:

tkyte@TKYTE816> select instance_name from v$instance;

INSTANCE_NAME
----------------
tkyte816

if you would like to make this generic.

Hopefully, this will show you how to debug these sorts of issues in the future.
you should note that you should use UTL_FILE or a bfile to open, read and verify
the success of your command!  You could use dbms_lob.loadfromfile as well to get
it into a database table for future reference.
Review & Followup
Rating: 5
Good techniques November 17, 2001
Reviewer: Doug from CT, USA
These will come in handy  - and it probably took you less than 10 minutes.

November 17, 2001 Doug -- Thanks for the question regarding "Is there any difference in intention between "even" releases and "odd" ones?", version 8.1.7
You Asked
I got inspired to ask this after noticing in the post about the technology
behind asktom that you were running a .2 patchset.  There is an administrator of
a secure area who refuses to apply "odd" numbered patch sets under the idea that
odd numbered releases or patchsets are considered maintenance releases and even
ones are not. I guess they are more "functional?"  Therefore he will only do
even numbered ones.  I have heard rumors like this in the past.  Is there any
truth to it? Was there ever any truth to it?  As far as I can figure, 8.1.7.3
will be the terminal release of 8i.. will there be an 8.1.7.4?  Was there truth
to this in the 7.x days? The terminal release was 7.3.4 as I recall.  Now,
taking this a step further, will there be an 8.1.8?   Is this complete garbage?
Sounds like it.
and we said...
they like .0 releases then?

Does that admin rely on their horoscope as well -- to see how the day is going?
Its as reliable as going with the even/odd theory.  Makes as much sense as well.

We (we being the collective we here -- all of us) patch up to the level
necessary to support our applications.  I am at 8.1.7.2 because that is where we
needed to be.  We tested there, haven't hit anything we needed from 8.1.7.3 --
hence haven't patched up.

I did run on 8.1.7.1 for a while.  I ran 8.1.6.1 as well.

7.3.3 was actually a huge functional release for us, added bitmap indexes for
example.  7.3.4 was the patchset with no new functions (and some ports there are
7.3.4.1's and such).

There will not be an 8.1.8 no.

As a "secure guy" - it would seem to me that they would be more frightened of
even numbers (functional -- new functionality in their mind) then in odd (fixes
for things wrong in their mind).  So, if you have their view of even and odd
right -- its seems that their logic would be backwards to me?

In any event -- no truth to it.
Review & Followup
Rating: 5
I figured November 17, 2001
Reviewer: Doug from CT, USA
I had a feeling it was blather.

Rating: 5
I'm going to borrow that line about the horoscope November 17, 2001
Reviewer: Doug from CT, USA
Within the last year, I've heard this odd/even comment twice and not given it
much head. I'm curious whether other Oracle folks have heard what appears to be
an urban legend or I am just surrounded by...

Rating: 3
Sensible enough November 17, 2001
Reviewer: Dave from Dayton, OH USA
These misguided people may be thinking of Linux kernels, where 2.3 is a
development release which is released as 2.4 when it is stable for general
release. I don't know where that practice originated but maybe it's more
widespread than Linux, and that's where these people picked up their
misunderstanding

November 18, 2001 -- Thanks for the question regarding "A question ", version 8
You Asked
Hi tom
I created table APP with primary key and 4 other table which is child of APP
table now I want to drop APP table and re create it do I need to re create all
child  constraints again or is there any way to re-build constraint as it was
before ?

Thank u
and we said...
if you drop that partent table, you need to drop the constraints and rebuild
them later (it'll be a wholly different parent table after all!)

If you can, alter that table.  If you cannot, here is a script that'll help you:

column fkey format a80 word_wrapped
select
'alter table "' || child_tname || '"' || chr(10) ||
'add constraint "' || child_cons_name || '"' || chr(10) ||
'foreign key ( ' || child_columns || ' ) ' || chr(10) ||
'references "' || parent_tname || '" ( ' || parent_columns || ');' fkey
from
( select a.table_name child_tname, a.constraint_name child_cons_name,
         b.r_constraint_name parent_cons_name,
         max(decode(position, 1,     '"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 2,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 3,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 4,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 5,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 6,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 7,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 8,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 9,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,10,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,11,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,12,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,13,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,14,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,15,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,16,', '||'"'||
                substr(column_name,1,30)||'"',NULL))
            child_columns
    from user_cons_columns a, user_constraints b
   where a.constraint_name = b.constraint_name
     and b.constraint_type = 'R'
   group by a.table_name, a.constraint_name, b.r_constraint_name ) child,
( select a.constraint_name parent_cons_name, a.table_name parent_tname,
         max(decode(position, 1,     '"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 2,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 3,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 4,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 5,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 6,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 7,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 8,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position, 9,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,10,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,11,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,12,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,13,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,14,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,15,', '||'"'||
                substr(column_name,1,30)||'"',NULL)) ||
         max(decode(position,16,', '||'"'||
                substr(column_name,1,30)||'"',NULL))
            parent_columns
    from user_cons_columns a, user_constraints b
   where a.constraint_name = b.constraint_name
     and b.constraint_type in ( 'P', 'U' )
   group by a.table_name, a.constraint_name ) parent
where child.parent_cons_name = parent.parent_cons_name
  and parent.parent_tname = upper('&1')
/

run that passing the name of the parent table and it'll generate all of the
alters you need to put these constraints back in place.  So, you would run:

spool tmp.sql
@cons app
spool off

-- verify you got them

drop table apps cascade constraints;
create table apps ......

@tmp
Review & Followup
Rating: 5
Reader November 17, 2001
Reviewer: Reader from USA
Per Manual
"Columns per index max 32 columns". Is there a reason why
the script uses a max of 16 columns -- Performance limits ?

If the Primary key uses indexes on another Tablespace with
the clause, " using index ... tablespace ...", how will the
script be modified to account for it

Thanks

Followup:
Per Connor below - he hit it right on the head.  I would go further, if you have
a primary key somewhere that has more then 3 or 4 columns -- you've got other
problems to be concerned with.  (and yes, the script is from early 7.x days)....

As for the primary key -- this just generates foreign keys -- not primary keys.
Hence, its not relevant.  The script doesn't have to be modified since foreign
keys do not generate indexes (but they should be indexed by you -- but the
dropping/adding of fkeys will not drop/add or touch any indexes)

Rating: 5
Number of constraint columns November 18, 2001
Reviewer: Connor from Glasgow
Without trying to preempt Tom, I would say the script was written before the
ceiling got raised from 16 to 32, and more practically, if you've got more than
16 columns in a constraint and/or index, there are probably some more serious
issues in your database that need to be looked at :-)

Rating: 4
Reader November 19, 2001
Reviewer: Reader from USA
After some digging in, I found, the script is from
*1998 07 24 Thomas Kyte Oracle Newsgroup post*, indeed
7.x

To the comment by reviewer, I understand that 32 column index is injurious to
the database. I just pointed it
out for completeness sake.

November 18, 2001 Senthil -- Thanks for the question regarding "To access the other Database other Oracle", version 6i
You Asked
Hi Tom,
Our application run on Oracle forms deployed on Oracle IAS 9i and the database
is 8.1.6. One of my requirement is to pull the data from informix database. Is
there any way i can make a connection to Informix  database and populate the
tables in Oracle database. I am looking for something like a database link so
that i can pull the data from the informix database.
Thanks and regards
M. Senthil Kumar
and we said...
See
http://www.oracle.com/gateways/
there is also the opportunity to load a pure jdbc jdbc driver into the database
itself and use JDBC from a stored procedure to access informix -- no distributed
query, no two phase commit, but something you can do easily tomorrow.
Review & Followup
Rating: 3
Followup November 18, 2001
Reviewer: Senthil from Qatar
Hi! Tom
Thanx for yr reply. Thers is a mistake in the question it should be "To access
the other Database from Oracle". Anyway you have answered my question. Could you
please elaborate the steps in loading the JDBC driver into oracle database ,(ver
8.1.6) so that i can access other database.

Followup:
You would basically use loadjava to load up their jar files.  Make sure its a
type-4 (pure java).  It cannot have any reliance on native C code at all.

Rating: 5
Oralce Workbench November 18, 2001
Reviewer: Parag from India
Tom :
I am 100% happy with ur answere. But for such kind of requirement , Oralce
should provide some kind of Tool , which can talk with Different type of
database. Can't we used Oracle Workbench for this . Beca If we wanntd to port
data from SQL-Server-7.0 to Oracle , we used to use Oracle Workbench.

November 18, 2001 Sam -- Thanks for the question regarding "Physical Properties, Relational properties, Object properties", version 8.1.7
You Asked
Tom

Can you define  the following(with examples) three kind of properties.

Physical Properties,
Relational properties,
Object properties

any other kind of properties?

What is the difference between the above 3, and while creating an object in what
orer are they given, or does it differ from object to object.

Is this true that all v$views have singular names like v$session, and all views
starting with dba will have plural name like  dba_ts_quotas.
( most of the times it seems to be true).

Thank you
and we said...
I assume you are talking of the wire diagram for a CREATE table?

phyiscal properties are things like "tablespace", "storage", "pctfree".

relational properties are things like "column names", "datatypes", "defaults"

object properties -- are just like relational properties but they refer to
attributes of object types.

see
http://technet.oracle.com/docs/products/oracle8i/doc_library/817_doc/server.817/a85397/statem3e.htm#2061078
It gives you the definitions of the above and shows you the order in which they
appear.

sys@ORA817DEV.US.ORACLE.COM> select object_name from all_objects where
object_name like 'V$%S';

OBJECT_NAME
------------------------------
V$ACCESS
V$ACTIVE_INSTANCES
V$ARCHIVE_PROCESSES
V$BGPROCESS
V$BUFFER_POOL_STATISTICS
V$DB_PIPES
V$DLM_ALL_LOCKS
V$DLM_LOCKS
V$DLM_RESS
V$ENABLEDPRIVS
V$FAST_START_SERVERS
V$FAST_START_TRANSACTIONS
V$GLOBAL_BLOCKED_LOCKS
V$LATCH_MISSES
V$LOCKS_WITH_COLLISIONS
V$LOGMNR_CONTENTS
V$LOGMNR_LOGS
V$LOGMNR_PARAMETERS
V$MLS_PARAMETERS
V$MTS
V$NLS_PARAMETERS
V$NLS_VALID_VALUES
V$PROCESS
V$PWFILE_USERS
V$PX_PROCESS
V$RECOVERY_FILE_STATUS
V$RECOVERY_PROGRESS
V$RECOVERY_STATUS
V$RESERVED_WORDS
V$SESSION_LONGOPS
V$SQLTEXT_WITH_NEWLINES
V$TEMPORARY_LOBS

32 rows selected.

sys@ORA817DEV.US.ORACLE.COM> select object_name from all_objects where
object_name like 'DBA\_%' escape '\'
  2  and object_name not like '%S';

OBJECT_NAME
------------------------------
DBA_2PC_PENDING
DBA_AUDIT_OBJECT
DBA_AUDIT_SESSION
DBA_AUDIT_STATEMENT
DBA_AUDIT_TRAIL
DBA_CATALOG
DBA_CONTEXT
DBA_DIM_CHILD_OF
DBA_DIM_JOIN_KEY
DBA_DIM_LEVEL_KEY
....
DBA_RCHILD
DBA_REFRESH
DBA_REFRESH_CHILDREN
DBA_RGROUP
DBA_SOURCE
DBA_FREE_SPACE

58 rows selected.

So, no -- they are not purely sigular and plural.


Subject | Article | Last Updated (East coast time)
Cursors | article only | Nov 19, 2001 07:35 am
Using Bind Variables in VJ++ | article only | Nov 19, 2001 07:43 am
Binds in external programs | article only | Nov 19, 2001 09:50 am
Counting the nuber of occurences of ; in a a string | article only | Nov 19, 2001 09:55 am
Database tunning | article only | Nov 19, 2001 10:03 am
Assigning a DB profile to self. | article only | Nov 19, 2001 09:17 pm
Hierarchical table row level security | article only | Nov 20, 2001 08:22 am
SQL SERVER CODE INTO ORACLE COE.. | article only | Nov 20, 2001 08:34 am
Package question | article only | Nov 20, 2001 08:43 am
How to bind output Parameter from PL/SQL into KSH script | article only | Nov 20, 2001 08:52 am
Export and Point in time recovery | article only | Nov 20, 2001 08:59 am
Error Handling | article only | Nov 20, 2001 10:56 am
Nested Table | article only | Nov 20, 2001 12:26 pm
returning pl/sql table records as ref cursor | article only | Nov 21, 2001 08:57 am
allocate different Tablespaces | article only | Nov 21, 2001 11:33 am
Script to create new users | article only | Nov 21, 2001 11:48 am
Set column default value to space instead of null | article only | Nov 21, 2001 11:53 am
Concept of Threads -- what is the REDO thread in the alert log. | article only | Nov 22, 2001 08:47 am
about the tablespaces | article only | Nov 23, 2001 09:46 am
How to find what privileges can be granted on an object?? | article only | Nov 23, 2001 04:17 pm
IAS 9i support for OWA Replacement Cartridge | article only | Nov 24, 2001 09:43 am
Can not desc,select,DML on table | article only | Nov 24, 2001 09:52 am
XML , generating xml from Select statement in pl/sql using DBMS_XMLQUERY | article only | Nov 24, 2001 07:37 pm
What SQL query is used by "auto trace" reports to query the plan table | article only | Nov 24, 2001 07:41 pm
How can I export the tablespace that has been dropped one of the datafile? | article only | Nov 25, 2001 11:24 am
The difference between '/' and ';' - maybe some details? | article only | Nov 25, 2001 12:52 pm
SE or EE | article only | Nov 25, 2001 02:04 pm
Clob data type | article only | Nov 25, 2001 02:49 pm
row(s) 1 - 28 of 28
November 19, 2001 LS -- Thanks for the question regarding "Cursors", version 8.1.6.3
You Asked
Hi

I never understood the concept of a cursor and I was wondering if you could
clarify a bit about it.
When I read about cursor definition it talks about a private SQL area, however
in my PL/SQL ILT boo it talks cursors as they were a pointer that points the
private SQL area and these two concepts really confuses me. Which on is correct?
Also doesnt private SQL area reside in PGA? Also I am a bit confused about
shared cursors... since it always talk about the parsed SQL statement in Shared
Pool. Is a cursor really a SQL statement? Since SQL are shared in Shared Pool

If you know a whitepaper that explains about cursors I would really appreciate
if you could post the link

Thank you very much
and we said...
Don't over analyze this concept.  It is really pretty simple.

A cursor, as far as you the developer is concerned, is just like a "FILE".  It
points to a result set, an answer to a query.  You use a cursor to read through
the result set line by line, row by row.

That is what a cursor is as far as you are concerned.

Now, physically in the database, we do a lot of work to manage them.  There is
the shared pool where optimized query plans, security checks and so on are
stored with parsed SQL statements.  These parsed sql statements are not cursors
-- they are just parsed sql statements.  A cursor will point to one of these
ultimately but a parsed sql statement is not a cursor.  So, a cursor will
ultimately point to the shared pool, that is where the parsed, optimized query
plan will be.

A cursor will consume storage from your PGA (process global area).  You have
bind variables that are unique to your cursor, they will be stored there.  You
have a state associated with your cursor (open, bound, executed, close) and that
will be stored there.
Review & Followup
Rating: 3
part "physically in the database..." March 27, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

Rating: 3
Just one more question September 18, 2001
Reviewer: Dharmaraj from CA,USA
Here you have mentioned that the cursor is nothing but a pointer to a "parsed
sql with the plan", and which can be found in the private sql area of SGA.
Now assuming I have a cursor which returns 1million rows and the cursor is
declared globally in a package body. the purpose is to retrieve 1000 records at
a time, does this affect performance:Deos it work like this
Whenever I fetch row from the cursor(EXPLICIT) it puts in the BufferCache, and
if I update a few rows based upon some conditions they become dirty and is
pushed using the LRU and DBWR process.and the pointer points to the last record
i have fetched from the global cursor.so when i go for the next fetch i can
start from the next record.
Am I correct, if it works like the one above we have to find a workaround using
rownum to retrieve the records, as this will affect the performance.
Could you please clarify this.

Followup:
yes, it works more or less like that.  the records for the cursor are fetched as
requested (assuming a simple select * from t).  Warning -- if you are selecting
from T and updating T and committing periodically -- you are setting yourself up
for an ora-01555.  Just search for ora-01555 on this site to read more about
that.

Rating: 3
what will happen if query using cursor is long running and parsed statement is pushed out of memory September 19, 2001
Reviewer: A reader from USA
Hi Tom

what will happen to a query which fetches record for a set of rows and then
waits and then fetches next set of rows and in between th eparsed statement got
pushed out of memory.

Followup:
it won't cause any errors -- your cursor in your pga/uga.  its not subject to
aging.

Rating: 4
A Reader September 20, 2001
Reviewer: A Reader from USA
Tom,
Could you please explain at some length abour CGA ( cursor global area) and the
constituent parts of PGA ( stack area and private sql area)

Thanks in advance

Followup:
They are just memory spaces, they are not especially relevant to us really.
They are "interesting" but not really relevant.

For some good info on this, see
http://www.ixora.com.au/home.htm
and search for cga. Steve Adams has written some good stuff on this sort of
topic.

Rating: 4
but September 20, 2001
Reviewer: Wells
"it won't cause any errors -- your cursor in your pga/uga.  its not subject to
aging."

what do you mean, do you mean that the parsed SQL statements  will be inthe
shared pool , where as the unparsed sql statement will be in the pga/uga.

How is it not subject to aging.

Followup:
No, I mean once you open up your cursor and start processing -- you have
everything you NEED at that point in your own space.

Rating: 2
Contradicts November 18, 2001
Reviewer: A reader
Hi Tom

I have attending some online courses in OLN, architecture, performance etc. My
confusion is, from your statement you are stating that the cursor resides in PGA
(assuming we are using dedicated server) but from these courses I attended all
the lecturers stated

1. During SQL processing, first Oracle allocates memory in SGA (not PGA as you
suggest) for the cursor (and yes they say cursor not shared SQL), this is really
confusing the words shared SQL and shared cursor
2. In the perfomance management course the lecturer repeately talks about shared
cursor, how can we share a cursor is the cursor is a "session" thing? How can we
share them across sessions? If these shared cursors are in the SGA then there is
no problem! But if they are in PGA how can they be shared at all?

You said the cursor is nothing but a pointer to a "parsed
sql with the plan", and which can be found in the private sql area of SGA. Here
it seems that you are stating cursor is in SGA? Where is the private SQL area in
SGA? Does each session get their private SQL area in the SGA?

Well what I dont get is where are the cursor located, SGA or PGA? Some people
said BOTH

Followup:
1) i did NOT suggest that.  I said:

"Now, physically in the database, we do a lot of work to manage them.  There is
the shared pool where optimized query plans, security checks and so on are
stored with parsed SQL statements.  These parsed sql statements are not cursors
-- they are just parsed sql statements."

That is the SGA component.

2) It is a shared "query" -- not a shared "cursor".  They mispeak a little.  Its
called the shared SQL area, not the shared cursor area.

(and technically I mispeak too, the cursor is actually in the CGA -- cursor
global area -- but that goes beyond what anyone really needs to know)

I state that the QUERY, the PLAN, the stuff that can be shared is in the SGA.

The BIND VARIABLES, your POINTERS to your temp work areas, your result set --
thats in YOUR space.

Saying "both" would not be entirely inaccurate, especially when talking
conceptually.  Think of it like this -- the query, the plan -- thats your
EXECUTABLE code.  We can all share that.  Your cursor -- thats your data, your
stack, your instruction pointer, we cannot share that.

Your cursor points to the plan.  Your cursor isn't shared -- but HOPEFULLY the
query/plan it points to is.

November 19, 2001 Vikas -- Thanks for the question regarding "Using Bind Variables in VJ++", version 8.0.5
You Asked
Hello! Tom,

I Just wanted some help from u regarding the implementation of bind variables in
VJ++ under Oracle 8.0.5. Previously developers in my organisation have been
writing statements using host variables which went for parsing againg and again
as new values are substituted in the batch oriented program which we are
executing.

Like we have a statement :

QCountry=" and a.country = "+ "'"+country+"'";

if (state.equals("")) QState="";
    else QState=" and a.state ="+ "'"+state+"'";

if (city.equals("")) QCity="";
    else QCity=" and a.city = "+"'"+city+"'";

if (bp_from_ui.equals("")) QBp="";
   else QBp=" and a.bp# = "+"'"+bp_from_ui+"'";

if (country.equalsIgnoreCase("us"))
{
if (mailcode.equals("")) QZip="";
else
QZip=" and a.mailcode = "+"'"+ mailcode+"'";
}
else
{
if (mailcode.equals("")) QZip="";
else
QZip=" and Upper(Substr(a.mailcode,1,7))="+"'"+ mailcode+"'";
}

sqlqry1= QBp + QZip + QCity + QCountry + QState;

String InsertRecords="insert into "+demo_modify+" select
a.adr#,a.bp#,a.Country,a.City,a.mailcode,a.Location,a.state,a.Avs_state,null,null
,null,null,null from "+schema+" a where 1=1 "+sqlqry1 + " and not exists (select
1 from "+ demo_modify+" b where a.BP#=b.bp# and a.adr#=b.adr#)";

How to convert these variables , bind variables so as these statements are not
parsed again & again. one time parsing many times executions is the best
solution to make the library cache hit ration to the max?? Am I correct.

2) Is the SQL SQRVER capable enough to convert these host variables into bind
variables OR Actually these are bind variables. If Yes please do confirm.If not
how to convert them??

"Select * from emp where empno =" + @emp_no

Waiting for your reply.

Regards,

Vikas Khanna
and we said...
That is correct.  By using hard coded values -- you are literally KILLING
PERFORMANCE, limiting your scalability, decreasing concurrency, wasting tons and
tons and tons of resources.

What you would do is this (have NOT compiled this, accept it as PSUEDO CODE):

sqlqry1 = QBp + " and a.country = ? ";

if ( !state.equals("") ) sqlqry1 = sqlqry1 + " and a.state = ? ";
if ( !city.equals("") ) sqlqry1 = sqlqry1 + " and a.city = ? ";
if ( !bp_from_ui.equals("") ) sqlqry1 = sqlqry1 + " and a.bp# = ? ";

if (country.equalsIgnoreCase("us"))
{
   if ( !mailcode.equals("")) sqlqry1 = sqlqry1 + " and a.mailcode = ? ";
}
else
{
   if ( !mailcode.equals("")) sqlqry1 = sqlqry1 + " and
Upper(Substr(a.mailcode,1,7))= ?";
}

PreparedStatement ps = connect.prepareStatement( sqlqry1 );

int i = 1;

ps.setString( i++, country );

if ( !state.equals("") ) ps.setString( i++, state );
if ( !city.equals("") ) ps.setString( i++, city );
if ( !bp_from_ui.equals("") ) ps.setString( i++, bp_from_ui );
if ( !mailcode.equals("")) ps.setString( i++, mailcode );

You use ? where they hard coded values, you use setString, setInt, etc to set
the values -- then execute it and get the result set back.

If you are like me, you might like to use stored procedures and get ALL SQL out
of the application (into the database where you can tune it, manage it, secure
it, and everything without affecting the application).  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1288401763279
for how that would work.

2) I'm not the right guy to ask how SQL Server works.
Review & Followup
Rating: 2
Implementation of Bind Variables in VJ++ November 19, 2001
Reviewer: Vikas Khanna from india
Hello! Tom,
Thanks for the support.But I still have concerns after implementation on the
basis of your guidelines.
I had a statement executing a query :
String Schema_Check = "select count(1) from dba_tables where owner =" + Schema +
";
s=c.createStatement();rs=s.executeQuery();rs.next();
schema_count=rs.getInt(1);rs.close();
Was giving results as PARSE_CALLS to EXECUTIONS  ratio as 1
as it was understandable because of Hard Parse.
BUT after implementation of Bind Variables still the ratio is 1 as depicted from
the V$sqlarea.Parse_Calls/Executions
String schema_check="select count(1) from dba_tables where owner = ?";
PreparedStatement ps = c.prepareStatement(schema_check);
ps.setString(1,schema);s=c.createStatement();rs=ps.executeQuery();rs.next();schem
a_count=rs.getInt(1);
rs.close();
Earlier we were declaring s as statement and then closing it.Does this mean that
in the new context we should not create statement as we have prepared
statements.Do we need to close prepared statements also in order to avoid the
Maximum Open Cursor Exceeded Problem??Am I true.

Is this table to be viewed to know the exact ratio of parsing to executions.
                                           Waiting for your well written
response.

Followup:
That is because you should NOT close a prepared statement until you are sure you
will NEVER execute it again.

Here, with bind variables-- at least you are SOFT PARSING (much better then hard
parses) but you can do better.  Keep the prepared statement as a class variable
-- outside the method and parse it ONCE per session, not ONCE per execution!

see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1478004815829
for a clear example.

You should set max open cursors higher (I run with at least 1,000) and make sure
you don't "leak" them (eg: open them but never ever reuse them -- a common
error).

November 19, 2001 Graham -- Thanks for the question regarding "Binds in external programs", version 8.1.7.2
You Asked
Okay, a couple of questions about bind and autobind.

I have an test app written in Borland Builder 5 that inserts about 100,000
records into a table.  The data is spread across quite a few files all of which
are in csv format.  Currently I open each csv file, read in a row, build an SQL
string for each line, fire it off and get the next line.  For the 100,000
records this takes approximately 16mins.  Currently we are using the OraOLEDB.

Binds would be an indeal solution for this but all the examples I've seen (on
here, in your book, and on other sites) only use data that is generated at
run-time: replacing x with a number generated from the loop counter.  Not very
practical when all the data is loaded from files.  If there is some way of
getting binds to work from within the test program then I would cut the total
time from 16mins down to approximately 1 and a half (90%).

I thought my prays had been answered when I found out about the 'alter session
set cursor_sharing = force;' but the program still takes it's 16mins to run
through.

I have only been doing DBA work for the two months (I'm a C coder by trade), so
I am still bit of a newbie and learning all the time.  Using C*Pro isn't an
option since we need the interface and interactivity/productivity that Builder
provides.

Any ideas?

Yours faithfully, Graham Reeds.
and we said...
Why isn't is practical when the data is read from a file?  Its a simple logical
extension from:

 for i in 1 .. 100
 loop
    execute immediate 'insert into t values ( :x )' using i;
 end loop;

to

   loop
      read a record
      exit when no more data
      execute immediate 'insert into t values ( :x )' using record_values;
   end loop

isn't it??

The issue you are seeing with cursor_sharing = force is that you are probably
PARSING the statement each time through as well as executing it.  You want to:

   parse inserts

   loop
         read record
         bind
         execute
   end loop

   close inserts

So, learn how to prepare a statement (parse it).
Bind to it.

execute it.

Then you are done.  Even better, employ array processing -- read and bind 100
records -- then execute the statement, read and bind 100 more and then execute.
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:464420312302
is an example of this in PLSQL (i don't do VB).  It shows the
parse/loop/bind&execute/end loop construct.
November 19, 2001 Nag -- Thanks for the question regarding "Counting the nuber of occurences of ; in a a string", version 8.1.7
You Asked
Tom

I started reading your book in detail( I just browsed throught through once
before). You were right, most of my questions seem to being answered. It is
saving a lot of time for me. Great effort from you.

1. I have a string like
sfsdsfd;sfsdfsfs;fsdfsdf;sdfsdfs;sdfsdf;sdffs;;;sfsf;sdfsf;;sfsdfs
Is there a generic function which can give me the total count of semi colons.

2.I was reading an article in Information week, and came across terminology like
high end database jobs. Can you explain the phrase  'high end database'. Does
this mean database administration.

3.I want to take a chunk of data into flat files from out database tables into
flat files and  store them into a database at a different location. There is no
connection between both the databases, so these is no question of creating a
database link.
Actually, I cannot even write to the flat files as I dont have access to the
database server. How can I spool the data to a text file, delimit it by comma's,
and then insert the data into the other database.
( can we spool the data using dbms_output.put_line?)

thank you
and we said...
tkyte@TKYTE816> variable x varchar2(255);
tkyte@TKYTE816>
tkyte@TKYTE816> exec :x := null;

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816> select nvl(length(:x)-length(replace(:x,';','')),0)
  2    from dual;

NVL(LENGTH(:X)-LENGTH(REPLACE(:X,';','')),0)
--------------------------------------------
                                           0

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> exec :x := 'sfsdsfd'

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816> select nvl(length(:x)-length(replace(:x,';','')),0)
  2    from dual;

NVL(LENGTH(:X)-LENGTH(REPLACE(:X,';','')),0)
--------------------------------------------
                                           0

tkyte@TKYTE816>
tkyte@TKYTE816> exec :x :=
'sfsdsfd;sfsdfsfs;fsdfsdf;sdfsdfs;sdfsdf;sdffs;;;sfsf;sdfsf;;sfsdfs';

PL/SQL procedure successfully completed.

tkyte@TKYTE816>
tkyte@TKYTE816> select nvl(length(:x)-length(replace(:x,';','')),0)
  2    from dual;

NVL(LENGTH(:X)-LENGTH(REPLACE(:X,';','')),0)
--------------------------------------------
                                          11

2) high end databases are those that push the limits.  They might be very high
end OLTP with 10's of thousands of users and millions/billions of transactions.
They might be multi-terabyte data warehouses.

they are high end like you have "high end <consumer item>", like a high end TV
-- all of the features/functions you can imagine and a price tag that is high.

3) see
http://osi.oracle.com/~tkyte/flat/index.html
...
Review & Followup
Rating: 5
November 19, 2001
Reviewer: Tianhua Wu from Atlanta, GA
nice scripts!

Rating: 4
i like it November 19, 2001
Reviewer: Madhu from USA
That's a clever way to find occurrences. I like it.

November 19, 2001 vivek -- Thanks for the question regarding "Database tunning", version Oracel 8.1.7
You Asked
Hi Tom,

   I have the idea that if index is not used on the table
than
     in  where clause
if we have
      1.) AND  operation it will be evaluated bottom up
      2.) OR   operation it will be evelauated top to bottom

what if we do have index is it the same order in whice it is evaluated ?

  Also I want to know what exacly a REF cursor is ?

before writing these questions i tried to searh your online search tool but many
links does not work !! ( Says page not found on OTN documentation)

Thanks,
vivek
and we said...
It is NOT determinate -- IT can and WILL change.  There are no rules here.  We
evaluate in any old order we feel like it.  Many things will influence it.

Here is an example that demonstrates this clearly:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x varchar2(5), y varchar2(5)
);
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'a', '1' );
1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( '2', '2' );
1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t where x = 2 and y = 2;

X     Y
----- -----
2     2

1 row selected.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t where y = 2 and x = 2;
select * from t where y = 2 and x = 2
                                *
ERROR at line 1:
ORA-01722: invalid number

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze table t compute statistics;

Table analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t where x = 2 and y = 2;
select * from t where x = 2 and y = 2
                      *
ERROR at line 1:
ORA-01722: invalid number

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t where y = 2 and x = 2;

X     Y
----- -----
2     2

1 row selected.

Since when we compare a string to a number we MUST convert the string to a
number -- we'll get a failure whenever we do the "x = 2" first in the predicate
since x = 'a' at least once.

If we did the predicates in some known predicable order -- we would be able to
look at the query and tell if it will succeed or fail.  As you can see -- you
cannot.  Sometimes bottom up, sometimes top down, sometimes middle out -- you
cannot tell, should not rely on any order at all.

On MY site (asktom) i searched for :

order of evaluation

and found this has been asked and answered....  I also searched for

ref cursor definition

and found it.  You can read:
http://osi.oracle.com/~tkyte/ResultSets/index.html
Review &
      Followup

      Rating:
      4
  November 19, 2001
Reviewer:  vivek
      shah  from NY,New York U.S.A
Greate information

      Rating:
      4
  November 19, 2001
Reviewer:  vivek
      shah  from NY,New York U.S.A
Grate information

      Rating:
      4
  November 19, 2001
Reviewer:  vivek
      shah  from NY,New York U.S.A
Grate information

November 19, 2001 Mandar -- Thanks for the question regarding
      "Assigning a DB profile to self.", version 7.3

      You Asked
I have come across a form (Forms 4.5) where a supervisor( SUPERVISOR role with
all DBA kind of privs) can  create a visitor user with read only permissions and
assigns it a temporary profile. This temp profile forces visitor to change the
password when he logs in first time through forms. And this temp profile gives
new user 5 days time. As soon as visitor changes its password the following
kstatement is fired  to change its own password.

ALTER USER <username> IDENTIFIED BY <password> PROFILE PERM_PROFILE;

but if visitor does not have ALTER USER system privilege then it fails on the
above command.

Which is the DB privilege, we can give to VISITOR on the PERM_PROFILE, that can
resolve this problem. Obviously I don't want to give visitor 'ALTER USER'
privilege.

Is there any other way to handle this situation?

      and we said...
Create a stored procedure that is owned by some "admin" account.

This procedure will use dbms_sql to dynamically execute

   'alter user ' || user || ' identified by ' || password ||
     ' profile perm_profile';

The OWNER of that procedure will need the "ALTER USER" priv (granted directly,
not VIA a role).  The owner of that procedure can grant execute on this to
"public". As it can only change the profile of the currently logged in user to
something you want, it is "safe" in that regards.

Execute that procedure instead of attempting to issue the command directly.  You
are wise to not want all users to have the extremely powerful alter user command
(with which they can take over your entire database -- all i need is create
session and alter user and I can do anything I want)
Review &
      Followup

      Rating: 5
Assigning DB
      Profile to self.  November 20, 2001
Reviewer:
      Mandar Gokhale  from Sydney, Australia
USEFUL????
The most useful, I would say.
This resolved my entire security issue.

November 20, 2001 Michael -- Thanks for the question regarding
      "Hierarchical table row level security", version 8.1.7

      You Asked
Hi Tom!

Would you advice how to organize row level security policy for a table
with hierarchical relations within. As an example let's take the sample table
emp from scott/tiger schema. The problem is to allow users (king, blake etc)
see own data and data of subordinated users. I tried to do this by such a
function (see below) but got ORA-28112 error (because I can't select the very
same object from within the function).

create or replace function get_sel_predicate(
  p_schema varchar2,
  p_object varchar2
) return varchar2
is
  predicate varchar2(2000);
begin
  predicate:=
    'empno in (
       select empno from emp
       connect by prior empno = mgr
       start with ename = '''||sys_context('userenv','session_user')||'''
     )';
  return (predicate);
end;

I must emphasize that we have to handle tables not views.
So your examples on
http://osi.oracle.com/~tkyte/article2/index.html
and others
are unacceptable. Is there any way to query the table from the function
registered
by dbms_rls.add_policy? I mean something like autonomous_transaction for
triggers.

Thanks in advance

      and we said...
Sorry that the are "unacceptable" (i don't like that term, software does what it
does, if you come at it with a preconcieved notion of how you feel it should
work vs how it actually does, you'll be disappointed every time)

You have the classic chicken and egg problem here -- as I described there.  You
don't want the person to see the data YET the person MUST see the data!  catch
22.

You need a table, you need a view.  You'll put the policy on the view, you'll
use the table in the policy.  It should not matter to anyone anywhere that you
are using a view, they'll never know.

As for:

Is there any way to query the table from the function
registered by dbms_rls.add_policy

You are not in your example even querying the table from the function!  You are
adding a PREDICATE to an existing query submitted by the end user.  The query
they submit:

select * from emp

will be rewritten as:

select * from ( select * from emp where <YOUR PREDICATE> )

Thats the way it works.  Therefore, obviously, there is no way to have your cake
(security) and eat it too (bypass it at your whim).

I'm sorry its unacceptable -- perhaps if you told us why is so "unacceptable",
we could help resolve your trepidation.

(also PLEASE never glue in literals like that!! use the function -- it would
just be:

  connect by prior empno = mgr
    start with ename = sys_context( ''userenv'', ''session_user'' ) '
Review &
      Followup

      Rating: 3
what fine
      graned access can do what views can't?  November 19, 2001

Reviewer:  Mikito Harakiri
Let's go through all the examples in

http://osi.oracle.com/~tkyte/article2/index.html
1. Employee. Whenever a new user -- Employee Smith is added, just use the view

view EmpEmpView
select * from (
        select * from emp
        where ename = USER
)

defined in some common schema. It is convenient to create a synonym in Smith
schema:

create synonym Emp to EmpEmpView

and so that when employee issues "select * from emp" the view would adjust
access for him.

2. Manager. Whenever a new user -- Manager Blake is added use another view --
MgrEmpView. Define a synonym in  similar way.

3. I can't really tell, but the idea of some "application context" doesn't
impress at all. I assume that there is auxilary table that resolves many-to-many
between Emp and HrRep tables, anyway, then just use it in yet another view!

          Followup:

Mikito -- I really don't understand you sometimes -- you seem to not like
anything about Oracle but here you are all of the time....

You aren't seriously suggesting a complete and entire set of views for each and
every single user in the system are you????  Thats what is sounds like

You also would be totally foregoing stored procedures in your case -- the stored
procedures would go against a single set of tables.  among other things.

Suppose we have this:

You have an HR application.  It has 1,000 users.  There are 10 different roles
out there ranging from the EMPLOYEE role to the CLERK role, to the ADMIN role to
the DEPT_MGR role to the HR_MGR_ROLE.

They all have different access to different bits of data.  A EMPLOYEE can see
themself (view1).  A MGR can see a set of people that report to them (view2).
An HR_MGR can see everyone in a set of departments (view3).

Now, we could write one monster view that supports all three of this views (plus
the other 7 roles) using OR's and AND's etc.  I believe we can all agree that
would not be practical nor performant.  So, I'll discard that out of hand.

The other approach would be to create a schema "employee" and create the
specific views needed for the employee role in there.  We can then create a
schema "hr_mgr" and create the specific views in there.  We can then create a
schema "mgr" and create the specific views in there.  And so on.

Now, we cannot realistically use synonyms because of the fact that SOMETIMES I
am an employee (i need to update MY address record or perform an action only an
EMPLOYEE can perform).  SOMETIMES I am an ADMIN (don't want to be logged in as
super user all of the time).  SOMETIMES I am a MGR (most times maybe, working on
my people).  In order to switch roles -- i would have to be dropping and
creating synonyms all of the time.

True, I could use alter sessoin set current_schema=..... to do this but then
again, I would be prevented pretty much from using stored procedures (definers
rights ones) and such.

Also, what about when I use some reporting tool???  How does it know what to do?
It must be trained somehow to work in this environment.  I just bought it, its
not aware of current_schema, I cannot use synonyms -- i'm sort of stuck.

The nice thing about FGAC is

o you don't have this view explosion.  There is one table or one view, there is
one policy where I can go and look and see what rules are for everyone -- one
place.

o its transparent.  There is only one table, one view.  If I access the data via
sqlplus -- there we go, the policy is in place.  If I access the data via brio,
the policy it there.  I can use stored procedures as normal.  Its in the
database, hidden from the app -- you cannot bypass it, its just there.

o its easier to change.  consider a rule change in security.  Tell me what
happens when you recreate 50 views in that one schema to reflect this new
policy.  All dependent objects go invalid, apps stop for a bit (doing DDL is
something best done in isolation), tons of work.  Compare that to updating a
single package body -- no cascading invalidations

I've taken applications that didn't have this FGAC feature, dropped the
functionality in on them -- and they don't even know it.  Try that with 10
different views to support 10 different roles or 10 different companies
accessing the same data.  It won't be very successful as the APPLICATION must
participate in the process -- it must be aware of the 10 views of the data and
willingly know which one it should be querying.  With FGAC -- they don't.

I'm sorry so many things don't impress you, that wasn't our goal actually.  Our
goal was to provide new tools, better ways of doing things.  You can do it
anyway you see fit.  Don't like it?  Don't use it.

      Rating: 3
What don't you
      like about the literals?  November 19, 2001

Reviewer:  trevor  from UK
Tom,
    Why don't you like the literals as per
    the original question.

    I code the same as your suggestion,
    but would be interested to know why
Thanks Trevor

          Followup:

And a followup to Connor's followup (he seems to beat me on this in the
mornings!  Its not fair, he has a 5 hour advantage over me with the
timezones)....

If you want the whole story on bind variables, I can recommend a book -- mine.
It is sort of a tome to "why you need bind variables", its a topic I revisit
more then once.

To summarize

o if you do not use bind variables you will not scale
o you will not perform at any where near what you could
o you will trash your shared pool and have constant issues
o you will fail

The value of bind variables cannot be overstated.

      Rating: 5
For the
      previous poster....  November 20, 2001
Reviewer:
      Connor  from Scotland
Literals are bad bad bad news...

Try this:

create table blah ( x number);

set timing on
declare
  v number;
begin
for i in 1 .. 10000 loop
  select count(*) into v from blah where x = i;
end loop;
end;
/

declare
  v number;
begin
for i in 1 .. 10000 loop
  execute immediate
    'select count(*) from blah where x = '||i
    into v;
end loop;
end;
/

The first one uses bind variables, the second literals.

See how long they take...Then shut your db, start it again, and then run three
sets of each concurrently and how bad things can really get...

      Rating: 5
About what is
      being said here  November 20, 2001
Reviewer:
      Andre Whittick Nasser  from Rio de Janeiro, Brazil
Tom,

You have my sympathy here. I agree with what you say. These questions and
reviews about FGAC, views and bind variables do not make sense to me and your
followups are really ok.

Congratulations again.

November 20, 2001 gagan -- Thanks for the question regarding "SQL
      SERVER CODE INTO ORACLE COE..", version 7.1.3

      You Asked
Hi Tom,
       I want to convert this SQL - Server code statement into ORacle Code (I am
using Oracle ver 7.1.3) so not able to use CASE statement.

SQL-SERVER code

    SUM(CASE WHEN DEPARTMENTNUMBER = 4 THEN
     CASE WHEN ACTIVITYNUMBER > 'UM' AND
     ACTIVITYNUMBER < 'UN' THEN SALESPRICETOTALCURRE
     ELSE 0 END WHEN DEPARTMENTNUMBER = 1 THEN
    CASE WHEN    ACTIVITYNUMBER  >= '200' AND
    ACTIVITYNUMBER <= '999' THEN SALESPRICETOTALCURRE
     ELSE 0 END WHEN DEPARTMENTNUMBER = 0 THEN CASE WHEN
     ACTIVITYNUMBER >= 'U200' AND
     ACTIVITYNUMBER <= 'U999' THEN SALESPRICETOTALCURRE
     ELSE 0 END ELSE 0 END;

Regards
Nitin

      and we said...
Hmmm, you use 9 year old software from us but the latest greatest from them.....

We can do that.  Its a tad "obscure" but we can do it.

basically your logic is:

 if deptno = 4 AND activityNumber like 'UM_%'
                (starts with UM and has at least one character more)

 if deptno = 1 and the first character of activitynumber is one of 23456789, the
second two are one of 1234567890 and there is no fourth character ....

 if deptno = 0 and the first character is a U and the second is one of 23456789
and the 3rd/4th are one of 1234567890 and there is no fifth...

decode and some string functions can do that for us:

ops$tkyte@ORA717DEV.US.ORACLE.COM> select departmentnumber, activitynumber,
salespricetotalcurre,
  2  decode( departmentnumber,
  3          4, decode( substr(activityNumber,1,2),
  4                     'UM', decode(length(activityNumber), 2, 0,
                                                SALESPRICETOTALCURRE), 0
  5                   ),
  6          1, decode(
                  translate(substr(activityNumber,1,1),'23456789','22222222')||
  7           translate(substr(activityNumber,2,2),'1234567890','2222222222')||
  8           substr(activityNumber,4),
  9                     '222', SALESPRICETOTALCURRE, 0 ),
 10          0, decode( substr(activityNumber,1,1) ||
 11           translate(substr(activityNumber,2,1),'23456789','22222222') ||
 12           translate(substr(activityNumber,3,2),'1234567890','2222222222') ||
 13                     substr(activityNumber,5),
 14                     'U222', SALESPRICETOTALCURRE, 0 )
 15        )
 16   from t;

DEPARTMENTNUMBER ACTIVITYNUMBER       SALESPRICETOTALCURRE DECODE(DEPARTMENTNUMB
---------------- -------------------- -------------------- ---------------------
               4 UM                                      1                     0
               4 UMA                                     1                     1
               4 UN                                      1                     0
               1 199                                     1                     0
               1 200                                     1                     1
               1 500                                     1                     1
               1 900                                     1                     1
               1 999                                     1                     1
               1 2000                                    1                     0
               0 U199                                    1                     0
               0 U200                                    1                     1
               0 U500                                    1                     1
               0 U900                                    1                     1
               0 U999                                    1                     1
               0 U2000                                   1                     0

15 rows selected.

ops$tkyte@ORA717DEV.US.ORACLE.COM>
ops$tkyte@ORA717DEV.US.ORACLE.COM> select
  2  sum( decode( departmentnumber,
  3          4, decode( substr(activityNumber,1,2),
  4                     'UM', decode(length(activityNumber),2,0,
SALESPRICETOTALCURRE), 0
  5                   ),
  6          1, decode(
translate(substr(activityNumber,1,1),'23456789','22222222') ||
  7
translate(substr(activityNumber,2,2),'1234567890','2222222222') ||
  8                     substr(activityNumber,4),
  9                     '222', SALESPRICETOTALCURRE, 0 ),
 10          0, decode( substr(activityNumber,1,1) ||
 11
translate(substr(activityNumber,2,1),'23456789','22222222') ||
 12
translate(substr(activityNumber,3,2),'1234567890','2222222222') ||
 13                     substr(activityNumber,5),
 14                     'U222', SALESPRICETOTALCURRE, 0 )
 15        ) )
 16   from t;

SUM(DECODE(DEPARTMENTNUMBE
--------------------------
                         9
Review & Followup

      Rating: 2
sql integration
      ........  November 19, 2001
Reviewer:  vikas
       from INDIA
The solution u send was working good but while checking
    ACTIVITYNUMBER >= 'U200' AND ACTIVITYNUMBER <= 'U999'
 the code does not work for <='U999'
   for eg our data contains
    U222,U343,U345-2,U567-1,U890,U992-6
  then the query does not work for U345-2 etc values...
    it gives only U222,U343,U890 where as it should have returned all the data
containg hypen(-)...

so this was the main problem we were facing sir....

          Followup:

Well, you know what -- given the inputs I had below -- that would be impossible
to forsee.  One would think they were numbers, nothing to the contrary was
present.

It is easy enough to fix, sounds like you want to change the rule I specified
(to let you know what I was doing, the rules I was following):

if deptno = 0 and the first character is a U and the second is one of 23456789
and the 3rd/4th are one of 1234567890 and there is no fifth...

into:

if deptno = 0 and the first character is a U and the second is one of 23456789
and the 3rd/4th are one of 1234567890 and ignorning any other characters from
the fifth on.

so, simply turn:

 10          0, decode( substr(activityNumber,1,1) ||
 11           translate(substr(activityNumber,2,1),'23456789','22222222') ||
 12           translate(substr(activityNumber,3,2),'1234567890','2222222222') ||
 13                     substr(activityNumber,5),
 14                     'U222', SALESPRICETOTALCURRE, 0 )

into

 10          0, decode( substr(activityNumber,1,1) ||
 11           translate(substr(activityNumber,2,1),'23456789','22222222') ||
 12           translate(substr(activityNumber,3,2),'1234567890','2222222222')
 13                     ,
 14                     'U222', SALESPRICETOTALCURRE, 0 )

ignoring the last characters.

For example, the old way:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select activityNumber,
  2                  decode( substr(activityNumber,1,1) ||
  3          translate(substr(activityNumber,2,1),'23456789','22222222') ||
  4          translate(substr(activityNumber,3,2),'1234567890','2222222222') ||
  5                         substr(activityNumber,5),
  6                  'U222', 'between u200 and u999', 'not between' )
  7  from t;

ACTIVITYNU DECODE(SUBSTR(ACTIVIT
---------- ---------------------
U100       not between
U200       between u200 and u999
U364-2     not between
U567-1     not between
U999       between u200 and u999
UABC       not between

6 rows selected.

Versus the new way:

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select activityNumber,
  2                  decode( substr(activityNumber,1,1) ||
  3             translate(substr(activityNumber,2,1),'23456789','22222222') ||
  4             translate(substr(activityNumber,3,2),'1234567890','2222222222'),
  5                  'U222', 'between u200 and u999', 'not between' )
  6  from t;

ACTIVITYNU DECODE(SUBSTR(ACTIVIT
---------- ---------------------
U100       not between
U200       between u200 and u999
U364-2     between u200 and u999
U567-1     between u200 and u999
U999       between u200 and u999
UABC       not between

6 rows selected.

shows the old vs the new way.  Simple extension of the existing logic.  I tried
to lay out the rules I was following in the event there was an ambiguity like
this -- you should be able to understand the logic I presented and rehape it to
conform to your actual requirements...

November 20, 2001 Jacques -- Thanks for the question regarding
      "Package question", version 817

      You Asked
Hi Tom,

I have the following package:

CREATE OR REPLACE PACKAGE CHK_BOX_PK IS
        PROCEDURE chk_flight_select (Flight_id IN VARCHAR,action IN
VARCHAR2,booking_id in varchar);

END chk_box_pk;
-----------------------
CREATE OR REPLACE PACKAGE BODY chk_box_pk IS

 TYPE flight IS TABLE OF flights.flight_id%TYPE
          INDEX BY BINARY_INTEGER;
     flight_id   flight;

PROCEDURE chk_flight_select (Flight_id IN VARCHAR,action IN VARCHAR2,booking_id
in VARCHAR) IS

    BEGIN
   IF action = 'INS' THEN
       Insert into flight_bookings(flight_id, booking_id) values(flight_id,
booking_id);
   END IF;

   IF action = 'DEL' THEN
       delete from flight_bookings where flight_id = flight_id and booking_id =
booking_id;

   END IF;
   END;
 end;

---------------------------------------------------------

whenever I use this to insert a value it works fine but when I delete a value
the package ends up deleting all the rows in the table with the referenced
booking number.

When I execute the delete line on its own in SQL+ substituting the variables
with the values they represent it works fine and just delete the line involved.

Do packages handle delete stamtents in a different way from ordinary sql or am I
just doing someting stupid.

Thanks

Jacques

      and we said...
Ahh -- but if you go into sqlplus and execute the query:

delete from flight_bookings where flight_id = flight_id and booking_id =
booking_id;

What happens then?  You delete every row where flight_id and booking_id IS NOT
NULL!!!!

You did a "bad" thing.  You named your parameters to the procedure after the
columns.  This is ambigous (to us -- not to the parser).  PLSQL just parsed this
statement and didn't find any bind variables -- flight_id is a column in the
table -- so it left it that way.

For this reason I ALWAYS code variable names starting with:

g_    package variables.
p_    parameters
l_    local variables.

Eg:

create package body foo
as

g_some_variable   number := 5;

procedure bar( p_input in varchar2 )
is
   l_local_var   date;
begin
   .....

No worries there on that one!  Change your parameter names and use this naming
convention everywhere to avoid issues like this in the future.
Review &
      Followup

      Rating:
      5
Thanks  November 19, 2001
Reviewer:
      Jacques Luckhoff
Thanks for a very fast and good response.

jacques

      Rating: 4
One more "BAD"
      thing  November 19, 2001
Reviewer:  Steven R.
      Gerber  from NJ USA
The PACKAGE Type(s) and PACKAGE variables are also bad. The TYPE flight is a
TABLE OF flight_id and the PACKAGE variable flight_id is of TYPE flight. That
ends up with PACKAGE variable filght_id is actually a TABLE OF flight_id(s)!
Talk about a recursive definition ...

          Followup:

good point -- points out the need for good naming conventions!

      Rating: 5
Yes,
      but  November 20, 2001
Reviewer:  George
      Jansen  from Washington, DC USA
<p>While the conventions I use are pretty much your, there is the alternative
view, in Steven Feurstein's <i>Oracle PL/SQL Best Practices</i>, that you should
"Qualify PL/SQL variables with their scope names when referenced inside SQL
statements." This appears as practice SQL-01.

          Followup:

IMHO -- verbose and pendantic and totally not necessary (and not nearly as
useful).  It can also lead to confusion as the "procedure.variable" name starts
to look like a correlation name.  For exmaple:

   select * from emp where emp.ename = insEmp.ename;

I'd rather just code:

   select * from emp where emp.ename = l_ename;  (or p_ename, whatever).

It is, to me, more clear that l_ename is a bind variable.  In a large query
reading procedure.variable can be very confusing -- is it a column name or is is
a variable name -- i have to look to the from clause to see what the correlation
names are to see if insEmp is a table reference or a procedure name.

Just my 3cents on that one.

November 20, 2001 Gyanu -- Thanks for the question regarding "How
      to bind output Parameter from PL/SQL into KSH script", version 8.1

      You Asked
I have KSH script which executes P/SQL procedure and returns few parameters.
After I exit from SQLPLUS environment I want them to carry them over into my KSH
script. Is there a way to do this?

      and we said...
the easiest way I know to do this is goes like this:

#!/bin/ksh

cat <<EOF > /tmp/$$.sql
set termout off
set feedback off
set echo off
spool /tmp/$$.ksh
begin
    for x in ( select rownum, username from all_users where rownum <= 5 )
    loop
        dbms_output.put_line( 'user' || x.rownum || '=' || x.username );
    end loop;
end;
/
exit
EOF

spool off
sqlplus / @/tmp/$$.sql

. /tmp/$$.ksh

echo $user1
echo $user2
echo $user3
echo $user4
echo $user5

rm /tmp/$$.sql /tmp/$$.ksh

-----------------------------------------------------

Review &
      Followup

      Rating: 4
Another
      approach  November 19, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
Here is an alternative to Tom's script, since you seem to have a specific
procedure.

If you seem to have a stored procedure like:

----------------------------------------------------
create or replace procedure calc (a number, b number,
                                  c out number, d out number)
is
begin
c:=a+b;
d:=a*b;
end calc;
----------------------------------------------------

You should do this:

----------------- Start of ksh script --------------
#!/bin/ksh

cat << EOF >/tmp/$$.sql

set termout off
set feedback off
set echo off
set serveroutput on
spool /tmp/$$.ksh
declare
a number:=10;
b number:=20;
c number;
d number;
begin
calc (a,b,c,d) -- This is where your proc comes in
dbms_output.put_line('VAR1='||c); -- These are your ksh
dbms_output.put_line('VAR2='||d); -- variable assignments
end;
/
spool off
exit
EOF

# you can choose your authentication scheme
sqlplus username/password@hoststring @/tmp/$$.sql

. /tmp/$$.ksh

echo $VAR1
echo $VAR2

rm /tmp/$$.sql /tmp/$$.tmp

------------------ End of ksh script ---------------

Just a couple of comments:

- Do not forget to "set serveroutput on"
- "spool off" should be inside the sql code, not in the ksh script body

      Rating:
      4
Continuing...  November 20, 2001
Reviewer:
      Andre Whittick Nasser  from Rio de Janeiro, Brazil
There was a small error in my script above. A semicolon (;) is missing:

...
begin
calc (a,b,c,d); <-- There should be a semicolon here
dbms_output.put_line('VAR1='||c);
...

Just that...

Thanks !

          Followup:

see -- we all make typos ;)

yes, my "spool off" should have been in the $$.sql file -- I moved it around and
missed it on the cut and paste.

November 20, 2001 Yogesh -- Thanks for the question regarding
      "Export and Point in time recovery", version 8.1.7

      You Asked
I was doing one experiment. I droped a table on 10/11/01. I was having logical
backup(EXPORT) upto 8/11/01, so I got my table back. My db was in archive log
mode so I tried to roll it fwd i.e. (PITR). But I'm enable to get the data for
last two days !! Can U please explain the cause ?

      and we said...
Because EXP is a LOGICAL not physical backup.  IMP just inserts data, just like
your application would.

suppose you had written the data down in your notebook on 8/11/01.  On 10/11/01
you dropped the table.  You then created the table, and from your notebook you
typed in the insert into statements in sqlplus.  You would not expect to be able
to "roll that forward" from the archives (i hope you wouldn't).  Well, IMP is
just doing the same thing.

You need to use real backups -- you need to read:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/toc.htm
from cover to cover...  It'll give you a good foundation on backup and recovery.
Review &
      Followup

      Rating: 4
My
      friend...  November 20, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
If you are or intend to be a DBA, I would suggest taking the Oracle University
courses. You WILL have a problem if you face a real production environment.

Hoping to help...

      Rating:
      3
  November 20, 2001
Reviewer:
      Vikram  from Phoenix
You just had to import the Table from your export into the running Database.
It might fail for rows which do not have RI !
But it shouldnt matter.
Or you could do a PITR from a previous Cold/Hot backup, not Export

November 20, 2001 Jim -- Thanks for the question regarding "Error
      Handling", version 8.1.7

      You Asked
Tom,
    I am helping a small development team build a small app.
    It will have a VB GUI, Oracle 8.1.7 and use some stored procs
    but not all data will be accessed via SPs. At some stage
    the app will be web enabled and VB maybe done away with.

    What the development team has asked for, is a way to trap
    oracle error message codes and return more meaningful
    messages.

    For example instead of

    ORA-00926 missing VALUES keyword

    return

    ORA-00926 missing VALUES keyword

    Cause: An INSERT statement has been entered without the keyword
    VALUES or SELECT. Either a VALUES clause or a SELECT subquery
    must follow the INSERT INTO clause.

    Action: Correct the syntax. Enter either a VALUES clause or a
    subquery after the INSERT INTO clause

    I think they would like to have something like the oerr
    utility output appended to the message.
    I am meeting with them this afternoon
    because I think they even want to add their own message
    to the Oracle error message.

    Any suggestions ?

    Thanks Jim

      and we said...
You can write a tiny app for this small group to load the
$ORACLE_HOME/rdbms/mesg/oraus.msg file into the database -- it has the error
codes, messages, causes and actions.

oerr just "greps" this file.
Review &
      Followup

      Rating:
      3
  November 20, 2001
Reviewer:
      A reader
Tom,

Can you please breif me, how to load that msg file into the database?...

And what i could do to display the breif message while raised an oracle error.

Sorry, i'm really NOT clear with ur answer.

Nirmal.

          Followup:

Ok, since this comes up from time to time, here are the steps to load up the
message file.

First, we gotta get one.  I just noticed that on NT, we do not appear to ship
the clear text version of the msg file, I've put the 817 msg file here:

http://asktom.oracle.com/~tkyte/oraus.msg
you can download that to load.  It has the action/cause text for messages that
have them (and not all do - your example below for example!)  Most do, some
don't.

After that, we'll create a table to load it into:

drop table mesg;
create table mesg ( id int primary key, text varchar2(4000) );

Next, we'll load the oraus.msg file with this control file:

load data
infile 'oraus.msg'
replace
into table mesg
(
id SEQUENCE,
text position (1:1000)
)

just run "sqlldr user/password controlfile.ctl".

Now, we'll clean up the loaded data:

create table mesg_text
( code varchar2(5),
   msg varchar2(255),
 cause varchar2(4000),
action varchar2(4000) );

declare
    l_code mesg_text.code%type;
    l_msg  mesg_text.msg%type;
    l_cause mesg_text.cause%type;
    l_action mesg_text.action%type;
    l_in_cause boolean;
    function clean( p_str in varchar2, p_what in varchar2 )
    return varchar2
    is
    begin
            return ltrim(rtrim(replace(
                  replace( substr( p_str, 3 ), p_what, '' ),chr(9), ' ' )));
    end;
begin
    for x in ( select text from mesg order by id )
    loop
        if ( x.text not like '//%' )
        then
            if ( l_code is not null )
            then
                insert into mesg_text values
                ( l_code, l_msg, ltrim(l_cause,chr(10)), ltrim(l_action,chr(10))
);
            end if;
            l_code := substr( x.text, 1, 5 );
            l_msg  := substr( x.text, 15 );
            l_cause := null;
            l_action := null;
            l_in_cause := NULL;
        elsif ( x.text like '// *Cause:%' )
        then
            l_in_cause := TRUE;
        elsif ( x.text like '// *Action:%' )
        then
            l_in_cause := FALSE;
        end if;

        if ( l_in_cause )
        then
            l_cause := l_cause || chr(10) || clean( x.text, '*Cause:' );
        elsif ( NOT l_in_cause )
        then
            l_action := l_action || chr(10) || clean( x.text, '*Action:' );
        end if;
    end loop;
    if ( l_code is not null )
    then
        insert into mesg_text values
        ( l_code, l_msg, ltrim(l_cause,chr(10)), ltrim(l_action,chr(10)) );
    end if;
end;
/

After that, we can query:

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec print_table( 'select * from mesg_text
where code = ''01555'' ' );
CODE                          : 01555

MSG                           : "snapshot too old: rollback segment number %s
with name \"%s\" too small"

CAUSE                         : rollback records needed by a reader for
consistent read are
overwritten by other writers

ACTION                        : Use larger rollback segments
-----------------

PL/SQL procedure successfully completed.

Now, your error handling code will get the error code, you'll run a query to get
the msg/cause and action and display it.  When you encounter a NULL cause and
action, you can fill in a message if you like over time (if its an error you
seem to hit and want more details)

      Rating: 5
Great
      idea  November 20, 2001
Reviewer:  Naveed Amin
      Khan  from West DesMoines Iowa
I think a great many applicatins can benefit from this technique.

      Rating: 5
Nice
      one!  November 20, 2001
Reviewer:  jim

Thanks Tom !

You have saved the day again... pretty soon
I'm going to start having to give you a
slice of my hourly rate !

November 20, 2001 Seetharaman -- Thanks for the question regarding
      "Nested Table", version 8.1.5

      You Asked
Hi Tom
  Greetings..

  My question this time is how to create a nested table and how
to retrieve records out of it??

  Pls reply me with an example

  Thanks in advance

regards

Seetharaman Srinivasan

      and we said...
Here is an example.  I will use a "complex" object type called
"myScalarType"

ops$tkyte@8i> create or replace type
  2  myScalarType as object
  3  ( x int,
  4    y date
  5  )
  6  /

Type created.

Then I create a nested table type of that scalar object:
ops$tkyte@8i>
ops$tkyte@8i> create or replace type
  2  myArrayType as table of myScalarType
  3  /

Type created.

and finally, a table with a column of that type:
ops$tkyte@8i>
ops$tkyte@8i>
ops$tkyte@8i> create table x
  2  ( pk       int primary key,
  3    array myArrayType
  4  )
  5  nested table array store as X_Array_Data
  6  (
  7    (PRIMARY KEY (nested_table_id, X))
  8     ORGANIZATION INDEX
  9  )
 10  /

Table created.

I like to store the nested tables as IOTS.  You in general
will always want to index the nested_table_id (hidden foreign
key back to the parent) so this makes sense to build the table
with this key in mind.  Now, to create some data and query it:

ops$tkyte@8i>
ops$tkyte@8i>
ops$tkyte@8i> insert into x values
  2  ( 1, myArrayType( myScalarType(1,sysdate ),
  3                    myScalarType(2,sysdate+2) ,
  4                    myScalarType(3,sysdate-2)
  5                  )
  6  );

1 row created.

ops$tkyte@8i> insert into x values
  2  ( 2, myArrayType( myScalarType(1,sysdate+100),
  3                    myScalarType(2,sysdate-2) ,
  4                    myScalarType(3,sysdate+243)
  5                  )
  6  );

1 row created.

I can either select arrays of data with each row:

ops$tkyte@8i>
ops$tkyte@8i>
ops$tkyte@8i> select x.pk, x.array array from X x
  2  /

        PK ARRAY(X, Y)
---------- ----------------------------------------
         1 MYARRAYTYPE(MYSCALARTYPE(1, '11-JUL-00')
           , MYSCALARTYPE(2, '13-JUL-00'), MYSCALAR
           TYPE(3, '09-JUL-00'))

         2 MYARRAYTYPE(MYSCALARTYPE(1, '19-OCT-00')
           , MYSCALARTYPE(2, '09-JUL-00'), MYSCALAR
           TYPE(3, '11-MAR-01'))

Or I can treat a single instance of a nested table as a
"table" itself:

ops$tkyte@8i>
ops$tkyte@8i> select *
  2    from THE (select array from x where pk=1)
  3  /

         X Y
---------- ---------
         1 11-JUL-00
         2 13-JUL-00
         3 09-JUL-00

Review &
      Followup

      Rating: 3
code no
      work.  November 19, 2001
Reviewer:  steve
      shiflett  from san jose, ca
This doesn't seem to work for 9i

ops$tkyte@8i> create table x
  2  ( pk       int primary key,
  3    array myArrayType
  4  )
  5  nested table array store as X_Array_Data
  6  (
  7    (PRIMARY KEY (nested_table_id, X))
  8     ORGANIZATION INDEX
  9  )
 10  /

          Followup:

code works great in 9i:

ops$tkyte@ORA9I.WORLD> create or replace type
  2  myScalarType as object
  3  ( x int,
  4    y date
  5  )
  6  /

Type created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> create or replace type
  2  myArrayType as table of myScalarType
  3  /

Type created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> create table x
  2  ( pk       int primary key,
  3    array myArrayType
  4  )
  5  nested table array store as X_Array_Data
  6  (
  7    (PRIMARY KEY (nested_table_id, X))
  8     ORGANIZATION INDEX
  9  )
 10  /

Table created.

one would REALLY need to supply the error message if you expect any meaningful
replies!!!

you most likely forgot to create the nested table types -- but without the error
message, I cannot even hazzard a good guess.

      Rating: 5
What's the
      advantage to this?  November 20, 2001
Reviewer:
      John  from ma
Great example!
But Why?
Seems like more work to me.

Do you use this in the real world?

          Followup:

see also

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:2010064718579
In real life, I do not use them as a persistent storage mechanism.  I use them
as a datatype in my plsql code constantly.  I use real parent/child tables
personally for persistent storage.

November 21, 2001 raju -- Thanks for the question regarding
      "returning pl/sql table records as ref cursor", version 8.1.6

      You Asked
hi tom,

i have pl/sql table that has got some records, i want to return those records as
a
ref cursor from a procedure

can you help on the above.

thank you.

      and we said...
You cannot.

If you use an OBJECT type instead, you can.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace type myScalarType as object
  2  ( x int, y date, z varchar2(30) )
  3  /

Type created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace type myArrayType as table
of myScalarType
  2  /

Type created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> variable x refcursor
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2     l_data myArrayType := myArrayType( myScalarType( 1, sysdate, 'hello' ),
  3                                  myScalarType( 2, sysdate+1, 'goodbye' ) );
  4  begin
  5          open :x for
  6          select * from TABLE( cast( l_data as myArrayType ) );
  7  end;
  8  /

PL/SQL procedure successfully completed.

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

         X Y         Z
---------- --------- ------------------------------
         1 12-NOV-01 hello
         2 13-NOV-01 goodby

Review &
      Followup

      Rating: 5
thanks
      tom  November 12, 2001
Reviewer:  raju
       from USA
can you declare that object type in my package alone, i don't want to create in
database. is that possible?
please reply.

          Followup:

If you want SQL to understand the type (and you do -- you want a ref cursor) -
it must be a SQL type created in SQL.

I've always been confused by this -- what is the issue with creating an object
type?  I mean -- you would not hesitate to create a table, a package, a view --
what is the technical issue with regards to creating something you need to have
your application work?  (this is not just to you Raju -- just a general question
for anyone)

      Rating: 5
ok it is fine,
      no probs -- but  November 12, 2001
Reviewer:
      A reader
ok ok ok tom,
no problem i will create.
i think we can create the second type in my package right?
if yes, can i use the query on that?
i want to know whether this is possible or not and one more thing in your
example

l_data myArrayType := myArrayType( myScalarType( 1, sysdate, 'hello' ),
                                    myScalarType( 2, sysdate+1, 'goodbye' ) );

you assigned the values in the above way,
can you give me an example to read from a cursor and loop through the cursor
records and assign to it.

thanks in advance

          Followup:

both types need to be sql types -- outside of packages, in the data dictionary.
ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2          l_data myArrayType := myArrayType();
  3  begin
  4      for x in ( select user_id, username, created from all_users )
  5      loop
  6         l_data.extend;
  7         l_data(l_data.count) := myScalarType( x.user_id, x.created,
x.username );
  8      end loop;
  9
 10          open :x for
 11          select * from TABLE( cast( l_data as myArrayType ) );
 12  end;
 13  /

PL/SQL procedure successfully completed.

      Rating: 2
Ill tell you
      why....  November 20, 2001
Reviewer:  Jason
       from Midwest
"I've always been confused by this -- what is the issue with creating an object
type?  I mean -- you would not hesitate to create a table, a package, a view --
what is the technical issue with regards to creating something you need to have
your application work?  (this is not just to you Raju -- just a general question

for anyone)"

Actually yes I would hesitate to create a table view etc.
The reason is because the development environment I work in these things (NEW
tables views etc) require lots of paperwork, review, DBA approval and its a
HASSLE.  I have been searching high and low for a way to dynamically build a
result set in Oracle and all the responses include creating an object....
I DONT WANT TO CREATE AN OBJECT!!!!  This should be a hell of a lot easier.  I
moved from a MS SQL Server shop to an Oracle shop.  I am not suggesting that SQL
Server is a better product overall but from a development standpoint I would
take SQL Sever over Oracle any day.  In SQL Server I could easily create temp
tables, global temp tables, return multiple result sets, build results sets
dynamically.  I didn't have to permantely create a thing like I do in Oracle.
For all the hype Oracle gets in the IT world...
I am just really disappointed in how hard it is to program against.

          Followup:

Well, lets see -- your complaints center around a self imposed bureaucracy,
where by you have to live with a set of rules.  A set of rules that obviously
impedes your ability to do your job.  An object type is not a table (stores not
data).  Its not a query (not a view).  Its executable code like a package or a
procedure -- its not any different.  If you cannot make the case or the people
you make the case to don't understand this, there isn't anything we can do here.

But as to your real frustration "I have been searching high and low for a way to
dynamically build a result set in Oracle".

Well, I don't know who you have been asking -- but I can say "it has NOTHING to
do with object types".  Object types are -- by their very definition -- STATIC.
You define them and then have a shape to them.  Nothing dynamic about them.  REF
CURSORS on the other hand -- the method by which you return a result set in
Oracle -- they can be of any size and shape.

This is what is would look like:

create or replace package my_pkg
as
   type rc is ref cursor;

   procedure get_some_data( p_cursor in out rc, p_inputs in date );
   procedure get_some_other)data
             ( p_cursor in out rc, p_where_clause in varchar2);
end;
/
create or replace package body my_pkg
as
   procedure get_some_data( p_cursor in out rc, p_inputs in date )
   is
   begin
        open p_cursor for select * from emp where hiredate > p_inputs;
   end;

   procedure get_some_other)data
             ( p_cursor in out rc, p_where_clause in varchar2)
   is
   begin
      open p_cursor for 'select * from dept where ' || p_where_clause;
   end;
end;
/

See

http://osi.oracle.com/~tkyte/ResultSets/index.html
for examples in perl, vb, java, odbc, ado/asp, pro*c, oci....

I'd say your frustration lies in the fact that you KNOW something -- SQLServer,
you are learning something else -- Oracle.  They are different, you would like
them to be same (but they are not).

In Oracle -- I would say temp tables are not necessary -- I've been using Oracle
for going on 15 years (and yes, I used sqlserver, sybase, informix, db2, sql/ds,
ingress, you name it -- i've probably used it at least once in a past life) and
I've NEVER needed a temp table.  They are a crutch that SQLServer *needs* that
we do not.  But anyway -- we do have them -- yes, they are *different*, its a
different implementation.  I understand the shop you are in forbids them or
makes them so hard for you to use -- but hey, nothing we can do about that.

Returning multiple result sets -- dynamically constructed -- no problem.  Read
the above link, you'll see how to do it, its trivial, its simple, its actually
in the documentation too. (and no, you need not permanently create an object
type).

Actually its funny - the object type thing lets me treat a PLSQL variable as if
it were a database table -- a feature that I'm fairly certain SQLServer won't
let me do.  So in the end, you are just being prevented from doing something in
Oracle that isn't quite possible in SQLServer.

Hope this helps you with result sets.  I find Oracle pretty easy to program
against myself (no surprise there).  It comes from knowing it, knowing how it
works, knowing the features it has.  It doesn't come from treating it as if it
were sqlserver.

      Rating: 5
little confused
      about temp table comment  November 20, 2001

Reviewer:  Doug  from CT, USA
Very interesting thread here.  I don't know SQL Server at all by the way.  But
when you say you've never found the need for a temp table in Oracle, you must
mean something else than the Oracle temp table I'm thinking about.  You address
global temporary tables in your book.  So..two quick followups - what is the
difference between a temp table in SQLServer and a)The one you talk about in
your Oracle book and b) the one you referred to never having needed in Oracle

          Followup:

see also

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:48812348054
In my book I described a use for temporary tables.  In my book, I used one for a
PALM sync application I wrote.  What I did was to have a JDBC thin client that
acted as the PALM conduit (the piece of software you install on your PC). This
talked to the PALM and to the database.  It started by getting all of the
changes from the PALM pilot and stuffing them into a temporary table on the
server.  As each changed was processed (by a stored procedure of course - all of
the real logic was in the database to do the sync) I deleted each row in the
temp table.  At the end of the sync, I placed all of the changes to be applied
to the palm into this same temporary table.  The jdbc client would fetch each
row and apply it to the palm and then commit.  The temp table would be empty.

This was pure convienence here. We could have just as easily used a real table
and at the end of the jdbc client applying each row to the palm pilot -- it
would have deleted from the table.  Due to our multi-versioning, read
consistency and non-blocking model -- this would work very well.  I simply used
a temp table because they were new and offered a little programming convience
(they cleaned themselves up).  Since the entire sync is one big transaction --
it didn't matter that they were temp or not.

Most people, coming from a SQLServer (be it MS or Sybase) background use temp
tables all over the place.  Stored procedure create and use them constantly.
Where we would use joins, inline views, complicated queries -- they will program
4 or 5 "simple queries" (typically for the convienence of the computer software
here) and then join the subresults together.  For example, I have a query I call
free.sql:

select nvl(b.tablespace_name,
             nvl(a.tablespace_name,'UNKOWN')) name,
       kbytes_alloc kbytes,
       kbytes_alloc-nvl(kbytes_free,0) used,
       nvl(kbytes_free,0) free,
       ((kbytes_alloc-nvl(kbytes_free,0))/
                          kbytes_alloc)*100 pct_used,
       nvl(largest,0) largest
from ( select sum(bytes)/1024 Kbytes_free,
              max(bytes)/1024 largest,
              tablespace_name
       from  sys.dba_free_space
       group by tablespace_name ) a,
     ( select sum(bytes)/1024 Kbytes_alloc,
              tablespace_name
       from sys.dba_data_files
       group by tablespace_name )b
where a.tablespace_name (+) = b.tablespace_name
order by 1;

In SQLServer, it would have been very common, unusual NOT to do something like
the following:

procedure p
is
  select sum(bytes)/1024 Kbytes_free,
              max(bytes)/1024 largest,
              tablespace_name
     INTO #temp_table_1             creates a temp table on the fly
     from  sys.dba_free_space
    group by tablespace_name
      select sum(bytes)/1024 Kbytes_alloc,
              tablespace_name
       INTO #temp_table_2
       from sys.dba_data_files
       group by tablespace_name
  select nvl(b.tablespace_name,
             nvl(a.tablespace_name,'UNKOWN')) name,
       kbytes_alloc kbytes,
       kbytes_alloc-nvl(kbytes_free,0) used,
       nvl(kbytes_free,0) free,
       ((kbytes_alloc-nvl(kbytes_free,0))/
                          kbytes_alloc)*100 pct_used,
       nvl(largest,0) largest
  from #temp_table_1 a, #temp_table_2 b
 where a.tablespace_name  =* b.tablespace_name
 order by 1

end;

In Oracle we

1) don't create tables on the fly
2) don't need to use temp tables here for performance reasons, the optimizer is
quite capable of dealing with many objects, complex queries.

People in SQLServer use temp tables at the drop of a hat.  They use them like we
use cursors (all over the place).  They don't use cursors like we do -- for
them, cursors are architecturally a "bad thing".

Its just the SQLServer and Oracle are as different as NIGHT and DAY.

November 21, 2001 Partha -- Thanks for the question regarding
      "allocate different Tablespaces", version 8.1.6

      You Asked
Tom,

Can you please me your advice or tips on following topics

1) I have about 40 Different Applications, should i create a diffrent
tablespaces for each application or can i merge multiple applications into one
tablespace.( right now i'm using individual tablespace for each application).

2) should i create diffrent roleid's for each application and give that roleid
to the user.( i created roleid for each application ).

3) How should i register each application in the database.

      and we said...
1) i might use different SETS of tablespaces for each application.  I use
locally managed tablespaces so each app would probably need at least 3 different
tablespaces -- a "small", "medimum" and maybe a "large" one to segment objects
by size.

I would use different SETS of tablespaces since:

o tablespaces are our level of backup and restore pretty much

o tablespaces can be restored to different points in time.  I might need to
restore application1's data to yesterday but don't want to affect anyone else.

o a tablespace is online or offline.  something that would make us offline a
tablespace for app1 should not affect app2.

2) i don't know what a "roleid" is.  do you mean "userid" or schema?  If so,
yes, each app would have its own schema -- maybe more then one (i like to
segment the code from the data if possible).

3) there is no facility for "registering" an application, not sure what you are
asking for here.
Review & Followup

      Rating: 4
Allocating
      Tablespaces  November 21, 2001
Reviewer:
      A reader

November 21, 2001 Partha -- Thanks for the question regarding
      "Script to create new users", version 8.1.6

      You Asked
Tom,

1)Can you please tell me how to create users through stored procedure, by
passing arguments such as userid,password,default tablespace,
and granting privilege create session to a user.

conclusion: when ever user created in the database i want's to pass just those
arguments so that i can avoid writing create user statements for each and
individual user.

Thanks in advance

      and we said...
create procedure new_user( p_name in varchar2,
                           p_pw   in varchar2,
                           p_def_tblspace in varchar2 default 'users' )
as
begin
   execute immediate 'create user ' || P_name || ' identified by ' ||
                        p_pw || ' default tablespace ' || p_def_tblspace ||
                      ' temporary tablespace temp';

   execute immediate 'grant create session to ' || p_name;
end;
/

read:

http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
if you get 'insufficient privs' when running this and grant:

grant create user to username;
grant create sesssion to username with admin option;

to the owner (username) of the procedure.

Review & Followup

      Rating: 5
Creating Users
      through Stored procedure  November 21, 2001

Reviewer:  A reader
Tom,

Really a good script for DBA's

November 21, 2001 Azman -- Thanks for the question regarding "Set
      column default value to space instead of null", version 8.1.7

      You Asked
Hi Tom,
Just want to ask you 1 question.

Is it possible to set the default value of a column to space instead of null?

      and we said...
scott@ORA817DEV.US.ORACLE.COM> create table t ( x int, y varchar2(5) default ' '
);

Table created.

scott@ORA817DEV.US.ORACLE.COM>
scott@ORA817DEV.US.ORACLE.COM> insert into t (x) values ( 1 );

1 row created.

scott@ORA817DEV.US.ORACLE.COM>
scott@ORA817DEV.US.ORACLE.COM> column dump format a15
scott@ORA817DEV.US.ORACLE.COM> select x, '"' || y || '"', dump(y) dump from t;

         X '"'||Y| DUMP
---------- ------- ---------------
         1 " "     Typ=1 Len=1: 32
November 22, 2001 Balraj -- Thanks for the question regarding
      "Concept of Threads -- what is the REDO thread in the alert log.", version
      8i

      You Asked
Hi Tom

I have the doubts about the concepts of threads In Oracle

Can u please explain me with few examples What is thread here.I understand
thread to be a process subpart..which needs CPU Time and resources..

When we start Oracle it writes in Alert Log

Instance started with Thread#1 and continues to write the same in all

What does that mean...

Pl explain with few examples

Thanks/Regards
Balraj

      and we said...
I think you mean REDO threads:

Mon May 14 08:39:25 2001
Successful mount of redo thread 1, with mount id 3779288125.
Mon May 14 08:39:25 2001
Database mounted in Exclusive Mode.
Completed: alter database mount exclusive
Mon May 14 08:39:25 2001
alter database open
Mon May 14 08:39:27 2001
Thread 1 opened at log sequence 1287
  Current log# 4 seq# 1287 mem# 0: C:\ORACLE\ORADATA\TKYTE816\BIGLOG1.LOG
Successful open of redo thread 1.
Mon May 14 08:39:27 2001

That is not a thread in the programming sense.  On windows and netware, Oracle
does use operating system threads instead of processes (as it does on unix).

The thread above is a redo thread.  Think of it like a string (a piece of
thread).  Each instance has its own redo thread.  In OPS (Parallel server) where
more then one instance may mount and open a SINGLE database -- each instance
will have its own redo thread -- its own string of redo records.

In Oracle Parallel Server, each instance writes to its own set of online redo
log files. The redo written by a single instance is called a "thread of redo".
Each online redo log file is associated with a particular thread number. When an
online redo log is archived, Oracle records its thread number to identify it
during recovery.

Review &
      Followup

      Rating:
      5
  June 05, 2001
Reviewer:
      A reader
Thanks so much for such an explanatory answer

      Rating: 3
mixing it with
      MTS   November 22, 2001
Reviewer:  Sudhakar
       from India
Hi tom ...

How it can be diffrentiated with MTS. MTS means we have multi threads and that
is possible in normal db (Non OPS).
Does it matter there ???

Sudhakar

          Followup:

the threads of redo are not to be confused with "threaded programming".  The
threads of redo are like the strings in your shirt.  They are woven together to
given us everything we need.

The "threads" of MTS are individual threads of execution that are totally
indepedent of eachother, they are true "threads of execution".

The are apples and oranges, not comparable in any fashion.

      Rating: 5
Haberdashery
      (sp?)  November 22, 2001
Reviewer:  jim
       from Australia
Tom,
    Thanks for unravelling the thread confusion !

November 23, 2001 ajay -- Thanks for the question regarding "about
      the tablespaces", version 8.1.5.0

      You Asked
hai tom,

nice to see after a gap of one month iam trying to ask questions but every time
its been full.
i want to know that ina databse how many tablespaces can i have and in a
tablespace how many data files can i have, is there any limit to it or we can
specify any number of data files to it.
give me the detaqils of it in clear of datafiles and its storage and tell me
about the pctused and pctfree things.
if i give pctused 80 and pctfree 20 what it happens.
please tell me int detail.

thank u

ajay

      and we said...
The Oracle reference documents limits by this (sorry you had to wait a month to
get an RTFM answer ;)

http://technet.oracle.com/doc/oracle8i_816/server.816/a76961/ch43.htm#11789
You can have 64k tablespaces with 1022 (typically, its os dependent) files /
tablespace and a limit ot 65533 files / database.

As for pctfree/pctused -- if you have my book, I go into this in depth.  As
well, a simple search for:

pctfree pctused

on this site will turn up a couple of good articles on it.
Review &
      Followup

      Rating: 5
Number of
      datafiles  November 21, 2001
Reviewer:
      Connor  from Glasgow
Rumour has it that you can't actually get to 64k datafiles under 32-bit Oracle
due to the limitation of 67m-ish bytes for an single SGA chunk.

Does anyone out there have access to a db of sufficient size to prove/disprove?

      Rating: 3
tablespaces is
      a occean  November 22, 2001
Reviewer:  ajay
       from india
it is been useful for mwe to know the size and no files but what is the 64k
inthat k means a little confusion.

          Followup:

64k is a fairly common term meaning 64 * 1024.  (a "k" is 1024 kilo<unit of
measure>).  Like 64 kilobytes.

November 23, 2001 Prince -- Thanks for the question regarding "How
      to find what privileges can be granted on an object??", version 8.1.7.2

      You Asked
Tom,

I am wondering, how to find what are all the privilege I can grant on an object.
(ex, I can grant select, insert, delete, update on tables/views, but execute on
procs etc). Which catalog tables have these information?

Thanks,

      and we said...
DBA_TAB_PRIVS does.  If you have the GRANTABLE field set, you can grant that
priv to others.

tkyte@TKYTE816> select owner, table_name, privilege
  2  from dba_tab_privs where grantable = 'YES' and grantee = USER;

OWNER                          TABLE_NAME
------------------------------ ------------------------------
PRIVILEGE
----------------------------------------
SYS                            V_$SQL
SELECT

Review &
      Followup

      Rating: 3
Let me clarify
      my question  November 21, 2001
Reviewer:
      Prince..
Tom,

Thanks for the reply. I guess I was not very clear on my question. My qyestion
was, "is there any table which tells what are all the  privilege anyone can have
on an object?"

For example, On TABLES one can have "SELECT, INSERT, DELETE, ALTER etc, but not
EXECUTE". On Procs one can have EXECUTE but not SELECT.

I see in the catproc.sql they have privilege# like -210,
-211 etc which represents different privilege. Are they available in any x$
tables??

Thanks,

          Followup:

There is no such table -- it is part of the language itself.  You would have to
goto the server SQL reference manual and look at the grant command.  It is part
of the syntax of the grant.

      Rating:
      1
system_privilege_map  November 23, 2001

Reviewer:  Hector Aguiling  from New Jersey, USA

Maybe Prince is interested on this...

SQL> select * from sys.system_privilege_map
  2  where rownum < 11
  3  /

 PRIVILEGE NAME
---------- --------------------------------
        -3 ALTER SYSTEM
        -4 AUDIT SYSTEM
        -5 CREATE SESSION
        -6 ALTER SESSION
        -7 RESTRICTED SESSION
       -10 CREATE TABLESPACE
       -11 ALTER TABLESPACE
       -12 MANAGE TABLESPACE
       -13 DROP TABLESPACE
       -15 UNLIMITED TABLESPACE

          Followup:

And that answers this part of the question:

...
"For example, On TABLES one can have "SELECT, INSERT, DELETE, ALTER etc, but not

EXECUTE". On Procs one can have EXECUTE but not SELECT. "
...

how? (it doesn't)  That shows the SYSTEM (not object) priveleges.

AFAIK, there is no table that says "you can grant SELECT on a table, you can
grant EXECUTE on a procedure (but you cannot grant SELECT on a procedure and
EXECUTE on a table).

You would have to create a table and place the information described in:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76989/ch4j4.htm#27143
into it.

November 24, 2001 Paul -- Thanks for the question regarding "IAS 9i
      support for OWA Replacement Cartridge", version IAS 9i

      You Asked
My customer is using an application that depends heavily upon the OWA
Replacement Cartridge to upload files into the Oracle database. The original
application was build (for several million dollars) using Oracle DBMS 7.3 some 4
years ago. Since then they have upgraded to Oracle DBMS 8.1.6 and OAS 4.0.8.

As my customer is now thinking about upgrading to IAS 9i what issues might I
expect to deal?

Paul
ps. A simple thank you seems totally inadequate for the help you have provided
to myself and others.

      and we said...
Well, I would recommend with 9iAS that you use the mod_plsql Apache module that
comes with iAS.

A little bit of history....

In the beginning there was "owa" (Oracle web agent) that came with OIS (Oracle
Internet Server) version 1.  It was very simplistic - did basic stored
procedures.  With OWS2.0 I wrote my own "cartridge" that mimicked OWA and added
database authentication, file upload/download, pre-post functions, the "oracle
tag", and so on.  Over time, many of the concepts got added into OWA.

Then came webdb which actually originated in the group I work in (we called it
webview and site builder, now it is known as "portal").  With webdb came the
lightweight listener -- a small http server that did the plsql stuff.  That
lightweight listener was actually based on my code (minus a couple of features
they didn't feel like supporting like file upload to the file system -- they
only do it into the database).

Now, the webdb lightweight listener became the mod_plsql module in iAS -- hence
the mod_plsql module is very much like my owa replacement as its base code is
the owa replacement (many of the same DBAUTH configuration parameters will be
reconizable by you).

So, my recommendation would be to upgrade to iAS with mod_plsql -- using the
native features in there.  There will be a slight modification to the document
table you upload into (they store a little more meta data and they do the
download a little differently, but the equivalent functionality is all there).

My owa replacement does not run with Apache as a module, it can run as a cgi-bin
(non-performant) but I've never ported it to the Apache mod api.

So, unless you are using a feature that owarepl did and mod_plsql doesn't (eg:
the biggest one being file upload to the filesystem instead of the database),
the migration is rather straight forward.  I've since migrated myself.
November 24, 2001 Tran Le -- Thanks for the question regarding "Can
      not desc,select,DML on table ", version 8.1.6

      You Asked
Hi tom
I have one question for you,sorry for my poor E.
I use J2EE to deploy my application. The EJB object I use is CMP. My DATASOURCE
connect to ORACLE DATABASE. Alter I deploy my application it create some tables
but I can not access it. I use command :

SQL> select table_name from user_tables ;

TABLE_NAME
------------------------------
CategoryBeanTable
ForumBeanTable
ForumBean_ideas_IdeaBean_Tab
IdeaBeanTable
JobBeanTable
OrganizationBeanTable
OrganizationBean_users_UserB
UserBeanTable
UserBean_jobs_JobBean_Table

I see all table, but it lower case and when I use command, I see error

SQL> desc CategoryBeanTable ;
ERROR:
ORA-04043: object CategoryBeanTable  does not exist

I use command :

SQL>select object_name,object_type from user_objects

OBJECT_NAME                    OBJECT_TYPE
------------------------------ ---------------
CategoryBeanTable              TABLE
ForumBeanTable                 TABLE
ForumBean_ideas_IdeaBean_Tab   TABLE
IdeaBeanTable                  TABLE
JobBeanTable                   TABLE
OrganizationBeanTable          TABLE
OrganizationBean_users_UserB   TABLE

I don't know why. Can you explaint for me ?
Thanhs

      and we said...
Whatever tool you used to create the tables used "quoted identifiers" (too bad
for you - makes your life hard).

You can:

SQL> desc "CategoryBeanTable"
SQL> select * from "CategoryBeanTable";

You must quote all identifiers that are in mixed case.

November 24, 2001 sunil -- Thanks for the question regarding "XML ,
      generating xml from Select statement in pl/sql using DBMS_XMLQUERY",
      version 9.0.1.1.0A

      You Asked
Hi Tom,

I am trying to generate a xml from a query in the database.
i am using xdk for pl/sql version
DBMS_XMLQuery to do this

Oracle XDK Java      9.0.1.1.0A

my database version  8.1.6
I am able to generate the xml quite fine.

but my problem is with the
  DBMS_XMLQUERY.setRowsetTag
i want to generate the xml which has got a rowsettag which is like this
     doc:Applicant.CreateFromData xmlns:doc="urn:sap-dom:document:sap:business"

but when i say
  DBMS_XMLQUERY.setRowsetTag (queryCtx ,'doc:Applicant.CreateFromData
xmlns:doc="urn:sap-com:document:sap:business"');

and copmile the procedure , it compile quite fine but when i  execute the
program i get the following error

<ERROR>oracle.xml.sql.OracleXMLSQLException: Character '"' is not allowed in an
XML tag name.</ERROR>

As i understand when i use simple name it works fine
For Example
--------

 DBMS_XMLQUERY.setRowsetTag (queryCtx ,'TOPLEVEL');
but if it contains spaces, Double Quotes(") or equal (=) ,it says they are not
allowed.

Is there a way i can add the Namesapce to the XML ROESETTAG

How can i generate a xml which has got the main tag as shown , (How can i
include defination of namespace in the document element using DBMS_XMLQUERY)

Thanks
Sunil Nettyam

      and we said...
I went to Steve Muench, XML guru and author of Building Oracle XML Applications

http://www.amazon.com/exec/obidos/ASIN/1565926919/
and this is what he has to say

...
Tom,

XSU is not namespace-aware, and what you're trying to do is
effectively generate results whose elements are namespace-qualified.

You'll need to combine XSU with XSLT to achieve your result.

Say your XSU result was:

<ROWSET>
<ROW>
<EMPNO>1234</EMPNO>
<ENAME>TOM</ENAME>
</ROW>
</ROWSET>

An XSLT stylesheet like:

<xsl:transform version="1.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform
xmlns:doc="urn:sap-dom:document:sap:business">
<xsl:template match="ROWSET">
<doc:Applicant.CreateFromData>
<xsl:copy-of select="ROW"/>
</doc:Applicant.CreateFromData>
</xsl:template>
</xsl:transform>

Will have the affect of changing <ROWSET> to your <doc:A.C> element.

If you need all the nested elements to be in the doc namespace, too,
then you'd need to do something like:

<xsl:transform version="1.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform
xmlns:doc="urn:sap-dom:document:sap:business">
<xsl:template match="ROWSET">
<doc:Applicant.CreateFromData>
<xsl:for-each select="ROW">
<doc:Row>
<doc:Empno><xsl:value-of select="EMPNO"/></doc:Empno>
<doc:Ename><xsl:value-of select="ENAME"/></doc:Ename>
</doc:Row>
</xsl:for-each>
</doc:Applicant.CreateFromData>
</xsl:template>
</xsl:transform>

Review &
      Followup

      Rating:
      5
Great  November 26, 2001
Reviewer:
      Sunil Nettyam  from king of prussia, pa
Hi,

Thanks, for showing the way to do it.
i have not yet worked with xslt, but i will work with XSLT and work out the
solution .

Thanks

November 24, 2001 Michael -- Thanks for the question regarding
      "What SQL query is used by "auto trace" reports to query the plan table",
      version 8i

      You Asked
I am building an interactive explain plan facility and would like the syntax to
query the plan table.  I would like the results similar to responces listed in
another task tom question:  reference query result:

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=1
Bytes=26)
   1    0   SORT (AGGREGATE)
   2    1     MERGE JOIN (Cost=6 Card=11 Bytes=286)
   3    2       SORT (JOIN) (Cost=3 Card=14 Bytes=182)
   4    3         TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=14
Bytes=182)
   5    2       SORT (JOIN) (Cost=3 Card=82 Bytes=1066)
   6    5         TABLE ACCESS (FULL) OF 'DEPT' (Cost=1 Card=82

      and we said...
Well, rather then guessing, I used SQL_TRACE to find out exactly what the query
is sqlplus is using.  To do this, I simply:

scott@ORA817DEV.US.ORACLE.COM> set autotrace traceonly explain
scott@ORA817DEV.US.ORACLE.COM> alter session set sql_trace=true;

Session altered.

scott@ORA817DEV.US.ORACLE.COM> select * from emp, dept where emp.deptno =
dept.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=5 Card=14 Bytes=700)
   1    0   NESTED LOOPS (Cost=5 Card=14 Bytes=700)
   2    1     TABLE ACCESS (FULL) OF 'DEPT' (Cost=1 Card=4 Bytes=72)
   3    1     TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=14 Bytes=448)

and then a tkprof report on the resulting trace file shows me:

SELECT ID ID_PLUS_EXP,PARENT_ID PARENT_ID_PLUS_EXP,LPAD(' ',2*(LEVEL-1))
  ||OPERATION||DECODE(OTHER_TAG,NULL,'','*')||DECODE(OPTIONS,NULL,'','
  ('||OPTIONS||')')||DECODE(OBJECT_NAME,NULL,'',' OF '''||OBJECT_NAME||'''')
  ||DECODE(OBJECT_TYPE,NULL,'',' ('||OBJECT_TYPE||')')||DECODE(ID,0,
  DECODE(OPTIMIZER,NULL,'',' Optimizer='||OPTIMIZER))||DECODE(COST,NULL,'','
  (Cost='||COST||DECODE(CARDINALITY,NULL,'',' Card='||CARDINALITY)
  ||DECODE(BYTES,NULL,'',' Bytes='||BYTES)||')') PLAN_PLUS_EXP,OBJECT_NODE
  OBJECT_NODE_PLUS_EXP
FROM
 PLAN_TABLE START WITH ID=0 AND STATEMENT_ID=:1 CONNECT BY PRIOR ID=PARENT_ID
  AND STATEMENT_ID=:1 ORDER BY ID,POSITION

that is the query plan exactly used by SQLPlus to get the explain plan data..

Review &
      Followup

      Rating: 5
got my
      answer  November 24, 2001
Reviewer:  mike
      hichwa
just as I expected, Tom found an easy way to ask, what I thought, was a tough
question.  This query is not published in the tuning guide, to the best of my
knowledge.

November 25, 2001 Shiyin -- Thanks for the question regarding "How
      can I export the tablespace that has been dropped one of the datafile?",
      version 8.1.6

      You Asked
Hi,Tom

   During my work,i have met such question,and hope yr answer.

1. I wrongly create a datafile under the tablespace DRSYS,then I
alter database 'datafile ' offline, and drop this datafile under OS command.Now
the troubles arise.

When i backup the db (alter tablespace drsys begin backup ... end backup),then
the db will report the error messages of the datafile.So I want to resolve this
problem.

Fisrt I want to export the drsys then drop this tablespace and import this
tablespace.But when I export this tablespace, I issued this command:
   'alter tablespace drsys read only; ' then arise the error
ORA-01230,ORA-01111,ORA-01110.So i can't export this tablespace.I wonder whether
the 'exp imp ' method can solve this problem under such situation.

Secondly I use the backup controlfile to trace command to recreate the
controlfile,but it will generate the datafile 'MISS000XX',what sould i do?

2. can't imp the tablespace

Once I exported one of the tablespace, oneday i wrongly dropped this
datafile.then i want to imp this tablespace,but when i create a new datafile
then the imp command  need the file_id of the datafile that I have dropped.so i
can't imp the tablespace,What sould i do?

thanks

      and we said...
It is CRUCIAL to understand that once added, a file is part of the database
until you DROP THE TABLESPACE it is associated with !!!

See

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:515222144417
I don't understand why you want to set the tablespace to read only -- looks like
you are trying to transport the tablespace but that won't work since you DON'T
have all of the files to begin with.

Step 1: make a full cold, consistent backup right now so you can at least get
back to this point if need be.

Now, if we've caught this soon enough or you are running in archivelog mode (as
you should be for a real database) and have the archives, we may be able to
recover gracefully.  Here is an example:

ops$tkyte@ORA817.US.ORACLE.COM> alter tablespace tmp_test add datafile
'/tmp/bogus.dbf' size 1m;

Tablespace altered.

ops$tkyte@ORA817.US.ORACLE.COM> alter database datafile '/tmp/bogus.dbf' offline
drop;

Database altered.

ops$tkyte@ORA817.US.ORACLE.COM> !rm -f /tmp/bogus.dbf

ops$tkyte@ORA817.US.ORACLE.COM> !ls /tmp/bogus.dbf
/tmp/bogus.dbf not found

ops$tkyte@ORA817.US.ORACLE.COM> alter tablespace tmp_test read only;
alter tablespace tmp_test read only
*
ERROR at line 1:
ORA-01230: cannot make read only - file 26 is offline
ORA-01110: data file 26: '/tmp/bogus.dbf'

So, here I am in the same situation.  What I can do, since I have no backup of
that datafile, is to create an empty one in its place:

ops$tkyte@ORA817.US.ORACLE.COM> alter database create datafile '/tmp/bogus.dbf';

Database altered.

ops$tkyte@ORA817.US.ORACLE.COM> alter tablespace tmp_test read only;
alter tablespace tmp_test read only
*
ERROR at line 1:
ORA-01230: cannot make read only - file 26 is offline
ORA-01110: data file 26: '/tmp/bogus.dbf'

ops$tkyte@ORA817.US.ORACLE.COM> alter database datafile '/tmp/bogus.dbf' online;
alter database datafile '/tmp/bogus.dbf' online
*
ERROR at line 1:
ORA-01113: file 26 needs media recovery
ORA-01110: data file 26: '/tmp/bogus.dbf'

So, we are not done yet -- it needs to be made consistent (i know, we didn't put
anything into it but it STILL needs to be consistent.  The database doesn't know
nothing was in there ever).

In this example I was on a test database with noarchive log mode but I did this
in a small enough window so that all of the needed logs were still available in
the online redo log.  You would simply:

ops$tkyte@ORA817.US.ORACLE.COM> alter database recover datafile
'/tmp/bogus.dbf';

Database altered.

ops$tkyte@ORA817.US.ORACLE.COM> alter database datafile '/tmp/bogus.dbf' online;

Database altered.

and now you are back to where you started.  You would NOT transport this
tablespace at this point, you WOULD simply resize the file to be some small size
and live with the fact that it is there.

2) this I don't understand unless you are talking about transporting in which
case, as stated above, you don't want to do this.  You need ALL of the files to
transport.  If you are missing one you cannot transport it.

Review &
      Followup

      Rating: 4
useful
      information  August 26, 2001
Reviewer:  Yu
      Shiyin  from PRC
very helpful!

      Rating: 4
Useful but
      awkward  November 25, 2001
Reviewer:  Uwe
      Schneider  from Germany
Yes, we have dropped a datafile as well (Oracle 8.1.7, archivelog), so this
article fits perfectly.

But we are very disappointed about the Oracle database product to let this
happen. Why does the DB accept a "alter database datafile '...' offline drop"
although it really KNOWS that this results in an inconsistency? If I issue a
DROP command I want to have the object dropped and not made inconsistent.

We consider that behaviour as an Oracle bug.

          Followup:

If it did not -- you could not recover from the fact that people "accidently
erase" files in noarchivelog mode.

If you do not understand the ramification of a command, I cannot understand why
you would use it...

You know, on Unix, I can as root issue "rm -rf /*" -- should it let me do it???

This command is important, it has its place, it is a necessary command.  But,
just like "drop tablespace t including contents" -- in the wrong hands, it is
dangerous.  That is why we have DBA's who know what the commands are, when to
use them.  There are many commands, that when used at the wrong time, in the
wrong circumstances -- can case damage.

Dropping the database does NOT cause inconsistencies.  It does not corrupt
anything.  It is simply the first step in cutting a tablespace out of the
database when you've lost a file and have no backups of it.  Without it -- we
would be in a bad way.

      Rating:
      5
  April 16, 2002
Reviewer:
      A reader
I think the word "DROP" in the 'Alter Database datafile <fn> offline drop'
creates all the confusion. The command is just for taking the datafile offline
so that there is no SCN resync at the time of startup. 'Alter database datafile
<fn> offline' will work only if the database is in archivelog mode. For
non-archivelog mode, we have to add the word drop to get the same thing done. It
doesn't drop anything even from the controlfile (only marks the file offline).
It would be better if the syntax is changed from 'offline drop' to 'offline
noarchive' - that will do a lot to clear the confusion on this command. Do you
agree Tom?

November 25, 2001 Doug -- Thanks for the question regarding "The
      difference between '/' and ';' - maybe some details?", version 8.1.7

      You Asked
What's the difference between '/' and ';' ?    They behave differently depending
on whether you run a script with @ or directly out of the buffer.  I'm sure
other people have run into the "invalid character" situation because the block
uses both of them.  Can you clear it up once and for all?

      and we said...
They do not behave differently depending on a script or a buffer.  They behave
the same.

In general, statements that do not include ";" in them, can use ";" to terminate
and run the command.  For example, INSERT, UPDATE, DELETE, and SELECT do not
contain embedded semi-colons.  Hence, if a command submitted to sqlplus starts
with one of those words and sqlplus encounters a line that ENDS with a
semi-colon, sqlplus will run that command.

Statements that can contain semi-colons naturally, such as CREATE OR REPLACE
PROCEDURE|PACAKGE|FUNCTION|TYPE and so on -- they will NOT be submitted when a
semi-colon is encountered at the end of a line since a ";" naturally occurs at
the end of the line within these statements.   These statements are submitted
for execution when the "/" is entered.

"/" simply "runs the buffer"

";" simply says "run this statement"

So, for example:

insert into t values ( 1 );
/
/

The ";" will run the statement, the buffer will contain the statement and the
following two "/"s will run the statement two more times.  If you tried:

insert into t values ( 1 );
;
;

it would NOT run the command (for some reason, it lists the buffer) two more
times -- there is no statement in front of the ";" to run.
Review &
      Followup

      Rating:
      4
interesting  November 25, 2001
Reviewer:
      Doug  from CT, USA
but there are cases when you have a buffer and it doesn't like ; and / in the
same clause.
Suppose I
SQL>select * From table;

no rows selected

SQL>edit

=> my semicolan is now replaced with a '/' and now if I add a a semicolan I get
this:

"afiedt.buf" 2 lines, 31 characters

  1* select * from atable;
SQL> /
select * from atable;
                           *
ERROR at line 1:
ORA-00911: invalid character

SQL> save x.sql replace;
Wrote file x.sql
SQL> @x                  => But I can run that as a script

no rows selected

no rows selected

SQL> get x
  1* select * from atable;
SQL> /
select * from atable;
                   *
ERROR at line 1:
ORA-00911: invalid character

Can you explain that particular case in the context of your answer?  Something
bothers it about having a ; and a / in a buffer immediately to run, wheras if it
is a script run with @ it does just what you say, it runs it twice.

          Followup:

the SEMI colon never gets into the buffer -- thats why.  You are putting the
semi colon in the buffer when you edit and that messes it up.

The ";" never makes it in the buffer -- you don't need to edit to see that, just
list it:

ops$tkyte@ORA815.US.ORACLE.COM> select * from t;

         X
----------
         1

ops$tkyte@ORA815.US.ORACLE.COM> l
  1* select * from t
ops$tkyte@ORA815.US.ORACLE.COM> /

         X
----------
         1

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

The semi-colon at the end of a line (on statements that support it) is specially
recognized by sqlplus as you enter it and it removes it -- submits the statement
(putting the statement minus ";" in the run buffer) and displays the results.

If you edit the buffer and force a semi-colon into it -- you don't type it in --
sqlplus won't recognize it -- it just runs the buffer which now has an invalid
character in it.

November 25, 2001 -- Thanks for the question regarding "SE or EE",
      version 8i

      You Asked
Hi,
How can we distinguish whether a db is SE or EE by querying the db?

Is there any data dictionary view which stores this information?

Thanks.

      and we said...
It'll be in the banner if it is enterprise:

ops$tkyte@ORA815.US.ORACLE.COM> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production
PL/SQL Release 8.1.5.0.0 - Production
CORE Version 8.1.3.0.0 - Production
TNS for Solaris: Version 8.1.5.0.0 - Production
NLSRTL Version 3.4.0.0.0 - Production

optionally, you can look for options that are enabled in EE but not SE

ops$tkyte@ORA815.US.ORACLE.COM> select decode( value, 'TRUE', 'EE', 'SE' )
  2  from v$option where parameter = 'Managed Standby';

DE
--
EE

November 25, 2001 Femi -- Thanks for the question regarding "Clob
      data type", version 8.1.7.2

      You Asked
Hi Tom,

I wonder if you can point me in the right direction. I would like to
create a stored procedure to polulate a table which has the CLUB data type as
part of the TABLE definition.

Hence, as I using this data type for the first time I don't won't to get it
wrong. Please note XML information will be stored.

Create table TT (user_info varchar2(8),
XML_info CLOB);

Would you recommed this table to be in it's own tablespace.

Kind regards.

      and we said...
well, to read all about lobs see:

http://technet.oracle.com/doc/oracle8i_816/appdev.816/a76940/toc.htm
The placement of the table does not really have so much to do with the fact that
it has a LOB in it or not-- it depends on the IO spread of the underlying files
in the database (you want an even number of reads/writes everywhere if
possible).  Whether this TABLE or its LOB SEGMENT (the table and lob could be in
two different tablespaces) need to be in their own tablespace will be driven
more by I/O distribution then anything else.  You can also move them later.

What might demand more of your attention is your chunk size for the lobs.
Choosen too big and you'll waste space.  Too small and you'll waste time.

Lobs are stored in chunks where a chunk is some even multiple of your databases
block size.  If you have a 32k chunksize and an 8k blocksize, we'll allocate 4
blocks/chunk and we ALWAYS allocate chunks of space.  So, if your XML is 32k or
less -- one chunk.  Put is just over 32k -- say 33k -- and it'll take 2 chunks
or 64k (and nothing but that LOB can use the remaining 31k).  So, be careful
when choosing the chunk size, look at the expected XML document size and choose
accordingly.


Subject | Article | Last Updated (East coast time)
Dynamic SQL vs Static SQL | article only | Nov 26, 2001 09:39 am
put java class in database and send it to the client with html that generate by htp.p | article only | Nov 26, 2001 09:58 am
Reading large files and binary files from webforms | article only | Nov 26, 2001 12:08 pm
Bulk insert vs sqlldr conventional load | article only | Nov 26, 2001 12:19 pm
Lot of Doubts | article only | Nov 26, 2001 12:39 pm
display the common results.... | article only | Nov 26, 2001 03:24 pm
Alias question | article only | Nov 26, 2001 09:18 pm
Definer & invoker rights | article only | Nov 27, 2001 08:25 am
Initial extent size | article only | Nov 27, 2001 09:05 am
Learning Oracle | article only | Nov 27, 2001 09:07 am
why dbms_sql and lobs | article only | Nov 27, 2001 10:22 am
Rollback segment | article only | Nov 27, 2001 12:18 pm
Electronic Signatures applied to database records | article only | Nov 27, 2001 03:12 pm
Compiled Error : DBMS_SQL.PARSE(v_CursorID, v_SQL, DBMS_SQL.NATIVE) | article only | Nov 27, 2001 08:52 pm
accessing other database from oracle | article only | Nov 28, 2001 07:26 am
Recover the Database | article only | Nov 28, 2001 08:38 am
Queries | article only | Nov 28, 2001 09:40 am
XML Parsing a CLOB | article only | Nov 28, 2001 10:13 am
Inline Function versus query | article only | Nov 28, 2001 11:41 am
Cursor Variable and Bind Variables | article only | Nov 28, 2001 02:57 pm
How do you remotely edit a package body? | article only | Nov 29, 2001 09:39 am
How to guarantee uniqueness of DBMS_Utility.Get_Hash_Value function? | article only | Nov 29, 2001 09:56 am
Oracle Java query Binding | article only | Nov 29, 2001 11:29 am
howto start oraclestartSid on NT | article only | Nov 30, 2001 12:58 pm
FGAC transparency | article only | Dec 01, 2001 03:30 pm
sending messages to all connected sessions ! | article only | Dec 02, 2001 09:45 am
row(s) 1 - 26 of 26
November 26, 2001 julien -- Thanks for the question regarding "Dynamic SQL vs Static SQL", version 8.1.7
You Asked
Hi tom,

I want to know how Oracle parse and execute both static and dynamic SQL, can you
explain to me ?

Is it better to execute stored procedure than to use parse, execute SQL ?

Thanks,

Julien.
and we said...
Both are done the same -- static sql is parsed and executed like anything else.

HOWEVER, in plsql -- there are great efficiencies to be gained by using static
sql as PLSQL will cache open cursors and reuse statements.  The loop:

ops$tkyte@ORA817.US.ORACLE.COM> declare
  2          x       number;
  3  begin
  4          for i in 1 .. 10
  5          loop
  6                  execute immediate 'select count(*) from dual d1' into x;
  7                  select count(*) into x from dual d2;
  8          end loop;
  9  end;
 10  /

PL/SQL procedure successfully completed.

can be used to demonstrate this.  If you enable sql_trace and tkprof (see
http://asktom.oracle.com/~tkyte/tkprof.html

you will find:

select count(*)
from
 dual d1

call     count       cpu    elapsed       disk      query    current      rows
------- ------  -------- ---------- ---------- ---------- ----------  --------
Parse       10      0.00       0.00          0          0          0         0
Execute     10      0.00       0.00          0          0          0         0
Fetch       10      0.00       0.01          0         10         40        10
------- ------  -------- ---------- ---------- ---------- ----------  --------
total       30      0.00       0.01          0         10         40        10

*******************************************************************************

SELECT COUNT(*)
FROM
 DUAL D2

call     count       cpu    elapsed       disk      query    current      rows
------- ------  -------- ---------- ---------- ---------- ----------  --------
Parse        1      0.00       0.00          0          0          0         0
Execute     10      0.00       0.00          0          0          0         0
Fetch       10      0.00       0.00          0         10         40        10
------- ------  -------- ---------- ---------- ---------- ----------  --------
total       21      0.00       0.00          0         10         40        10

The "static query" (d2) was parsed once and executed 10 times.  This is great
for performance and especially useful for scalability.

I like to use stored procedures whenever possible myself.
Review & Followup
Rating: 4
Dynamic SQL vs Static SQL - Why? November 26, 2001
Reviewer: Samik Nath from Japan/Tokyo
Well Tom, Query = 10 and Current = 40 here why?
Current=40 and Query = 0 why not like this?

Followup:
Samik -- please don't email me AND ask the same question here -- it is
preferrable that you just ask here as the answer can be shared with all.

because the current mode blocks are the segment header block we happen to read
more then once to do the full scan of dual and the query mode block is the one
block DUAL is on.

Apparently we are reading the segment header block 4 times to do the full scan
and we get the single block dual is on 1 time (query mode gets) when full
scanning it.

Hence 40 current mode (segment header) and 10 query mode.

November 26, 2001 Astari -- Thanks for the question regarding "put java class in database and send it to the client with html that generate by htp.p", version 8.1.7
You Asked
Dear all,
i have a system like this,
1. i have oracle 8.1.7 database server version
2. i have running oracle apache server + jservlet +jsp on my   machine
3. i have java chart class that working properly in browser

my question is, can i store my java class to my database server and put a page
like this in my oracle stored procedure :

 htp.p("<APPLET code = "Chart.class" width= "500" height= "425">
    <PARAM NAME="C0" VALUE="1">
        <PARAM NAME="C1" VALUE="2">
        <PARAM NAME="C2" VALUE="3">
        <PARAM NAME="C3" VALUE="4">
        <PARAM NAME="C4" VALUE="5">

      <PARAM NAME="C0_label" VALUE="Januari">
      <PARAM NAME="C1_label" VALUE="Februari">
      <PARAM NAME="C2_label" VALUE="Maret">
      <PARAM NAME="C3_label" VALUE="April">
      <PARAM NAME="C4_label" VALUE="Mei">

</APPLET>")

where the param name and value i generate from query that run in my database
server so i don't have to send my jdbc driver to client instead i just have to
send my chart class to client.

my question is where did i have to put my chart class in the database so the
server can send it to my client and also is it possible that chart only execute
in my client browser because from i know that oracle doesn't really support for
java class that working with awt or something like that

thx for your attention
and we said...
Sure you can do this -- you would not necessarily put the class file into the
database -- you would put it in the file system managed by the webserver itself
and let the webserver simply retrieve the file as it would ANY other file.

This really doesn't have to do with the database at all -- its a webserver
configuration..

See
http://java.sun.com/products/jdk/1.1/docs/guide/misc/applet.html
it shows how to use a codebase as well as code to tell the browser where to get
the class file from.
Review & Followup
Rating: 5
Thx Very much December 06, 2001
Reviewer: Astari Yahya
Thank you very much for your answer Tom, and specially for
the speed you answer to my question.

November 26, 2001 Yves -- Thanks for the question regarding "Reading large files and binary files from webforms", version forms 6i patch 14
You Asked
Hi Tom.

The fillowing java code is from Oracle Note 130431.1

   import java.awt.*;
   import java.io.*;
   import java.beans.*;

   import oracle.forms.ui.*;
   import oracle.forms.properties.*;
   import oracle.forms.handler.*;
   import oracle.ewt.lwAWT.*;

   public class LocalFileWrapper extends VBean
     {  public static final ID SETFILENAME = ID.registerProperty("setfilename");
        public static final ID READFILE = ID.registerProperty("readfile");

        private String fileName = null;

        public String readFile()
          {  FileReader in;
             File inputFile;
             String str = "";
             try  {  inputFile = new File(fileName);
                     in = new FileReader(inputFile);

                     char c[] = new char[(int)inputFile.length()];
                     char c1[]= new char[(int)inputFile.length()];

                     in.read(c);
                     int j=0;
                     for (int i=0;i<inputFile.length();i++)
                       {  if((int)c[i]==13)
                            ;
                          else
                            c1[j++]=c[i];
                       }
                     str = String.copyValueOf(c1,0,j);
                     in.close();
                  }
             catch (IOException e)
                  {  System.out.println("Error " );
                     e.printStackTrace();
                  }
             return str;
          }

        public Object getProperty(ID id)
          {  try
               {  if (id == READFILE)
                    {  return readFile();
                    }
                  return super.getProperty(id);
               }
             catch (Exception e)
               {  e.printStackTrace();
                  return null;
               }
          }

        public boolean setProperty(ID id, Object value)
          {  try
               {  if (id == SETFILENAME)
                    {  fileName = (String) value;
                    }

                  return super.setProperty(id, value);
               }

             catch (Exception e)
               {  e.printStackTrace();
                  return false;
               }
          }

     }

I have implemented it successfully and it works.  Unfortunately, there are two
limitations with it that I hope you can help me overcome.  I have been stuck on
this for 2 weeks.  Here we go!

1.  As it is this code only works with Text files.  I would like to change it to
work for binary files as well, but I don't know how since I am new to Java.  I
was thinking of UU encoding the binary file as I am reading it into my database
table, then when I am extracting it out of the database, I'd UU decode it.

2.  The way the code works is that it is loaded into a forms filetext and from
there it can be saved to any tables.  The filetext item is really a varchar2 and
the limit right now is 32,000 characters.  Some files I intend to load will be
about 7 MB, and I believe I will exceed this limit.  Do you see a way around
this problem (what change in the java code for example)?.  The note mentions
that the files could be read line by line with some code change.  The latter may
be a workaround is if I can save the file content as I am reading it.

I value your insight and hope you can help me with this one.
and we said...
Here is an example java program to load a blob into the database:

import java.io.*;
import java.lang.*;
import java.sql.*;
import java.util.*;
import oracle.jdbc.driver.*;

public class loadblob {

   public static void main(String[] argv) {
      if (argv.length < 4) {
         System.out.println
         ("Arguments: <ID> <name> <type> <full path to filename to load>");
         System.exit(1);
      }

      try {
         // Grab all the parameters
         long id = Long.valueOf(argv[0]).longValue();
         String name = argv[1];
         long type = Long.valueOf(argv[2]).longValue();
         FileInputStream is = new FileInputStream(argv[3]);

         // Register an oracle JDBC driver, connect, and disable auto-commit
         DriverManager.registerDriver(new OracleDriver());
         Connection conn = DriverManager.getConnection
                            ("jdbc:oracle:oci8:@oaxaca","scott","tiger");
         conn.setAutoCommit(false);

         String sql = "begin " +
                       "insert into lobtest(id,data) values (?,empty_blob()) "+
                       "return data into ?; "+
                      "end;";
         OracleCallableStatement ocs =
                     (OracleCallableStatement) conn.prepareCall(sql);
         ocs.setLong(1, id);
         ocs.registerOutParameter(2, OracleTypes.BLOB);
         ocs.executeUpdate();
         OutputStream os = (ocs.getBLOB(2)).getBinaryOutputStream();

         // Transfer the data from the file to the blob via the lob locator
         byte buffer[] = new byte[1024];
         int length;

         while ((length = is.read(buffer, 0, 1024)) != -1) {
            os.write(buffer, 0, length);
         }

         // Close up shop...
         is.close();
         os.close();
         ocs.close();
         conn.commit();
         conn.close();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}
Review & Followup
Rating: 2
Follow up November 26, 2001
Reviewer: yves from Washington, D.C.
Have you implemented this from Forms 6i?

If so, into what object is this class attached and how did you setup the bean
area?

What about the filesize limitation with the example from the Oracle note?

Followup:
I did not do this in 6i.  I haven't done anything with java and 6i.

This is just straight java code, it has no filesize limitations whatsoever, it
reads the file 1k at a time and writes it to the lob.

November 26, 2001 Allen -- Thanks for the question regarding "Bulk insert vs sqlldr conventional load", version 8.1.6.3
You Asked
Hi, Tom:
I have to insert 50,000 records every hour to a reading table while on-line user
have to perform SELECT on the reading table at the same time (using index). I
guess that means direct load is out of the question. As for Bulk insert (using
the FORALL) vs SQLLDR conventional load, which one is better (performance and
resource).
Thanks
and we said...
SQLLDR conventional path loader.

It does array inserts (like a forall)

and you don't have to write any code (my favorite option)
Review & Followup
Rating: 4
November 26, 2001
Reviewer: Fabio from Porto Alegre, RS BRASIL

November 26, 2001 Venkatewara Reddy -- Thanks for the question regarding "Lot of Doubts", version 8.1.5
You Asked
Dear Tom ,
Thanks for answering my previous questions. Here I have some questions which is
i am confusing regarding standby database and others.

1. How to create standby database from primary database to standby database
  with in the same organisation with different systems. Can I Map network drive
from other system to my primary system for transfering all data files etc is it
correct??.
2. After creating standby database from primary system archive log files to
applyed to standy database.
  For ex:
   I am using database "psi1" this is my primary. I would like to have
standby database for "psi1" in another system.When ever "PSI1" generated
archive logs that should apply to the standby also.

3.Which is the best method for recovery mode whether  Manual Recovery Mode or
Managed Recovery Mode

4. When I query v$datafile, following results appered. It means USERS01.DBF has
corrupt??. How to recover it is corrupt. I am not understand
URRECOVERABLE_CHANGE#=1437014. What it means.

Query is
HRMS@8.1.5>
Wrote file afiedt.buf

  1* SELECT ts#, UNRECOVERABLE_TIME,SUBSTR(NAME,1,35),CHECKPOINT_TIME FROM
V$DATAFILE
HRMS@8.1.5>/

  TS# UNRECOVER SUBSTR(NAME,1,35)            CHECKPOIN  UNRECOVERABLE_CHANGE#
---------- --------- -------------------------------------------------        0
         E:\ORACLE\ORADATA\PSI1\SYSTEM01.DBF 17-NOV-01    0
         1 08-SEP-01 E:\ORACLE\ORADATA\PSI1\USERS01.DBF  17-NOV-01    1437014
         2           E:\ORACLE\ORADATA\PSI1\RBS01.DBF    17-NOV-01    0
         3           E:\ORACLE\ORADATA\PSI1\TEMP01.DBF   17-NOV-01    0
         4           E:\ORACLE\ORADATA\PSI1\OEMREP01.DBF 17-NOV-01    0
         5           E:\ORACLE\ORADATA\PSI1\INDX01.DBF   17-NOV-01    0
         6           E:\ORACLE\ORADATA\PSI1\HRMS_TBS.DBF 17-NOV-01    0
         7           E:\ORACLE\ORADATA\PSI1\WEB_TBS.DBF  17-NOV-01    0
         9           E:\ORACLE\ORADATA\PSI1\AMPS.DBF     17-NOV-01    0
        10           E:\ORACLE\ORADATA\PSI1\ERPV22.DBF   17-NOV-01    0
        11           E:\ORACLE\ORADATA\PSI1\HRMSFOX.DBF  17-NOV-01    0

11 rows selected.

5. I two systems which installed oracle on both systems One is 8.1.5 standard
production and one more is 8.1.6 standard is kept separately. I would like to
create standby on 8.1.6 machine in separate drive because space constraint. Is
it possible. If yes what are all the parameters I should give init.ora for
standby in 8.1.6 system.

6.LOCK_NAME_SPACE
 While initializing this paramater what value I should give and from where I
should pickup, How can I generate lock name using DLM.
7. In Oraceld Database "autocommit" by default off. In this state I have
inserted and updated some record. After insert I issed quit to exit sql*plus
session. So my previous records has been commited .Be cause "exit" implicityly
commit the changes then it will exit.
Next I issued the following statements

SQL>SET AUTOCOMMIT OFF
SQL>Insert into t1 values ('abcd',123);
SQL> 1 Row Inserted
SQL>EXIT

Again start SQL session, When I issue
SQL> Select * from t1;
no rows selected
SQL>

What is the reason exit is not commit the changes.

Thanks in advance.

Reddy
and we said...
Have you read
http://technet.oracle.com/doc/oracle8i_816/server.816/a76995/toc.htm
1) move them (the datafiles) initially anyway you see fit -- network drive, ftp,
whatever.  It does not matter to us

2) read about the managed standby database in the above mentioned documentation.
http://technet.oracle.com/doc/oracle8i_816/server.816/a76995/standbyc.htm#29726
3) You'll have to answer this -- they both work, you need to determine which is
best for you.  Do you want to script it and do it yourself or do you want it
just to happen.

4) not knowing the conditions of your database, or even if this is the standy or
not, i cannot comment.

5) the standby's should be of the same release as different features and log
file formats are supported by each.  815 to 815 and 816 to 816.

6) you only need set this is standby and primary are on the same machine (sort
of a pointless configuration for a standby other then for testing the setup of
this feature -- you do NOT run a standby on the primary server, doesn't make
sense).  Just use unique names like "stby"...

7) "autocommit" is a feature of sqlplus only (oracle doesn't support the concept
of an autocommit).  With autocommit on in sqlplus, each statement you submit is
committed.  If you have autocommit on then:

insert into t values(1);
insert into t values(2);

would have a commit done after EACH insert.  When you exit sqlplus, it commits
all outstanding work regardless of the setting of autocommit (autocommit isn't
about exiting, its about whether each STATEMENT is committed right away)

I don't know what happened in your case - perhaps T1 is a global temporary table
-- but the results are committed upon exit:

ops$tkyte@ORA815.US.ORACLE.COM> create table t ( x int );
Table created.

ops$tkyte@ORA815.US.ORACLE.COM> set autocommit OFF
ops$tkyte@ORA815.US.ORACLE.COM> insert into t values ( 1 );
1 row created.

ops$tkyte@ORA815.US.ORACLE.COM> EXIT

Disconnected from Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production
With the Partitioning and Java options
PL/SQL Release 8.1.5.0.0 - Production

$ sqlplus /

SQL*Plus: Release 8.1.5.0.0 - Production on Sun Nov 25 12:28:13 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to:
Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production
With the Partitioning and Java options
PL/SQL Release 8.1.5.0.0 - Production

ops$tkyte@ORA815.US.ORACLE.COM> select * from t;

         X
----------
         1

ops$tkyte@ORA815.US.ORACLE.COM>
Review & Followup
Rating: 3
Lot of doubts November 26, 2001
Reviewer: Reddy R.V from Bangalore, India
Thanks for your reply.
For questoin 4, it is not a standby database. Production database on 8.1.5 os
winnt4.0. If it is corrupt how can I recover. What are all the guide lines to
folow.

Thanks
Reddy

Followup:
It is not corrupt.  That is simply the time of the last operation you performed
that was unrecoverable (like a "create table t nologging ... as select" or
create index i unrecoverable).

Backup the datafile and you'll be OK.

November 26, 2001 vishnu -- Thanks for the question regarding "display the common results....", version 8i
You Asked
Hi Tom ,
Here is my question and i am sure you will give me the solution like before....

i have a table called "results"...
and i have name,cource1,cource2,cource3......cource10 as fields..

and the data in the table as below
name    cource1,cource2,cource3......cource10
tome      yes                          yes
vis              yes
ram       yes
jam                       yes
tome             yes
ram              yes
jag       yes
jag              yes
jag                       yes           yes
tome                                    yes
vis       yes
mary            yes       yes
mary                                    yes

(empty fields are null fields)

I want an out put like below..it should search all the rows and if "yes" is
there in any "cource" it should return "yes" and otherwise null or "no " for
that particular "name" in the final out put.

Ex in the above

name    cource1,cource2,cource3......cource10
tome     yes     yes      no          yes
vis      yes     yes      no           no
ram      yes      yes     no           no
jam       no      no      yes          no
jag       yes     yes     yes          yes
mary     no        yes    yes           yes

Pl advise me ...
Thanks
vis
and we said...
ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( name varchar2(5), c1
varchar2(3), c2 varchar2(3) );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'tom', 'yes', null );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'tom', null, 'yes' );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'bob', 'yes', null );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'bill', null, 'yes' );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select name, nvl(max(c1),'no'),
nvl(max(c2),'no')
  2    from t
  3   group by name;

NAME                           NVL NVL
------------------------------ --- ---
bill                           no  yes
bob                            yes no
tom                            yes yes
Review & Followup
Rating: 4
IT'S WONDER FULL.... November 26, 2001
Reviewer: vis from USA
Hi Tom ,
It's Wonder full,But when i tested the query and " no " value is not getting
pulled ..Am i missing any thing
Vis

Followup:
well, what is getting pulled then.

do this for me:

SQL> set null (null)
SQL> <run the query here>

and let me see the output.

Rating: 3
Set to null...... November 26, 2001
Reviewer: vis from USA
The out put is showing up like below and "no" is not showing up ..pl help

bill                               yes
bob                            yes
tom                            yes yes

Followup:
I have a feeling that you do not have NULLS in there -- must have spaces.  If
you would have:

SQL> set null (null)
SQL> <run the query here>

I could have confirmed that.....

try this instead then:

ops$tkyte@ORA817DEV.US.ORACLE.COM> update t set c1 = '   ' where c1 is null;
2 rows updated.

ops$tkyte@ORA817DEV.US.ORACLE.COM> update t set c2 = '   ' where c2 is null;
2 rows updated.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select name,
  2             max(decode(c1,'yes','yes','no')),
  3             max(decode(c2,'yes','yes','no'))
  4    from t
  5   group by name
  6  /

NAME                           MAX MAX
------------------------------ --- ---
bill                           no  yes
bob                            yes no
tom                            yes yes

Rating: 5
Handy November 26, 2001
Reviewer: Jim
Well I'll be... never knew about the SET NULL [somethingelse]

November 26, 2001 Cesar -- Thanks for the question regarding "Alias question", version 8.1.6
You Asked
Hi Tom, I have this view:

View: today

Name                            Null?    Type
------------------------------- -------- ----
Username                        NOT NULL VARCHAR2(30)
In                                       VARCHAR2(8)
Lunch                                    VARCHAR2(8)
Return                                   VARCHAR2(8)
Out                                      VARCHAR2(8)

Why doesn't work the next query?

SQL> select * from today
  2  where username = 'JSM';
where username = 'JSM'
      *
ERROR at line 2:
ORA-00904: invalid column name

But this query is Ok:

SQL> select * from today
  2  where "Username" = 'JSM';

Username                       In       Lunch    Return   Out
------------------------------ -------- -------- -------- --------
JSM                            08:29:16 14:05:57

Thanks!
and we said...
The table was created with quoted identifiers.  Whatever tool you are using
issues:

create table today
( "Username"  varchar2(30) not null,
   ...

)

quoted identifiers allow you to preserve case, use otherwise illegal characters
and so on.  the downside is -- you must always quotes your identifers after that.
November 27, 2001 Balasubramanian -- Thanks for the question regarding "Definer & invoker rights", version 8.1.7
You Asked
Hi Tom,

Please explaing the following problem.

Testuser:
---------
    create table test1 (
      f1  varchar2 (50))
    /

    create or replace procedure p1
    as
    begin
       insert into test1 values ( 'Procedure by TESTUSER' ) ;
    end ;
    /

    create or replace procedure m1
    authid current_user
    as
    begin
       p1 ;
    end ;
    /

    grant execute on m1 to scott
    /

Scott:
------
    create table test1 (
      f1  varchar2 (50))
    /

    create or replace procedure p1
    as
    begin
       insert into test1 values ( 'Procedure by SCOTT' ) ;
    end ;
    /

Now i excuted the following PL/SQL block in the user SCOTT

    begin
        Testuser.m1 ;
        commit ;
    end ;

if i select value from test1 from scott, i don't get any records.
But i excuted from testuser, i get the records as follows:

    scott> select * from test1 ;

    no rows selected

    testuser> select * from test1 ;

    f1
    ---------------------
    procedure by TESTUSER

from this example, i understand that this definer & invoker rights is only for
tables. How i can simulate this for procedures. for example if i execute m1 from
scott, this procedure should call p1 of scott not the testuser.

Thanks,
Balasubramanian.R
and we said...
If you want the entire story -- you need to get my book. I go into this in great
detail.

Invokers rights procedures run much like a Pro*C/Java/VB application would
OUTSIDE of the database.

Lets use Pro*c as an example.

When you compile and link your C application -- the functions that will be
invoked are determined right then and there.  No matter WHO runs the program --
"function f" is "function f" -- the same function f.

Now, if that Pro*C application asks you for your username and password and logs
in as you and then does:

   exec sql select x into :y from t;

The reference to T will be determined based on YOUR account.  If I run this
application -- the same function F will be called, but table T will be resolved
with respect to MY schema.

So, the static references to functions/procedures are static, they are figured
out at runtime.  There is no difference there -- the program is a program is a
program and just like any other environment, what functions get called is fixed
at compile/link time.  The database objects referenced -- they are dynamically
resolved at runtime.

So, how can we do this so that a different procedure gets called depending on
the user running the main procedure?  The key is the last sentence in the
paragram above -- "they are dynamically resolved at runtime".  The answer is
"use dynamic SQL".

Consider:

ops$tkyte@ORA817DEV.US.ORACLE.COM> grant connect, resource to a identified by a;
Grant succeeded.

ops$tkyte@ORA817DEV.US.ORACLE.COM> grant connect, resource to b identified by b;
Grant succeeded.

ops$tkyte@ORA817DEV.US.ORACLE.COM> grant connect, resource to c identified by c;
Grant succeeded.

ops$tkyte@ORA817DEV.US.ORACLE.COM> @connect a/a

a@ORA817DEV.US.ORACLE.COM> create procedure p
  2  as
  3  begin
  4      dbms_output.put_line( 'I am procedure p created by user A' );
  5  end;
  6  /
Procedure created.

a@ORA817DEV.US.ORACLE.COM> create procedure ir_routine( p_static in boolean
default TRUE )
  2  authid current_user
  3  as
  4  begin
  5      if ( p_static )
  6      then
  7          dbms_output.put_line( 'static invocation' );
  8          p;
  9      else
 10          dbms_output.put_line( 'dynamic invocation' );
 11          execute immediate 'begin p; end;';
 12      end if;
 13  end;
 14  /
Procedure created.

a@ORA817DEV.US.ORACLE.COM> grant execute on ir_routine to public
  2  /
Grant succeeded.

a@ORA817DEV.US.ORACLE.COM> @connect b/b

b@ORA817DEV.US.ORACLE.COM> create procedure p
  2  as
  3  begin
  4      dbms_output.put_line( 'I am procedure p created by user B' );
  5  end;
  6  /
Procedure created.

b@ORA817DEV.US.ORACLE.COM> exec a.ir_routine( TRUE );
static invocation
I am procedure p created by user A

PL/SQL procedure successfully completed.

b@ORA817DEV.US.ORACLE.COM> exec a.ir_routine( FALSE );
dynamic invocation
I am procedure p created by user B

PL/SQL procedure successfully completed.

b@ORA817DEV.US.ORACLE.COM> @connect c/c

c@ORA817DEV.US.ORACLE.COM> create procedure p
  2  as
  3  begin
  4      dbms_output.put_line( 'I am procedure p created by user c' );
  5  end;
  6  /
Procedure created.

c@ORA817DEV.US.ORACLE.COM> exec a.ir_routine( TRUE );
static invocation
I am procedure p created by user A

PL/SQL procedure successfully completed.

c@ORA817DEV.US.ORACLE.COM> exec a.ir_routine( FALSE );
dynamic invocation
I am procedure p created by user c

Now, and this is important, before you go crazy and do everything
dynamically -- consider the performance impact (PLEASE).  Use this sparingly,
only when necessary and never in a routine that might be executed TONS.

Invokers rights routines are great for generic utilities (to dump arbitrary
queries to a flat file using dbms_sql for example).  They are NOT intended to be
the way to write large applications.  Use them sparingly, else you'll lose lots
of the benefits of shared SQL and if you dynamically execute everything --
you'll be parsing tons of times and thats expensive.

PL/SQL procedure successfully completed.
Review & Followup
Rating: 5
Good ! November 27, 2001
Reviewer: Andre Whittick Nasser from Rio de Janeiro, Brazil
Tom,

This difference between what is dynamic and static is a topic I continually have
to explain to people. You have put it in a super appropriate way...

Congrats !

Rating: 5
Thanks November 27, 2001
Reviewer: Rengasamy Balasubramanian from Singapore
Thanks for your quick response.

Bala

November 27, 2001 -- Thanks for the question regarding "Initial extent size", version 8i
You Asked
Hi,

 Can we alter the initial extent of a dictionary managed tablespace (temporary &
permanent)?

 The Oracle documentation states
"Restriction: You cannot specify INITIAL in an ALTER statement. "

 Pl. explain, why we cannot alter the INITIAL.

Thanks.
and we said...
No, you cannot alter an initial.  If you think about it -- it makes sense.

The initial is ALREADY allocated.  Its there, its a fixed size.  Just like you
cannot grow and shrink in size allocated next extents, you cannot modify the
initial.  You would have to recreate the object (using alter table MOVE for
example) in order to modify the initial extent.

Temporary tables do no have an initial extent:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create global temporary table t ( x int )
storage (initial 1m );
create global temporary table t ( x int ) storage (initial 1m )
*
ERROR at line 1:
ORA-14451: unsupported feature with temporary table

they are dynamically allocated in the tablespace assigned to the current schema
that uses them -- they'll get their initial extent per session and will size it
based on the temporary tablespace they happen to be using in that session.
Review & Followup
Rating: 2
Is it possible to alter INITIAL of temporary tablespace? November 25, 2001
Reviewer: A reader
In that case, can we alter the INITIAL of a temporary tablespace.

Followup:
If it is not locally managed, sure.

ops$tkyte@ORA815.US.ORACLE.COM> alter tablespace temp default storage ( initial
1m );

Tablespace altered.

ops$tkyte@ORA815.US.ORACLE.COM> alter tablespace temp default storage ( initial
64k );

Tablespace altered.

Rating: 4
Tom, following is one way I had tried ... November 27, 2001
Reviewer: Sudhir
alter table ABC deallocate unused keep 1MB;

if there is no data it will actually change initial extent size to 1MB, correct?
I remember trying this on one of my table with 1GB initial extent and it was
unused for long time.

Thanks

Followup:
Excellent point -- didn't think of that.  We can shrink initial down to the size
of the HWM (high water mark) -- so if you've overallocated that initial and
NEVER used it -- we can release it.  How much you can release depends on

o the HWM -- space that contained data at SOME time in the past cannot be
releases

o the size of the extents in a locally managed tablespace -- initial will never
go below the uniform size of course.

Here is an example with a dictionary managed tablespace and a locally managed
one:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x int )
  2  tablespace system
  3  storage ( initial 2m );
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t select user_id from all_users;
23 rows created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select initial_extent
  2    from user_tables
  3   where table_name = 'T';

INITIAL_EXTENT
--------------
       2097152

ops$tkyte@ORA817DEV.US.ORACLE.COM> select extent_id, bytes
  2    from user_extents
  3   where segment_name = 'T';

 EXTENT_ID      BYTES
---------- ----------
         0    2129920

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table T deallocate unused keep 1M;
Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select initial_extent
  2    from user_tables
  3   where table_name = 'T';

INITIAL_EXTENT
--------------
       1064960

ops$tkyte@ORA817DEV.US.ORACLE.COM> select extent_id, bytes
  2    from user_extents
  3   where segment_name = 'T';

 EXTENT_ID      BYTES
---------- ----------
         0    1064960

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table T deallocate unused keep 100k;
Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select initial_extent
  2    from user_tables
  3   where table_name = 'T';

INITIAL_EXTENT
--------------
        122880

ops$tkyte@ORA817DEV.US.ORACLE.COM> select extent_id, bytes
  2    from user_extents
  3   where segment_name = 'T';

 EXTENT_ID      BYTES
---------- ----------
         0     122880

so, that shows we were able to shrink those down without moving/rebuilding --
I never tried to go below the HWM, now we'll use a LMT with 512k uniform
extents

ops$tkyte@ORA817DEV.US.ORACLE.COM> drop table t;
Table dropped.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x int )
  2  tablespace users
  3  storage ( initial 2m );
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t select user_id from all_users;
23 rows created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select initial_extent
  2    from user_tables
  3   where table_name = 'T';

INITIAL_EXTENT
--------------
       2097152

ops$tkyte@ORA817DEV.US.ORACLE.COM> select extent_id, bytes
  2    from user_extents
  3   where segment_name = 'T';

 EXTENT_ID      BYTES
---------- ----------
         0     524288
         1     524288
         2     524288
         3     524288

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table T deallocate unused keep 1M;
Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select initial_extent
  2    from user_tables
  3   where table_name = 'T';

INITIAL_EXTENT
--------------
       1572864

ops$tkyte@ORA817DEV.US.ORACLE.COM> select extent_id, bytes
  2    from user_extents
  3   where segment_name = 'T';

 EXTENT_ID      BYTES
---------- ----------
         0     524288
         1     524288
         2     524288

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table T deallocate unused keep 960k;
Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select initial_extent
  2    from user_tables
  3   where table_name = 'T';

INITIAL_EXTENT
--------------
       1048576

ops$tkyte@ORA817DEV.US.ORACLE.COM> select extent_id, bytes
  2    from user_extents
  3   where segment_name = 'T';

 EXTENT_ID      BYTES
---------- ----------
         0     524288
         1     524288

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table T deallocate unused keep 100k;
Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select initial_extent
  2    from user_tables
  3   where table_name = 'T';

INITIAL_EXTENT
--------------
        524288

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select extent_id, bytes
  2    from user_extents
  3   where segment_name = 'T';

 EXTENT_ID      BYTES
---------- ----------
         0     524288

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

Rating: 4
November 27, 2001
Reviewer: Tianhua Wu from Atlanta, Ga
In 8i, there is a move command, you can change a lot of things you can not do
before 8i.  However it does rebuild the table and require enough free space
available.

November 27, 2001 arunima -- Thanks for the question regarding "Learning Oracle", version 8.1.6
You Asked
Tom,

I am a beginner. Can you guide me to what is the best resource for learning
PL/SQL and understanding the basic oracle administration.

Thanks a lot.
and we said...
I would read this manual from start to finish:
http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/toc.htm
if you remember 1/4 of that, you'll already know 2x what most people do.  I find
that to be an excellent document.
Review & Followup
Rating: 3
Learning Oracle November 26, 2001
Reviewer: arunima from New York , USA
That was a quick response. I would read this. But I feel this document may not
give me much hands on experience.

Can you suggest me something for improving the hands on skill on PL/SQL and
Oracle administration.

Thanks a lot.

Followup:
search for

feurstein oracle

on www.amazon.com -- i understand his books on PLSQL are well regarded with lots
of examples to work through.

Rating: 4
excellent advice November 26, 2001
Reviewer: A reader from USA
There is no shortcut way to becoming proficient at Oracle. Look for a beginner's
book on Oracle if you only want the tip of the iceberg. See Amazon for reader
reviews.

Rating: 5
re: shortcut November 26, 2001
Reviewer: Mark A. Williams from Indianapolis, IN USA
>There is no shortcut way to becoming proficient at Oracle...

Well, rumor has it that Larry is going to announce a new product at OpenWorld -
Oracle Internal.  It's basically a chip (Sparc of course, running jvm 1.3.1)
that is inserted into your cranium.  It allows instant access to all things
Oracle (via a wireless interface).  Fortunately Oracle have moved away from
Power Unit pricing.  Otherwise, you would have to translate your brain power
into the appropriate MHz leading to disproportinate licensing costs.  Remember
to shave your head before you go.

You are right of course.  Just trying to take a break from studying for the 9i
OCP upgrade exam that is going to be offered at OpenWorld...

Rating: 5
Export/Import ? November 26, 2001
Reviewer: Steve
I'll check out the link recommended by Tom,
but I would much rather
imp sys/canuguessit fromuser=tomkyte touser=me

Rating: 5
November 27, 2001
Reviewer: A reader
Hi, Tom.

I find this document exellent too. You have recommended me to read this early.
But now I am looking for the document for Oracle9i. Can you recommend me one?
I cannot find Oracle9i concepts on Oracle.com

Followup:
http://otn.oracle.com/
-> documentation -> Oracle9i  Database -> Oracle9i Database Online
Documentation

That will get you to all of the oracle9i docs, click on "list all of the books"
and you'll get to:

http://download-west.oracle.com/otndoc/oracle9i/901_doc/nav/docindex.htm#index-CON
...

      Rating:
      4
  November 27, 2001
Reviewer:
      A reader
What is the best way to prepare for 9i upgrade exam?

      Rating: 5
excellent
      advice  November 27, 2001
Reviewer:  an
       from Wilmington, DE

      Rating: 5
Make the right
      choice...  November 27, 2001
Reviewer:  Sven
      Bleckwedel  from Santos, SP Brazil
Arunima,

Do a favor to yourself, and acquire Tom´s Book.  It contains a lot of useful
information.  I readed some Oracle books (from Oracle Press and anothers), but
like Tom´s book I had not found equal.

Sven

      Rating: 5
The Best
      Way...  November 27, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
I'll give an obvious, though not mentioned suggestion: the Oracle University
courses will give theory and practice (trough labs).

I know they're expensive -- around US$1000 each -- but if you think of
cost/benefit, they're the best you can get. It seems you should pay attention to
the Development track. You can just begin by taking two courses:

- Introduction to Oracle9i: SQL
- Introduction to Oracle9i: PL/SQL

If you are more ambitious, you can consider getting certified, which is a BIG
market differential. A can affirm that myself.

Take a look at:

Education:
http://www.oracle.com/education
Certification:
http://www.oracle.com/education/certification
Hoping to help...

      Rating: 5
Another
      Learning Option  November 27, 2001
Reviewer:
      Chip Briggs  from Denver CO USA
The Oracle Learning Network has excellent online courses:

http://www.oracle.com/education/oln/
The Oracle9i OCP Upgrade modules are excellent preparation
for the Oracle9i DBA Upgrade exam.

The Oracle Press PL/SQL books by Scott Urman and Joe Trezzo
are great resources (as well as the O'Reilly books by
Steve Feuerstein).  If possible, consider attending a
local Oracle Users group and the IOUG-A Live conference:

http://www.ioug.org/
The Oracle Developer Tools User Group has a web site:

http://www.odtug.org/
I like buying technical books (30% to 40% discount) at

http://www.bookpool.com/

November 27, 2001
      sushant -- Thanks for the question
      regarding "why dbms_sql and lobs", version 8.1.5

      You Asked
i want to know what is the practical significance of the
dbms_sql package (apart from using ddl commands in plsql blocks)
but that can be easily acheived with native dynamic sql(executive
immediate). moreover u need the privilege create any table for
creating tables with the dbms_sql package

  why do we need to use lobs. what is the advantage of storing any graphic or
textual data of a very large size inside the database rather than just keeping
it as a file in a directory.wont retrieving such large data from the database be
more slower than having it just in the normal operating system directory

      and we said...
Well, in order to fully see the difference I'm going to refer you to my book.
There I have a 40 page chapter that compares and contrasts DBMS_SQL to NDS and
points out when you would use each.  Here is a short list of when you might use
dbms_sql over NDS:

o you don't know the number of SELECT list items at compile time.  NDS demands
you know the number and types of output variables at PLSQL compilation time,
DBMS_SQL does not

o you don't know the number of INPUT items at compile time.  NDS demands you
know the number and types of bind variables at compile time, DBMS_SQL does not

o you will be dynamically executing the SAME statement
dozens/hundreds/thousands/ or more times.  DBMS_SQL allows you to parse the
query ONCE and execute it over and over and over.  NDS does not -- it will
parse/execute/close each and every time, reducing performace and scalability
greatly.

You do NOT need the "create any table" priv for DBMS_SQL -- you need the SAME
set of privs you do with NDS (they both just execute SQL after all -- neither
needs more or less privs then the other).  You do however need CREATE TABLE (not
ANY) granted directly to you -- see:

http://osi.oracle.com/~tkyte/Misc/RolesAndProcedures.html
for some details (or my chapter on Invokers/Definers rights where I go into
great detail on this topic)

As for lobs -- consider this:

o if stored outside the database, you need to make it so that you keep the file
system consistent with the database.  The file system has no redo logs, no
transactions -- it is very hard to keep them consistent.

o what happens if someone "accidently" erases a file in the operating system.
You might not discover that for weeks -- opps, there goes that file.
referential integrity in the database prevents this.

o I backup my database -- i've backed up my stuff (if my stuff is in the
database).

o no, reading the image out of the database does not have to be any slower then
the filesystem -- the retrieval speeds approach that (or even exceed) that of
the filesystem.  They are stored very effeciently -- different from rows and
columns in a structured table are.

o in my database I have tons of security options. I can audit who has seen what,
I can restrict access procedurally, I can use builtin functions like fine
grained access control, etc etc etc.  In the filesystem -- well I don't have
many options there...

o databases tend to be centralized resources that any client can connect to.
File systems are not.  If I'm already connected to the database over net8 or
http or iiop -- why do I need to bother with a file system.  The database is
accessible everywhere, the file system is not as acceessible.

Review &
      Followup

      Rating: 5
About your book
      !  November 27, 2001
Reviewer:  Andre Whittick
      Nasser  from Rio de Janeiro, Brazil
I have taken a look at your book. Excellent piece of work ! Also, I have seen
what you meant by saying in this site it is not exectly focused at
administration.

Even so, great book, even from my hands-on DBA perpective.

Then you suggest reading Lewis' book, which by the way is sold in a package
together with yours at Amazon. Cool combination !

What I would like to ask you, and I did not have this perception, is:

1) Does your book cover 9i's new features ?
2) If not, do you plan a new relase ?
3) If so, when ?

Thanks !

          Followup:

1) no it doesn't, its upto 817
2) I'm thinking about it -- its a TON of work
3) ....

November 27, 2001 Fabio -- Thanks for the question regarding
      "Rollback segment", version 8.0.5

      You Asked
Hello Tom,

sometimes I need to transfer data from database A to database B. I do it by
using a database link, since data I'm trying to move is conditional. I'm not
sure if SQLPlus copy command is available in this version. In case it's
available, which one is the best way?

Database B has 6 rollback segments as follow:

select segment_name, segment_id, file_id, initial_extent, next_extent,
min_extents, max_extents, pct_increase, status
from dba_rollback_segs;

SEGMENT_NAME SEGMENT_ID FILE_ID INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS
MAX_EXTENTS    PCT_INCREASE STATUS
SYSTEM    0    1    53248    53248    2    249    0    ONLINE
RBS0    1    2    524288    524288    2    249    0    ONLINE
RBS1    2    2    524288    524288    2    249    0    ONLINE
RBS2    3    2    524288    524288    2    249    0    ONLINE
RBS3    4    2    524288    524288    2    249    0    ONLINE
RBS4    5    2    524288    524288    2    249    0    ONLINE

These rollback segs are enough to handle the typical transactions, but when I
try to move data by doing

insert into t1@b
select * from t1
where t1.c1 = 2;

it gives me ORA-01562 error.

Can I create a big rollback segment, say RBATCH and set the transaction to use
it (something like SET TRANSACTION USE ROLLBACK SEGMENT RBATCH)?

Thanks,

Fabio

      and we said...
I did not try this in 8.0, but in 8i I was able to do this by executing the set
transaction on the remote site:

ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2      cursor_name number := dbms_sql.open_cursor@ora815.us.oracle.com;
  3      ignore      number;
  4  begin
  5      dbms_sql.parse@ora815.us.oracle.com( cursor_name,
  6              'set transaction use rollback segment rbs_04',
  7               dbms_sql.native );
  8
  9      ignore := dbms_sql.execute@ora815.us.oracle.com(cursor_name);
 10      dbms_sql.close_cursor@ora815.us.oracle.com( cursor_name );
 11      delete from emp@ora815.us.oracle.com;
 12      insert into emp@ora815.us.oracle.com
 13      select * from emp;
 14  end;
 15  /

PL/SQL procedure successfully completed.

Review &
      Followup

      Rating:
      4
  November 27, 2001
Reviewer:  Fabio
       from Porto Alegre, RS Brasil
I tried to do this in 8.0 and got the messages below:

SQL> conn systemakers@a
Enter password: *****
Connected.
SQL> declare
  2        cursor_name number := dbms_sql.open_cursor@b;
  3        ignore      number;
  4  begin
  5       dbms_sql.parse@b( cursor_name,
  6               'set transaction use rollback segment rbs4',
  7                dbms_sql.native );
  8
  9       ignore := dbms_sql.execute@b(cursor_name);
 10       dbms_sql.close_cursor@b( cursor_name );
 11       delete from emp@b;
 12       insert into emp@b
 13       select * from emp;
 14  end;
 15  /
declare
*
ERROR at line 1:
ORA-04052: error occurred when looking up remote object SYSTEMAKERS.DBMS_SQL@B
ORA-00604: error occurred at recursive SQL level 1
ORA-12514: Message 12514 not found;  product=RDBMS; facility=ORA

What is wrong?

          Followup:

your database link isn't setup properly.

> oerr ora 12514
12514, 00000, "TNS:listener could not resolve SERVICE_NAME given in connect
descriptor"
// *Cause:  The SERVICE_NAME in the CONNECT_DATA was not found in the listener's
tables.
// *Action: Check to make sure that the SERVICE_NAME specified is correct.
// *Comment: This error will be returned if the database instance has not
// registered with the listener; the instance may need to be started.

November 27, 2001 Ed -- Thanks for the question regarding
      "Electronic Signatures applied to database records", version 8.0.6

      You Asked
I am trying to determine if it is possible to use an electronic
signature within a database structure.  Specifically, can an
electronic signature be applied to a row of data or better a discrete
series of rows of data?  If so, how would you impliment this?

I am currently working with Oracle 8.0.6 in a production environment,
but am also using Oracle 8.1.7 and 9i in a testing environment.

Any help would be appreciated.

      and we said...
Electronic siguatures can be applied to any bit of data -- all it is is a hash
of the

o source data
o your certificate

the signature can then be used to prove that

o you signed it, just take the data + certificate and hash it, compare to the
prexisting hash and that shows YOU signed it.

o the data did not change since you signed it -- if it did, taking the
data+certificate will result in a different hash.

the signature therefore is just an ATTRIBUTE of data.  If you wanted to sign
"many rows", you might have a table like this:

create table some_data ( x int, y date, z varchar2(255), fk_to_signature int );

create table signatures ( signature_id number primary key,
                          signature raw(2000) );

If you wanted to "sign" a set of rows, you would fetch them out -- send them and
the certificate to the "signer", get the hash back, generate a primary key and
insert the signature and update the foreign key.  the rows are now "signed".

If you modify them, you can tell.   if you want to prove that person X signed
them, you can.

Its done outside the database,unless your signing software is in java in which
case you could possibly load it into the database as well (in 8i and up -- not
8.0)

Review &
      Followup

      Rating:
      5
  November 27, 2001
Reviewer:
      A reader

      Rating: 3
How about an
      Example  November 27, 2001
Reviewer:
      Rsanjay  from NJ,USA
Tom,
  It looks pretty simple but a shiort and simple example would really clear
everything. An example as U always do - Create table t
select * from all_objects ..

Thanks for all the help

          Followup:

I don't have any "electronic signature" software.

It would involve you retrieving the data you wanted to "sign".  Signing the data
using this software.  Putting the signature into the database along with the
data.

Its not something I can simply demonstrate in sqlplus...

November 27, 2001 Dongt -- Thanks for the question regarding
      "Compiled Error : DBMS_SQL.PARSE(v_CursorID, v_SQL, DBMS_SQL.NATIVE)",
      version 8.0.6

      You Asked
I've had a small procedure using DBMS_SQL which worked ok (in SQL).
When I compiled the same procedure in Oracle Form 5.0, it compiled with error :

Error 512 at line 28,column 47
Implementation Restriction: 'DBMS_SQL.NATIVE': Cannot directly access remote
package variable or cursor.

Here's the statement :
  DBMS_SQL.PARSE(v_CursorID, v_SQL, DBMS_SQL.NATIVE);

Your help is very appreciated,
dtphan@lasd.org

I've learned more from your columns than from my Oracle trainning !

      and we said...
That means that forms cannot access a remote package variable value --
dbms_sql.native is a constant defined in the package in the database.

The way dbms_sql works -- it would be VERY chatty to have it in the form -- lots
and lots of round trips.

Consider using the built in EXEC_SQL (i believe forms 5.0 had that).  That is
the client side version of DBMS_SQL.

Else, replace dbms_sql.native with 1.

Thats the value of it:

 -------------
  --  CONSTANTS
  --
  v6 constant integer := 0;
  native constant integer := 1;
  v7 constant integer := 2;
  --
  --------------

from the package and won't change.
Review &
      Followup

      Rating: 5
"Compiled Error
      : DBMS_SQL.PARSE(v_CursorID, v_SQL,
      DBMS_SQL.NATIVE)"  November 28, 2001
Reviewer:
      Dongt Phan  from LA, CA
Yes Sir !
I changed
"DBMS_SQL.PARSE(v_CursorID, v_SQL, DBMS_SQL.NATIVE);"
to
"DBMS_SQL.PARSE(v_CursorID, v_SQL, 1);"
and the form was very happy !
Thank you very much, Tom.
DP

November 28, 2001 mathew -- Thanks for the question regarding
      "accessing other database from oracle ", version 8i

      You Asked
hi,
    When I load the Java Stored procedure into the database how will it find the
driver to access the other database? Can you provide an example of Java stored
procedure which access another database?
From which version was Java stored procedure introduced?Is there a way to
stimulate Java Stored Procedure in the previous versions of Oracle?

thanks,
Mathew

      and we said...
Oracle8i release 1 (version 815) is the first release of Oracle to support java
in the database.  Prior to that, there is no way to emulate having java in the
database -- the java will necessarily be OUTSIDE of the database.  In 8.0,  you
might be able to use a C based external procedure to allow PLSQL to talk to a
java program by going through a C layer.  It would be upto you to write the code
to do this.

In order to use java to access another database, you would have to specify
whether this other database is Oracle or something else.  If it is Oracle-- the
answer is simple, database links.  See the create database link command

If the other database is NOT Oracle, you have two choices

1) see
http://www.oracle.com/gateways
 you can use a transparent gateway.  This will give you distributed
queries (cross database joins for example) as well as distributed transactions
with two phase commit.

2) you can load their type4 THIN, pure java, jdbc driver into Oracle using
loadjava (as you would to load any jar file or class).  In this fashion, you can
open an independent transaction to another database -- no distributed queries,
no distributed transactions -- just a jdbc connection.
Review &
      Followup

      Rating:
      3
  November 27, 2001
Reviewer:
      mathew  from India
thanks tom.I am still wondering how do I specify the driver name? Do i specify
the driver information the same way I would if the class file had been outside
the database?
thanks a lot tom for the reply.

          Followup:

Yes, when you load the driver into the database, you would specify it in the
same way you would outside the database.  Its not any different.

November 28, 2001 Arumugam -- Thanks for the question regarding
      "Recover the Database", version 8.1.7

      You Asked
Hello TOM,
     I have the following the doubts.

         1. I created the datafile. But i want to remove the file now. How can i
delete the file.
         2. I'm taking the backup now. If the system is crahsed How can i
recover it. ie.. if i will install new oracle how can i use the old back up from
old install?.

 Awainting for your reply.

regards,
sivababu

      and we said...
1) you cannot remove a datafile.  Once added, a datafile is there forever until
you drop the tablespace.  Then you can remove all of the datafiles associated
with that tablespace.  You can shrink the datafile using the alter database
datafile command -- but you cannot remove it.

2) read

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/toc.htm
from start to finish, backup and recovery is something you want more then a
cursory knowledge of.
Review & Followup

      Rating:
      4
  November 29, 2001
Reviewer:
      sivababu  from INDIA
It is very usefull.

      Rating:
      4
  November 29, 2001
Reviewer:
      sivababu  from INDIA

      Rating: 4
It is
      usefull  November 29, 2001
Reviewer:
      sivababu  from INDIA
Hello TOM,
   This is correct. Unfortunately i created in DRSYS tablespace. But it is not
our tablespace. So i made offline. But it is not used now.

November 28, 2001 Omar -- Thanks for the question regarding
      "Queries", version 8.1.6

      You Asked
Hi Tom,
   I have this situation.

we have 4 levels of working units here in our university
represented in these 4 tables in our personnel system
level 1:
Unit (
   unit_code number(2),
   Unit_Desc varchar2(50)
 )
Level 2:
Department(
  unit_code number(2),
  Dept_code number(2),
  Dept_desc varchar2(50),
Level 3:
Division (
  Unit_code number(2),
  Dept_code number(2),
  Div_code  number(2),
  Div_Desc  varchar2(50)
 )
Level 4:
Section(
  Unit_code number(2),
  Dept_code number(2),
  Div_code  number(2),
  Sec_code  number(2),
  Sec_desc  varchar2(50)
)

Another table for employees looks like
Basic_info (
 emp_no  number(6),
 .....
 unit_code number(2),
 dept_code number(2),
 div_code  number(2),
 Sec_code  number(2) ,
....
)

some of employees work in level 1 and has there unit_code filled
and all other codes null, others work in Level 2 and have there
(unit_code,dept_code) filled and the rest are null, and so on
downto level 4.

THE Q.
1. first of all if there is any comment about the prev.
structure or recomendations.
2. I need to build a procedure that recieves the emp_no as input
parameter and returns the lowest level of his work unit.

thanks in advance

      and we said...
1) my comments -- yuck.  Normalization run amok.  I would prefer
A table with A key.  Something like:

create table x
( code int primary key,
  descript <and all other COMMON columns> );

create table unit ( code int primary key references X,
                    <unit specific columns> );
create table department ( code int primary key references X,
                          <dept specific columns> );
.... and so on

create table basic_info( emp_no number primary key,
                         code int references X );

I probably would not even HAVE unit, department as standalone
tables -- just roll them into the X table.  Have their columns
be NULL when they don't apply.

two tables -- one key.  But, given you have what you have:

ops$tkyte@ORA8I.WORLD> insert into basic_info
  2  values ( 1, 1, null, null, null );
ops$tkyte@ORA8I.WORLD> insert into basic_info
  2  values ( 1, 1, 1, null, null );
ops$tkyte@ORA8I.WORLD> insert into basic_info
  2  values ( 1, 1, 1, 1, null );
ops$tkyte@ORA8I.WORLD> insert into basic_info
  2  values ( 1, 1, 1, 1, 1 );

ops$tkyte@ORA8I.WORLD> insert into unit
  2  values ( 1, 'unit 1' );
ops$tkyte@ORA8I.WORLD> insert into department
  2  values ( 1, 1, 'dept 1' );
ops$tkyte@ORA8I.WORLD> insert into division
  2  values ( 1, 1, 1, 'div     1' );
ops$tkyte@ORA8I.WORLD> insert into section
  2  values ( 1, 1, 1, 1, 'sect 1' );

ops$tkyte@ORA8I.WORLD> select emp_no,
  2        (case when unit_code is not null
  3                   and dept_code is not null
  4                   and div_code is not null
  5                   and sec_code is not null
  6              then (select sec_desc
  7                      from section s
  8                     where s.unit_code = e.unit_code
  9                       and s.dept_code = e.dept_code
 10                       and s.div_code = e.div_code
 11                       and s.sec_code = e.sec_code )
 12              when unit_code is not null
 13                   and dept_code is not null
 14                   and div_code is not null
 15                   and sec_code IS null
 16              then (select div_desc
 17                      from division s
 18                     where s.unit_code = e.unit_code
 19                       and s.dept_code = e.dept_code
 20                       and s.div_code = e.div_code )
 21              when unit_code is not null
 22                   and dept_code is not null
 23                   and div_code IS null
 24                   and sec_code IS null
 25              then (select dept_desc
 26                      from Department s
 27                     where s.unit_code = e.unit_code
 28                       and s.dept_code = e.dept_code )
 29              when unit_code is not null
 30                   and dept_code IS null
 31                   and div_code IS null
 32                   and sec_code IS null
 33              then (select unit_desc
 34                      from unit s
 35                     where s.unit_code = e.unit_code )
 36              else NULL
 37          end)
 38   from basic_info e
 39  /

    EMP_NO (CASEWHENUNIT_CODEISNOTNULLANDDEPT_CODEISNOTNULLAN
---------- --------------------------------------------------
         1 unit 1
         1 dept 1
         1 div  1
         1 sect 1

will query for you.
Review & Followup

      Rating: 2
Will it work on
      8.0.4?  November 28, 2001
Reviewer:  Thaha
      hussain  from Bahrain
Will this SQL work on  8.0.4.0.0 ?

We tried something like this

select s.regno,
         (case
            when month_year IS not null
               then (
                 select max(to_number(month_year))
            from fee_collect_masters fm,fee_collect_details fd
             where fm.regno (+)= s.regno
               and fm.recpt_no = fd.recpt_no)
               else null
            end)
 from students
/

It shows an error

SQL> /
            when month_year IS not null
            *
ERROR at line 3:
ORA-00907: missing right parenthesis

What is the problem?

          Followup:

case is new with 8i release 2 (816)

select ... (select )  from table.   is new with 8i release 1 (815)

In 8.0 (or 8i) the above can be coded as:

select s.regno, decode( s.month_year, NULL, NULL, f.month_year )
  from students s,
       (select regno, max(to_number(month_year)) month_year
          from fee_collect_masters fm,fee_collect_details fd
         where fm.recpt_no = fd.recpt_no
         group by regno ) f
 where s.regno = f.regno (+)
/

      Rating: 2
What happend to
      oracle Web Site?  November 28, 2001
Reviewer:
      Thaha hussain  from Bahrain
I refreshed the 'submitted page' a few times and my response replicated. Very
bad!

          Followup:

Ok, we added a redirect after the submission to avoid people reloading the page
that submits their review.  should be all fixed up.

November 28, 2001 Peter -- Thanks for the question regarding "XML
      Parsing a CLOB", version 8.1.7

      You Asked
I have an XML document stored as a clob and I wish to Parse it.
I have writen the following small test:

create or replace  java source
named "Validate" as
import java.sql.*;
import java.io.*;

import java.lang.String;
import oracle.xml.sql.dataset.*;
import oracle.xml.sql.query.*;

import oracle.xml.sql.*;
import oracle.sql.*;
import oracle.jdbc.driver.*;
import oracle.xml.parser.schema.*;
import oracle.xml.parser.v2.*;
import org.xml.sax.*;
import org.w3c.dom.*;

 public class Validate {
 public static String validateCLOB(oracle.sql.CLOB xmldoc) {
 SAXParser parser = new SAXParser();

 try {
     parser.parse( new ByteArrayInputStream(xmldoc.getBytes()));
     return "Valid XML Document";
      } catch(SAXException e) {
         return "Invalid XML Document" + e.getMessage();
      }
catch(Exception e) {
         return "Error " + e.getMessage();
      }
       }
         }
/

CREATE OR REPLACE FUNCTION validateCLOB(xmldoc CLOB)
return varchar2
AS LANGUAGE JAVA NAME 'Validate.validateCLOB(oracle.sql.CLOB)
                       returns java.lang.String';
/

SQL> desc myxml
 Name                                      Null?    Type
 ----------------------------------------- -------- ------------
 X                                                  CLOB

SQL> select validateCLOB(x) from myxml
  2  /

VALIDATECLOB(X)
------------------------------------------
Error Invalid UTF8 encoding.

If I change the datatype from CLOB to Varchar2 then everything works fine.
I have seen this problem raised in FAQ, but as yet, I have not seen an answer
which actually works.

      and we said...
I asked Sean Dillon, our resident XML guru, to take a look and he says:

....

The method you used on the SAXParser (an inherited method from
oracle.xml.parser.v2.XMLParser: parse() ), is one of these:

parse(InputSource)
parse(java.io.InputStream)
parse(java.io.Reader)
parse(java.lang.String)

The method call you made on the CLOB (an inherited method from
oracle.sql.Datum.getBytes() ) returns a byte[]. This makes the parse method
perform an implicit converstion from the byte array to call the parse method. If
you simply call the parse method with an InputStream the implicit converstion
can be avoided. Change:

parser.parse( new ByteArrayInputStream(xmldoc.getBytes()));

...to...

parser.parse( xmldoc.getCharacterStream() );

...and you're all set.
Review & Followup

      Rating:
      5
Analyst/Developer  November 28, 2001

Reviewer:  Peter Courtney  from NSW Australia

Perhaps this answer should be published in FAQs. I have seen similar type
questions raised, but as yet, this is the first "real" answer I have seen

      Rating: 5
CLOB parsing in
      Oracle  August 09, 2002
Reviewer:  Robyn
      Lawrence  from Canberra, ACT Australia
I was trying to expand the Oracle technet example which does Server Side XML
Validation but only allows the xml and xsd to be varchar2(4000).  So I wanted to
be able to read in a FULL size XML doc and XSD schema into Oracle using CLOBS.
I spent a day trying to use the

InputStream xmlInstream = xml.getAsciiStream();
and producing a byte [] array from this, by using using the read() function.
Although it did not fall over creating the byte [] when I came to try to call
the (XMLSchema)builder it caused an unknown Java Exception.

I was trying to use the byte[] which I assembled from reading in a CLOB.
XMLSchema schemadoc = (XMLSchema)builder.build(in, null );

However your brilliant suggestion of:

Reader xsdInstream = xsd.getCharacterStream();

XMLSchema schemadoc = (XMLSchema)builder.build(xsdInstream, null );

Worked a treat!  I also used it for:

dp.parse (xmlInstream);

rather than:

dp.parse (in);

Thank you very much!!

November 28, 2001 Yogesh -- Thanks for the question regarding
      "Inline Function versus query", version 8.1.7

      You Asked
I have a PL SQL block which is as given below.

declare
    cursor xcur is select ROWID, CNO, CNcode from TBAS387809420829229;
    num number := 1;
    v_Ctot number;
    v_CNCTot number;
BEGIN
    DBMS_OUTPUT.ENABLE(20000);
    for rec in xcur
    loop
    SELECT
    /*+ INDEX(T_HIS IDX_TH )*/
        SUM(AMOUNT)
    INTO
        v_Ctot
    FROM
        T_HIS
    WHERE
        CNO = rec.CNO AND
        CUCode = CUCode;
    SELECT
        /*+ INDEX(T_HIS IDX_TH_CS )*/
        SUM(AMOUNT)
    INTO
        v_CNCTot
    FROM
        T_HIS
    WHERE
        T_HIS.CNCODE = rec.CNcode AND
        CNO = rec.CNO AND
        CUCode=CUCode;

    update TBAS387809420829229 set
        Ctot = v_Ctot ,
        CNCtot = v_CNCTot
    WHERE
        ROWID = rec.rowid;
    DBMS_OUTPUT.PUT_LINE('' || num);
    num:= num + 1;
    end loop;
END;

and another one which is doing the same function as that of above one but uses
inline function as given below.

declare
    cursor xcur is select ROWID, CNO, CNcode from TBAS387809420829229;
    num number := 1;
    v_CTot number;
    v_CCTot number;

    function Add_C_i(v_CNo NUMBER) RETURN NUMBER AS
        v_CTot    NUMBER;
    BEGIN
        SELECT
        /*+ INDEX(T_HIS IDX_TH )*/
            SUM(AMOUNT)
        INTO
            v_CTot
        FROM
            T_HIS
        WHERE
            CNO = v_CNo AND
            CUCode = CUCode;
        RETURN v_CTot;
    END;
    function Add_CNC_i(p_CNo NUMBER,p_CNcode NUMBER) RETURN NUMBER AS
    v_CCTot NUMBER;
    v_CNcode    T_HIS.CNcode%TYPE;
    v_Cno        T_HIS.Cno%TYPE;
    v_CUCode    T_HIS.CUCode%TYPE;
    BEGIN
    SELECT
        /*+ INDEX(T_HIS IDX_TH_CS )*/
        SUM(AMOUNT)
    INTO
        v_CCTot
    FROM
        T_HIS
    WHERE
        T_HIS.CNCODE = p_CNcode AND
        CNO = p_CNo AND
        CUCode=CUCode;

        RETURN v_CCTot;
    END;
BEGIN
    DBMS_OUTPUT.ENABLE(20000);
    for rec in xcur
    loop
    v_CTot := Add_C_i(rec.CNO);
    v_CCTot := Add_CNC_i(rec.CNO, rec.CNcode);
    update TBAS387809420829229 set
        Ctot = v_CTot ,
        CNCtot = v_CCTot
    WHERE
        ROWID = rec.rowid;
    DBMS_OUTPUT.PUT_LINE('' || num);
    num:= num + 1;
    end loop;
END;
----------------------------------------------------------
The PL SQL block which has the Select statements embeded within are working
faster than the other one which is having two function for tha same purpose.

In case we try to use external functions for similar stuff we face similar
performance issue.

If we check the Execution Plan for the Select statement it is using the
specified index.

Kindly

      and we said...
and how does this simple update that does the same exact thing as all of that
code:

update TBAS387809420829229 t
   set ctot = ( select sum(amount)
                  from t_his
                 where t_his.cncode = t.cncode ),
       cnctot = ( select sum(amount)
                    from t_his
                   where t_his.cncode = t.cncode
                     and t_his.cno = t.cno );

perform.....

or even:

update TBAS387809420829229 t
   set ( ctot, cnctot ) =
         ( select sum(amount), sum( decode( t_his.cno, t.cno, amount, 0 ) )
             from t_his
            where t_his.cncode = t.cncode );

The phenomena you are seeing is the effect of "inlining" code -- it is a common
optimizer technique used by compilers.  Function calls add code, there is a
small overhead for each function call and return.  We have to set up the
temporary variables, setup the step, remember where to return to, move the data
from temporaries into your variables, etc.  If the above loop is executed
thousands of times -- it'll add up.

That is not to say functions are evil -- quite the contrary.  Use them, use them
all over the place -- good modular code is much more important...

But -- in this case, you are doing too much work procedurally -- you are taking
the really hard approach to a simple problem.  try this update:
update TBAS387809420829229 t
   set ( ctot, cnctot ) =
         ( select sum(amount), sum( decode( t_his.cno, t.cno, amount, 0 ) )
             from t_his
            where t_his.cncode = t.cncode );

and if you are ambitious, post the results of the

1) plsql code without functions
2) plsql code with functions
3) simple update

I did a small test on 2500 rows and found:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table TBAS387809420829229
  2  ( cno int, cncode int, ctot int, cnctot int );

Table created.

Elapsed: 00:00:00.06
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t_his
  2  ( cno int, cncode int, cucode int, amount int );

Table created.

Elapsed: 00:00:00.05

ops$tkyte@ORA817DEV.US.ORACLE.COM> begin
  2      for l_cno in 1 .. 50
  3      loop
  4          for l_cncode in 1 .. 50
  5          loop
  6              insert into TBAS387809420829229
  7              values ( l_cno, l_cncode, 0, 0 );
  8
  9              for i in 1 .. 10
 10              loop
 11                  insert into t_his
 12                  values ( l_cno, l_cncode, 1, abs(dbms_random.random) );
 13              end loop;
 14          end loop;
 15      end loop;
 16  end;
 17  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:09.63

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index idx_th on t_his( cno );
Index created.

Elapsed: 00:00:01.32
ops$tkyte@ORA817DEV.US.ORACLE.COM> create index idx_th_cs on t_his( cno, cncode
);

Index created.

Elapsed: 00:00:01.19
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace procedure inlined_code
  2  as
  3      cursor xcur is select ROWID, CNO, CNcode from TBAS387809420829229;
  4      num number := 1;
  5      v_Ctot number;
  6      v_CNCTot number;
  7  BEGIN
  8          dbms_output.enable( 20000 );
...
 41  END;
 42  /

Procedure created.

Elapsed: 00:00:00.20
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace procedure non_inlined_code
  2  as
  3      cursor xcur is select ROWID, CNO, CNcode from TBAS387809420829229;
  4      num number := 1;
  5      v_CTot number;
  6      v_CCTot number;
...
 58  /

Procedure created.

Elapsed: 00:00:00.24
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace procedure the_best_way
  2  as
  3  begin
  4          dbms_output.enable( 20000 );
  5  update TBAS387809420829229 t
  6     set ( ctot, cnctot ) =
  7           ( select sum(amount), sum( decode( t_his.cncode, t.cncode, amount,
0 ) )
  8               from t_his
  9              where t_his.cno = t.cno );
 10      dbms_output.put_line( sql%rowcount || ' rows updated' );
 11  end;
 12  /

Procedure created.

Elapsed: 00:00:00.12
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> set timing on
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec inlined_code
2
3
4
5
...
2497
2498
2499
2500
2501

PL/SQL procedure successfully completed.

Elapsed: 00:00:10.65
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec non_inlined_code
2
3
4
5
6
7
8
....
2499
2500
2501

PL/SQL procedure successfully completed.

Elapsed: 00:00:10.34
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec the_best_way
2500 rows updated

PL/SQL procedure successfully completed.

Elapsed: 00:00:09.08

The simple (unhinted) update is best.  Less code, less run time, easiery to
maintain (and the list goes on)
Review &
      Followup

      Rating: 5
Great
      !  November 28, 2001
Reviewer:  Andre Whittick
      Nasser  from Rio de Janeiro, Brazil
Never have I seen the term KISS so well placed.

November 28, 2001 Peter -- Thanks for the question regarding
      "Cursor Variable and Bind Variables", version 8i

      You Asked
Hi Tom,

I'm trying to use a cursor variable in the manner below.
However, I'd like to use a bind variable for my v_in_string
(see the code below). How do I accomplish that?
I tried to use "USING", but it didn't work.
Thanks

CREATE OR REPLACE PROCEDURE test_proc IS
   TYPE t_ref_cursor IS REF CURSOR;
   v_ref_cursor t_ref_cursor;

   v_select_string VARCHAR2(4000);
   v_in_string VARCHAR2(100) := '1, 2, 3';

BEGIN
   v_select_string := 'SELECT * ' ||
                      'FROM   test_table ' ||
                      'WHERE  pk_id IN (' || v_in_string || ')';

   OPEN v_ref_cursor FOR
      v_select_str;

   -- ...rest of the code...
END test_proc;
/

      and we said...
ops$tkyte@ORA815.US.ORACLE.COM> create or replace type myTableType as table of
number
  2  /

Type created.

ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM> create or replace function str2tbl( p_str in
varchar2 ) return myTableType
  2  as
  3      l_str   long default p_str || ',';
  4      l_n        number;
  5      l_data    myTableType := myTabletype();
  6  begin
  7      loop
  8          l_n := instr( l_str, ',' );
  9          exit when (nvl(l_n,0) = 0);
 10          l_data.extend;
 11          l_data( l_data.count ) := ltrim(rtrim(substr(l_str,1,l_n-1)));
 12          l_str := substr( l_str, l_n+1 );
 13      end loop;
 14      return l_data;
 15  end;
 16  /

Function created.

ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM> variable x varchar2(255)
ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM> exec :x := '1,2,3, 4, 5'

PL/SQL procedure successfully completed.

ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM> select *
  2    from all_users
  3   where user_id in ( select * from table( cast ( str2tbl(:x) as myTableType
) ) )
  4  /

USERNAME                          USER_ID CREATED
------------------------------ ---------- ---------
SYSTEM                                  5 21-JUN-01

Review &
      Followup

      Rating:
      5
  November 28, 2001
Reviewer:  Peter
       from CA, USA
Tom,

Is it worth going through all this just so we can use bind variables?  Would the
performance be much worse in this case if we just use a dynamic SQL without
using bind variables?

Thanks

          Followup:

YES IT WOULD BE.

At the very very least, you could do this:

CREATE OR REPLACE PROCEDURE test_proc IS
   TYPE t_ref_cursor IS REF CURSOR;
   v_ref_cursor t_ref_cursor;

   v_select_string VARCHAR2(4000);
   v_in_string VARCHAR2(100) := '1, 2, 3';

BEGIN
   v_select_string := 'SELECT * ' ||
                      'FROM   test_table ' ||
                      'WHERE  pk_id IN (' || v_in_string || ')';

   execute immediate 'alter session set cursor_sharing=FORCE';
   OPEN v_ref_cursor FOR
      v_select_str;
 execute immediate 'alter session set cursor_sharing=EXACT';

   -- ...rest of the code...
END test_proc;

That way, you would only get as many different query plans stuffed up in your
shared pool as you had number of in-list elements, that is, you would have:

select * from t where id in ( :1 )
select * from t where id in ( :1, :2 )
select * from t where id in ( :1, :2, :3 )
....

instead of hundreds/thousands of unique statements.

Yes, this is extremely imporant. (and once you've written str2table once -- its
part of your database, no muss, no fuss, its just there)

November 29, 2001 Isiah -- Thanks for the question regarding "How
      do you remotely edit a package body?", version 8.0.5

      You Asked
Hi Tom,

I need to modify a client's database, which is located in a remote site behind a
firewall.  I can access this remote database only from my local AIX server using
sqlplus.  (That is, the remote site's firewall only let in packets from this AIX
server.)

I have to edit and add several lines of code to a package in the remote
database. I don't have the source code of the package so I need to extract it
first.  What would be the easiest way to do this?

Thanks.

      and we said...
I call this script "getcode.sql"

set feedback off
set heading off
set termout off
set linesize 1000
set trimspool on
set verify off
spool &1..sql
prompt set define off
select decode( type||'-'||to_char(line,'fm99999'),
               'PACKAGE BODY-1', '/'||chr(10),
                null) ||
       decode(line,1,'create or replace ', '' ) ||
       text text
  from user_source
 where name = upper('&&1')
 order by type, line;
prompt /
prompt set define on
spool off
set feedback on
set heading on
set termout on
set linesize 100

if you just go:

SQL> @getcode packagename
SQL> edit packagename  (do your changes)
SQL> @packagename

you'll have it...
Review & Followup

      Rating: 5
More
      scripts  November 29, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
Tom, where are all those "abracadabra" scripts ? Do you have a collection of
them available online ? Any links beyond Code Tips ?

          Followup:

pretty much all of them are in my book -- code from the book is available on the
WROX website (www.wrox.com, search for oracle)

      Rating: 3
Could not
      understand  November 29, 2001
Reviewer:  Gururaj
      Kulkarni  from Norcross,GA USA
Tom,

Could you tell me how this particular code helps ?

-Thanks
-Gururaj

      Rating:
      5
Answer  November 29, 2001
Reviewer:
      A reader
Hi, Gururaj Kulkarni,

just plug in the code and give one of your package's name and you will find it
very useful.

Do it by yourself is the only way to understand.

Take care

November 29, 2001 Denis -- Thanks for the question regarding "How
      to guarantee uniqueness of DBMS_Utility.Get_Hash_Value function?", version
      8.1.7

      You Asked
Dear Tom,

Is there any way to guarantee uniqueness of the results of the
DBMS_Utility.Get_Hash_Value function?

For example: I have a set of strings of a fixed length (or know  length of the
longest string) and know that they can only consist of certain characters (e.g.
uppercase letters and digits). Is it possible based on this information (or some
additional information) to derive base and hash_size arguments of the function
to avoid collisions? or at least guarantee 99.9% of uniqueness?

All Oracle documents I have seen so far are saying that "large" hash sizes
provide "good" results. How large is "large" based on the data? What does "good"
mean in terms of probability of the collisions?

Thank you,

Denis.

      and we said...
By definition -- hash functions guarantee REPETITION -- it is one of their
attributes, two strings can and will hash to the same value!

If not -- dbms_utility.get_hash_value would be the greatest compression tool on
the planet!  If there were a one to one mapping between the infinite set of
strings and a finite hash table......

So, there is no way with a hash to avoid collisions, you will have collisions.

It really depends on the values of your strings -- not their lengths -- as to
how big the hash table needs be to avoid collisions "99.9%" of the time (which
is not practical in general).

Large should be larger then then set of strings you plan on hashing.  It is
generally recommanded to pick the next prime number greater then then expected
size of the hashed values.
Review & Followup

      Rating: 1
There is a way
      to avoid collisions...  November 28, 2001

Reviewer:  Denis Avdonin  from Galway, Ireland

Tom,

The statement that hash functions in general do not guarantee uniqueness is not
quite true. There are different types of the functions. There are so called
"perfect" hash functions, which guarantee uniqueness for known set of source
data. Example: if length of all strings is 5 and they can only contain upper
case letters and digits then there are 36^5 = 60,466,176 possible strings, which
can be easily fit into NUMBER range without collisions.

However, get_hash_value is a generic function, so I do not expect it to be
perfect. Nevertheless, it would be useful to understand how it works. Do you
have an insight what algorithm is implemented behind the PL/SQL wrapper? Or at
least have more precise guidelines on choosing base and hash_size depending on
source data...

Kind regards,

Denis.

          Followup:

Ok, if you want a hash table with 60million slots -- more power to you.  And
again, its only achievable when you know ALL of the keys...

There are no guidelines to choosing the base -- thats totally up to you -- I
mean, you are going to use the number somewhere.  I always use base = 1
personally since all base does is add itself to the hash.  Base is sort of
meaningless in this case.

The guideline for the size -- the next prime number above the expected size of
your table.
The algorithm is not published and it has changed over time from release to
release (and will undoubtably change again).  If you need a perfect hash or a
hash that returns the same values forever, you'll have to write it yourself.

      Rating: 5
A little
      comment...  November 28, 2001
Reviewer:  Andre
      Whittick Nasser  from Rio de Janeiro, Brazil
Tom,

Honestly, I congratulate you on your patience to repeat the same answers over
and over.

When needed, I have tried to look up first in the on-line books, then search
your site for related topics. But, as you commented in your question page, many
of the answers are already in your archives.

Longer ago, I remember, you used to send a personal letter pointing to one of
these archive answers.

For example, a very similar question was placed yesterday or so.

I notice you sometimes forgo answering "more useful" questions instead.

Anyway...

      Rating: 4
Hash size
      recommendation  November 29, 2001
Reviewer:
      padders  from UK
Tom, please can you clarify. You state that the optimal hash size is the next
prime number above the expected size of your table. I have no reason to doubt
you on this, but DBMS_UTILITY package specification suggests using a power of 2
for the hash_size parameter works best. Can you settle this?

I see this hash function regularly recommended for one-way password hashes (I
believe you yourself have recommended it). If as you say the algorithm has
changed over time and is highly likely to change again, this is potentially
going
to cause headaches for applications using this algorithm if/when they upgrade,
since strings will no longer hash to the same value, and any stored hashes will
be rendered useless.

Thanks for the continued outstanding support you provide.

          Followup:

well, to test this I wrote a brute force "get next prime"
create or replace function get_next_prime( p_n in number ) return number
as
    l_n number default p_n;
    l_NOT_prime boolean;
begin

    loop
        for i in 2 .. l_n/2+1
        loop
            l_NOT_prime := ( l_n/i = trunc(l_n/i) );
            exit when l_NOT_prime;
        end loop;
        if (NOT l_NOT_prime)
        then
            return l_n;
        end if;
        l_n := l_n+1;
    end loop;
end;
/

and a routine to hash strings:

create or replace function test_tab_size( p_tab_size in number ) return varchar2
as
    l_data dbms_sql.varchar2_table;
    l_empty dbms_sql.varchar2_table;
    l_idx   number;
    l_collision_cnt number := 0;
    l_tab_size      number := p_tab_size;
    l_msg           varchar2(4000);
begin

    dbms_random.seed( userenv('sessionid') );

    for i in 1 .. p_tab_size
    loop
        l_idx := dbms_utility.get_hash_value(dbms_random.string('a',30),1,
l_tab_size);

        if ( l_data.exists(l_idx) )
        then
            l_collision_cnt := l_collision_cnt+1;
        end if;
        l_data(l_idx) := 'Y';
    end loop;

    l_msg := l_collision_cnt || ' collisions with tabsize = ' || l_tab_size;

    dbms_random.seed( userenv('sessionid') );
    l_data := l_empty;
    l_collision_cnt := 0;
    l_tab_size := get_next_prime( l_tab_size );

    for i in 1 .. p_tab_size
    loop
        l_idx := dbms_utility.get_hash_value(dbms_random.string('a',30),1,
l_tab_size);

        if ( l_data.exists(l_idx) )
        then
            l_collision_cnt := l_collision_cnt+1;
        end if;
        l_data(l_idx) := 'Y';
    end loop;
    l_msg := l_msg || chr(10) ||
    ( l_collision_cnt || ' collisions with tabsize = ' || l_tab_size);

    return l_msg;
end;
/

(random strings of 30 bytes -- reset the seed in the middle so both loops hashed
the same strings each time).

I then ran it for various powers of 2 and the next prime above that:

1 collisions with tabsize = 2
0 collisions with tabsize = 5
PL/SQL procedure successfully completed.

1 collisions with tabsize = 4
2 collisions with tabsize = 5
PL/SQL procedure successfully completed.

1 collisions with tabsize = 8
3 collisions with tabsize = 11
PL/SQL procedure successfully completed.

6 collisions with tabsize = 16
4 collisions with tabsize = 17
PL/SQL procedure successfully completed.

12 collisions with tabsize = 32
10 collisions with tabsize = 37
PL/SQL procedure successfully completed.

23 collisions with tabsize = 64
21 collisions with tabsize = 67
PL/SQL procedure successfully completed.

51 collisions with tabsize = 128
50 collisions with tabsize = 131
PL/SQL procedure successfully completed.

95 collisions with tabsize = 256
98 collisions with tabsize = 257
PL/SQL procedure successfully completed.

189 collisions with tabsize = 512
186 collisions with tabsize = 521
PL/SQL procedure successfully completed.

376 collisions with tabsize = 1024
374 collisions with tabsize = 1031
PL/SQL procedure successfully completed.

732 collisions with tabsize = 2048
762 collisions with tabsize = 2053
PL/SQL procedure successfully completed.

1485 collisions with tabsize = 4096
1486 collisions with tabsize = 4099
PL/SQL procedure successfully completed.

2988 collisions with tabsize = 8192
3033 collisions with tabsize = 8209
PL/SQL procedure successfully completed.

6032 collisions with tabsize = 16384
6007 collisions with tabsize = 16411
PL/SQL procedure successfully completed.

12070 collisions with tabsize = 32768
12114 collisions with tabsize = 32771
PL/SQL procedure successfully completed.

24168 collisions with tabsize = 65536
24092 collisions with tabsize = 65537
PL/SQL procedure successfully completed.

I would say that it is somewhat of a "draw" in that regards ( i probably should
have tested with a non-prime number between the power of two and the prime too I
guess!)

Yes, it is an issue that dbms_utility.get_hash_value has changed over time (i
point this out in my book when talking about it).  However, the superior
dbms_obfuscation_toolkit.md5 routine -- being a standard algorithm, won't.

      Rating: 3
How to find
      hash_size (formula)  November 29, 2001
Reviewer:
      Kjetil Skotheim  from Oslo, Norway
Example:
We have say 3000 strings to hash. And we want no collisions
with a probability of 99.9%. How big should the hash_size
argument of DBMS_Utility.Get_Hash_Value at least be?

Three approximation formulas:

(they are really the same formula written in three different
ways and they are more accurate the bigger m and n gets)

p = e ^ ( - m*m / (2*n*n) )
m = sqrt( - 2 * n * ln(p) )
n = - ( m * m ) / ( 2 * ln(p) )

p is accepted probability of collition
m is number of strings to hash
n is "hash buckets", that is hash_size

Using the third formula:
m = 3000
p = 1 - 99.9% / 100 = 0.001
n = - ( 3000 * 3000 ) / ( 2 * ln(0.001) ) = 651442
.....so we should use at least hash_size 651441.

For details see:

http://www-inst.eecs.berkeley.edu/~cs70/lectures/lecture19.pdf
Or search Google.com for: hash collision approximation probability

      Rating: 4
Re: How to find
      hash_size (formula)  November 29, 2001
Reviewer:
      Kjetil Skotheim  from Oslo, Norway
...oops...sorry p should be:

p = 99.9% / 100 = 0.999
then n = 4.5E9 = 4500000000 = 4.5 billions

November 29, 2001 ronald -- Thanks for the question regarding
      "Oracle Java query Binding", version 8.1.7

      You Asked
The developers are using java  to query the database. When I looked at my
parsing it was 1:1 to executions.
My question how to make sure the query coming from the java are well binding so
database will not be over parsed the sql statement.

      and we said...
use the script:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1163635055580
and chang the count(*) > 100 to count(*) > 10 over time as you find and fix the
statements not using binds.

Your java developers should declare many of their prepared and callable
statements OUTSIDE the method as a "global" variable.  They should parse a
statment ONCE per session -- not ONCE per execution.

Tell them to read

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1478004815829
for example.
November 30, 2001
      SREE -- Thanks for the question regarding
      "howto start oraclestartSid on NT", version

      You Asked
Hi Tom
Could you tell me how to start a
OracleStartSID on nt.My probelm is i cannot
see the above mentioned service in the
control panel and both OracleServiceSID
and OracleTNSlisterner are running.

Any help is greatly appreciated.
regards
sree

      and we said...

In Oracle8i, release 8.1, there is no OracleStart*, just an
OracleServiceSID.  If that is running the database is running -
do you see different?  If you feel you have missing services for
databases you have, you can use the oradim program to creating
them.  I believe however that you are good to go as it is.

CREATING THE INSTANCE AND SERVICES for 8i:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1.  Using the command line version of Instance Manager to create
the new NT service.

  a)     Change to the <oracle_home>\bin directory
  b)    Type in the following command:
          ORADIM -NEW -SID <sid_name> -INTPWD <password> -
               STARTMODE AUTO -PFILE

<drive>:\<oracle_home>\database\init<sid_name>.ora

2.  Verify that the service was created.

  a)     Open the Control Panel and double click on Services
icon.
  b)     Scroll down to find the Oracle services and verify that

        the "ORACLESERVICE<new_sid>" is listed and started.

3.  Verify that the AUTO START registry entry was created.

  a)    Run regedt32
  b)    Choose HKEY_LOCAL_MACHINE, SOFTWARE, ORACLE
  c)    Find the ORA_<sid_name>_AUTOSTART is = TRUE

Review &
      Followup

      Rating: 5
Problem with
      tnslistener service  November 30, 2001
Reviewer:
      A reader
Tom

My  oracle service is starting properly

but my tnslistener service  is not starting.

Can you tell me how I can create a new tnslistener service.

thanks

          Followup:

just run

lsnrctl start <listener-name>

at the command prompt.  it'll create the service for you.

December 01, 2001 Michael -- Thanks for the question regarding
      "FGAC transparency", version 8.1.7

      You Asked
Hi Tom!

I guess the main advantage of FGAC is its transparency for users.

Consider the well-known table "emp" from scott/tiger.
The task is to allow users see own data and data of subordinated users.
It could be done this way.

connect rls_test/rls_test

create table emp_base_table as select * from scott.emp;
create view emp as select * from emp_base_table;
grant select on emp to public;

create or replace function get_sel_predicate(
  p_schema varchar2,
  p_object varchar2
) return varchar2
is
  predicate varchar2(2000);
begin
  predicate:=
    'empno in (
       select empno from emp
       connect by prior empno = mgr
       start with ename = sys_context(''userenv'',''session_user'')
     )';
  return (predicate);
end;
/

begin
  dbms_rls.add_policy(
    object_name => 'emp',
    policy_name => 'emp_sel_policy',
    policy_function => 'get_sel_predicate',
    statement_types => 'select'
  );
end;
/

Let's see what we've got now.

connect blake/blake
alter session set current_schema=rls_test;
select * from emp;

Works fine.
But if there's an hierarchical query...

select * from emp
connect by prior empno=mgr
start with empno = 7698; -- 7698 is BLAKE's empno

... an  error (ORA-01473: cannot have subqueries in CONNECT BY clause)
 arises. For BLAKE it looks strange because he knows nothing about FGAC etc
 and believes that there's no subqueries there. It's clear why we get such an
 error. The problem is how to get it around. Constraining users that much is
 really TOO much. What would you do in this case?

Best regards, Michael

      and we said...
Well, actually -- how many end users do you know that know how to do a connect
by??

This is NOT a side effect of FGAC, this is a side effect of the policy for
securing data you have come up with.  FGAC is just a way to constrain the data
they can see -- you would be doing this SOMEWHERE, SOMEHOW (eg: via a view).
FGAC is just a mechanism for you to do this easier.  (point being -- FGAC is not
being evil here, your security constraints are)...

Oracle9i removes this ORA-01472 restriction:

  1  Select *
  2    from (
  3  select emp.*
  4    from emp
  5   where empno in ( select empno
  6                                     from emp
  7                              connect by prior empno = mgr
  8                                start with ename = 'BLAKE' )
  9             )
 10   connect by prior empno = mgr
 11*    start with empno = 7698
scott@ORA9I.WORLD> /

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM
DEPTNO
---------- ---------- --------- ---------- --------- ---------- ----------
----------
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850
  30
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300
  30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500
  30
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400
  30
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0
  30
      7900 JAMES      CLERK           7698 03-DEC-81        950
  30

6 rows selected.

December 02, 2001 -- Thanks for the question regarding "sending
      messages to all connected sessions !", version 8.1.7

      You Asked
Hai Mr Tom ,

I want to send message from SQLDBA/SVRMGR to all the connected sessions.  Is
there anyway other than DBMS_PIPE.  As soon as I send message it should be
displayed on the screens of connected users.

Why a datablock gets corrupted ?  If it gets corrupted then how should I fix it.

My last query is that one user dropped table suddenly.  How should I get it
back.  Database is in archive log mode.

thanks for your help
regs
mubeen

      and we said...
1) no, there is no broadcast facility like that.  The clients connected to
Oracle are vast and varied.  What would it mean to broadcast to an application
server?  A client connected via sqlplus?  Or forms?

The client itself must be listening for such a message which could be sent using
DBMS_ALERT (but not via DBMS_PIPES).  DBMS_ALERT is a "broadcast" method (but
the client must check and then display the message -- so SQLPlus would never
participate in this).  DBMS_PIPE is a point to point conversation.

2) many reasons, mostly due to hardware related issues (the hardware doesn't
write what it was asked to or there is a physical defect on the disk itself).

Have a good backup and recovery process in place, keep multiple backups
available (in case your last backup backed  up the corruption).

3) database point in time recovery is useful for this.  RMAN will automate it
(see the RMAN documenation for details).  You can do it yourself by restoring
SYSTEM, ROLLBACK and the tablespace containing the table to another machine.
You would then point in time recover this mini database to immediately BEFORE
the drop.  You can then export the table and import it into the real database.
If the table is the only thing in the tablespace -- you can even transport that
tablespace already formatted to the target database using exp and imp.
Review &
      Followup

      Rating: 3
Calling Alert
      local (form)procedure in sqlplus procedure using sqlplus
      7.2.2  November 30, 2001
Reviewer:  Ofoe
       from Ghana
Hi Tom;
can you also give me the built in Show_Alert function code so i can make use of
it in my own sqlplus procedure.
I tried using this function in sqlplus but error message appeared that it has
not been declare.
Thanks
Ofoe.

          Followup:

show_alert is a GUI function in Oracle forms -- it is not a PLSQL command.
There is no "show_alert" function for inside of SQLPLUS.

      Rating: 4
DBMS_ALERT
      Example.  December 02, 2001
Reviewer:  Parag
       from India
Hi Tom :

Can u please give us one example of dbms_alert , where a DBA can send some
message to all connected Users.

Regards
- Parag

          Followup:

I cannot demonstrate the impossible.  As I said -- the client application MUST
PARTICIPATE in this.  Be that sqlplus, forms, something you wrote, etc.

The "dba" would just "exec dbms_alert.signal( 'some_alert', 'some_message' );"
but if no one was listening to him, it would not matter.  Each and every client
would have had to of issued:

  dbms_alert.register( 'some_alert' );

upon connecting and would periodically have to issue:

  dbms_alert.waitone( .... );

to see if a message had been sent.  There are asyncronous callbacks available in
OCI (Oracles C Call level interface) but not in general.

      Rating: 3
workaround in
      some cases  December 03, 2001
Reviewer:
      Markus  from Finland
Provided that:
- your clients are on Windows
- your network topology allows
- your IT-policy allows
(etc...)
you might want to try this:

select 'NET SEND '||machine||' Please log out from <application> immediately!
Administrator.' from v$session where type='USER';

...or if you want to use e.g. NT-usernames, use OSUSER instead of MACHINE.

Copy the result and paste it into command prompt. Users will see your message in
a popup dialog box.

This works only in some specific environments, but I have used it successfully
in several offices. Likewise, I have used this technique in several other
scripts to dynamically build DML commands before issuing them.


Subject | Article | Last Updated (East coast time)
HTML Forms | article only | Dec 03, 2001 01:42 pm
going through a cursor field by field as well as row by row | article only | Dec 03, 2001 03:28 pm
stored procedures | article only | Dec 05, 2001 04:29 pm
locally managed tablespace | article only | Dec 06, 2001 03:09 pm
SQL join problem | article only | Dec 07, 2001 11:14 am
How to alter LMT uniform size to use autoallocate | article only | Dec 07, 2001 11:18 am
IMPORTING TABLE PARTITION. | article only | Dec 07, 2001 04:19 pm
Substing | article only | Dec 07, 2001 05:03 pm
Count & Sum | article only | Dec 07, 2001 06:41 pm
index on "select" column | article only | Dec 07, 2001 06:43 pm
sequence Question | article only | Dec 08, 2001 09:31 am
Loops Efficiency | article only | Dec 08, 2001 10:01 am
hierarchical query on dba_dependencies | article only | Dec 08, 2001 02:18 pm
pl/sql Tables | article only | Dec 08, 2001 02:29 pm
about the insert | article only | Dec 08, 2001 04:10 pm
Table Partitioning | article only | Dec 08, 2001 04:17 pm
Data Encryption | article only | Dec 08, 2001 04:40 pm
Database Design | article only | Dec 09, 2001 09:45 am
row(s) 1 - 18 of 18
December 03, 2001 Munzer -- Thanks for the question regarding "HTML Forms", version 8i
You Asked
Tom:

1.  I had a problem using htp.p('&nbsp;') when I compiled it .  I got a message
saying oracle expects a value.  I am trying to create a space in an HTML form
created by a PL/SQL procedure.  Is there a way around this?

2.  I have a main menu where one of the hyperlinks has a "year" value that is
expected to be entered by the user before displaying the next page.  I do not
have a submit button, but I want to pass this year value to the next form when
the user selects the hyperlink.  How do you capture this value and send it to
the PL/SQL procedyre that I defined to be called when pressing the hyperlink?

3.  I want to dynamically create a select list of this year and the previous ten
years in the column for year on the html form.  Would you do a SQL select and a
loop to define the select list and how would you make the <input type=text>
default to this year?

Thank you,
and we said...
1) issue:

SQL> set define off

before using strings with ampersands in them.  they are the default substitution
character in sqlplus.

2) you would use java script to post the data.  Something similar to this:

<script LANGUAGE="JavaScript1.1">
<!--

function doSubmit()
{
  document.my_form.submit();
}
//-->
</script>

<a href="javascript:doSubmit()">click me to submit the form</a>
<p>

<form action=my_action name=my_form method=get>
Enter a year please: <input type=text name=the_year>
</form>

will work.

3) I would use owa_util.listprint:

ops$tkyte@ORA8I.WORLD> begin
  2      owa_util.listprint( 'select to_char(add_months(sysdate,-(rownum-1)*12),
''YYYY''),
  3                                  to_char(add_months(sysdate,-(rownum-1)*12),
''YYYY''),
  4                                  decode(rownum,1,''Y'',NULL)
  5                             from all_objects where rownum <= 10',
  6                          'year_list',
  7                           5 );
  8  end;
  9  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA8I.WORLD> exec owa_util.showpage
<SELECT NAME="year_list" SIZE="5">
<OPTION SELECTED value="2001">2001
<OPTION value="2000">2000
<OPTION value="1999">1999
<OPTION value="1998">1998
<OPTION value="1997">1997
<OPTION value="1996">1996
<OPTION value="1995">1995
<OPTION value="1994">1994
<OPTION value="1993">1993
<OPTION value="1992">1992
</SELECT>

PL/SQL procedure successfully completed.

to do this automagically for me.  I don't see where the "input type=text" comes
into play as the list is a list, not a text item.
Review & Followup
Rating: 4
Where can I get more information on "owa_util" package. December 03, 2001
Reviewer: Monish
Tom,
Where can I get more information on "owa_util" package.
Thanks

Followup:
see
http://technet.oracle.com/docs/products/ias/doc_library/1022doc_otn/index.htm
for details.

December 03, 2001 Hareesh -- Thanks for the question regarding "going through a cursor field by field as well as row by row", version
You Asked
Can i go throgh a cursor variable field by field in a loop

Just like in VB we can go through resultset by saying field(n)
and we said...
No, not with a cursor variable in PL/SQL.  To do that -- you
want to use DBMS_SQL.  That is more akin to the ODBC/JDBC result
set type. here is a quick example.  It prints a result set
"down" the page instead of across.  Useful for wide queries in
sqlplus.

It will work in Oracle8.0 and up (there are solutions for 7.3
and before as well but this is the easier)

ops$tkyte@8i> create or replace procedure dump_table( p_tname in
varchar2 )
  2  is
  3      l_theCursor     integer default dbms_sql.open_cursor;
  4      l_columnValue   varchar2(4000);
  5      l_status        integer;
  6      l_query         varchar2(1000)
  7                      default 'select rowid, a.* from ' ||
p_tname || ' a';
  8      l_descTbl       dbms_sql.desc_tab;
  9      l_colCnt        number;
 10  begin
 11      execute immediate 'alter session set
nls_date_format=''dd-mon-yyyy hh24:mi:ss'' ';
 12      dbms_sql.parse(  l_theCursor,  l_query, dbms_sql.native
);
 13      dbms_sql.describe_columns( l_theCursor, l_colCnt,
l_descTbl );
 14
 15      for i in 1 .. l_colCnt loop
 16          dbms_sql.define_column( l_theCursor, i,
l_columnValue, 4000 );
 17      end loop;
 18
 19      l_status := dbms_sql.execute(l_theCursor);
 20
 21      while ( dbms_sql.fetch_rows(l_theCursor) > 0 ) loop
 22          for i in 1 .. l_colCnt loop
 23              dbms_sql.column_value( l_theCursor, i,
l_columnValue );
 24              dbms_output.put_line( rpad(
l_descTbl(i).col_name, 30 ) || ': ' ||
 25                                    l_columnValue );
 26          end loop;
 27          dbms_output.put_line( '-----------------' );
 28      end loop;
 29      execute immediate 'alter session set
nls_date_format=''dd-MON-yy'' ';
 30  exception
 31      when others then
 32          execute immediate 'alter session set
nls_date_format=''dd-MON-yy'' ';
 33          raise;
 34  end;
 35  /

Procedure created.

ops$tkyte@8i>
ops$tkyte@8i> exec dump_table( 'emp' );
ROWID                         : AAASDhAADAAACSKAAA
EMPNO                         : 7369
ENAME                         : SMITH
JOB                           : CLERK
MGR                           : 7902
HIREDATE                      : 17-dec-1980 00:00:00
SAL                           : 800
COMM                          :
DEPTNO                        : 20
-----------------
ROWID                         : AAASDhAADAAACSKAAB
EMPNO                         : 7499
.....
Review & Followup
Rating: 2
Can i go throgh a cursor variable field by field in a loop December 03, 2001
Reviewer: Fanya Elyashkevich from USA
Please provide a solution to do it in 7.3.4

I tried everything to get the Resultset from a cursor: no Luck!

Can you help please

Followup:
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:235814350980
it shows how to define without using dbms_sql.describe_columns (which is new
with 8.0)

other then that -- dbms_sql works just fine in 7.3 (since 7.1)

December 05, 2001 Lilian -- Thanks for the question regarding "stored procedures", version 8.1.6
You Asked
Hi Tom:

recently i had an issue from our programmer, who uses INSERTS or UPDATES to
oracle using ASP via an ODBC connection. These updates can take as long as 4.5
seconds per client. For instance, a joint account may take up to 9 seconds. The
obvious solution is to use stored procedures. What would it take to make this
happen?

i am learning pl/sql now, so would you help me out about the issue, following as
is some information the programmer give to me:

' Update
SQL1 = "UPDATE client SET "
If (l_ClientSince <> "0") Then
    SQL1 = SQL1 & "CLTSINCE = SYSDATE, "
End If
SQL1 = SQL1 & "BIRTHDATE = TO_DATE(" & "'" & l_birthdate & "'," & "'" &
"MM/DD/YYYY" & "')"  & ", "
SQL1 = SQL1 & "CUSTSTATUS = 2, "
SQL1 = SQL1 & "EMAIL = '" & replacestring(l_PrimaryEmail,"'", "''") & "', "
SQL1 = SQL1 & "FIRSTNAME = '" & replacestring(l_PrimaryFirstName,"'", "''") &
"', "
SQL1 = SQL1 & "FIRSTNAME2 = '" & replacestring(UCASE(l_PrimaryFirstName),"'",
"''") & "', "
SQL1 = SQL1 & "LASTNAME = '" & replacestring(l_PrimaryLastName,"'", "''") & "',
"
SQL1 = SQL1 & "LASTNAME2 = '" & replacestring(UCASE(l_PrimaryLastName),"'",
"''") & "', "
SQL1 = SQL1 & "LASTUPDDAT = SYSDATE, "
SQL1 = SQL1 & "LASTUPDOP =    '" & l_EDGE_UID & "', "
SQL1 = SQL1 & "MAIDENNAME = '" & replacestring(l_PrimaryPassword,"'", "''") &
"', "
SQL1 = SQL1 & "SSN = '" & l_SSN & "', "
SQL1 = SQL1 & "PROFILECIF = " & l_PrimaryCIF & ", "
SQL1 = SQL1 & "MIDINITIAL = '" & replacestring(trim(l_PrimaryMiddleName),"'",
"''") & "', "
SQL1 = SQL1 & "SOLICIT = '" & l_Reference & "' "
SQL1 = SQL1 & "WHERE PERSONID = " & l_PrimaryCIF

' Insert
SQL1 = "insert into
client(CLTSINCE,BIRTHDATE,CREATEDATE,CREATEOP,CUSTSTATUS,EMAIL,FIRSTNAME,FIRSTNAM
E2,GENDER,LANGUAGE_,LASTNAME,LASTNAME2,LASTUPDDAT,LASTUPDOP,MAIDENNAME,MAILSTOP,P
ERSONID,PROFILECIF,RESIDENT,CALLSTOP,EMAILSTOP,SURVEYSTOP,SSN,MIDINITIAL,SOLICIT)
"
SQL1 = SQL1 & " VALUES ("
SQL1 = SQL1 & "SYSDATE" & ", "
SQL1 = SQL1 & "TO_DATE(" & "'" & l_birthdate & "'," & "'" & "MM/DD/YYYY" & "')"
& ", "
SQL1 = SQL1 & "SYSDATE" & ", "
SQL1 = SQL1 & "'" & l_createop & "', "
SQL1 = SQL1 & "2, "
SQL1 = SQL1 & "'" & replacestring(l_PrimaryEmail,"'", "''") & "', "
SQL1 = SQL1 & "'" & replacestring(l_PrimaryFirstName,"'", "''") & "', "
SQL1 = SQL1 & "'" & replacestring(UCASE(l_PrimaryFirstName),"'", "''") & "', "
SQL1 = SQL1 & "'" & l_gender & "', "
SQL1 = SQL1 & "'" & l_language & "', "
SQL1 = SQL1 & "'" & replacestring(l_PrimaryLastName,"'", "''") & "', "
SQL1 = SQL1 & "'" & replacestring(UCASE(l_PrimaryLastName),"'", "''") & "', "
SQL1 = SQL1 & "" & "SYSDATE" & ", "
SQL1 = SQL1 & "'" & l_lastupdop & "', "
SQL1 = SQL1 & "'" & replacestring(l_PrimaryPassword,"'", "''") & "', "
SQL1 = SQL1 & "'" & l_mailstop & "', "
SQL1 = SQL1 & " " & l_PrimaryCIF & ", "
SQL1 = SQL1 & " " & l_PrimaryCIF & ", "
SQL1 = SQL1 & "'" & l_resident & "', "
SQL1 = SQL1 & "'" & l_callstop & "', "
SQL1 = SQL1 & "'" & l_emailstop & "', "
SQL1 = SQL1 & "'" & l_surveystop & "', "
SQL1 = SQL1 & "'" & l_SSN & "', "
SQL1 = SQL1 & "'" & replacestring(trim(l_PrimaryMiddleName),"'", "''") & "', "
SQL1 = SQL1 & "'" & l_Reference & "')"

thanks in advance,
an
and we said...
Yuck -- your problem is that your "programmer" did not use bind variables.  They
are spending 90% of their time parsing queries.

They have doomed you to failure. Even if you moved this to the server in a plsql
routine -- they would subvert your tuning by NOT BINDING to the stored procedure
call.

They should be preparing a statement:

  update t set x = :x, y = :y, z = :z where a > :a and b < :b

ONCE per program execution and then executing it over and over and over.

By not using bind variables and by parsing the statement each and every time,
they have killed:

o performance
o scalability

Just use bind variables and you will be OK.
Review & Followup
Rating: 4
A little bit example on that December 03, 2001
Reviewer: A reader
Hi, Tom,

Would you give just a little bit example based on the origianl queation's
example please?

Thanks

Rating: 4
bind variables December 03, 2001
Reviewer: an from DE
thank you very much for your suggestion and help.
i still have quesiton here, should i just use a sql statement:

update t set x = :x, y = :y where a > :a and b < :b; that will solve my problem,
or it's better to create a stored procedure with bind variables, then let front
end app. calls the procedure?
would you show me example?
thanks a lot!

Followup:
You can certainly put it into stored procedures -- the comment that follows this
has some good reasons why (I agree 100% with his points) however -- in your
case, unless you educate your developer the problem you are having will PERSIST.

Right now they are sending statements like:

  insert into t values ( 5 );
  insert into t values ( 6 );
  insert into t values ( 7 );
   ......

and each statement is unique.  So, we create a procedure p for them:

create procedure p ( p_input in number )
as
begin
   insert into t values ( p_input );
end;

we've removed all of the "insert into t values ( 5 )" and such from the shared
pool, but now that programmer will flood us with:

   begin p(5); end;
   begin p(6); end;
   begin p(7); end;

you have to EDUCATE them as to the proper way to code -- then consider stored
procedures.

Rating: 4
Reply - A little bit example on that December 03, 2001
Reviewer: Jim from Australia
I believe you should get all you SQL out of the front end
and put in stored procedures.

Heres just a few reasons
1: You can change your front end technology and not have to
   recode your business logic again.
   eg move from VB to Oracle Forms, or Java or ...
2: If you leave the SQL in the front end and you have to
   change the SQL then that means you have to
   reinstall the front end again. That may not be a problem
   now but what happens if your system or subsequent system
   ends up with hundreds or thousands of users who could
   be located in remote/distributed locations.

   Changing the SQL in a stored procedure means single
   point of maintenance, you change the code in one place
   and everyone sees it.
3: Having a call to a stored procedure means less impact
   to your network as opposed to sending a potentially
   large piece of SQL across it.

4: Procedures can assist with security since they offer
   execute authority. Instead of granting privs to a role
   or a user you can grant execute on the stored procedure
   to the role/user. The procedure is then in control
   of how the underlying data structures are accessed.

There is probably more that I just can't think of at the moment.

If you do take the stored procedure option, make sure
you PACKAGE your procedures! This was stressed quite
clearly by Tom to me and it is SO IMPORTANT
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:286816015990
or search Tom's site for "Compile procedure automatically"

Regards
Jim

Rating: 5
Bind variables examples December 04, 2001
Reviewer: Georg from Germany
You can find some examples in MetaLink. Just type "bind variable asp vb" and
klick on search.

Rating: 5
thanks all December 04, 2001
Reviewer: an from DE, usa
it's great help, resouces, information, and so on. I do appreciate all of your
comment.
thanks again!

Rating: 3
More Explanation December 04, 2001
Reviewer: Srimal from Trenton, USA
Hello Mr Tom,

You mentioned that performance will be improved with using bind variables (I
understand the scalability part and bind variables will improve scalability).
Are you saying that we prepare update statements and/or insert statements during
the application start (specific for asp only) and that would improve the
performance on the oracle end!

Doesn't an execute sql without returning a resultset enough to improve
performance using ADOs (from asp)!

Followup:
You need to use bind variables in ALL applications and ALL languages --
ESPECIALLY for inserts/updates/deletes (as you don't want to have to parse a
statement for every row you ever insert do you -- NO you don't)

You should ALWAYS prepare statements, ALWAYS bind their inputs.  Never use the
bad technique demonstrated in the original question of gluing character string
literals into the inserts/updates.  Its a KILLER.

Doesn't matter what language you are using, Java, C, VB, whatever -- use binds.

Rating: 5
What about ad-hoc user queries December 04, 2001
Reviewer: Matthew Cromer from Raleigh, NC
What do you think about ad-hoc user queries that do not use bind variables?

Is this something that needs to be fixed?  Sometimes the user is querying
against 1 or two columns, sometimes 3 or four, and the columns are not known
beforehand.  Is it a large problem that these client gui queries (probably 2 or
3 per minute across the client base) do not use bind variables?

Followup:
YES, that is 4320 statements in a day, that is a problem.  Those statements are
squeezing out others.  Especially if you look at them and find that of the 4320
-there are really only "100"  unique queries once you remove the constants.

It is trivial for any tool to bind (in most cases -- its EASIER to bind then to
NOT BIND!!! don't have to worry about quotes and such)...
If you can control the generation of these queries, you should have them use
binds.  If not, consider looking at cursor_sharing.

December 06, 2001 -- Thanks for the question regarding "locally managed tablespace", version 816.3
You Asked
i created a locally management tablespace ,as far as i know that even if you
spcify a storage clause on table level it will NOT overite the tablespace
storage parameters correct?
now i created an new user B i gave him quota ONLY on this new tablespace ,i made
export from user A and i do import with ignore=y (it should overide storage
parameters)  to user B and i am getting this error
IMP-00003: ORACLE error 1658 encountered
ORA-01658: unable to create INITIAL extent for segment in tablespace   ,because
in the export file its hard coded the storage parameters ,my question is why
wouldnt the tablespace storage parameters have the upper hand ?
and we said...
We will use the storage parameters to figure out how many extents to initially
allocate.  So, if you use:

create table t ( x int ) storage( initial 5m );

and create that in a LMT with 512k extents -- you'll get 10 extents allocated on
the CREATE.

That is why you are getting the error above -- the initial extent does not
specify the SIZE of the extents in a LMT, rather, it dictates HOW MANY to
allocate (as would minextents as well)
December 07, 2001 franz -- Thanks for the question regarding "SQL join problem", version 8.1.7
You Asked
I have more of a SQL-Language problem than an oracle specific one:

given following table 'fstest'
NAME                 ATTR                 VALUE1
-------------------- -------------------- ------------
a1                   #server              s1
a1                   #server              s2
s1                   #opc1                opc11
s1                   #opc2                opc12
s1                   someattr             someval
s2                   #opc1                opc21
s2                   someattr             someval

I want to create a view showing me all servers with some attr values:
SERVER       OPC1      OPC2
------------ --------- ---------
s1           opc11     opc12
s2           opc21

so I tried:

select fs1.value1 as server,  nvl(fs3.value1,' ') as opc2
from fstest fs1, fstest fs3 where
fs1.attr='#server' and
nvl(fs3.attr, '#opc2') = '#opc2' and
fs1.value1(+) = fs3.name;

but I never get the line for server "s2":
SERVER       OPC1      OPC2
------------ --------- ---------
s1           opc11     opc12

There is sure something wrong with my joins, but after dozens of variations of
my sql-code I give up. Any hints?

Thanks in advance!
and we said...
select name,
       max( decode( attr, '#ocp1', value1, null ) ) ocp1,
       max( decode( attr, '#ocp2', value1, null ) ) ocp2
  from fstest
 group by name;
Review & Followup
Rating: 3
December 07, 2001
Reviewer: Rajesh from Dublin
select fs1.value1 as server,  max( decode( fs3.attr, '#opc1', fs3.value1, null )
) as opc1,  max( decode( fs3.attr, '#opc2', fs3.value1, null ) ) as opc2
from fstest fs1, fstest fs3 where
fs1.attr='#server' and
fs1.value1 = fs3.name
group by fs1.value1;

This colud give for all servers

Followup:
No, it couldn't and wouldn't.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select name,
  2         max( decode( attr, '#ocp1', value1, null ) ) ocp1,
  3         max( decode( attr, '#ocp2', value1, null ) ) ocp2
  4    from fstest
  5   group by name;

NAME                           OCP1       OCP2
------------------------------ ---------- ----------
a1
s1                             opc11      opc12
s2                             opc21

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select fs1.value1 as server,  max( decode(
fs3.attr, '#opc1', fs3.value1, null )
  2  ) as opc1,  max( decode( fs3.attr, '#opc2', fs3.value1, null ) ) as opc2
  3  from fstest fs1, fstest fs3 where
  4  fs1.attr='#server' and
  5  fs1.value1 = fs3.name
  6  group by fs1.value1;

SERVER     OPC1       OPC2
---------- ---------- ----------
s1
s2

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

but anyway -- I suppose I might have been missing a predicate:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select name,
  2         max( decode( attr, '#ocp1', value1, null ) ) ocp1,
  3         max( decode( attr, '#ocp2', value1, null ) ) ocp2
  4    from fstest
  5   where name in ( select value1 from fstest where attr = '#server' )
  6   group by name;

NAME                           OCP1       OCP2
------------------------------ ---------- ----------
s1                             opc11      opc12
s2                             opc21

but its not really clear from the question.

Rating: 3
How about this ? December 07, 2001
Reviewer: Vikram from Phoenix
select
DECODE(attr,'#server',name||' '||value1||attr,NULL) Server
     , DECODE(attr, '#ocp1', value1, NULL) ocp1
     , DECODE(attr, '#ocp2', value1, NULL) ocp2
            .          ocp3
            .          ocp4
            .
  from fstest
where level <= 2
start with attr = '#server'
connect by prior value1 = name
--group by name

Then you can use a Aggregate function with the Group BY to
get the required no. of rows.
But you should know the values of ATTR before-hand !

December 07, 2001 Lisa -- Thanks for the question regarding "How to alter LMT uniform size to use autoallocate", version 816
You Asked
Currently I am using "EXTENT MANAGEMENT LOCAL UNIFORM SIZE 40K" in
my tablespace definition, spaces grow very quickly. How can I alter
the tablespace and ADD the autoallocate option to my uniform size 40k ?
The Oracle EOM studio GLU software can only let me resize to add more space, all
the other option is gray out. (If I click the storage, the extent management
screen gray out).
s
and we said...
You cannot -- it goes against the very nature of a LMT with uniform extent
sizes.

What you need to do is set up three tablespaces -- small, med and large.  Use a
small extent size on small (say 64k), a med extent size on med (say 512k) and a
big extent size on big (say 5m).

Now, any object you expect to be less then say 50meg, keep it in small.  It'll
always have objects with less then 1,000 extents (which is just fine).

Any object you expect to be less then say 250m (but safely up to 500m), put in
medimum.  They'll have 500-1000 extents max.

Any object you expect to be 4gig or less -- put into large.

Now, you only have to consider objects bigger then 4gig and treat them special.

You can do this easily by creating these three tablespaces and using:

alter table T move tablespace <small|med|large>;

and then

alter index <index on t> rebuild tablespace <small|med|large>;

for each index on t.
Review & Followup
Rating: 4
But, before I create additional TBS December 07, 2001
Reviewer: Lisa from TX
I have serveral owner schema (ie. userA userB ..) they all have same tables
structure (userA.tab, userB.tab), If I create a large tablespace X to hold
userA.tab.
Questions:

1. When I login as userA and do "alter table tab move tablespace X", do I need
any additional attention before I submit the alter statement ?
2. Any future additional records of userA.tab will it go into tablespace X?

3. Because large table 'tab' problem is accross all user schema userA,
userB(same sctructure) ... I need to re-organize them into large tablespace
respectfully, Do I need to create large tablespace for each one of the schema
owner tablespace for hold their own?

Please advise!!!!

Followup:
1) you just need enough room in tablespace X to hold the table.  You might want
to specify an explicit "initial" in a storage clause equal to the size of the
LMT extents in the event the initial in the old tablespace is larger then the
extent of the tablespace you are moving to.

2) yes.

3) you can, but it is not a requirement.

December 07, 2001 Luis -- Thanks for the question regarding "IMPORTING TABLE PARTITION.", version 8.1.5
You Asked
HI, TOM!
Congratulations on your book. I'll receive it in about 4 weeks.
Is there a way to import a partition into the table it once belonged to before?
I've done the
following test. Hope you can take a look at it and answer me the previous
question and
these ones: a) What happened to partition P_JAN? Is it possible to recreate it?
b) Where are the imported rows really located? c) Why did I get the error
IMP-00057?

Thanks in advance. Before I forget : Merry Christmas and happy new year.

Luis C L Nobre
Brasilia, Brazil

SQL> CREATE TABLE TEST (CDRID CHAR (21) NOT NULL, ORIGTIME DATE)
     PARTITION BY RANGE (ORIGTIME)
      (
       PARTITION P_JAN VALUES LESS THAN
         (TO_DATE(' 2001-02-01 00:00:00',
          'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
         TABLESPACE TBLSPACE1,
       PARTITION P_FEB VALUES LESS THAN
         (TO_DATE(' 2001-03-01 00:00:00',
          'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
          TABLESPACE TBLSPACE2
      );

Table created.

SQL> alter session set nls_date_format = 'yyyy-mm-dd';
Session altered.

SQL> insert into test values ('001', '2001-01-01');
1 row created.
SQL> insert into test values ('002', '2001-01-15');
1 row created.
SQL> insert into test values ('003', '2001-02-10');
1 row created.
SQL> insert into test values ('004', '2001-02-10');
1 row created.

SQL> commit;
Commit complete.

SQL> select * from test;

CDRID                 ORIGTIME

--------------------- ----------

001                   2001-01-01

002                   2001-01-15

003                   2001-02-10

004                   2001-02-10

dbrasmis17,oracle,/ora04/sema/export> exp userid=system file=exp_test_pjan.dmp
\n> tables=test:p_jan

Export: Release 8.1.5.0.0 - Production on Mon Dec 3 16:29:08 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Password:

Connected to: Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production
With the Partitioning and Java options
PL/SQL Release 8.1.5.0.0 - Production
Export done in WE8ISO8859P1 character set and WE8ISO8859P1 NCHAR character set

About to export specified tables via Conventional Path ...
. . exporting table                           TEST
. . exporting partition                          P_JAN          2 rows exported
Export terminated successfully without warnings.
dbrasmis17,oracle,/ora04/sema/export>

SQL> alter table test drop partition p_jan;

Table altered.

SQL> select * from test;

CDRID                 ORIGTIME

--------------------- ----------

003                   2001-02-10

004                   2001-02-10

dbrasmis17,oracle,/ora04/sema/export> imp userid=system file=exp_test_pjan.dmp
\n> full=y ignore=y

Import: Release 8.1.5.0.0 - Production on Mon Dec 3 16:44:36 2001

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Password:

Connected to: Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production
With the Partitioning and Java options
PL/SQL Release 8.1.5.0.0 - Production

Export file created by EXPORT:V08.01.05 via conventional path
import done in WE8ISO8859P1 character set and WE8ISO8859P1 NCHAR character set
. importing SYSTEM's objects into SYSTEM
. . importing partition                 "TEST":"P_JAN"          2 rows imported
IMP-00057: Warning: Dump file may not contain data of all partitions of this
table
Import terminated successfully with warnings.
dbrasmis17,oracle,/ora04/sema/export>

SQL> select * from test;

CDRID                 ORIGTIME
--------------------- ----------
003                   2001-02-10
004                   2001-02-10
001                   2001-01-01
002                   2001-01-15

SQL> select partition_name from dba_tab_partitions where table_name = 'TEST';

PARTITION_NAME
------------------------------
P_FEB

SQL> ?????
and we said...
a) What happened to partition P_JAN? Is it possible to recreate it?

well, you dropped it.  Now P_FEB is everything less than
TO_DATE(' 2001-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS',
           'NLS_CALENDAR=GREGORIAN'))

which will include jan data for 2001 in the future.  As soon as you dropped it
-- p_feb became the "low" point in the table.

Yes, you could recreate it -- you would SPLIT the partition P_FEB into two.

b) Where are the imported rows really located?

P_FEB

c) Why did I get the error IMP-00057?

it is not an ERROR, its a warning saying "hey, only some -- and maybe not all --
partitions of the table were in here, beware"...
Review & Followup
Rating: 5
Thanks, Tom! December 07, 2001
Reviewer: Luis C L Nobre from Brazil
I really appreciated your help. Thanks again.

December 07, 2001 Jacques -- Thanks for the question regarding "Substing", version 817
You Asked
Hi Tom,

I have the following data in a table the column contains a country and a city
seperated by a "-" sign

example:

Algeria - Algiers

I need to generate a city code consisting of the first 3 letters of the city eg.
ALG.

Is there a way to use the substr command or something like that to only select
from the data after the "-" sign?

Thanks

j
and we said...
ops$tkyte@ORA817DEV.US.ORACLE.COM> variable field varchar2(25)
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec :field := 'Algeria - Algiers'

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select
      upper(substr( ltrim(substr( :field, instr(:field, '-')+1 )), 1, 3 ))
  2   from dual;

UPP
---
ALG
December 07, 2001 Vinnie -- Thanks for the question regarding "Count & Sum", version 8.1.7
You Asked
Tom,

I would like to create a query that does a sum on a count.

Ie.

I have the following:

SQL> select * from temp;

         A
----------
         2
         3
       3.5
       3.6
         4
       4.1

6 rows selected.

SQL> select trunc(a),count(1) from temp
  2  group by trunc(a);

  TRUNC(A)   COUNT(1)
---------- ----------
         2          1      1
         3          3      4
         4          2      6

How can I get that last field?

Thanks as always
Vinnie
and we said...
(see chapter 12 of my book -- i know you have it ;)

ops$tkyte@ORA817DEV.US.ORACLE.COM> select trunc_x, cnt,
  2         sum(cnt) over ( order by trunc_x range unbounded preceding )
  3    from (
  4  select trunc(x) trunc_x, count(*) cnt
  5    from t
  6   group by trunc(x)
  7         )
  8  /

   TRUNC_X        CNT SUM(CNT)OVER(ORDERBYTRUNC_XRANGEUNBOUNDEDPRECEDING)
---------- ---------- ---------------------------------------------------
         2          1                                                   1
         3          3                                                   4
         4          2                                                   6
Review & Followup
Rating: 3
wouldn't scalar subquery do? December 07, 2001
Reviewer: Mikito Harakiri
select empno, sal,
(select sum(sal) from emp ee where ee.empno <= e.empno)
from emp e

I wonder whether "range unbounded preceding" construct is really necessary.

Followup:
The scalar subquery would be slllooooowwwww on a table of any size.  Try it out,
you'll see.

So, the scalar subquery would "do", but it would be very much less performant.

Yes, range unbounded preceding is the default window (but it sounds so cool, I
hate to leave it out).

Rating: 4
what about ordering of rows May 22, 2003
Reviewer: Asim Naveed from Pakistan
This review is related to the answer of vennie question

the ORDER BY trunc_x should be added at the end of the
query if you want the result to show running sum. Other
wise oracle does not guarantee any specific order.

following is cut/paste from oracle SQL referrence manual.

order_by_clause
Use the ORDER BY clause to order rows returned by the statement. Without an
order_by_clause, no guarantee exists that the same query executed more than
once will retrieve rows in the same order.

Tom,  please correct me if i am wrong.

December 07, 2001 Leon -- Thanks for the question regarding "index on "select" column", version 8.1.6
You Asked
I hope Oracle would use only index to select information from the
table as soon as all information is present in an index, so
 select col2
 from table1
 where col1= value
would use only index as soon as index
CREATE UNIQUE INDEX12  ON table1(COL1, COL2)
exists
Unfortunately statistics for select like that shows that speed of this
query is exactly the same as with index "CREATE UNIQUE INDEX1  ON
table1(COL1)"

Does anybody has good experience in using "index only" (simulating
IOT) queries?
Potentially it should be faster then IOT as soon as indexes could be
cached in memory but IOT can't.

Thanks
Leon

Hi Tom,

As usually I applaud to your attention, fast respond and brake through
suggestions.
Here is my story.
Richard J Niemiec from TUSC recommended to use technique to include “select”
columns into index definition, because of not necessary loop to data structures
as soon as all data are in an index.
Oracle “Expert” some times suggests doing same things without saying why.

As the result I was thinking to suggest to use instead of lookup tables lookup
indexes in data warehousing and include all columns from lookup tables into
index definition as soon as during joint with a fact table all data could come
from index.

I think you agree it is not traditional approach to query analyses and it is not
well documented.

Anyway my test shows that I get performance improvements only with select(1)
queries, not with “select  company name from table where company_id=Value” I
have tested single table select and joints. I have simulated multi user
environment and high load. It did not produce any benefits, actually it slow
down performance probably because of index become larger. Index_FFS was
considerably faster for count(1), but only for queries evolving full table scan.

Anyway I have contacted Richard, but did not get anything new from him with
exemption of “believe me”. I want to make it more like science rather then art.

So my question is basically is about how to verify that table is not in use for
particular select query. How to make sure Oracle actually does index-only
operation?

I would appritiate your respond and I am going to present it to Vancouver OUG.

Thanks
Leon

PS
according to IOT please execute script and see the error message

CREATE TABLE io(a INT, b INT, c INT, d INT,
                primary key(c,b))
ORGANIZATION INDEX
TABLESPACE OPT STORAGE(INITIAL 1M NEXT 1M PCTINCREASE 0 ) CACHE ;
and we said...
Ok, first -- logic dictates that if you are running a query and all we have to
do is process the index -- it will be FASTER then doing the index and then the
table.

It is evident that the buffer cache will be more efficient -- as we do not have
to cache the table blocks.

*it is faster*.

Here is an example.  I have an 8k blocksize.  I have 300 block buffers (wanted
to really exaggerage this for you).

I did:

REM
REM create table t ( x int, y int, a char(2000) default '*',
REM                  b char(2000) default '*', c char(2000)
REM                 default '*' );
REM
REM
REM insert /*+ APPEND */ into t (x,y) select rownum, -rownum
REM from all_objects where rownum <= 5000
REM /
REM
REM create index t_dx on t(x,y)
REM /
REM
REM

and that created 5000 rows.  Then I ran:

alter session set sql_trace=true;
declare
    l_y int;
begin
    for i in 1 .. 5000
    loop
        select y into l_y from t t1 where x = i;
    end loop;
end;
/

drop index t_dx;
create unique index t_dx on t(x)
/

declare
    l_y int;
begin
    for i in 1 .. 5000
    loop
        select y into l_y from t t2 where x = i;
    end loop;
end;
/

Now, the tkprof from that shows me:

SELECT Y
FROM
 T T1  WHERE X = :b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.01          0          0          0           0
Execute   5000      0.36       0.36          0          0          0           0
Fetch     5000      0.30       0.42         14      10013          0        5000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    10001      0.67       0.79         14      10013          0        5000

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 397     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
   5000  INDEX RANGE SCAN (object id 32885)

********************************************************************************

SELECT Y
FROM
 T T2  WHERE X = :b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.01       0.01          0          0          0           0
Execute   5000      0.35       0.33          0          0          0           0
Fetch     5000      1.13      10.89       5041      15000          0        5000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    10001      1.49      11.23       5041      15000          0        5000

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 397     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
   5000  TABLE ACCESS BY INDEX ROWID T
  10000   INDEX UNIQUE SCAN (object id 32886)

So, the table access by rowid added lots to the CPU time -- and since I forced a
small buffer cache, really showed off the speedup with regards to that.

There is no doubt there -- using the index instead of the index access to the
table paid off rather handsomely.

Now, I did the same thing again, only this time I used a 7000 block buffer cache
just to see what the difference would be with the table in cache:

SELECT Y
FROM
 T T1  WHERE X = :b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute   5000      0.35       0.34          0          0          0           0
Fetch     5000      0.28       0.76         14      10013          0        5000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    10001      0.63       1.10         14      10013          0        5000

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 397     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
   5000  INDEX RANGE SCAN (object id 32887)

********************************************************************************

SELECT Y
FROM
 T T2  WHERE X = :b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute   5000      0.32       0.30          0          0          0           0
Fetch     5000      0.34       1.00         25      15000          0        5000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    10001      0.66       1.30         25      15000          0        5000

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 397     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
   5000  TABLE ACCESS BY INDEX ROWID T
  10000   INDEX UNIQUE SCAN (object id 32888)

********************************************************************************

Now, not nearly as dramatic but consider -- when was the last time you could
dedicate your entire buffer cache to a SINGLE table?  In a "real" system - you
will achieve some performance in between the two of these tests.

You'll never get the speed up of the first one (probably -- maybe on a really
tight system).

You'll never have the true closeness of the second one.

It'll be somewhere in between.

As of the IOT -- that is the "cache" attribute of a table.  It does not mean
in any sense that IOTs are not cached.

The CACHE attribute of a table dictates how Oracle will buffer the blocks after
a FULL TABLE SCAN.  Normally, the blocks read from a full table scan of a LONG
table are put into the buffer cache in a manner that makes them be the first
blocks to get OUT of the buffer cache.  This is to avoid a full scan totally
wiping out your buffer cache.  As you read through the table, you start
replacing the data you just read in the buffer cache -- instead of other older
data.

The CACHE attribute changes that.  It makes Oracle treat the table like a
"short" table and puts the blocks into the buffer cache in such a way that they
are NOT the first to get thrown out.

IOTs don't have the LONG/SHORT table issue -- hence the cache attribute doesn't
apply.

That does not mean in any sense that IOTS are NOT cached!!!.  A simple
example will show that:

tkyte@TKYTE816> create table t ( object_id primary key, object_name, owner )
  2  organization index
  3  as
  4  select object_id, object_name, owner from all_objects;

Table created.

tkyte@TKYTE816> select count(*) from t;

  COUNT(*)
----------
     22054

tkyte@TKYTE816> alter session set sql_trace=true;

Session altered.

tkyte@TKYTE816> select count(*) from t;

  COUNT(*)
----------
     22054

select count(*)
from
 t

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.01       0.01          0        130          4           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.01       0.01          0        130          4           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 397

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
  22054   INDEX FAST FULL SCAN (object id 32890)

no physical IO's -- that IOT is cached.
Review & Followup
Rating: 5
index-only query June 06, 2001
Reviewer: A reader from Vancouver, BC, Canada
Thanks a lot for excellent research. I appreciate your feedback.

Rating: 5
November 20, 2001
Reviewer: Helena Markova from Bratislava, Slovakia

Rating: 3
index on "select" column December 07, 2001
Reviewer: Subra from San Francisco, CA USA
Tom, Hats Off to your wonderful way of explanation.
Here is a scenario I found baffling.
Our database is configured to do RULE based optimation.
I have a table T (a, b, c, ... columns) with about 600K records, and with a
primary index on columns a, and b.  My following query is selection columns from
the primary index only, but the query plan is showing TABLE_SCAN. Can you please
explain why ?

SELECT COUNT(*) FROM T;
Count: 600000

EXPLAIN PLAN
SET STATEMENT_ID = 'expl2' FOR
        SELECT  DISTINCT a, b        FROM    T ;

SELECT substr(LPAD(' ',2*(LEVEL-1))||operation,1,20) operation,
substr(options,1,15) options,
substr(object_name,1,25) object_name, substr(to_char(position),1,5)
position,cost
FROM plan_table
START WITH id = 0
AND statement_id = 'expl2'
CONNECT BY PRIOR id = parent_id AND
statement_id = 'expl2';

OPERATION            OPTIONS         OBJECT_NAME               POSIT COST
-------------------- --------------- ------------------------- ----- ----------
SELECT STATEMENT
  SORT               UNIQUE                                    1
    TABLE ACCESS     FULL            T_IDB_ACCT_LIST           1

Since all the required columns are existing in the index, I would imagine the
efficient way to process this query is by using the index.  But somehow it is
doing FULL TABLE scan. I appreciate your help in understanding this scenario.

Thanks Much !
Subra

Followup:
Use the CBO, it is much smarter then the RBO and has more ways to access the
data.  The fast full scan of the index is available to the CBO.

Rating: 5
Just great tom. December 07, 2001
Reviewer: Sean Bu from atlanta

Rating: 4
But if there's both... May 03, 2002
Reviewer: Jon from CT, USA
Tom,  I found this while researching to see if Oracle will retrieve data from
the index if it can.  You seem to suggest it will.  But in your example, you
drop the one index and create a new one.  What if you have both?  The data below
tells me that it could still go to the table, even if it could get the data only
from the index.  Am I wrong?  Thanks as always for your excellent work (and also
for your crusade against u, ur, etc.)!

11:18:59  ==>  select y from t1 where x = 5;

        Y
---------
       -5

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   INDEX (RANGE SCAN) OF 'T_DX'

Statistics
----------------------------------------------------------
         29  recursive calls
          0  db block gets
          7  consistent gets
          1  physical reads
          0  redo size
        177  bytes sent via SQL*Net to client
        126  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

11:19:16  ==> create unique index t_dx2 on t1(x);

Index created.

11:19:30  ==> select y from t1 where x = 5;

        Y
---------
       -5

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T1'
   2    1     INDEX (UNIQUE SCAN) OF 'T_DX2'

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          1  physical reads
          0  redo size
        177  bytes sent via SQL*Net to client
        125  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

December 08, 2001 Partha -- Thanks for the question regarding "sequence Question", version 8.1.6
You Asked
Tom,

I have interesting question.

I wrote a Trigger AS follows...

CREATE or REPLACE TRIGGER MJ_ST_TRIGGER
BEFORE INSERT ON MJ_STS
FOR EACH ROW
BEGIN
    SELECT MOR_SRM_SEQ.nextval INTO :new.s_id FROM dual;
END;

my questions for above trigger are
1) First i insert a record into MJ_STS Table then trigger fired and inserted the
1.

2) i went to sql*plus and i executed statement as..
select MOR_SRM_SEQ.nextval FROM dual;

then the value i saw is 2

3) then again i inserted second record into MJ_STS Table, right now my sequence
number should be 2, not 3 why i'm getting 3.

can you please give me the explaination and to avoid missing sequence numbers,
how should i solve above???

4) i tried to used following, does it solve my problem
lmf@pm1> create or replace trigger mj_trigger
  2     before insert on major_storms for each row
  3     begin
  4          :new.s_id := next_val( 'MY_SEQ' );
  5     end;
  6  /

Warning: Trigger created with compilation errors.

lmf@pm1> show err
Errors for TRIGGER MJ_TRIGGER:

LINE/COL ERROR
-------- ----------------------------------------------------
2/9      PL/SQL: Statement ignored
2/22     PLS-00201: identifier 'NEXT_VAL' must be declared
--------

thanks in advance
and we said...
3) why do you believe it should be 2?  Everytime you call NEXTVAL, it gives you
a number and the next call to nextval by definition CANNOT return that same
number (else you would get dups).  The database cannot tell you did not "use"
the nextval you selected in sqlplus.  If you wanted to see where the sequence
"was" you should have used currval.

3 is the correct answer here.

There is (and I'll say this really loud) no way to use a sequence to generate
a gap free sequence of numbers, it is not possible, do not even attempt it, do
not count on it, change the requirment if you have one to have a gap free
sequence of numbers.

Sequences will generate gaps no matter what, it only takes one rollback and
instant gap.

4) did you write a function next_val?? if not, there is no such function in your
database.
Review & Followup
Rating: 3
Sequence issue December 07, 2001
Reviewer: A reader

Rating: 4
Gap Free Sequence Possibility December 07, 2001
Reviewer: Chip from Denver, CO
If a table column is populated with a sequence number,
can a SQL query using RANK over the table column be
used to return a gap free list of numbers ?

If so, could the RANK numbers be used to replace the
sequence generated numbers in the table column ?

Followup:
Rank is assigned on the fly to the rows, the next time you query the data -- if
there have been inserts/updates/deletes -- the rank assigned to any given row
will potentially be different.

You use sequences to generate surrogate primary keys, unique identifiers. They
are static identifiers that you can use to "find" that row time and time again.
we should attribute nothing more or less to them (eg: any qualities like "gap
free".  Heck -- they do not even imply order of insertion (they might
APPROXIMATE it but in a concurrent system or OPS they certainly don't imply or
assure it).

December 08, 2001 Munzer -- Thanks for the question regarding "Loops Efficiency", version 8i
You Asked
Tom:

Which is a better solution when using SQL query in PL/SQL program:

1.  Create a cursor for SQL query and then use a "for cursor loop"
to print results out.

2.  or doing

For x in (Select * from tab)
Loop
htp.p(x.col)
end loop;

Do you recommend programming using cursors or as #2.

Thank you,
and we said...
search for

explicit implicit

on my site.

I *love* implicit cursors:

  for x in ( select * from t )
  loop
    ....

they are

o faster (code runs faster)
o easier to code
o easier to read
o leave less chance for me to code a bug (less code = less opportunity to screw
it up)

I use explicit cursors:

   open
   loop
      fetch
      exit when ...
   end loop
   close

only when forced to (eg: when I must use a ref cursor).  They are

o slower (code runs slower)
o harder to code
o harder to read
o give ample opportunity to screw things up.
December 08, 2001 Mikito -- Thanks for the question regarding "hierarchical query on dba_dependencies ", version 9i
You Asked
I'm trying to find all the objects that my view uses like this:

select lpad(' ',(level-1)*2)||name||'('|| type || ')' from dba_dependencies
where level <2
connect by prior referenced_owner=owner
and referenced_name=name
start with name = 'DBA_VIEWS'

but oracle tell's me that there is a loop in the data. Clearly, it executes
hierarchical query first, so that even putting a condition, say, "level < 4"
doesn't help. Any workaround?

Also, any query against dba_dependencies is so slow, espetially on large
database. Is dba_dependencies tuned at all?
and we said...
Well, all of the objects you view uses is the first level only (and there can be
cyclical dependencies in this view, its not a good candidate for this)

It is a slow view.  If you look at it, is a view of some other views, some of
which are union all views of many tables.  It is tuned -- its just a VERY hard
question you are asking (the dba_dependencies question is a hard question to
answer).  The data dictionary is stored for operational access, not "data
mining", so this one's performance is impacted by that.

So, the question becomes: can we satisfy your desired goal in some way without
changing the data dictionary, they way oracle works etc..... Yes, I believe we
can:

ops$tkyte@ORA9I.WORLD> create or replace type myScalarType as object
  2  ( lvl       number,
  3    rname  varchar2(30),
  4    rowner varchar2(30),
  5    rtype  varchar2(30)
  6  )
  7  /

Type created.

ops$tkyte@ORA9I.WORLD> create or replace type myTableType as table of
myScalarType
  2  /

Type created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> create or replace
  2  function depends( p_name  in varchar2,
  3                    p_type  in varchar2,
  4                    p_owner in varchar2 default USER,
  5                    p_lvl   in number default 1 ) return myTableType
  6  AUTHID CURRENT_USER
  7  as
  8      l_data myTableType := myTableType();
  9
 10      procedure recurse( p_name  in varchar2,
 11                         p_type  in varchar2,
 12                         p_owner in varchar2,
 13                         p_lvl   in number )
 14      is
 15      begin
 16          if ( l_data.count > 1000 )
 17          then
 18              raise_application_error( -20001, 'probable connect by loop,
aborting' );
 19          end if;
 20
 21          for x in ( select /*+ first_rows */ referenced_name,
 22                                              referenced_owner,
 23                                              referenced_type
 24                        from dba_dependencies
 25                      where owner = p_owner
 26                          and type = p_type
 27                          and name = p_name )
 28          loop
 29              l_data.extend;
 30              l_data(l_data.count) :=
 31                     myScalarType( p_lvl, x.referenced_name,
 32                                   x.referenced_owner, x.referenced_type );
 33              recurse( x.referenced_name, x.referenced_type,
 34                       x.referenced_owner, p_lvl+1);
 35          end loop;
 36      end;
 37  begin
 38      l_data.extend;
 39      l_data(l_data.count) := myScalarType( 1, p_name, p_owner, p_type );
 40      recurse( p_name, p_type, p_owner, 2 );
 41      return l_data;
 42  end;
 43  /

Function created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> set timing on
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> select * from table(
cast(depends('DBA_VIEWS','VIEW','SYS') as myTableType ) );
LVL RNAME           ROWNER    RTYPE
--- --------------- --------- ---------------
  1 DBA_VIEWS       SYS       VIEW
  2 TYPED_VIEW$     SYS       TABLE
  2 USER$           SYS       TABLE
  2 VIEW$           SYS       TABLE
  2 OBJ$            SYS       TABLE
  2 SUPEROBJ$       SYS       TABLE
  2 STANDARD        SYS       PACKAGE

7 rows selected.

Elapsed: 00:00:00.42
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> drop table t;

Table dropped.

Elapsed: 00:00:00.13
ops$tkyte@ORA9I.WORLD> create table t ( x int );

Table created.

Elapsed: 00:00:00.03
ops$tkyte@ORA9I.WORLD> create or replace view v1 as select * from t;

View created.

Elapsed: 00:00:00.06
ops$tkyte@ORA9I.WORLD> create or replace view v2 as select t.x xx, v1.x yy from
v1, t;

View created.

Elapsed: 00:00:00.06
ops$tkyte@ORA9I.WORLD> create or replace view v3 as select v2.*, t.x xxx, v1.x
yyy from v2, v1, t;

View created.

Elapsed: 00:00:00.07
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> select lpad(' ',lvl*2,' ') || rowner || '.' || rname ||
'(' || rtype || ')' hierarchy
  2    from table( cast(depends('V3','VIEW') as myTableType ) );
HIERARCHY
---------------------------------------------------------------------------------
--------------------------------------------------
  OPS$TKYTE.V3(VIEW)
    OPS$TKYTE.T(TABLE)
    OPS$TKYTE.V1(VIEW)
      OPS$TKYTE.T(TABLE)
    OPS$TKYTE.V2(VIEW)
      OPS$TKYTE.T(TABLE)
      OPS$TKYTE.V1(VIEW)
        OPS$TKYTE.T(TABLE)

8 rows selected.

Elapsed: 00:00:00.47
ops$tkyte@ORA9I.WORLD>

(note: this in was in Oracle9i -- in 8i, the query doesn't go quite as fast, I
didn't tune it for that release, that would be an exercise for the reader...)
Review & Followup
Rating: 5
missed connect by predicate December 08, 2001
Reviewer: Mikito Harakiri
I actually missed

by prior referenced_type=type

predicate. Now, there is no loops anymore, but it doesn't affect performance, of
course.

I don't quite understand what you mean by "operational access vs. data mining".
When invalidating an object, oracle is able to invalidate all the dependent
objects reasonably fast. My query is logically the same thing, so in theory I
must be able to tune it. You demonstrated that rewriting the query achieves the
goal, but more challeging question is if the query can be tuned without
rewriting with standard incremental evaluation techniques (indexes, MVs, etc).

Followup:
They take a procedural approach, not a set based on.  Infrequently, this is
faster, this is one of those cases.

Besides, at the low level, the data dictionary is "object ids", "user ids",
"type codes".  The Object Names, Usernames and Typenames are convienences for us
humans.  Operationally -- the data is all numbers.  Conceptually, we view this
data with readable names.  Hence the operational data is not optimally stored
for us to query in this case, but it is optimially stored for them to do their
transactions.

December 08, 2001 Bhavani -- Thanks for the question regarding "pl/sql Tables", version 8.1.7
You Asked
Hi Tom,

We use some temporary database tables, in certaion procedures.  Once that
procedure is done, that table is not used for any other purpose, till again this
procedure is executed.  Some one said, pl/sql Tables will be used effectively
for this purpose.

Can you please explain this with a simple example.

Thanks and Best Regards

Bhavani
and we said...
PLSQL tables are like arrays, not like tables.  Global temporary tables are like
tables, not like arrays.  Hence they are sort of "apples" and "toaster ovens".
They serve different purposes.  Much like the analogy "if all you have is a
hammer -- everything must be a nail", if I limit myself to one of them I can
probably use it -- but you should use each in turn when they are appropriate.

I do not see how you would use them in place of global temporary tables.  Since
global temporary tables consume space if and only if they are being used, having
them when you are not running the proceudre adds zero overhead to your system.
Use the global temporary tables if they are appropriate.  Use PLSQL tables if an
ARRAY is a more appropriate construct.
December 08, 2001 ajay -- Thanks for the question regarding "about the insert", version 8.1.5
You Asked
hai tom,

let me know how the data will store in the databse, and i want to know how to
store the data in sequence wise in the database that is internally.
if i give insert
insert into emp values(1,'ajay');
insert into emp values(4,'sanjay');
insert into emp values(3,'satya');
insert into emp values(2,'saha');

i want to store it in the sequence even though i enter in irregular ways after
commit or before commit.
empno name
1     ajay
2     saha
3     satya
4     sanjay
in the database how it is possble please explain me in detail.

thank u
tom
and we said...
(if you have my book, read the chapter on tables and read about index organized
tables -- tons of detail there).

If you:

create table emp ( empno number primary key, ename varchar2(10) ) ORGANIZATION
INDEX;

you will achieve physical ordering of the data on disk.  Otherwise, in a heap
table we put the data where ever we find space.
Review & Followup
Rating: 4
December 08, 2001
Reviewer: Jim Kennedy from Portland, OR USA
While one can store the data in an index organized table (Great book BTW) one
should not rely on the order of the result set unless one specifies the order in
the query.

Thus whether it is an index organized table or not

select * from emp

may return a different result than :

select * from emp order by empno;

Followup:
That rule is 100% correct -- words to live by.

With regards to an IOT however -- a full index scan of it will in fact return
the data in sorted order (by primary key).  Its documented behavior for this one
object.

So yes

o an IOT will store it in "sequence"
o an index full scan of the IOT will return it "sorted by primary key"
o you should also use an order by to assure yourself the data is returned
sorted, if we don't have to sort, we won't but if we access the data
differently, we will sort it for you ensuring the data is returned to you as you
expect it.

December 08, 2001 Bhavani -- Thanks for the question regarding "Table Partitioning", version 8.1.7
You Asked
Hi Tom,

We have some tables which will grow very fast say, 10000 rows per day.  Table
Partitioning on date field really doesn't work.  Basically, we want a partition
for every 3 months and you know its really not possible to define 40 partitions
for 10 years.  And even if we define like that, what will happen after 10 Years
(Some one says, i am thinking too much, but we should make systems as completely
as possible).

Is there any way in oracle, so that, oracle will create table partition
automatically (don't say use dbms_job and run a procedure in that job which uses
execute immediate or Native dynamic sql to create the new partition) for every 3
months without manual intervention.

Thank you very much.

Regards

Bhavani
and we said...
Why is it not really possible??? That doesn't make sense to me.  40 partitions
is nothing, it is totally possible, probably, doable and is done by people.

Why cannot I say "use dbms_jobs", what is wrong with that.  If you don't want to
hear how to do it, don't ask -- but don't limit my responses.  If you take away
the tools, what do you expect me to be able to do?  The answer to your question
IS to use dbms_job (but then again, just create 40 partitions, its not only
POSSIBLE, its very doable)
Review & Followup
Rating: 3
Table Partitioning December 08, 2001
Reviewer: A reader
Hi Tom,

We have got More than one DBA at different locations, and some one by mistake
removed a Procedure from DBMS_JOB Package.  We found that after nearly 1 Month.
Thats why i obviously expected some other way other than Using DBMS_JOB.  (At
least System Parameters will not be changed without knowing what it really means
by any DBA)  I don't want to limit your responses, rather i am expecting other
way to do it.

And again you are right, we can always create 40 partitions.  But i want a way
to do it by oracle Automatically with out any manual intervention.

Thanks for your response and Best Regards

Bhavani

Followup:
You cannot remove a procedure from the DBMS_JOB package.

Perhaps you mean they removed a job.  However, if they are so careless as to do
this, there is NOTHING we can do in any way shape or form to help you.  They can
mess anything up.

I disagree with your statement "At least System Parameters will not be changed
without knowing what it really means by any DBA".  If there are ignorant of the
system they are maintaing and remove jobs "just because", they'll be ignorant of
Oracle as well and do things just because.  "Oh I didn't know you needed that
set".

Even if Oracle had a "create me a new partition every three months" -- you know
how we would do it?  We would schedule a job, a job in the schema that owns
table.  Just like we do for snapshot refreshes.  You are back at square one.

In order to create the partitions automatically, you'll use DBMS_JOB.  You will
train or otherwise get rid of your "DBA who removes jobs and doesn't think to
tell anyone".   That DBA has already proven themselves to be a liability -- fix
that problem, DON'T stop using a feature because someone did something stupid
once upon a time.  If we all did that, we'd be back to the abacus for computing.

Don't compound that DBA's mistake with another mistake of your own of equal OR
GREATER proportions.  Use DBMS_JOB -- thats how it is done.  Period.  You have a
rather unique requirement:  every three months, create a new partition.  Where
does that partition go?  Why three months?  We cannot give you a "create"
command to fill in all of these blanks, we must one time script it and then
schedule it.

Rating: 5
true indeed December 08, 2001
Reviewer: A reader
you have to do it either way by dbms_job, crontab or control-m whatever tool is
good but you definitely have to do it with a schedule!
40 partition is nothing, we have over 1200 in our datawarehouse

December 08, 2001 Bhavani -- Thanks for the question regarding "Data Encryption", version 8.1.7
You Asked
Hi Tom,

I believe, when we are communicating with Oracle server from a client using
SQL/Plus, except username / password, every other data will be sent as plain
text (Sorry if i am wrong).

Is there any way to send every data in encrypted form to the server and receive
in the same form from the server?

Thanks & Regards

Bhavani
and we said...
you want advanced security.
http://www.oracle.com/ip/deploy/database/oracle9i/index.html?se_advsecurity.html
....
December 09, 2001 Munzer -- Thanks for the question regarding "Database Design", version 8i
You Asked
Tom:

1.  I am designing a database for order entry.  I have a table PO (po_no,
po_date, po_status) and another child table (po_no, stock_no,stock_desc,qty,
unit).  Because a user may not find a stock_no in a reference table (for all
stock numbers) he can enter a '999999' for any stock number and then enter his
own description for it.

Since I had to have a primary key I added an "item_no" for each item on the po
so i can have (PO_no, item_no,stock_no) as primary key.  Is this a good design
or there is a better way?

Problem with this is that user has to manually enter the item number on the form
sicne i can not have a sequence that increases per PO, meaning if there are 10
items on the po it will go from 1 to 10 and then reset to start back again at 1.

Would it be better just to have  a (one column) sequence number as a unqiue
identified in the child table?

2.  I am letting the user enter the info using an HTML form creatd by PL/SQL
procedure.  IS there a way for a user when he selects the stock number from a
drop-down list the description will pop out automatically in the description
field.  DO you have to submit for with all data entered, find a description for
that stock number and return all values again when running another procedure.  I
do not think this is a good way of doing it?
and we said...
1) since this item_no is meaningless, only present to ensure uniqueness, why
does it have to go from 1..10.  Why isn't it good enough just to be UNIQUE???

Use a sequence, it matters not if it goes from 1..10.  You can always get 1..10
when you query if you want:

select child_table.*, row_number() over ( order by item_no )
  from child_table
 where po_no = :bind_variable;

2) see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:234614318676
...


Subject | Article | Last Updated (East coast time)
Error while loading Activation8i.jar using loadjava | article only | Dec 10, 2001 04:26 pm
bind variable in dynamic sql | article only | Dec 10, 2001 08:12 pm
error, outlines, and updates | article only | Dec 11, 2001 02:32 pm
Recovery Recovery | article only | Dec 11, 2001 04:57 pm
Fetching email into a database | article only | Dec 12, 2001 09:33 am
Script to generate and insert sample data values into a table | article only | Dec 13, 2001 08:27 am
Migrating database from US7ASCII to UTF8 | article only | Dec 13, 2001 08:37 am
How can I do the following - tks | article only | Dec 13, 2001 10:58 am
trying to create a script for creating indexes for all foreign keys | article only | Dec 13, 2001 01:48 pm
dbms_tcp | article only | Dec 14, 2001 07:19 am
How to find Information about Indexes !! | article only | Dec 14, 2001 05:49 pm
Decode function | article only | Dec 15, 2001 01:14 pm
PL/SQL execeptions | article only | Dec 15, 2001 04:19 pm
row(s) 1 - 13 of 13
December 10, 2001 Sridevi -- Thanks for the question regarding "Error while loading Activation8i.jar using loadjava", version Oracle 8.1.7
You Asked
Hi,
  I am trying to send email from a form  by using java with
  PL/SQL. I have installed Javamail and Javabeans from Sun.
  But I was having problems as I was not able to load class
  'javax\mail\internet\MimeBodyPart'.

  I read an article that you had written and I uploaded the same
  jar files form your article.
  I am trying to load activation8i.jar in to the database from
  the command line using
  loadjava -u sys/psswd@db -o -r -v -g (user name)
          c:\invfax\activation8i.jar.
 I get this error:
'SQL error while connecting with oci8 driver to db: ORA-01031:
 insufficient privileges.
  Could not open connection.
  loadjava: 2 errors'.

I can see the jar file being executed and when it comes to
resolving the above mentioned class it says that it has already
been resolved and hence it is skipping it.

When I try doing this using 'System' it works fine with out any
errors. But I am not able to load the above class . I need this
as my java code is not compiling as it can not find a method
that is in this class.

Also I noticed that I do have a class MimeBodyPart but that has
a number_ before its name and not 'javax'.

Could you please help me troubleshoot this error?

I am new to Java and I am trying to learn and troubleshoot at
the same time.

Thank You..
and we said...
If you goto
http://java.sun.com/products/javamail/index.html
 you¡¦ll be able to download their Java Mail
API.  The download you get will consist of a couple of hundred
files ¡V only one of which we are interested in.  After you
download the Java mail API ¡V make sure also to get their the
JavaBeansTM Activation Framework extension or JAF
(javax.activation).   This is needed to run the Java mailapi
package.

After you have downloaded these two sets of files ¡V you will
need to extract mail.jar from the Java mailapi download and
activation.jar from the JAF download.  This is all you will need
from this ¡V feel free to read through the documentation, there
is a lot of functionality in there we are not using, we are just
using the ¡§send an email¡¨ part of the API.  The API includes
functions for receiving mail as well from IMAP, POP and other
sources.

We will need to load the mail.jar and activation.jar into the
database using loadjava but before we can do that we must
repackage them.  These jar files are compressed in a format that
is not understood by the database byte code interpreter.  You
need to ¡§unjar¡¨ and ¡§rejar¡¨ them without compression OR use
a tool such as WinZip to ¡§rejar¡¨ them into a zip file.  What I
did on Windows 2000 was:

1. Used WinZip to extract the contents of mail.jar into my
c:\temp\mail directory
2. Used WinZip to create a new archive c:\temp\mail8i.zip
3. Put the contents of c:\temp\mail\*.* including subdirectories
into this new archive

I did the same thing for activation.jar ¡V only replacing mail
with activation in the above steps.  Now we are ready to load
these zip (or jar files, whatever you named them) into the
database. These need to be loaded using the SYS user since they
have 'protected' Java packages that regular users cannot upload.
 We will use the commands:

loadjava -u sys/manager -o -r -v -f -noverify -synonym -g public
mail8i.zip
loadjava -u sys/manager -o -r -v -f -noverify -synonym -g public
activation8i.zip

Where:

ƒá -u sys/manager: is the userid and password for your SYS
account.  As stated previously, some of the packages are
protected and must be loaded as SYS

ƒá -o: is shorthand for -oci8, I am using the oci8 driver.  You
could use the thin driver as well but you¡¦ll need to modify the
the command to do so

ƒá -r: is short for ¡Vresolve.  This will resolve all external
references in the loaded classes helping to verify that the
loaded java classes will be able to function after we load them

ƒá -v: is short for ¡Vverbose.  This gives us something to do
while loadjava is running.  We can see it work through each step
of its process.

ƒá -f: is short for ¡Vforce.  This isn¡¦t necessary on the first
load but is OK to use.  If you try a load and hit and error,
correct it and reload ¡V then you would either need to dropjava
the jar file or use ¡Vforce.  Using ¡Vforce just makes it easier
for us.

ƒá -noverify:  does not attempt to verify the bytecode. You must
be grantedoracle.aurora.security.JServerPermission(Verifier) to
execute this option. In addition, this option must be used in
conjunction with -r.  SYS has this privilege.  This is needed
because the bytecode verifier will flag some issues with the
mail.jar file and this works around that issue.

ƒá -synonym: creates public synonyms for these classes.  Since
we will NOT install the mail java code we write as SYS, this
allows us to ¡§see¡¨ the SYS loaded java classes.

ƒá -g public: grants execute on these loaded classes to PUBLIC.
If this is not desirable, change the ¡Vg to be just the user you
want to create the ¡§send mail¡¨ routines in, for example ¡§-g
UTILITY_ACCT¡¨.
Review & Followup
Rating: 4
But is this always the result of the archive format? December 10, 2001
Reviewer: Daryl from Dallas
I'm having a similar problem. I've repackaged all the Sun stuff into their own
ZIP archives, without compression. They load fine on my Windows NT and Solaris
boxes. But at another site, running Oracle 8.1.7 under HP-UX, I get this error
--------------------------------
could not open connection
loadjava: 2 errors
SQL Error while connecting with oci8 driver to my_db_name:
ORA-01031: insufficient privileges
--------------------------------

I'm able to connect as sys to the my_db_name databases,
so I'm really puzzled as to what's going on here. All the Metalink docs
(searching on "ORA-01031" and "loadjava") point to some kind of permissions
problem, but everything in the HP-UX database looks the same as my Windows
databases.
(e.g., DBA_JAVA_POLCY and DBA_SYS_PRIVS return the same data for the SYS user).

Other ideas?

Followup:
can you give me an example? (i've personally loaded the stuff above into 817
HP/UX) tell me where to get the jar and I'll try loading it myself.

Rating: 4
Here's what you want December 10, 2001
Reviewer: Daryl from Dallas
I've put activation.zip (no compression) at
http://www.superserve.com/~darylb/pics/activation.zip

      Rating: 4
TNS is the
      problem  December 11, 2001
Reviewer:  Daryl
       from Dallas
It turns out that the problem had to do with the TNS connection string. If the
person doing the install specifies "loadjava -user
sys/sys_password@my_db.company.com ...", it doesn't work.
Doing the operation from the server machine itself (via
telnet/ssh), setting the ORACLE_SID (and friends) and
doing "loadjava -user sys/syspassword ... " it DOES work.
loadjava simply isn't conveying the REAL information as to what happened.

December 10, 2001 Lucy -- Thanks for the question regarding "bind
      variable in dynamic sql", version 8.1.6

      You Asked
One of our developer wrote a stored procedure like

IF (objectname = 'PROJECT')
               THEN
                  EXECUTE IMMEDIATE    'select '
                                 || I_fieldname
                                 || ' from project where roject_id = '
                                 || projectid
                     INTO t_text;
which I_fieldname is the input parameter which could be some column of the
project table, I don't think he uses the bind vaiable at all, but how can we
convert the code into bind variable?

Thanks

      and we said...
Simply code:

if ( objectname = 'PROJECT' )
then
   execute immediate 'select ' || i_fieldname ||
                      ' from project
                       where project_id = :project_id'
      into t_text
     using projectid;
end if;

Review &
      Followup

      Rating: 5
Bind variables
      in Native Dynamic SQL  June 20, 2002
Reviewer:
      A reader  from Australia
Just what I needed - a useful example

December 11, 2001 Nag -- Thanks for the question regarding "error,
      outlines, and updates", version 8.1.7

      You Asked
1.hOW should I execute a script like this from the sqlplus prompt

set feedback off
set heading off
set termout off
set linesize 1000
set trimspool on
set verify off
spool &1..sql
prompt set define off
select decode( type||'-'||to_char(line,'fm99999'),
               'PACKAGE BODY-1', '/'||chr(10),
                null) ||
       decode(line,1,'create or replace ', '' ) ||
       text text
  from user_source
 where name = upper('&&1')
 order by type, line;
prompt /
prompt set define on
spool off
set feedback on
set heading on
set termout on
set linesize 100

Iam getting the error

SQL> /
set feedback off
    *
ERROR at line 1:
ORA-00922: missing or invalid option

saving it in a file , and running it from the prompt , is not working.

2.how should I update 4 columns in table t , with values coming from other
different tables t1 and t2.

Actually what are the different ways of doing it.

3.what is meant by  'storing an execution plan for a query using stored
outlines'
What are outlines.

Thanks

      and we said...
1) put:

set feedback off
set heading off
set termout off
set linesize 1000
set trimspool on
set verify off
spool &1..sql
prompt set define off
select decode( type||'-'||to_char(line,'fm99999'),
               'PACKAGE BODY-1', '/'||chr(10),
                null) ||
       decode(line,1,'create or replace ', '' ) ||
       text text
  from user_source
 where name = upper('&&1')
 order by type, line;
prompt /
prompt set define on
spool off
set feedback on
set heading on
set termout on
set linesize 100

into a file (i call it "getcode.sql" ) and run:

SQL> @getcode your_procedure_name

2) update t
      set (c1,c2,c3,c4) = ( select t2.c1, t2.c2, t3.c3, t3.c4
                               from t2, t3
                             where t2.x = t1.x and t2.y = t3.y )
     and exists ( select t2.c1, t2.c2, t3.c3, t3.c4
                               from t2, t3
                             where t2.x = t1.x and t2.y = t3.y )

is one method...

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1408003858195
shows another

3) see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76992/outlines.htm#13547
also, i have an entire chapter on this topic in my book if you need more
details.

Review &
      Followup

      Rating: 3
updating a
      table using procedure that reads values from disk  December
      10, 2001
Reviewer:  Godwin  from Ghana
Can I also update  columns in table t , with values coming from records stored
on floppy disk?

          Followup:

see

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1615330671789
... in 9i, yes.  In 8i and before -- yes but you would have to write PLSQL code
using UTL_FILE to read the file..

      Rating:
      4
  December 11, 2001
Reviewer:  Scott
       from Chicago
wrt #2, Tom's solution works just swell but you may see a nice performance
increase (depending on your data) by doing this in PL/SQL

BEGIN
  FOR rec IN
  ( select t2.c1, t2.c2, t3.c3, t3.c4
      from t2, t3
     where t2.x = t1.x and t2.y = t3.y )
  LOOP
    UPDATE t
       SET (c1,c2,c3,c4) = (rec.c1, rec.c2, rec.c3, rec.c4 );
  END LOOP;
END;

cheers,
Scott

          Followup:

Thats just updating a join (well, if you correct your update statement to have a
predicate it would be anyway -- I THINK you meant to select out the rowid or
primary key), which is better accomplished via the link I provided:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1408003858195
in a single statement!!!

update ( select t1.c new_value, t2.c old_value
           from t1, t2
          where t1.primary_key = t2.primary_key )
  set old_value = new_value
/

never do procedurally what you can do in a single statement i always say.

December 11, 2001 Gururaj -- Thanks for the question regarding
      "Recovery Recovery", version 7.x Or 8.x

      You Asked
Hi Tom,

1)How can I use Cold backup files to recover a dropped table, in
other words How can I restore a dropped table using cold back up
files ?

2) Is 'Hot standby database ' fool proof one ?

   I have copied the following lines from a Oreilly's book.

"With the hot stand by database you actually use one database at a time The
second database is constantly in recover mode. AS an
archived redo log file is generated, it is copied to the remote site
and applied to the database.In the event of a failure of the primary
database, you complete the recovery process and bring up the stand by
database.

With this facility you will have to maintain redundant computer and
storage systems and in the case of recovery, you will lost any
committed transactions that have been moved to an archived log file."

 My questions
1) what recovery process is he talking about ? How do I do it ?
2) Could you brief me about 2nd paragraph ?

Thanks
Gururaj

      and we said...
1) you would do a point in time recovery of the tablespace.  we must do an
ENTIRE tablespace, not just a table

If you are using RMAN, it automates this for you.  See the rman guides:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76990/rmanconc.htm#439215

If not, you would

o restore system, rollback, and the tablespace constaining the table elsewhere
o you would point in time recover this database to before the drop table
o you would export (or transport using export in 8i) the table (or tablespace)
out of this database and imp to the other database

you MUST be running in archivelog mode or else you will have to revert to the
copy of the table that was in the last cold backup, losing all of the
intervening changes.

2) The recovery process is the standard recovery process Oracle uses when in
archivelog mode.

See

http://technet.oracle.com/doc/oracle8i_816/server.816/a76993/toc.htm
for details on HOW backup and recovery work

and for details on standby to answer the 2cnd paragraph see

http://technet.oracle.com/doc/oracle8i_816/server.816/a76995/toc.htm
...
Review
      & Followup

      Rating: 4
Pretty clear..
      also true in 9i?  December 11, 2001
Reviewer:
      Doug  from CT, USA
I recognize the problem of recovering "a" table to a different SCN number than
others, but can RMAN do just a table in 9i? (by checking constraints or
something?)

          Followup:

Just a tablespace -- it'll be a TABLESPACE.  all of the objects in a tablespace
must be consistent with respect to eachother.  The tablespace is a data
structure, it must be consistent as well.

      Rating: 4
Never mind
      about the 9i thing  December 11, 2001
Reviewer:
      Doug  from CT, USA
K jumped the gun...

http://downloadeast.oracle.com/otndoc/oracle9i/901_doc/server.901/a90135/rmancona.htm#459447

December 12, 2001
      Jacques -- Thanks for the question
      regarding "Fetching email into a database", version 817

      You Asked
Hi Tom,

I'm trying to build a system which will be able to read messages from emails
into a database.

Is it possible to set up a procedure in Oracle 8.1.7 that will enable you  to
log on to a mail server (MS Exchange in this case)and retrieve messages for a
specific user account by using built in packages from Oracle.

If not could you please suggest some ways of doing this - I suppose the mail.jar
is probably the answer but my experience with Java is non existent and I'd
appreciate it if you could give me a few pointers.

Thanks

Jacques

      and we said...
You'll want to get a little java experience.

The protocols for reading mail, IMAP, POP, etc -- are a little intense.  While
technically POSSIBLE to do with PLSQL and UTL_TCP, it would be very very low
level.  You would have to basically implement the IMAP or POP client protocol
(doable, but hard).

Using Java, you can get the protocol support built in, you get an API that makes
it easy to read email.  It does the work for you.

I would recommand Java in this case.
Review &
      Followup

      Rating:
      1
  December 14, 2001
Reviewer:
      A reader

December 13, 2001 Bob -- Thanks for the question regarding "Script
      to generate and insert sample data values into a table", version 8.1.7.0

      You Asked
How to create a PL/SQL sript to generate and insert into a table some sample
dummy values?

      and we said...
I might use the dbms_random package.  You can call the plsql functions in it
right from SQL.

Oracle8, release 8.0 introduced the DBMS_RANDOM package.  In Oracle8i release 2
(version 8.1.6) new functionality was introduced for the DBMS_RANDOM package but
it doesn?t seem to have made it into the documentation as yet.  Fortunately for
you ? one of the new functions is on that returns a random number between 0 and
1.  The new functions in their entirety are:

FUNCTION value RETURN NUMBER;
FUNCTION value (low IN NUMBER, high IN NUMBER) RETURN NUMBER;

FUNCTION normal RETURN NUMBER;

FUNCTION string (opt char, len NUMBER) RETURN VARCHAR2;

The first version of VALUE returns a random number that is greater then or equal
to 0 and less than 1.  The second version of VALUE returns a random number that
is greater then or equal to LOW and less then HIGH.  An example of their usage
would be:

SQL> select dbms_random.value, dbms_random.value(55,100)
  2  from dual;

     VALUE DBMS_RANDOM.VALUE(55,100)
---------- -------------------------
.782821936                79.6367038

The NORMAL function is designed to return a set of numbers with a normal
distribution.  This normal distribution has a standard deviation of 1 and is
centered around the number zero.  Therefore, we would expect about 68% of the
values returned by this function to be between ?1 and +1, 95% to be between ?2
and +2, and 99% to be between ?3 and +3.   And in fact that is what we observe:

SQL> create table t
  2  as
  3  select dbms_random.normal
  4    from all_objects
  5  /
Table created.

SQL> select count(*),
  2    sum( decode( ceil(abs(normal)), 1, 1, 0 ) )/count(*) "+/- 1 stddev",
  3    sum( decode( ceil(abs(normal)), 1, 1, 2, 1, 0 ) )/count(*) "+/- 2
stddev",
  4    sum( decode( ceil(abs(normal)), 1, 1, 2, 1, 3, 1, 0 ) )/count(*) "+/- 3
stddev",
  5    stddev(normal)
  6  from t
  7  /

  COUNT(*) +/- 1 stddev +/- 2 stddev +/- 3 stddev STDDEV(NORMAL)
---------- ------------ ------------ ------------ --------------
     21958   .679433464   .954458512   .997495218     1.00407451

Lastly, there is the STRING function.  This function returns a random string of
characters up to 60 characters in length.  The OPT parameter is a single
character that may be any of the following values:

Value    Meaning    Sample output
U    Upper Case Letters    DBMS_RANDOM.STRING('U',20)
                                ---------------------------
                                LBLRTNOZBGDDEXRDAPGE
                                FHYUPCQKIKZNKJJBWNZN

L    Lower Case Letters    DBMS_RANDOM.STRING('L',20)
                                ----------------------------
                                cupmmjtgcsxiblgzaibt
                                zwqzsmivudqqroaajygg

A    Mixed Case             DBMS_RANDOM.STRING('A',20)
        Alpha-Numeric Chars     ---------------------------
                                FOsgh_VtqIi`dcWPWUQt
                                AidjSWQFi[JYraUWBmeb

X    Upper Case          DBMS_RANDOM.STRING('X',20)
        Alpha-Numeric Chars     ----------------------------
                                O1L0F67FI=20?9;@I:NC
                                3E@PL51IC4R:?3SGRP?2

P    Any ?printable? char    DBMS_RANDOM.STRING('P',20)
                                ----------------------------
                                jE+3hPw_v6|+K-T^3nd.
                                >/v/K&_E/gQOa{ep*BVb

To get more information about these functions and the DBMS_RANDOM package, you
can issue:

select text
  from all_source
 where name = 'DBMS_RANDOM'
   and type = 'PACKAGE' order by line;

In SQLPlus for documentation

Review &
      Followup

      Rating: 5
This is what i
      was looking for  December 12, 2001
Reviewer:
      Sherry  from US
This is most useful since I am a QE and often need to create random data for
testing.   Not sure if Tom can answer question from here but I am struggling to
find a
way to create tables with random # of columns and random data types with random
data ?

          Followup:

Well, you would have to write a program, similar to the one below.  It would
generate a random number between 1 and max number of columns you want.

It would loop that many times to build the create table statement.

You would have an array of possible datatypes.  For each column, you would
generate a random number between 1 and max number of datatypes to pick one.  You
would use dbms_random to generate a length for varchar2 data....

You could then use the procedure:

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:2151576678914
to populate this table with random data.

      Rating:
      4
Excellent  December 13, 2001
Reviewer:
      Sanjay Raj  from USA
Thanks was of great help. I used to do the same thing in 10 -15 steps without
the DBMS_RANDOM package but now I can smile

December 13, 2001 Pratap -- Thanks for the question regarding
      "Migrating database from US7ASCII to UTF8", version 8.1.6

      You Asked
Hi Tom

We have two databases -

USER1 - DB1 - US7ASCII
USER2 - DB2 - UTF8

Some of the tables in USER1 and USER2 are exactly the same.
So for these tables, to migrate data from USER1 to USER2 we
are using insert scripts and copy commands (wherever there are long columns).

Do you see any problems in the migrating the data in such a manner when the
database character sets are different?

Secondly how do I confirm that the database from where I am migrating the data
is in a consistent state and no transactions are going on there.

Thanks

Pratap

      and we said...
from USER1 to USER2 should be no problem as long as the data in db1 is all 7bit.
 If some 8bit data is stored there, it will be converted to 7bit data first.

Oracle provides for a consistent query, the results will be consistent with
respect to the point in time your query began.  You need to do nothing to enable
this facility.  read:

http://technet.oracle.com/doc/oracle8i_816/server.816/a76965/c23cnsis.htm#2611
...
Review
      & Followup

      Rating: 4
About the
      second question  December 12, 2001
Reviewer:
      Pratap  from India
Thanks Tom, but I when I start the migration I need to be sure -

1. That all the currently running transactions are complete
2. And nobody else start any new transaction when the migration is going on.
(We would shut down the web site from where the transactions are done, but still
there are background processes and unfinished transactions going on)

          Followup:

1) do a shutdown normal
2) do a startup enable restricted session, now only DBA's can log in.

December 13, 2001 Tariq -- Thanks for the question regarding "How
      can I do the following - tks", version 9i

      You Asked
Hi

             I want to do something like as follows, can you pls help as to how
             it
             can be done in oracle using anything (queries,cursors, procedures
etc., I need to automate it as tables
             are huge and I need to reconcile our records. Please
             note table_1 has multiple records with the same id
             while table_2 would have just one record for each id, I am using
             postgres under solaris, I can do the connecting part, will really
             appreciate your help very very much

             Thanks
             Mike
             mr_ocp@yahoo.com

             table_1
             ============
             id, account_name, amount, trans_type

             table_2
             ============
             id, trans_name, amount

             sql statment
             ============
             select a.id, a.amount as credit, b.amount as debit,
             a.amount + b.amount as diff from table_1 as a, table_1 as b
             where a.id = b.id and a.amount > 0 and b.amount < 0;

             # check if this account_name exists in table_2 table

             if diff is > 0 then
             select table_2.id, table_2.amount from table_2
               where table_2.id=table_1.id;

               if exists then
                diff = diff - table_name_2.amount

             print a.id, credit, debit, diff  # for all records it fetches

             end if
               end if

      and we said...
Just run this query in sqlplus, it does all of that for you.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t1 ( id int, amount int );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t2 ( id int, amount int );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t1 values ( 1, 100 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t1 values ( 1, -50 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t2 values ( 1,  25 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t1 values ( 2, 200 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t1 values ( 2, -75 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select a.id,
  2         a.amount credit,
  3         b.amount debit,
  4         a.amount + b.amount - decode( sign( a.amount + b.amount ),
  5                    1, nvl((select amount from t2 c where c.id = a.id ),0),
  6                                        0 ) diff
  7    from t1 a, t1 b
  8   where a.id = b.id
  9     and a.amount > 0
 10     and b.amount < 0
 11  /

        ID     CREDIT      DEBIT       DIFF
---------- ---------- ---------- ----------
         1        100        -50         25
         2        200        -75        125

December 13, 2001 Andre -- Thanks for the question regarding
      "trying to create a script for creating indexes for all foreign keys",
      version 8.0.5

      You Asked
How can I create a script that's not gonna give me a duplicate index name when I
try to create a index for all my foreign keys on my database?
thank you very much

      and we said...
Well, typically people name indexes after something meaningful so they know what
it is there for.  I guess you could just name yours after the foreign key
constraint.

Use the foreign key contraint name and add "_IDX" to it.  That way, if you have
a constraint "EMP_FK_TO_DEPT", you'll get a meaningful index named
"EMP_FK_TO_DEPT_IDX".  If you let the constraint names default ( really bad idea
) you'll get names like "SYS_C00113221_IDX" but then you'll still be able to
determine what constraint this index is being used for.
December 14, 2001 Tamas -- Thanks for the question regarding
      "dbms_tcp", version 8i

      You Asked
Hi Tom,

could you point me to some examples on the dbms_tcp package?
Ftp'ing a file from the Oracle server to some other site or
something similar?

Thank you for your help.

Tamas Szecsy
Geometria GIS Systems House Ltd.

      and we said...
Well, FTP is a pretty complex protocol to implement so I'll go
with something much easier -- HTTP.

The package is UTL_TCP and it allows you to create sockets and
read/write data.  Here is a very simple example:

ops$tkyte@DEV816> DECLARE
  2          c utl_tcp.connection;
  3          d number;
  4  BEGIN
  5      c := utl_tcp.open_connection('aria', 80);
  6      d := utl_tcp.write_line(c, 'GET / HTTP/1.0' );
  7      d := utl_tcp.write_line(c);
  8      BEGIN
  9        LOOP
 10           dbms_output.put_line(utl_tcp.get_line(c, TRUE));
 11        END LOOP;
 12       EXCEPTION
 13         WHEN utl_tcp.end_of_input THEN
 14               NULL;
 15       END;
 16       utl_tcp.close_connection(c);
 17  END;
 18  /

HTTP/1.0 200 OK
Date: Tue, 19 Sep 2000 12:41:25 GMT
Allow: GET, HEAD
Server: Oracle_Web_listener2.1/1.20in2
Content-Length: 299
Content-Type: text/html
Last-Modified: Wed, 10 Nov 1999 22:38:02 GMT
URI: <index.html>
<HTML>
<HEAD>
<TITLE>Oracle Service Industries</TITLE>
</HEAD>
<FRAMESET COLS="130,*" border=0>
<FRAME SRC="nav.html" NAME="sidebar" frameborder=0>
<FRAME SRC="
http://aria.us.oracle.com/sb/web$sb.folder.home
NAME="body" frameborder="0"
marginheight="0"
marginwidth="0">
</FRAMESET>
</BODY>
</HTML>

PL/SQL procedure successfully completed.
Review &
      Followup

      Rating: 5
Requesting FTP
      implementation  December 13, 2001
Reviewer:
      Dheeraj  from India
Dear Tom,

This is very useful. My requirement is to FTP, anyway. Could you direct me to
the relevant stuff.

Thanks and regards,
Dheeraj

          Followup:

You'll want to get and use the Java classes that implement FTP.   They are there
in the database and there are many 3rd party jar's that do it as well.

ftp is a little more sophisticated, you'll not be doing that in plsql alone.

December 14, 2001 OP -- Thanks for the question regarding "How to
      find Information about Indexes !!", version 8.1.6.0.0

      You Asked
Dear Tom,
Hi !

This Question is related with Indexes.

Like there is a DataDictionary table,through which it's
possible to find out the Text related with the stored
procedure.

I there any method by which it's possible to get the
TEXT with the Constraint.Like what statement got used
to create the Constraint.

If C1 is a Constraint Existing on T1 table.After creating it
at a later point of time I want to know how CONSTRAINT C1
go created i.e the statement behind this constraint !!

Thanks & Regards
OP

      and we said...
You do not.  The constraint is not stored anywhere in its
textual form.

If you would like to see the constriaint text -- they way I do
it is via exp/imp.  For example, lets say I ran:

tkyte@TKYTE816> create table t ( x int check ( x is not null )
);
Table created.

(shows that the constraint is typically part of a larger command
as well -- there is no constraint text to "save")....

I then use exp to get the structure of the table out:

C:\>exp tkyte/tkyte tables=t rows=n

Export: Release 8.1.6.0.0 - Production on Thu Nov 30 10:27:42
(c) Copyright 1999 Oracle Corporation.  All rights reserved.
Connected to: Oracle8i Enterprise Edition Release 8.1.6.0.0 -
Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production
Export done in WE8ISO8859P1 character set and WE8ISO8859P1 NCHAR
character set
Note: table data (rows) will not be exported

About to export specified tables via Conventional Path ...
. . exporting table                              T
Export terminated successfully without warnings.

and then I use IMP to "see" the create table and other
relevant statements I just exported:

C:\>imp tkyte/tkyte full=y indexfile=stdout

Import: Release 8.1.6.0.0 - Production on Thu Nov 30 10:27:53

(c) Copyright 1999 Oracle Corporation.  All rights reserved.

Connected to: Oracle8i Enterprise Edition Release 8.1.6.0.0 -
Production
With the Partitioning option
JServer Release 8.1.6.0.0 - Production

Export file created by EXPORT:V08.01.06 via conventional path
import done in WE8ISO8859P1 character set and WE8ISO8859P1 NCHAR
character set

CREATE TABLE "TKYTE"."T" ("X" NUMBER(*,0)) PCTFREE 10 PCTUSED 40
INITRANS 1 MAXTRANS 255 LOGGING STORAGE(INITIAL 65536 NEXT 65536
MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 50 FREELISTS 1
FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "SYSTEM" ;
ALTER TABLE "TKYTE"."T" ADD CHECK ( x is not null ) ENABLE ;

Import terminated successfully without warnings.

Review &
      Followup

      Rating: 5
What
      about...  December 14, 2001
Reviewer:  Ethan
      Post  from Dallas, TX
Tom,

I have had experience with a corrupted indexfile after I remove the REM's.  In
many cases the lines break in the middle of a column name.  When I run it in
SQL*Plus a number of commands will bomb out.  I had to write my own fix for this
to find incorrect line breaks and correct them.  I also tried playing with some
of the variuos SQL*Plus parameters and nothing seemed to work.

- Ethan

          Followup:

No -- I don't believe you did.  I'll go out on a limb here -- I'm quite sure of
it actually.

indexfile=index.xxxx gives you a clean file.

show=y -- that'll do what you describe.  I believe you might be talking about
show=y, not indexfile=filename

If you can give me a counter example -- I'll gladly file a bug.

indexfile=test.sql -- clean file.
show=y  -- file that is 80 characters wide and it breaks the SQL when it hits 80
characters.

      Rating:
      5
Indexfile  December 15, 2001
Reviewer:
      Wayne Phillips  from South Africa
Tom got the facts on this one for sure.
But I'm sure you have checked it out by now.
Imp into Indexfile without show=y is thr right way.

WP

December 15, 2001 Shamsul Bahri -- Thanks for the question
      regarding "Decode function", version 8.1.7

      You Asked
I have one table, Posting with below structure

Fields        Type
------        ---------
status        number(2)
operation_status    number(2)
operation_flag    number(2)
mobile_no        varchar(20)

My questions, how to use decode function to display below output :

Request    status    opstatus    opflag    count(mobile_no)
-------    ------    --------    ------    -------------
Release    12        1        0        98
Change    12        1        1        4
Update    13        1        1        17
Promotion    13        1        2        6

Currently, my sql statement like below :
select
decode(status,
12, 'Release or Change',
13, 'Update or Promotion',
) Request,
status, operation_status, operation_flag,
count(mobile_no)
from posting
group by status, operation_status, operation_flag;

FYI, combination of field status, operation_status and operation_flag is
considered one request.

for example, request release is status = 12, operation_status = 1 and
operation_flag = 0.

      and we said...
and is change "status=12 and operation_status=1 and operation_flag = 0"?

try:

select request, status, operation-status, operation_flag, count(mobile_no)
  from
( select case when status=12 and operation_status = 1 and operation_flag = 0
            then 'Release'
            when status=12 and operation_status = 1 and operation_flag = 1
            then 'Change'
            when status=13 and operation_status = 1 and operation_flag = 0
            then 'Update'
            when status=13 and operation_status = 1 and operation_flag = 1
            then 'Promotion'
            else 'unknown'
       end request,
       status, operation_status, operation_flag, mobile_no
  from t ) group by request, status, operation-status, operation_flag

Review &
      Followup

      Rating: 3
New
      knowlegde  December 17, 2001
Reviewer:  Shamsul
      Bahri Yusoff  from KL, Malaysia
Thank you for solving my answer. Thru your answer, I just know one can use
select case in SQL statement. That's new for me.

Your solution works and I appreaciated it very much.

Thank you again :)

December 15, 2001 Munzer -- Thanks for the question regarding
      "PL/SQL execeptions", version 8i

      You Asked
Tom:

1.  If you have a PL/SQL procedure that generates HTML tags and does basically
inserts into several tables, what exception handler would you be using.  E.g
"WHEN OTHERS" .

2. same thing If you are doing "SELECT" would you be checking for "WHEN
NO-VALUE-FOUND" or else?

Thank you

      and we said...
1) i would use named exceptions for those exceptions I expected.

I never ever use when others (that basically means you don't care, any error is
OK).  I would catch things like dup_val_on_index or use pragma exception_init to
map specific errors i was EXPECTING and could recover from only.

when others is almost always a bug unless immediately followed by "raise".

2) a SELECT .. INTO can throw a when no_data_found and too_many_rows.  If I
EXPECTED to have a no_data_found (eg: i was looking for a row and if I found one
great, else run some code) i would have a when no data found.

I rarely have a too_many_rows -- that means the data is wrong somehow probably.
I want that exception to stop my program DEAD.  I don't want to catch things I'm
not expecting.  If you do, you end up ignoring them and you never know they
happened.  I would rather my application FAILS, falls over, stops running then
have it ignore some error.
Review & Followup

      Rating: 3
add a record to
      a table using a sequence like yyyymm****
      200112001-200112****...  December 24, 2001

Reviewer:  mysdirma  from china
hi tom!!
how are you?
can you help me?   I have  a script like down,can you tell me some about this
script, good or bad ,if bad   what can I do  ????/*

REM this script create a sequence like (yyyymm****) and add a record into  a
table
REM written by mysdirma zhnjiangdianxin
REM create table seq(seq_ym number(6),seq_num num(3),seq_id,number(9));
REM create table temp_table(char_col varchar2(20),number_col number(20),date_col
date);
REM table seq is a sigle table
CREATE OR REPLACE PROCEDURE add_temp_table (
   p_char_col            temp_table.char_col%TYPE,
   output       IN OUT   VARCHAR2
)
AS
   v_seq_ym    NUMBER;
   v_seq_num   NUMBER;
   v_seq_id    NUMBER;
   v_ym        NUMBER;
   v_id        NUMBER;
BEGIN
   SELECT TO_NUMBER (TO_CHAR (SYSDATE, 'yyyymm'))
     INTO v_ym
     FROM DUAL;
   SELECT seq_ym, seq_num, seq_id
     INTO v_seq_ym, v_seq_num, v_seq_id
     FROM seq;

   IF v_seq_ym = v_ym
   THEN
      BEGIN
         UPDATE seq
            SET seq_num =   v_seq_num
                          + 1,
                seq_id =   v_seq_id
                         + 1
          WHERE ROWNUM = 1;

         IF SQL%FOUND
         THEN
            SELECT seq_id
              INTO v_id
              FROM seq
             WHERE ROWNUM = 1;

            INSERT INTO temp_table
                        (char_col, num_col, date_col)
                 VALUES (p_char_col, v_id, SYSDATE);

            output := 'Ìí¼ÓÊý¾Ý³É¹¦£¡£¡£¡£¡';
            COMMIT;
         ELSE
            output := 'ÏµÍ³Ã¦ÇëÉÔºó£¡£¡£¡£¡';
            ROLLBACK;
         END IF;
      END;
   ELSE
      BEGIN
         v_id :=   v_ym * 1000
                 + 1;

         UPDATE seq
            SET seq_ym = v_ym,
                seq_num = 1,
                seq_id = v_id
          WHERE ROWNUM = 1;

         IF SQL%FOUND
         THEN
            SELECT seq_id
              INTO v_id
              FROM seq
             WHERE ROWNUM = 1;

            INSERT INTO temp_table
                        (num_col)
                 VALUES (v_id);

            output := 'Ìí¼ÓÊý¾Ý³É¹¦£¡£¡£¡£¡';
            COMMIT;
         ELSE
            output := 'ÏµÍ³Ã¦ÇëÉÔºó£¡£¡£¡£¡';
            ROLLBACK;
         END IF;
      END;
   END IF;
EXCEPTION
   WHEN NO_DATA_FOUND
   THEN
      output := 'SEQ ±íÖÐÎÞÊý¾Ý£¬Óë¹ÜÀíÔ±ÁªÏµ£¡£¡£¡£¡';
      NULL;
END add_temp_table;
/

thanks !!!
2001-12
mysdirma


Subject | Article | Last Updated (East coast time)
Multiple SELECTS or one Procedure to generate Count Statistics? | article only | Dec 17, 2001 07:49 am
PL/SQL exceptions | article only | Dec 17, 2001 08:04 am
a few questions | article only | Dec 17, 2001 09:22 am
domain | article only | Dec 17, 2001 09:28 am
DYNAMIC SQL NULL VALUE | article only | Dec 17, 2001 08:05 pm
Migrating to Oracle 8 and Developer 6 | article only | Dec 18, 2001 10:03 am
Stunning Performance Improvement -Why? | article only | Dec 18, 2001 04:19 pm
Oracle JVM Timezone different to OS Timezone | article only | Dec 19, 2001 07:59 am
Database misused indexes when I applied function to SYSDATE | article only | Dec 19, 2001 12:44 pm
Sequence of datafile usage | article only | Dec 19, 2001 04:14 pm
Effect of ORDER BY clause on ROWNUM | article only | Dec 20, 2001 10:03 am
How to convert "&" before sending to Stored Procedures. | article only | Dec 20, 2001 03:59 pm
rollback segments | article only | Dec 21, 2001 08:01 am
how to call a stored procedure from Oracle reports | article only | Dec 21, 2001 08:06 pm
Reports Server needs an X Windows Server | article only | Dec 21, 2001 08:38 pm
owa_util.listprint usage | article only | Dec 22, 2001 09:49 am
about space management in oracle 8.1.xand 9i | article only | Dec 23, 2001 10:30 am
Followup Maximum number of cursors | article only | Dec 23, 2001 10:55 am
Snapshot Too Old | article only | Dec 23, 2001 03:06 pm
row(s) 1 - 19 of 19
December 17, 2001 Eric -- Thanks for the question regarding "Multiple SELECTS or one Procedure to generate Count Statistics? ", version 8.1.7.2.0
You Asked
I've got an application showing purchases from a catalog. I
need to show statistics on those purchases -- the number of
buyers by product by month, the number of buyers by source
(space ads, direct mail, telephone, online) by month, the number
of buyers by state by month, etc. In other words, there are a
lot of row counts to generate.

The question is, am I better off creating an SQL statement for
each count request, or, since I have so many counts to generate,
am I better off writing an SQL Procedure to loop through all the
rows with a single table scan and update tables with the counts?

An example count request -- counts by product code by month:

SELECT TO_CHAR(purchdate, 'YYYYMM'), prodcode, count(*)
FROM transactions
GROUP BY TO_CHAR(purchase,'YYYYMM'), prodcode

Oracle is pretty good at optimizing SQL, and it's certainly
easier to focus on each SQL statement one at a time. But, it
will require many full-table scans (and/or many indexes). The
Procedure route is much more difficult to write in a general way
(since I really have 30 or 40 different tables to do these
statistics on with different columns to count in each table,
with more coming in all the time).

One more bit of info -- these counts are only generated after
the file is updated. These updates are done monthly or
quarterly, so these counts are not run all the time and are not
generated on demand. We save them as PDF files for viewing.

Any advice is greatly appreciated! :-)

PS. I currently do this using Oracle Reports. This ends up as
the "one SQL statement per count" method. But, I've just gotten
a file in with 4 million records, and I don't want to wait until
next year for the report to finish! :-)
and we said...
Is this one table?  Have you looked at a group by CUBE?

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace view transactions
  2  as
  3  select emp.deptno product,
  4         emp.job    buyer,
  5         dept.loc    source,
  6         decode( emp.deptno, 10, 'VA', 20, 'PA', 30, 'VA' ) state
  7    from scott.emp, scott.dept
  8  /

View created.

ignore the view, its just there to create data, i know its a cartesian
product, i just needed some data!

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> break on what skip 1
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select a.*,
  2         decode( what, '0111', 'By Product',
  3                       '0010', 'By Product, Buyer, State',
  4                       '0110', 'By Product, State',
  5                       '0011', 'By Product, Buyer' ) descript
  6  from (
  7  select product, buyer, source, state, count(*),
  8         grouping(product) || grouping( buyer ) ||
  9         grouping( source) || grouping( state ) what
 10    from transactions
 11   group by cube( product, buyer, source, state )
 12      ) a
 13   where what in ( '0111', '0010', '0110', '0011' )
 14   order by what
 15  /

   PRODUCT BUYER     SOURCE        ST   COUNT(*) WHAT DESCRIPT
---------- --------- ------------- -- ---------- ---- ------------------------
        10 CLERK                   VA          5 0010 By Product, Buyer, State
        10 MANAGER                 VA          5      By Product, Buyer, State
        10 PRESIDENT               VA          5      By Product, Buyer, State
        20 CLERK                   PA         10      By Product, Buyer, State
        20 MANAGER                 PA          5      By Product, Buyer, State
        30 MANAGER                 VA          5      By Product, Buyer, State
        30 SALESMAN                VA         20      By Product, Buyer, State
        30 CLERK                   VA          5      By Product, Buyer, State
        20 ANALYST                 PA         10      By Product, Buyer, State

        10 CLERK                               5 0011 By Product, Buyer
        20 MANAGER                             5      By Product, Buyer
        20 CLERK                              10      By Product, Buyer
        30 SALESMAN                           20      By Product, Buyer
        30 MANAGER                             5      By Product, Buyer
        30 CLERK                               5      By Product, Buyer
        20 ANALYST                            10      By Product, Buyer
        10 MANAGER                             5      By Product, Buyer
        10 PRESIDENT                           5      By Product, Buyer

        10                         VA         15 0110 By Product, State
        20                         PA         25      By Product, State
        30                         VA         30      By Product, State

        10                                    15 0111 By Product
        20                                    25      By Product
        30                                    30      By Product

24 rows selected.

Here, I use the grouping function to determine if we grouped by a column or not
-- to keep just the ones I wanted.  You get all of the aggregates you could want
from a result set this way.

In 9i, it can be more efficient.  In the example above -- it make 16 sets of
aggregates of which we kept four:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select distinct what
  2  from (
  3  select product, buyer, source, state, count(*),
  4         grouping(product) || grouping( buyer ) ||
  5         grouping( source) || grouping( state ) what
  6    from transactions
  7   group by cube( product, buyer, source, state )
  8      ) a
  9  /

WHAT
----
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111

16 rows selected.

In 9i, we can ask for the grouping sets we want specifically:

ops$tkyte@ORA9I.WORLD> select a.*,
  2         decode( what, '011', 'By Product',
  3                       '000', 'By Product, Buyer, State',
  4                       '010', 'By Product, State',
  5                       '001', 'By Product, Buyer' ) descript
  6  from (
  7  select product, buyer, state, count(*),
  8         grouping(product) || grouping( buyer ) || grouping( state ) what
  9    from transactions
 10   group by grouping sets( ( product ), ( product, buyer, state ),
 11                                          (product, state), (product, buyer )
)
 12      ) a
 13   order by what
 14  /

   PRODUCT BUYER     ST   COUNT(*) WHAT DESCRIPT
---------- --------- -- ---------- ---- ------------------------
        10 CLERK     VA          4 000  By Product, Buyer, State
        10 MANAGER   VA          4 000  By Product, Buyer, State
        10 PRESIDENT VA          4 000  By Product, Buyer, State
        20 ANALYST   PA          8 000  By Product, Buyer, State
        20 CLERK     PA          8 000  By Product, Buyer, State
        20 MANAGER   PA          4 000  By Product, Buyer, State
        30 CLERK     VA          4 000  By Product, Buyer, State
        30 MANAGER   VA          4 000  By Product, Buyer, State
        30 SALESMAN  VA         16 000  By Product, Buyer, State
        10 CLERK                 4 001  By Product, Buyer
        10 MANAGER               4 001  By Product, Buyer
        10 PRESIDENT             4 001  By Product, Buyer
        20 ANALYST               8 001  By Product, Buyer
        20 CLERK                 8 001  By Product, Buyer
        20 MANAGER               4 001  By Product, Buyer
        30 CLERK                 4 001  By Product, Buyer
        30 MANAGER               4 001  By Product, Buyer
        30 SALESMAN             16 001  By Product, Buyer
        10           VA         12 010  By Product, State
        20           PA         20 010  By Product, State
        30           VA         24 010  By Product, State
        10                      12 011  By Product
        30                      24 011  By Product
        20                      20 011  By Product

24 rows selected.

That is more efficient cause it only created the aggregates we were ultimately
interested in.
Review & Followup
Rating: 5
Looks like what the doctor ordered! December 16, 2001
Reviewer: Eric Raskin from Pleasantville, NY
Thanks very much for the tip.  This looks just like what we need.  Now I just
have to see how Oracle Reports deals with the Group by Cube...

Followup:
And if it gives you any heartburn -- hide the construct in a VIEW or use dynamic
sql.

Rating: 5
Materialized view makes the most sense... December 16, 2001
Reviewer: Eric Raskin from Pleasantville, NY USA
As a matter of fact, I'm probably going to create a materialized view for this.
The reports I do have multiple segments -- each separate "count" is its own
little section.  Oracle Reports likes to work this way, in that you create
"additional layouts" for each "matrix" that you show.  By using a materialized
view, we'll only have to generate the actual data once.  I figure that this will
give the best performance/space trade-off -- much better than my original plan
of indexing everything.  Without the materialized view, I would be back in the
same boat of full table scans for each Oracle Reports Matrix -- they would just
be "cubes" rather than straight "selects".

Rating: 5
I tried it, but I must have done something wrong!!! December 16, 2001
Reviewer: Eric Raskin from Pleasantville, NY USA
[BTW, sorry for so many posts on this without a response...]

Here is the actual cube query I tried:

select distinct(what)
from (
  select lr_counts.hldate(hotline) hldate,
     rtype,
     sexcode,
     state,
     substr(zip,1,3) scf,
     numpurch,
     lr_counts.nonnull(telnum) telnum,
     lr_counts.nonnull(email) email,
     lr_counts.nonnull(antiaging) antiaging,
     lr_counts.nonnull(busopp) busopp,
     count(*) count,
     grouping(lr_counts.hldate(hotline))  ||
       grouping(rtype) ||
       grouping(sexcode) ||
       grouping(state)   ||
       grouping(substr(zip,1,3)) ||
       grouping(numpurch) ||
       grouping(lr_counts.nonnull(telnum)) ||
       grouping(lr_counts.nonnull(email)) ||
       grouping(lr_counts.nonnull(antiaging)) ||
       grouping(lr_counts.nonnull(busopp)) what
  from wellsupp
  group by cube (lr_counts.hldate(hotline)),
         rtype,
         sexcode,
         state,
         substr(zip,1,3),
         numpurch,
         lr_counts.nonnull(telnum),
         lr_counts.nonnull(email),
         lr_counts.nonnull(antiaging),
         lr_counts.nonnull(busopp)
) a
order by what
/

The lr_counts.hldate() function returns a varchar2 from a date in the YYYYMM
format if the "hotline" column value is in the current year, or YYYY || '00' if
it is in a prior year.  This breaks out our dates for all months this year, and
just a total for each prior year.

The nonnull function does just that -- returns '1' if the value is not null and
null if it is null.  This allows me to group on things like telephone numbers,
where all I want to know is if it exists in the row or not (not group by each
and every telephone number).

I tried to follow your pattern to the letter, but I must have done something
wrong, because this is what I got after running it on a table with approx 62,000
rows:

WHAT
----------
0000000000
1000000000

Why didn't I get the full cube?  Shouldn't I have gotten 100 rows (since I have
10 items in the GROUP BY CUBE clause)?

Followup:
You have:

 group by cube (lr_counts.hldate(hotline)),
                                         ^^
         rtype,
         sexcode,
         state,
         substr(zip,1,3),
         numpurch,
         lr_counts.nonnull(telnum),
         lr_counts.nonnull(email),
         lr_counts.nonnull(antiaging),
         lr_counts.nonnull(busopp)
) a
order by what
/

but that should be:

 group by cube (lr_counts.hldate(hotline),
         rtype,
         sexcode,
         state,
         substr(zip,1,3),
         numpurch,
         lr_counts.nonnull(telnum),
         lr_counts.nonnull(email),
         lr_counts.nonnull(antiaging),
         lr_counts.nonnull(busopp) )
                                   ^^
) a
order by what
/

it only grouped by CUBE on the first column (0/1 two combos)

Also -- STRONGLY and seriously encourage you to drop the lr_counts package usage
and just use DECODE to do this.  It'll be many times faster.

nonnull = decode( column, NULL, 0, 1 )
hldate  = to_char(date,'YYYY') || decode(trunc(date,'YEAR'),
                                    trunc(sysdate,'YEAR'),to_char(date,'MM'),
                                    '00' )

Rating: 5
Ooops December 16, 2001
Reviewer: Eric Raskin from Pleasantville, NY USA
Actually, that would have been 2^10 = 1024 rows, right?

Duh!

Followup:
yes, thats what you'll get after moving the )

Rating: 5
Sheepish... :-/ December 16, 2001
Reviewer: A reader
Thanks again.  It's MUCH better now.

Thanks also for the hint about DECODE.  I'll use it instead.

Rating: 5
Way too slow in 8.1.7 December 16, 2001
Reviewer: Eric Raskin from Pleasantville NY USA
I ran my test cube and it took longer than the individual SELECTS I started with
-- a little over 9 minutes for only 61,000 rows.  Obviously that won't do much
good.  I'm on the Solaris Intel platform, and I'm not sure that 9i is available
for it yet (but I'll check).  So, I guess I'll end up doing a UNION of CUBES
into a table, collecting just the CUBES I need.  Any single CUBE seems to run
very quickly, but when I had all 10 GROUP items together, the combinatorial
explosion of unused super-aggregates rapidly killed any performance gain.

If you have any other suggestions about a way to go, rather than a UNION of
CUBES into a table, I'd really like to hear it....

Followup:
9i -- so you can get the specific cubes you want.  In 8i, the "union ALL" of the
specific group bys will have to be the approach.  In 9i, the selective group by
with grouping sets will be more performant as it only has to read the table
once.

December 17, 2001 Munzer -- Thanks for the question regarding "PL/SQL exceptions", version 8i
You Asked
Tom:

AS a followup to
Munzer,

The response to your question is waiting at:
http://asktom.oracle.com/pls/ask/f?p=4950:9:::NO::F4950_P9_ORIG,F4950_P9_DISPLAYID:Y,2246726113595
It was found to be relevant to a broad audience and has been entered into the
archive.

1.  Is in it better to define one exception "WHEN_OTHERS" and display the oracle
error and error message in it using "SQLERRM".

DO you really define your own exception to display more of a user friendly
messages since user may not know what are those oracle error messages.

2. Would the exception handler work for "SELECT" statements in cursors or just
the "SELECT" statements in the body of program.

3. Can you also have nested exceptions.  Where if astatemenet generates an
exception , it runs another piece of code that also has it is own exception and
so on?

Thank you
and we said...
1) Sorry if it wasn't clear, i thought it was..

I never ever use WHEN OTHERS.   I feel when others is a BUG.  I hate when
others.  If you just "display" the error code and error message -- you are
HIDING the fact that your procedure FAILED from the caller.  Also, the way to
display is dbms_output -- if I don't have that enabled -- I'll never see the
error.

I catch ONLY those exceptions I expect and that I can actually DO something
about.  For example -- if I'm doing an update and run out of rollback segment
space -- there is NOTHING i can do to fix that.  I would NOT catch that error, I
would let that error propagate up the stack.  I would MUCH rather have my
process fail utterly and miserably then to silently fail and not let anyone
know.  You don't know how many times I see that -- "my process runs successfully
but the data doesn't get updated -- why is Oracle broken in this way".  It
always turns out to be a when others that hides the error from everyone.

There are literrally thousands of error messages possible.  I do not catch and
come up with a more meaningful error message for them.  If I'm expecting an
error, I catch it and deal with it.  If I'm not expecting an error -- I just
propagate it up.  When the end user gets it -- there is NOTHING they can really
do other then note the error code and the conditions.  They file a report and
you fix it.

2) selects done with explicit cursors do not fling the standard "no data found",
"too many rows" exceptions.  they only happen with select INTO statements.

3) yes.  try it out, very simple to key in small tests and see what works (and
more importantly -- HOW it works)
Review & Followup
Rating: 3
December 17, 2001
Reviewer: AB from UK
Tom

Obviously you must distinguish between your released application code and your
personal "utilities" such as the code in your (amazing) book?

I've seen you not only use WHEN OTHERS in your code, but also WITHOUT a RAISE !
Admittedly, it is in small example code such as the unloading routines in your
book. However, this is why I ask you to draw the distinction between these and
your "professional application code".

When you say NEVER use WHEN OTHERS, do you mean NEVER use it without a RAISE?

Thanks.

Followup:
I mean without a RAISE.  A when others that is not followed by a RAISE is most
likely a bug (unless its a demo).

Code like this:

when others
then
    rollback;
    call_autonomous_transaction_to_log_error( .... );
    RAISE;
end;

is valid. with the raise, it is probably a BUG (probably, not definitely).

So, to be clear -- in "real" code, WHEN OTHERS that is not followed by a RAISE
is most likely a bug.

In the book -- i used when others every now and again to show the effect of
catching an ignoring an error.  For example in chapter 4 on transactions i have:

...<quote>

tkyte@TKYTE816> begin
  2          p;
  3  exception
  4          when others then null;
  5  end;
  6  /
I fired and updated 1 rows
I fired and updated 1 rows

PL/SQL procedure successfully completed.

tkyte@TKYTE816> select * from t;

         X
----------
         1

tkyte@TKYTE816> select * from t2;

       CNT
----------
         1

Here, we ran a block of code that ignored any, and all, errors. The difference
in outcome here is very large. Whereas the first call to P had no changes take
place (apparently), this one has one of the two inserts taking place. Oracle
considered the block the client submitted to be the statement. This statement
succeeded (by catching and ignoring the error). Oracle did not rollback to the
savepoint after executing this, hence the partial work performed by P was
preserved. Notice however that within P, we still have statement level
atomicity. P becomes the client of Oracle when it submits its two insert
statements. Each insert either entirely succeeds, or fails. This is evidenced by
the fact that we can see the trigger on T fired twice and updated T2 twice, yet
the count in T2 only reflects one update. The second insert executed in P had an
implicit savepoint wrapped around it.

The difference between the two blocks of code is subtle, and something you must
consider in your applications. Adding an exception handler to a block of PL/SQL
code can radically change its behavior, as shown by the above. A more correct
way, one that restores the statement level atomicity, but allows you to catch
and ignore the error, would be:
....</quote>

Rating: 5
Good stuff July 12, 2002
Reviewer: Doug C from CT, USA
Good stuff.. I will probably change my WHEN OTHERS coding habits now.

Rating: 4
March 10, 2003
Reviewer: A reader

December 17, 2001 Shiyin -- Thanks for the question regarding "a few questions", version 8.1.6
You Asked
Hi,Tom

it's so difficult to ask u a question:

1. when i mount the database, how can i know how many dictionary table or view i
can query?

2. Tom, for the table t1( a number,b varchar2(10))

the first case :

i created one index indx1(a,b)

the second case :
i create two indexes indxA(a) indxB(b)

then if there are millions of records in the table t1,and would u pls tell me
what's the difference between the two case index when i use the following query
:

select * from t1
where a=?
and   b=?

or

select * from t1
where b=?
and   a=?

3. when can i use the command 'analyze table xx compute statistics'?
i know if i use the command 'analyze table xx compute statistics' ,Oracle will
use the CBO in the execute plan,in my db some of the tables are truncated every
night and then appended from another db; some are used nomally,i don't i often i
use the command 'analyze table xx compute statistics'? every day or every week?
or ...

4. Tom, would u pls tell the relationship between the os processes and the
oracle processes when i run in the dedicated mode? what's the situation if i use
the same name to login Oracle in different SQL*PLUS prompt?

thanks advance.
and we said...
1) when you mount, you may query only fixed tables/views (v$ tables basically).
The real tables/views are not accesible until you open the database.

You'll get this:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from all_users;
select * from all_users
              *
ERROR at line 1:
ORA-01219: database not open: queries allowed on fixed tables/views only

when the database is mounted but not open.  You can query v$ tables.

2) Your best choice would be index(a,b).  If you index(a) and index(b) we might
be able to join the indexes to find the answer but the single index on (a,b)
would be best.

3) you can use that command whenever you want to.  You would want to analyze the
tables right after loading them.  You can search for

monitoring

on this site for how to automate the gathering of statistics on the other tables
(so you analyze them only when they need to be analyzed)

4) do you have my book?  I go into the Oracle architecture in great detail.

In dedicated server mode, there is a 1 to 1 relationship between your login and
an OS process on the server.  Every login = A process.  If you login 5 times
with sqlplus, you would have 5 processes.
Review & Followup
Rating: 3
Muy interesante December 17, 2001
Reviewer: Mauriel from Panama
La pregunta fue interesante pero me gustaria conocer mas  a fondo lo los indices
saben donde puedo conseguir mas informacion ?

December 17, 2001 murray -- Thanks for the question regarding "domain", version 8.0.4.0.0
You Asked
I am trying to create a domain to solve a mutually exclusive
relationship problem.  This involves tables - customer,
supplier, and account transaction where the account number in
the account transaction table must reference either the customer
table or the supplier table.  CREATE DOMAIN ACC AS NUMBER (8)
NOT NULL,
    CHECK (VALUE IN (SELECT ACCOUNT_NUMBER FROM CUSTOMER UNION
SELECT

ACCOUNT_NUMBER FROM SUPPLIER));
 This is the statement I am using but Oracle returns a message -
invalid create command.
Can you tell me the correct syntax?
and we said...
The concept you are trying to express above is not achievable in
a relational database using a declaritive form.  A parent child
relationship is a single parent to a single child. A child
cannot have a foreign key to one of two tables.

Another issue is that CREATE DOMAIN isn't valid -- there is no
such create.

You will have to use a trigger to enforce such logic --
thankfully the above doesn't work.  It would perform pretty
slowly if it did.  To union the entire customer table with the
supplier table for each insert/update to the table in question
would be less then performant.

You can use a trigger similar to:

...
begin
   select account_number into l_account_number
     from customer
    where account_number = :new.account_number
      FOR UPDATE;

exception
   when no_data_found then
   select account_number into l_account_number
     from supplier
    where account_number = :new.account_number
      FOR UPDATE;
end;

you'll need to put additional logic on the two parents to make
sure that when you delete/update a record in them, there are no
orphaned children as well.

Personally -- I think you have a data model problem.  You are
stuffing 2 different columns into the same column.  Either that
or you need a "person table" with the account number in it and
subtype tables customer with customer specific attributes and
supplier with supplier specific attributes and then this table
would have a foreign key to "person".  You are either missing a
table or a column.
Review & Followup
Rating: 5
December 17, 2001
Reviewer: Pascal from HAMBURG,Germany
Hi Tom,

I  came across this Qn in ur site and i have been faced with the same ARC
problems.

I saw that when one generates Table API from  Oracle's Designer , the situation
could be handled by Calling this procedure(Validate_arc  :see below)  in
Pre-Insert and Pre-Update Triggers to validate  the  ARC .

PROCEDURE validate_arc(cg$rec IN OUT  account%ROWTYPE) IS
i NUMBER;
BEGIN
    i := 0;
    IF (cg$rec.cust_id IS NOT NULL) THEN
        i := i + 1;
    END IF;
    IF cg$rec.supplier_id IS NOT NULL) THEN
        i := i + 1;
    END IF;

    IF (i = 0) THEN

    /*  MSG_ARC_MAND_VIOLATED  */

   END IF;

   IF (i > 1) THEN

  /* Raise  ARC_TOO_MANY_VAL  Exception  and Handle  */

   END IF;

END validate_arc;

I assume that  we create two Foreign keys  in Table Accounts for Children
Supplier and Customer(Both NULL)

I have also thought about creating a CHECK Constraint on Table Accounts  such as
:

CHECK( (supp_id is not null or cust_id is null)  or (supp_id is  null and
cust_id is not null ) )

My question though is that why do you think that this is a Data Model problem
because ARCs are quite a usual thing to encounter in many Data Models, though
implementations might differ...

Also there's another solution, which i have never implemented(i know only the
Theory), that says :  Create two candidate columns in Table Accounts:

For Example:  acct_no_for char(3) values ('SUPP' , 'CUST')
    and       acct_no    number

then it says that acct_no should carry unique  values for suppliers  and
Customers :   But i was never able to implement this Theory which i got from
some Data Modelling Book...

So, please give us more insights on how to Handle Queries from tables in an ARC
and how to implement  Exclusive-OR Situations.(Some more examples please)

Best regards,

Pascal

Followup:
(I don't know what ARC means btw...  Best not to assume that i know all acronyms
that are familar to you)

You have a totally different model then the original question.

They want ONE column that is a foreign key to EITHER tablea or tableb.

You have two mutually exclusive columns, each of which is a foreign key to a
single table.

They have one column, you have two.

You have done it the way I suggested they do it.

You have the example of mutual exclusion -- your check constraint on the table
is perfect for that.

Rating: 5
Suppose i have a Company Table(One to Many from Acct to Company) December 17, 2001
Reviewer: Pascal from HAMBURG,Germany
Hi Tom,

Thanks very much for follow-up to this Mutually Exclusive Relationship
issue.(Sorry i said ARC because they use it a lot in Oracle's Designer )

Now, suppose i have another Table , say Company(Comps) which has many to One
Relationship to Accounts - say , "A  Company may be the Authority for One  or
More Accounts "

Can you please give us an Example of a Query(Select) that would  Start from
Company  Table , and show us how it would relate to Suppliers  and Customers.

For instance: "Get a list of all Accounts belonging to some Company ,which may
be for Suppliers or for Customers "

Since these two foreign keys on Accounts Table allow for NULLs , would the
indexes on Foreign Keys be used when i perform a JOIN ?

Thanks in advance for your Response ,

With Best Regards,

Pascal

Followup:
ops$tkyte@ORA817DEV.US.ORACLE.COM> create table suppliers( supp_id int primary
key );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table customers( cust_id int primary
key );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create table comps
  2  ( comp_id int primary key,
  3    supp_id     references suppliers,
  4    cust_id     references customers,
  5    constraint  mutually_exclusive check
          ((supp_id is not null and cust_id is null) or
  6        (supp_id is null and cust_id is not null))
  7  )
  8  /

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into suppliers values ( 100 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into customers values ( 200 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into comps values ( 1, 100, null );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into comps values ( 2, null, 200 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> select *
  2    from comps, suppliers, customers
  3   where comps.supp_id = suppliers.supp_id(+)
  4     and comps.cust_id = customers.cust_id(+)
  5  /

   COMP_ID    SUPP_ID    CUST_ID    SUPP_ID    CUST_ID
---------- ---------- ---------- ---------- ----------
         1        100                   100
         2                   200                   200

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   NESTED LOOPS (OUTER)
   2    1     NESTED LOOPS (OUTER)
   3    2       TABLE ACCESS (FULL) OF 'COMPS'
   4    2       INDEX (UNIQUE SCAN) OF 'SYS_C004280' (UNIQUE)
   5    1     INDEX (UNIQUE SCAN) OF 'SYS_C004279' (UNIQUE)

Yes, the indexes would be used.

Rating: 5
Thanks very Much for UR Prompt Response!! December 17, 2001
Reviewer: Pascal from HAMBURG,Germany
Hi Tom,

Thanks A lot for your Prompt Response.
I find ur  website to be very very Useful.

Best Regards,

Pascal

December 17, 2001 Mins -- Thanks for the question regarding "DYNAMIC SQL NULL VALUE", version 8.17.2
You Asked
Hi Tom,

I am trying to pass null values to the dynamic sql and as follows:
But I am not able to get the record (fetch), I get the record,
if the value is not null.

The function compiles properly.

What am I doing wrong here. Please help
Thanks
i_emp_employee_id varchar2(6);
i_pln_plan_id number(5);

A_NULL CHAR(1);

select_str := 'SELECT
svc_credits_id,ROWID
        FROM '  || tabuse  || '.' || 'SVC_CREDITS' ||
'
        WHERE emp_employee_id = :1
        AND pln_plan_id = :2';

IF  I_PLN_PLAN_ID = 0 THEN

OPEN C1 for select_str using
i_emp_employee_id ,A_NULL ;

ELSE

OPEN C1 for select_str using
i_emp_employee_id ,i_pln_plan_id ;

END IF;
ELSE

OPEN C1 for select_str using
i_emp_employee_id ,i_pln_plan_id ;

END IF;
and we said...
You cannot use "where x = NULL", that is neither TRUE nor FALSE, consider:

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> select * from dual where dummy = null;

no rows selected

ops$tkyte@ORA9I.WORLD> select * from dual where dummy <> null;

no rows selected

ops$tkyte@ORA9I.WORLD>

you would think that dummy is either EQUAL to or NOT EQUAL to something but with
NULL's in SQL -- its actually *unknown*.

You should do this instead:

if ( i_pln_plan_id = 0 )
then
   open c1 for 'select svc_credits_id, rowid from ' || tabuse ...
               'where emp_employeed_id = :1 and pln_plan_id IS NULL' using ..
else
   ....
end if;
Review & Followup
Rating: 4
But the document gives a different ... December 17, 2001
Reviewer: Mins
Passing Nulls

Suppose you want to pass nulls to a dynamic SQL statement. For example, you
might write the following EXECUTE IMMEDIATE statement:
EXECUTE IMMEDIATE ’UPDATE emp SET comm = :x’ USING NULL;
However, this statement fails with a bad expression error because the literal
NULL is
not allowed in the USING clause. To work around this restriction, simply replace
the
keyword NULL with an uninitialized variable, as follows:
DECLARE
a_null CHAR(1); -- set to NULL automatically at run time
BEGIN
EXECUTE IMMEDIATE ’UPDATE emp SET comm = :x’ USING a_null;
END;

This is from
PL/SQL
User’s Guide and Reference
Release 8.1.5
February 1999
Part No. A67842-01

Is there way I could do this way...

Followup:
No, the documentation is NOT saying anything that conflicts with what I've said.

You followed the documentation, you are successfully passing in a NULL, you have
done that (thats what the documentation describes -- HOWTO pass a null in)

the problem is:

where x = :bind_variable

where bind_variable is NULL will NEVER be true (nor will it be FALSE, it'll be
UNKNOWN)

you have to say "where x is NULL", period.  Thats the way SQL works.  "where x=
NULL" is never TRUE or FALSE.  You need a different predicate to check for
nullness.

Rating: 3
a dirty workaround for a single syntax... December 18, 2001
Reviewer: A reader from ca, usa
SQL> create table z_test (col1 number, col2 varchar2(10));

Table created.

SQL> insert into z_test values (1, null);

1 row created.

SQL> insert into z_test values (2, 'X');

1 row created.

SQL> select * from z_test where col2 = null;

no rows selected

SQL> -- knocks out an index on col2
SQL> select * from z_test where 'X'||col2 = 'X'||null;

      COL1 COL2
---------- ----------
         1

SQL> -- knocks out an index on col2
SQL> -- 'XYZ' is not naturally occurring in col2
SQL> select * from z_test where nvl(col2, 'XYZ') = nvl(null, 'XYZ');

      COL1 COL2
---------- ----------
         1

SQL>

December 18, 2001 Sridevi -- Thanks for the question regarding "Migrating to Oracle 8 and Developer 6", version Oracle 7 and 8 and Developer 6
You Asked
Hi Tom,
I have been trying to ask u this question for the past 1 week. But you do not
seem to be available. Looks like we need more of you here.

We have some applicatiosn developed on Oracle 7.x, Forms 4.5 and Reports 2.5.

We have an agenda for development of 3 related applications accessing the same
database (Oracle 7.x) and which has to be just called from the main application
already stablised in Forms 4.5.

We ALSO have an agenda to migrate all Forms 4.5 and Reports 2.5 to Developr 6
and Oracle 7.x to Oracle 8, at a later date.

But somehow the agenda makers are under the impression that it is easier to
develop the 3 new applicatiosn in Forms 4.5 and Reports 2.5 and call it from the
main appliction --- And then immediately after these 3 new applications are
ported and stabilised in the user site,   take up  the migration of all the
applications(3 new ones as well as 4 older ones) at one go.

Their contention is that migration of a 7.x database to an Oracle 8 (Oracle
8.1.5 to be precise) is a gargutan task.

But I think this process of developing appliction in Forms 4.5 and within 6
months migrating it to Developer 6 is a waste of human effort as well as a waste
of mandays.

I was trying to put forth my idea thus:
1) Migrate the Oracle 7.x database to Oracle 8.1.5 database
2) Quickly migrate the 4 old applications to Developer 6 without enhancing any
code and just using the converter.(Would we face any problems here?)
The enhancements in these 4 old applications making use of new features of
Developer 6 can be done on a staggered long term schdule since these
applications are already quite stable and come up for maintenance only once in a
while.
3)Develop the 3 new applicatiosn on Develope 6 itself thus making use of new
features of Oracle 8.1.5 and Develop 6(like ref cursors, basing blocks on from
clause query or procedures etc. which i am sure will be very useful to our
applications).

WHAT IS YOUR OPINION TOM?
IS MY APPROACH OK OR ARE THEY GIVING A MORE FEASIBLE SOLUTION?

SO SHOULD IT BE...
I) DEVELOP APPL IN FORMS 4.5 AND REPORTS 2.5, AND THEN MIGRATE ALL APPLICTIONS
AT ONE GO.
(I think this approach takes more mandays which is very valuable to us)
OR
II) MIGRATE THE DATABASE, CONVERT OLD APPL TO NEW, DEVELOP APPL IN 6

PLEASE HELP!!!!!!!.
and we said...
Safe approach:

do the work in 4.5 and 2.5 on the existing database environment that you know
works with the existing 4 applications and then migrate at your own leisure.
Low risk, high probability of success.

Risky approach:

rapidly migrate the data to a new database version.  Upgrade the forms.  You
will be dealing with unknown "feature related" issues -- subtle changes to the
software.  There will be bugs, there will be subtle changes to features (and you
rely on the old behavior).  Everything will ultimately work -- it MAY even work
without a single issue -- but it could be rocky in the beginning, especially if
you are under the gun to do it now and do it fast.

I myself would prefer to be using 8i -- taking advantage of the new features and
functions, working with software developed this century -- however, if given
only a few months to get 2 new applications developed, tested and fielded WHILE
maintaining the status quo for 4 existing ones -- I might think seriously about
the first low risk (but not as fun) path.

This is less about wasting time/mandays then it is about a smooth transition and
priorities.  When you get to the end of this road, the riskier approach might
have taken a little less time but might have been a very bumpy ride.  The low
risk approach might take more resources -- but the ride would have been smoother
perhaps.
Review & Followup
Rating: 3
steps for the migration December 18, 2001
Reviewer: Godwin from Ghana
Please Tom i have finished developing my application in the V7
developer2000(forms 4.5,reports 2.5) and i want to migrate straight away to V8
developer 6.
Can you outline the various steps for me to follow?
Thanks for the wonderful work you 've been doing.

Followup:
To migrate the database, read the Oracle Migration Guide:
http://technet.oracle.com/docs/products/oracle8i/doc_library/817_doc/server.817/index.htm
To migrate the forms, just install the new release and compile them.

December 18, 2001 Ramesh -- Thanks for the question regarding "Stunning Performance Improvement -Why?", version Forms 4.5
You Asked
Tom,
Hi, I have recently been trying to tune a Oracle Forms application. The
application calls 6 procedures. The entire process was taking around 12 minutes
to run (719.24 secs).
The time taken for the individual procedures to execute were as follows:
PROCEDURE 1 :301.45 secs
PROCEDURE 2 :131.09 secs
PROCEDURE 3 :176.32 secs
PROCEDURE 4 :76.61  secs
PROCEDURE 5 : 7.87  secs
PROCEDURE 6 :25.90  secs

Procedure 1 executes the following query and processes the records returned by
the query further:
select  a.sc_scrip_cd,a.sc_scrip_name,a.sc_sec_type,
         scd_quoted_flg, c.se_asset_hdr
         from gmst_scrip a, gmst_scrip_det b,gmst_security c
         where a.sc_scrip_cd = b.scd_scrip_cd and
               a.sc_sec_type = c.se_type and
               ((a.sc_scrip_cd in(select co_scrip_cd from tr_contract
                                   where co_cont_status = 0 and
                                         co_bght_sold   = 'B' and
                                         co_cont_dt between '01-APR-00' and
'31-MAR-01'))
              or (a.sc_scrip_cd in(select ba_acct_cd from sprm_balance
                                   where ba_group_ind = 'A'  and
                                         ba_year=1 and
                                         ba_open_qty >0)))
         order by c.se_desc,a.sc_scrip_name ;

The above query was taking 5 minutes to return the results when run in SQL PLUS.
I changed the query to:
select  a.sc_scrip_cd,a.sc_scrip_name,a.sc_sec_type,
         scd_quoted_flg, c.se_asset_hdr
         from gmst_scrip a, gmst_scrip_det b,gmst_security c
         where a.sc_scrip_cd = b.scd_scrip_cd and
               a.sc_sec_type = c.se_type and
               (a.sc_scrip_cd in(select co_scrip_cd from tr_contract
                                   where co_cont_status = 0 and
                                         co_bght_sold   = 'B' and
                                         co_cont_dt between '01-APR-00' and
'31-MAR-01'
              UNION              select ba_acct_cd from sprm_balance
                                   where ba_group_ind = 'A'  and
                                         ba_year=1 and
                                         ba_open_qty >0))
         order by c.se_desc,a.sc_scrip_name ;

Procedure 2 and 3 also had queries which used the OR operator. I changed it to
the UNION operator in all the cases. After the change, the execution times were
as follows:

PROCEDURE 1 :3.58  secs
PROCEDURE 2 :2.77  secs
PROCEDURE 3 :3.71  secs
PROCEDURE 4 :62.21 secs
PROCEDURE 5 :4.46  secs
PROCEDURE 6 :18.15 secs

Total Time: 94.85 secs.

I am unable to understand the reason why substituting UNION for OR would cause
such a drastic reduction in execution times.

Also, Procedure 4 had two queries to calculate the asset sum and the liabilities
sum and a formula to get the difference.
i.e. select sum(fin_amount) into asset_sum from finance_table where
finance_header='ASSET';
     select sum(fin_amount) into liability_sum from finance_table where
finance_header='LIAB';
     DIFF :=ASSET_SUM-LIABILITY_SUM;

I changed it to :
select
sum(decode(finance_header,'ASSET',fin_amount,0)-sum(decode(finance_header,'LIAB',
fin_amount,0)
into diff from finance_table;

There was no appreciable difference in the execution times when I checked both
the cases in SQL PLUS, however there is a reduction of around 12 secs when the
procedure is executed through the Oracle Forms application. The queries are in a
loop which processes around 80-100 records, so even if there is a improvement of
0.1 seconds, it may make a difference to the final figure. However as a rule of
thumb does combining the statements really make a difference?

I would appreciate if you could tell me the reasons for the performance
improvement.

TIA

Ramesh.
and we said...
Use sql_trace and tkprof to analyze exactly what is happening in the database
with each query.

See
http://asktom.oracle.com/~tkyte/tkprof.html
for details.

followup to comment

fixed the link -- sorry about that.
Review & Followup
Rating: 1
Page is not available May 02, 2001
Reviewer: Gururaj from GA USA
The page link which you have mentioned is not availabale
for the reader.(Time stamp : May 02 2001 12:20 EST)

Could you fix this Tom ..?

Thanks
Gururaj

Rating: 3
Link does not work December 18, 2001
Reviewer: pawanputra from USA
Can U please fix the link

Followup:
link works fine for me.

December 19, 2001 Steve -- Thanks for the question regarding "Oracle JVM Timezone different to OS Timezone", version 8.1.7
You Asked
Hi Tom,

I have Oracle installed on a machine where the local
timezone is GMT+10. Here's my test script ...

create or replace and compile java source named JTime as
public class JTime
{
public static void ShowDate()
{
java.util.Date dt = new java.util.Date () ;
java.util.TimeZone tz = java.util.TimeZone.getDefault () ;
System.out.println ("dt = " + dt) ;
System.out.println ("tz = " + tz) ;
}
}
/
create or replace procedure JTime
is language java
name 'JTime.ShowDate ()' ;
/
set serveroutput on size 1000000
begin
dbms_java.set_output (1000000) ;
JTime ;
dbms_output.put_line ('Sysdate = ' || to_char (sysdate, 'YYYY-Mon-DD
HH24:MI:SS')) ;
end ;
/

Here's the output from executing in SQL*Plus ...

SQL*Plus: Release 8.1.7.0.0 - Production on Tue Dec 11 14:20:45
2001

(c) Copyright 2000 Oracle Corporation. All rights reserved.

Connected to:
Oracle8i Enterprise Edition Release 8.1.7.0.0 - 64bit Production
With the Partitioning option
JServer Release 8.1.7.0.0 - 64bit Production

SQL> @tst

Java created.

Procedure created.

dt = Mon Dec 10 22:20:54 EST 2001
tz =
java.util.SimpleTimeZone[id=EST,offset=-
18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=3
,startDay=1,startDayOfWeek=1,startTime=7200000,endMode=2,endMonth=9,endDay=-1,end
DayOfWeek=1,endTime=7200000]
Sysdate = 2001-Dec-11 14:20:55

PL/SQL procedure successfully completed.

As you can see, the Aurora JVM is running with a timezone of GMT-5.  If I run
pretty much the same java code using the OS JVM (v 1.3), I see a timezone id of
"Australia/Victoria".  I have tried changing my $TZ environment variable to
"Australia/Victoria", and I get a correct value within the Oracle JVM, but it
completely screws up SYSDATE (appears to show GMT).

I would dearly love an explanation, and information on how to fix it.

Thanks,

Steve

Here's the output from the properties :

SQL> -- listing properties --
java.specification.name=Java Platform API Specification
java.version=1.2.1
oracle.aurora.mts.INIT=oracle.aurora.mts.rdbms.INIT
user.timezone=EST
java.specification.version=1.2
java.vm.vendor=Oracle Corporation
java.vm.specification.version=1.0
user.home=
java.naming.factory.initial=oracle.aurora.namespace.InitialContex...
os.arch=PA_RISC
java.vendor.url=
http://www.oracle.com/java/
file.encoding.pkg=sun.io
user.region=US
java.home=/opt/app/oracle/product/8.1.7/javavm/
java.class.path=
line.separator=
java.io.tmpdir=/var/tmp/
jdbc.drivers=oracle.jdbc.driver.OracleDriver
os.name=HP-UX
java.vendor=Oracle Corporation
oracle.jserver.version=8.1.7
oracle.server.version=8.1.7
java.library.path=
java.vm.specification.vendor=Sun Microsystems Inc.
oracle.aurora.namespace.INIT=oracle.aurora.namespace.rdbms.INIT
oracle.aurora.rdbms.SID=DevFM
file.encoding=ISO8859_1
oracle.aurora.mts.session.INIT=oracle.aurora.mts.session.rdbms.INIT
java.specification.vendor=Sun Microsystems Inc.
oracle.aurora.vm.environment.name=rdbms
user.name=
user.language=en
java.vm.name=JServer VM
java.vm.specification.name=Java Virtual Machine Specification
java.class.version=46.0
oracle.aurora.rdbms.oracle_home=/opt/app/oracle/product/8.1.7/
sun.boot.library.path=/opt/app/oracle/product/8.1.7/lib64:
sqlj.runtime=sqlj.framework.ide.aurora.rdbms.Oracl...
java.naming.factory.url.pkgs=oracle.aurora.ejb.jndi:com.sun.jndi.u...
java.protocol.handler.pkgs=oracle.aurora.rdbms.url
os.version=B.11.00
java.vm.version=1.2.1
java.compiler=
path.separator=:
file.separator=/
user.dir=

PL/SQL procedure successfully completed.
and we said...
Hi Steve,

My name is Mark Piermarini and I work for Tom Kyte. He asked me to finish
helping you with this problem. I see the environment variable "user.region" is
set to "US" -- I will look into that more. For now, I wrote some Java to set the
default timezone for JVM session. It has to be called but only once. It will
either take a valid named time zone like 'Australia/Sydney' or an offset from
GMT. It will also set the default based on the session time from the database.
Can you load the java class and PL/SQL package and then test to see if it works
for you? Bug 2124255 is closely related to this problem. Below I listed the
source code and a test run.
============================================================
create or replace and compile java source named "TZ_Stuff" as
import java.sql.*;
import java.util.*;
import oracle.jdbc.driver.OracleDriver;

// Set the default JVM timezone to be either a user-defined value or a
// value that is retrieved from the database session time zone. One of
// the setDefault() methods should be called before any Java time zone
// work is done and it only needs to be executed once for a JVM. All
// methods are exposed in the PL/SQL wrapper package. list() method
// will show all valid named time zones.
//
// Bug 2124255 in the Oracle Metalink is similar problem.
//
public class TZ_Stuff {

  public static void list() {
    String[] ids = TimeZone.getAvailableIDs();
    for (int i = 0; i < ids.length; i++) {
      System.out.println(ids[i]);
    }
  }

  // Accept a time zone in the form of "Australia/Sydney" or
  // "GMT[|-]hh[[:]mm]". Using a custom time zone might have
  // implications on daylight savings. This method is not exhaustive
  // in its' error and input handling. There is a debug message
  // displayed which can be removed.
  public static void setDefault(String tz) {
    String theTZ = tz;

    // If the string starts with a plus or minus sign then the caller
    // is using a raw offset so prefix with GMT.
    if (tz.startsWith("+") || tz.startsWith("-")) {
      theTZ = "GMT" + tz;
    }

    // Now set the default timezone
    System.out.println("NEW DEFAULT TZ = " + TimeZone.getTimeZone(theTZ));
    TimeZone.setDefault(TimeZone.getTimeZone(theTZ));
  }

  // Find the value from the database and set it to the default. Only
  // execute this once so we do not bother keeping the connection or
  // caching a prepared statement. Or anything for that matter.
  public static void setDefault() throws Exception {
    Connection c = new OracleDriver().defaultConnection();
    Statement s = c.createStatement();
    ResultSet rs = s.executeQuery("select sessiontimezone from dual");
    while (rs.next()) {
      setDefault(rs.getString(1));
    }

    rs.close();
    s.close();
    c.close();
  }
}
/
show errors

create or replace package tz_stuff as
  procedure list as
  language java name 'TZ_Stuff.list()';

  procedure sync_1 as
  language java name 'TZ_Stuff.setDefault()';

  procedure sync_2(p_time_zone in varchar2) as
  language java name 'TZ_Stuff.setDefault(java.lang.String)';
end;
/
show errors

exec tz_stuff.list
exec tz_stuff.sync_2('Australia/Sydney')

-- -------------------------------------------------------------
-- -- This is your code....
-- -------------------------------------------------------------
create or replace and compile java source named JTime as
public class JTime {
  public static void ShowDate() {
    java.util.Date dt = new java.util.Date ();
    java.util.TimeZone tz = java.util.TimeZone.getDefault ();
    System.out.println ("dt = " + dt);
    System.out.println ("tz = " + tz);
  }
}
/

create or replace procedure JTime
is language java name 'JTime.ShowDate()';
/

set serveroutput on size 1000000
exec dbms_java.set_output (1000000);
begin
  JTime;
  dbms_output.put_line (
    'Sysdate = ' ||
    to_char (sysdate, 'YYYY-Mon-DD HH24:MI:SS'));
end;
/

============================================================
============================================================

Could you run this:

create or replace and compile java source named "props" as
public class props {
  public static void show_props() {
    System.getProperties().list(System.out);
  }
}
/
show errors
create or replace procedure java_props
as language java name 'props.show_props()';
/
show errors
set serveroutput on size 10000
exec dbms_java.set_output(10000)
exec java_props

and let us know what it says...
December 19, 2001 hahaer -- Thanks for the question regarding "Database misused indexes when I applied function to SYSDATE", version 901
You Asked
Database misused indexes when I applied function to SYSDATE, e.g.
TRUNC(SYSDATE), SYSDATE + 10. Let's look at a sample:

        rudolf@TEST901.WORLD>CREATE TABLE t (id number, adate date);

        Table created.

        rudolf@TEST901.WORLD>BEGIN
          2    FOR i IN 1 .. 10000 LOOP
          3       INSERT INTO t VALUES (i, sysdate - 100 + trunc(i/100));
          4    END LOOP;
          5  END;
          6  /

        PL/SQL procedure successfully completed.

        rudolf@TEST901.WORLD>CREATE INDEX t_adate_ind ON t (adate);

        Index created.

        rudolf@TEST901.WORLD>ANALYZE TABLE t COMPUTE STATISTICS FOR TABLE FOR
ALL INDEXED COLUMNS FOR ALL INDEXES;

        Table analyzed.

        rudolf@TEST901.WORLD> SET AUTOTRACE ON
        rudolf@TEST901.WORLD>SELECT COUNT(id) FROM t WHERE adate < SYSDATE
          2  /

         COUNT(ID)
        ----------
             10000

        Execution Plan
        ----------------------------------------------------------
           0      SELECT STATEMENT Optimizer=CHOOSE (Cost=16 Card=1 Bytes=15)
           1    0   SORT (AGGREGATE)
           2    1     TABLE ACCESS (FULL) OF 'T' (Cost=16 Card=10000
Bytes=150000)

        Statistics
        ----------------------------------------------------------
                  0  recursive calls
                  3  db block gets
                 99  consistent gets
                  0  physical reads
                  0  redo size
                384  bytes sent via SQL*Net to client
                503  bytes received via SQL*Net from client
                  2  SQL*Net roundtrips to/from client
                  0  sorts (memory)
                  0  sorts (disk)
                  1  rows processed

It didn't use the index T_ADATE_IND as expected, since Oracle assumed we were
trying to retrieve the majority of rows  out of table T according to CBO rules.
However, when I do as follows, the result goes out of my expectation:

        rudolf@TEST901.WORLD>SELECT COUNT(ID) FROM t WHERE adate <
trunc(sysdate)+ 100;

         COUNT(ID)
        ----------
             10000

        Execution Plan
        ----------------------------------------------------------
           0      SELECT STATEMENT Optimizer=CHOOSE (Cost=5 Card=1 Bytes=15)
           1    0   SORT (AGGREGATE)
           2    1     TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=5 Card=500
Bytes=7500)
           3    2       INDEX (RANGE SCAN) OF 'T_ADATE_IND' (NON-UNIQUE) (Cost=4
Card=500)

        Statistics
        ----------------------------------------------------------
                  0  recursive calls
                  0  db block gets
                217  consistent gets
                  0  physical reads
                  0  redo size
                384  bytes sent via SQL*Net to client
                503  bytes received via SQL*Net from client
                  2  SQL*Net roundtrips to/from client
                  0  sorts (memory)
                  0  sorts (disk)
                  1  rows processed

Note, here the index T_ADATE_IND was used, and the cost is much bigger than the
original one. See, 99 consistent gets vs. 217 consistent gets. Woo, Oracle made
a wrong decision or I was doing in a wrong way? I have tested both oracle8.1.6
and oracle 9.0.1 on a linux box.
and we said...
The short answer is that the optimizer treats all functions as bind varibles
(with the exception of function based indexes).  Functions are evaluated at
runtime -- not parse time.  Hence the query:

SELECT COUNT(ID) FROM t WHERE adate < trunc(sysdate)+ 100;

is evaluated much in the way that:

SELECT COUNT(ID) FROM t WHERE adate < :x;

would be.

SELECT COUNT(ID)
FROM
 T  WHERE ADATE < SYSDATE

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.03       0.02          0         25          4           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.03       0.03          0         25          4           1

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
  10000   TABLE ACCESS FULL T

********************************************************************************

SELECT COUNT(ID)
FROM
 T  WHERE ADATE < :b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.05       0.04          0         52          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.05       0.04          0         52          0           1

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE
  10000   TABLE ACCESS BY INDEX ROWID T
  10001    INDEX RANGE SCAN (object id 24272)

Its a tricky problem -- in a way, I'm surprise it works with SYSDATE when I
think about it -- as sysdate is not a deterministic function and the query plan
could change over time as sysdate changes....
Review & Followup
Rating: 4
It could be smart optimizer December 20, 2001
Reviewer: Stano from Slovakia
I think it's OK and it just proves cleverness of optimizer in Oracle 8i, and
perhaps also fact, that it treats sysdate as a constant with known value during
optimization. I suppose that because of:

SQL> SELECT COUNT(id) FROM t WHERE adate < SYSDATE;

 COUNT(ID)
----------
     10000

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=15)
   1    0   SORT (AGGREGATE)
   2    1     TABLE ACCESS (FULL) OF 'T' (Cost=4 Card=10000 Bytes=150000)

Statistics
----------------------------------------------------------
         22  recursive calls
          4  db block gets
         26  consistent gets
          0  physical reads
          0  redo size
        133  bytes sent via SQL*Net to client
        135  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed

In this case optimizer knows, that all values in the table holds used predicate,
so doesn't use index, because it has to visit table anyway (you are counting
id's).

SQL> SELECT COUNT(id) FROM t WHERE adate > sysdate;

 COUNT(ID)
----------
         0

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=15)
   1    0   SORT (AGGREGATE)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=3 Card=67 Bytes=1005)
   3    2       INDEX (RANGE SCAN) OF 'T_ADATE_IND' (NON-UNIQUE) (Cost=2
Card=67)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        144  bytes sent via SQL*Net to client
        135  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed

December 19, 2001 Ramesh -- Thanks for the question regarding "Sequence of datafile usage ", version 8.0.5.2
You Asked
Hi Tom,
I have a quick question. When you have multiple datafiles in a tablespace, how
does the oracle knows which one to use when data needs to inserted/updated. Is
there any way you can force oracle to use a given datafile within the
tablespace?
Thanks.
and we said...
You can only force the use of a particular datafile when you do a DIRECT PATH
load using sqlldr, otherwise we just manage the space in a big heap.  We
maintain freelists so that if you insert 5 rows -- they may go into 5 different
files, they might all go into one.  It just depends.
Review & Followup
Rating: 3
Further question December 19, 2001
Reviewer: Yu Dong from Ontario, Canada
So why sometimes data is imported into data2.dbf rather than data1.dbf in a
tablespace? The two datafiles have the same size like 1GB. has it anything to do
 with the first extend size? Thanks.

Followup:
data in a dictionary managed tablespace is managed in database tables.  We find
space by running a query -- looking for the best fit.  WHERE the data goes
physically -- we don't care, we are just looking for space (enough space).  We
don't go file by file, extent by extent.  It should not matter, space is space
is space.

Rating: 4
True for data. But extents. . . December 20, 2001
Reviewer: AJ Allen from Troy, MI USofA
This is true for data, however I seem to have noticed that when a tablespace has
several datafiles, Oracle allocates extents in a round-robin fashion from one
datafile to the next datafile in order of creation (file id).

December 20, 2001 Shaun -- Thanks for the question regarding " Effect of ORDER BY clause on ROWNUM", version 8i
You Asked
Tom,

When selecting ROWNUM, I would have expected that my first row would always have
a ROWNUM of 1, but when I add an ORDER BY clause to my SELECT statement, the
ROWNUM values do not necessarily come out sequentially. Is this the proper
expected behavior? ... and if so, why? [It seems like ROWNUM would be a lot more
useful if the ORDER BY clause didn't affect it.]

Thanks for any insight you can provide,

Shaun
and we said...
The rownum is assigned to rows as they satisfy the predicate (which is why
"select * from t where rownum > 1" never returns ANY rows -- there is never a
row 1)

It is assigned BEFORE  the order by or group by (else you could not "select *
from t where rownum < 10")

If you want it AFTER that, you would use an inline view:

select a.*, rownum
  from ( select * from emp order by ename ) A
/
Review & Followup
Rating: 4
Query December 20, 2001
Reviewer: William from Australia
Tom,

Can you please explain to me this following scenario:
create table TEST_DATA (tid integer, tdata varchar2(50));
insert into test_data values (1, 'Value 1');
insert into test_data values (2, 'Value 2');
insert into test_data values (3, 'Value 3');

SQL> select * from test_data where rownum = 1;
       TID TDATA
---------- -----------------------------------------
         1 Value 1

SQL> select * from test_data where rownum = 1 order by tid desc ;
       TID TDATA
---------- ------------------------------------------
         1 Value 1

so far everything is as expected but if I add a primary key:
alter table TEST_DATA add constraint test_data_pk primary key (tid);

SQL> select * from test_data where rownum = 1 order by tid desc ;
       TID TDATA
---------- -------------------------------------------
         3 Value 3

By adding the primary key, it appears that the order by is
performed first and the the where clause. Can you please
explain?

Thanks

Followup:
Look at the query plan, the optimizer is seeing the ORDER BY TID DESC and is
using the primary key index to access the data in order to avoid a sort in this
case.

In short however -- this is the classic example of WHY you need to do it as I
describe with the inline view, else the results are somewhat arbitrary.

Rating: 2
Can We Use ROWNUM to insert UNIQUE NUMBERS into a Table like THIS? December 20, 2001
Reviewer: Pascal from Hamburg,Germany
Hi Tom,

Just a Follow up on ROWNUM,

First I would like to ask you to explain what's going on here when i do the
Update:

drop table test_data;

create table TEST_DATA (tid integer, tdata varchar2(50));

insert into test_data values (1, 'Value 1');
insert into test_data values (2, 'Value 2');
insert into test_data values (3, 'Value 3');
insert into test_data values (5, 'Value  5');
insert into test_data values (7, 'Value  7');
insert into test_data values (8, 'Value  8');

select * from test_data;

     1 Value 1
     2 Value 2
     3 Value 3
     5 Value  5
     7 Value  7
     8 Value  8

UPDATE  test_data set  TID = ROWNUM;

select * from test_data ;

    1 Value 1
    2 Value 2
    3 Value 3
    4 Value  5
    5 Value  7
    6 Value  8

Finally, can we use this Technique to assign Unique numbers to a Table.

Best Ragards,

Pascal

Followup:
You can -- but the numbers will be assigned as rows are hit -- you have no
control over what rows will get what numbers.

It will not assign numbers based on the order of insertion in general.

It would be better to use a sequence upon insertion to get a unique number
assigned.

December 20, 2001 Monish -- Thanks for the question regarding "How to convert "&" before sending to Stored Procedures.", version 9ias
You Asked
Tom,

In a HTML Form's <input type="text" name="p_other"> the user may enter values
containing "&".

When this Form is submitted, it does not call the associated procedure defined
in the action, with either methods (post or get).

Is there a way we could convert the "&" to "&amp" even before the string
http://server:port/pls/mydad/myproc?p_name=a&bcd
is
created. ( I would actually like it to be
http://server:port/pls/mydad/myproc?p_name=a&ampbcd
.

I know we could use javascript to convert all fields where a "&" is found into
"&amp" before submitting the form.

Do have any other ways to do it (using Oracle Builtins etc.).

Thanks.
and we said...
You don't have to do that -- the browser encodes all of this for you.  If you
have a form:

<form action=/pls/mydata/myproc>
<input type=text name=p_name>
<input type=submit>
</form>

and the user types in AT&T, the BROWSER will automagically URL encode that
string for you.  You need do hothing.
December 21, 2001 mathew -- Thanks for the question regarding "rollback segments", version 8+
You Asked
hi,
    If a person makes a modifications to a table and then sees the data , he
sees the modified data while all others see the unmodified data untill he
commits. Where is the oracle engine fetching data from , for both these
catagories of people? if data is buffered to save IO and change records are
entered to the redo logs what is the role of the rollback segments in this
situation?

regards,
mathew.
and we said...
read
http://technet.oracle.com/docs/products/oracle8i/doc_library/817_doc/server.817/a76965/c23cnsis.htm#2570
in fact, read:
http://technet.oracle.com/docs/products/oracle8i/doc_library/817_doc/server.817/a76965/toc.htm
from cover to cover and you'll know more about Oracle then most people!
Review & Followup
Rating: 3
January 02, 2002
Reviewer: mathew from India
thanks

December 21, 2001 George -- Thanks for the question regarding "how to call a stored procedure from Oracle reports", version 6i
You Asked
Hi,

I need help to call a db stored procedure below from report builder, when it is
called, I need to pass in proper parameters like deptno in the sp.
1.Where to call and What the correct command? looks like I have to have select
statement to buile a report, how to use select statement to call sp or any other
way to call?

2. how to pass parameters in the sp, for a simple query I can use bind variable,
is it possible to use bind variable to call sp and what the syntex?

3. if possible can you show me a example?

create or replace package testpkg AS         //working
TYPE sumCur IS REF CURSOR;
    procedure test(
                dno IN NUMBER,
        sum_cv IN OUT NOCOPY sumCur);
END;

CREATE OR REPLACE PACKAGE BODY testpkg AS
    procedure test(
                dno IN NUMBER,
        sum_cv IN OUT NOCOPY sumCur) AS
        sql_statement VARCHAR2(100);
    BEGIN
        sql_statement :='SELECT dname, from dept  where deptno = :d ';
        OPEN sum_cv FOR sql_statement using dno;
    END test;
END;

Thanks very much
and we said...
Anywhere you can put PLSQL, you can put a call to a procedure -- You just code.
See chapter 6 of  Oracle Reports Developer Release 6i: Building Reports
found at:
http://technet.oracle.com/docs/products/reports/content.html
there is a whole chapter on this subject.
December 21, 2001 Johan -- Thanks for the question regarding "Reports Server needs an X Windows Server", version 9iAS 1.0.2.1
You Asked
Tom,

We are using the reports server (reports server 6i) component of Oracle 9iAS to
host our production reports.

We recently had a problem where reports could not be run and the reports server
responded with a ORA-30000, stating that there was a problem with the PLSQL
Toolkit.

If we start the X server on the PC from which the 9iAS software was installed
(and which is still pointed to by the system's environment variables), the
problem disappear immediately and the report run normally.

My questions :
(1) why does the reports server require an X Windows server to run reports
successfully ?.
(2) how can I configure Oracle 9iAS reports server to not require an X Server -
the PC we are currently using to run the X Server emulation was never intended
to be part of the production installation and therefore go out of action with
power failure, etc, etc.
and we said...
It needs a virtual device for doing image stuff -- on unix, thats all done with
X.

I have the same problem -- I have a vt-100 on my server, no graphics console.
What we do is use a small X emulator -- vnc (very very handy to have about)

see
http://www.uk.research.att.com/vnc/
Here, we start VNC on the unix box during boot time, this gives us a virtual
console -- one that you can actually attach to if you want.  It is this display
we use for the reports server.  This has worked very nicely for us (we also use
it to do the installed with OUI, very nice cause we can kick off an install,
disconnect from the virtual display, drive home and reconnect with that virtual
console and finish the install)
Review & Followup
Rating: 5
Thanks - will solve the problem January 06, 2002
Reviewer: Johan Snyman from Johannesburg, South Africa

December 22, 2001 Munzer -- Thanks for the question regarding "owa_util.listprint usage", version 8i
You Asked
Say you have a PLSQL variable p_country with the value you want selected in it.

You can code:

  dbms_application_info.set_client_info( p_country );

  owa_util.listPrint
  ( 'select cod_country, nam_country,
            decode( cod_country, USERENV(''client_info''), ''Y'', null )
       from country
      order by cod_country',
    'p_code_country',
     1,
     FALSE );

for example:

ops$tkyte@ORA8I.WORLD> declare
  2          p_country  varchar2(30) default 'SYS';
  3  begin
  4    dbms_application_info.set_client_info( p_country );
  5
  6    owa_util.listPrint
  7    ( 'select user_id, username,
  8              decode( username, USERENV(''client_info''), ''Y'', null )
  9         from all_users
 10        where username like ''S%''
 11        order by username',
 12      'p_code_country',
 13       1,
 14       FALSE );
 15  end;
 16  /

Tom :

As a followup to your answer above to using owa_util.listprint, I used it and it
works fine.

My questions is that I have to pass two parameters to the SQL query and decode
function for default value selection.  How can you use the
dbms_application_info.set_client_info to do that.  Can you use something else to
set anothe value.

2.  Also, is this an alternative solution to use bind_variables.
and we said...
You can use an application context to do this and yes, this is an alternative to
bind variables HOWEVER - its much more work.  I don't understand your apparent
aversion to bind variables (seems to be a constant thread with you).  bind
variables are crucial, you must use them in your code.  I cannot overstate this
fact.

Here is how to do this with a context, and with binds.  IMHO, binds win here,
less code, less objects, less muss, no fuss.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace context my_ctx using
my_proc;

Context created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace procedure my_proc( p_name
in varchar2, p_val in varchar2 )
  2  as
  3  begin
  4          dbms_session.set_context( 'my_ctx', p_name, p_val );
  5  end;
  6  /

Procedure created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> @owainit
ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
  2          nm      owa.vc_arr;
  3          vl      owa.vc_arr;
  4  begin
  5          nm(1) := 'WEB_AUTHENT_PREFIX';
  6          vl(1) := 'WEB$';
  7          owa.init_cgi_env( nm.count, nm, vl );
  8  end;
  9  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> begin
  2          my_proc( 'foo', 'Hello World' );
  3          my_proc( 'bar', 'Goodbye!' );
  4
  5          owa_util.listprint
  6          ( 'select sys_context( ''my_ctx'', ''foo'' ),
  7                            sys_context( ''my_ctx'', ''bar'' ),
  8                            null
  9                   from dual' ,
 10        'this_is_a_demo',
 11             1,
 12             FALSE
 13          );
 14          owa_util.showpage;
 15  end;
 16  /
<SELECT NAME="this_is_a_demo" SIZE="1">
<OPTION value="Hello World">Goodbye!
</SELECT>

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> begin
  2          owa_util.listprint
  3          ( owa_util.bind_variables
  4            ( 'select :foo, :bar, null from dual',
  5                  'foo', 'Hello World',
  6                  'bar', 'Goodbye!'
  7            ),
  8        'this_is_a_demo',
  9             1,
 10             FALSE
 11          );
 12          owa_util.showpage;
 13  end;
 14  /
<SELECT NAME="this_is_a_demo" SIZE="1">
<OPTION value="Hello World">Goodbye!
</SELECT>

PL/SQL procedure successfully completed.
December 23, 2001 zhu -- Thanks for the question regarding "about space management in oracle 8.1.xand 9i", version 8.1.7
You Asked
Hi, tom:
  Nice to get a chance to ask you a question again:)
  When i read oracle9i document: concepts, i get some question:
At page4-11, it said: When you create a tablespace, you choose one of these
methods of space management. You cannot alter the method at a later time.
  But Oracle do provide package dbms_space_admin to help us convert tablespace
between locally managed and dictionary managed
Then why does the concept mannual said that?

And a second short question:
What do u think public is, a role or a schema? I checked sql.bsq, and find the
statement create role public, but in documents, it always said public is a
schema(page 6-3), How to understand it, that magic public?

Thanks.
and we said...
Yes, that would be technically inaccurate -- you can convert LMTS/DMTS (however
I would strongly discourage the practice, not nearly as good as moving the data
from a DMT to a LMT and getting 100% of the benefits of LMTS.  doing the
conversion is not as good)

PUBLIC is technically a schema.

ops$tkyte@ORA817DEV.US.ORACLE.COM> connect / as sysoper;
Connected.
ops$tkyte@ORA817DEV.US.ORACLE.COM> select user from dual;

USER
------------------------------
PUBLIC

ops$tkyte@ORA817DEV.US.ORACLE.COM> connect / as sysdba;
Connected.
ops$tkyte@ORA817DEV.US.ORACLE.COM> select user from dual;

USER
------------------------------
SYS

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

and since it is the OWNER of things -- its a schema really, not a role.
December 23, 2001 Munzer -- Thanks for the question regarding "Followup Maximum number of cursors", version 8i
You Asked
Tom:

AS a followup to :

The response to your question is waiting at:
http://asktom.oracle.com/pls/ask/f?p=4950:9:::NO::F4950_P9_ORIG,F4950_P9_DISPLAYID:Y,2298290920735
It was found to be relevant to a broad audience and has been entered into the
archive.

1.  Can you tell me how you define a session.  Is it the time I start the
applicatin using the browser basically going to the login screen by running a
PL/SQL procedure.

Does it end after I run a second procedure or I close my browser.

Does oracle keep adding cursors if i run procedure 1 then 2 the 3 ....etc.

I thought it would close cursors after you exit each procedure.

2.  Does your book explain how to use bind variables in detail.  I thought it
was more oriented toward a dba rather than a developer.

3.  I did a workaround for using
dbms_application_info.set_client_info(par1||','||par2);

Then i use a combination of subst and lenght to pull the right parameter value.
Do you see a proble with using this rather than contexts.  But I will look into
bind variables and I will get your book.

THank you
and we said...
1) unless I know your architecture and tools -- i cannot really answer this in
YOUR context.

Some connection pools login once (start a session) and use that connection for
1,000's of pages.  These sessions last hours or days.

Other connection pools (better ones) start a session (but keep the connection)
for each page. These sessions last for a very short time (fractions of a second)

If you keep the session open page after page after page -- and you have a cursor
leak, this will kill you.

2) My book could be titled:

Expert One on One Oracle -- How to use bind variables and why its relevant.

It is a recurring theme throughout.  My book is directed at ANYONE who uses
Oracle -- dba and developer alike, although it has more of a developer slant to
it.

3) you need not look "into" bind variables -- I gave you the explicit example
right there!!!
Review & Followup
Rating: 2
How can this happen December 23, 2001
Reviewer: Kulguru
"If you keep the session open page after page after page -- and you have a
cursor leak, this will kill you."

For example once I login into my account of my bank, the session is always open
, no matter how many pages I navigate. And if in one page I do a tranfer from
one account to another of mine, and if the background procedure doing the
transfer , opens a cursor and does not close,  how will that kill me .

Make it more clear for us.

Thank you

Followup:
You will run out of cursors eventually -- you will get ORA-01000 and not be able
to do anything else.  Your session is dead.

Its like if you opened a file in the OS and never closed.  Just kept opening
them.  Eventually you'll hit max open files, bamm, no more files for you.

I really don't know how to say it more clearly.  If you open a resource, lose
the handle to that resource, never reuse that resource and that resource is
finite (you only get so much of it) you'll eventually run out and its "game over
player one".

December 23, 2001 Steven -- Thanks for the question regarding "Snapshot Too Old", version 8.1.6.3
You Asked
We have a PeopleSoft order,manufacturing, and financials system.  There are
about 14000 orders taken per day, about 10 concurrent database transactions
ACTIVE in v$session at any time.  Total database size is about 300GB and the
largest table is about 13GB.
PeopleSoft is a mixed OLTP/Batch system as you know.  We were getting ORA-01555
about an hour into a single large job.
Because it is a PeopleSoft as-shipped batch job, modifying the code is not
practical at this time (its written in a combination of COBOL and the internal
code AppEngine).
We had 80 rollback segments, with initial=next=5MB and Optimal=50MB.  So I
created an additional 20 segments initial=next=5MB and Optimal=100MB.  My
thought was that the shrink was wiping out some incremental piece of data I
needed.  But it appears (since I got the ORA1555 on one of my new segments) that
I am not on the right track.

Help me think this through.  If decreasing the statistical likelihood by 25%
didnt fix it (20/80) then the only next step I can think of is to assign a
rollback segment to the task and fix it at 3GB.  But then I get contention on
the availablitity of that one BIG_RBS.

After one of the batch jobs failed last night on ORA-01555 on RBS No.91:
This is output of DBMS_STATSREP for that hour:

       Trans Table      Pct   Undo Bytes
RBS No     Gets       Waits     Written        Wraps  Shrinks  Extends
------ ------------ ------- --------------- -------- -------- --------
    89    654,479.0    0.01     143,016,946       38        6       37
    90     21,258.0    0.00      67,752,000       16        0        0
    91     22,544.0    0.00     143,646,484       29        0        1

RBS No    Segment Size  Avg Active    Optimal Size    Maximum Size
------ --------------- ----------- --------------- ---------------
    89     104,849,408 316,757,846     104,857,600     602,923,008
    90     104,849,408  27,112,398     104,857,600     110,092,288
    91     110,092,288  56,011,711     104,857,600   3,580,870,656

Previous Hour:
       Trans Table      Pct   Undo Bytes
RBS No     Gets       Waits     Written        Wraps  Shrinks  Extends
------ ------------ ------- --------------- -------- -------- --------
    89     55,351.0    0.00     150,826,270       40        0       20
    90     42,349.0    0.00       9,750,322        2        0        0
    91     25,362.0    0.00       5,181,280        2        0        0

RBS No    Segment Size     Avg Active    Optimal Size    Maximum Size

------ ---------------    ----------- --------------- ---------------

    89     209,707,008    162,103,269     104,857,600     602,923,008
    90     104,849,408     28,459,375     104,857,600     110,092,288
    91     104,849,408     59,034,897     104,857,600   3,580,870,656
and we said...
the probability of a 1555 is directly proportional to the size of your SMALLEST
rollback segment --  as fast as that wraps, you will get the 1555.  Its not the
total amount of RBS, the size of the biggest -- its the size of the SMALLEST
RBS.

Rather then adding 20, you should have measured how fast you wrap your existing
rollback and then made them BIGGER permanently (i hugely do not like "optimal").
 If you find you wrap 50mb rollback segment in 1/2 hour and your batch job is
taking 1 hour -- you need to DOUBLE that space.

Adding extra RBS increased the time it takes to wrap but apparently not enough
here-- since we allocate RBS segments in a round robin fashion, the small ones
still wrap faster.

Assigning a RBS to that job won't fix a thing!  1555 is due to rollback
generated by OTHER transactions not being available (your rollback for YOUR
transaction is by definition available, we need it to rollback! the 1555 comes
from OTHER transactions rollback getting overwritten).

You need to permanently allocate more RBS -- larger permanently allocated
rollback.  If you only have 10 concurrent transactions, you don't need anywhere
near 100 RBS -- you need more like 15 and they should just be really big
(permanently).  You need to look in v$transaction -- not v$session to determine
the number of active transactions.
Review & Followup
Rating: 5
Followup on Wrap December 23, 2001
Reviewer: Steve Meller from Atlanta
So if I wrap 40 times in an hour in a 100MB segment, increase all segments to
max(Average Active) and "test", iterate until no wraps?

Followup:
If you need to support hour long statements -- you need to get the wraps down to
0/1.  Its the duration of the longest running STATEMENT that dictates the size
of your rollback segments.

I'm not sure where you are going with "max(Average Active)" -- you want to have
enough rollback segments (in number) to avoid contention and they all need to be
big enough so as to not wrap.

Rating: 3
Rollback December 23, 2001
Reviewer: Javed from Jeddah, Saudi Arabia
For Oracle EBusiness Suite, I used 1 rollback segment with 100MB initial and
500MB optimal for a 500GB database.

Rating: 5
Followup to Wrap December 23, 2001
Reviewer: Steve Meller from Atlanta
Tom, I much appreciate your patience. I need to manage the 1555 as probabilistic
to save $$ on disk in our dasdi box.In an average hour we see about 6 tx per sec
and the current Next_Extent of 5MB is ok for all but a few.  In your response
DISPLAYID:233214228495 you wrote that every RBS should be sized for the large
job.  So I meant by AveActive capturing the size of the large tx, 5MB per extent
times 60-70 as a minimum rbs size - then let the segment autoextend if
needed,instead of setting every rbs to HWMsize.

Followup:
Do NOT let is autoextend.  ONLY a WRITE transaction will cause it to extend, A
READ transaction will not - -that is the conundrum here!!

(you might be interested in my book, i go into depth on this very topic)

You have QUERIES that take an hour to complete apparently.  They READ data.
They will never cause rollback to extend.  It is because the rollback doesn't
need to grow for the update transactions that you are getting the 1555.

You need to see how fast your smallest RBS wraps and make it PERMANENTLY larger
so it stops wrapping in the duration of time your longest statement takes to
execute.  That is the method to avoid the 1555.

This is the common mistake.  People size RBS for the update transactions, not
realizing they must be sized for ALL transactions -- read and write.

Rollback is an integral database structure, it is not something to be skimped
on.  There are rules of thumb out there for sizing them -- one of them is
something like 10% of the database size (30gig in your case).  That might be
extreme in your case, but maybe not.  Its not overhead, its not something you
can save $$ on.

You have probably spent more money on your salary trying to fix this and having
to re-run jobs then you would have spent on an 18gig mirrored disk (i'm almost
certain of that)


Subject | Article | Last Updated (East coast time)
How does a cursor in UGA is linked to a parsed sql statement | article only | Dec 24, 2001 08:41 am
Operating System File to Database and vice Versa | article only | Dec 24, 2001 09:27 am
Java Stored Procedure | article only | Dec 24, 2001 09:31 am
comparison betwwen pro*c and uti_file database package | article only | Dec 26, 2001 12:26 pm
Using ROWNUM | article only | Dec 26, 2001 12:50 pm
DATA TYPE SERIAL | article only | Dec 26, 2001 05:04 pm
complex Update | article only | Dec 26, 2001 05:15 pm
How to test a function returning a ref cursor from sqlplus | article only | Dec 26, 2001 08:58 pm
Followup to ROWNUM and exceptions | article only | Dec 27, 2001 09:44 am
decode help.... | article only | Dec 27, 2001 10:14 am
DBMS_OBFUSCATION_TOOLKIT | article only | Dec 27, 2001 01:54 pm
SQL help | article only | Dec 27, 2001 02:48 pm
OCI mid-tier question | article only | Dec 27, 2001 03:28 pm
Please help on SQL query | article only | Dec 27, 2001 03:37 pm
Week Range -- and getting quarters.. | article only | Dec 27, 2001 05:36 pm
Share Memory Segment | article only | Dec 28, 2001 09:08 am
Oracle 9i | article only | Dec 28, 2001 10:18 am
Nested Stored procedures | article only | Dec 28, 2001 01:48 pm
update... | article only | Dec 29, 2001 02:22 pm
RBO-Outer joined table as Driving table. | article only | Dec 29, 2001 02:36 pm
Relational VS Object Oriented Database Design | article only | Dec 30, 2001 10:12 am
row(s) 1 - 21 of 21
December 24, 2001 Sam -- Thanks for the question regarding "How does a cursor in UGA is linked to a parsed sql statement", version 8.1.7
You Asked
From one of your answers titled 'database buffer cache':

Parts of the cursor will be in the PGA and UGA and shared pool
(depending on the server mode -- dedicated server or MTS will
dictate where components are stored).  The current sessions
specific data being in the UGA as it is the specific to the user
(pga and uga are fairly synonymous in dedicated server mode,
very different in MTS mode).  The parsed cursor and query plan
                              --------------------------------

The result set itself (pointed to by the cursor but not really
part of the cursor) will be in either the sort (temp) area or
the database buffer cache -- depending on how the data is
accessed.  All cached blocks will be in the buffer cache -- if
there is a sort or aggregate or the need of temporary result
sets, then the sort area (which is in the pga and/or uga
depending on the server mode -- dedicated server or MTS again)
will hold much of the result set.

In many cases -- the data is "no where" as we do not fetch the
entire answer before getting the first row -- we typically get
the data as it is requested whenever possible.

1.You have left the underlined unfinished sentence. You  need to finish it.

2. "Parts of the cursor will be in the PGA and UGA and shared pool "

According to my understand cursors for a session are allocated from the users
pga/uga on the operating side, and each cursor points to a parsed query in the
shared pool.

what you mean by " Parts of the cursor will be in the PGA and UGA and shared
pool " , it is highly confusing. Do you mean data is partly in pga and uga (
when using sort memory area) and partly in the buffer cache. Clarify.

But a cursor is strictly confined to the users UGA on the operating system side
aint it.

3."In many cases -- the data is "no where" as we do not fetch the
entire answer before getting the first row -- we typically get
the data as it is requested whenever possible."

"NO WHERE" - does it point to data blocks, buffer cache, sort area.

4.I have also read on your website , that the bind variables associated with a
cursor are stored in the UGA. Then how do these bind variables get associated
with a query in the shared pool.

And I guess when we use hardcoded variabes we should be able to find them in the
shared pool and not in the users uga ?

Lastly how does this change when we switch to MTS from dedicated server mode.

Thank you
and we said...
The parsed cursor and query plan will be in the shared pool -- the library cache
-- to be shared by ALL sessions.

What I meant when I said: "Parts of the cursor will be in the PGA and UGA and
shared pool" is exactly what it says.  Your cursor in the UGA/PGA will point to
data in the library cache.  Your cursor is officially in a CGA (cursor global
area)  in your PGA/UGA (depending on configuration of Oracle) and will point to
areas in the shared pool.  So, part of it is in one place and part in the other.

So no, I would not say a cursor is strictly confined to the users UGA, It is
dependent on and points to other pieces of memory.

3) no where -- it doesn't point to ANYTHING yet.  When you open a cursor, we
might do nothing (other then set up the cursor).  It points no where.  The
result set hasn't been touched, there is no result set.  See, if we run this
code:

declare
    cursor c1 is select * from emp;
begin
    open c1;
    close c1;
end;

SELECT *
FROM
 EMP

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.00          0          0          0           0

"no where" -- no IO, no results, nothing.

4) your cursor area points to the SGA.  When you use hardcoded variables -- they
are in the SQL text itself, they are part of the query, they'll be in the
library cache.

In MTS -- the UGA is much larger as more stuff is stored in there (since the PGA
is specific to a process and in shared server mode you are not bound to a single
process).  The UGA is migrated to the SGA -- typically the LARGE_POOL (thats
where you want it).  So, your entire session state is stuffed in the UGA, the
UGA is in the SGA and the PGA is smaller (and you have less of them).
Review & Followup
Rating: 5
December 23, 2001
Reviewer: Sam
;
What I meant when I said: "Parts of the cursor will be in the PGA and UGA and
shared pool" is exactly what it says.  Your cursor in the UGA/PGA will point to
Data in the library cache.  Your cursor is officially in a CGA (cursor global
area)  in your PGA/UGA (depending on configuration of Oracle) and will point to
areas in the shared pool.  So, part of it is in one place and part in the other.

So no, I would not say a cursor is strictly confined to the users UGA, It is
dependent on and points to other pieces of memory.

;

So

1.Part of the cursor which is nothing but a pointer( which should be a minor
part of the cursor) will be in the uga/pga,

and

2.will point to the actual cursor area in the library cache with the parsed sql
statement( this should be the major part of the cursor)

I. Tom, can we control the size of a cursor, for example how much avg space does
steps 1 and 2 above take , how do we decide that.
II.So if we just open and close cursor, there will be no data movement, it will
not move from the place whereever it exists  i.e. either data blocks or from the
buffer cache.

so do you mena to say that once we fetch the cursor the size of the cursor
dynamically increases , depending upon the amount of data returned by the
associated parsed sql statement.

Thank you

Followup:
Part of the cursor will be a pointer, other parts will be other pointers to
results (retained sort areas and such), bind variables, the cursor state, what
its done, where it goes to next and so on.

Think of it like this, just like with "programs" there is TEXT (object code).
This is the query plan.  Every user can share the TEXT of a program.  Every
program instance (cursor) has its own stack pointer, stack data, results,
instruction pointers, etc.

I would say the MAJOR part is the cursor in the UGA/PGA.  The parsed, optimized
query plan us useless without it -- its just a plan.  The cursor is the instance
of that plan in action.  They go hand in hand.  Its up to you what you feel is
the "major" part -- you cannot really have one without the other.

I) you can in a fashion with things like "sort area retained size".  If you
consider that part of the cursor (i do personally).

II) maybe, maybe no.  A cursor is used to do an INSERT, a cursor is used to do
SELECT FOR UPDATE.  change my example to have a query like:

SELECT *
FROM
 EMP FOR UPDATE

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          1         18           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.00          0          1         18           0

and you can see we did IO.  The OPEN did that.

Rating: 5
To make it more clear , let me explain in my own way, you correct me , if Iam wrong December 23, 2001
Reviewer: Sam

According to you..

"Part of the cursor will be a pointer, other parts will be other pointers to
results (retained sort areas and such), bind variables, the cursor state, what
its done, where it goes to next and so on."

let us consider an example

Select * from emp where empno=:empno

1.The above select is parsed and is in the library cache.
2.:empno bind variable is in the uga/pga
3.Most of the data retrieved is in the buffer cache(assumption)

4.Some data is in the data blocks(assumption)
5.Some data is in the sort area(assumption),( and the sort area comes from the
uga/paga )

Now if we execute the query

1.we go to the uga/pga
2.through the cursor associated we are pointed to the parsed sql statement.
3.we are then pointed through different pointers ( 3 in fact to) data in buffer
cache, data blocks , sort area.

The cursor (i,e. pointer keeps pointing to one row after the other, first in the
data blocks, then in the buffer cache and then in the sort area)

Tom, you have to tell me if the above I have explained is accurate, kindly
verify my understanding.

Further, how long does the association between the parsed sqlstatment  and the
cursor stay active, how can we kill that association.

How many cursors like that can remain active with associated sql statements at a
given time( I guess 12 Iam I right , as according to you , oracle allots 12
cursors at a time).

Followup:
Conceptually, that is the way it would look.

The association between the cursor and the parsed sql statement stays active as
long as the cursor remains open.  If something invalidates the plan in the
cache, the cursor will know about it -- its a lifetime relationship from the
point of view of the cursor.  You kill the association by closing the cursor
(bear in mind, some environments like PLSQL and Pro*c will cache cursors for you
so a close might not be a real close).

You can have thousands of cursors, it depends on the open_cursor init.ora
parameter.  We allocate blocks of 64 cursor slots at a time, not 12.

Rating: 5
Thanks very much tom December 23, 2001
Reviewer: Sam
I guess I understand cursors now better than ever.

Now to just sign off, I just want to create  a situation in my sqlplus session
where I will hit the ora 01000 error, i.e.  max open cursors  exceeded , and
then I want to fix it by fixing my program, mind you I dont want to change the
init.ora param for fixing this error.

Can you give me one such program or scenario.

Thank you very much

Followup:
what do you program in.

Rating: 5
Mostly December 23, 2001
Reviewer: Sam
I program in pl/sql.

Some times I also do pro*c, and XML  and shell.

But most of the times it is the the good old PL/SQL.

Thank you

Followup:
Then don't worry about it.  Use IMPLICIT cursors, eg:

  select * into l_rec from t where ....;

or

  for x in ( select * from t )
  loop

and you never need concern yourself with this.  PLSQL will manage everything for
you.  Its only when you use explicit cursors that you have to worry about
closing them.

December 24, 2001 Sankalp -- Thanks for the question regarding "Operating System File to Database and vice Versa", version 8.1.6
You Asked
Dear Tom,

Hopefully, U r able to find time for this question as last few days U seem to be
very busy.

My question has two parts

A) We r building version control system as part of our insurance package using
FORM BUILDER . Using BFILE ,BLOB and dbms_LOB and PL/SQL code we can very well
upload file from operation system to Oracle Database. But , correct me if I am
wrong, downloading file from database to Operating system cannot be done using
PL/SQL. It needs Java interface.
   If it can be done using PL/SQL then how to go about it?

B) If its not possible using Pl/SQL, then what detailed way I can run a java
code from Forms Runtime?

Thanks in advance
SANKALP
and we said...
a) if it is a text file, UTL_FILE can easily create and write it.  See the
supplied packages guide for details on UTL_FILE.

If it is a binary file, a Java stored procedure will be the right approach.

b) You would just create a java stored procedure and run it just like you would
any PLSQL stored procedure, you won't be able to tell the difference.

My book has a whole chapter on java stored procedure, you can see many examples
here by searching for:

create replace compile java source named

on this site.
December 24, 2001 Quang Tien -- Thanks for the question regarding "Java Stored Procedure ", version 8.1.6
You Asked
Hi tom!

I am a newbie in writting stored procedure by java. Recently, I wrote a stored
procedure as following:

import java.io.*;
import java.sql.*;

class T5Ibs {

    /*
          * Scan Directory
     * In: The name of those directory
     * Out: None
     */
    public static String scan(String SharedDir) {

        File inf = new File(SharedDir);

        try {
            //Scaning the IN directory
            File[] infList = inf.listFiles();
            System.out.println("p_Path: " + inf.getAbsolutePath());
            //Processing the files in SharedDir directory
            return infList[0].getAbsolutePath();
        } catch (Exception e) {
                System.out.println("Scan: " + e);
            return "ERROR";
        }
    }

    public static void main(String[] args) {
        System.out.println("SharedDir"+scan("F:\\temp"));
    }

}
create or replace FUNCTION scan(dir varchar2)
  RETURN VARCHAR2
  AS LANGUAGE JAVA
  NAME 'T5Ibs.scan(java.lang.String) return java.lang.String';

I installed oracle on windows 2000. I ran successful when scan the local drivers
in that machine.
After that, I map 2 network driver (grant read, write permission):
the g driver from a windows 98: The program run successfully in both oracle and
windows2000
the f driver from another windows2000: The java program run successfully in
windows but failed when running stored procedure in oracle. The detail as
followwing:

conn system/manager
grant javasyspriv to center;
execute dbms_java.grant_permission('CENTER','java.io.FilePermission','*', '*');
/
conn center/center
set serveroutput on
exec dbms_java.set_output(20000)

declare
dir varchar2(40);
begin
dir:=scan('f:\temp');
dbms_output.put_line(dir);
end;
SQL> /
p_Path: f:\temp
Scan: java.lang.NullPointerException
ERROR

PL/SQL procedure successfully completed.

The same case also occurs when mapping a driver from a WinNT machime. It is very
helpful If you could explain the reason for me.

Thank in advance
Tien,
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:241814624807
In win/NT, unlike unix, a mapped drive is specific to a USER or even a specific
LOGIN instance.  Its not like an NFS mounted drive which everyone can see.

Oracle is running as a service, as a minimally priveleged user.  The above link
explains this in detail.
Review & Followup
Rating: 3
Java stored Procedure December 25, 2001
Reviewer: Pham Quang Tien from Ha Noi - Viet Nam
It is useful for my work and my knowledge

Thank again

December 26, 2001 Sachin -- Thanks for the question regarding "comparison betwwen pro*c and uti_file database package", version Oracle8i
You Asked
Hi tom

Would you please tell me either pro*c is fast or Database's
uti_file package is fast for generating a Report.

Thanks

Sachin Dhole
and we said...
In most every case, Pro*c will be faster however, as long as PLSQL is fast
enough, you would find its ease of programming, maintenance, development, etc to
outweigh any performance gain.

So, only if performance was the only criteria would I choose pro*c over a much
simplier language like plsql.  There are probably many more people that can
maintain/enhance the plsql over time then the pro*c.
Review & Followup
Rating: 2
Why is pro*c faster than pl/sql December 26, 2001
Reviewer: Kulguru
Tom

1.We have read you so many times, state that pl/sql is slower than pro*c , why
is it so.

2.Isnt it true that that from 9i  the performance of pl/sql is going to
radically improve, due to some changes in the way pl/sql coverts code into pcode
etc.

Followup:
1) C is C, C is fast (when correctly coded), C is very low level.  C runs as
native binary code on the operating system of choice.

PLSQL, even in 9i when it is natively compiled, is a high level language that is
interpreted.  Even when natively compiled, there is overhead involved due to the
VM (virtual machine) nature of the environment.

Rating: 3
Report by Pro*C December 26, 2001
Reviewer: Mohammed Al-moayed from Yemen
Yes, As I know that Using PRO*C is more efficient ,I want to leanr how to
perform report by using Pro*c .How can I do that by using it to Genrate Report
that Take Long Time.

Rating: 4
Canyou give this little clarification December 26, 2001
Reviewer: Kulguru
"PLSQL, even in 9i when it is natively compiled, is a high level language that
is interpreted.  Even when natively compiled, there is overhead involved due to
the VM (virtual machine) nature of the environment."

By the above, do you mean that untill 8i, the plsql code we are writing is being
converted into c code ,and then it is being converted into binary code.

But with 9i the pl/sql code is directly converted into binary code.

Is this what you mean.

Further,

"Even when natively compiled, there is overhead involved due to the VM (virtual
machine) nature of the environment."

What do you mean by the 'overhead involved due to the VM nature of the
environment.

TQ Tom

December 26, 2001 Munzer -- Thanks for the question regarding "Using ROWNUM", version 8i
You Asked
Tom:

I am trying to delete some rows in a table using rownum.  When I do a select
rownum,orgcode from org  it shows all rownum stating from 1 to 350.

When I try to delete using:

delete from org wher rownum > 280

it says no rows found.

It seems that using rownum works in select and delete whe nyou are using <
rownum otherwise if u use =,>,between it does not filter records as required.

DO you have any opinions on how to filter records and delete as I do not have a
primary key in the table and my best solution is to use rownum.

Do you use ROWNUM,ROWID for anything or is it just for oracle internal use.

Thank you,
and we said...
See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:948366252775
you cannot do what you are trying to do.  In fact, it really makes no sense.
You are delete a random set of 70 rows (rownum is NOT an attribute of a row, its
assigned as its fetched).  YOu might just as well delete from t where rownum <
70;  it'll do the same thing (delete SOME 70 rows and stop).

If you have specific rows you need to delete, you need to write a query that can
get those rows.

rownum and rowid are used all of the time by many applications in many cases,
they are not for internal use only.
December 26, 2001 felipe -- Thanks for the question regarding "DATA TYPE SERIAL", version 8.1.6
You Asked
Hi

I am new in Oracle.

I have experiences in Postgres. It had a data type serial (I used it type for
primary key), that I use the next form.

create table emp(id serial primary key, name varchar(50));

insert into emp(name) values('MIKE');

How can implements it in Oracle? Oracle had sequence and I tried to use
CREATE TRIGGER ....INSTEAD OF..., but it is only for views not for table. It is
the only form?

Thank's and Merry Crystmas
and we said...
you would create a sequence:

create sequence my_seq;

and then create a trigger on the BASE table:

create trigger <trigger_name>
before insert on <table_name> for each row
begin
   select my_seq.nextval into :new.primary_key_column from dual;
end;
December 26, 2001 Partha -- Thanks for the question regarding "complex Update", version 8.1.6
You Asked
Tom,

event_details Table has follwing structure

 Name                                      Null?    Type
 ----------------------------------------- -------- ---------------------
 E_KEY                                     NOT NULL NUMBER(10)
 E_OUTAGE_NUMBER                           NOT NULL NUMBER
 E_EVENT_IDX                                        NUMBER
 E_EVENT_CLS                                        NUMBER
 E_EVENT_TYPE                                       VARCHAR2(32)
 E_STATUS                                           NUMBER(22)
 E_ACTIVE                                           VARCHAR2(1)
 E_STREET_ADDRESS                                   VARCHAR2(100)
 E_CITY_STATE                                       VARCHAR2(45)
 E_POSTAL_CODE                                      VARCHAR2(28)
 E_BEGIN_TIME                                       DATE
 E_OUTAGE_INTERRUPT_DEV                             VARCHAR2(32)
 E_TROUBLE_CODE                                     VARCHAR2(64)
 E_OUTAGE_ACTION                                    VARCHAR2(32)
 E_OPS_EXCLUDE_REASON                               VARCHAR2(255)
 E_OPS_EXCLUDE_FLAG                                 VARCHAR2(1)
 E_OPERATOR_COMMENT                                 VARCHAR2(255)
 E_EVENT_STATUS                                     VARCHAR2(32)
 E_COMPLETION_TIME                                  DATE
 E_PHASES                                           NUMBER(38)
 E_EST_RESTORE_TIME                                 DATE
 DV_KEY                                             NUMBER(10)
 CZ_KEY                                             NUMBER(10)
 E_CUST_CALLED                                      NUMBER(38)
 E_PM_EXCLUDE_FLAG                                  VARCHAR2(1)
 E_NUM_MOMENTARIES                                  NUMBER
 E_EST_NUM_CUST                                     NUMBER
 E_CUST_OUT                                         NUMBER
 CIS_CLEANSED_FLAG                                  VARCHAR2(1)
 RDM_MAJOR_STORM_FLAG                               VARCHAR2(1)
 RDM_INDICES_FLAG                                   VARCHAR2(1)
 RDM_UPDATED_FLAG                                   VARCHAR2(1)

event_supply_nodes has following structure

 Name                                      Null?    Type
 ----------------------------------------- -------- ------------------
 E_KEY                                     NOT NULL NUMBER(10)
 ESN_SUPPLY_IDX                            NOT NULL NUMBER(38)
 DV_KEY                                             NUMBER(10)
 CZ_FEEDER_KEY                                      NUMBER(10)
 ESN_CUST_OUT                                       NUMBER(38)
 ESN_WHEN_RESTORED                                  DATE
 ESN_DURATION                                       NUMBER(38,4)
 ESN_CMI                                            NUMBER(38,4)
 RDM_UPDATED_FLAG                                   VARCHAR2(1)

Question: In the event_supply_nodes table update the esn_when_restored column
based on the updated e_completion_time column in event_details.

The logic i need is,

If the esn_when_restored is less than or equal to the e_completion_time,do not
update the column esn_when_restored.
Otherwise update esn_when_restored to the new e_completion_time.

Once the esn_when_restored is updated, update the esn_duration (in minutes)
to the difference between esn_when_restored & e_begin_time (from event_details
table) for that event.

Update the esn_cmi column as a product of esn_cust_out & the new esn_duration.

Thanks in Advance
and we said...
update ( select esn.esn_when_restored,
                esn.esn_duration,
                ed.e_completion_time,
                ed.e_begin_time
           from event_supply_nodes esn,
                event_details ed
          where esn.e_key = ed.e_key
            and nvl(esn.esn_when_restored,ed.e_completion_time+1) >
                                                      ed.e_completion_time )
  set esn_when_restored = e_completion_time,
      esn_duration = e_completion_time - e_begin_time
/

Simply update the join -- your complex logic becomes very simple.
Review & Followup
Rating: 4
ashraf gamal December 27, 2001
Reviewer: A reader

Rating: 4
Complex Update December 27, 2001
Reviewer: A reader
Really superb

Rating: 4
Complex update May 16, 2003
Reviewer: Marcio from Brazil
Are Analytic Function not allow on update?

update (
select sigla_tx
     , nvl(variante_tx, sigla_tx ||
             row_number() over ( partition by sigla_tx, variante_tx
                                     order by sigla_tx, variante_tx) )
new_variante
     , variante_tx
  from enlace_sc )
   set variante_tx = new_variante
/

Followup:
no, for the same reasons as ORDER BY and things that "sort" or "aggregate" are
not.  the results can be ambigous -- the same update of the same data could lead
to different results depending on how the data "fell out" of an order by
(considering an order by on a non-unique column for a moment...)

Rating: 4
Sorry about English :( May 16, 2003
Reviewer: Marcio from Brazil
The analytical functions are not allowed here?

update (
select sigla_tx
     , nvl(variante_tx, sigla_tx ||
             row_number() over ( partition by sigla_tx, variante_tx
                                     order by sigla_tx, variante_tx) )
new_variante
     , variante_tx
  from enlace_sc )
   set variante_tx = new_variante
/

December 26, 2001 oracle -- Thanks for the question regarding "How to test a function returning a ref cursor from sqlplus", version 8.1.7
You Asked
My function returns ref cursor. At the sqlplus prompt how should I test my
functions , and see the rows in the ref cursor.

the same from within a procedure how should I do it.

For the function I tried to do the following:

sqlplus>variable x refcursor

begin

open  c for 'select f_function(USA,SYSDATE,SYSDATE,0) into :x from dual'

end;

print :x

I want to see the rows returned by my function f_function , how should I do it.

When Iam trying to do

sqlplus>select f_function(USA,SYSDATE,SYSDATE,0)  from dual;
it is not working Iam getting a wrong datatype error.

Please guide.

Junior
and we said...
Ok, here is an example of a procedure, function and anonymous block that return
ref cursors in sqlplus:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace package types
  2  as
  3          type rc is ref cursor;
  4  end;
  5  /

Package created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace procedure get_cursor_proc(
p_cursor in out types.rc )
  2  is
  3  begin
  4          open p_cursor for select * from dual;
  5  end;
  6  /

Procedure created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace function get_cursor_func
return types.rc
  2  as
  3          l_cursor types.rc;
  4  begin
  5          open l_cursor for select * from dual;
  6          return l_cursor;
  7  end;
  8  /

Function created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> variable x refcursor
ops$tkyte@ORA817DEV.US.ORACLE.COM> set autoprint on
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM procedure
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec get_cursor_proc(:x)

PL/SQL procedure successfully completed.

D
-
X

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM function
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec :x := get_cursor_func

PL/SQL procedure successfully completed.

D
-
X

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM anonymous block
ops$tkyte@ORA817DEV.US.ORACLE.COM> begin
  2          open :x for select * from dual;
  3  end;
  4  /

PL/SQL procedure successfully completed.

D
-
X
Review & Followup
Rating: 5
cool, a day to day solution , and one more thing== September 15, 2001
Reviewer: A reader from USA
why doesnt select get_cursor_func from dual, work when it is returning a ref
cursor

Followup:
because a ref cursor is not a sqltype.  Only SQL types can be selected from a
user defined function (eg: select function_returning_boolean from dual won't
work either)

Rating: 5
what is the difference September 15, 2001
Reviewer: A reader from USA
Tom

What is a ref cursor.

What is the difference betweeen a regular cursor and a refcursor.

and

This is a often asked question in interviews.

Followup:
I ref cursor is a variable that holds a cursor.  Underneath, it is a "regular"
cursor.  It is a pointer to a cursor.

Normally a cursor is a static thing, it points to A query:

declare
    c1 cursor for select * from emp;
....

It is clear that C1 will run that query and none other.  A ref cursor can have
an arbitrary query associated with it:

declare
   type rc is ref cursor;
   c1  rc;
begin
   if ( a = b ) then
         open c1 for select * from emp;
   else
         open c1 for select * from dept;
   end if;
    .....

Rating: 5
Thank you , finally the concept is clear to me September 16, 2001
Reviewer: Chen from USA
Tom, Does oracle has any document which define all the terms like refcursor,
vaarray, nested table etc etc etc.

What I mean is a document which is like a dictionary of the above terms and
more.

Followup:
These constructs are documented as they are encounted.  All of the above are in
the plsql programmers guide (amongst others).

Rating: 5
dbms_output.put_line and print September 16, 2001
Reviewer: Thanks from USA
Internally are dbms_output.put_line  and print same. Do they work the same way.

In the refcursor function example you have given, if I have a dbms_output call,
will it be displayed when I give the print :x command.

Followup:
dbms_output and print are very very very different.

dbms_output.put_line just adds data to a big array.  After your call completes,
sqlplus reads this buffered data via dbms_output.get_lines and prints it.

PRINT prints the contents of a bind variable.

Rating: 4
Closing A Ref Cursor September 17, 2001
Reviewer: Anup Singh from India
Hi Tom,

Is It Not Required To Explicit Close A Cursor Opened By Ref Cursor ? Why ?

Thanks And Regards

Followup:
The client is responsible for closing the cursor.  In this case, the client is
ALWAYS sqlplus and sqlplus issues the close for us.  If the recipient of the ref
cursor was another PLSQL routine, it would be upto that plsql routine to close
it (if your java/jdbc client gets it - they close it and so on)

Rating: 5
According to the def given in the sqlplus guide , an anonymous block December 26, 2001
Reviewer: Kulguru
... need not have begin and end statements

"A PL/SQL program unit that has no name and does not require the explicit
presence of the BEGIN and END keywords to enclose the executable statements. "

But in your example for anonymous block , you have given the begin and end
statements.

Can you clear this confusion.

Followup:
ops$tkyte@ORA817DEV.US.ORACLE.COM> REM procedure
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec get_cursor_proc(:x)

PL/SQL procedure successfully completed.

D
-
X

that is an anonymous block as well.  It needs not have a begin/end in sqlplus
(only in sqlplus)

I was showing how to open a ref cursor using a PROCEDURE call and in just an
anonymous block -- which could have been coded as:

SQL> exec open :x for select * from dual;

just as easily, instead of:

ops$tkyte@ORA817DEV.US.ORACLE.COM> begin
  2          open :x for select * from dual;
  3  end;
  4  /

December 27, 2001 Munzer -- Thanks for the question regarding "Followup to ROWNUM and exceptions", version 8i
You Asked
AS a followup to :

The response to your question is waiting at:
http://asktom.oracle.com/pls/ask/f?p=4950:9:::NO::F4950_P9_ORIG,F4950_P9_DISPLAYID:Y,2311177153459
Tom:

1.  Are you saying that when I do "SELECT rownum from org" the rownum is
assigned at the moment the record is selected and not in the physical table?

IF that is the case what do you really can use Rownum for?
Should I never use rownum in a query criteria?

2.  I have a PL/SQL program and a WHEN OTHER exception as:

WHEN OTHER THEN
  htp.big('SQLCODE:  '||SQLCODE);
  htp.p('<BR>');
  htp.big(SQLERRM);
  htp.p('<BR>');

problem is that program is printing the oracle errors is a user definable screen
rather than oracle default screen.

However I can not get the second error code to be on separate line.  IT print
right after the first error message.  Are these errors stored anywhere, where I
ca nset a FOR LOOP in the exception to do the formatting?  DO you have any
ideas.

I am trying to print all program errors that occur in a nice format.

THank you,
and we said...
1) correct.

You can use it to limit the number of rows you get:

select *
  from ( select * from emp order by sal )
 where rownum <= 5;

will get the first 5 records AFTER sorting by sal....

It has various uses.  You can even use it to get rows N through M of a result
set (useful for pagination)
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:127412348064

2) you can either:

htp.p( '<br><pre>' );
htp.big( sqlerrm );
htp.p( '</pre><br> );

or

htp.big( replace( sqlerrm, chr(10), '<br>' ) );
December 27, 2001 vishnu -- Thanks for the question regarding "decode help....", version 8i
You Asked
Hi Tom ,
Merry Christmas and happy new year..
Can i have a decode function like this
 table.region  in decode(:region ,americas,('ccus','ccpr'),:region)
In the above what i am doing is if the parameter is "americas" it should return
'ccus' and 'ccpr' else any selected parameter ..pl explain.
Thanks
Vishnu
and we said...
ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( region varchar2(25) );
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'ccus' );
1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'ccpr' );
1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'xxxx' );
1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> variable region varchar2(25)

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec :region := 'americas';
PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select *
  2    from t
  3   where region in ( select decode(:region,'americas','ccus',:region)
  4                       from dual
  5                      UNION ALL
  6                     select decode(:region,'americas','ccpr',:region)
  7                       from dual
  8                   );

REGION
-------------------------
ccpr
ccus

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec :region := 'xxxx';
PL/SQL procedure successfully completed.

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

REGION
-------------------------
xxxx

ops$tkyte@ORA817DEV.US.ORACLE.COM>
Review & Followup
Rating: 3
decode help December 26, 2001
Reviewer: vis from USA
Hi Tom ,
Thank you very much for the answer ,However if i run the querry in oracle
reports i am getting an error that key word select is missing.Do i need to
modify decode while in oracle reports..
Can u pl help

Followup:
It must be a reports issue, can you use dynamic sql (to avoid having reports
attempt to parse the query) or use a ref cursor from a stored procedure (to
avoid again having reports attempt to process the query)

Also, please file a TAR with support.

Rating: 4
Need more December 27, 2001
Reviewer: A reader
Hi, Tom

Would you mind give us an short example to display how to
get a work around by DYNAMIC SQL please, i can not get it.
There are issues with REF CURSOR work around. We are using REF SURSOR in report
right now, but as long as we move from
development to production, it can not find the program unit,
and it seems a bug(we already find workaroung).

Thanks

Followup:
sorry, I don't do reports personally.  Please try
http://otn.oracle.com/
under discussions to see if anyone there has an idea for you.

One workaround I can give you from the DATABASE perspective is:

create view V
as
 select *
   from t
  where region in
      ( select
decode(userenv('client_info'),'americas','ccus',userenv('client_info'))
          from dual
         UNION ALL
        select
decode(userenv('client_info'),'americas','ccpr',userenv('client_info'))
          from dual
      );

you will just call:

  dbms_application_info.set_client_info( :region );

and then "select * from v"

December 27, 2001 William -- Thanks for the question regarding "DBMS_OBFUSCATION_TOOLKIT", version 8.1.6
You Asked
Hi Tom,
 In a stored procedure I try to call DESencrypt functino to encrypt a
password but get DBMS_OBFUSCATION_TOOLKIT not available message. Could you
please tell me what SQL file I need to run to make this package availible in a
NT server. Thanks.

William
and we said...
run catobtk.sql in $ORACLE_HOME/rdbms/admin

but a better way to store a password is to NOT store a password!  Hash it
instead.  Storing the password means someone can get your key (it must be in
your code or somewhere) and get all passwords.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:95412348059
for details.
December 27, 2001 Ping -- Thanks for the question regarding "SQL help", version 8.1.7
You Asked
Hi Tom,

Thanks for helping me solve the outer join problem.

Now I have a question about the single quot "'" in character string.

I have a stored procedure like this:

Create or replace procedure xyz is
cursor c_cursor is
select x,y,z from test;
v_x  varchar2(20);
v_y  varchar2(20);
v_z  varchar2(20);

begin
  open c_cursor;
  loop
    fetch c_cursor into v_x, v_y,v_z;
    exit when c_cursor%NOTFOUND;

update anothertable
set yyy = v_y,
    zzz = v_z
where xxx = v_x;

  end loop;
    close c_cursor;
end;
/

The problem is it is possible that the v_x,v_y,v_z string have the single quot
in them, like "98's model".

Please help how to get it work. Thanks as always,

Ping
and we said...
It needs no help.  You need not worry about single quotes when using bind
variables and you are using bind variables.

It just works.  Try it.

Btw, you should just code:

  update ( select yyy, zzz, y, z
             from test, anothertable
            where test.x = anothertable.xxx )
     set yyy = y,
         zzz = z;

never do procedurally what can be accomplished in a single statement.  Also --
implicit cursors are faster and easier to code with, so:

begin
  for x in ( select * from test )
  loop
     update anothertable set yyy = x.y, zzz = x.z where xxxx = x.x;
  end loop;
end;

would be preferable to your approach as well, but just use the single update.
Review & Followup
Rating: 5
Revise of my question December 27, 2001
Reviewer: Ping from VA USA
Tom,

The question is more complicated than the one I asked just now -- I am trying to
use a simplied form to ask my question, but I failed.

The single quot problem arises when I constructed a string and then execute
immediate. Here is the scenario:

I have two tables A and B with almost the same structure, using A to update B,
but only updating the columns of B if the column from A is not null. The logic I
am using to construct the string is like this:

 IF   V_DESCR IS NOT NULL THEN
  V_STRING := V_STRING||'DESCR = '''||V_DESCR||''', ';
 END IF;

But the thing is the v_descr already has a ' in it, so I got an error ORA-00933,
SQL command not properly ended.

Please advise how to get away with it. Thanks, Ping

Followup:
Do not do that!!  Use bind variables!!

Use DBMS_SQL and bind that value in.  Otherwise you'll trash your shared pool
and your system can and will grind to a halt over time.

Use bind variables!  Excessively important (so important, i'm not going to tell
you how to do the quote in the string).

Rating: 4
Good answer December 27, 2001
Reviewer: Rejib Sankaran from Seattle, Washington USA
Thank you Tom for helping out, and thank you Ping for answer the question I
wanted to ask.

December 27, 2001 Tom -- Thanks for the question regarding "OCI mid-tier question", version 8.1.7
You Asked
I'm working on the middle-tier (using OCI) of an application and have a design
question.  The mid-tier communicates to an applet client; and communication
between the two is done with XML.

I call into Oracle stored procedures from the OCI app.  Several of the
procedures accumulate results from a number of tables.  I would just do joins
and return the result, but some of the data is header/detail.  Does it make more
sense to return call a single procedure that returns a CLOB with the results of
multiple queries in an XML format, or should I call several different procedures
from the OCI app?

Previously, I've used DBMS_XMLQUERY to automatically format the results from a
query; and I've used DBMS_LOB to work with long strings, but I'm sort of stuck
on which would be the best option for this.

I'd appreciate any advice you may have.

Have a happy New Year.
and we said...
By far, using dbms_xmlquery and the related XML toolkit functions would be my
preference.  Anytime I can call the database and have it do my work for me -- I
do so.

So, I (personally) would tend to encapsulate the logic in a stored procedure
exclusively.  At that point -- I would drop all mention of C and just use
mod_plsql with Apache.  No need to code in OCI to do this.
December 27, 2001 Sreenivas -- Thanks for the question regarding "Please help on SQL query", version 8.0.6
You Asked
Hi Tom,
Can you help re-writing a sql query whenever you have time?
The following sql query:
"select sum(vmi_trending_level_lbs) lbs,
sum(vmi_trending_raw_reading) units,
sum(vmi_trending_level_ft_per_min) items,
sum(vmi_trending_level_gallons) gal,
vmi_trending_reading_date
from vmi_trending
where (vmi_trending_reading_date,vmi_trending_composite_key) in ( select
c.vmi_trending_reading_date,c.vmi_trending_composite_key
from vmi_supply_chain_data a,vmi_aggregate_silos b,
vmi_trending  c
where a.vmi_sc_id = 113
and a.vmi_sc_aggregate_id = b.vmi_aggregate_id
and b.vmi_aggregate_silo_comp_key = c.vmi_trending_composite_key   and
c.vmi_trending_reading_date>to_date('10/25/2001','MM/DD/YYYY'))
group by vmi_trending_reading_date;"

returns following output:
LBS    UNITS    ITEMS    GAL    VMI_TRENDING_READING_DATE
436745    436745            10/25/2001 12:30:00
527649    527649            10/25/2001 20:30:00
460336    460336            10/26/2001 04:30:00
748662    748662            10/26/2001 12:30:00
485917    485917            10/26/2001 19:30:00
1818864    1818864            10/27/2001 04:30:00
867846    867846            10/27/2001 21:40:00

Whereas my requirement is to get only the last readings of each day like:
LBS    UNITS    ITEMS    GAL    VMI_TRENDING_READING_DATE
527649    527649            10/25/2001 08:30 PM
485917    485917            10/26/2001 07:30 PM
867846    867846            10/27/2001 09:40 PM

Can this be done using single sql query without having to use ref cursor?

Thank you in advance.
and we said...
Sure, pretend this simple select * from t:

ops$tkyte@ORA806.WORLD> select * from t;

       LBS      UNITS DT
---------- ---------- -------------------
    436745     436745 10/25/2001 12:30:00
    527649     527649 10/25/2001 20:30:00
    460336     460336 10/26/2001 04:30:00
    748662     748662 10/26/2001 12:30:00
    485917     485917 10/26/2001 19:30:00
   1818864    1818864 10/27/2001 04:30:00
    867846     867846 10/27/2001 21:40:00

7 rows selected.

is your EXISTING query above, just wrap the following around it:

ops$tkyte@ORA806.WORLD>
ops$tkyte@ORA806.WORLD> select to_char(
to_date(substr(data,1,14),'yyyymmddhh24miss'), 'mm/dd/yyyy hh:mi am' )
  2                                  VMI_TRENDING_READING_DATE,
  3         to_number(substr(data,15,12)) lbs,
  4         to_number(substr(data,27))    units
  5    from ( select max( to_char( dt, 'yyyymmddhh24miss' ) ||
  6                       to_char(lbs,'00000000009') ||
  7                       to_char(units) ) data
  8             from ( select * from t )
  9            group by trunc(dt)
 10         )
 11  /

VMI_TRENDING_READIN        LBS      UNITS
------------------- ---------- ----------
10/25/2001 08:30 pm     527649     527649
10/26/2001 07:30 pm     485917     485917
10/27/2001 09:40 pm     867846     867846

ops$tkyte@ORA806.WORLD>

and you get what you want.  We trick MAX into picking up not only the MAX date
(by encoding the date into a sortable string) but the other fields as well.  We
just have to substr them back out for display....
Review & Followup
Rating: 5
Wise trick December 27, 2001
Reviewer: KS from MA USA
It's very useful trick to manupulate dates, Thanks a lot.

Rating: 2
December 27, 2001
Reviewer: A reader
select to_char(
to_date(substr(data,1,14),'yyyymmddhh24miss'), 'mm/dd/yyyy hh:mi am' )
  2                                  VMI_TRENDING_READING_DATE,
  3         to_number(substr(data,15,12)) lbs,
  4         to_number(substr(data,27))    units
  5    from ( select max( to_char( dt, 'yyyymmddhh24miss' ) ||
  6                       to_char(lbs,'00000000009') ||
  7                       to_char(units) ) data
  8             from ( select * from t )
  9            group by trunc(dt)
 10         )
 11  /

Can you explain this query in different steps to us, and what is the trick you
are talking about .

Followup:
see
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1992894042210
it explains the crux of this.

What I did was build a SORTABLE string

to_char(dt,'yyyymmddhh24miss') || to_char(lbs,'00000000009') || to_char(units)

We took the MAX() of this string by trunc(dt) -- that found the MAX for each
unique day (what was asked for).

We then substr back out the fields we needed, performing the necessary
conversions back to the base types.

December 27, 2001 Theresa -- Thanks for the question regarding "Week Range -- and getting quarters..", version Version 7
You Asked
I would like to code a between date parameter which uses sysdate
to calculate last weeks start and end date. With a sysdate =
06/08/00 then last weeks date range is 05/28/00 through
06/03/00.

I would also like to figure out the previous quarter from any
sysdate.

Thank you in advance.
and we said...
You can use NEXT_DAY and a little math on sysdate to do this.
If you take sysdate and go back 14 days (2 weeks) and find the
NEXT sunday, thats the beginning of the range.  Take sysdate go
back a week (7 days) and find the next SAT, thats the end of the
range.

Here is an example (you'll just need to verify the boundary
values are in line with what you are thinking and adjust it
accordingly):

ops$tkyte@8i> select next_day( (sysdate+r)-14, 'SUN' ),
  2         next_day( (sysdate+r)-7, 'SAT' ),
  3         (sysdate+r)
  4  from ( select rownum-10 r
  5           from all_objects
  6          where rownum < 25 )
  7  /

NEXT_DAY( NEXT_DAY( (SYSDATE+
--------- --------- ---------
21-MAY-00 27-MAY-00 30-MAY-00
21-MAY-00 27-MAY-00 31-MAY-00
21-MAY-00 27-MAY-00 01-JUN-00
21-MAY-00 27-MAY-00 02-JUN-00
21-MAY-00 03-JUN-00 03-JUN-00
28-MAY-00 03-JUN-00 04-JUN-00
28-MAY-00 03-JUN-00 05-JUN-00
28-MAY-00 03-JUN-00 06-JUN-00
28-MAY-00 03-JUN-00 07-JUN-00
28-MAY-00 03-JUN-00 08-JUN-00
28-MAY-00 03-JUN-00 09-JUN-00
28-MAY-00 10-JUN-00 10-JUN-00
04-JUN-00 10-JUN-00 11-JUN-00
04-JUN-00 10-JUN-00 12-JUN-00
04-JUN-00 10-JUN-00 13-JUN-00
04-JUN-00 10-JUN-00 14-JUN-00
04-JUN-00 10-JUN-00 15-JUN-00
04-JUN-00 10-JUN-00 16-JUN-00
04-JUN-00 17-JUN-00 17-JUN-00
11-JUN-00 17-JUN-00 18-JUN-00
11-JUN-00 17-JUN-00 19-JUN-00
11-JUN-00 17-JUN-00 20-JUN-00
11-JUN-00 17-JUN-00 21-JUN-00
11-JUN-00 17-JUN-00 22-JUN-00

24 rows selected.

and to get the previous qtr, something like:

ops$tkyte@8i> select
     mod( to_char(add_months(sysdate,r),'Q')+2, 4)+1 last_qtr,
  2             to_char( add_months( sysdate,r ), 'Q' )
curr_qtr,
  3             add_months( sysdate,r )
  4    from ( select rownum-1 r from all_objects where rownum <=
12 )
  5  /

LAST_QTR                                      C ADD_MONTH
--------------------------------------------- - ---------
                                            1 2 08-JUN-00
                                            2 3 08-JUL-00
                                            2 3 08-AUG-00
                                            2 3 08-SEP-00
                                            3 4 08-OCT-00
                                            3 4 08-NOV-00
                                            3 4 08-DEC-00
                                            4 1 08-JAN-01
                                            4 1 08-FEB-01
                                            4 1 08-MAR-01
                                            1 2 08-APR-01
                                            1 2 08-MAY-01

12 rows selected.

should do it.
Review & Followup
Rating: 4
To find Last "n" weeks December 27, 2001
Reviewer: Gonela from Chicago, USA
My requirement would be to find-out last 13 weeks data.

If this date starts from the middle of the week, we should pick last 13 weeks
starting from prior week of input date.

Also, if the input date is of JAN or FEB month, it should pick previous year
data also.

Your quick help in writing SQL query for this, would be appreciated.

From the following Query, I am getting last 13 months based on the input date.
Same way, I want to get last 13 weeks.
Request your help in this regard.
-----------------------------------------------------------
SELECT DISTINCT
TO_CHAR(TO_DATE('10-Jan-01','DD-MON-RR'),'WW')-r "Week Counter",
ADD_MONTHS(TO_CHAR(TO_DATE('10-Jan-01','DD-MON-RR'),'DD-MON-RR'),-r   ) "Last 13
Months"
    FROM ( SELECT ROWNUM r
            FROM all_objects
            WHERE ROWNUM < 14)
--------------------------------------------------
Look forward for your reply,

Followup:
Not sure if I have the right exact logic for you here, you can fine tune it.
All I'm doing is going back one week (-7) and finding the next SATURDAY and then
subtracting 13*7 days from that.  That tells me when the 13 week period begins:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select dt, next_day(dt-7, 'SAT')-13*7
  2    from ( select sysdate+rownum dt from all_objects where rownum < 25 )
  3  /

DT        NEXT_DAY(
--------- ---------
28-DEC-01 22-SEP-01
29-DEC-01 29-SEP-01
30-DEC-01 29-SEP-01
31-DEC-01 29-SEP-01
01-JAN-02 29-SEP-01
02-JAN-02 29-SEP-01
03-JAN-02 29-SEP-01
04-JAN-02 29-SEP-01
05-JAN-02 06-OCT-01
06-JAN-02 06-OCT-01
07-JAN-02 06-OCT-01
08-JAN-02 06-OCT-01
09-JAN-02 06-OCT-01
10-JAN-02 06-OCT-01
11-JAN-02 06-OCT-01
12-JAN-02 13-OCT-01
13-JAN-02 13-OCT-01
14-JAN-02 13-OCT-01
15-JAN-02 13-OCT-01
16-JAN-02 13-OCT-01
17-JAN-02 13-OCT-01
18-JAN-02 13-OCT-01
19-JAN-02 20-OCT-01
20-JAN-02 20-OCT-01

24 rows selected.

December 28, 2001 Huy -- Thanks for the question regarding "Share Memory Segment", version 8.1.6
You Asked
Dear Tom,
After I installed Oracle Software version 8.1.6 for Linux, I run
SVRMGRL,I startup nomount then I meet error :

SVRMGR> startup nomount
ORA-27123: unable to attach to shared memory segment
Linux Error: 22: Invalid argument
My Sytem :
         -RedHat 7.0
         -RAM 128 Mb
         -Main/Chip Intel
Linux System Configuration :
 Share Memory :
    -SHMMAX 67108863
    -SHMMIN 1
    -SHMMNI 100
    -SHMSEG 10
 Senaphores :
    -SEMMNI 100
    -SEMMSL 110 ( PROCESSES = 100 In init file)
    -SEMMMNS 200
    -SEMOPM 100         -SEMVMS 32767
Please help me.
Regards.
----------------------------------------
Thanks Tom,
I glad to recevied your mail, this is my init file :

SID = VSW
open_cursors = 100
max_enabled_roles = 30
db_block_buffers = 409600
shared_pool_size = 41943040
large_pool_size = 614400
java_pool_size = 0
log_checkpoint_interval = 10000
log_checkpoint_timeout = 1800
processes = 100
log_buffer = 163840
db_block_size = 8192

I think SGA very very big, but pls show more detail.

Thanks,
Regards
and we said...
You are trying to allocate a 3.12 GIG SGA on a machine with 128
MEG of ram.

ops$tkyte@ORA8I.WORLD> select 409600*8+409600/1024+614400/1024
from dual;

409600*8+409600/1024+614400/1024
--------------------------------
                         3277800

Thats how many K of ram you are asking for.

ops$tkyte@ORA8I.WORLD> select 3277800/1024 from dual
  2  /

3277800/1024
------------
  3200.97656

Thats how many meg

ops$tkyte@ORA8I.WORLD> select 3200.97656/1024 from dual;

3200.97656/1024
---------------
     3.12595367

ops$tkyte@ORA8I.WORLD>

And thats how many GIG

You need to back WAY off on you db_block_buffers.

Set db_block_buffers to 500 for now.
Set shared_pool_size to 15360000.
Unless you are using MTS, set large_pool_size to 0.
Set the java_pool_size to 1048576.
Review & Followup
Rating: 3
SGA Config. December 28, 2001
Reviewer: Johnson from India
Can you please suggest us the init.ora parameters with values for a 128MB RAM
system?

Followup:
Well, thats a tiny system, hope its single user development...

say 15meg shared pool
    10meg block buffers
     0meg large pool
     1meg java pool if you are not using java in the db 20meg otherwise

December 28, 2001 Suresh -- Thanks for the question regarding "Oracle 9i", version 8.1.7
You Asked
Tom,
  I do not know if I can ask you this. I would like to buy Oracle 9i,
Forms/Reports 6i, Designer and Discoverer..Could you please give me the URL link
or Toll-free number that I can contact to get the software. Thanks.

Regards,
Suresh
and we said...
http://store.oracle.com/
is the place to go.
December 28,
      2001 Sonali -- Thanks for the question
      regarding "Nested Stored procedures", version 8.1.7/ 8.0.6

      You Asked
Is this what I am observing here is true ?
What if I want to rollback the whole transaction even if the outer procedure
fails after the call to inner procedure ?

I have 2 procedures here ...
The 1st procedure is called inside the 2nd one. I am making the outside
procedure fail by inserting duplicate PK values.
But to my surprise - this is what is happening
In pr_test procedure the 1st insert gets commited.
In pr_nestedtest procedure the insert gets commited.
But when it comes back to pr_test to do the 2nd duplicate insert which fails and
does not get commited but I thought that it will rollback my 1st insert from
pr_test but it doesn't !!!!
So if the outside procedure fails before calling the inner procedure everything
gets rollbacked, but if it fails after the call to inside procedure and inside
one gets commited, everything till the end of the inside procedure gets
commited.

Work_id is a Primary key of this table.

Create or replace procedure pr_nestedtest(inold_ID int)
IS
Begin
INSERT into work (Work_ID, Work_Level, WORK_CHARGEBACK)
values(199,inold_ID, 50);

Commit;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END pr_nestedtest;
/

---------------------------------------------------------------------------------
-------------------------------------

create or replace procedure pr_test(inold_ID int)
IS
Begin
INSERT into work (Work_ID, Work_Level, WORK_CHARGEBACK)
values(inold_ID ,100, 50);

pr_nestedtest(inold_ID); ---Execute PROCEDURE

-- making outside procedure fail by inserting duplicate PK values

INSERT into work (Work_ID, Work_Level, WORK_CHARGEBACK)
values(inold_ID ,500, 50);

Commit;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END pr_test;
/

If I take out the commit statement from the inner procedure everything gets
rollbacked which is what I would want. But the real case which I am concerned
about has a inner procedure inside cursor and is huge. So if I take out the
commit then I will run out of Rollback segment, what should I do ? I want the
whole outer procedure along with inner to rollback if anything anywhere fails.
So how do we make the whole thing rollback?

Can I use savepoints ? How are they different from rollback ? I am also reading
your book right now to see if it has any hints.

In the procedure can I specify the rollback segment name?   We may need to have
a really big rollback segment for this.  Or maybe it can be part of the create
procedure statement?

I cannot do set transaction rollback xxx; because this procedure will be called
from external program.

Create or replace procedure pr_nestedtest(inold_ID int)
IS
Begin
INSERT into mwebwork (Work_ID, Work_Level, WORK_CHARGEBACK)
values(199,inold_ID, 50);

END pr_nestedtest;
/

Thanks
Sonali

      and we said...
wow, you really need to understand more about transactions.

A commit is a commit -- it commits all outstanding work and cannot be undone.
The entire purpose, goal and only meaning of commit is to make changes
permanent.

The "nesting" of procedures has nothing to do with this behavior.  Whether you
coded in a linear fashion (no procedures) or modular -- the effect would be the
same.  Commit -- and the data is committed, will not be rolled back.

Look at your logic in thinking here:

<quote>
If I take out the commit statement from the inner procedure everything gets
rollbacked which is what I would want. But the real case which I am concerned
about has a inner procedure inside cursor and is huge. So if I take out the
commit then I will run out of Rollback segment, what should I do ?

</quote>

well, if you release that rollback (you appear to be trying to "save" on some
resource here) how would we be able to rollback???

Savepoints won't release rollback -- if they did, we wouldn't be able to roll
back!!

You should use equi-sized rollback segments.  You need to bite the bullet and
size your system for what you do.  Having a "big" rbs and using "set
transaction" is something i really don't like to do (yes, you can do this in the
procedure as long as the transaction has not yet begun as the set transaction
must be the first statement in there).

My approach would be to SIZE rollback appropriate so that any rbs would do.

Review &
      Followup

      Rating:
      3
  December 28, 2001
Reviewer:
      sonali  from newton, ma usa
I know what commit means I should have been more clear about my question.
What I was confused about was -
Que1 -
In this case something failed after the call to inner procedure ( which had its
own begin and commit), so inner procedure will get commited but I thought
because I had exception,rollback on the outer one, and the statement in the
outer procedure failed after the call to the inner procedure,
I thought that if anything fails/ anywhere in the outer procedure will rollback
everything in the outer procedure commiting only the inner procedure. But like I
said, I was wrong about that.

Que2-
this is a different que- I want to rollback everything no matter where it fails,
inner/outer so obviously I will not have commit in inner procedure, so I was
thinking if I can use savepoint( but you said I cannot- got it) or if I can set
transaction rollback segment xxx; inside procedure, which you said is not a good
idea, why do you say that having equal RB is better than setting one for this
procedure ?
I have equal rollback set segments set on the server, but was going to set one
for this so that it will not slow others down, or in other words did not wanted
to use all RB space making others unable to work.

thanks
Sonali

          Followup:

procedures do not cause ANY nesting of transactions.  You can use autonomous
transactions (see

http://osi.oracle.com/~tkyte/autonomous/index.html
) but they are a totally different beast.

You can use a savepoint, it just won't do anything for you in your case.

All RBS is shared by everyone.  Using the set transaction use rollback segment
won't affect:

<quote>
but was going to set one
for this so that it will not slow others down, or in other words did not wanted
to use all RB space making others unable to work.
</quote>

for the simple reason that the one you explicitly use will continue to be used
by everyone else in a round robin fashion.  It does not set it aside just for
you.

December 29, 2001 -- Thanks for the question regarding "update...",
      version 8

      You Asked
This question is regarding about update table
I have one table
Create table test (item_no number, sls_date date);
Itemno  sls_date
------  ----------
1001    1-jan-91
1001    1-feb-91
1001    3-mar-91
1002    1-jan-91
1002    2-mar-91
1002    5-jun-91
1003    5-jan-91
1004    7-mar-91
 and so on…

later I modify test table and add sr_no number (5)  (sr_no for serial number)

and now I need to update test table sr_no according to the date.

Like I want result like this
Sr_no    Itemno   sls_date
------- --------  ----------
1        1001    1-jan-91
2        1001    1-feb-91
3        1001    3-mar-91
1        1002    1-jan-91
2        1002    2-mar-91
1        1003    5-jan-91
2        1003    7-jan-91
1        1004    7-mar-91
 and so on…

can I update serial number with simple update statement or need to write
producer can u please show me with example

      and we said...
Here are two approaches, one in sql one procedural.  which works best depends on
volumn of data and indexes that exist:

ops$tkyte@ORA9I.WORLD> create table t ( itemno int, sls_date date );

Table created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> insert into t values ( 1001,'1-jan-91' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values ( 1001,'1-feb-91' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values ( 1001,'3-mar-91' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values ( 1002,'1-jan-91' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values ( 1002,'2-mar-91' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values ( 1002,'5-jun-91' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values ( 1003,'5-jan-91' );

1 row created.

ops$tkyte@ORA9I.WORLD> insert into t values ( 1004,'7-mar-91' );

1 row created.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> alter table t add sr_no number;

Table altered.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> update t
  2     set sr_no = ( select count(*)
  3                     from t t2
  4                    where t2.itemno = t.itemno
  5                      and t2.sls_date <= t.sls_date )
  6  /

8 rows updated.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> select *
  2    from t
  3   order by itemno, sls_date
  4  /

    ITEMNO SLS_DATE       SR_NO
---------- --------- ----------
      1001 01-JAN-91          1
      1001 01-FEB-91          2
      1001 03-MAR-91          3
      1002 01-JAN-91          1
      1002 02-MAR-91          2
      1002 05-JUN-91          3
      1003 05-JAN-91          1
      1004 07-MAR-91          1

8 rows selected.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> update t set sr_no = null;

8 rows updated.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> declare
  2      l_last_itemno number default -1;
  3      l_seq         number;
  4  begin
  5      for x in ( select rowid r, itemno from t order by itemno, sls_date )
  6      loop
  7          if ( l_last_itemno <> x.itemno )
  8          then
  9              l_seq := 1;
 10              l_last_itemno := x.itemno;
 11          end if;
 12          update t set sr_no = l_seq where rowid = x.r;
 13          l_seq := l_seq+1;
 14      end loop;
 15  end;
 16  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> select *
  2    from t
  3   order by itemno, sls_date
  4  /

    ITEMNO SLS_DATE       SR_NO
---------- --------- ----------
      1001 01-JAN-91          1
      1001 01-FEB-91          2
      1001 03-MAR-91          3
      1002 01-JAN-91          1
      1002 02-MAR-91          2
      1002 05-JUN-91          3
      1003 05-JAN-91          1
      1004 07-MAR-91          1

8 rows selected.

Review &
      Followup

      Rating: 4
my
      remarks  December 29, 2001
Reviewer:
      A reader
it works nice tom thank u very much

December 29, 2001 Rahul -- Thanks for the question regarding
      "RBO-Outer joined table as Driving table.", version 8.1.7

      You Asked
Hello Tom,

1)I am under the impression that for Cost based optimizer, a table participating
in an Outer join(+) will not be used as the driving table. Is the same
applicable for RBO. If yes, then what if i accidentally have a table used in
outer join as the last table in the from clause(dr.table for RBO). Is the next
from right, used as the driving table.

2)What will happen if i delete the statistics for entire schema, but still use
hints for some queries(ORDERED).Will there be any difference in the performance
while the statistics are deleted but hints are still used.Will hints enable
Oracle use the CBO while Optimizer mode is set to CHOOSE.

3)Could i strictly ensure that Oracle uses CBO for some queries and RBO for
some??.

Thanks,
Rahul.

      and we said...
1) a table that is outer joined to, eg:

  select *
    from dept, emp
   where emp.deptno (+) = dept.deptno;

(here emp is being outer joined to) Cannot be used as a driving table under
either optimizer.  The RBO uses the table order only when it can, else it uses
rules to reorder the tables in the from clause.  Here, DEPT will be the driving
table regardless of optimizer goal.

2) You will be using the CBO for all queries with hints (unless the hint is RULE
of course).  The optimizer will make its decisions based on little to no data.
How it will work depends on your data and your queries.  No statements of fact
can be made without knowing that information.

3) Set the optimizer goal to RULE in the init.ora.  Then add an ALL_ROWS or
FIRST_ROWS hint to queries you want to use the CBO with.

Or, analyze your tables and use the RULE hint when you wanted to use the RBO.

However, I would suggest you twiddle with the optimizer_index_cost_adj init.ora
parameter and use the CBO exclusively.

You might want to pick up Jonathan Lewis's book "Practical Oracle8i" -- he has a
good discussion on this.
Review & Followup

      Rating: 4
RBO and driving
      table  July 10, 2001
Reviewer:  Rahul Pathri
       from Sunnyvale, CA USA
The information provided clarified a lot and paved way for new experiences.

      Rating: 4
If structured
      properly is RBO still a good optimizer to choose  December
      29, 2001
Reviewer:  Lakshmi Narasimhan R  from Dubai,
      UAE
Hi Tom

in my firm, they have developed their big product based on RBO fully.  Since
already been couple of versions running on diff clients they are not willing to
change this and also its working without much problem.

Is there any problem now changing it into CBO and analysing all the tables.
Since all select has been made for RBO will it create problem ?  or Oracle
engine is capable of handling automatically.

I am arguing to change to CBO since couldnt use most of the new features like
partition, function based index etc.

You have any suggestion.

thanks in advance

          Followup:

You will have to test -- it is something I would consider a major change.  Some
queries will run better, some will run unchanged -- undoubtably there will be
some that do not perform as well and may need some help via init.ora parameters
or reworking.

      Rating:
      3
  December 29, 2001
Reviewer:
      Kulguru
"The RBO uses the table order only when it can, else it uses rules to reorder
the tables in the from clause"

Tom, this is for the first time that you are stating this fact on your web site.

From your earlier discussions, I was under the impression that when we use RBO,
the order of the table is used for sure, but when we use CBO, then the order of
tables doesnt matter unless and untill we use the /* + ordered */ hint.

It is coming really as a surprise that for example

when we use  a

query like

select * from emp, dept
where emp.deptno=dept.deptno

you are saying that using RBO , there is a possibility that  emp might be used
as a driving table and not dept.

Can you substantiate this claim.

Thank you

          Followup:

Well, lets be clear here.  Its always ONLY been true that the order of the
tables in the from clause MAY affect the query plan in the RBO.  Stress the
keywords ONLY and MAY.  It is true that in RBO, the order of tables in the from
clause can be important.  It is true that in CBO, it is not so.  It is true that
in RBO, it will use RULES to process the query and these rules govern how the
tables will be accessed.

Here is the simplest example that shows the same query using different driving
tables under RBO.  I just play games with the indexes -- the RBO uses its rules
to find the driving table using the indexes, not the order of the tables in the
from clause.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table emp as select * from scott.emp;
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table dept as select * from
scott.dept;
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace traceonly explain
ops$tkyte@ORA817DEV.US.ORACLE.COM> create index dept_idx on dept(deptno);
Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from emp, dept where emp.deptno =
dept.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   NESTED LOOPS
   2    1     TABLE ACCESS (FULL) OF 'EMP'
   3    1     TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'
   4    3       INDEX (RANGE SCAN) OF 'DEPT_IDX' (NON-UNIQUE)

so here, EMP is the "driving" table, we full scan it and do an index access
into DEPT

ops$tkyte@ORA817DEV.US.ORACLE.COM> drop index dept_idx;
Index dropped.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index emp_idx on emp(deptno);
Index created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from emp, dept where emp.deptno =
dept.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   NESTED LOOPS
   2    1     TABLE ACCESS (FULL) OF 'DEPT'
   3    1     TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
   4    3       INDEX (RANGE SCAN) OF 'EMP_IDX' (NON-UNIQUE)

same query, different indexes -- the roles are reversed.  DEPT drives, EMP is
driven into

ops$tkyte@ORA817DEV.US.ORACLE.COM> create index dept_idx on dept(deptno);
Index created.

Now they both have equally "appealing" indexes -- the order of the tables in
the from clause is used to break the tie

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from emp, dept where emp.deptno =
dept.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   NESTED LOOPS
   2    1     TABLE ACCESS (FULL) OF 'DEPT'
   3    1     TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
   4    3       INDEX (RANGE SCAN) OF 'EMP_IDX' (NON-UNIQUE)

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from dept, emp where emp.deptno =
dept.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   NESTED LOOPS
   2    1     TABLE ACCESS (FULL) OF 'EMP'
   3    1     TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'
   4    3       INDEX (RANGE SCAN) OF 'DEPT_IDX' (NON-UNIQUE)

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace off

December 30, 2001 Peter -- Thanks for the question regarding
      "Relational VS Object Oriented Database Design", version Oracle 8.1.6

      You Asked
Hi Tom:

There are two different mind set between relational vs. Object
Oriented Database Design.

Can you provide your experiences, what are the criteria (pro and
con) to use relational vs. OO database design in Oracle? Objects
in Oracle have better performance than relational table, or vice
versa.

Thanks for your time and efforts.

Peter Cheng

      and we said...
First off, in Oracle you would be considering pure relational
versus Object RELATIONAL, not OO.  We have object relational
extensions to the relational database.  We do not have an object
oriented database.

The answer to this comes down to the data you are working with.
Let's say you are building a banking application.  You are
building the application for the teller to service a person when
they walk in the door.  The Object perfect for that application
is a "person" object identified by name or account number.  That
person object has all of the attributes of a person in a bank, a
name, an address, a list of accounts with all of the account
attributes, a list of recent transactions, and so on.  A big
glob of data that represents all of the information about a
person.  That is the perfect view for the teller.  HOWEVER, at
the end of the day, there is someone else who has a totally
different view of the data -- they need to count how many
transactions happened that day.  How much money is in the bank.
They have a transaction oriented, not person oriented,
perspective of the data.  In this case, a RELATIONAL model with
possibly application specific Object relational views built on
top of it is perfect.  You need an account table, that is joined
to a transaction table and a person table.  In that fashion, the
guy who needs to count the transactions is satisfied and so is
the guy who needs the person oriented view.

That is the power of the relational model, it is able to easily
give many views of the same data.  Think of it this way with the
scott/tiger EMP, DEPT tables.  It might seem to make sense to
create an EMP object type, a nested table of EMP, a DEPT object
with an attribute of EMP nested table and then a table of DEPT
types.  Now the whole scott/tiger emp/dept example fits into 1
table with 4 rows.  Sounds great.  The problem is people will
ask questions like:

o how many emps do I have?
o KING is standing here at the front door -- is he an employee
or not?
o how much salary did I pay accountants last year?

and so on.  None of these questions are easilly answered with a
DEPT oriented view of the data.

Just some food for thought.  I've not really used the Object
relational concepts as a STORAGE mechanism, I have used them in
my programming with PLSQL lots.  I tend to stick with real
tables and use the objects in my code frequently.
Review &
      Followup

      Rating: 4
Any
      recommendations on books of database design?  August 21,
      2001
Reviewer:  A reader

      Rating: 4
Any
      recommendations on books of database design?  August 21,
      2001
Reviewer:  F  from USA

      Rating: 4
Mahendra
      Jadav  December 30, 2001
Reviewer:  Mahendra
      Jadav  from INDIA
This implies, do not to use ORDBMS as storage mechanism. Use OR views based on
plain table. Correct?

          Followup:

That is my personal choice, yes.

      Rating:
      4
Beautiful  December 31, 2001
Reviewer:
      Srimal  from Trenton, USA
Hello Mr Tom,

Your response is consise and to the point and amazing!


Subject | Article | Last Updated (East coast time)
SQL help again | article only | Dec 31, 2001 09:35 am
SQL help again | article only | Dec 31, 2001 01:23 pm
and again, sql help again (update a join) | article only | Dec 31, 2001 02:00 pm
row(s) 1 - 3 of 3
December 31, 2001 Ping -- Thanks for the question regarding "SQL help again", version 8.1.7
You Asked
Hi Tom,

I understand the importance to use reuse the SQL statement, using bind variables
-- but I really can't see how it helps for my purpose:

I need to, in a stored procedure, update table A with table B (similar
structure, about 100 columns), but the number of columns need to update is
dynamic: update only if the columns from B is not null. What I did is to
construct a string using the following logic:

 IF   V_DESCR IS NOT NULL THEN
  V_STRING := V_STRING||'DESCR = '''||V_DESCR||''', ';
 END IF;

and I encountered error because the single quotes in the variables.

I reported this couple days ago and you suggested to use dbms_sql.bind_variable.
Please advice on how to use the package and yet achieve the logic of only
include the not null columns in the parsed statement.

Thanks a bunch,

Ping
and we said...
why don't you simply execute:

update ( select a.c1 a_c1, a.c2 a_c2, ... a.cn a_cn,
                b.c1 b_c1, b.c2 b_c2, ... b.cn b_cn
           from a, b
          where a.pk = b.pk )
   set a_c1 = nvl( b_c1, a_c1 ),
       a_c2 = nvl( b_c2, a_c2 ),
       ....
       a_cn = nvl( b_cn, a_cn );

search this very site for DBMS_SQL for many examples.  If you can procedurally
build a sql statement -- you can easily procedurally bind to it.  You would:

  ...
  if ( v_desc is not null )
  then
     v_string := v_string || ' descr = :descr, ';
  end if;
  ....
  dbms_sql.parse( v_cursor, v_string, ... );

   ....
  if ( v_desc is not null )
  then
      dbms_sql.bind_variable( v_cursor, 'descr', v_descr );
  end if;
  ....

  dbms_sql.execute....

(but that makes that single update that does ALL of the work without a stitch of
procedural code look MUCH nicer does it.....)
December 31, 2001 Ping -- Thanks for the question regarding "SQL help again", version 8.1.7
You Asked
Hi Tom,

To my previous question:

why don't you simply execute:

update ( select a.c1 a_c1, a.c2 a_c2, ... a.cn a_cn,
                b.c1 b_c1, b.c2 b_c2, ... b.cn b_cn
           from a, b
          where a.pk = b.pk )
   set a_c1 = nvl( b_c1, a_c1 ),
       a_c2 = nvl( b_c2, a_c2 ),
       ....
       a_cn = nvl( b_cn, a_cn );

I guess I can do that if you are saying adding one condition like b.action =
'UPDATE', and the size of A of 30+ mil row (and keep growing) and B of 10k,is OK
performance wise? Thanks, Ping
and we said...
The size of A is not as relevant as the size of B.  B drives how many rows will
be updated here.

I loaded up a table t with 500,000+ rows and t2 with 1,300 rows.  Executed the
following update (i use the CBO -- you will too)

ops$tkyte@ORA817DEV.US.ORACLE.COM> update ( select a.owner a_owner,
a.object_name a_object_name, a.subobject_name a_subobject_name,
  2                  b.owner b_owner, b.object_name b_object_name,
b.subobject_name b_subobject_name
  3                 from t a, t2 b
  4                    where a.object_id = b.object_id
  5             )
  6    set a_owner = nvl( b_owner, a_owner ),
  7        a_object_Name = nvl( b_object_name, a_object_name ),
  8        a_subobject_Name = nvl( b_subobject_name, a_subobject_name )
  9  /

1373 rows updated.

Elapsed: 00:00:01.67

Execution Plan
----------------------------------------------------------
   0      UPDATE STATEMENT Optimizer=CHOOSE (Cost=2749 Card=1373 Bytes=144165)
   1    0   UPDATE OF 'T'
   2    1     NESTED LOOPS (Cost=2749 Card=1373 Bytes=144165)
   3    2       TABLE ACCESS (FULL) OF 'T2' (Cost=3 Card=1373 Bytes=75515)
   4    2       TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=549024
Bytes=27451200)
   5    4         INDEX (UNIQUE SCAN) OF 'T_PK' (UNIQUE) (Cost=1 Card=549024)

See, it'll full scan "B" (small) and index access into "A" (big) to do the
update and only update 10k rows -- it will not scan 30+ mil rows.
December 31, 2001 John -- Thanks for the question regarding "and again, sql help again (update a join)", version 8.1.6.0.0
You Asked
Hi Tom,

 Thanks again for providing this valuable service and a Happy New Year to all.

In the previous question you again used the Update(select..) form, which I have
a bit of a problem grasping.
ie.
update ( select a.c1 a_c1, a.c2 a_c2, ... a.cn a_cn,
                b.c1 b_c1, b.c2 b_c2, ... b.cn b_cn
           from a, b
          where a.pk = b.pk )
   set a_c1 = nvl( b_c1, a_c1 ),
       a_c2 = nvl( b_c2, a_c2 ),
       ....
       a_cn = nvl( b_cn, a_cn );
I've looked it up in Oracles' doccumentation when I first saw you use it but am
still not following. Can you expand on how this works, please?
for instance: Can both A and B be updated using this form?
Max number of tables this form allows?
I am amazed daily by some of the techniques you use here.
Thank you for all the help you've given me these past months.
and we said...
You can only update a single key preserved table, else you'll get a message
like:

ERROR at line 9:
ORA-01776: cannot modify more than one base table through a join view

Basically, you are updating a JOIN.  See
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:548422757486
for some more details.


Oracle9i SQL Reference

雪狼 作品

资料来源

资料来源：http://asktom.oracle.com

收集整理：Snowywolf

整理时间：2004-01

版权声明

您可以自由地将此文档复制发行，但请保留此声明页。

请勿将此文档用于任何商业用途。

联系作者

ITPUB号：Snowywolf

E m a i l：lisj@supermap.com

N a m e ：李绍俊

雪狼 作品