oracle tips
===========================================================
Problem to connect as SYSDBA(zt from asktom)
===========================================================
Hi there,

I am running Oracle 8.1.7 EE on SUN Solaris. I created two databases
SUGAR and TestDb (I need one to do some testing). Both are set
remote_login_passwordfile = exclusive. The following shows how I had trouble to
connect as SYSDBA. The big problem is that I cannot connect to TestDb as SYSDBA.

$sqlplus /nolog
SQL> conn sys/change_on_install@testdb
connected
SQL> select * from v$pwfile_users;
username sysdb sysop
------------------------------
internal true true
sys true true
SQL> conn sys/change_on_install@testdb as sysdba
ERROR
ORA-01017: invalid username/password; logon denied
Warning: You are on longer connected to ORACLE
SQL> conn sys/change_on_install@SUGAR
connected
SQL> select * from v$pwfile_users;
username sysdb sysop
------------------------------
internal true true
sys true true
SQL> conn sys/change_on_install@SUGAR as sysdba
ERROR
ORA-01017: invalid username/password; logon denied
Warning: You are on longer connected to ORACLE
SQL> conn sys/change_on_install as sysdba
connected
SQL> select name from v$database;
name
------
SUGAR

Questions:
1. Why "conn sys/change_on_install@testdb/sugar as sysdba" always failed, but
"conn sys/change_on_install as sysdba" OK ?

2. Why I cannot connect to testdb as SYSDBA?

Thanks for any help.
and we said...
what was the password you used when you created the password file and have you 
tried that?

the sysdba trick is generally used to allow other NON-SYS users to connect btw,
best to use your OWN account that has been granted sysdba!

Anyway, hopeful this will clear up the confusion and show how this works:

$ orapwd file=orapw password=foobar entries=40

I just recreated my password file with a password foobar. My sys password is
NOT foobar


$ svrmgrl

SVRMGR> connect internal
Connected.

SVRMGR> startup
ORACLE instance started.
Total System Global Area 193073136 bytes
Fixed Size 69616 bytes
Variable Size 141639680 bytes
Database Buffers 45056000 bytes
Redo Buffers 6307840 bytes
Database mounted.
Database opened.

SVRMGR> connect sys/change_on_install@ora816dev
Connected.

that works OK, lets try as sysdba:

SVRMGR> connect sys/change_on_install@ora816dev as sysdba;
ORA-01017: invalid username/password; logon denied

there I got your error. My SYS password is change_on_install but the password
file has foobar in it. SYS is special -- sys connecting as sysdba is like
internal -- you have to use the password file password! Lets try that:


SVRMGR> connect sys/foobar@ora816dev as sysdba;
Connected.

SVRMGR> grant sysdba to scott;
Statement processed.

now, we'll see this does not hold true for other users:

SVRMGR> connect scott/tiger@ora816dev as sysdba;
Connected.

That worked great, now lets just modify sys's password (not really, didn't
change it but Oracle won't notice that


SVRMGR> alter user sys identified by change_on_install;
Statement processed.

SVRMGR> connect sys/change_on_install@ora816dev as sysdba;
Connected.
SVRMGR>
Hey, now we can use change_on_install -- that is because altering SYS's
password will sync up the password in the password file -- sys is a very very
close cousin of INTERNAL. sys's password will be burned into the password file
now. the password foobar is obsolete


SVRMGR> connect sys/foobar@ora816dev as sysdba;
ORA-01017: invalid username/password; logon denied
SVRMGR>

jametong 发表于:2005.06.14 16:04 ::分类: ( oracle refs ) ::阅读:(6230次) :: 评论 (46)
===========================================================
relation between consistent gets and arraysize(zt from asktom)
===========================================================
Consistenet gets is based upon re-constructing a block
for consistent read. Hence it is a function of only the
number of db_blocks to be read.
If you say that it is altered by the arraysize, do you
suggest that, due to arraysize, some blocks are read
muliple times and hence some blocks have > 1 
consistent read in the process
Thanks 
Followup:
No, you are wrong in your statement.
A consistent get is a block gotten in read consistent mode (point in time mode).  It MAY or MAY NOT involve reconstruction (rolling back).
Db Block Gets are CURRENT mode gets -- blocks read "as of right now".

Some blocks are processed more then once, yes, the blocks will have more then 1 
consistent read in the process.  Consider:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t as select * from all_objects;
Table created.
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec show_space( 'T')
Free Blocks.............................0
Total Blocks............................320
Total Bytes.............................2621440
Unused Blocks...........................4
Unused Bytes............................32768
Last Used Ext FileId....................7
Last Used Ext BlockId...................40969
Last Used Block.........................60
PL/SQL procedure successfully completed.
Table has 316 blocks, 22,908 rows..

ops$tkyte@ORA817DEV.US.ORACLE.COM> set autotrace traceonly statistics;
ops$tkyte@ORA817DEV.US.ORACLE.COM> set arraysize 15
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t;
22908 rows selected.
here with an array size of 15, we expect
22908/15 + 316 = 1843 consistent mode gets.  db block gets -- they were for 
performing the FULL SCAN, they had nothing to do with the data itself we 
selected

Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
       1824  consistent gets
        170  physical reads
          0  redo size
    2704448  bytes sent via SQL*Net to client
     169922  bytes received via SQL*Net from client
       1529  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      22908  rows processed
ops$tkyte@ORA817DEV.US.ORACLE.COM> set arraysize 100
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t;
22908 rows selected.
Now, with 100 as the arraysize, we expect
22908/100 + 316 = 545 consistent mode gets.
Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
        546  consistent gets
        180  physical reads
          0  redo size
    2557774  bytes sent via SQL*Net to client
      25844  bytes received via SQL*Net from client
        231  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      22908  rows processed
ops$tkyte@ORA817DEV.US.ORACLE.COM> set arraysize 1000
ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from t;
22908 rows selected.
now, with arraysize = 1000, we expect:
22908/1000+316 = 338 consistent mode gets...
Statistics
----------------------------------------------------------
          0  recursive calls
         12  db block gets
        342  consistent gets
        222  physical reads
          0  redo size
    2534383  bytes sent via SQL*Net to client
       2867  bytes received via SQL*Net from client
         24  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      22908  rows processed

so yes, the blocks are gotten in consistent mode MORE THEN ONCE when the array 
fetch size is lower then the number of rows to be retrieved in this case
This is because we'll be 1/2 way through processing a block -- have enough rows 
to return to the client -- and we'll give UP that block.  When they ask for the 
next N rows, we need to get that halfway processed block again and pick up where 
we left off.
 

jametong 发表于:2005.06.07 09:03 ::分类: ( oracle refs ) ::阅读:(29617次) :: 评论 (550)
===========================================================
about tune db cache
===========================================================
i have 8174 db.
how can i know that i have the db buffer too small?
thanks

Followup:
trick question.

you have to first make sure your SQL is as good as it gets (reduce the number of
LIO's your sql does).

Then, you need to understand if a sql cache of any size can cache some
percentage of your data (maybe it can, maybe it can't)

Then you can look at ratio to see if you have a satisfactory hit.


But basically, you want to look at what you system is waiting for. Not waiting
on physical IO? then your cache is at least big enough. Waiting on physical
IO? DO NOT INCREASE YOUR BUFFER CACHE FIRST, rather look at your top SQL, if
you have a query that is executed lots and returns like 2 rows but does 100
LIO's to do it -- you need to look at that ( i would hope for single digit IO's
for a popular query that returns 2 rows). do you have a popular query that just
does a ton of LIO's (regardless of the rows) -- why? can you do anything about
it? if so -- fix it.

Then, you might find that your buffer cache is just fine after all (watch the
LIO's and the PIO's will take care of themselves).

Increasing the buffer cache to help a PIO problem is the last step -- you want
to exhaust other avenues first (more efficient sql, better algorithms, quit
running stuff you don't really need to run, that sort of stuff -- they'll give
you the big payoff. increasing the buffer cache doesn't always have the same
potential as those approaches)



jametong 发表于:2005.05.19 18:34 ::分类: ( oracle refs ) ::阅读:(1170次) :: 评论 (4)
===========================================================
DIFFERENCES BETWEEN PROCESSES, SESSIONS AND CONNECTIONS(zt from asktom)
===========================================================
-- Thanks for the question regarding "DIFFERENCES BETWEEN PROCESSES, SESSIONS AND CONNECTIONS", version 8.1.7.4
originally submitted on 28-Sep-2002 10:19 Eastern US time, last updated 27-Apr-2005 16:37

You Asked
Hi Tom

What's the difference between connections, sessions and processes?

I read a note from Metalink about the difference but I simply dont get it!

May you give a brief explanation?

Thank you
and we said...
A process is a physical process or thread.

On unix, you can see a process with "ps" for example. It is there.

There are many types of processes in Oracle -- background processes like SMON,
PMON, RECO, ARCH, CKPT, EMNn, DBWR, etc..... And user processes like dedicated
servers or shared server (multi-threaded server -- aka MTS -- configuration)


A connection is a "physical circuit", a pathway to a database. You can be
connected to a database yet have 0 or 1 or MORE sessions going on that
connection. We can see that with sqlplus, consider (single user system here,
its all about me)


[tkyte@tkyte-pc-isdn tkyte]$ ps -auxww | grep oracleora920
[tkyte@tkyte-pc-isdn tkyte]$ sqlplus /nolog

SQL*Plus: Release 9.2.0.1.0 - Production on Sat Sep 28 10:36:03 2002

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

idle> !ps -auxww | grep oracleora920
tkyte 19971 0.0 0.1 2196 916 pts/1 S 10:36 0:00 /bin/bash -c ps
-auxww | grep oracleora920
tkyte 19973 0.0 0.1 1736 564 pts/1 S 10:36 0:00 grep oracleora920

no process, no nothing

idle> connect /
Connected.
idle> !ps -auxww | grep oracleora920
ora920 19974 1.5 2.2 230976 11752 ? S 10:36 0:00 oracleora920
(DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
tkyte 19975 0.0 0.1 2196 916 pts/1 S 10:36 0:00 /bin/bash -c ps
-auxww | grep oracleora920
tkyte 19977 0.0 0.1 1736 564 pts/1 S 10:36 0:00 grep oracleora920

got my process now...

idle> disconnect
Disconnected from 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
idle> !ps -auxww | grep oracleora920
ora920 19974 0.6 2.3 230976 11876 ? S 10:36 0:00 oracleora920
(DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
tkyte 19978 0.0 0.1 2196 916 pts/1 S 10:36 0:00 /bin/bash -c ps
-auxww | grep oracleora920
tkyte 19980 0.0 0.1 1736 564 pts/1 S 10:36 0:00 grep oracleora920

idle> select * from dual;
SP2-0640: Not connected

still have my process, but no session, the message is a little "misleading".
Technically -- I have a connection, I don't have a session



further, autotrace in sqlplus can be used to show that you can have
a) a connection
b) that uses a single process
c) to service two sessions:


ops$tkyte@ORA920.US.ORACLE.COM> select username from v$session where username is
not null;

USERNAME
------------------------------
OPS$TKYTE

one session, ME

ops$tkyte@ORA920.US.ORACLE.COM> select username, program from v$process;

USERNAME PROGRAM
--------------- ------------------------------------------------
PSEUDO
ora920 oracle@tkyte-pc-isdn.us.oracle.com (PMON)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (DBW0)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (LGWR)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (CKPT)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (SMON)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (RECO)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (CJQ0)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (QMN0)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (S000)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (D000)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (ARC0)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (ARC1)
tkyte oracle@tkyte-pc-isdn.us.oracle.com (TNS V1-V3)

14 rows selected.

you can see all of the backgrounds and my dedicated server...

ops$tkyte@ORA920.US.ORACLE.COM> set autotrace on statistics;

Autotrace for statistics uses ANOTHER session so it can query up the stats for
your CURRENT session without impacting the STATS for that session!

/* 这种情况有几个人注意过啊^_^ 我是没有发现过.. */

ops$tkyte@ORA920.US.ORACLE.COM> select username from v$session where username is
not null;

USERNAME
------------------------------
OPS$TKYTE
OPS$TKYTE


see, two sessions but....

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
418 bytes sent via SQL*Net to client
499 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed

ops$tkyte@ORA920.US.ORACLE.COM> select username, program from v$process;

USERNAME PROGRAM
--------------- ------------------------------------------------
PSEUDO
ora920 oracle@tkyte-pc-isdn.us.oracle.com (PMON)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (DBW0)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (LGWR)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (CKPT)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (SMON)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (RECO)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (CJQ0)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (QMN0)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (S000)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (D000)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (ARC0)
ora920 oracle@tkyte-pc-isdn.us.oracle.com (ARC1)
tkyte oracle@tkyte-pc-isdn.us.oracle.com (TNS V1-V3)

14 rows selected.

same 14 processes...

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
1095 bytes sent via SQL*Net to client
499 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed

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


I'll try to put it into a single, simple paragraph:

A connection is a physical circuit between you and the database. A connection
might be one of many types -- most popular begin DEDICATED server and SHARED
server. Zero, one or more sessions may be established over a given connection
to the database as show above with sqlplus. A process will be used by a session
to execute statements. Sometimes there is a one to one relationship between
CONNECTION->SESSION->PROCESS (eg: a normal dedicated server connection).
Sometimes there is a one to many from connection to sessions (eg: like
autotrace, one connection, two sessions, one process). A process does not have
to be dedicated to a specific connection or session however, for example when
using shared server (MTS), your SESSION will grab a process from a pool of
processes in order to execute a statement. When the call is over, that process
is released back to the pool of processes.



jametong 发表于:2005.04.28 10:06 ::分类: ( oracle refs ) ::阅读:(4365次) :: 评论 (41)
===========================================================
Calling Export from Pl/sql using C external proc
===========================================================
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:1993409963502

Sudee -- Thanks for the question regarding "Calling Export from Pl/sql using C external proc.", version 8.1.6
originally submitted on 16-Nov-2001 20:55 Eastern US time, last updated 27-Apr-2005 9:31

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:oracleextprocshell.dll';


create or replace procedure shell (
cmd IN char)
as external
name "sh"
library shell_lib
language C
parameters (
cmd string);

exec shell('C:oracleora81binexp userid=system/manager
file=C:oracleextproctest.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:bintouch c:temptest.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 tempexp.log
tkyte@TKYTE816> begin
2 shell( 'c:oraclebinexp userid=scott/tiger ' ||
3 ' file=c:temptest.dmp tables=emp 2> tempexp.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 tempexp.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 tempexp.log

tkyte@TKYTE816>
tkyte@TKYTE816> begin
2 shell( 'command /c set > tempexp.log' );
3 end;
4 /

PL/SQL procedure successfully completed.

tkyte@TKYTE816> host type tempexp.log
COMSPEC=C:WINNTSYSTEM32COMMAND.COM
ORACLE_SID=extproc

ALLUSERSPROFILE=C:DOCUME~1ALLUSE~1
COMMONPROGRAMFILES=C:PROGRA~1COMMON~1
COMPUTERNAME=TKYTE-DELL
JSERV=C:oracle9i/Apache/Jserv/conf
NUMBER_OF_PROCESSORS=1
OLAP_HOME=C:oracle9iolap
OS=Windows_NT
OS2LIBPATH=C:WINNTsystem32os2dll;
PATH=C:oraclebin;C:oracle9ibin;C:orantbin;C:oracle9i/bin;C:oracle9iApach
ePerl
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:WINNTTEMP
TMP=C:WINNTTEMP
USERPROFILE=C:DOCUME~1DEFAUL~1
WV_GATEWAY_CFG=C:oracle9iApachemodplsqlcfgwdbsvr.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 tempexp.log

tkyte@TKYTE816>
tkyte@TKYTE816> begin
2 shell( 'c:oraclebinexp userid=scott/tiger@tkyte816 ' ||
3 ' file=c:temptest.dmp tables=emp 2> tempexp.log' );
4 end;
5 /

PL/SQL procedure successfully completed.

tkyte@TKYTE816> host type tempexp.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 tempexp.log

tkyte@TKYTE816>
tkyte@TKYTE816> begin
2 shell( 'set ORACLE_SID=tkyte816 && ' ||
3 'c:oraclebinexp
userid=scott/tiger@tkyte816 ' ||
4 ' file=c:temptest.dmp tables=emp 2> tempexp.log' );
5 end;
6 /

PL/SQL procedure successfully completed.

tkyte@TKYTE816> host type tempexp.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.


jametong 发表于:2005.04.27 23:26 ::分类: ( oracle refs ) ::阅读:(37201次) :: 评论 (650)
===========================================================
sql to get data from flat file(zt from asktom)
===========================================================
Nag -- Thanks for the question regarding "sql to get data from flat file-- this is mind blowing", version 8.1.7
originally submitted on 12-Oct-2001 19:26 Eastern US time, last updated 26-Apr-2005 20:08

You Asked
"In 9i, with the addition of external tables ( the ability to query a FLAT FILE  
with SQL) -- SQLLDR might be "moot". Using the external table and the insert
/*+ append */ I can basically do a direct path load from file to database
without running a command outside of the database."

Tom

We just cant wait, to see how the above is done, what are the new sql clauses we
need to use to achieve the above( there should be some new clauses to do the
above).

Kindly demonstrate the above, this feature will be trend setting and path
breaking.

Nag
and we said...
Ok, here is a demo I use for training internally:

For external tables, we need to use a directory object -- we'll
start with that, mapping to the temp directory

create or replace directory data_dir as 'c:temp'
/

Now, we'll create the external table.
part of its definition is what looks like a control file -- it is


create table external_table
(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)
)
ORGANIZATION EXTERNAL
( type oracle_loader
default directory data_dir
access parameters
( fields terminated by ',' )
location ('emp.dat')
)
/


In tempemp.dat I have a file that looks like this:

7369,SMITH,CLERK,7902,17-DEC-80,800,,20
7499,ALLEN,SALESMAN,7698,20-FEB-81,1600,300,30
7521,WARD,SALESMAN,7698,22-FEB-81,1250,500,30
....


(its a dump of the emp table in csv format)


Now you can just:

select * from external_table
/



and now, if you modified the scott/tiger EMP table:

delete from emp where mod(empno,2) = 1
/
update emp set sal = sal/2
/
commit;

You could sync up the flat file with the database table using this single
command:


merge into EMP e1
using EXTERNAL_TABLE e2
on ( e2.empno = e1.empno )
when matched then
update set e1.sal = e2.sal
when not matched then
insert ( empno, ename, job, mgr, hiredate, sal, comm, deptno )
values ( e2.empno, e2.ename, e2.job, e2.mgr, e2.hiredate, e2.sal, e2.comm,
e2.deptno )
/
commit;


that'll update the records in the EMP table from the flat file if they exist OR
it will insert them.

Doing a direct path load would simply be:

insert /*+ append */ into emp select * from external_table;


jametong 发表于:2005.04.27 08:39 ::分类: ( oracle refs ) ::阅读:(4188次) :: 评论 (23)
===========================================================
how tom write pagenation sql
===========================================================
http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:25685777038588
in general your query won't get the "next n rows".

Why would you not just:


select /*+ FIRST_ROWS */ *
from ( select /*+ FIRST_ROWS */ a.*, rownum rnum
from (select /*+ FIRST_ROWS */ * from t where .... order by ... ) a
where rownum <= :MAX_ROW )
where rnum >= :MIN_ROW;


done. that is how I write all pagination queries.


(you do know that A||B has serious programming issues -- A=1, B=11 vs A=11, B=1
-- you need to encode the fields very very carefully. don't go there, really
bad, confusing idea.


jametong 发表于:2005.04.27 00:58 ::分类: ( oracle refs ) ::阅读:(15885次) :: 评论 (387)
===========================================================
DIAGNOSING AND RESOLVING ORA-04031 ERROR
===========================================================

The purpose of this document is to provide an easy to use, step by step guide to resolving ORA-04031 errors.

Contents:

1. Instance parameters related with the Shared Pool
2. Diagnosing ORA-04031 errors
3. Resolving error ORA-04031

    * Known Oracle BUGs
    * ORA-4031 when compiling Java code
    * Small shared pool size
          o Library Cache Hit Ratio
          o Shared Pool Size Calculation
    * Shared Pool Fragmentation
          o V$SQLAREA View
          o X$KSMLRU View
          o X$KSMSP View (Similar to Heapdump Information

4. ORA-04031 error and Large Pool
5. ORA-04031 and Flushing the SHARED POOL
6. Advanced analysis to ORA-04031 error

DIAGNOSING AND RESOLVING ORA-04031 ERROR


When any attempt to allocate a large piece of contiguous memory in the shared pool fails Oracle first flushes all objects that are not currently in use from the pool and the resulting free memory chunks are merged. If there is still not a single chunk large enough to satisfy the request the ORA-04031 error is returned.

The message that you will get when this error appears is the following:

    04031, 00000, "unable to allocate %s bytes of shared memory ("%s","%s","%s","%s")"
    // *Cause: More shared memory is needed than was allocated in the shared
    // pool.
    // *Action: If the shared pool is out of memory, either use the
    // dbms_shared_pool package to pin large packages,
    // reduce your use of shared memory, or increase the amount of
    // available shared memory by increasing the value of the
    // INIT.ORA parameters "shared_pool_reserved_size" and
    // "shared_pool_size".
    // If the large pool is out of memory, increase the INIT.ORA
    // parameter "large_pool_size".


1. Instance parameters related with the Shared Pool

    Before continuing, understanding the following instance parameters will be essential:
  • SHARED_POOL_SIZE - This parameter specifies the size of the shared pool in bytes and can accept

  • a numerical values or a number followed by the suffix "K" or "M" where "K" means "multiply by 1000"
    and "M" means "multiply by 1000000"
  • SHARED_POOL_RESERVED_SIZE - It specifies the shared pool space which is reserved for large contiguous requests for shared pool memory. This parameter along with the SHARED_POOL_RESERVED_MIN_ALLOC parameter, can be used to avoid the occurrence of this error from situations where shared pool fragmentation forces Oracle to search for and free
    chunks of unused pool to satisfy the current request.

    Ideally, this parameter should be large enough to satisfy any request scanning for memory on the reserved list without flushing objects from the shared pool. Since the operating system memory may constraint the size of the shared pool, in general, you should set this parameter to 10% of the SHARED_POOL_SIZE parameter.

  • SHARED_POOL_RESERVED_MIN_ALLOC - The value of this parameter controls allocation of reserved memory. Memory allocation larger than this value can allocate space from the reserved list if a chunk of memory of sufficient size is not found on the shared pool free lists. The default value is adequate for most systems. If you increase the value, then the Oracle server will allow fewer allocations from the reserved list and will request more memory from the shared pool list. This parameter is hidden in Oracle 8i and higer, but it can be found by executing the following SQL statement:

    select nam.ksppinm NAME,
    val.KSPPSTVL VALUE
    from x$ksppi nam,
    x$ksppsv val
    where nam.indx = val.indx
    and nam.ksppinm like '%shared%'
    order by 1;

  • 10g Note: In Oracle 10g a new feature called "automatic memory management" allows the dba to reserve a pool of shared memory that is used to allocate the shared pool, the buffer cache, the java pool and the large pool.
    In general, when the database needs to allocate a large object into the shared pool and cannot find contiguous space available, it will automatically increase the shared pool size using free space from other SGA structure.
    Since the space allocation is automatically managed by Oracle, the probability of getting ora-4031 errors may be greatly reduced. Automatic Memory Management is enabled when the parameter SGA_TARGET is greater than zero and the current setting can be obtained quering the v$sga_dynamic_components view.

    Please refer to the 10g Administration Manual for further reference.

2. Diagnosing error ORA-04031:

Note: Most common ORA-4031 occurrences are related to the SHARED POOL SIZE, therefore the diagnostic steps provided in this article will mostly address issues related to the shared pool. For other areas like large_pool or java_pool where the memory allocation algorith is simpler, normally the error is caused by an undersized structure.

ORA-04031 error can be due to either an inadequeate sizing of the SHARED POOL size or due to heavy fragmentation leading the database to not finding large enough chuncks of memory.

    Inadequate Sizing: The first thing is determining if the ORA-04031 error is a result of lack of contiguous space in the library cache by verifying the following:

    REQUEST_FAILURES is > 0 and LAST_FAILURE_SIZE is <
    SHARED_POOL_RESERVED_MIN_ALLOC

    or

    REQUEST_FAILURES is 0 and LAST_FAILURE_SIZE is < SHARED_POOL_RESERVED_MIN_ALLOC

    If this is the case, consider lowering SHARED_POOL_RESERVED_MIN_ALLOC to
    allow the database putting more objects into the shared pool reserved space and then increase the
    SHARED_POOL_SIZE if the problem is not resolved.

    Fragmentation: If this is not the case, then you must determine if the ORA-04031 was a result of fragmentation in the library cache or in the shared pool reserved space by following this rule:

    REQUEST_FAILURES is > 0 and LAST_FAILURE_SIZE is >
    SHARED_POOL_RESERVED_MIN_ALLOC.

    To resolve this consider increasing SHARED_POOL_RESERVED_MIN_ALLOC to lower
    the number of objects being cached into the shared pool reserved space and
    increase SHARED_POOL_RESERVED_SIZE and SHARED_POOL_SIZE to increase the
    available memory in the shared pool reserved space.

3. Resolving error ORA-04031:
  • Oracle BUGs
  • Oracle recommends to apply the latest patchser available for your platform. Most of the ORA-4031 errors related to BUGs can be avoided by applying these patchsets. The following table summarize the most common BUGs related with this error, possible workaround and the patchset that fixes the problem.

    BUG Description Workaround Fixed
    <Bug:1397603> ORA-4031 / SGA memory leak of PERMANENT memory occurs for buffer handles. _db_handles_cached = 0 8172, 901
    <Bug:1640583> ORA-4031 due to leak / cache buffer chain contention from AND-EQUAL access Not available 8171, 901
    Bug:1318267
    Not Public
    INSERT AS SELECT statements may not be shared when they should be if TIMED_STATISTICS. It can lead to ORA-4031 _SQLEXEC_PROGRESSION_COST=0 8171, 8200
    Bug:1193003
    Not Public
    Cursors may not be shared in 8.1 when they should be Not available 8162, 8170, 901
    <Bug:2104071> ORA-4031/excessive "miscellaneous"
    shared pool usage possible.
    (many PINS)
    None-> This is known to affect the XML parser. 8174, 9013, 9201
    <Note:263791.1> Several number of BUGs related
    to ORA-4031 erros were fixed
    in the 9.2.0.5 patchset

    9205

  • ORA-4031 when compiling Java code:


  • If you run out of memory while compiling a java code (within loadjava or deployejb), you should see an error:

    A SQL exception occurred while compiling: : ORA-04031: unable to allocate bytes of shared memory ("shared pool","unknown object","joxlod: init h", "JOX: ioc_allocate_pal")

    The solution is to shut down the database and set JAVA_POOL_SIZE to a larger value. The mention of "shared pool" in the error message is a misleading reference to running out of memory in the "Shared Global Area". It does not mean you should increase your SHARED_POOL_SIZE. Instead, you must increase your JAVA_POOL_SIZE, restart your server, and try again.

    See <Bug:2736601>

  • Small shared pool size
  • In many cases, a small shared pool can be the cause of the ORA-04031 error.

    The following information will help you to adjust the size of the shared
    pool:

    Library Cache Hit Ratio
    The hit ratio helps to measure the usage of the shared pool based on how many times a SQL/PLSQL statement needed to be parsed instead of being

      reused. The following SQL statement help you to calculate the library cache
      hit ratio:

      SELECT SUM(PINS) "EXECUTIONS",


      SUM(RELOADS) "CACHE MISSES WHILE EXECUTING"


      FROM V$LIBRARYCACHE;

      If the ratio of misses to executions is more than 1%, then try to reduce
      the library cache misses by increasing the shared pool size.

    • Shared Pool Size Calculation
      To calculate the size of the shared pool that best fits to your current
      workload, please refer to:

      <Note:1012046.6>:
      HOW TO CALCULATE YOUR SHARED POOL SIZE.

  • Shared Pool Fragmentation:


  • Every time a SQL or PL/SQL statement needs to be executed the
    parse representation is loaded in the library cache requiring a specific
    amount of free contiguous space. The first resource where the database
    scans is the free memory available in the shared pool. Once the free memory
    is exhausted, the database looks for reusing an already allocated piece
    not in use. If a chunk with the exact size is not available, the scan continues
    looking for space based on the following criteria:
    - The chuck size is larger than the required size

    - The space is contiguous

    - The chuck is available (not in use)
    Then that chunk is split and the remaining free space is added to the appropriate free space list. When the database is operating in this way for a certain period of time the shared pool structure will be fragmented.

    When the shared pool is suffering fragmentation ORA-04031
    errors (when the database cannot find a contiguous piece of free memory) may occur.
    Also as a concequence , the allocation of a
    piece of free space takes more time an the performance may be affected
    (the "chunk allocation" is protected by a single latch called
    "shared pool latch" which is held during the whole operation). However, ORA-4031
    errors don't always affect the performance of the database.

    See <Note:61623.1>:
    for a detailed discussion on shared pool fragmentation.

    If the SHARED_POOL_SIZE is large enough, most ORA-04031 errors are a
    result of dynamic sql fragmenting the shared pool. This can
    be caused by:

    o Not sharing SQL

    o Making unnecessary parse
    calls (soft)

    o Not using bind variables

    To reduce fragmentation you will need to address one or more of the
    causes described before. In general to reduce fragmentation you must analyze
    how the application is using the shared pool and maximize the use of sharable cursors.

    Please refer to <Note:62143.1>,
    which describes these options in greater detail. This note contains as well
    further detail on how the shared pool works.

    The following views will help you to identify non-sharable versions
    of SQL/PLSQL text in the shared pool:

    • V$SQLAREA View
      This view keeps information of every SQL statement and
      PL/SQL block executed in the database. The following SQL can show you statements
      with literal values or candidates to include bind variables:

      SELECT substr(sql_text,1,40) "SQL",

      count(*) ,

      sum(executions) "TotExecs"

      FROM v$sqlarea

      WHERE executions < 5

      GROUP BY substr(sql_text,1,40)

      HAVING count(*) > 30

      ORDER BY 2;

      Note: The number "30" in the having section of the statement can be
      adjusted as needed to get more detailed information.


    • X$KSMLRU View
      There is a fixed table called x$ksmlru that tracks allocations in the
      shared pool that cause other objects in the shared pool to be aged out.
      This fixed table can be used to identify what is causing the large allocation.

      If many objects are being periodically flushed from the shared pool
      then this will cause response time problems and will likely cause library
      cache latch contention problems when the objects are reloaded into the
      shared pool.

      One unusual thing about the x$ksmlru fixed table is that the contents
      of the fixed table are erased whenever someone selects from the fixed table.
      This is done since the fixed table stores only the largest allocations
      that have occurred. The values are reset after being selected so that subsequent
      large allocations can be noted even if they were not quite as large as
      others that occurred previously. Because of this resetting, the output
      of selecting from this table should be carefully kept since it cannot be
      retrieved back after the query is issued.

      To monitor this fixed table just run the following:

      SELECT * FROM X$KSMLRU WHERE ksmlrsiz > 0;

      This view can only be queried by connected as the SYS.


    • X$KSMSP View (Similar to Heapdump Information)
      Using this view you will be able to find out how the free space
      is currently allocated, which will be helpful to undrestand the level of
      fragmentation of the shared pool. As it was described before, the first place to
      find a chunck big enough for the cursor allocation is the free list. The following SQL shows the chucks available in the free list:

      select '0 (<140)' BUCKET, KSMCHCLS, 10*trunc(KSMCHSIZ/10) "From",

      count(*) "Count" , max(KSMCHSIZ) "Biggest",

      trunc(avg(KSMCHSIZ)) "AvgSize", trunc(sum(KSMCHSIZ)) "Total"

      from x$ksmsp

      where KSMCHSIZ<140

      and KSMCHCLS='free'

      group by KSMCHCLS, 10*trunc(KSMCHSIZ/10)

      UNION ALL

      select '1 (140-267)' BUCKET, KSMCHCLS, 20*trunc(KSMCHSIZ/20) ,

      count(*) , max(KSMCHSIZ) ,

      trunc(avg(KSMCHSIZ)) "AvgSize", trunc(sum(KSMCHSIZ)) "Total"

      from x$ksmsp

      where KSMCHSIZ between 140 and 267

      and KSMCHCLS='free'

      group by KSMCHCLS, 20*trunc(KSMCHSIZ/20)

      UNION ALL

      select '2 (268-523)' BUCKET, KSMCHCLS, 50*trunc(KSMCHSIZ/50) ,

      count(*) , max(KSMCHSIZ) ,

      trunc(avg(KSMCHSIZ)) "AvgSize", trunc(sum(KSMCHSIZ)) "Total"

      from x$ksmsp

      where KSMCHSIZ between 268 and 523

      and KSMCHCLS='free'

      group by KSMCHCLS, 50*trunc(KSMCHSIZ/50)

      UNION ALL

      select '3-5 (524-4107)' BUCKET, KSMCHCLS, 500*trunc(KSMCHSIZ/500) ,

      count(*) , max(KSMCHSIZ) ,

      trunc(avg(KSMCHSIZ)) "AvgSize", trunc(sum(KSMCHSIZ)) "Total"

      from x$ksmsp

      where KSMCHSIZ between 524 and 4107

      and KSMCHCLS='free'

      group by KSMCHCLS, 500*trunc(KSMCHSIZ/500)

      UNION ALL

      select '6+ (4108+)' BUCKET, KSMCHCLS, 1000*trunc(KSMCHSIZ/1000) ,

      count(*) , max(KSMCHSIZ) ,

      trunc(avg(KSMCHSIZ)) "AvgSize", trunc(sum(KSMCHSIZ)) "Total"

      from x$ksmsp

      where KSMCHSIZ >= 4108

      and KSMCHCLS='free'

      group by KSMCHCLS, 1000*trunc(KSMCHSIZ/1000);

      Note: The information available in this view is the same that is generated as part of a HEAPDUMP level 2.

      If the result of the above query shows that must of the space available is on the top part of the list (meaning available only in very small chuncks). It is very likely that the error is due to a heavy fragmentation.


4. ORA-04031 error and Large Pool

The Large pool is an optional memory area that can be configured to provide large memory allocations for one of the following operations :
  • session memory for the multi-threaded server and the Oracle XA interface.
  • The memory ( Buffers ) for Oracle backup and restore operations and for I/O server processes.
  • Parallel Execution messaging buffers.
  • The Large pool does not have a LRU list. It is different from reserved space in the shared pool, which uses the same LRU list as other memory allocated from the shared pool.
    Chunks of memory are never aged out of the large pool,memory has to be explicitly allocated and freed by each session.
    If there is no free memory left when a request is made then an ORA-4031 will be signalled similar to this :

    ORA-04031: unable to allocate XXXX bytes of shared memory
    ("large pool","unknown object","session heap","frame")

    Few things can be checked when this error occurs:

    1- Check V$SGASTAT and see how much memory is used and free using the following SQL statement:


      SELECT pool,name,bytes FROM v$sgastat where pool = 'large pool';

    2- You can also take a heapdump level 32 to dump the large pool heap and check free chunks sizes.

    Memory is allocated from the large pool in chunks of LARGE_POOL_MIN_ALLOC bytes to help avoid fragmentation. Any request to allocate a chunk size less LARGE_POOL_MIN_ALLOC will be allocated with size of LARGE_POOL_MIN_ALLOC. In general you may see more memory usage when using Large Pool compared to Shared Pool.

    Usually to resolve an ORA-4031 in the large pool the LARGE_POOL_SIZE size must be increased.


    5. ORA-04031 and SHARED POOL FLUSHING

    There are several technics to increase cursor sharability so that shared pool fragmentation is reduce as well as likeability of ORA-4031 errors. The best way is by modifying the application to use bind variables. Another workaround when the application cannot be modified is using CURSOR_SHARING to a value different of FORCE (Be aware that this may cause changes in execution plan, so it is advisable to test the application first). When none of the above techniques can be used and fragmentation is considearble heavy in the system, flushing the shared pool might help alliviating the fragmentation. However some considerations must be taken into account:
    • Flushing the shared pool will cause that all the cursor that are not in use are removed from the library cache. Therefore just after the shared pool flusing is issued, most of the SQL and PL/SQL cursors will have to be hard parsed. This will increase the CPU usage of the system and will also increase the latch activity.
    • When applications don't use bind variables and have heavy possibilities of many users doing frequen similar operations (like in OLTP systems) it is common that soon after the flush is issued the fragmentation is back in place. So be advice that flushing the shared pool is not always the solution for a bad application.
    • For large shared pool flushing the shared pool may cause a halt of the system, specially when the instance is very active. It is recommended to flush the shared pool during off-peak hours.


    6. Advanced analysis to ORA-04031error

    If none of the techniques provided cannot resolve the occurence of ORA-04031 errors, additional tracing may be needed to get a snapshot of the shared pool when the problem is in place.

      Modify the init.ora paramater to add the following events to get a trace file with additional information about the problem:
      event = "4031 trace name errorstack level 3"
      event = "4031 trace name HEAPDUMP level 3"

      Note: This parameter will take not effect unless the instance is bounced.

      If the problem is reproducible, the event can be set at session level using the following statement before the execution of the faulty SQL statement:
      SQL> alter session set events '4031 trace name errorstack level 3';
      SQL> alter session set events '4031 trace name HEAPDUMP level 3';

    This trace file should be sent to Oracle Support for troubleshooting.

    Important Note: In Oracle 9.2.0.5 and Oracle 10g releases a trace file is generated BY DEFAULT every time an ORA-4031 error occurs, and can be located in the user_dump_dest directory. If your database version is one of these, you don't need to follow the steps described before to generate additional tracing.


    RELATED DOCUMENTS

    <Note:1012046.6> How to Calculate Your Shared Pool Size
    <Note:62143.1> Understanding and Tuning the Shared Pool
    <Note:1012049.6> Tuning Library Cache Latch Contention
    <Note:61623.1> Resolving Shared Pool Fragmentation




    jametong 发表于:2005.04.26 07:41 ::分类: ( oracle refs ) ::阅读:(2312次) :: 评论 (41)
    ===========================================================
    about date manipulation(zt asktom)
    ===========================================================
    How to get the the date of first day of the week for a given week #?  For 
    example, the beginning day for week# 34 in 2003 is AUG-18-2003, how do I find
    the beginning date for the same week # 34 in 2002? 'iw' can't be used in the
    to_date function.

    Thanks!

    Followup:
    well, we can use the fact that at least from 1800 to 2199, jan 4th is in the 
    first week... this:

    ops$tkyte@ORA920> select *
    2 from (
    3 select dt1, to_char( dt1, 'yyyy' ),
    4 to_char( dt4, 'iw' ),
    5 decode( to_char( dt4, 'iw' ), '01', null, '******' ) xxx
    6 from (
    7 select add_months( to_date( '01-jan-1800', 'dd-mon-yyyy'), (rownum-1)*12 )
    dt1,
    8 add_months( to_date( '02-jan-1800', 'dd-mon-yyyy'), (rownum-1)*12 )
    dt2,
    9 add_months( to_date( '03-jan-1800', 'dd-mon-yyyy'), (rownum-1)*12 )
    dt3,
    10 add_months( to_date( '04-jan-1800', 'dd-mon-yyyy'), (rownum-1)*12 )
    dt4,
    11 add_months( to_date( '05-jan-1800', 'dd-mon-yyyy'), (rownum-1)*12 )
    dt5,
    12 add_months( to_date( '06-jan-1800', 'dd-mon-yyyy'), (rownum-1)*12 )
    dt6,
    13 add_months( to_date( '07-jan-1800', 'dd-mon-yyyy'), (rownum-1)*12 )
    dt7
    14 from all_objects
    15 where rownum <= 400
    16 )
    17 )
    18 where xxx is not null
    19 /

    no rows selected


    shows that.

    Then, we can use the fact that next_day(dt-7,'mon') returns the monday of that
    week that DT falls in.

    sooo, it would seem that if we

    take jan-4th of the year of interest.

    we add to that the (week-2)* 7 days (-1 becuase we start at week one, -1 again
    because we back off 7 days) .

    and then ask for the next monday -- we get it:

    ops$tkyte@ORA920> variable year varchar2(4)
    ops$tkyte@ORA920> variable week number
    ops$tkyte@ORA920>
    ops$tkyte@ORA920> exec :year := '2003'; :week := 34

    PL/SQL procedure successfully completed.

    ops$tkyte@ORA920>
    ops$tkyte@ORA920> select next_day( to_date( '04-jan-' || :year, 'dd-mon-yyyy' )
    + (:week-2)*7, 'mon' )
    2 from dual
    3 /

    NEXT_DAY(TO_DATE('04
    --------------------
    18-aug-2003 00:00:00



    this query generates all of the "first days of the week" by IW week for a year:

    ops$tkyte@ORA920> select year, week,
    2 next_day( to_date( '04-jan-' || year, 'dd-mon-yyyy' ) + (week-2)*7,
    'mon' )
    3 from (select '2003' year, rownum week from all_objects where rownum <= 53
    )
    4 /

    YEAR WEEK NEXT_DAY(TO_DATE('04
    ---- ---------- --------------------
    2003 1 30-dec-2002 00:00:00
    2003 2 06-jan-2003 00:00:00
    2003 3 13-jan-2003 00:00:00
    2003 4 20-jan-2003 00:00:00
    2003 5 27-jan-2003 00:00:00
    2003 6 03-feb-2003 00:00:00
    2003 7 10-feb-2003 00:00:00
    2003 8 17-feb-2003 00:00:00
    2003 9 24-feb-2003 00:00:00
    2003 10 03-mar-2003 00:00:00
    2003 11 10-mar-2003 00:00:00
    2003 12 17-mar-2003 00:00:00
    2003 13 24-mar-2003 00:00:00
    2003 14 31-mar-2003 00:00:00
    2003 15 07-apr-2003 00:00:00
    2003 16 14-apr-2003 00:00:00
    2003 17 21-apr-2003 00:00:00
    2003 18 28-apr-2003 00:00:00
    2003 19 05-may-2003 00:00:00
    2003 20 12-may-2003 00:00:00
    2003 21 19-may-2003 00:00:00
    2003 22 26-may-2003 00:00:00
    2003 23 02-jun-2003 00:00:00
    2003 24 09-jun-2003 00:00:00
    2003 25 16-jun-2003 00:00:00
    2003 26 23-jun-2003 00:00:00
    2003 27 30-jun-2003 00:00:00
    2003 28 07-jul-2003 00:00:00
    2003 29 14-jul-2003 00:00:00
    2003 30 21-jul-2003 00:00:00
    2003 31 28-jul-2003 00:00:00
    2003 32 04-aug-2003 00:00:00
    2003 33 11-aug-2003 00:00:00
    2003 34 18-aug-2003 00:00:00
    2003 35 25-aug-2003 00:00:00
    2003 36 01-sep-2003 00:00:00
    2003 37 08-sep-2003 00:00:00
    2003 38 15-sep-2003 00:00:00
    2003 39 22-sep-2003 00:00:00
    2003 40 29-sep-2003 00:00:00
    2003 41 06-oct-2003 00:00:00
    2003 42 13-oct-2003 00:00:00
    2003 43 20-oct-2003 00:00:00
    2003 44 27-oct-2003 00:00:00
    2003 45 03-nov-2003 00:00:00
    2003 46 10-nov-2003 00:00:00
    2003 47 17-nov-2003 00:00:00
    2003 48 24-nov-2003 00:00:00
    2003 49 01-dec-2003 00:00:00
    2003 50 08-dec-2003 00:00:00
    2003 51 15-dec-2003 00:00:00
    2003 52 22-dec-2003 00:00:00
    2003 53 29-dec-2003 00:00:00

    53 rows selected.



    please -- check out the boundary value conditions!!! (eg: test this, date things
    can be tricky)


    jametong 发表于:2005.04.26 05:29 ::分类: ( oracle refs ) ::阅读:(582次) :: 评论 (0)
    ===========================================================
    how to send html email through utl_smtp
    ===========================================================
    You Asked (Jump to Tom's latest followup)
    Hi Tom

    I hope I'm phrasing this correctly...

    I'd like to be able to send an HTML formatted email from the database using the
    UTL_SMTP package. I don't see any way of setting the MIME type.

    Is this beyond the scope of UTL_SMTP?

    thanks in advance!

    Ken
    and we said...
    I asked Tyler Muth (tyler.muth@oracle.com) to answer this one since I knew he 
    already had the code (we use it on our Oracle Calendar software shipped with the
    email server to send reminders for appointments). Tyler provided this answer
    for us:

    ...

    You are correct in you observation that there is no MIME type parameter in
    UTL_SMTP, but this does not limit the types of email you can send. It's
    actually very flexible, in that UTL_SMTP allows you to contruct and pass in
    the whole email message. What this means to you is that constructing an
    HTML message is possible using UTL_SMTP, but your going to have to do some
    work to create it.

    The folowing is the basic structure of the message you need to construct:


    Normal Headers
    Content-Type: multipart/alternative;
    boundary="some_unique_string_not_in_email"

    --some_unique_string_not_in_email
    Content-Type: text/plain; charset=us-ascii

    Text email message here.

    --some_unique_string_not_in_email
    Content-Type: text/html; charset=us-ascii

    <html>
    <head>
    <title>some subject</title>
    </head>
    <body>
    Your <b>Html</b> email message here.
    </body>
    </html>

    --some_unique_string_not_in_email--


    Ok, that looks hard, but if you use this procedure I wrote, its really quite
    easy, it does all of the work for you:


    create or replace procedure html_email(
    p_to in varchar2,
    p_from in varchar2,
    p_subject in varchar2,
    p_text in varchar2 default null,
    p_html in varchar2 default null,
    p_smtp_hostname in varchar2,
    p_smtp_portnum in varchar2)
    is
    l_boundary varchar2(255) default 'a1b2c3d4e3f2g1';
    l_connection utl_smtp.connection;
    l_body_html clob := empty_clob; --This LOB will be the email message
    l_offset number;
    l_ammount number;
    l_temp varchar2(32767) default null;
    begin
    l_connection := utl_smtp.open_connection( p_smtp_hostname, p_smtp_portnum );
    utl_smtp.helo( l_connection, p_smtp_hostname );
    utl_smtp.mail( l_connection, p_from );
    utl_smtp.rcpt( l_connection, p_to );

    l_temp := l_temp || 'MIME-Version: 1.0' || chr(13) || chr(10);
    l_temp := l_temp || 'To: ' || p_to || chr(13) || chr(10);
    l_temp := l_temp || 'From: ' || p_from || chr(13) || chr(10);
    l_temp := l_temp || 'Subject: ' || p_subject || chr(13) || chr(10);
    l_temp := l_temp || 'Reply-To: ' || p_from || chr(13) || chr(10);
    l_temp := l_temp || 'Content-Type: multipart/alternative; boundary=' ||
    chr(34) || l_boundary || chr(34) || chr(13) ||
    chr(10);

    ----------------------------------------------------
    -- Write the headers
    dbms_lob.createtemporary( l_body_html, false, 10 );
    dbms_lob.write(l_body_html,length(l_temp),1,l_temp);


    ----------------------------------------------------
    -- Write the text boundary
    l_offset := dbms_lob.getlength(l_body_html) + 1;
    l_temp := '--' || l_boundary || chr(13)||chr(10);
    l_temp := l_temp || 'content-type: text/plain; charset=us-ascii' ||
    chr(13) || chr(10) || chr(13) || chr(10);
    dbms_lob.write(l_body_html,length(l_temp),l_offset,l_temp);

    ----------------------------------------------------
    -- Write the plain text portion of the email
    l_offset := dbms_lob.getlength(l_body_html) + 1;
    dbms_lob.write(l_body_html,length(p_text),l_offset,p_text);

    ----------------------------------------------------
    -- Write the HTML boundary
    l_temp := chr(13)||chr(10)||chr(13)||chr(10)||'--' || l_boundary ||
    chr(13) || chr(10);
    l_temp := l_temp || 'content-type: text/html;' ||
    chr(13) || chr(10) || chr(13) || chr(10);
    l_offset := dbms_lob.getlength(l_body_html) + 1;
    dbms_lob.write(l_body_html,length(l_temp),l_offset,l_temp);

    ----------------------------------------------------
    -- Write the HTML portion of the message
    l_offset := dbms_lob.getlength(l_body_html) + 1;
    dbms_lob.write(l_body_html,length(p_html),l_offset,p_html);

    ----------------------------------------------------
    -- Write the final html boundary
    l_temp := chr(13) || chr(10) || '--' || l_boundary || '--' || chr(13);
    l_offset := dbms_lob.getlength(l_body_html) + 1;
    dbms_lob.write(l_body_html,length(l_temp),l_offset,l_temp);


    ----------------------------------------------------
    -- Send the email in 1900 byte chunks to UTL_SMTP
    l_offset := 1;
    l_ammount := 1900;
    utl_smtp.open_data(l_connection);
    while l_offset < dbms_lob.getlength(l_body_html) loop
    utl_smtp.write_data(l_connection,
    dbms_lob.substr(l_body_html,l_ammount,l_offset));
    l_offset := l_offset + l_ammount ;
    l_ammount := least(1900,dbms_lob.getlength(l_body_html) - l_ammount);
    end loop;
    utl_smtp.close_data(l_connection);
    utl_smtp.quit( l_connection );
    dbms_lob.freetemporary(l_body_html);
    end;
    /
    show errors



    jametong 发表于:2005.04.25 11:09 ::分类: ( oracle refs ) ::阅读:(837次) :: 评论 (1)
    ===========================================================
    One way for str2table(zt asktom)
    ===========================================================
    Mohammad -- Thanks for the question regarding "list all user(s) group by group_list", version 8.1.7
    originally submitted on 27-Jun-2003 10:46 Eastern US time, last updated 21-Apr-2005 12:02 You Asked (Jump to Tom's latest followup)
    Hello Tom,

    i have the follwing table:

    LOGIN_NAME GROUP_LIST
    --------------- --------------------------------------------------
    Demo 1; 9000; 1000;
    Koo 1000;
    Feh 1000; 1006; 1021; 1030;
    Hene 1006; 1000; 1021;
    Jaehrling 1000;
    Koell 1000;
    Woeh 1000; 1001;


    Now I am trying to write a query to get the below results

    Demo 1
    Demo 9000
    Demo 1000
    .
    ..

    Could you plaese help me to solve this problem

    Best regards
    Mohammad
    and we said...
    oh yuck.  hate it when people do that.  "relational" database... ok

    ops$tkyte@ORA817DEV> create or replace type myArray as table of number
    2 /

    Type created.

    ops$tkyte@ORA817DEV>
    ops$tkyte@ORA817DEV> create or replace function str2table( p_string in varchar2
    ) return myArray
    2 as
    3 l_data myArray := myArray();
    4 l_string long := p_string;
    5 l_n number;
    6 begin
    7 while (l_string is not null)
    8 loop
    9 l_n := instr( l_string, ';' );
    10 if ( l_n = 0 )
    11 then
    12 l_n := length(l_string)+1;
    13 end if;
    14 l_data.extend;
    15 l_data(l_data.count) := substr( l_string, 1, l_n-1 );
    16 l_string := substr( l_string, l_n+1 );
    17 end loop;
    18 return l_data;
    19 end;
    20 /

    Function created.

    ops$tkyte@ORA817DEV>
    ops$tkyte@ORA817DEV> drop table t;

    Table dropped.

    ops$tkyte@ORA817DEV> create table t ( login_name varchar2(10), group_list
    varchar2(200) );

    Table created.

    ops$tkyte@ORA817DEV>
    ops$tkyte@ORA817DEV> insert into t values ( 'demo', '1; 9000; 1000;' );

    1 row created.

    ops$tkyte@ORA817DEV> insert into t values ( 'feh', '1000; 1006; 1021; 1030;' );

    1 row created.

    ops$tkyte@ORA817DEV>
    ops$tkyte@ORA817DEV> select t.login_name, t2.column_value
    2 from t, TABLE(cast( str2table(t.group_list) as myArray )) t2
    3 /

    LOGIN_NAME COLUMN_VALUE
    ---------- ------------
    demo 1
    demo 9000
    demo 1000
    feh 1000
    feh 1006
    feh 1021
    feh 1030

    7 rows selected.


    is one way.


    jametong 发表于:2005.04.22 12:50 ::分类: ( oracle refs ) ::阅读:(492次) :: 评论 (0)
    ===========================================================
    index creattion guidelines.
    ===========================================================

    很多人都会为如何创建索引发愁, 在什么情况下需要创建索引? 对哪些字段创建索引? 创建什么索引?

    下面就是对应的答案, 来自Oracle perf tunning guide.

    Choosing Columns and Expressions to Index

    A key is a column or expression on which you can build an index. Follow these guidelines for choosing keys to index:

    • Consider indexing keys that are used frequently in WHERE clauses.
    • Consider indexing keys that are used frequently to join tables in SQL statements. For more information on optimizing joins, see the section "Using Hash Clusters".
    • Index keys that have high selectivity. The selectivity of an index is the percentage of rows in a table having the same value for the indexed key. An index's selectivity is optimal if few rows have the same value.


      Note:

      Oracle automatically creates indexes, or uses existing indexes, on the keys and expressions of unique and primary keys that you define with integrity constraints.


      Indexing low selectivity columns can be helpful if the data distribution is skewed so that one or two values occur much less often than other values.

    • Do not use standard B-tree indexes on keys or expressions with few distinct values. Such keys or expressions usually have poor selectivity and therefore do not optimize performance unless the frequently selected key values appear less frequently than the other key values. You can use bitmap indexes effectively in such cases, unless a high concurrency OLTP application is involved where the index is modified frequently.
    • Do not index columns that are modified frequently. UPDATE statements that modify indexed columns and INSERT and DELETE statements that modify indexed tables take longer than if there were no index. Such SQL statements must modify data in indexes as well as data in tables. They also generate additional undo and redo.
    • Do not index keys that appear only in WHERE clauses with functions or operators. A WHERE clause that uses a function, other than MIN or MAX, or an operator with an indexed key does not make available the access path that uses the index except with function-based indexes.
    • Consider indexing foreign keys of referential integrity constraints in cases in which a large number of concurrent INSERT, UPDATE, and DELETE statements access the parent and child tables. Such an index allows UPDATEs and DELETEs on the parent table without share locking the child table.
    • When choosing to index a key, consider whether the performance gain for queries is worth the performance loss for INSERTs, UPDATEs, and DELETEs and the use of the space required to store the index. You might want to experiment by comparing the processing times of the SQL statements with and without indexes. You can measure processing time with the SQL trace facility.


    jametong 发表于:2005.04.22 12:00 ::分类: ( oracle refs ) ::阅读:(434次) :: 评论 (0)
    ===========================================================
    use of dbms_random.(zt www.dbazine.com)
    ===========================================================

    Building a Random Character Value Generator

    Oracle Database 10g provides a random value generator via a package named DBMS_RANDOM, which can be used to generate random values. However, those values are arbitrary, not representative of the real-life system. For instance, the following an example of how you can generate a string 30 characters long:

    SQL> select dbms_random.string('P',30) from dual;

    DBMS_RANDOM.STRING('P',30)
    -----------------------------------------------------
    O=*KXh}#O`D~1|'^VheWr:jZ>!:P}3

    The package DBMS_RANDOM has several functions and procedures, one of which is STRING(), which accepts two parameters and returns a character value. The types of characters generated are determined by the first parameter — OPTION. Here are the options and the types of string generated:

    Option Type of String Produced
    U Any uppercase alphabetic characters
    L Any lowercase alphabetic characters
    A Any mixed case alphabetic characters
    X Any alphanumeric character in upper case
    P Any printable character

    You can also use lowercase characters for the options; e.g., x instead of X. In this example, we used X, which produced a string of printable characters, not just alphabetic ones. Clearly, this kind of character string will not represent a customer name. Using an option such as “A” would generate a more appropriate string.

    Populating a Table

    Let’s start with a real-life example. In the case of Acme Bank’s application development, the team is mulling over the proper indexing, partitioning, physical layout, materialized view planning, and so on, for the ACCOUNTS table, which holds the customers’ account data. Here is how the table looks :

    SQL> desc accounts
    Name Null? Type
    ----------------- -------- ------------
    ACC_NO NOT NULL NUMBER
    FIRST_NAME NOT NULL VARCHAR2(30)
    LAST_NAME NOT NULL VARCHAR2(30)
    ACC_TYPE NOT NULL VARCHAR2(1)
    FOLIO_ID NUMBER
    SUB_ACC_TYPE VARCHAR2(30)
    ACC_OPEN_DT NOT NULL DATE
    ACC_MOD_DT DATE
    ACC_MGR_ID NUMBER

    The columns are fairly self-explanatory. To represent customers in the real world, the following requirements have been specified for the columns:

    Column Name

    Purpose

    Data Pattern

    ACC_NO

    Account Number

    Any number less than 10 digits

    FIRST_NAME

    The first name

    • 10% Alan

    • 10% Barbara

    • 5% Charles

    • 5% David

    • 15% Ellen

    • 20% Frank

    • 10% George

    • 5% Hillary

    • 10% Iris

    • 10% Josh

    LAST_NAME

    The last name

    Any alphabetic character between four and 30 but 25 percent should be “Smith”

    ACC_TYPE

    The type of account — Savings, Checking, and so on

    20 percent each of S, C, M, D, and X

    FOLIO_ID

    The folio ID from the other systems

    Half NULL and the rest half a number related to the account number

    SUB_ACC_TYPE

    If the customer is incorporated, then sub-account types, if any 75 percent null

    From the values populated:

    • 5% — S

    • 20% — C

    ACC_OPEN_DT

    Date account was opened

    A date between now and 500 days ago

    ACC_MGR_ID

    The ID of the account manager servicing the account

    There are five account managers, with account percentages distributed as follows:

    • 1 — 40 percent

    • 2 — 10 percent

    • 3 — 10 percent

    • 4 —10 percent

    • 5 — 30 percent

    As you can see, some fairly complex requirements were specified, but for good reasons. These accurately reflect how the data will be distributed in real life. In real life, there will be customers with first names like “Josh” and “Ellen,” not “XepqjEuF”; so, the names must be chosen from the set of possible names. And, in the U.S., people are called by a variety of last names. Thus, we want a semi-random distribution with 25 percent of a very popular last name, “Smith.”

    Generating Random Numbers

    Before we go any further, we have to discuss how to generate random numbers. The package dbms_random contains a function to return random numbers. If you want to return any random number between -2^31 and +2^31, use the function RANDOM. The following shows how we have generated numbers 10 times:

    SQL> begin
    2 for i in 1..10 loop
    3 dbms_output.put_line('Random Number='||dbms_random.random);
    4 end loop;
    5 end;
    6 /
    Random Number=-81420432
    Random Number=-1024262734
    Random Number=-1965250926
    Random Number=1439118604
    Random Number=675429938
    Random Number=-466227661
    Random Number=613708106
    Random Number=-1154140330
    Random Number=-643127572
    Random Number=-133140229

    This function is available but deprecated. Oracle recommends using a new function called VALUE().

    SQL> l
    1 begin
    2 for i in 1..10 loop
    3 dbms_output.put_line('Random Number='||dbms_random.value);
    4 end loop;
    5* end;
    SQL> /
    Random Number=.547109841457281046373693994862305187
    Random Number=.00500720861223234783817674992068380455
    Random Number=.86974675431616311272549579082479240362
    Random Number=.16306119784529083761710557238498944243
    Random Number=.39327329046753189206427695323437381763
    Random Number=.68307381430584611139249432690613072007
    Random Number=.24640768414299435941101562183729221882
    Random Number=.50568180275705934132098716939122047439
    Random Number=.73345513921455391594299189253661168712
    Random Number=.71764049051903979360796313613342367114

    Note the difference; VALUE returns a positive random decimal number less than one, with 38 digits after the decimal point. In most cases, this is probably enough, with some modification (if you are looking for a 10-digit whole number, for instance, simply multiply it by 10,000,000,000 and use FLOOR() to discard the decimals).

       1  begin
    2 for i in 1..10 loop
    3 dbms_output.put_line('Random Number='||
    4 floor (10000000000 * dbms_random.value)
    5 );
    6 end loop;
    7* end;
    SQL> /
    Random Number=939084911
    Random Number=690705371
    Random Number=4696700513
    Random Number=7978266084
    Random Number=5157885833
    Random Number=8902042948
    Random Number=5839885968
    Random Number=6207324613
    Random Number=5633096626
    Random Number=1891871746

    The function VALUE() is overloaded; another variation of the functions accepts a set of low and high values and returns a number between them. To generate a number between 10 and 20, for instance, you will use

    dbms_random.value (10, 20)

    Note: The numbers generated will be more than or equal to 10, but less than (never equal to) 20.

    Using it to generate multiple values, we get

      1  begin
    2 for i in 1..10 loop
    3 dbms_output.put_line('Random Number='||
    4 dbms_random.value (10,20)
    5 );
    6 end loop;
    7* end;
    SQL> /
    Random Number=11.0908840421899990054735051046498510644
    Random Number=14.5391525077977177619575126573478641174
    Random Number=11.1343623028437386191996545034616142284
    Random Number=14.8831724931888089801812805693409810454
    Random Number=11.7294096895635532492353976105129628219
    Random Number=15.0589018451126293465505440533299716691
    Random Number=15.6152418028444556585301007183814067306
    Random Number=18.2903839241741813303152060555229669855
    Random Number=13.0914352695913402037626709927051618367
    Random Number=12.6027933168087755621076348461280998683

    As you can see, the numbers are generated with 37 digits after the decimal point. This is a very valuable function and will suffice for lmost types of random number generation. If you want to generate only whole numbers, use the same approach used earlier, using the FLOOR() function.

    floor(dbms_random.value (10,20))

    Generating Specific Characters and Strings

    So, how can we generate specific strings that follow a predetermined statistical pattern?

    We can borrow a page from the probability theory text to accomplish this. The trick is to use a method similar to Monte-Carlo simulation used by statisticians worldwide. In this approach, we generate a random number, between one and 100 (both inclusive). Over a period of time, the probability that a specific number, say six, will turn up is exactly one time out of 100, or 1 percent of the time. In fact, all the numbers have 1/100 probability. Going by the same approach, the probability that either of two numbers — say, 1 and 2 — will be 2 percent. And, of course, the probability that any one of numbers between one and 10 will turn up is 10 percent. We will use this to configure the probability of the random value.

    Take, for instance, the value of the column ACC_TYPE, which calls for equal probability of S, C, M, D and X; or 20 percent probability each. If we generate a whole number between one and five (both inclusive), the probability of each number will be 20 percent. Then we can use a DECODE() function to get the ACC_TYPE value.

    SQL> select
    2 decode (
    3 floor (
    4 dbms_random.value (1,6)
    5 ),
    6 1,'S',
    7 2,'C',
    8 3,'M',
    9 4,'D',
    10 'X'
    11 )
    12 from dual;

    First, we are generating a number between one and five (line 4). Since the number is generated is less than the highest value passed as a parameter, we have specified six. And since we want a whole number, we have used the FLOOR() function in line 3. It truncates all decimal values from the generated number. Depending on the number obtained, we used DECODE() to get one of the values — S, C, M, D, or X. Since the numbers 1, 2, 3, 4, and 5 will have equal probability of being generated, so will be the letters — at 20 percent each.

    This technique is very valuable for generating random, but useful values, as shown previously. The same approach can be used to generate almost all types of pre-determined random values.

    Random Values with NULLs

    Remember, the requirement for FOLIO_ID is a little different. It needs only 50 percent of the values populated; the rest should be NULL. How can we achieve this?

    Quite simply, we will use the same probability approach with a twist: we will use a determination of yes or no. Generating a random number between one and 100 will ensure 1 percent probability of each number. Hence, a number less than 51 will have exactly 50 percent probability of occurring. We can use this in a CASE statement to get the value.

    SQL> select
    2 case
    3 when dbms_random.value (1,100) < 51 then null
    4 else
    5 floor(dbms_random.value(1,100))
    6 end
    7 from dual;

    On line 3, we should check to see whether the number generated is less than 51. If so, we return NULL. Since the probability of a sub-51 number is 50 percent , we have NULLs occurring 50 percent of the time as well. In the other 50 percent of the time, we have generated a value to be used as a FOLIO_ID.

    Random Strings of Random Length

    In dbms_random.string, a random string is generated, but of fixed length. That is not representative of real life; in reality, people have last names of varying lengths. In this example, the requirement is to have a length between four and 30 characters. To facilitate this, we can pass the length as a random number as well to the function dbms_random.string in line 6 below.

      1  begin
    2 for i in 1..10 loop
    3 dbms_output.put_line('Random String='||
    4 dbms_random.string (
    5 'A',
    6 dbms_random.value(4,30)
    7 )
    8 );
    9 end loop;
    10* end;
    SQL> /
    Random String=RniQZGquFVJYFpGLOvtNd
    Random String=GhcphpcsaCXlhigRQY
    Random String=JtakoelUf
    Random String=BgCOu
    Random String=QFBzQxcHqGlHWkZFmnN
    Random String=lSxVjqJvpwBB
    Random String=jfhNARzALrLOKZRpOwnhrzz
    Random String=KuFtdJcqQpjkrFmzFbzcXnYFGjWo
    Random String=BhuZ
    Random String=GebcqcgvzBfEpTYnJPmYAQdb

    Notice that the strings are of different lengths. Remember, 25 percent of the last names must be “Smith,” and the rest must have random lengths. We can accomplish this by combining the random strings and the Monte-Carlo approach:

       decode (
    floor(dbms_random.value(1,5)),
    1,'Smith',
    dbms_random.string ('A',dbms_random.value(4,30))
    )

    The previous expression will return “Smith” 25 percent of the time and a random alphabetic string between four and 30 characters long the rest of the time.

    Putting it All Together

    Now that you understood the building blocks of the randomization approach, you can put them together to build the account record generation PL/SQL block as shown below. In the following example, we are loading 100,000 records into the table ACCOUNTS. Here is the loading program in full:

    begin
    for l_acc_no in 1..100000 loop
    insert into accounts
    values
    (
    l_acc_no,
    -- First Name
    decode (
    floor(dbms_random.value (1,21)),
    1, 'Alan',
    2, 'Alan',
    3, 'Barbara',
    4, 'Barbara',
    5, 'Charles',
    6, 'David',
    7, 'Ellen',
    8, 'Ellen',
    9, 'Ellen',
    10, 'Frank',
    11, 'Frank',
    12, 'Frank',
    13, 'George',
    14, 'George',
    15, 'George',
    16, 'Hillary',
    17, 'Iris',
    18, 'Iris',
    19,'Josh',
    20,'Josh',
    'XXX'
    ),
    -- Last Name
    decode (
    floor(dbms_random.value(1,5)),
    1,'Smith',
    dbms_random.string ('A',dbms_random.value(4,30))
    ),
    -- Account Type
    decode (
    floor(dbms_random.value (1,5)),
    1,'S',2,'C',3,'M',4,'D','X'
    ),
    -- Folio ID
    case
    when dbms_random.value (1,100) < 51 then null
    else
    l_acc_no + floor(dbms_random.value(1,100))
    end,
    -- Sub Acc Type
    case
    when dbms_random.value (1,100) < 76 then null
    else
    decode (floor(dbms_random.value (1,6)),
    1,'S',2,'C',3,'C',4,'C',5,'C',null)
    end,
    -- Acc Opening Date
    sysdate - dbms_random.value(1,500),
    -- Account Manager ID
    decode (
    floor(dbms_random.value (1,11)),
    1,1,2,1,3,1,4,1,5,2,6,3,7,4,8,5,9,5,10,5,0
    )
    );
    end loop;
    commit;
    end;

    Now, how do we know that all these exercise yielded fruit? After this table is loaded, let’s see the actual distribution:

    SQL> select first_name, count(*) from accounts group by first_name;


    FIRST_NAME COUNT(*)
    ------------------------------ ----------
    Alan 9834
    Barbara 10224
    Charles 5046
    David 4980
    Ellen 15094
    Frank 14960
    George 14890
    Hillary 4898
    Iris