Archive for the ‘数据库技术’ Category.

先Oracle DB再Oracle Dev套件,ORACLE_HOME会被覆盖

今天碰到了一个oracle数据库实例连接的问题。
我的一个数据库实例安装成功很久了(当初是可以连接的),之后很久没有连本地的oracle数据库实例。
今天一连数据库实例发现连不上,报:ORA-12560: TNS:protocol adapter error 的错。
查了下DBConsole和service两个服务都正常启动。

最后查明原因,是我在安装数据库之后,又安装的Oracle开发套件,而安装Oracle开发套件时也会在相应的注册表项中创建一个全新的oracle_home变量,这个变量会成为新的默认home项。
先Oracle DB再Oracle Dev套件,ORACLE_HOME会被覆盖
所以造成,你通过sqlplus去连得时候,它检查的是这个新的oracle_home下的tnsnames.ora,所以报了那个错

解决方法1:
在新的oracle_home目录下tnsnames.ora中添加你的tns,然后
C:\> set oracle_sid=<DB name>
e.g C:\> set oracle_sid=<rajesh>
C:\> sqlplus /nolog {press enter}
sql:\>connect sys as sysdba {press enter}
password : sys {press enter}
sql:\> connected
或者
解决方法2:
对于这种问题(即安装Oracle DB也安装Oracle Dev套件的),只要在系统的我的电脑->环境变量里边明确指定了ORACLE_HOME,ORACLE_SID,就没有问题了
ORACLE_HOME=D:\oracle\product\10.1.0\Db_1
ORACLE_SID=test

Updating with Values from Another Table

Problem

You wish to update rows in one table using values from another. For example, you have a table called NEW_SAL, which holds the new salaries for certain employees. The contents of table NEW_SAL are:

select *

from new_sal

DEPTNO        SAL

—— ———-

10       4000

Column DEPTNO is the primary key of table NEW_SAL. You want to update the salaries and commission of certain employees in table EMP using values table NEW_SAL if there is a match between EMP.DEPTNO and NEW_SAL.DEPTNO, update EMP.SAL to NEW_SAL.SAL, and update EMP.COMM to 50% of NEW_SAL.SAL. The rows in EMP are as follows:

select deptno,ename,sal,comm

from emp

order by 1

DEPTNO ENAME             SAL       COMM

—— ———- ———- ———-

10 CLARK           2450

10 KING            5000

10 MILLER          1300

20 SMITH            800

20 ADAMS           1100

20 FORD            3000

20 SCOTT           3000

20 JONES           2975

30 ALLEN           1600         300

30 BLAKE           2850

30 MARTIN          1250        1400

30 JAMES            950

30 TURNER          1500           0

30 WARD            1250         500

Solution

Use a join between NEW_SAL and EMP to find and return the new COMM values to the UPDATE statement. It is quite common for updates such as this one to be performed via correlated subquery. Another technique involves creating a view (traditional or inline, depending on what your database supports), then updating that view.

DB2 and MySQL

Use a correlated subquery to set new SAL and COMM values in EMP. Also use a correlated subquery to identify which rows from EMP should be updated:

1 update emp e set (e.sal,e.comm) = (select ns.sal, ns.sal/2

2                                      from new_sal ns

3                                     where ns.deptno=e.deptno)

4  where exists ( select null

5                   from new_sal ns

6
where ns.deptno = e.deptno )

Oracle

The method for the DB2 solution will certainly work for Oracle, but as an alternative, you can update an inline view:

1 update (

2  select e.sal as emp_sal, e.comm as emp_comm,

3         ns.sal as ns_sal, ns.sal/2 as ns_comm

4    from emp e, new_sal ns

5   where e.deptno = ns.deptno

6 ) set emp_sal = ns_sal, emp_comm = ns_comm

PostgreSQL

The method used for the DB2 solution will work for PostgreSQL, but as an alternative you can (quite conveniently) join directly in the UPDATE statement:

1 update emp

2    set sal = ns.sal,

3        comm = ns.sal/2

4   from new_sal ns

5  where ns.deptno = emp.deptno

SQL Server

The method used for the DB2 solution will work for SQL Server, but as an alternative you can (similarly to the PostgreSQL solution) join directly in the UPDATE statement:

1 update e

2    set e.sal  = ns.sal,

3        e.comm = ns.sal/2

4   from emp e,

5        new_sal ns

6  where ns.deptno = e.deptno

Discussion

Before discussing the different solutions, I’d like to mention something important regarding updates that use queries to supply new values. A WHERE clause in the subquery of a correlated update is not the same as the WHERE clause of the table being updated. If you look at the UPDATE statement in the “Problem” section, the join on DEPTNO between EMP and NEW_SAL is done and returns rows to the SET clause of the UPDATE statement. For employees in DEPTNO 10, valid values are returned because there is a match DEPTNO in table NEW_SAL. But what about employees in the other departments? NEW_SAL does not have any other departments, so the SAL and COMM for employees in DEPTNOs 20 and 30 are set to NULL. Unless you are doing so via LIMIT or TOP or whatever mechanism your vendor supplies for limiting the number of rows returned in a result set, the only way to restrict rows from a table in SQL is to use a WHERE clause. To correctly perform this UPDATE, use a WHERE clause on the table being updated along with a WHERE clause in the correlated subquery.

DB2 and MySQL

To ensure you do not update every row in table EMP, remember to include a correlated subquery in the WHERE clause of the UPDATE. Performing the join (the correlated subquery) in the SET clause is not enough. By using a WHERE clause in the UPDATE, you ensure that only rows in EMP that match on DEPTNO to table NEW_SAL are updated. This holds true for all RDBMSs.

Oracle

In the Oracle solution using the update join view, you are using equi-joins to determine which rows will be updated. You can confirm which rows are being updated by executing the query independently. To be able to successfully use this type of UPDATE, you must first understand the concept of key-preservation. The DEPTNO column of the table NEW_SAL is the primary key of that table, thus its values are unique within the table. When joining between EMP and NEW_SAL, however, NEW_SAL.DEPTNO is not unique in the result set, as can be seen below:

select e.empno, e.deptno e_dept, ns.sal, ns.deptno ns_deptno

from emp e, new_sal ns

where e.deptno = ns.deptno

EMPNO     E_DEPT        SAL  NS_DEPTNO

—– ———- ———- ———-

7782         10       4000         10

7839         10       4000         10

7934         10       4000         10

To enable Oracle to update this join, one of the tables must be key-preserved, meaning that if its values are not unique in the r
esult set, it should at least be unique in the table it comes from. In this case NEW_SAL has a primary key on DEPTNO, which makes it unique in the table. Because it is unique in its table, it may appear multiple times in the result set and will still be considered key-preserved, thus allowing the update to complete successfully.

PostgreSQL and SQL Server

The syntax is a bit different between these two platforms, but the technique is the same. Being able to join directly in the UPDATE statement is extremely convenient. Since you specify which table to update (the table listed after the UPDATE keyword) there’s no confusion as to which table’s rows are modified. Additionally, because you are using joins in the update (since there is an explicit WHERE clause), you can avoid some of the pitfalls when coding correlated subquery updates; in particular, if you missed a join here, it would be very obvious you’d have a problem.

Inline view(内联视图)

Copy from: http://www.orafaq.com/wiki/Inline_view

An inline view is a SELECT statement in the FROM-clause of another SELECT statement. In-line views are commonly used simplify complex queries by removing join operations and condensing several separate queries into a single query. This feature was introduced in Oracle 7.2.

This feature is commonly referred to in the MSSQL community as a derived table, and in the Postgres community simply refers to it as a subselect (subselects are inline views + subqueries in Oracle nomenclature).

Examples

Example inline view:

SELECT *

FROM (select deptno, count(*) emp_count

from emp

group by deptno) emp,

dept

WHERE dept.deptno = emp.depto;

Another good example of an inline view is:

SELECT a.last_name, a.salary, a.department_id, b.maxsal
  FROM employees a,
       (SELECT department_id, max(salary)maxsal
          FROM employees
      GROUP BY department_id) b
 WHERE a.department_id = b.department_id
   AND a.salary < b.maxsal;

The above query display the employees who earn the highest salary in each department.

v$sql summary

<< V$SQL>>

Copy from http://download.oracle.com/docs/cd/B19306_01/server.102/b14237/dynviews_2113.htm

V$SQL lists statistics on shared SQL area without the GROUP BY clause and contains one row for each child of the original SQL text entered. Statistics displayed in V$SQL are normally updated at the end of query execution. However, for long running queries, they are updated every 5 seconds. This makes it easy to see the impact of long running SQL statements while they are still in progress.

——————-

<>

Copy from http://www.ss64.com/orav/V$SQL.html

Information about Sql processes running now.

–Examples

Select

substr(sql_text,0,80),

decode(command_type,2,‘INSERT’),

executions

From V$SQL

Where command_type = 2

Order By executions;

Select

substr(sql_text,0,80),

decode(command_type,3,‘SELECT’),

executions

From V$SQL

Where command_type = 3

Order By executions;

/*

List of command_type values with meaning:

Insert 2

Select 3

Update 6

Delete 7

Lock Table 26

Alter Database 35

Alter Session 42

Commit 44

Rollback 45

Savepoint 46

Begin/Declare 47

*/

PS:EXECUTIONS:Number of executions that took place on this object since it was brought into the library cache

——————-

<>

Copy from http://www.oracle-training.cc/oracle_tips_v$sql.htm

Whenever your database is experiencing a performance problem, it is very useful to have a script that displays all of the currently executing SQL statements. The following script joins the v$sql and v$session tables to show you all of the SQL that is executing at that moment in your database.

set pagesize 24

set newpage 1

set linesize 125

column sql_text  format a100

column user_name format a12

SELECT
an lang=”EN-US” style=”font-family:Courier;color:black;background:white;mso-highlight: white”>   u.sid, SUBSTR (u.username, 1, 12) user_name, s.sql_text

FROM v$sql s, v$session u

WHERE s.hash_value = u.sql_hash_value

AND sql_text NOT LIKE ‘%from v$sql s, v$session u%’

ORDER BY u.sid;

——————-

<>

Copy from http://www.dba-oracle.com/concepts/query_active_users_v%24session.htm

Once we figure out who is on the system, we will probably want to know what they are doing. In this case, we will join the v$session view we just queried with another view, the V$SQL view. The V$SQL view will provide us with the SQL that is being executed on our system. Let’s see GRUMPY’s session details:

SQL> select a.sid, a.serial#, b.sql_text

2  from v$session a, v$sqlarea b

3  where a.sql_address=b.address

4  and a.username=’GRUMPY’;

SID    SERIAL# SQL_TEXT

———- ———- ———————————————-

122      61521 select count(*) from gen_person where gen_person_id=95000

——————-

<>

Copy from http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:385254862843

You Asked

<
p class=”MsoNormal”>What is the diff between:

v$sql

v$sqlarea

v$sqltext

v$sqltext_with_newlines

when I query v$sql joining with v$session and filter by a SID I get more than one SQL

(expected) but if I join v$sqltext with v$session with same conditions I get one sql

statement only (last SQL issued) why is this?

Thanks

Alan

and we said…

v$sql the details — if you have multiple copies of the query:

“select * from T”

in your shared pool, v$sql will have a row per query.  This can happen if user U1 and

user U2 both have a table T and both issue “select * from T”.  Those are entirely

different queries with different plans and so on.  v$sql will have 2 rows.

v$sqlarea is a aggregate of v$sql.  It selects out DISTINCT sql.  “select * from T” will

appear there.

It is not clear to me how you are joing v$session to v$sql to get more then one row.  If

you wish to see the queries a session has open (maybe open, we cache cursors so you might

see some queries that are closed) use v$open_cursor by sid.

v$sqltext is simply a way to see the entire query.  the v$sql and v$sqlarea views only

show the first 1000 bytes.  newlines and other control characters are replace with

whitespace.

v$sqltext_with_newlines is v$sqltext without the whitespace replacment.

——————-

Some Definition

Copy from http://articles.techrepublic.com.com/5100-10878_11-6164425.html

V$SQL: This view gives you the full text of the SQL statement in a character large object (CLOB) column, plus the first 1,000 characters of it in a convenient VARCHAR2 column. The statistics available are extensive: number of parses and invalidations, disk reads and writes, execution times, wait times, and optimizer data. You can also tell the user and schema that created the statement, and how many users are currently executing it.

V$SQLAREA: This view contains many of the same statistics as V$SQL. However, V$SQL contains one row for each child of an original SQL statement, whereas this view contains only one row for each SQL string entered.

V$SQLSTATS: New in 10gR2, this view is faster and more convenient than V$SQL and V$SQLAREA; however, it contains only a subset of the other views’ columns. In particular, it does not link to user information. There is one row for each combination of SQL and execution plan hash value. As a bonus, the entries in this view may persist longer than the other views. You may find a statement here even after it has aged out of the shared pool (and, therefore, it disappears from V$SQLAREA).

V$SQLTEXT: There are times that you want each line of a SQL statement separately, instead of one big object as in V$SQL; V$SQLTEXT gives you this. The COMMAND_TYPE column is a code you can use to select certain statement types (i.e., only INSERT or SELECT.) The SQL_TEXT column has one piece of the text, and the PIECE column numbers them for sorting via ORDER BY. A variant, V$SQLTEXT_WITH_NEWLINES, keeps the original linefeeds to improve readability (V$SQLTEXT replaces them with spaces). Neither V$SQLTEXT nor V$SQLTEXT_WITH_NEWLINES tells you who executed the statement or provides you with any statistics. To get that information, you’ll have to join back to V$SQL or V$SQLAREA using the ADDRESS and HASH_VALUE columns.

Sequences

Create Single Use Sequences

Use each sequence to supply unique ID values for one column of one table.

Do Not Limit the Range of Your Sequences

Do not create sequences that wrap using the CYCLE option or that have a specified MAXVALUE. The total range of sequences is so great that the upper limits realistically are never encountered.

In general, do not design sequences that wrap or have limited ranges.

Use Number Datatypes to Store Sequence Values

Use a NUMBER datatype to store sequence values within PL/SQL.

If you need to handle a sequence generate a sequence value in your C code, do not assume that a sequence–generated value will fit inside a C long variable. The maximum value for an ascending sequence is 10^27,whereas the maximum value for a C signed long integer is 10^9. If 10^9 is not a reasonable limit for your sequence, you may use a double instead of a long integer. Remember that by using a double for your sequence, you may lose some precision on fractional values. If you do not need to do arithmetic, and simply need to fetch your sequence either to print it or store it back, consider retrieving your sequence in a character string.

Database Server Side versus Client Side

Performance is a critical aspect of any application. Because network round trips are very costly in a typical client–server environment,minimizing the number of round trips is key to ensuring good performance.

You should decide whether your PL/SQL procedures reside on the server or on the client based on whichever results in the fewest number of network round trips. Here are some guidelines:

*Procedures that call Oracle Forms built–ins (more generally,client built–ins) must reside on the client.

*Procedures that reference fields directly, either as :block.field or via NAME_IN/COPY, must reside on the client. You can avoid referencing fields directly by accepting field values or names as parameters to your PL/SQL procedures, which also improves your code’s modularity.

*If a procedure contains three or more SQL statements, or becomes very complicated, the procedure usually belongs on the server.

*Procedures that perform no SQL and that need no database access should reside wherever they are needed.

If a procedure is called from the server, it must reside on the server. If a procedure is called from both client and server, it should be defined in both places, unless the procedure is very complicated and double maintenance is too costly. In the latter case, the procedure should reside on the server.

[转]数据库主键设计之思考

主键的必要性:

有些朋友可能不提倡数据库表必须要主键,但在我的思考中,觉得每个表都应该具有主键,不管是单主键还是双主键,主键的存在就代表着表结构的完整性,表的记录必须得有唯一区分的字段,主键主要是用于其他表的外键关联,本记录的修改与删除,当我们没有主键时,这些操作会变的非常麻烦。

主键的无意义性:

我强调主键不应该具有实际的意义,这可能对于一些朋友来说不太认同,比如订单表吧,会有”订单编号”字段,而这个字段呢在业务实际中本身就是应该具有唯一性,具有唯一标识记录的功能,但我是不推荐采用订单编号字段作为主键的,因为具有实际意义的字段,具有”意义更改”的可能性,比如订单编号在刚开始的时候我们一切顺利,后来客户说”订单可以作废,并重新生成订单,而且订单号要保持原订单号一致”,这样原来的主键就面临危险了。因此,具有唯一性的实际字段也代表可以作为主键。因此,我推荐是新设一个字段专门用为主键,此主键本身在业务逻辑上不体现,不具有实际意义。而这种主键在一定程序增加了复杂度,所以要视实际系统的规模大小而定,对于小项目,以后扩展不会很大的话,也查允许用实际唯一的字段作主键的。

主键的选择

我们现在在思考一下,应该采用什么来作表的主键比较合理,申明一下,主键的设计没有一个定论,各人有各人的方法,哪怕同一个,在不同的项目中,也会采用不同的主键设计原则。

第一:编号作主键

此方法就是采用实际业务中的唯一字段的”编号”作为主键设计,这在小型的项目中是推荐这样做的,因为这可以使项目比较简单化,但在使用中却可能带来一些麻烦,比如要进行”编号修改”时,可能要涉及到很多相关联的其他表,就象黎叔说的”后果很严重”;还有就是上面提到的”业务要求允许编号重复时 “,我们再那么先知,都无法知道业务将会修改成什么?

第二:自动编号主键

这种方法也是很多朋友在使用的,就是新建一个ID字段,自动增长,非常方便也满足主键的原则,优点是:数据库自动编号,速度快,而且是增量增长,聚集型主键按顺序存放,对于检索非常有利;数字型的,占用空间小,易排序,在程序中传递也方便;如果通过非系统增加记录(比如手动录入,或是用其他工具直接在表里插入新记录,或老系统数据导入)时,非常方便,不用担心主键重复问题。

缺点:其实缺点也就是来自其优点,就是因为自动增长,在手动要插入指定ID的记录时会显得麻烦,尤其是当系统与其他系统集成时,需要数据导入时,很难保证原系统的ID不发生主键冲突(前提是老系统也是数字型的);如果其他系统主键不是数字型那就麻烦更大了,会导致修改主键数据类型了,这也会导致其他相关表的修改,后果同样很严重;就算其他系统也是数字型的,在导入时,为了区分新老数据,可能想在老数据主键前统一加一个”o”(old)来表示这是老数据,那么自动增长的数字型又面临一个挑战。

第三:Max加一

由于自动编号存在那些问题,所以有些朋友就采用自己生成,同样是数字型的,只是把自动增长去掉了,采用在Insert时,读取Max值后加一,这种方法可以避免自动编号的问题,但也存在一个效率问题,如果记录非常大的话,那么Max()也会影响效率的;更严重的是并发性问题,如果同时有两人读到相同的Max后,加一后插入的 ID值会重复,这已经是有经验教训的了。

第四:自制加一

考虑Max加一的效率后,有人采用自制加一,也就是建一个特别的表,字段为:表名,当前序列值。这样在往表中插入值时,先从此表中找到相应表的最大值后加一,进行插入,有人可能发现,也可能会存在并发处理,这个并发处理,我们可以采用lock线程的方式来避免,在生成此值的时,先Lock,取到值以后,再unLock出来,这样不会有两人同时生成了。这比Max加一的速度要快多了。但同样存在一个问题:在与其他系统集成时,脱离了系统中的生成方法后,很麻烦保证自制表中的最大值与导入后的保持一致,而且数字型都存在上面讲到的”o”老数据的导入问题。因此在”自制加一”中可以把主键设为字符型的。字符型的自制加一我倒是蛮推荐的,应该字符型主键可以应付很多我们意想不到的情况。

第五:GUID主键

目前一个比较好的主键是采用GUID,当然我是推荐主键还是字符型的,但值由GUID生成,GUID是可以自动生成,也可以程序生成,而且键值不可能重复,可以解决系统集成问题,几个系统的GUID值导到一起时,也不会发生重复,就算有”o”老数据也可以区分,而且效率很高,在。NET里可以直接使用 System.Guid.NewGuid()进行生成,在SQL里也可以使用 NewID()生成。

优点是:

同 IDENTITY 列相比,uniqueidentifier 列可以通过 NewID() 函数提前得知新增加的行 ID,为应用程序的后续处理提供了很大方便。

便于数据库移植,其它数据库中并不一定具有 IDENTITY 列,而 Guid 列可以作为字符型列转换到其它数据库中,同时将应用程序中产生的 GUID 值存入数据库,它不会对原有数据带来影响。

便于数据库初始化,如果应用程序要加载一些初始数据, IDENTITY 列的处理方式就比较麻烦,而 uniqueidentifier 列则无需任何处理,直接用 T-SQL 加载即可。

便于对某些对象或常量进行永久标识,如类的 ClassID,对象的实例标识,UDDI 中的联系人、服务接口、tModel标识定义等。

缺点是:

GUID 值较长,不容易记忆和输入,而且这个值是随机、无顺序的。

GUID 的值有 16 个字节,与其它那些诸如 4 字节的整数相比要相对大一些。这意味着如果在数据库中使用 uniqueidentifier 键,可能会带来两方面的消极影响:存储空间增大;索引时间较慢。

我也不是推荐GUID最好,其实在不同的情况,我们都可以采用上面的某一种方式,思考了一些利与弊,也方便大家在进行设计时参考。这些也只是我的一点思考而已,而且可能我知识面限制,会有一些误论在里面,希望大

PL/SQL Versions

PL/SQL Versions

Version/Release

Characteristics

Version 1.0

First available in SQL*Plus as a batch-processing script. Oracle Version 6.0 was released at approximately the same time. PL/SQL was then implemented within SQL*Forms Version 3, the predecessor of Oracle Forms.

Release 1.1

Available only in the Oracle Developer/2000 Release 1 tools. This upgrade supports client-side packages and allows client-side programs to execute stored code transparently.

Version 2.0

Available with Release 7.0 (Oracle Server). Major upgrade to Version 1. Adds support for stored procedures, functions, packages, programmer-defined records, PL/SQL tables, and many package extensions, including DBMS_OUTPUT and DBMS_PIPE.

Release 2.1

Available with Release 7.1 of the Oracle Server Version. Supports programmer-defined subtypes, enables the use of stored functions inside SQL statements, and offers dynamic SQL with the DBMS_SQL package. With Version 2.1, you can now execute SQL DDL statements from within PL/SQL programs.

Release 2.2

Available with Release 7.2 of the Oracle Server Version. Implements a binary “wrapper” for PL/SQL programs to protect source code, supports cursor variables for embedded PL/SQL environments such as Pro*C, and makes available database-driven job scheduling with the DBMS_JOB package.

Release 2.3

Available with Release 7.3 of the Oracle Server Version. Enhances functionality of PL/SQL tables, offers improved remote dependency management, adds file I/O capabilities to PL/SQL, and completes the implementation of cursor variables.

Version 8.0

Available with Oracle8 Release 8.0. The drastic change in version number reflects Oracle’s effort to synchronize version numbers across related products. PL/SQL8 is the version of PL/SQL which supports the many enhancements of Oracle8, including large objects (LOBs), object-oriented design and development, collections (VARRAYs and nested tables), and Oracle/AQ (the Oracle/Advanced Queueing facility).

PL/SQL的两种应用模式

服务器端的P L / S Q L
从O r a c l e 6 . 0版开始,P L / S Q L就驻留在数据库服务器端,同时,该服务器也是P L / S Q L引擎的默认位置。由于数据库服务器可以处理S Q L语句,所以S Q L语句和P L / S Q L块都可以送到该服务器进行处理。一个客户应用,不管是用O r a c l e开发工具实现的或使用其他开发工具编制的,都可以向数据库服务器提交S Q L语句和P L / S Q L块。SQL *Plus就是一个这种客户应用的案例,该程序可以在S Q L提示符下接收交互输入的S Q L语句和P L / S Q L命令并将其送往服务器执行。例如,我们可以假设在SQL *Plus与服务器建立了连接的情况下输入下列的SQL,P L / S Q L命令:
SQL_PLSQL.sql
SQL> CREATE OR REPLACE PROCEDURE ServerProcedure AS
2 BEGIN
3 NULL;
4 END ServerProcedure;
5 /
Procedure created.
SQL> DECLARE
2 v_StudentRecord students%ROWTYPE;
3 v_Counter BINARY_INTEGER;
4 BEGIN
5 v_Counter := 7;
6
7 SELECT *
8 INTO v_StudentRecord
9 FROM students
10 WHERE id = 10001;
11
12 ServerProcedure;
13
14 END;
15 /
PL/SQL procedure successfully completed.
SQL> UPDATE classes
2 SET max_students = 70
3 WHERE department = ‘HIS’
4 AND course = 101;
1 row updated.

图1演示了在服务器端的P L / S Q L引擎对P L / S Q L块的处理过程。客户应用可以向服务器提
交P L / S Q L块(该块可以带有过程和包括调用服务器端存储过程的S Q L语句),以及单独的S Q L语句。如图所示, P L / S Q L块和S Q L语句通过网络送往服务器。一旦服务器收到了这些内容, S Q L语句将直接进入服务器内含的S Q L语句执行器,而P L / S Q L块则送往P L / S Q L引擎进行语法分析。在该块的运行期间, P L / S Q L引擎负责执行过程语句(如赋值语句和存储过程调用)。对于该块中出现的S Q L语句(如S E L E C T语句等),P L / S Q L引擎将它们送往S Q L语句执行器执行。

客户端的P L / S Q L
除了在服务器端的P L / S Q L引擎外,几种O r a c l e开发工具也带有P L / S Q L引擎。由于这些开发工具是运行在客户端的,所以它们的P L / S Q L引擎也可以运行在客户端。这样一来,借助于客户端的P L / S Q L支持,P L / S Q L块中的过程语句就可以在本地运行,而没有必要送到服务器端。例如开发工具Oracle Forms(该工具是Oracle Developer的一部分)自身带有P L / S Q L引擎;在O r a c l e D e v e l o p e r工具包中,如Oracle Reports也带有P L / S Q L引擎。需要指出的是这种引擎与P L / S Q L服务器端的引擎有所不同。P L / S Q L块只能出现在客户端应用中,并且该块必须用开发工具来编制。
假设一个Oracle Forms应用包括了触发器和过程,这些语句都在客户端执行。只有该程序中的S Q L语句和调用服务器端存储子程序的语句被送往服务器进行处理。如图2 所示,客户端的P L / S Q L引擎可以处理过程语句。

与服务器端的P L / S Q L一样,应用程序提交的单独的S Q L语句(如U P D AT E语句)直接通过网络送往服务器端的S Q L语句执行器。不同的是, P L / S Q L块是在客户端直接处理。任何过程语句(如赋值语句)的处理都不会引起网络传输。P L / S Q L块中的S Q L语句要提交给S Q L语句执行器,对服务器端的存储子程序的调用则是送到服务器端的P L / S Q L引擎执行。

再补一图:

Because PL/SQL is used both in the database (for stored procedures and database triggers) and in the application code (to implement logic within a form, for example), you can leverage the same programming language for both client-side and server-side development. You can even move programs from one component of the configuration to another.For example, you might decide that a function which was originally coded for a single screen could be shared by all of the modules in an application. To make this happen, you simply move that function from the client-side screen component to the server-side database environment. You have to change neither the PL/SQL code nor any of the programs that call that function.