Vous êtes sur la page 1sur 19

EBS Sql Tuning Guidelines Application Services

EBS Sql Tuning Guidelines

Sudhakar.G - Apps DBA


Ravi Chander .K - DBA

Page 1
EBS Sql Tuning Guidelines Application Services

1. INTRODUCTION.........................................................................................................................................3
1.1 INTENT....................................................................................................................................................3
1.2 AUDIENCE...............................................................................................................................................3
2. OVERVIEW................................................................................................................................................3
2.1 PHYSICAL I/O.........................................................................................................................................3
2.2 DISK SORT..............................................................................................................................................4
2.3 RECURSIVE CALLS..................................................................................................................................4
3 PERFORMANCE TUNING.............................................................................................................................4
3.1 INDEX SUPPRESSION...............................................................................................................................4
3.2 COMPARING WRONG DATA TYPES..........................................................................................................5
3.3 FUNCTION-BASED INDEXES....................................................................................................................6
Creating the Function-based Index:.........................................................................................................6
3.4 USING THE ‘MINUS’ OPERATOR................................................................................................................7
3.5 USING THE ‘UNION’ OPERATOR................................................................................................................8
3.6 USING THE ‘ROWNUM’........................................................................................................................8
3.7 TRY TO AVOID ‘OR’ IF POSSIBLE............................................................................................................8
3.8 DEALING WITH INEQUALITIES................................................................................................................9
3.9 NESTED SUBQUERIES............................................................................................................................10
3.10 JOIN METHODS...................................................................................................................................12
3.10.1 NESTED LOOPS JOINS......................................................................................................................12
3.10.2 SORT-MERGE JOINS.........................................................................................................................12
3.10.3 CLUSTER JOINS................................................................................................................................13
3.10.4 HASH JOINS.....................................................................................................................................13
3.11 REDUCING SQL PARSING IN RECURSIVE PROCEDURES.....................................................................14
3.12 TRY TO MINIMIZE THE DISK SORTS.....................................................................................................16
4. RULES TO KEEP IN MIND.........................................................................................................................16
4.1 WATCH INDEXED WHERE CONDITIONS..............................................................................................16
4.2 WATCH NON-INDEXED WHERE CONDITIONS.....................................................................................17
4.3 CONSIDER IN OR UNION IN PLACE OF OR.........................................................................................18
4.4 WEIGH JOIN VERSUS EXISTS SUB-QUERY........................................................................................19
4.5 CONSIDER EXISTS IN PLACE OF DISTINCT.......................................................................................19
4.6 CONSIDER NOT EXISTS IN PLACE OF NOT IN..................................................................................19
4.8 ORDERING VIA THE WHERE CLAUSE.................................................................................................20
4.9 Use PL/SQL to reduce network traffic.................................................................................................20

Page 2
EBS Sql Tuning Guidelines Application Services

1. Introduction

1.1 Intent

This document is intended to help the developers to write efficient code during the development stage. Some of
the sqls have been presented with the corresponding elapsed times. These statistics are based on the
experiment results that were carried out in TCS offshore performance-engineering laboratory.

1.2 Audience

The intended readers of this document are:


 Developers

2. Overview

2.1 Physical I/O

In general to tune a query we need to optimize the query execution path so that it utilizes system resources
efficiently and gets back the data with minimum Physical I/O.

2.2 Disk Sort

Oracle database automatically performs sorting operations on row data as requested by any of the following
operations

 CREATE INDEX, ALTER INDEX ... REBUILD


 DISTINCT
 ORDER BY
 GROUP BY
 UNION
 INTERSECT
 MINUS
 IN, NOT IN
 Aggregation functions (MAX, MIN, AVG, SUM)
 Certain unindexed joins

Sorts that can’t fit into the sort_area_size will be paged out into the TEMP tablespaces for a disk sort. Disk sorts
are about 14,000 times slower than the memory sorts.

2.3 Recursive Calls

Recursive call occurs when one SQL statement requires the execution of a further separate SQL statement.

Recursive calls can be generated by any or all of the following activities

 An object requiring an additional extent for storage (dynamic extension)


 Misses on the dictionary cache
 Firing of database triggers

Page 3
EBS Sql Tuning Guidelines Application Services

 DDL statements
 Execution of SQL statements within stored procedures, packages, functions, and anonymous PL/SQL
blocks
 Enforcement of referential integrity constraints

3 Performance Tuning
The below are some of the common methods to minimize the quantity of above discussed(Physical I/O,
Recursive Calls, disk sorts) in the oracle database and there by improve the performance of the system

3.1 Index Suppression

Any function that modifies the column name in a WHERE clause will suppress the corresponding index. Many

common functions that are used to suppress a standard index are

NOT / IS NULL / != or <>

Comparing a number field to a character field

Any modification to the Indexed Column Name

(TO_CHAR, TO_DATE, +0, || '', SUBSTR, DECODE...)

Suppression Example; despite the intended hint to use the index, the SUBSTR function will suppress the index

on the EMP_ID column below:

select /*+ index(customer custidx) */ EMP_ID, ZIP_CODE


from EMPLOYEE
where SUBSTR(EMP_ID,1,4) = '2502';
Execution Time - 225 seconds

The SUBSTR function was re-written with a LIKE instead and part of the index is used and the performance is

substantially increased:

select EMP_ID, ZIP_CODE


from EMPLOYEE
where EMP_ID LIKE '2502%';
Execution Time - 5 seconds

Page 4
EBS Sql Tuning Guidelines Application Services

3.2 Comparing wrong data types

If you compare the wrong data types, your index may be suppressed internally. This is because Oracle will re-

write the query so that the comparison is correct. This problem is at times difficult to track down.

Comparing Characters to Numbers:

where char_data = 123


could be rewritten to:

where To_Number(char_data) = 123

Comparing Numbers to Characters:

where num_data = ‘123’


could be rewritten lik:e

where To_Char(num_data) = ‘123’

Tip: Comparing mismatched data types could cause an internal index suppression that is difficult to track down.

Oracle will often place a function on the column that fixes the mismatch, but suppresses the index.

3.3 Function-based Indexes

Function-based indexes allow you to create an index based on a function or expression. Function-based indexes

can involve multiple columns, arithmetic expressions or may be a PL/SQL function or C callout. The following

example shows an example of a function based index.

Creating the Function-based Index:

CREATE INDEX emp_idx ON emp (UPPER(ename));

An index has been created on the ename column when the UPPER function is used on this column.

Query the emp table using the Function-based Index:

Page 5
EBS Sql Tuning Guidelines Application Services

select ename, job, deptno


from emp
where upper(ename) = ‘ELLISON’;

The function-based index (emp_idx) can be used for the query above. For large tables where the condition

retrieves a small amount of records, the query yields substantial performance gains over a full table scan.

To comprehend the advantages of function-based indexes consider the following queries.

We run the query, executing a full table scan.


select count(*)
from sample
where ratio(balance,limit) >.5;

Elapse time: 20.1 minutes

We create a functional index.

create index ration_idx on sample ( ratio(balance, limit));

We re-run the query using the function-based index.

select count(*)
from sample
where ratio(balance,limit) >.5;

Elapse time: 7 seconds!!!

Note that the function RATIO simply divides argument 1 by argument 2.

3.4 using the ‘minus’ operator

The MINUS operator, for example, can be much faster than using WHERE NOT EXISTS or WHERE NOT IN
(SELECT). Following is an example of the power of the MINUS operator versus the NOT IN construct. First, the
NOT IN approach:

SELECT customer_id
FROM customers
WHERE area_code IN (402, 310)
AND zip_code NOT IN (68116, 68106);

Even if we have indexes on both the AREA_CODE and ZIP_CODE columns, the NOT IN predicate, to eliminate
two zip codes from the result set, will necessitate a full table scan. On the other hand:

SELECT customer_id
FROM customers
WHERE area_code IN (402, 310)

Page 6
EBS Sql Tuning Guidelines Application Services

MINUS
(SELECT customer_id
FROM customers
WHERE zip_code IN (68116, 68106);

3.5 using the ‘union’ operator

The UNION operator, which is standard SQL and not peculiar to Oracle, is also a potential shortcut, especially
for a self-join with two noncontiguous index range values.

Following is an example of the UNION operator retrieving two noncontiguous result sets in a similar business
situation:

SELECT customer_id
FROM customer
WHERE area_code IN (402, 310)
UNION
SELECT customer_id
FROM customers
WHERE zip_code IN (31326, 31327);

Bear in mind that this only helps if the AREA_CODE and ZIP_CODE columns are left-most in the indexes.

3.6 Using the ‘ROWNUM’

Take advantage of ROWNUM. ROWNUM is a special pseudo-column that exists for every result set. It is quite
useful for limiting a potential runaway query and avoiding application grief. It refers to the relative row for a given
query, before any ORDER BY clause is applied. This is important to understand. If your statement looks like:

SELECT COUNT(*)
FROM customers
WHERE ROWNUM < 100

Oracle will select and return the first 99 rows and the query will halt. If you have a name search on a large table,
selecting WHERE NAME LIKE S% could easily return 100,000 rows or more. Rather than forcing your users to
logically qualify the query, you can add this row-limit qualifier to end the search when the upper limit is reached:

SELECT name, address, city


FROM customers
WHERE name LIKE 'S%' AND ROWNUM < 1000
will return no more than 999 rows. More important, the query will return when the upper limit is reached, before

executing any sorts. This is a wonderful saving grace that you should use more often.

3.7 Try to avoid ‘OR’ if possible

Placing indexes on statements having an OR clause and multiple WHERE conditions can be difficult. While in

previous versions it was essential to index at least one column in each clause OR’ed together, the merging of

indexes in the later versions of Oracle (V8+) becomes hazardous to the performance. Experiment with

Page 7
EBS Sql Tuning Guidelines Application Services

potentially suppression all indexes except the most limiting (retrieves the least amount of rows). Consider the

following examples:

Given: Indexes on EMPNO, ENAME and DEPTNO

select ENAME,DEPTNO,CITY,DIVISION
from EMP1
where EMPNO = 1
or ENAME = 'LONEY'
or DEPTNO = 10;
Execution Time: 4400 Seconds

Execution Plan:
TABLE ACCESS EMP1 FULL

The Solution:

SELECT /*+ INDEX(EMP EMP11) */


ENAME, DEPTNO, CITY, DIVISION
FROM EMP1
WHERE EMPNO = 1
OR ENAME = 'LONEY'
OR DEPTNO = 10;
Execution Time: 280 Seconds

Execution Plan:
TABLE ACCESS EMP1 ROWID
TABLE ACCESS EMP11 INDEX RS

3.8 Dealing with Inequalities

The cost-based optimizer tends to have problems with inequalities. Since Oracle records the high and low value

for a column and assumes a linear distribution of data, problems occur when an inequality is used on a table with

a non-linear distribution of data. This can be solved by overriding the optimizer or by using histograms

Given:

Page 8
EBS Sql Tuning Guidelines Application Services

The ORDER_LINE Table has 10,000 rows between 1 and 10,000

There are 5000 records (half the table) with an item number > 9990

There is an index on item_no

The Optimizer chooses to use the index, since it believes there are only 10 rows to be retrieved:

SELECT SIZE, ITEM_NO


FROM ORDER_LINE
WHERE ITEM_NO > 9990;

Execution Time: 530 Seconds

The data and half the table will be retrieved by the query, and then we must suppress the index and substantially

increase performance. We suppress the index (and override the optimizer) since the query retrieves 50% of the

table (which is much more than the 5% or less rule for using the index)!

SELECT /*+ FULL(ORDER_LINE) */ SIZE, ITEM_NO


FROM ORDER_LINE
WHERE ITEM_NO > 9990;

Execution Time: 5 Seconds

Tip: Strongly consider using hints to override the optimizer when using the “<“ and “>“ when the distribution of

data is not linear between the high & low values of a column. Histograms may also be employed.

3.9 Nested Subqueries

Using nested sub queries instead of joining tables in a single query can lead to dramatic performance gains.

Only certain queries will meet the criteria for making this modification. When you find the right one, this trick will

take performance improvement to an exponentially better height. The conditions for changing a query to a

nested sub query occur when:

Tables are being joined to return the rows from ONLY one table.

Conditions from each table will lead to a reasonable percentage of the rows to be retrieved (more than 10%)

Page 9
EBS Sql Tuning Guidelines Application Services

The original query:

SELECT A.COL1, A.COL2


FROM TABLE1 A, TABLE2 B
WHERE A.COL3 = VAR
AND A.COL4 = B.COL1
AND B.COL2 = VAR;

The new query:

SELECT A.COL1, A.COL2


FROM TABLE1 A
WHERE A.COL3 = VAR
AND EXISTS
(SELECT ‘X’
FROM TABLE B
WHERE A.COL4 = B.COL1
AND B.COL2 = VAR);

A real life example:

SELECT ORDER.ORDNO, ORDER.CUSTNO


FROM ORDER_LINE OL, ORDER
WHERE ORDER.ORDNO = OL.ORDNO
AND ORDER.CUSTNO = 5
AND OL.PRICE = 200;

Execution Time: 240 Minutes

The solution:

SELECT ORDNO, CUSTNO


FROM ORDER
WHERE CUSTNO = 5
AND EXISTS
(SELECT ‘X’
FROM ORDER_LINE OL
WHERE ORDER.ORDNO = OL.ORDNO

Page 10
EBS Sql Tuning Guidelines Application Services

AND OL.PRICE = 200);

Execution Time: 9 Seconds

3.10 Join Methods

The following are the various ways to join row sources together.

3.10.1 Nested Loops Joins

In a nested loops join, Oracle reads the first row from the first row source and then checks the second row

source for matches. All matches are then placed in the result set and Oracle goes on to the next row from the

first row source. This continues until all rows in the first row source have been processed. The first row source is

often called the outer table or driving table, while the second row source is called the inner table. This is one of

the fastest methods of receiving the first records back from a join.

Nested loops joins are ideal when the driving row source (the records that you’re looking for) is small and the

joined columns of the inner row source are uniquely indexed or have a highly selective non-unique index. Nested

loops joins have an advantage over other join methods in that they can quickly retrieve the first few rows of the

result set without having to wait for the entire result set to be determined.

3.10.2 Sort-Merge Joins

In a sort-merge join, Oracle sorts the first row source by its join columns, sorts the second row source by its join

columns, and then “merges” the sorted row sources together. As matches are found, they are put into the result

set.

Sort-merge joins can be effective when lack of data selectivity or useful indexes render a nested loops join

inefficient, or when both of the row sources are quite large (greater than 5% of the records). However, sort-

merge joins can only be used for equijoins (WHERE D.deptno = E.deptno, as opposed to WHERE D.deptno >=

E.deptno). Also, sort-merge joins require temporary segments for sorting (if SORT_AREA_SIZE is set too small).

This can lead to extra memory utilization and/or extra disk I/O in the temporary tablespace.

3.10.3 Cluster Joins

A cluster join is really just a special case of the nested loops join. If the two row sources being joined are actually

tables that are part of a cluster and if the join is an equijoin between the cluster keys of the two tables, then

Oracle can use a cluster join. In this case, Oracle reads each row from the first row source and finds all matches

in the second row source by using the cluster index.

Page 11
EBS Sql Tuning Guidelines Application Services

Cluster joins are extremely efficient, since the joining rows in the two row sources will actually be located in the

same physical data block. However, clusters carry certain caveats of their own, and you can’t have a cluster join

without a cluster. Therefore, cluster joins are not very commonly used.

3.10.4 Hash Joins

In a hash join, Oracle reads all of the join column values from the second row source, builds a hash table (in

memory if HASH_AREA_SIZE is large enough), and then probes the hash table for each of the join column

values from the first row source. This is like a nested loops join, except that first Oracle builds a hash table to

facilitate the operation. When using an ORDERED hint, the first table in the FROM clause is the driving table,

but only after the second table is loaded in the hash table. The first table then accesses the hash table for

matches. If enough memory is available (HASH_AREA_SIZE for the hash and DB_BLOCK_BUFFERS for the

other table) then the join will be completely be processed in memory.

Hash joins can be effective when the lack of a useful index renders nested loops joins inefficient. The hash join

might be faster than a sort-merge join in this case because only one row source needs to be sorted, and could

possibly be faster than a nested loops join because probing a hash table in memory can be faster than traversing

a B-tree index.

3.11 Reducing SQL Parsing in Recursive Procedures

Reduce the parse-to-execution ratio in your applications.

Description: Extensive SQL parsing can become a serious problem for a heavily loaded Oracle instance. This is
especially true if a SQL statement executed many times is also parsed many times. There are a number of
standard techniques and guidelines, which help reduce unnecessary parsing. In some special cases, though,
even following all the guidelines does not save you from extensive parsing. Find out below how to apply a
workaround in a specific situation to further reduce the parse-to-execute ratio of a statement.

The effect can be observed when a SQL cursor is used in a recursively-structured procedure. In such
procedures, very often a cursor is opened and for each fetched row the same procedure is called, which opens
the same cursor, etc. In most of the cases the recursive call is executed before the cursor is closed. As a result
of this, for each new "cursor open" a parse call is executed resulting in as many parses as executions.

Take a look at a simplified recursive procedure using the SCOTT schema:

PROCEDURE recurs (p_mgr IN emp.mgr%TYPE)


IS
CURSOR emp_mgr IS

Page 12
EBS Sql Tuning Guidelines Application Services

SELECT empno
FROM emp
WHERE mgr = p_mgr;

BEGIN
FOR c IN emp_mgr
LOOP
recurs(c.empno);
END LOOP;
END recurs;

As you can see the recursive call is executed before the (implicit) cursor is closed. The main idea for reducing
the parse calls is to first collect the results of the cursor (for example in a PL/SQL table), then close the cursor
and finally cycle through the results and perform the recursive procedure calls.

See below and example of such procedure (In this procedure I have used a bulk bind select, but a normal cursor
loop can be used too):

PROCEDURE recurs_close (p_mgr IN emp.mgr%TYPE)


IS
CURSOR emp_mgr IS
SELECT empno
FROM emp
WHERE mgr = p_mgr;
TYPE t_empno IS TABLE OF NUMBER(4) INDEX BY BINARY_INTEGER;
p_empno t_empno;
i PLS_INTEGER := 0;
BEGIN

OPEN emp_mgr;
FETCH emp_mgr BULK COLLECT INTO p_empno;
i := emp_mgr%ROWCOUNT;
CLOSE emp_mgr;
FOR j IN 1..i
LOOP
recurs_close(p_empno(j));
END LOOP;
END recurs_close;

In the excerpts of the trace files generated during the procedure execution can be seen that the first procedure
has as many parses as executions (14), while the second has 1 parse only.

exec cursor_parse.recurs(7839);

SELECT empno
FROM emp
WHERE mgr = :b1

call count cpu elapsed disk query current rows


------- ------ ----- ---------- ------- ---------- ---------- ----------
Parse 14 0.02 0.15 0 0 00

Page 13
EBS Sql Tuning Guidelines Application Services

Execute 14 0.00 0.00 0 0 00


Fetch 27 0.00 0.05 1 26 28 13
------- ------ ----- ---------- ------- ---------- ---------- ----------
total 55 0.02 0.20 1 26 28 13

exec cursor_parse.recurs_close(7839);

SELECT empno
FROM emp
WHERE mgr = :b1

call count cpu elapsed disk query current rows


------- ----- ---- ------- ---- ----- ------- --------
Parse 1 0.00 0.00 0 0 00
Execute 14 0.00 0.00 0 0 00
Fetch 14 0.00 0.00 0 14 28 13
------- ----- ---- ------- ----- ------ -------- --------
total 29 0.00 0.00 0 14 28 13

Most of the important statistics are better for the execution of the recurs_close than the recurs procedure.

Statistic name recurs recurs_close


opened cursors cumulative 26 12
recursive calls 89 50
session logical reads 84 72
consistent gets 41 29
no work - consistent read gets 32 20
cursor authentications 2 1
parse count (total) 26 12

3.12 Try to minimize the disk sorts

A sort operation can become problematic if it requires disk I/O for it to complete. The memory space
that can be used to perform a sort operation is controlled by the system parameter SORT_AREA_SIZE
and PGA_AGGREGATE_TARGET. If the sort is too large to be contained in the space determined by
the above parameters, oracle will continue the sort on disk. This is where performance problems can
begin to develop.
The below is the short list of some of the most commonly used SQL commands that can cause sorts

 CREATE INDEX, ALTER INDEX ... REBUILD


 DISTINCT
 ORDER BY
 GROUP BY
 UNION
 INTERSECT
 MINUS

Page 14
EBS Sql Tuning Guidelines Application Services

 IN, NOT IN
 Aggregation functions (MAX, MIN, AVG, SUM)
 Certain unindexed joins
 Certain correlated subqueries

Since disk sort involves both physical reads and physical writes, try to avoid using distinct, order by, group by,
union, intersect, minus and some aggregate functions if the application permits.

4. Rules to keep in mind

4.1 Watch Indexed WHERE Conditions

Assume index on address (city, state)

Non-leading index column references cannot use indexes

Where state = 'TX' [Index Not used]

Where city = 'DALLAS' [Index Used]

Where state = 'TX' and city = 'DALLAS' [Index Used]

NOT, != and <> disable index use

Where state not in ('TX', 'FL','OH') [Index Not used]

Where state! = 'TX' [Index Not used]

NULL value references can never use indexes

Where state IS NULL [Index Not used]

Where state IS NOT NULL [Index Not used]

Expression references can never use indexes

Where substr(city,1,3) = 'DAL' [Index Not used]

Where city like 'DAL%' [Index Used]

Where city || state = 'DALLASTX' [Index Not used]

Where city = 'DALLAS' and state = 'TX‘ [Index Used]

Where salary * 12 >= 24000 [Index Not used]

Where salary >= 2000 [Index Used]

Page 15
EBS Sql Tuning Guidelines Application Services

4.2 Watch Non-Indexed WHERE Conditions

Oracle evaluates Non-Indexed conditions linked by AND bottom up

Bad: select * from address where

areacode = 972 and

type_nr = (select seq_nr from code_table where type = ‘HOME’)

Good: select * from address where

type_nr = (select seq_nr from code_table where type = ‘HOME’) and

areacode = 972

Oracle evaluates Non-Indexed conditions linked by OR top down

Bad: select * from address where

type_nr = (select seq_nr from code_table where type = ‘HOME’) or

areacode = 972

Good: select * from address where

areacode = 972 or

type_nr = (select seq_nr from code_table where type = ‘HOME’)

4.3 Consider IN or UNION in place of OR

if columns are not indexed, stick with OR

if columns are indexed, use IN or UNION in place of OR

IN example

Bad: select * from address where

state = 'TX‘ or

state = 'FL‘ or

state = 'OH‘

Good: select * from address where

Page 16
EBS Sql Tuning Guidelines Application Services

state in ('TX','FL','OH')

UNION example

Bad: select * from address where

state = ‘TX’ or

areacode = 972

Good: select * from address where

state = ‘TX’

union

select * from address where

areacode = 972

4.4 Weigh JOIN versus EXISTS Sub-Query

use table JOIN instead of EXISTS sub-query

when the percentage of rows returned from the outer sub-query is high

select e.name, e.phone, e.mailstop

from employee e, department d

where e.deptno = d.deptno

and d.status = ‘ACTIVE’

use EXISTS sub-query instead of table JOIN

when the percentage of rows returned from the outer sub-query is low

select e.name, e.phone, e.mailstop

from employee e

where e.deptno in (select d.deptno

from department d

where d.status != ‘ACTIVE’)

Page 17
EBS Sql Tuning Guidelines Application Services

4.5 Consider EXISTS in place of DISTINCT

avoid joins that use DISTINCT, use EXISTS sub-query instead


Bad: select distinct deptno, deptname from emp, dept where

emp.deptno = dept.deptno

Good: select deptno, deptname from dept where

exists (select ‘X’ from emp where

emp.deptno = dept.deptno)
Note – only has to find one match

4.6 Consider NOT EXISTS in place of NOT IN

avoid sub-queries that use NOT IN, use NOT EXISTS instead

Bad: select * from emp where

deptno not in (select deptno from dept where

deptstatus = ‘A’)

Good: select * from emp where

not exists (select ‘X’ from dept where

deptstatus = ‘A’ and

dept.deptno = emp.deptno)

Note – only has to find one non-match

4.8 Ordering Via the WHERE Clause

a dummy WHERE clause referencing an indexed column will retrieve all records in ascending order not perform
a costly sort operation

Bad: select * from address

Page 18
EBS Sql Tuning Guidelines Application Services

order by city
Good: select * from address where city > ‘’

4.9 Use PL/SQL to reduce network traffic

Utilize PL/SQL to group related SQL commands and thereby reduce network traffic

Bad:

select city_name, state_code

into :v_city, :v_sate

from zip_codes where zip_code = ‘75022’;

insert into customer (‘Bert Scalzo’,’75022’, :v_city, v_state);

Good:

begin

select city_name, state_code

into :v_city, :v_sate

from zip_codes where zip_code = ‘75022’;

insert into customer (‘Bert Scalzo’,’75022’, :v_city, v_state);

end;

Page 19

Vous aimerez peut-être aussi