Oracle SQL
Oracle SQL
1
ORACLE SQL
Type of relations :
1. One to One : Student -- School
2. One to Many : Department -- Employee
3. Many to One : Employee -- Department
4. Many to Many : Students -- Courses
ORACLE :
1. PL/SQL
PL (Procedural Language) Triggers & Blocks and it is a Set of
Commands are executed one statement as block (at once)
SQL (Structure Query Language) : Set of Commands are executed one by
one
2. Developer : Forms, Reports, Graphics
3. Designer
4. DBA Data Base Administration
Tuning DB
Recovering DB
Data Type:
1. Number : 1-38 digits
Number takes the Max. digits
Number(no)
Number(no,decimal)
2. Char(no) : 1-255 character
3. Varchar2(no) : 1–2000
4. Date : Number or Julian, it takes 7 bytes
5. Raw : 2 KB saved in binary
6. Longrow : 4 GB for emages and sounds, saved in binary
7. Long : 2 GB for notes, only one Long in table is allowed
Oracle Commands :
1. DDL (Data Define Language) : Create (for tables), Rename, Drop, Alter
2. DML (Data Manipulation Language) : Select, Alter, Delete, Update, Insert
3. DCL (Data Control Language) : Create, Drop for users
Users of Oracle :
1. Sys/sys : owner of database
2. System/manager : Local for database (All privilege)
3. Scott/tiger : user of database (Certain Privilege)
4. Demo/demo : user of database
3
SQL> describ deptOR SQL> describ
dept; Name Null? Type
We can save the last SQL statement written using the SQL+
command : SQL> Save c:\kaz it will be saved with
extension .SQL
Created file c:\kaz
4
DEPTNO DNAME LOC
5 rows selected.
5 rows
selected.
SQL> ed
Wrote file
[Link] 1*
select * from
dept
5 rows selected.
emp; EMPNO
5
7369
7499
7521
7566
6
SQL> select empno no1,ename name from emp;
$ used to change the default header (Aliases)
NO1 NAME
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7369 9600
7499 19200
7521 15000
7566 35700
7369 800
7499 1600 300 1900
7521 1250 500 1750
7566 2975
if any of sal or comm fields has a null value the result will be null so we use
NVL(fieldname,0) where 0 means: replace the null field with 0, as:
SQL> select empno,sal,comm,sal+nvl(comm,0) from emp;
emp; ENAME||'EARNS'||SAL
7
SQL> select ename||' earns '||sal "Employee Information" from emp;
Employee Information
BETWEEN:
SQL> select * from emp where sal BETWEEN 1000 and
2000; The 1000 & 2000 values are included
6 rows selected.
SQL> select * from emp where hiredate between '1-jan-1980' and '1-jan-1982';
11 rows selected.
8
LIKE & NOT LIKE:
= : exactly the same
LIKE : some part of it using % part, _ for one
'SCOTT';
IN & NOT IN :
SQL> select ENAME,JOB FRom emp where JOB IN ('CLERK','MANAGER');
ENAME JOB
SMITH CLERK
JONES MANAGER
BLAKE
MANAGER CLARK
MANAGER
ADAMS CLERK
JAMES CLERK
MILLER CLERK
7 rows selected.
9
IS NULL & IS NOT NULL :
SQL> SELECT * FROM EMP WHERE COMM IS NULL;
10 rows
selected.
ORDER BY :
The defaul ordering is ASC but we can make it DESC
SQL> select * from emp order by sal;
14 rows
selected.
1
0
7782 CLARK MANAGER 7839 09-JUN-1981 2450 10
7499 ALLEN SALESMAN 7698 20-FEB-1981 1600 300 30
7844 SALESMAN 7698 08-SEP-1981 1500 0 30
TURNER
7934 MILLER CLERK 7782 23-JAN-1982 1300 10
7521 WARD SALESMAN 7698 22-FEB-1981 1250 500 30
7654 MARTIN SALESMAN 7698 28-SEP-1981 1250 1400 30
7876 ADAMS CLERK 7788 23-MAY-1987 1100 20
7900 JAMES CLERK 7698 03-DEC-1981 950 30
7369 SMITH CLERK 7902 17-DEC-1980 800 20
1
1
SQL> select * from emp order by sal,job;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
14 rows
selected.
14 rows selected.
14 rows selected.
14 rows selected.
DISTINCT :
SQL> select distinct deptno,job from emp;
DEPTNO JOB
10 CLERK
10 MANAGER
10 PRESIDENT
20 ANALYST
20 CLERK
20 MANAGER
30 CLERK
30 MANAGER
30 SALESMAN
9 rows selected.
********************************************************************
1
3
SINGLE ROW FUNCTIONS FOR CHARACTERS
DUAL :
SQL> select 5*12 from emp;
It will show 60 as many records in emp so we use a dummy table called DUAL
in these cases, it contain one record used for calculation :
dual; 5*12
60
dual; 'KHALE
khaled
sysdate,user :
The date will be read from the computer where ORACLE
installed SQL> select sysdate,user from dual;
SYSDATE USER
INICAP :
SQL> SELECT 'KHALED ZAGHLOUL' FROM DUAL;
'KHALEDZAGHLOUL
KHALED ZAGHLOUL
1
4
Change the first Character to capital letter
INITCAP('KHALED
Khaled Zaghloul
DNAME SUB
ACCOUNTING ACC
RESEARCH RES
SALES SAL
OPERATIONS OPE
DNAME INSTR(DNAME,'A',1,1)
ACCOUNTING 1
RESEARCH 5
SALES 2
OPERATIONS 5
ACCOUNTING CCOUNTING
RESEARCH RESEARCH
SALES SALES
OPERATIONS OPERATIONS
DNAME LPAD(DNAME,20,'*')
ACCOUNTING
**********ACCOUNTING
1
5
RESEARCH ************RESEARCH
SALES ***************SALES
OPERATIONS
**********OPERATIONS
1
6
SQL> select dname,rpad(dname,20,'*') from dept
DNAME RPAD(DNAME,20,'*')
ACCOUNTING
ACCOUNTING**********
RESEARCH RESEARCH************
SALES SALES***************
OPERATIONS
OPERATIONS**********
ACCOUNTING $$$$
$ACCOUNTING***** RESEARCH
$$$$$$$RESEARCH*****
SALES $$$$$$$$$$SALES*****
OPERATIONS $$$$
$OPERATIONS*****
DNAME TRANSLATE(DNAM
ACCOUNTING
*CCOUNTING
RESEARCH RESE*RCH
SALES S*%ES
OPERATIONS OPER*TIONS
DNAME REPLACE(DNAME,'AC','XYZ')
ACCOUNTING XYZCOUNTING
RESEARCH RESEARCH
SALES SALES
OPERATIONS OPERATIONS
LENGTH :
If the field is of type CHAR, it gives the Max. length
VARCHAR2, it gives the Exact length
SQL> select dname,length(dname) from dept;
1
7
DNAME LENGTH(DNAME)
ACCOUNTING 10
RESEARCH 8
SALES 5
OPERATIONS 10
1
8
Example :
DNAME LENGTH(DNAME)-LENGTH(TRANSLATE(DNAME,'XC','X'))
ACCOUNTING 2
RESEARCH 1
SALES 0
OPERATIONS 0
1
9
SINGLE ROW FUNCTIONS FOR NUMBERS
ROUND :
SQL> select round(97.89),round(97.89,1),round(97.89,-1) from dual;
98 97.9 100
TRUNC :
SQL> select trunc(97.89),trunc(97.89,1),trunc(97.89,-1) from dual;
97 97.8 90
SIGN :
SQL> select sign(67),sign(0),sign(-34) from dual;
1 0 -1
CEIL(5.89) FLOOR(5.89)
6 5
MOD(3,2)
ABS(23) ABS(-45)
23 45
2
0
SINGLE ROW FUNCTIONS FOR DATES
SYSDATE :
SQL> select sysdate from dual;
SYSDATE
19-DEC-1999
SYSDATE+2
21-DEC-1999
19-DEC-1999
MONTHS_BETWEEN :
SQL> select ename,sysdate,hiredate,months_between(sysdate,hiredate) from emp;
The result will be No. of months and apart of month
ADD_MONTHS :
SQL> select add_months('1-jan-2000',1) from
dual; Add a No. of months to the Date given
ADD_MONTHS(
01-FEB-2000
2
1
ADD_MONTHS(
29-FEB-2000
LAST_DAY :
SQL> select last_day('1-feb-1996') from
dual; Gives the date of the last day in a
month
LAST_DAY('1
29-FEB-1996
NEXT_DAY :
SQL> select next_day('19-jul-2000','friday') from
dual; Gives the date of the next first day given
NEXT_DAY('1
21-JUL-2000
ROUND :
SQL> select
round(sysdate),round(sysdate,'month'),round(sysdate,'year')
from dual;
TRUNC :
SQL> select
trunc(sysdate),trunc(sysdate,'month'),trunc(sysdate,'year')
from dual;
TRUNC(SYSDATE,'YEAR'))
200
2
3
This would obviously print out the begin- and end-time for each SQL statement if
they were sent as a batch. The alternative technique is just as simple but provides a
bit more information about the query itself. By using SET STATISTICS TIME ON, you
obtain information about CPU time and elapsed time for both parse and execution of
the query.
SET STATISTICS TIME ON
SELECT * FROM authors
SELECT * FROM titleauthor
The first reading is the CPU and elapsed time to parse and compile
the query. The second reading is the CPU and elapsed time to
execute the query.
Note: that SET STATISTICS TIME does not take into account time spent waiting for
locks or resources. Thus, the times may differ from that of the GETDATE() function if
there is any kind of resource contention.
Using the GETDATE() method may be all you need to gauge your query time(s), but
if you are interested in compile and optimize time(s), you will need to use SET
STATISTICS TIME ON|OFF.
DECODE :
It Means (IF THEN ELSE)
SQL> select ename,sal,decode(sal,2450,'ok','bad') from
emp; Means (If sal=2450 Then ‘OK’ Else ‘Bad’)
ENAME SAL DEC
2
4
SQL> select ename,sal,decode(sign(sal-2450),0,'ok',1,'good','bad') from emp;
Means (If sal<2450 Then ‘bad’ Else
If Sal = 2450 Then ‘ok’ Else ‘good’)
Functions to handle the format of date (TO_CHAR & TO_DATE & TO_NUMBER)
TO_CHAR :
SQL> select ename,to_char(hiredate,'day dd,month year') from emp;
ENAME TO_CHAR(HIREDATE,'DAYDD,MONTHYEAR')
2
5
SMITH 17-DEC-1980 Wed 17,December
1980 ALLEN 20-
FEB-1981 Fri 20,February 1981 WARD
22-FEB-1981 Sun 22,February
1981 JONES
02-APR-1981 Thu 02,April 1981
2
6
SQL> select ename,hiredate,to_char(hiredate,'Dy dd,MM YYYY') from emp;
1,600.000
WARD 1250
1,250.000
JONES 2975
2,975.000
SMITH 800
000,800.000
ALLEN 1600
001,600.000
WARD 1250
001,250.000
JONES 2975
002,975.000
TO_CHAR(SYSDATE,'DDMONTH,Y
2
7
SQL> select to_char(sysdate,'dd month,yyyy hh24:mi:ss') from dual;
TO_CHAR(SYSDATE,'DDMONTH,Y
2
8
SQL> select to_char(sysdate,'dd month,yyyy hh24:mi:ss am') from dual;
TO_CHAR(SYSDATE,'DDMONTH,YYYY
TO_DATE :
SQL> select to_char(to_date(‘19-07-2000’,’DD MM YYYY’),’DAY’)
from dual; Gives the name of the day of a date
FORMAT CHANGE :
The date is in format of : 19-JUL-
2000 To change it to a format :
19/07/2000 We start from windows
:
1. START
2. RUN : Regedit
3. HKEY_LOCAL_MACHINE
4. SOFTWARE
5. ORACLE
6. NLS_DATE_FORMAT : double click on it, then write the new format
7. EXIT
To validate the new format we have to reconnect to SQL :
SQL> Connect Scott/Tiger
The solution for Y2K was by putting a new format for year it is RR so if we write the
format in : DD MM RR : if RR (Year) between 0 & 49 it consider it as 20RR and
If it was between 50 & 99 it consider it as 19RR
2
9
JOINS
There are 3 kinds of Join:
1- Equi-Join:
SQL> select ename,dname from emp,dept where [Link] = [Link];
ENAME DNAME
SMITH RESEARCH
ALLEN SALES
CLARK ACCOUNTING
SCOTT RESEARCH
2- Non Equi-Join:
SQL> select ename,dname,[Link] from emp,dept where [Link] =
[Link];
SMITH RESEARCH 20
ALLEN SALES 30
CLARK ACCOUNTING 10
SCOTT RESEARCH 20
KING ACCOUNTING 10
The number of join conditions are at least equal to the number of tables in select
statement - 1
3- Self Join:
SQL> select ename,dname,[Link] from emp e,dept d where [Link] = [Link];
SMITH RESEARCH 20
ALLEN SALES 30
CLARK ACCOUNTING 10
SCOTT RESEARCH 20
KING ACCOUNTING 10
SMITH 800 1
MILLER 1300 2
ALLEN 1600 3
CLARK 2450 4
SCOTT 3000 4
KING 5000 5
3
0
SQL> select [Link], [Link] from emp e, emp m where [Link] = [Link];
ENAME ENAME
SMITH FORD
ALLEN BLAKE
CLARK KING
SCOTT JONES
4- Outer Join:
SQL> select [Link],[Link] from emp e,dept d where [Link] =[Link];
ENAME DNAME
CLARK ACCOUNTING
KING ACCOUNTING
SMITH RESEARCH
SCOTT RESEARCH
ALLEN SALES
This statement did not bring the OPERATION department, Becouse it has no
employees in it, so
:
CLARK ACCOUNTING
KING ACCOUNTING
SMITH RESEARCH
SCOTT RESEARCH
ALLEN SALES
OPERATIONS
3
1
GRASP THE SYNTAX OF OUTER JOINS
Starting with Oracle9i, the confusion of the outer join syntax using the (+) notation
has been superseded by the ISO 99 outer join syntax. There are three types of
outer joins: left, right, and the full outer. The purpose of an outer join is to include
nonmatching rows, which the outer join returns as NULL values.
Let's review the syntax differences between these variations in joins:
The full outer join has no direct equivalent in Oracle8i, but it's very handy to find
missing rows in both tables being joined in Oracle9i. In the example below, we
include employees with departments as well as departments without employees:
29025
3
2
emp; AVG(SAL)
2073.2143
3
3
GROUP BY :
SQL> select deptno,sum(sal) from emp group by deptno;
DEPTNO SUM(SAL)
10 8750
20 10875
30 9400
10 1300
10 2450
10 5000
20 6000
20 1900
20 2975
30 950
30 2850
30 5600
9 rows selected.
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
9 rows selected.
550 550
3
4
SQL> select count(*),avg(comm),sum(comm)/count(comm) from emp;
14 550 550
SQL> select
count(*),count(comm),avg(comm),sum(comm)/count(comm),sum(comm)/count(*)
from emp;
The GROUP BY clause in queries has become more complex recently. Until
A few years ago, the only option for aggregate functions was the standard
DEPTNO SUM(SAL)
10 8750
20 10875
30 9400
DEPTNO SUM(SAL)
10 8750
20 1087
5
30 9400
29025
With the ROLLUP clause, you can now do the same thing as the
union example did, but more easily and accurately. The ROLLUP
clause simply
adds a row to the result that applies the aggregate function to all the rows in the
current rollup. For example:
3
5
select deptno,sum(sal) from emp group by rollup(deptno);
DEPTNO SUM(SAL)
10 8750
20 1087
5
30 9400
29025
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT
5000
10 8750
20 CLERK 1900
20 ANALYST 6000
20 MANAGER 2975
20 10875
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 9400
29025
Notice that we didn't get extra rows for JOB. These rows are
called super-aggregate rows. The ROLLUP clause only adds
rows at the end of each column in its clause. If you want a
summary for every possible combination of grouping column,
use the CUBE clause:
29025
CLERK 4150
ANALYST 6000
MANAGER 8275
SALESMAN 5600
3
6
PRESIDENT 5000
10 8750
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
20 10875
20 CLERK 1900
20 ANALYST 6000
20 MANAGER 2975
30 9400
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
We now have our aggregate rows plus a summary row for each
column in The group by expression. We know the total salary for
PRESIDENT and department 10.
You can use a CUBE grouping to create a cross-tabulation
report, or matrix report, from the SQL results. But when
generating a report, how
do you tell the difference between a row that is normally part of the GROUP BY and
those that have been generated by ROLLUP or CUBE?
The GROUPING function returns 0 if its argument is not part of a
ROLLUP or CUBE in the current row, and 1 if it is:
select
grouping(deptno),grouping(job),deptno,job,sum(s
al) from emp group by cube(deptno,job)
1 1 29025
1 0 CLERK 4150
1 0 ANALYST 6000
1 0 MANAGER 8275
1 0 SALESMAN 5600
1 0 PRESIDENT 5000
0 1 10 875
0
0 0 10 CLERK 1300
0 0 10 MANAGER 2450
0 0 10 PRESIDENT
5000
0 1 20 10875
0 0 20 CLERK 1900
0 0 20 ANALYST 6000
0 0 20 MANAGER 2975
0 1 30 9400
0 0 30 CLERK 950
0 0 30 MANAGER 2850
3
7
0 0 30 SALESMAN
5600
The first row is the CUBE row for both DEPTNO and JOB, so
GROUPING returns 1 for both. The second row is the CUBE row for
the JOB CLERK,
so GROUPING(DEPTNO) returns 1, but GROUPING(JOB) returns 0. These values can be
used by external utilities to detect whether it's a super-aggregate row or a normal
aggregate row.
Oracle9i introduces some new syntax with the GROUPING SETS
clause. Rather than grouping results on a single column, a
GROUPING SETS clause
3
8
Allows a query to group by a combination of data as if it were a single GROUP
BY column. Before Oracle9i, such grouping would have to be done through an
awkward hack. Here's a simple example of grouping before Oracle 9i:
'||job); RPAD(DEPTNO,10)||JOB
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT
SUM(SAL) 5000
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
29025
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
10 8750
20 CLERK 1900
20 ANALYST 6000
20 MANAGER 2975
20 10875
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 9400
29025
4
0
DEPTGRP JOBGRP DEPTNO JOB SUM(SAL)
0 0 10 CLERK 1300
0 0 10 MANAGER 2450
0 0 10 PRESIDENT
5000
0 1 10 8750
0 0 20 CLERK 1900
0 0 20 ANALYST 6000
0 0 20 MANAGER 2975
0 1 20 10875
0 0 30 CLERK 950
0 0 30 MANAGER 2850
0 0 30 SALESMAN
5600
0 1 30 9400
1 1 29025
Note:
There is a system table that you can query to get a rowcount for every table with a
defined clustered index. By using the following query, you can determine the
number of rows in the table based upon the value stored in the sysindexes table.
SQL> SELECT rows FROM sysindexes WHERE id = OBJECT_ID('authors') AND indid < 2
The indid portion of the query identifies the type of index that is defined upon the
table. An indid of 1 is a clustered index; greater than 1 is a nonclustered index
(except for 255, which is an entry for tables that have text or image data).
Obviously, you cannot apply a WHERE clause to this query based upon some criteria
within the target table. Additionally, this technique does not work with views. If you
were counting only the rows where Fname = 'John', then you would have to resort to
the regular method of SELECT COUNT(*) FROM the actual table.
550 157.14286
Examples:
1- give the average of salary for each department where it is greater
than 2000 ? SQL> select deptno,avg(sal) from emp group by deptno
having avg(sal) > 2000;
DEPTNO AVG(SAL)
10 2916.6667
20 2175
4
1
2- Give the minimum average salary between
departments ? SQL> select min(avg(sal)) from emp
group by deptno;
MIN(AVG(SAL))
1566.6667
4
2
SUB QUERIES:
** bring out the employees in SCOTT department ?
SQL> select * from emp where deptno=(select deptno from emp where
ename='SCOTT');
DEPTNO AVG(SAL)
30 1566.6667
** Bring out the employees who's salary is greater than the Max. salary of All
CLERCKS ? SQL> select * from emp where sal > all (select sal from emp where
job='CLERK');
8 rows selected.
4
3
** Bring out the employees who's salaries is greater than any CLERCK
salary? SQL> select * from emp where sal > any(select sal from emp
where job='CLERK');
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
13 rows selected.
** Bring out the employees who's salaries is equal any CLERCK salary?
SQL> select * from emp where sal in (select sal from emp where job='CLERK');
** Bring out the employees who's salaries and job are the same as SCOTT?
SQL> select * from emp where sal = (select sal from emp where ename='SCOTT')
and job = (select job from emp where ename='SCOTT');
OR
SQL> select * from emp where (sal,job) = (select sal,job from emp where
ename='SCOTT');
4
5
SQL> select [Link],v.avg_sal from dept d,(select deptno,avg(sal) avg_sal from emp
group by deptno) v where [Link]=[Link];
DNAME AVG_SAL
ACCOUNTING 2916.6667
RESEARCH 2175
SALES 1566.6667
4
6
DML (Data Manipulation Language)
e.g. Change the salary of not null comm. with comm., and comm.
With sal ? SQL> update emp set sal=comm,comm=sal where
comm is not null; Errors :
1. Unique constraint (username,,,,) Violated : When we insert a record with
duplicate primary key
2. If we insert or update foreign key and it is not exist in the attached table.
CASCADE OPTIONS
v2k Cascading of updated or deleted key data via constraints, which has been in
Access and Oracle for some time, has finally arrived in SQL Server 2000. Before this
new functionality, cascading of changes in key data usually had to be performed via
application triggers. While triggers are still going to be around, there will likely be
fewer of them. Consider the following scenario:
The ON UPDATE CASCADE portion of the foreign key definition tells SQL Server to
cascade or "domino" the updates made to the primary key in Parent to the Child
table.
The row in both tables would now be updated from 'Smith' to 'Johnson.' The ON
DELETE NO ACTION clause tells SQL Server to do just that, take no action if a
primary key is deleted from the Parent table. This is the default behavior of SQL
Server. So if you left this clause out of your table/foreign key definitions or kept it in,
4
7
then SQL would raise an error stating something like the following and would not let
you delete the row.
4
8
DELETE FROM Parent WHERE Lname = 'Johnson'
Server: Msg 547, Level 16, State 1, Line 1
DELETE statement conflicted with COLUMN REFERENCE constraint 'fk1'. The conflict
occurred in database 'test', table 'Child', column 'Lname'. The statement has been
terminated. These options can be useful for managing your application's data, but
this functionality is also a double-edged sword. If you were to use both ON DELETE
CASCADE and ON UPDATE CASCADE, you could potentially invalidate all your data
within your database if you started updating or deleting top-level keys.
NOTE : Until now non of the previous statements are really executed, to save the
result we have to write : COMMIT and to not save the result we use ROLLBACK, so
where our work was ?
It was on a logical space (table space) called users ([Link]).
When we use UPDATE statement, the previous values will be saved in ROLLBACK
SEQMENT until we make COMMIT the this segment will be free.
Before we make COMMIT non of the users can see any changes we did on the
database. ORACLE While updating, deleting or inserting will LOCK automatically the
table until the user make COMMIT or ROLLBACK
1. Share Lock : for tables
2. Exclusive Lock : for records under updating
If we write EXIT (normal exit) with out commit or rollback then it will be understood
as commit But in case of Not normal exit it will be understood as rollback.
If we have multi statements like :
SQL> insert ………..
SQL> update
………….
We can save these statement as an indicator to make rollBack step
by step SQL> SavePoint A
another
statements
SQL> SavePoint
4
9
DDL (Data Definition Language)
Note: Any DDL command will make a Commit for all previous written statements and
the DDL command it self.
The table name must be :
1. Maximum length 30 Char.
2. Start with Char.
3. The special char. Allowed (#,$,_)
F1 NUMBER
F2 VARCHAR2(10)
F3 DATE
5
0
Note: The table is an Object for the user saved in data dictionary in capital letter. The
name of Data Dictionary for table is : USER_TABLES
CONSTRAINTS:
1. Primary key :
Not null, Unique (No Duplicate)
Only one PK for a table
We can make composite PK e.g. : PK(f1,f2,,,,)
2. Unique key :
Can be Null
No Duplicate
We can make composite UK
We can have more than one UK in one table
3. Foreign key :
Can be Null
Must be attached to PK or UK
Can’t be attached to composite PK or UK
The constraints in PK or UK must be the same as FK
4. Check key : Just one of two values e.g. : Male or Female
PARENT:
SQL> CREATE TABLE ACC_MST(ACC_NO NUMBER,ACC_NAME
VARCHAR2(20),BALANCE
NUMBER, CONSTRAINT ACC_MST_PK PRIMARY KEY (ACC_NO));
CHILD:
SQL> CREATE TABLE ACC_TRN(TRN_ACC_NO NUMBER,TRN_TYPE
NUMBER(1),AMOUNT
NUMBER, CONSTRAINT ACC_MST_TRN_FK FOREIGN KEY (TRN_ACC_NO)
REFERENCES ACC_MST(ACC_NO));
5
1
Note: We can’t Delete or Modify constraint but we can Add or
Drop only, but we can disable a constraint.
SQL> ALTER TABLE ACC_TRN ADD CONSTRAINT ACC_TRN_CK CHECK (TRN_TYPE IN (-1,1));
SQL> ALTER TABLE ACC_TRN DISABLE CONSTRAINT ACC_MST_TRN_FK;
SQL> DESC ACC_TRN
Name Null? Type
TRN_ACC_NO NUMBER
TRN_TYPE
NUMBER(1)
AMOUNT NUMBER
CONSTRAINT_NAME
CTZN_PK
CTZN_UK
CTZN_CK
C
-
P
U
C
SEARCH_CONDITION
GENDER IN (-1,1)
5
2
SQL> SELECT R_CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME
='CTZN';
5
3
R_CONSTRAINT_NAME
GENDER CTZN_CK
NAT_NO CTZN_PK 1
PASS_NO CTZN_UK 1
GENDER CTZN_CK
NAT_NO CTZN_PK 1
PASS_NO CTZN_UK 1
GENDER CTZN_CK
NAT_NO CTZN_PK 1
PASS_NO CTZN_UK 1
5
4
SQL> SELECT ROWID,DEPTNO,DNAME FROM
DEPT; ROWID DEPTNO DNAME
AAAAe/AACAAAAEgAAA 10 ACCOUNTING
AAAAe/AACAAAAEgAAB 20 RESEARCH
AAAAe/AACAAAAEgAAC 30 SALES
AAAAe/AACAAAAEgAAD 40 OPERATIONS
VARCHAR2(40)
INSTANCES VARCHAR2(40)
5
5
PARTITIONED VARCHAR2(3)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
BUFFER_POOL VARCHAR2(7)
5
6
SQL> SELECT INDEX_NAME,INDEX_TYPE,UNIQUENESS FROM USER_INDEXES;
VIEW:
If we create a View from more than one table, then we can insert on one table only
at a time. And we can end the statement with (WITH READ ONLY).
View created.
V1 doesn't contain any data but it brings data from the original
table SQL> SELECT * FROM V1;
7369 SMITH 20
7499 ALLEN 30
7521 WARD 30
7566 JONES 20
7654 MARTIN 30
7698 BLAKE 30
7782 CLARK 10
7788 SCOTT 20
7839 KING 10
7844 TURNER 30
7876 ADAMS 20
7900 JAMES 30
7902 FORD 20
7934 MILLER 10
8000 ZAGHLOUL 40
15 rows selected.
1 row created.
5
7
SQL> SELECT * FROM EMP WHERE EMPNO = 8888;
8888 SUL 40
View created.
SQL> CREATE OR REPLACE VIEW V2 AS SELECT * FROM EMP WHERE DEPTNO = 10;
View created.
17 rows selected.
5
9
SQL> CREATE OR REPLACE VIEW V2 AS SELECT * FROM EMP WHERE DEPTNO = 10
WITH CHECK OPTION;
View created.
1 row created.
View created.
19 rows selected.
View created.
6
0
SQL> SELECT * FROM V4;
10 2916.666 5
7
20 1895 5
30 1000 7
40 2000 2
OR :
ACCOUNTING 10 5
2916.6667
RESEARCH 20 1895 5
SALES 30 1000 7
OPERATIONS 40 2000 2
TEXT
SQL> DESC
USER_VIEWS;
Name Null? Type
6
1
SEQUENCES: Auto generated
Numbers The Sequence Format :
CREATE SEQUENCE seq_name
START WITH n1 the default is 1
INCREMENT BY n2 the default
is 1 MAXVALUE n3
MINVALUE n4
CYCLE / NOCYCLE After arriving to Max., Back to
biginning CACHE / NOCACHE the default is 20
6
2
7934 MILLER CLERK 7782 23-01-1982 1300 10
14 rows
selected.
6
3
ASSIGN EXPLICIT DEFAULTS IN A TABLE
In Oracle's data definition language (DDL), the Oracle DBA has the ability to assign
default values to any data column. This feature removes the tedium of naming all
of the column values for every INSERT statement.
Create
table
Student
(
student_id number,
student_rank varchar2(3) DEFAULT 'FRESHMAN'
);
When using a default value, the developer would simply omit the
In the above SQL, it's not clear that the default value of 'FRESHMAN' was inserted
into the table.
Starting in Oracle9i, the DEFAULT keyword can be used to explicitly assign the
column's default value during any INSERT or UPDATE statement:
insert into
student
values
('jones', DEFAULT);
update
stude
nt
set
student_rank = DEFAULT
where
student_id = 12345;
Oracle8i:
Select last_name,
department_name From
employees e, departments d
Where e.department_id = d.department_id;
Oracle9i:
6
4
Select last_name,
department_name From
employees e, departments d
USING (department_id);
The ON clause is used to join tables where the column names do not match in both
tables:
6
5
Oracle8i:
Select last_name,
department_name From
employees e, departments d
Where e.department_id =
d.dept_id;
Oracle9i
Select last_name,
department_name From
employees e, departments d ON
(department_id = dept_id);
It's important to note that the old-fashioned Oracle SQL:join syntax continues to be
supported, and that this new enhancement is most important for porting non-Oracle
systems into an Oracle database.
6
6
RENAME A COLUMN WITHIN A TABLE IN ORACLE8i
Last time, we told you that Oracle8i offers a new way to rename a column in an
Oracle table without having to copy the table, which was an update from a recent tip
that focused on Oracle7 and Oracle8 ("Rename a column within an Oracle table," July
11, 2001).
We received several reader requests for the procedure, so here's how you can use
this Oracle8i technique. Starting in Oracle8i, you can use the Add Column and Drop
Column options to rename a column within a table. While the position of the column
within the table moves, the column is effectively renamed with the existing values.
6
7
Here's the output from the script:
SQL> create table temp_don (old_first_column char(20),old_second_column
char(20)); SQL> insert into temp_don values ('string1','string2');
SQL> desc temp_don;
Name Null? Type
OLD_FIRST_COLUMN CHAR(20)
OLD_SECOND_COLUMN
CHAR(20)
OLD_FIRST_COLUMN CHAR(20)
OLD_SECOND_COLUMN
CHAR(20)
NEW_FIRST_COLUMN CHAR(20)
string1 string2
OLD_SECOND_COLUMN
CHAR(20)
NEW_FIRST_COLUMN CHAR(20)
string2 string1
6
8
DCL (Data Control Language )
7
0
SQL> CREATE TABLE YY (N NUMBER);
CREATE TABLE YY (N NUMBER)
*
ERROR at line 1:
ORA-01950: no privileges on tablespace 'SYSTEM'
TYPES OF ROLES:
1. Connect : Privilege to Enter a database
2. Resource : Privilege to deal with a database
3. DBA :
7
1
WHAT IS A BATCH v7.0?
A batch is a set of commands sent to SQL Server as one unit of work. The following
will outline what happens when SQL Server receives a batch. The batch separator is
the GO keyword.
The examples below should assist in this concept. Assume the following table
structure. CREATE TABLE TableX (Col1 INT NOT NULL).
Batch #1
INSERT INTO TableX (Col1) VALUES
(1) INSERT INTO TableX (Col1)
VALUES (2) GO
Batch #2
INSERT INTO TableX (Col1) VALUES
(3) INSERT INTO TableX (Col1) VALU
(4) GO
Batch #3
INSERT INTO TableX (Col1) VALUES (NULL)
INSERT INTO TableX (Col1) VALUES (5)
GO
Upon submitting a batch to SQL, the server takes it as a string of T- SQL commands
and parses the string for syntax. If no syntax error(s) are found, as in Batch #1, then
all of the statement(s) are executed. If a syntax error is found, as in Batch #2, then
none of the statements are executed and SQL Server returns an error to the client.
Note that Batch #3 is syntactically correct but will violate the NOT NULL constraint.
This is still considered a syntax-valid batch so, even though the INSERT NULL
command will fail, the second command is valid and will be executed/inserted into
the table. Values 1, 2, and 5 will be inserted. Note that this behavior applies for
constraint violations. Some run-time errors stop the current statement as well as
subsequent statements within the batch.
The following rules for batches are reprinted from MSDN Books Online:
1. CREATE DEFAULT, CREATE PROCEDURE, CREATE RULE, CREATE TRIGGER, and
CREATE VIEW statements cannot be combined with other statements in a batch.
2. A table cannot be altered and then the new columns referenced in the same
batch.
3. If an EXECUTE statement is the first statement in a batch, the EXECUTE
keyword is not required. The EXECUTE keyword is required if the EXECUTE
statement is not the first statement in the batch.
7
2
Oracle9i'S NEW BUILT-IN FUNCTIONS
Oracle9i is continuing the company's commitment to extending the SQL language by
providing numerous new built-in functions. As you may recall, Oracle started allowing
end users to create their own functions beginning with Oracle8.
A user can take just about any function imaginable and encapsulate and use it
directly inside an Oracle SQL statement. Continuing with Oracle's commitment
toward e-commerce systems, Oracle9i introduces more than 30 different built-in
functions, extending the functionality of all the Oracle SQL to provide a wealth of
business-related functions.
Several of these new functions are built-in datetime functions, which allow worldwide
systems to properly manage times.
The primary purpose of these built-in functions is to translate datetimes for both local
and global processing. For example, in a worldwide e-commerce system, it's
important to understand the local time where the customer placed the order,
especially when the company makes shipping commitments based on the local
processing time. But the centralized headquarters still needs to be able to extract the
dates based on a global time, such as Greenwich Mean Time.
Here are some of the new datetime built-in functions:
CURRENT_DATE
CURRENT_TIMESTAMP
LOCALTIMESTAMP
DBTIMEZONE
SESSIONTIMEZONE
EXTRACT (datetime)
FROM_TZ
TO_TIMESTAMP
TO_TIMESTAMP_TZ
TO_YMINTERVAL
TZ_OFFSET
7
3
7369,SMITH,CLERK,7902,12-JAN-98,800,20
7499,ALLEN,SALESMAN,7698,03-MAR-96,1600,300,30
7521,WARD,SALESMAN,7698,27-APR-97,1250,500,30
7566,JONES,MANAGER,7839,20-OCT-97,2975,,20
7654,MARTIN,SALESMAN,7698,28-SEP-98,1250,1400,30
7698,BLAKE,MANAGER,7839,11-NOV-98,2850,,30
7782,CLARK,MANAGER,7839,29-DEC-97,2450,,10
7788,SCOTT,ANALYST,7566,21-SEP-96,3000,,20
7839,KING,PRESIDENT,,27-MAY-98,5000,,10
7844,TURNER,SALESMAN,7698,24-OCT-98,1500,0,30
7876,ADAMS,CLERK,7788,12-JUN-97,1100,,20
Now, we can issue any SQL against the table. However, there are a couple of
important limitations to external tables: You can't use DML operations, and you
can't create indexes on external tables. Also, external tables have a processing
overhead, and they aren't suitable for large tables.
Prior to Oracle9i, we could only use this index when both sex and emp_id were
present in the SQL query or when the query specified the sex column. The following
query wouldn't be able to use the concatenated index:
7
4
select emp_id from emp where emp_id = 123;
he Oracle9i skip scan execution plan allows for the use of the concatenated index,
even though the SQL query doesn't specify sex. This feature promises that there's
no need to provide a second index on the emp_id column. Oracle acknowledges that
the index skip scan is not as fast as a direct index lookup, but it states that the
index skip scan is faster than a full table scan.
7
5
What Oracle doesn't mention is that the cardinality of the leading column has a direct
impact on the speed of the index skip scan. In our example, the first column, sex, has
only two columns. While Oracle doesn't publish the internals of the index skip scan,
we can infer from the execution plans that Oracle is internally generating multiple
queries, thus satisfying the query with multiple subqueries.
If you wanted something logically reversed, say "if col = 'N/A' then return NULL," you
had to use some kind of DECODE statement:
DECODE(col,'N/A',null,col).
Oracle9i introduces a new SQL function that accomplishes the same thing more
succinctly: NULLIF(col,'N/A'). That is, "if col = 'N/A' then return NULL, otherwise return
the column."
One difference between the NULLIF function and NVL is that NVL is actually
comparing its first argument to NULL and returning the second, so the first and
second arguments can be any datatype. The NULLIF command does a comparison
between its two arguments, so the datatype of its arguments must be compatible.
7
6
COALESCE
Oracle9i also introduces a related function for handling NULL values,called
COALESCE, that can take any number of arguments and return the first expression
in its list that is not NULL--or that is NULL, if all of the expressions evaluate to null.
It's actually an NVL with an unlimited number of arguments.
7
7
COALESCE(col,'N/A') is logically identical to NVL(col,'N/A'). The only way to do a
longer version, such as COALESCE(col1,col2,col3,'N/A'), would e to use
ECODE(col1,null,col2,null,col3,null,'N/A').
COALESCE has a different limitation. It must have at least two arguments, one of
which is not the literal NULL. COALESCE('a') will issue an ORA-938 error, "not
enough arguments for function," but so will COALESCE(NULL,NULL).
Like NULLIF, COALESCE arguments must have compatible datatypes. For example,
COALESCE('A',1) will get an
ORA-932 error, "inconsistent datatypes: expected CHAR got NUMBER."
So all the datatypes in the expression have to be cast to an appropriate datatype:
COALESCE('A',to_char(1)).
The index skip scan is an execution plan in Oracle9i whereby an Oracle query can
bypass the leading edge of a concatenated index and access the inside keys of a
multivalues index. For example, consider the following concatenated index:
create index
sex_emp_id
on
emp (sex, emp_id)
;
Prior to Oracle9i, this index could only be used when both sex and EMP_ID were
present in the SQL query, or when the sex column was specified.
The following query would not be able to use the
emp_id = 123;
The Oracle9i skip scan execution plan allows for the concatenated index to be used,
even though sex is not specified in the SQL query. This feature means that there is
no need to provide a second index on the EMP_ID column. Oracle acknowledges
that the index skip scan is not as fast as a direct index lookup, but states that the
index skip scan is faster than a full-table scan.
What Oracle does not mention is that the cardinality of the leading column has a
direct impact on the speed of the index skip scan. While Oracle does not publish the
internals of the index skip scan, we can infer from the execution plans that Oracle is
internally generating multiple queries, thereby satisfying the query with multiple
subqueries:
7
8
SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=1 Bytes=5)
0 SORT (AGGREGATE)
1 INDEX (SKIP SCAN) OF 'SEX_EMP_ID' (NON-UNIQUE)
Internally, Oracle9i is probably generating two queries and joining the resulting
Row ID lists: select emp_name from emp_where sex = 'F' and emp_id = 123
UNION
select emp_name from emp_where sex = 'M' and emp_id = 123;
Oracle skip scan execution plan performance will decrease according to the number
of unique values in the high order key. If the leading column were "state" with 50
values, Oracle would be issuing 50 index probes to retrieve the result set.
The index skip scan is only useful in shops where disk space savings are critical.
Shops that can afford the disk space to build a second index will always get faster
performance.
svrmgrl
connect
internal
startup
Starting with Oracle9i, the server manager has been removed, and you must now use
server manager commands within the Oracle SQL*Plus product.
Oracle allows you to connect to SQL*Plus with AS SYSDBA or AS SYSOPER
commands. Once connected to the database, the Oracle DBA can startup the
database, shutdown the database, and perform other administrative tasks such as
providing trace files and using the oradebug utility.
In the following examples, you can see how Oracle is used to connect to the database
and issue startup and shutdown commands:
sqlplus /nolog
connect / as
sysdba startup
sqlplus /nolog
connect system/manager as sysdba
oradebug ipc
These commands can also easily be placed inside shell script to perform routine
database functions:
7
9
#!/bin/ksh
8
0
# First, we must set the environment . . . .
ORACLE_SID=mon1
export ORACLE_SID
ORACLE_HOME=`cat /etc/oratab|grep ^$ORACLE_SID:|cut -f2 -
d':'` export ORACLE_HOME
PATH=$ORACLE_HOME/bin:$PATH
export PATH
$ORACLE_HOME/bin/sqlplus /nolog<<!
connect system/manager as
sysdba select * from v\
$database; shutdown
immediate
exit
!
select
substr([Link],1,18) username,
substr([Link],1,15) program,
decode([Link],
0,'No Command',
1,'Create Table',
2,'Insert',
3,'Select',
6,'Update',
7,'Delete',
9,'Create Index',
15,'Alter Table',
21,'Create View',
23,'Validate
Index', 35,'Alter
Database',
39,'Create
Tablespace', 41,'Drop
Tablespace', 40,'Alter
Tablespace', 53,'Drop
8
1
User', 62,'Analyze
Table', 63,'Analyze
Index',
[Link]||': Other') command
8
2
from v$session s, v$process p, v$transaction t, v$rollstat
r, v$rollname n where [Link] = [Link] and
[Link] = [Link] (+)
and [Link] = [Link] (+) and [Link] =
[Link] (+) order by 1;
Here is a sample of the output, showing the individual command for each session:
LIKE clause: SQL> select ksppinm from x$ksppi where ksppinm like
'%_io_%';
KSPPINM
sessions
license_max_sessions
license_sessions_warni
ng
_session_idle_bit_latches
_enable_NUMA_optimizati
on
java_soft_sessionspace_li
mit
java_max_sessionspace_si
8
3
ze
_trace_options
_io_slaves_disabled
dbwr_io_slaves
_lgwr_io_slaves
As you can see above, we didn't get the answer we expected. The SQL displayed all
values that contained "io", and not just those with an underscore.
To remedy this problem, Oracle SQL supports an ESCAPE clause to tell Oracle that
the character is to be interpreted literally:
8
4
SQL> select ksppinm from x$ksppi where ksppinm like '%\_io\_%' ESCAPE'\';
KSPPINM
_io_slaves_disabled
dbwr_io_slaves
_lgwr_io_slaves
_arch_io_slaves
_backup_disk_io_slaves
backup_tape_io_slaves
_backup_io_pool_size
_db_file_direct_io_count
_log_io_size
fast_start_io_target
_hash_multiblock_io_count
_smm_auto_min_io_size
_smm_auto_max_io_size
_ldr_io_size
Select
student_last_name
From student
where student_id =
12345 FOR UPDATE
WAIT 15;
In the real world, many large online systems do not use the FOR UPDATE clause.
Rather, they ensure data integrity by rereading the data when the end user requests
a change. If the data has changed since it was initially displayed to the user, an error
message is displayed.
8
5
COMBINE TABLES WITH THE SQL MERGE STATEMENT
Oracle9i introduces a new SQL statement that is intended to allow you to merge two
tables in a single statement. Rather than write two SQL statements, an UPDATE to
update rows that exist in both tables, and an INSERT to add rows that don't exist in
the merging table, you can now write a single SQL MERGE statement that will do
both.
commit;
select * from inventory;
PART_NO PART_COUNT
1 4
3 6
2 2
The result is that the shipment data has been merged into the inventory data, so
that any shipment that matched something in inventory was added to the count,
while anything that didn't match was added to the inventory.
You must specify both a WHEN MATCHED and WHEN NOT MATCHED statement. If
you have a case for excluding either one of them, you probably should use a
regular INSERT or UPDATE statement.
Another point is that you can't use the MERGE statement to modify a row more
than once, and you can't modify the column being referenced in the ON clause.
The target table of the MERGE statement (which is inventory in the example) must
be a table or view into which the user can INSERT and UPDATE.
The source table (which is shipment in the example) can be from any query table
source, such as external tables or pipelined table functions.
8
6
PERFORM CASE-INSENSITIVE QUERIES WITH FUNCTION-BASED INDEXES
One of the fundamental rules of optimizing an Oracle database is that applying a
function to an index will disable the use of that index, such as in this query:
Internally, the index has stored a B-Tree algorithm to the name in mixed case. It
probably wouldn't be useful to try to scan the index with a function applied to the
value, so access to the index is disabled.
To work around this restriction, many applications would build tables with a mixed-
case column and a forced-uppercase column:
This plan requires storage of every case-insensitive column twice, in addition to the
original column. What is really needed is some way of organizing the index B-Tree so
it stores the uppercase version of the column.
Oracle8 introduced the function-based index to do just that. It stores the result of a
function as the key used by the index to locate rows.
If the same function is being applied to the same column, the optimizer will use the
index to locate the value.
Therefore, you could take the first table and apply a function-based index on the
column:
8
8
GRANT QUERY REWRITE TO <user>;
Also, notice that function-based indexes are only used in cost-based optimizations, so
the table must be analyzed before the index will be used.
8
9
GENERATE HTML REPORTS FROM SQL*PLUS RESULTS
After it's turned on, several characters, such as >, <, and & are automatically
changed to HTML entities. You can disable this feature by adding the option ENTMAP
OFF.
When you issue a query, the results will be generated as an HTML TABLE, TR, and
TD instead of as the usual formatted ASCII output:
If you want to see the results as a preformatted HTML PRE element, use the option
PREFORMAT ON:
SYSDATE
30-MAR-03
</pre>
If you specify SPOOL ON, SQL*Plus will generate headers to the spool file when you
issue the SPOOL command.
9
0
You can change the HEAD tag contents, BODY tag, and TABLE tag attributes in the
output by specifying those tag names as options:
9
1
SQL> set markup html head '<style type="text/css">body
{background: white}</style>' -
>body 'bgcolor="#FFFFFF"' -
>table 'width="100%"
border=0' SQL> select
sysdate from dual;
<br>
<p>
<table width="100%" border=0>
<tr>
<th>
SYSDATE
</th>
</tr>
<tr>
<td>
30-MAR-03
</td>
</tr>
</table>
<p>
With MARKUP HTML ON enabled, the PAGESIZE, LINESIZE, TTITLE, BTITLE, and
COLUMN commands are reflected in the HTML output.
You can enable MARKUP HTML commands and options from the command line, like
this:
REM -- [Link]
select * from emp order by
empno; exit;
Using this method, you can run an old character mode SQL*Plus report and generate
HTML without modifying the script.
9
2
USE @URL AND @@URL IN SQL*PLUS
These parameters are bound to DEFINE parameters after the script is loaded. The
@@[Link] mytablespace will load the script [Link] from the same relative
directory, then mytablespace will be bound to the SQL*Plus parameter &1. One
difference in the @URL functionality is that the .sql extension is not optional.
9
3
SIMULATING @URL IN ORACLE8i
One drawback to this feature is that it doesn't seem to support HTTP proxy. Scripts
must be loaded from direct connections. One workaround for access via a proxy or
simulating this functionality in Oracle8i is this script:
REM --
http_at.sql set
feedback off set
linesize 255
set serveroutput on size
64000 set trimspool on
spool
[Link]
declare
l_pieces
utl_http.html_pieces;
l_piece varchar2(2000);
l_url varchar2(2048) :=
'&1'; l_maxline integer :=
255; l_index integer;
l_stub varchar2(255);
l_proxy varchar2(2048) :=
'[Link]'; begin
l_pieces :=
utl_http.request_pieces(l_url,1000,l_proxy); for i
in l_pieces.first .. l_pieces.last loop
l_piece := l_pieces(i);
while length(l_piece) > l_maxline
loop l_stub :=
substr(l_piece,1,l_maxline);
l_index := length(l_stub);
while l_index > 0 and substr(l_stub,l_index,1) != chr(10)
loo
p l_index := l_index
- 1; end loop;
l_stub :=
substr(l_piece,1,l_index-1);
l_piece :=
substr(l_piece,l_index+1);
dbms_output.put_line(l_stub);
end loop;
dbms_output.put_line(l_piece);
end
loop; end;
/
spool off;
9
4
data: sqlplus scott/tiger
@http_at
[Link]
@test
9
5