2000年7月25日星期二

Tomcat ユーザ認証

■BASIC 認証

実行環境
JDK 5.0
eclipse 3.2
Tomcat 5.5
Windows XP

J2EE Webアプリケーションでは、安全なアプリケーション設計を行うため、任意のページにセキュリティ制約条件をつけて安全性を高めることができます。
セキュリティ制約条件がつけられたページにアクセスがあった場合、パスワードによるログイン認証を行うことができます。
ログイン認証には、BASIC 認証、DIGEST 認証、FORM 認証、CLIENT-CERT 認証があります。

◆BASIC 認証 : 最も一般的な認証方式。ユーザー名とパスワードをクリアテキストでサーバーに送信する。(パスワードは Base64 エンコード)
◆DIGEST 認証 : パスワードを暗号化して送信する。
◆FORM 認証 : ログインページなどをHTML形式でカスタマイズできる。ユーザー名とパスワードをクリアテキストでサーバーに送信する。
◆CLIENT-CERT 認証 : HTTPS(HTTP over SSL)を使用した認証システム。

ここでは、BASIC 認証を用いて、「secure」フォルダ以下のファイルにセキュリティ制約条件をつけた例をレポート。コンテナは Tomcat を使用し、eclipse + tomcatPlugin を使用して作成します。

ディレクトリ構成は下記のようになります。


web.xml に security-constraint タグと login-config タグを下記のように追加記述します。


security-constraint の子要素



Tomcat 5.5\conf にある tomcat-users.xml を編集します。ここでは、新しいロール名「test」、ユーザー名「test」、パスワード「test」を下記のように定義します。パスワードは仮のものですので、適切に変更してください。


http://localhost:8080/SrvSample/secure/menu.html にアクセスしてみます。


ユーザー名とパスワードを入力して「OK」を押すと menu.html にアクセスできます。


■FORM 認証

実行環境
JDK 5.0
eclipse 3.2
Tomcat 5.5
Windows XP

FORM 認証のは BASIC 認証とよく似ています。FORM 認証では、ログインフォームをHTML形式でカスタマイズできます。また、ログインに失敗した場合に転送するエラーページもカスタマイズできます。

ここでは、ログインページを login.html、エラーページを error.html とし、前の BASIC 認証を FORM 認証に書き換えてみます。

ディレクトリ構成は下記のようになります。


BASIC 認証で記述した web.xml の login-config タグの部分を下記のように書き換えます。


login.html を記述します。送信先は「j_security_check」、ユーザー名は「j_username」、パスワードは「j_password」と設定します。これはユーザー名とパスワードが「j_security_check」という予約された場所に送られることを意味しています。変更することはできません。


Tomcat を再起動して、http://localhost:8080/SrvSample/secure/menu.html にアクセス。


■JDBCRealm にる認証

実行環境
JDK 5.0
Tomcat 5.5
MySQL 5.0
Windows XP

BASIC 認証や FORM 認証は、Tomcat のデフォルトの UserDatabaseRealm で行います。UserDatabaseRealm では、ユーザー名、パスワード、ロール名を tomcat-users.xml から読み込んで使用しますが、ユーザーが多数になると管理が困難になるでしょう。
JDBCRealm を使うとデータベースにユーザー名、パスワード、ロール名を登録して管理することができます。ユーザー数の拡大に対応しやすくなるでしょう。

☆server.xml の設定

JDBCRealm 方式を使用するには Tomcat の server.xml Engine タグ内の150行目あたりを下記のように書き換えます。ここではデータベースに MySQL を使用し、データベース名「authority」、データベースユーザー名「authority」、パスワード「authority」と設定します。


☆データベースの設定

MySQL にデータベース名「authority」、ユーザー名「authority」、パスワード「authority」を設定します。

SQL文
grant all privileges on authority.* to authority@localhost identified by 'authority';
flush privileges;
create database authority;

「users」テーブルと「user_roles」テーブルを設定します。
ユーザー名「test」、パスワード「test」、ロール名「test」を登録します。
JDBCRealm 方式に切り替えると、tomcat-users.xml にデフォルトで記述してある「tomcat」、「admin」などのユーザー名とロール名もデータベースに登録し直す必要があります。


設定はこれで完了です。

2000年7月23日星期日

C/S和B/S

一、什么是C/S和B/S

要想对“C/S”和“B/S”技术发展变化有所了解,首先必须搞清楚三个问题。

第一、什么是C/S结构。

C/S (Client/Server)结构,即大家熟知的客户机和服务器结构。它是软件系统体系结构,通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统的通讯开销。目前大多数应用软件系统都是Client/Server形式的两层结构,由于现在的软件应用系统正在向分布式的Web应用发展,Web和Client/Server 应用都可以进行同样的业务处理,应用不同的模块共享逻辑组件;因此,内部的和外部的用户都可以访问新的和现有的应用系统,通过现有应用系统中的逻辑可以扩展出新的应用系统。这也就是目前应用系统的发展方向。

传统的C/S体系结构虽然采用的是开放模式,但这只是系统开发一级的开放性,在特定的应用中无论是Client端还是Server端都还需要特定的软件支持。由于没能提供用户真正期望的开放环境,C/S结构的软件需要针对不同的操作系统系统开发不同版本的软件,加之产品的更新换代十分快,已经很难适应百台电脑以上局域网用户同时使用。而且代价高, 效率低。

第二、什么是B/S结构。

B/S(Browser/Server)结构即浏览器和服务器结构。它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO)。

以目前的技术看,局域网建立B/S结构的网络应用,并通过Internet/Intranet模式下数据库应用,相对易于把握、成本也是较低的。它是一次性到位的开发,能实现不同的人员,从不同的地点,以不同的接入方式(比如LAN, WAN, Internet/Intranet等)访问和操作共同的数据库;它能有效地保护数据平台和管理访问权限,服务器数据库也很安全 。特别是在JAVA这样的跨平台语言出现之后,B/S架构管理软件更是方便、快捷、高效。

第三、管理软件主流技术。

管理软件技术的主流技术与管理思想一样,也经历了三个发展时期。首先,界面技术从上世纪DOS字符界面到Windows图形界面(或图形用户界面GUI),直至Browser浏览器界面三个不同的发展时期。其次,今天所有电脑的浏览器界面,不仅直观和易于使用,更主要的是基于浏览器平台的任何应用软件其风格都是一样的,使用人对操作培训的要求不高,而且软件可操作性强,易于识别;再者,平台体系结构也从过去单用户发展到今天的文件/服务器(F/S)体系、客户机/服务器(C/S)体系和浏览器/服务器(B/S)体系。

二、C/S和B/S 之比较

C/S和B/S是当今世界开发模式技术架构的两大主流技术。C/S是美国 Borland公司最早研发,B/S是美国微软公司研发。目前,这两项技术以被世界各国所掌握,国内公司以C/S和B/S技术开发出产品也很多。这两种技术都有自己一定的市场份额和客户群,各家企业都说自己的管理软件架构技术功能强大、先进、方便,都能举出各自的客户群体,都有一大群文人墨客为自己摇旗呐喊,广告满天飞,可谓仁者见仁,智者见智。

1、C/S架构软件的优势与劣势

(1)、应用服务器运行数据负荷较轻。

最简单的C/S体系结构的数据库应用由两部分组成,即客户应用程序和数据库服务器程序。二者可分别称为前台程序与后台程序。运行数据库服务器程序的机器,也称为应用服务器。一旦服务器程序被启动,就随时等待响应客户程序发来的请求;客户应用程序运行在用户自己的电脑上,对应于数据库服务器,可称为客户电脑,当需要对数据库中的数据进行任何操作时,客户程序就自动地寻找服务器程序,并向其发出请求,服务器程序根据预定的规则作出应答,送回结果,应用服务器运行数据负荷较轻。

(2)、数据的储存管理功能较为透明。

在数据库应用中,数据的储存管理功能,是由服务器程序和客户应用程序分别独立进行的,前台应用可以违反的规则,并且通常把那些不同的(不管是已知还是未知的)运行数据,在服务器程序中不集中实现,例如访问者的权限,编号可以重复、必须有客户才能建立定单这样的规则。所有这些,对于工作在前台程序上的最终用户,是“透明”的,他们无须过问(通常也无法干涉)背后的过程,就可以完成自己的一切工作。在客户服务器架构的应用中,前台程序不是非常“瘦小”,麻烦的事情都交给了服务器和网络。在C/S体系的下,数据库不能真正成为公共、专业化的仓库,它受到独立的专门管理。

(3)、C/S架构的劣势是高昂的维护成本且投资大。

首先,采用C/S架构,要选择适当的数据库平台来实现数据库数据的真正“统一”,使分布于两地的数据同步完全交由数据库系统去管理,但逻辑上两地的操作者要直接访问同一个数据库才能有效实现,有这样一些问题,如果需要建立“实时”的数据同步,就必须在两地间建立实时的通讯连接,保持两地的数据库服务器在线运行,网络管理工作人员既要对服务器维护管理,又要对客户端维护和管理,这需要高昂的投资和复杂的技术支持,维护成本很高,维护任务量大。

其次,传统的C/S结构的软件需要针对不同的操作系统系统开发不同版本的软件,由于产品的更新换代十分快,代价高和低效率已经不适应工作需要。在JAVA这样的跨平台语言出现之后,B/S架构更是猛烈冲击C/S,并对其形成威胁和挑战。

2、B/S架构软件的优势与劣势

(1)、维护和升级方式简单。

目前,软件系统的改进和升级越来越频繁,B/S架构的产品明显体现着更为方便的特性。对一个稍微大一点单位来说,系统管理人员如果需要在几百甚至上千部电脑之间来回奔跑,效率和工作量是可想而知的,但B/S架构的软件只需要管理服务器就行了,所有的客户端只是浏览器,根本不需要做任何的维护。无论用户的规模有多大,有多少分支机构都不会增加任何维护升级的工作量,所有的操作只需要针对服务器进行;如果是异地,只需要把服务器连接专网即可,实现远程维护、升级和共享。所以客户机越来越“瘦”,而服务器越来越“胖”是将来信息化发展的主流方向。今后,软件升级和维护会越来越容易,而使用起来会越来越简单,这对用户人力、物力、时间、费用的节省是显而易见的,惊人的。因此,维护和升级革命的方式是“瘦”客户机,“胖”服务器。

(2)、成本降低,选择更多。

大家都知道windows在桌面电脑上几乎一统天下,浏览器成为了标准配置,但在服务器操作系统上windows并不是处于绝对的统治地位。现在的趋势是凡使用B/S架构的应用管理软件,只需安装在Linux服务器上即可,而且安全性高。所以服务器操作系统的选择是很多的,不管选用那种操作系统都可以让大部分人使用windows作为桌面操作系统电脑不受影响,这就使的最流行免费的Linux操作系统快速发展起来,Linux除了操作系统是免费的以外,连数据库也是免费的,这种选择非常盛行。

比如说很多人每天上“网易”(原文为新浪)网,只要安装了浏览器就可以了,并不需要了解“网易”的服务器用的是什么操作系统,而事实上大部分网站确实没有使用windows操作系统,但用户的电脑本身安装的大部分是windows操作系统。

(3)、应用服务器运行数据负荷较重。

由于B/S架构管理软件只安装在服务器端(Server)上,网络管理人员只需要管理服务器就行了,用户界面主要事务逻辑在服务器(Server)端完全通过WWW浏览器实现,极少部分事务逻辑在前端(Browser)实现,所有的客户端只有浏览器,网络管理人员只需要做硬件维护。但是,应用服务器运行数据负荷较重,一旦发生服务器“崩溃”等问题,后果不堪设想。因此,许多单位都备有数据库存储服务器,以防万一。

3,C/S 与 B/S 区别

Client/Server是建立在局域网的基础上的,Browser/Server是建立在广域网的基础上的。

(1)、硬件环境不同:

C/S 一般建立在专用的网络上, 小范围里的网络环境, 局域网之间再通过专门服务器提供连接和数据交换服务。

B/S 建立在广域网之上的, 不必是专门的网络硬件环境,例如电话上网,租用设备, 信息自己管理, 有比C/S更强的适应范围, 一般只要有操作系统和浏览器就行。

(2)、对安全要求不同

C/S 一般面向相对固定的用户群, 对信息安全的控制能力很强。一般高度机密的信息系统采用C/S 结构适宜,可以通过B/S发布部分可公开信息。

B/S 建立在广域网之上, 对安全的控制能力相对弱, 面向是不可知的用户群。

(3)、对程序架构不同

C/S 程序可以更加注重流程,可以对权限多层次校验,对系统运行速度可以较少考虑。

B/S 对安全以及访问速度的多重的考虑, 建立在需要更加优化的基础之上。 比C/S有更高的要求,B/S结构的程序架构是发展的趋势,从MS的.Net系列的BizTalk 2000 Exchange 2000等,全面支持网络的构件搭建的系统。SUN和IBM推的JavaBean构件技术等,使B/S更加成熟。

(4)、软件重用不同

C/S 程序可以不可避免的整体性考虑, 构件的重用性不如在B/S要求下的构件的重用性好。

B/S 对的多重结构,要求构件相对独立的功能。 能够相对较好的重用。就如买来的餐桌可以再利用,而不是做在墙上的石头桌子。

(5)、系统维护不同

系统维护是软件生存周期中,开销大,相当重要

C/S 程序由于整体性,必须整体考察,处理出现的问题以及系统升级难,可能是再做一个全新的系统。

B/S 构件组成方面构件个别的更换,实现系统的无缝升级。系统维护开销减到最小,用户从网上自己下载安装就可以实现升级。

(6)、处理问题不同

C/S 程序可以处理用户面固定,并且在相同区域, 安全要求高的需求,与操作系统相关,应该都是相同的系统。

B/S 建立在广域网上, 面向不同的用户群,分散地域, 这是C/S无法作到的,与操作系统平台关系最小。

(7)、用户接口不同

C/S 多是建立在Window平台上,表现方法有限,对程序员普遍要求较高。

B/S 建立在浏览器上, 有更加丰富和生动的表现方式与用户交流, 并且大部分难度减低,降低开发成本。

(8)、信息流不同

C/S 程序一般是典型的中央集权的机械式处理,交互性相对低。

B/S 信息流向可变化, B-B、 B-C、 B-G等信息流向的变化, 更象交易中心

一、C/S结构与B/S结构的特点分析

随着计算机技术的不断发展与应用,计算模式从集中式转向了分布式,尤为典型的是C/S结构(Client/Server的简称,客户机/服务器模式)。两层结构C/S模式,在上个世纪八十年代及九十年代初得到了大量应用,最直接的原因是可视化开发工具的推广。之后,它开始向三层结构发展。近年来,随着网络技术不断发展,尤其是基于Web的信息发布和检索技术、Java计算技术以及网络分布式对象技术的飞速发展,导致了很多应用系统的体系结构从C/S结构向更加灵活的多级分布结构演变,使得软件系统的网络体系结构跨入一个新阶段,即B/S体系结构(Browser/Server的简称,浏览器/服务器模式)。基于Web的B/S方式其实也是一种客户机/服务器方式,只不过它的客户端是浏览器。为了区别于传统的C/S模式,才特意将其称为B/S模式。认识到这些结构的特征,对于系统的选型而言是很关键的。

1、系统的性能

在系统的性能方面,B/S占有优势的是其异地浏览和信息采集的灵活性。任何时间、任何地点、任何系统,只要可以使用浏览器上网,就可以使用B/S系统的终端。

不过,采用B/S结构,客户端只能完成浏览、查询、数据输入等简单功能,绝大部分工作由服务器承担,这使得服务器的负担很重。采用C/S结构时,客户端和服务器端都能够处理任务,这虽然对客户机的要求较高,但因此可以减轻服务器的压力。而且,由于客户端使用浏览器,使得网上发布的信息必须是以HTML格式为主,其它格式文件多半是以附件的形式存放。而HTML格式文件(也就是Web页面)不便于编辑修改,给文件管理带来了许多不便。

2、系统的开发

C/S结构是建立在中间件产品基础之上的,要求应用开发者自己去处理事务管理、消息队列、数据的复制和同步、通信安全等系统级的问题。这对应用开发者提出了较高的要求,而且迫使应用开发者投入很多精力来解决应用程序以外的问题。这使得应用程序的维护、移植和互操作变得复杂。如果客户端是在不同的操作系统上,C/S结构的软件需要开发不同版本的客户端软件。

但是,与B/S结构相比,C/S技术发展历史更为“悠久”。从技术成熟度及软件设计、开发人员的掌握水平来看,C/S技术应是更成熟、更可靠的。

3、系统的升级维护

C/S系统的各部分模块中有一部分改变,就要关联到其它模块的变动,使系统升级成本比较大。B/S与C/S处理模式相比,则大大简化了客户端,只要客户端机器能上网就可以。对于B/S而言,开发、维护等几乎所有工作也都集中在服务器端,当企业对网络应用进行升级时,只需更新服务器端的软件就可以,这减轻了异地用户系统维护与升级的成本。如果客户端的软件系统升级比较频繁,那么B/S架构的产品优势明显——所有的升级操作只需要针对服务器进行,这对那些点多面广的应用是很有价值的,例如一些招聘网站就需要采用B/S模式,客户端分散,且应用简单,只需要进行简单的浏览和少量信息的录入。

在系统安全维护上,B/S则略显不足,B/S结构尤其得考虑数据的安全性和服务器的安全性,毕竟现在的网络安全系数并不高。以OA软件为例,B/S结构要实现办公协作过程中复杂的工作流控制与安全性控制,还有很多技术上的难点。因此,当前虽然出现了B/S结构的OA系统产品,但尚未大范围推广。

设计模式的实际应用

通常,概念和这些概念在现实世界中的应用是有区别的,设计模式也不例外。

  设计模式无处不在。在阅读技术方面的出版物或者浏览技术方面的网站时,很容易发现对设计模式的引用。到目前为止,您很可能已经阅读过(至少翻阅过)一些设计模式方面的书籍,如《Core J2EE Design Patterns》或者Gang of Four编写的《Design Patterns》。此时,您可能会对设计模式有一些疑问。设计模式如何帮助我?他们是银弹吗?使用设计模式有什么问题吗?为什么我不能从集成开发环境(integrated development environment,IDE)中获得设计模式?
  上述的几个问题是采用设计模式进行处理过程中遇到的一些经典问题。通常,概念和这些概念在显示世界中的应用是有区别的,设计模式也不例外。本文将讨论设计模式在现实世界中的应用。这些信息可以帮助您成功地在项目中采用设计模式来作出正确的决定。

快速概述
  设计模式提供了一种共享经验的方式,可以使团体受益和避免不断的重复发明。设计模式通常捕捉问题的描述、问题的语境、推荐的问题解决方案以及使用解决方案后可以预见到的结果。为了具有最广泛的适用性(从而对更多的读者有用),设计模式通常从取决于环境的精确细节中抽象而来。这种抽象性产生了一些把设计模式应用到现有的案例中所必需的译码。这是一个重要细节:尽管设计模式是共享专业知识的好方法,但通常它对正确应用专业知识是非常重要的。
  设计模式这个概念最初产生于建筑行业。设计师(设计建筑物而不是计算机系统)意识到他们需要共享有关正确设计技术的想法。这些想法是在可以使设计师团体从分享经验和教训中获益的设计模式中形成的。设计模式在80年代后期从建筑业进入计算机系统领域。面向对象(Object-oriented,OO)原则逐渐得到普及,而设计模式成为培育新的OO追随者的最佳实践。
  Richard Gamma等(人们通常把他们称作 Gang of Four [GoF] )编著的《Design Patterns: Elements of Reusable Object-Oriented Software》一书使设计模式成为万众瞩目的焦点。随着设计模式逐渐普及,他们所涉及的领域就像“Ben and Jerry”效应那样也逐渐广泛起来。对那些不熟悉著名冰淇淋品牌的人来说,Ben and Jerry是一家冰淇淋产品的供应商,其冰淇淋产品拥有各种可以想象得到的配料组合(还包括一些您永远想象不到的)。因此,它就是设计模式,和普通的OO设计模式一样来源于GoF的著作,但是现在包括了专为开发语言、应用服务器、行业合成等提供的设计模式。

设计模式分类
  设计模式通常根据一些公共特性而组合在一起。GoF的著作把设计模式划分为三类:Creational、Behavioral和Structural。用于J2EE的设计模式通常划分为表现层(Presentation Tier)、业务逻辑层(Business Logic Tier)和集成层(Integration Tier)。这种分组方式可以使描述所有设计模式共享的公共细节更加轻松,或者使设计模式的分类和发现更加轻松。
  在对设计模式实际应用的讨论中,需要把设计模式划分为两类:broad exposure和isolated use。这种划分基于设计模式对应用程序设计人员和开发人员的可见性和应用程序的多个部分对设计模式的相依性。
  Broad exposure 设计模式因为可以影响多个团队成员或者应用程序的多个方面的设计和开发而闻名。这类设计模式的品质包括:
采用它会对很多根据设计模式创建的类产生负面影响。
应用程序的不同部分知道设计模式的使用。
使用这种设计模式的决定不能轻易取消。
  这类设计模式的例子有Model-View-Controller(MVC)模式、Value Object J2EE模式和Data Access Object(DAO)J2EE模式
  Isolated use是指设计模式的使用是隐藏细节的设计模式。这类设计模式的品质包括:

设计模式不影响其他团队成员或者应用程序其他部分的工作。
可以轻松地更改使用设计模式的决定,而且产生的影响极小。
  这类设计模式的例子有Singleton GoF模式或者Intercepting Filter J2EE模式。
  将设计模式划分为几类为了解设计模式的范围提供了一种快速的方法。了解范围使评估设计模式的影响更加轻松。可以使用或者抛弃这种设计模式吗?一旦采用这种设计模式就会影响应用程序的设计吗?这种设计模式影响了应用程序的多个部分和其他的应用程序了吗?预先了解这些影响为采用设计模式提供了指导。

设计模式应用AntiPatterns
  随着设计模式逐渐普及,出现了另一种叫做AntiPatterns的模式类型。尽管设计模式提供了关于可重复的最佳方法的专业知识,但是AntiPatterns通常描述应当避免的重复行为。AntiPatterns 验证了这样的事实:做错事情和办对事情的人一样多。
  本节将探讨设计模式采用中的AntiPatterns。了解这些AntiPatterns可以帮助您避免设计模式采用中的缺陷。如同设计模式一样,在他们提供了一些远见或者他们是一些非常熟悉的环境时,在他们可以为您的经验添加色彩和使您不再感到孤独时,此处的AntiPatterns是一个全新的概念。如果您想阅读更多有关AntiPatterns的资料,请参见本文结尾处的资源列表。

AntiPattern清单
设计模式?是的,我们全部拥有
  问题:决定在项目中使用哪一种设计模式。
  应用: 既有broad exposure又有isolated use设计模式。
  环境:一位开发人员通过介绍希望在一项工程中使用设计模式。
  动力:AntiPattern的动力通常有两种来源。一种是开发人员通过包括设计模式的最佳实践来改进项目的渴望。另一种是开发人员天生的好奇心驱使他利用这个项目来研究设计模式。
  推荐的解决方案:项目中应用了所有知名的设计模式。设计模式手册生成一份清单,而目标是可以核对所有的设计模式。
  产生的语境:项目团队和交付的应用程序由于不自然地引入太多设计模式而遭受损失。这就导致设计和开发非常复杂。这种不必要的复杂性会从已经完成的工作量、开发团队了解发生事情的能力、应用程序的实际性能和功能的正确性等方面影响开发成果。
  设计基本原理:设计模式是专业知识的主要来源。尽管使用他们的效果很好,但是全部使用他们就未必也是好的。
实际解决方案:设计模式的描述包含了使用模式的目标语境。必须考虑如何确保设计模式匹配项目。第二,设计模式不是来源于当某人阅读了一本设计模式的著作后,问:“我可以把这个设计模式使用在什么地方?”而是来源于某人寻找已发现问题的解决方案。

Developer/Project AntiPattern的实现
  (也称为:Design pattern xyz? Yeah,我们有10个)
  问题:在项目中或者项目之间控制设计模式的实现。
  应用:broad exposure和isolated use设计模式都从解决这种环境中受益。但是,broad exposure设计模式无疑控制了实现。
  语境:开发团队将设计模式结合到项目中。团队由许多经验丰富的开发人员组成,他们知道应该什么时候使用设计模式。所以会正确的设计模式。如果涉及到多个项目,项目之间没有设计模式实现共享。
  动力:最终期限日益临近,团队成员工作效率很高。重新使用实现会影响团队效率。假设他们都是专家,他们的实现都非常优秀。在多项目情况中,跨团队通信和代码共享要么没有被考虑,要么被作为进度表中的潜在影响被排除。
  推荐的解决方案:团队可以根据需要单独包含和实现设计模式。
  产生的语境:即使使用了正确的设计模式,但是他们是以很多不同的方式实现的。在限制集成和重新使用成果的实现之间存在不兼容。很多不必要的时间和工作被花费在维护、调试和扩展各种实现上。最终,各种实现都将被统一。
  设计基本原理:应当允许专家成员独立工作。只要所包含的设计模式足够好,就不需要共享实现。
  实际解决方案:开发团队应当协调设计模式的使用。共享设计模式的公共实现可在将来降低成本,但是更重要的是,它使开发人员之间互相兼容。如果需要,这种共享可以被限制到划归先前讨论的broad exposure设计模式内。重用实现在项目间也极有价值,尤其在未来将要集成的时候。

设计模式采用中IDE的角色
  IDE在继续发展和提供更多的功能。最初的IDE组成了一种编辑环境和一些调试工具。现在,他们通常包含设计环境、审计工具、配置管理系统集成等等。随着IDE不断扩展范围,需要确认他们在设计模式实现中的角色。诚然,设计模式在开发语言中实现,而IDE可以用于编辑源代码。但是,IDE可以扮演其他的角色吗?
  一些IDE具有下拉菜单,使您能够选择应用程序中包括的设计模式。虽然这可以加快设计模式的使用,但是它只会导致更快地编写出极差的代码。评估这个特性需要记住几个因素。
  第一,设计模式在抽象中描述问题,并需要一些译码来达到正确的实现。但是,他们常常包含“示例实现(sample implementation)”,并且IDE正是将这种示例类结构插入到应用程序中。这很可能不是所需要的实现,并且把他们放到应用程序中将带来更多的困惑,以及需要更多的编辑和重构工作而不是思考最初的实现。
  第二,和IDE拖放设计模式方法有关的另一个问题是前面讨论的两种AntiPatterns。加快设计模式的实现很可能会产生大量的设计模式应用,以及同一设计模式的多种版本,而不是解决任意问题的版本。
  设计模式面临的挑战不仅仅是得到一次快速实现,而是确定使用了正确的实现,以及机构中已有的一个完美的实现。

BEA WebLogic Workshop 8.1和设计模式
  您可能是一位BEA的客户,如果您正在阅读本文,您可能想知道新的BEA WebLogic Workshop 8.1是如何影响您的设计模式考虑的。首先,WebLogic Workshop是IDE,因此前面有关IDE的章节同样适用。对这些讨论感兴趣的Workshop的两个额外方面是控件和预实现的设计模式。
  WebLogic Workshop Controls是打包功能的一种方法,可以轻松将其包含到使用Workshop IDE的应用程序中。打包包括IDE必需的可视元素、运行时行为、要求的配置等等。控件是如何影响设计模式应用的呢?还记得设计模式在前面划分为isolated use和broad exposure吗?划分到isolated use类的设计模式可能被打包成 Workshop Controls。把设计模式作为控件打包可使 Workshop IDE的其他用户共享实现,从而避免了每一个Developer/Project AntiPattern中的实现。
  您可能想知道为什么broad exposure设计模式为什么不可以作为控件实现。原因是broad exposure设计模式导致创建了许多其他类或者独立于其他应用程序。这种情况就不适合控件的即插即用方面。broad exposure设计模式的采用应当三思而后行,一旦采用就不能轻易取消。这些要求不符合WebLogic Workshop Control的目标。
  WebLogic Workshop还具有很多预实现设计模式,如Pageflow和用户接口结构。在Workshop 中,您可以创建JSP和定义Pageflow来控制Web应用程序页面之间的定位。在这种情况下,WebLogic Workshop使用流行的Apache Struts 表现层框架。Workshop的这个方面(使用 Struts)提供了一种Model-View-Controller(MVC)设计模式实现,意味着不用创建自己的MVC实现。Workshop包含的其他功能很可能替代您自己的设计模式实现。尽管一些设计模式实现的开盒即用很好,但是应当验证不仅实现而且实现创建的WebLogic任何依从性也非常合适。

成功采用设计模式的三个步骤
  如何把设计模式的采用和日益临近的最后期限、紧缩的预算和很多公司现有的有限团队资源相结合?以下是成功制订设计模式的三个步骤。

强大的通信和培训
  许多机构拥有领先技术,可能正式通过了设计师论坛的论证或者非正式的公认专家。这些领先厂商将推广设计模式采用中的开放通信,并将培训开发具体设计模式的团队。通信应当跨开发团队和项目以便预先防止采用竖井和多种惟一的实现(谨记每个Developer/Project AntiPattern的实现)。培训可以采用正式的internal lunch-and-learns、正式的internal class或者派一些员工参加外部培训。这些培训方式将促进正确的设计模式应用程序。如果仅有极少的观众能够参加培训,最佳的候选人是那些感觉适合在回来后能够培训其同事的人。

设计模式采用指导
  设计模式可用于使项目受益,但是他们也可能因为误用而对应用程序造成损害。应当鼓励采用他们,但是对其的采用应当受到审阅和验证。设计模式可以包含在设计和开发过程中。在任何一种情况中,设计模式的使用应当由审阅者确认和验证。在审阅过程中还可能会遇到这样的情况,额外的设计模式不适用于最初包括的地方。即使环境中没有进行正式的审阅,这一步骤也可以通过同事审阅或者团队讨论来完成。这一步骤中的审阅者要么是主要团队的成员,要么与他们建立开放通信。
  指导采用对于broad exposure类别的设计模式非常关键。这些设计模式具有很多相关的风险,因为他们将创建依赖性。这些依赖性可能在一些对象类中,例如,只工作在更加广泛的DAO设计模式实现范围中的数据访问对象(DAO)、或者跨应用程序边界(如使用Value Object设计模式在应用程序和应用程序层之间传输数据)。这些设计模式也可以由项目中的其他人或者不同项目的人实现,而且实现应当重新使用,不同于创建另一种独特的实现。

重用实现,不只是设计模式
  只要在创建自己的设计模式实现中有一定的满足,团队和公司就可以在重用发生在代码层时,而不是设计创意层时获得更多益处。使企业获益的最初设计模式是改进的实现。但是,真正的目标是重用实现。重用实现将导致:a)其他可重用的类(取决于公共实现);b)缩短开发时间和降低成本;c)缩短维护时间和降低成本;d)在应用程序之间和内部轻松集成。
  这种重用对broad exposure设计模式非常重要(有时是基本的)。这些设计模式创建了外部依赖性(集成将从公共实现中受益)或者产生全部的自定义类库(如果有公共基础将可重用)。isolated use设计模式也可以从重用中获益,但是如果他们是根据具体情况定制的,他们就非常难以重用。
  有时您可能会问自己:“如果重用比较好,为什么设计模式和可以重用的实现不可以一同应用呢?”在我们讨论设计模式如何使更多读者获益的时候才会讨论这个问题。如果可能,如果已经预定义了实现,那么达到广泛适用性这个目标就会非常困难。然而,一旦设计模式被应用到特殊的问题域或者技术基础设施中,那么就可以重用在该环境中产生的实现。

架构中的设计模式
  这看起来像是一件可怕的任务,需要掌握设计模式如何应用在实际情况中,如何构建优质的实现,以及如何促进重用实现。完成该任务的方法之一就是在环境中引入应用程序架构。应用程序架构提供了应用程序需要的结构,从而使开发团队可以关注应用程序的域逻辑。这包含了已实现的设计模式。除了重用设计模式概念或者单个实现之外,可以在多个项目和应用程序之间重用架构。这种共享的公共实现确保了兼容性,并为开发和维护多种不同的实现提供了一种低成本替代方案。兼容性提供了重新使用需要的技术基础。没有足够的篇幅在这里深入讨论架构的其他重要品质,如运行时监测和管理、可配置应用程序逻辑和适应性行为等。您可以从Carnegie Mellon Software Engineering Institute (www.sei.cmu.edu/ata/ata_init.html) 中学习到更多有关架构的知识。

结束语
  设计模式是一种令人惊异的资源,应该使用他以增加您的优势。虽然设计模式提供了可重用的概念,但是面临的挑战是决定使用哪一种设计模式和致力于可以重用的实现。通过了解采用设计模式中会产生的风险,就可以在继续学习和实现更多设计模式时避免风险。
  按照本文概述的步骤会产生一个流程,用于在团队和机构中推广成功的设计模式采用。

2000年7月22日星期六

Struts編

サンプル参照:http://www.hellohiro.com/struts.htm

XML編

XML(SAX)編
◆SAXとは?
SAXはSimple API for XMLの略です。DOM(Document Object Model)と並んでXMLを解析するために使用する標準APIです。SAXはXML文書を先頭から読んでいきそこで発生したイベントをアプリケーションでとらえて処理するAPIです。DOMに比べて、メモリ消費量が少ない、解析速度が速いなどのメリットがありますが、ノードの追加、削除など、XML文書を更新する機能はありません。
XML(SAX)編 参照⇒ http://www.hellohiro.com/xmlsax.htm

XML(DOM)編
◆DOMとは?
DOMはDocument Object Modelの略です。XMLにアクセスするためのAPI(Application Programming Interface)です。W3Cによって仕様が公開されています。DOMは、XML文書をツリー構造として扱います。これを「DOMツリー」といいます。XML文書全体を解析してDOMツリーとしてメモリ上に保存するのでデータの多いXML文書を解析する場合は多くのメモリを消費します。

◆DOMツリーとは?
DOMツリーとはDOMがメモリ上に作成したXML文書全体の階層構造のことです。XML文書は階層構造で表現することができます。
XML(DOM)編 参照⇒ http://www.hellohiro.com/xmldom.htm

2000年7月19日星期三

システム設計概念

【基本設計】
【①】業務フロー:業務の流れを理解し、機能を洗い出す。
【②】機能一覧表:開発範囲となる機能(画面・帳票・バッチ)の一覧。
【③】ネットワーク構成図:システム構成を把握。
【④】テーブル定義:SIObject Browser使用。
【⑤】ER 図:SIObject Browser使用。
【⑥】画面遷移図:画面遷移を図示。
【⑦】機能設計書:機能別の設計書。
【⑧】表紙。
【⑨】I/O関連図:データと機能の関係を図示。
【⑩】画面レイアウト:画面イメージ。
【⑪】帳票レイアウト:帳票イメージ。
【⑫】設計書記述様式:設計書の記述方法の説明。

【詳細設計】
【①】機能設計書:機能別の設計書。
【②】表紙。
【③】目次・概要。
【④】フローチャート:バッチ処理のフローチャート。
【⑤】項目説明書:画面・帳票の項目説明。
【⑥】イベント一覧:画面操作で発生するイベントの一覧。
【⑦】BL一覧:機能に含まれるビジネスロジックの一覧。
【⑧】更新仕様書:機能またはBL単位の更新・処理内容を記述。
【⑨】補足説明書:上記の記述に対する補足説明。

2000年7月18日星期二

Web开发 用于操作数据库


package test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

public class TestDAO {
private Connection conObj = null;

public TestDAO() {
if(conObj==null){
try {
conObj=TestDBAccess.getInstance().getConnection();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}

public ArrayList select(String keyStr) {
String sql = "";
PreparedStatement pstmt = null;
ResultSet rset = null;
ArrayList dataList = new ArrayList();

// SQL作成
sql = " SELECT * FROM dbo.TableName ";

// エリアコード
if (keyStr.equals("") || keyStr == null) {
sql += " WHERE COL1 LIKE ? ";
keyStr = "%";
} else {
sql += " WHERE COL1 = ? ";
}

try {

pstmt = this.conObj.prepareStatement(sql);
pstmt.setString(1, keyStr);

rset = pstmt.executeQuery();

while (rset.next()) {
ArrayList rowList = new ArrayList();

// データ格納
rowList.add(this.checkString(rset.getString("COL1")));
rowList.add(this.checkString(rset.getString("COL2")));
rowList.add(this.checkString(rset.getString("COL3")));
rowList.add(this.checkString(rset.getString("COL4")));
rowList.add(this.checkString(rset.getString("COL5")));

dataList.add(rowList);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (rset != null)
rset.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return dataList;
}

public boolean delete(String keyStr) {
boolean ret = true;
PreparedStatement pstmt = null;
String sql = "";

// SQL作成
sql = " DELETE FROM dbo.TableName ";
sql += " WHERE ";
sql += " ID = ? ";

try {
// データセット
pstmt = this.conObj.prepareStatement(sql);
// エリアコード
pstmt.setString(1, keyStr);

// SQL実行
pstmt.execute();
} catch (Exception e) {
e.printStackTrace();
ret = false;
} finally {
try {
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return ret;
}

public boolean insert(ArrayList dataList) {
boolean ret = true;
String sql = "";
PreparedStatement pstmt = null;

sql = " INSERT INTO dbo.TableName ( ";
sql += " COL1, ";
sql += " COL2, ";
sql += " COL3, ";
sql += " COL4, ";
sql += " COL5 ";
sql += " ) values ( ";
sql += "?, ";
sql += "?, ";
sql += "?, ";
sql += "?, ";
sql += "? ";
sql += ")";

try {
pstmt = this.conObj.prepareStatement(sql);

pstmt.setString(1, this.checkString(dataList.get(0)));// COL1
pstmt.setString(2, this.checkString(dataList.get(1)));// COL2
pstmt.setString(3, this.checkString(dataList.get(2)));// COL3
pstmt.setString(4, this.checkString(dataList.get(3)));// COL4
pstmt.setString(5, this.checkString(dataList.get(4)));// COL5

// SQL実行
pstmt.execute();

} catch (Exception e) {
e.printStackTrace();
ret = false;
} finally {
try {
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return ret;
}

public boolean update(ArrayList dataList) {
boolean ret = true;
String sql = "";
PreparedStatement pstmt = null;

// SQL作成
sql = " UPDATE dbo.TableName SET ";
sql += " COL1 = ?, ";
sql += " COL2 = ?, ";
sql += " COL3 = ?, ";
sql += " COL4 = ?, ";
sql += " COL5 = ? ";
sql += " WHERE ";
sql += " ID = ? ";

try {
pstmt = this.conObj.prepareStatement(sql);

pstmt.setString(1, this.checkString(dataList.get(0)));// COL1
pstmt.setString(2, this.checkString(dataList.get(1)));// COL2
pstmt.setString(3, this.checkString(dataList.get(2)));// COL3
pstmt.setString(4, this.checkString(dataList.get(3)));// COL4
pstmt.setString(5, this.checkString(dataList.get(4)));// COL5

// SQL実行
pstmt.execute();
} catch (Exception e) {
e.printStackTrace();
ret = false;
} finally {
try {
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return ret;
}

private String checkString(Object obj) {
return obj == null ? "" : obj.toString().trim();
}
}

Web开发 用于获得数据库连接


package test;

import java.sql.*;
import javax.naming.*;
import javax.sql.*;

public class TestDBAccess {
private static TestDBAccess _instance = null; // DB接続管理オブジェクト
private DataSource ds = null;

private TestDBAccess() throws SQLException, Exception {
try {
// 初期コンテキストを取得
InitialContext ic = new InitialContext();
// ルックアップしてデータソースを取得
this.ds = (DataSource) ic.lookup("java:comp/env/jdbc/viper");
} catch (Exception e) {
e.printStackTrace();
}
}

public synchronized static TestDBAccess getInstance() throws SQLException, Exception {
return _instance == null ? new TestDBAccess() : _instance;
}

public Connection getConnection() throws SQLException, Exception {
Connection con = null;

try {
// コネクション取得
con = this.ds.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
}

Web开发 用于输出日志


package test;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

public class TestLog {
private static final long serialVersionUID = 1L;
private FileWriter filewrt;
private String logName = "";
private String DirPATH = System.getProperty("catalina.home") + "\\logs\\";

public TestLog() {
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMM");
Date date = new Date();
logName = DirPATH + "veriserve" + sdf1.format(date) + ".log";
}

public TestLog(String name) {
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMM");
Date date = new Date();
logName = DirPATH + name + sdf1.format(date) + ".log";
}

private void open() {
try {
// ログファイル名
File FileName = new File(logName);

if (CheckBeforeWriteFile(FileName)) {
// ファイル追加モード
filewrt = new FileWriter(FileName, true);
} else {
// 新規作成
if (FileName.createNewFile()) {
filewrt = new FileWriter(FileName, true);
}
}

} catch (IOException e) {

// エラー発生
e.printStackTrace();
}
}

private void close(){
try {
filewrt.close();
} catch( IOException e){
// エラー発生
e.printStackTrace();
}
}

private static boolean CheckBeforeWriteFile(File FileName) {
if (FileName.exists()) {
if (FileName.isFile() && FileName.canWrite()) {
return true;
}
}
return false;
}

public void Write(String PGName, String Msg) {
String LogMsg;
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy'/'MM'/'dd HH':'mm':'ss");
Date date = new Date();

LogMsg = sdf1.format(date) + "\t" + "[" + PGName + "]\t" + Msg + "\n";

try {
this.open();
filewrt.write(LogMsg);
this.close();
} catch (IOException e) {
// エラー発生
e.printStackTrace();
}
}
}

2000年7月8日星期六

2000年7月7日星期五

tomcat+apache+mod_jk整合

◆ApacheとTomcatの連携 ここではTomcatをApacheに組み込んで動かしてみたいと思います。こうすることでApacheが動いている環境でもポート80でTomcatを利用することがきるようになります。ApacheとTomcatの連携にはJK2コネクタを使用します。JK2コネクタはTomcatとApacheを連携するためのモジュールです。JK2コネクタはJKコネクタの改良版として開発され設定もシンプルになっています。

◆ApacheとTomcatを連携するメリット
①.ApacheのHTTPサーバとしての様々な機能を利用できるようになる。
②.一台のWebサーバに対して複数のTomcatのインスタンスを割り当てることによって負荷分散を実現できる。
③.静的なファイル(HTMLファイルや画像ファイル)をより高速なApacheが処理し、動的なページ(Servlet、Jsp)をTomcatが処理することによって効率のよいレスポンスが実現できる。

mod_jkのダウンロード:
http://tomcat.apache.org/connectors-doc/

ApacheとTomcatをmod_jkでの連携方法:
http://www.develop-memo.com/server/apache/modjk.html
http://www.wings.msn.to/contents/env/jsp/renkei_win.html
http://www.jajakarta.org/tomcat/tomcat3.2-4.0/tomcat-3.2.3/doc-ja/mod_jk-howto.html

2000年7月2日星期日

IT関連用語

問題:J2SE
→Java 2 Platform Standard Editionの略です。Java 2プログラミング言語の機能セットの一つで、基礎となる標準的な機能をまとめた、デスクトップ向けエディションです。

問題:J2EE
→Java 2 Platform Enterprise Editionの略です。Java 2プログラミング言語の機能セットの一つで、標準機能セットのJ2SEに、サーバ用のAPIや諸機能を付加した、企業向け、サーバ向けエディションです。

問題:J2ME
→Java 2 Platform Micro Editionの略です。Java 2プログラミング言語の機能セットの一つで、家電製品や携帯情報端末、携帯電話などの組み込み機器向けの機能をまとめた、小規模組み込みシステム向けエディションです。

問題:Servlet
→Webサーバ上で動作するJavaアプリケーションの一種です。WebサーバがServletを起動し、Servletからデータベースなどにアクセスし、その結果Webページとして返す際などに利用される。Servletを追加することにより、Webサーバの機能を拡張することができる。

問題:JavaBeans
→再利用しやすくするため、決められた作法に基づいて開発されたJavaのソフトウェアコンポーネントです。JavaBeansを部品として利用しながらソフトウェアの開発効率を高めることができる。

問題:Apache
→最も人気の高いWebサーバソフトウェアの一つです。Apacheはフリーソフトウェアとして無償で公開され、世界中のボランティアプログラマたちの手によって長年に渡って開発が続けられている。

問題:Tomcat
→オープンソースのソフトウェアで、Java Servlet、JSPを処理するアプリケーションサーバです。Tomcatは単独でウェブサーバとして動作することも可能だが、ApacheやIISのプラグインと動作できるようになっており、実際にはプラグインとしての利用が主流である。

問題:JBoss
→Java言語で書かれたJ2EEアプリケーションサーバです。JBossはTomcatなどのアプリケーションサーバを含むため、JBossのみでウェブアプリケーションを実行できる。EJBを実装したものでもあるため、様々なEJBアプリケーションを実行することも可能である。

問題:Cookie
→ウェブサーバとウェブブラウザとの間で、ユーザに関する情報やアクセス情報などをやり取りするための仕組みです。

問題:JVM
→Java Virtual Machineの略です。Javaプログラムを実行する仮想的なマシンです。Javaプログラムは通常CPUに依存しない中間コードにコンパイルされて配布される。VMがこの中間コードをCPUに依存したコードに変換して実行する。

問題:JDK
→Java Development Kitの略で、Javaプログラミングを行う際に必要、Javaのコンプイラ等が含まれる。

問題:JRE
Java Runtime Engineの略です。Javaの実行環境です。Javaアプリケーションを実行する際に必要。実行するだけならJRE、開発もするならJDKが必要。

問題:JSP
→HTMLファイル中に埋め込まれるJavaプログラムです。ユーザからそのページへのアクセス要求があった時にコンパイルされ、その結果がWebページとしてユーザに返される。

問題:PL・SQL:
→PL・SQLとは、SQL言語にプログラムに必要な繰り返し命令、エラー処理などを追加した言語であり、Programming Language for SQLの略です。

問題:SQL・Plus:
→SQL・Plusとは、Oracleデータベース用の対話ツールです。 主にデータベースに対してこのツールを通してSQLの実行などを行います。更にSQL・Plusには、各種のコマンドが用意されています。

問題:MySqlの使うことがありますか
→はい、MySqlの業務経験がないですが、Programming Levelで他のdatabaseとあまり変わらないと思います。対応できると思います。

問題:Hibernateでの開発経験がありますか:
→はい、HibernateはJava開発でよく使うOpenSourceのframeworkです。これは業務経験がないですが、別のframeworkでの開発経験がありますので、対応できると思います。

問題:Linuxでの経験がありますか。
→はい、直接Linuxでの開発経験がないですが、開発環境はWindowsで、システムの実行環境はLinuxでした。

問題:インデックスを使えますか。
→はい、使えます。インデックスを正しい使えばシステムの性能をアップできます。でも、使い方は正しくない時システムに悪い影響もあります。例えば:よく使えないコラム或いは状態が少ないのコラム(性別)でインデックスを作るのはシステムにとって性能をあまりよくないと思います。

問題:PL・SQLの経験がありますか。
→はい、経験があります。私はOracle9Iデータベースでの開発経験があります。その時PL・SQLでテスト用データの作成、操作結果のオンラインチェック、データベースバックアップなど仕事を担当しました。

問題:PL/SQLを使ったことありますか?
→はい、使ったことあります。PL/SQL-プロシージャを作ったことがあります。また、PL・SQLでテスト用データの作成、操作結果のオンラインチェック、データベースバックアップなどを担当しました。

問題:Linux(或いはUnix 或いはAIX)はどの程度使えますか?
→はい、システム管理者とする経験はありませんが、一般ユーザとする経験はあります。例えば、Linux環境でプログラムソースの作成、コンバイル、アプリ実行などができます。そして、ローカル作業環境の管理ができます。

問題:Ajaxの業務経験はありますか?
→はい、直接にAjaxを使う経験はありませんが、その関連技術のJavaScript、XML、CSSの業務経験があります。チャンスがあれば、是非挑戦したいと思います。

問題:UMLの経験がありますか?
→はい、私は基本設計と詳細設計の経験があります。設計する時、UMLを使って、ユースケース図、パッケージ図、クラス図、シーケンス図などを作成して、分析を行いました。

2000年6月23日星期五

VB中的字符串处理

1、处理机制

在VB4.0以后,字符串采用统一编码方式,即“UniCode”。
早期英文字符占用1个字节,汉字占用2个字节,即ANSI方式;UniCode方式下,所有字符都占用2个字节。
在字符串函数中,考虑的是字符个数,而不是字节数。
为了兼容早期的软件,可使用转换函数StrConv把字符串转换为指定格式。
新字符串=StrConv(待转字符串,转换常数)
常数

说明

vbUpperCase
1
将字符串文字转成大写。

vbLowerCase
2
将字符串文字转成小写。

vbProperCase
3
将字符串中每个字的开头字母转成大写。

vbUnicode
64
根据系统的缺省码页将字符串转成 Unicode。

vbFromUnicode
128
将字符串由 Unicode 转成系统的缺省码页。


当在Unicode方式下,必须用加了“B”的字符串函数来处理ANSI的字符串才能得到正确的值,函数如下:
处理Unicode的字符串的函数名
处理ANSI的字符串的函数名

len
lenB

left
leftB

right
rightB

mid
midB

instr
instrB

函数说明见下面:


例:运行下面程序,查看两种编码的使用区别。

Private Sub Command1_Click()
Dim tempStr, newStr As String
tempStr = "VB程序设计"
Print "tempStr="; tempStr
newStr = StrConv(tempStr, vbFromUnicode)
Print "******"
Print "执行newStr = StrConv(tempStr, vbFromUnicode)后:"
Print "newStr="; newStr
Print "LenB(newStr)="; LenB(newStr)
Print "注:每个长度单位为1个字节,字符占1个,汉字占2个"
Print "Len(newstr)="; Len(newStr)
Print "注:每个长度单位为2个字节,字符占半个,汉字占1个"
Print "******"
newStr = StrConv(newStr, vbUnicode)
Print "执行newStr = StrConv(tempStr, vbUnicode)后:"
Print "newStr="; newStr
Print "LenB(newStr)="; LenB(newStr)
Print "注:每个长度单位为1个字节,字符占2个,汉字占2个"
Print "Len(newStr)="; Len(newStr)
Print "注:每个长度单位为2个字节,字符占1个,汉字占1个"
End Sub


2、字符串函数

删除空格字符串
去掉字符串左部连续空格:LTrim$(字符串)
去掉字符串左部连续空格:RTrim$(字符串)
去掉字符串两边连续空格:Trim$(字符串)
例:使用函数。查看运行结果。
Private Sub Command1_Click()
aaa1 = "aaaaa "
bbb1 = " bbbbb"
ccc1 = " ccccc "
Print "|" + LTrim(aaa1) + "|" + LTrim(bbb1) + "|" + LTrim(ccc1) + "|"
Print "|" + RTrim(aaa1) + "|" + RTrim(bbb1) + "|" + RTrim(ccc1) + "|"
Print "|" + Trim(aaa1) + "|" + Trim(bbb1) + "|" + Trim(ccc1) + "|"
End Sub


字符串截取函数
左部截取:Left$(字符串,n) 从左部开始取n个字符
右部截取:Right$(字符串,n) 从右部取n个字符
中部截取:Mid$(字符串,p,n) 从左部开始的第p个字符,取连续n个字符
例:使用函数。查看运行结果。
Private Sub Command1_Click()
MyString = "Mid Function Demo"
FirstWord = Left(MyString, 3) ' 返回 "Mid"。
LastWord = Right(MyString, 4) ' 返回 "Demo"。
MidWords = Mid(MyString, 5) ' 返回 "Funcion Demo"。
Print FirstWord, LastWord, MidWords
End Sub


字符串长度测试函数
Len(字符串):字符串的长度。
Len(变量名):变量的存储空间。
例:使用函数。查看运行结果。
Private Type CustomerRecord ' 定义用户自定义的数据类型。
ID As Integer ' 将此定义放在常规模块中。
Name As String * 10
Address As String * 30
End Type

Private Sub Command1_Click()
Dim Customer As CustomerRecord ' 声明变量。
Dim MyInt As Integer, MyCur As Currency
Dim MyString, MyLen
MyString = "Hello World" ' 设置变量初值。
MyLen = Len(MyInt) ' 返回 2。
Print MyLen
MyLen = Len(Customer) ' 返回 42。
Print MyLen
MyLen = Len(MyString) ' 返回 11。
Print MyLen
MyLen = Len(MyCur) ' 返回 8。
Print MyLen
End Sub


String$函数
String$(n,ASCII码值):返回由该ASCII码指定的字符组成的n个字符的字符串
String$(n,字符串):返回由该字符串的第一个字符组成n个字符的字符串
例:使用函数。查看运行结果。
Private Sub Command1_Click()
Print String$(6, 65) '返回字符串"AAAAAA
Print String$(3, "c") '返回字符串"ccc"
End Sub


空格函数
Space$(n):返回由n个空格组成的字符串
例:使用函数。查看运行结果。
Private Sub Command1_Click()
Print "start" + Space(3) + "END" '返回字符串"start END"
Print "start" + "123" + "END" '返回字符串"start123END"
End Sub


字符串匹配函数
Instr$([开始位置,]string1,string2[,n]) 查找某字符串在另一个字符串中首次出现的位置。
n为0,二进制比较(区分大小写);n为1,文本方式比较(不区分大小写);n为2,数据库信息比较。
返回的结果:

如果
InStr返回

string1 为零长度
0

string1 为 Null
Null

string2 为零长度
开始位置

string2 为 Null
Null

string2 找不到
0

在 string1 中找到string2
找到的位置

开始位置 > string2
0

例:使用函数。查看运行结果。
Private Sub Command1_Click()
Dim SearchString, SearchChar, MyPos
SearchString = "XXpXXpXXPXXP" ' 被搜索的字符串。
SearchChar = "P" ' 要查找字符串 "P"。

' 从第四个字符开始,以文本比较的方式找起。返回值为 6(小写 p)。
' 小写 p 和大写 P 在文本比较下是一样的。
MyPos = InStr(4, SearchString, SearchChar, 1)
Print MyPos

' 从第一个字符开使,以二进制比较的方式找起。返回值为 9(大写 P)。
' 小写 p 和大写 P 在二进制比较下是不一样的。
MyPos = InStr(1, SearchString, SearchChar, 0)
Print MyPos

' 缺省的比对方式为二进制比较(最后一个参数可省略)。
MyPos1 = InStr(SearchString, SearchChar) ' 返回 9。
mypos2 = InStr(1, SearchString, "W") ' 返回 0。
Print MyPos1, mypos2
End Sub


字母大小写转换函数
Ucase$(字符串):将字符串转换为大写
Lcase$(字符串):将字符串转换为小写
例:使用函数。查看运行结果。
Private Sub Command1_Click()
Print UCase$("Rose") '返回字符串"ROSE"
Print LCase$("Rose") '返回字符串"rose"
End Sub

替换字符串命令
Mid$(字符串,位置[,L])=子字符串
说明:在字符串中,从指定位置开始L个字符被子字符串替换,如果子字符串长度大于L,子字符串被截取;如果L没有,则替换后的字符串长度和被替换前的字符串长度一样。
例:使用函数。查看运行结果。
Private Sub Command1_Click()
Dim MyString
MyString = "The dog jumps" ' 设置字符串初值。
Mid(MyString, 5, 3) = "fox"
Print MyString ' MyString = "The fox jumps"
Mid(MyString, 5) = "cow"
Print MyString ' MyString = "The cow jumps"
Mid(MyString, 5) = "cow jumped over"
Print MyString ' MyString = "The cow jumpe"
Mid(MyString, 5, 3) = "duck"
Print MyString ' MyString = "The duc jumpe"
End Sub

VB文件操作

在VB中,对于顺序文件、随机文件、二进制文件的操作通常都有3个步骤:

(1)打开文件

文件操作的第一步是打开文件。在创建新文件或使用旧文件之前,必须先打开文件。打开文件的操作,会为这个文件在内存中准备一个读写时使用的缓冲区,并且声明文件在什么地方,叫什么名字,文件的处理方式。

(2)访问文件

访问文件是文件操作的第二步。所谓访问文件,即对文件进行读/写操作。从磁盘将数据送到内存称为“读”,从内存将数据存到磁盘称为“写”。

(3)关闭文件

打开的文件使用(读/写)完后,必须关闭,否则会造成数据丢失。关闭文件会把文件缓冲区中的数据全部写入磁盘,释放掉该文件缓冲区占用的内存。

A 顺序文件

顺序文件用于处理一般的文本文件,它是标准的ASCII文件。顺序文件中各数据的写入顺序、在文件中的存放顺序、和从文件中的读出顺序3者是一致的。

顺序文件按行组织信息。每行由若干项组成,行的长度不固定,每行由回车换行符号结束。

a 顺序文件的打开与关闭

在对顺序文件进行操作之前,必须用Open语句打开要操作的文件。在对一个文件操作完成后,要用Close语句将它关闭。

1.Open语句的一般格式

Open 文件名 [For打开方式 ] As [#]文件号

(1)文件名。

(2)打开方式包括以下3种。

Input Output Append

(3)文件号。

是一个1~511之间的整数。它用来代表所打开的文件,文件号可以是整数或数值型变量。

例如:

① Open "d:\shu1.dat" For Input As #1

该语句以输入方式打开文件shu1.dat,并指定文件号为1。

② Open "d:\shu2.dat" For  Output As #5

该语句以输出方式打开文件shu2.dat,即向文件shu2.dat进行写操作,并指定文件号为5。

③ Open "d:\shu3.dat" For  Append As #7

该语句以添加方式打开文件shu3.dat,即向文件shu3.dat添加数据,并指定文件号为7。

2.Close语句的一般格式

Close [文件号表列]

例如:

① Close #1

关闭文件号为1的文件。

② Close #2,#7,#8

关闭文件号为2,7,8的文件。

③ Close

关闭所有已打开的文件。

b 顺序文件的写操作

VB用Print语句或Write语句向顺序文件写入数据。创建一个新的顺序文件或向一个已存在的顺序文件中添加数据,都是通过写操作实现的。另外,顺序文件也可由文本编辑器(记事本、Word等)创建。

1.Print语句

Print语句的一般格式:

Print #文件号 [,输出表列]

例如:

Open "d:\shu2.dat" For  Output As #2

Print # 2, "zhang";"wang";"li"

Print # 2, 78;99;67

Close #2

执行上面的程序段后,写入到文件中的数据如下:

zhangwangli

78 99 67

2.Write语句

用Write语句项文件写入数据时,与Print语句不同的是,Write语句能自动在各数据项之间插入逗号,并给各字符串加上双引号。

Write语句的一般格式:

Write #文件号 [,输出表列]

例如:

Open "d:\shua.dat" For  Output As #6

Write # 6, "zhang";"wang";"li"

Write # 6, 78;99;67

Close #6

执行上面的程序段后,写入到文件中的数据如下:

"zhang","wang","li"

78,99,67

c 顺序文件的读操作

顺序文件的读操作,就是从已存在的顺序文件中读取数据。在读一个顺序文件时,首先要用Input方式将准备读的文件打开。VB提供了Input、Line Input语句和Input函数将顺序文件的内容读入。Input函数将在9.4节中介绍。

1.Input语句

Input语句一般格式:

Input #文件号,变量表列

例如:

Private Sub form_Click()

Dim x$,y$,z$,a%,b%,c%

Open "c:\_vb\shua.dat" For Input As #1

Input #1,x,y,z

Input #1,a,b,c

Print x,y,z

Print a,b,c

Print a + b + c

Close #1

End Sub

如果顺序文件shua.dat的内容如下:

"zhang","wang","li"

78,99,67

执行Form_Click过程,在窗体上显示的内容为:

zhang wang li

78 99 67

244

2.Line Input语句

Line Input语句是从打开的顺序文件中读取一行。

Line Input语句的一般格式:

Line Input #文件号,字符串变量

例如:

如果顺序文件shua.dat的内容如下:

"zhang","wang","li"

78,99,67

我们用Line Input语句将数据读出并且把它显示在文本框中。

Private Sub Command1_Click()

Dim a$,b$

Open "c:\_vb\shua.dat" For Input As #2

Line Input #2,a

Line Input #2,b

Text1.Text = a & b

End Sub

执行以上过程,文本框中显示的内容为:

"zhang","wang","li"78,99,67



B 随机文件

使用顺序文件有一个很大的缺点,就是它必须顺序访问,即使明知所要的数据是在文件的末端,也要把前面的数据全部读完才能取得该数据。而随机文件则可直接快速访问文件中的任意一条记录,它的缺点是占用空间较大。

随机文件由固定长度的记录组成,一条记录包含一个或多个字段。具有一个字段的记录对应于任一标准类型,比如整数或者定长字符串。具有多个字段的记录对应于用户定义类型。随机文件中每个记录都有一个记录号,只要指出记录号,就可以对该文件进行读写。

1 随机文件的打开与关闭

在对一个随机文件操作之前,也必须用Open语句打开文件,随机文件的打开方式必须是Random方式,同时要指明记录的长度。与顺序文件不同的是,随机文件打开后,可同时进行写入与读出操作。

Open语句的一般格式:

Open 文件名 For Random As #文件号 Len=记录长度

说明:

记录长度是一条记录所占的字节数。可以用Len函数获得。

例如,定义以下记录:

Type student

Name As String*10

Age As Integer

End Type

就可以用下面的语句打开:

Open "d:\Test.dat" For Random As #9 Len=Len(student)

随机文件的关闭同顺序文件一样,用Close 语句。

2 随机文件的写操作

用Put语句进行随机文件的写操作。

Put语句一般格式为:

Put # 文件号,记录号,变量

说明:

Put语句把变量的内容写入文件中指定的记录位置。记录号是一个大于或等于1的整数。

例如,Put # 1,9,t

表示将变量t的内容送到1号文件中的第9号记录去。

3 随机文件的读操作

用Get语句进行随机文件的读操作。

Get语句格式一般为:

Get # 文件号,记录号,变量

说明:

Get语句把文件中由记录号指定的记录内容读入到指定的变量中。

例如,Get # 2,3,u

表示将2号文件中的第3条记录读出后存放到变量u中。

D 二进制文件

二进制文件被看作是字节顺序排列的。由于对二进制文件的读写是以字节为单位进行的,所以能对文件进行完全的控制。如果知道文件中数据的组织结构,则任何文件都可以当作二进制文件来处理使用。

1 二进制文件的打开与关闭

二进制文件的打开用Open语句。

其格式为:

Open 文件名 For Binary As #文件号

使用Close语句关闭二进制文件。

2 二进制文件的读/写操作

对二进制文件的读/写同随机文件一样用Put和Get语句。

它们的格式如下:

Put # 文件号,位置,变量

Get # 文件号,位置,变量



文件操作常用函数

1.LOF函数

格式:LOF(文件号)

功能:返回一个已打开文件的大小,类型为Long,单位是字节。

2.FileLen函数

格式:FileLen(文件名)

功能:返回一个未打开文件的大小,类型为long,单位是字节。文件名可以包含驱动器以及目录。

3.EOF函数

格式:EOF(文件号)

功能:用于判断读取的位置是否已到达文件尾。当读到文件尾时,返回True,否则返回False。对于顺序文件,用EOF 函数测试是否到达文件尾;对于随机文件和二进制文件,如果读不到最后一个记录的全部数据,返回True,否则返回False。对于以Output 方式打开的文件,EOF 函数总是返回True。

4.LOC函数

格式:LOC(文件号)

功能:返回文件当前读/写的位置,类型为Long。 对于随机文件,返回最近读/写的记录号;对于二进制文件,返回最近读/写的字节的位置。对于顺序文件,返回文件中当前字节位置除以 128 的值。对于顺序文件而言,Loc 的返回值无实际意义。

5.Input函数

格式:Input(字符数,#文件号)

功能:从打开的顺序文件读取指定数量的字符。Input函数返回从文件中读出的所有字符,包括逗号、回车符、换行符、引号和空格等。

例如:Text1.Text=Input(Lof(2),#2)

该语句是将2号文件的内容全部复制到文本框中。

VB基础知识

一:变量定义
Dim a as integer,b as long,c as single , d as String
等价于
Dim a%,b&,c! , d$

二:注意“+”和“&”的区别
"ABC"+"DEF" → "ABCDEF"
"姓名:" & "张三" → "姓名:张三"
23 & "7" → "237"
23+"7" → 30

三:输入框
Dim r!
r = InputBox("请输入半径","输入框")

四:消息框
dim inta
inta=MsgBox(“密码错”,21,“密码核对” )

五:if 语句
Dim weight as single,pay as single
weight= Text1.Text

If weight > 50 Then
pay =(weight - 50)* 0.5 + 50 * 0.2
Else
pay = weight * 0.2
End If

六:if elseif 语句
Dim score!
score = Text1.Text

If score >= 90 Then
Text2.Text = "优秀"
ElseIf score >= 80 Then
Text2.Text = "良好"
ElseIf score >= 70 Then
Text2.Text = "中"
ElseIf score >= 60 Then
Text2.Text = "及格"
Else
Text2.Text = "不及格"
End If

七:行If语句
Dim b As Single,max As Single

If b > max Then max = b

八:Select Case语句
Dim score!
score = Text1.Text

Select Case score
Case Is >= 90
Text2.Text = "优秀"
Case Is >= 80
Text2.Text = "良好"
Case Is >= 70
Text2.Text = "中"
Case Is >= 60
Text2.Text = "及格"
Case Else
Text2.Text = "不及格"
End Select

九:for循环
For n=1 To 10 Step 3
Print n,
Next n

十:While循环
x=1
While x<5 Print x, x=x+1 Wend 十一:Do while循环 r = m Mod n Do While r > 0
m = n
n = r
r = m Mod n
Loop
r = m Mod n

十二:Do until循环
Do Until r = 0
m = n
n = r
r = m Mod n
Loop

十三:循环的结束
1.Exit For
该语句用于For…Next循环,在循环体中可以出现一次或多次。当系统执行到该语句时,就强制退出当前循环。常见的使用格式是:If 条件 Then Exit For 即当循环执行过程中满足某个条件时,就执行循环退出语句结束循环。

2.Exit Do 该语句用于Do…Loop循环,具体用法同Exit For一样。

十四:一维数组
Dim A(5)As Integer 等价于 Dim A%(5)
定义了一个一维数组,名字为y,类型为Integer,占据6个(0~5)整型变量的空间。

十五:二维数组
Dim T(2,3)As Integer
定义了一个二维数组,名字为T,类型为Integer,该数组有3行(0~2)4列(0~3),占据12(3×4)个整型变量的空间

十六:子过程
Sub jieCheng(n%,p&)
On Error GoTo Click_Err
Dim i%
p = 1

For i = 1 To n
p = p * i
Next i

Click_Err:
Resume Next
End Sub

子过程的调用
Dim a&,b&,c&,d&
Call jieCheng(7,a)
Call jieCheng(11,b)
Call jieCheng(10,c)

d = a + b-c

Print "7!+11!-10!=";d

十七:函数过程
例子一:
Function jieCheng &(n%)
On Error GoTo Click_Err
Dim i%
jch = 1

For i = 1 To n
jch = jch * i
Next i

Click_Err:
Resume Next
End Function

函数过程的调用
Dim d&
d = jieCheng(7)+ jieCheng(11)-jieCheng(10)
Print "7!+11!-10!=";d

例子二:
Function sum%(b%())
On Error GoTo Click_Err
Dim i%

For i = LBound(b)To UBound(b)
If b(i)< 0 Then
sum = sum + b(i)
End If
Next i
Click_Err:
Resume Next
End Function

函数过程的调用
Dim a%(10),s%,i%

For i = 1 To 10
a(i)= Int(Rnd * 100)- 50
Print a(i);
Next i
Print
s = sum(a())
Print "数组中的负元素之和为:";s

技巧一:格式转换
CStr(value)
将value转换成string型

CInt(value)
将value转换成int形

CLng(value)
将value转换成long形

注:CBool,CByte,CDate,CVar,CVDate,CVErr,用法类似

技巧二:格式化
Format$( value, "0000")
将value格式化成4位

Format(Now, "yyyymmdd")
将当前日期格式化成yyyymmdd格式

Format(Now - 1, "yyyy-mm-dd")
将当前日期减一天后格式化成yyyy-mm-dd格式

2000年5月30日星期二

(视频)Oracle10g安装

float转varchar防科学计数法

举例:
SELECT CAST(CAST(Quantum AS decimal(18,0)) AS varchar) AS Quantum

解说:
CAST 和 CONVERT
将某种数据类型的表达式显式转换为另一种数据类型。CAST 和 CONVERT 提供相似的功能。

语法
使用 CAST:

CAST ( expression AS data_type )

使用 CONVERT:

CONVERT (data_type[(length)], expression [, style])

参数
expression

是任何有效的 Microsoft® SQL Server™ 表达式。有关更多信息,请参见表达式。

data_type

目标系统所提供的数据类型,包括 bigint 和 sql_variant。不能使用用户定义的数据类型。有关可用的数据类型的更多信息,请参见数据类型。

length

nchar、nvarchar、char、varchar、binary 或 varbinary 数据类型的可选参数。

2000年5月26日星期五

用pl-sql导入数据的技巧

方法:
1: 打开并登陆 pl-sql。

2: 选择Tools => Data Generator 弹出操作界面,界面说明如下:
Owner: 选择数据库拥有者。
Table: 选择你将要操作的表。
Number of records: 输入将要插入数据的数量。

3: 在下面表格对应字段(Data)栏里输入“导入数据的规则”(见后面介绍)。

4: 点击最左下方的“齿轮状”图标(Create Data In DB)产生数据。(完成)

注:
如果已有规则尚不能满足用户需求,则用户可根据自己的需要自定义规则。
自定义规则方法如下:
1:点击界面左侧“扳子状”图标。
2:在弹出界面的右下方(User Definitions)区里输入自定义规则

如:
在item栏里输入w; 在value 栏里输入 abc012 。
点“Apply” =〉“OK” 则自定义规则完成。
以后在其他规则中使用 ‘w’ 便可随机产生(abc012)中的一位字母。(完成)

说明:
[]代表规则
[a]: (随机从a-z中产生一位小写字母)
[A]: (随机从A-Z中产生一位大写字母)
[@]: (随机从A-Z 或 a-z中产生一位字母)
[#]: (随机从A-Z 或 a-z或0-9中产生一位字母)
[*]: (随机从#33-#126中产生一位 ASCII 字母)
[0]: (随机从0-9中产生一位数字)
[1]: (随机从1-9中产生一位数字)
[9]: (随机从0-9中产生一位数字)

[SQL(to_date(‘12/12/2006’,‘dd/mm/yyyy’))] : (执行SQL方法)
Sequence(1) : (从1开始产生一个时序序列。注:不加[])
Random(1,5) : (产生一个从1-5的随机数。注:不加[])
Email : (随机产生一条合法的邮件地址。注:不加[])

举例如下:
[aaaaaw] +’012’+’ ’+’abc’
[AAAAA]
Email(产生合法邮件地址)
[1] + ‘.’ [01](随机产生浮点数)
SQL(to_date(‘12/12/2006’,‘dd/mm/yyyy’))(执行SQL产生日期)
[Aaa00] (产生字母数字组合串)
[AA ‘-’ 1000] [Aa(5..15) ' ' Aa(8..20)]
Uppercase([Aa(5..15) ' ' Aa(8..20)]) (所有字母变大写)
[Aaaa(5..15)] + sequence(2)(产生字母+时序组合串)
LowerCase([Aa(5..15) ‘ ’ Aa(8..20)])(所有字母变小写)
Random(1,5) (产生1-5随机数)
Sequence(1, 1)(序列,参数2为步长,可省略,省略后默认为1)
InitCaps( List(select AAA from test2) )(从List任选并使首字母大写)
Signal(Min, Max, Delta, Noise):产生随机数,包括小数

例: Signal(-10, 20, 0.1, 0.1)
Random([Min], Max):产生随机整数或日期

例: Random('12/12/2006')
Sequence(Start, [Inc], [WithinParent]):产生时序数

例: sequence(2,1)(参数2可省略,省略后默认为1)
List(‘item’(weight), ‘item’(weight), ...):从列表或查询结果中取值

例: List('CLERK'(50), 'SALESMAN'(30), 'MANAGER'(10))
Text([Style], MaxCharacters, [WordsPerLine, LinesPerParagraph])
产生Text

Style: LorumIpsum (default), English, German or Japanese. It can also be a character set like [aA],

The specified size can be a number or a range (min..max).

例: Text(‘Japanese’,5000)
File(path, path, ...):从指定目录中读取文件

例: File('d: images *.bmp')
Firstname :General list of first names
Lastname :General list of last names
Company :Company names (random list of existing companies)
Address1 :Address line 1
Address2 :Address line 2
ZIP:ZIP code
City :City
State :State
Country :Country
Email: (related to Firstname, Lastname and Country)

常用oracle函数

SQL中的单记录函数
1.ASCII
返回与指定的字符对应的十进制数;
SQL> select ascii('A') A,ascii('a') a,ascii('0') zero,ascii(' ') space from dual;
A A ZERO SPACE
--------- --------- --------- ---------
65 97 48 32
2.CHR
给出整数,返回对应的字符;
SQL> select chr(54740) zhao,chr(65) chr65 from dual;
ZH C
-- -
赵 A
3.CONCAT
连接两个字符串;
SQL> select concat('010-','88888888')||'转23' 高乾竞电话 from dual;
高乾竞电话
----------------
010-88888888转23
4.INITCAP
返回字符串并将字符串的第一个字母变为大写;
SQL> select initcap('smith') upp from dual;
UPP
-----
Smith
5.INSTR(C1,C2,I,J)
在一个字符串中搜索指定的字符,返回发现指定的字符的位置;
C1 被搜索的字符串
C2 希望搜索的字符串
I 搜索的开始位置,默认为1
J 出现的位置,默认为1
SQL> select instr('oracle traning','ra',1,2) instring from dual;
INSTRING
---------
9
6.LENGTH
返回字符串的长度;
SQL> select name,length(name),addr,length(addr),sal,length(to_char(sal)) from gao.nchar_tst;
NAME LENGTH(NAME) ADDR LENGTH(ADDR) SAL LENGTH(TO_CHAR(SAL))
------ ------------ ---------------- ------------ --------- --------------------
高乾竞    3 北京市海锭区   6 9999.99 7
7.LOWER
返回字符串,并将所有的字符小写
SQL> select lower('AaBbCcDd')AaBbCcDd from dual;
AABBCCDD
--------
aabbccdd
8.UPPER
返回字符串,并将所有的字符大写
SQL> select upper('AaBbCcDd') upper from dual;
UPPER
--------
AABBCCDD
9.RPAD和LPAD(粘贴字符)
RPAD 在列的右边粘贴字符
LPAD 在列的左边粘贴字符
SQL> select lpad(rpad('gao',10,'*'),17,'*')from dual;
LPAD(RPAD('GAO',1
-----------------
*******gao*******
不够字符则用*来填满
10.LTRIM和RTRIM
LTRIM 删除左边出现的字符串
RTRIM 删除右边出现的字符串
SQL> select ltrim(rtrim(' gao qian jing ',' '),' ') from dual;
LTRIM(RTRIM('
-------------
gao qian jing
11.SUBSTR(string,start,count)
取子字符串,从start开始,取count个
SQL> select substr('13088888888',3,8) from dual;
SUBSTR('
--------
08888888
12.REPLACE('string','s1','s2')
string 希望被替换的字符或变量
s1 被替换的字符串
s2 要替换的字符串
SQL> select replace('he love you','he','i') from dual;
REPLACE('H
----------
i love you
13.SOUNDEX
返回一个与给定的字符串读音相同的字符串
SQL> create table table1(xm varchar(8));
SQL> insert into table1 values('weather');
SQL> insert into table1 values('wether');
SQL> insert into table1 values('gao');
SQL> select xm from table1 where soundex(xm)=soundex('weather');
XM
--------
weather
wether
14.TRIM('s' from 'string')
LEADING 剪掉前面的字符
TRAILING 剪掉后面的字符
如果不指定,默认为空格符
15.ABS
返回指定值的绝对值
SQL> select abs(100),abs(-100) from dual;
ABS(100) ABS(-100)
--------- ---------
100 100
16.ACOS
给出反余弦的值
SQL> select acos(-1) from dual;
ACOS(-1)
---------
3.1415927
17.ASIN
给出反正弦的值
SQL> select asin(0.5) from dual;
ASIN(0.5)
---------
.52359878
18.ATAN
返回一个数字的反正切值
SQL> select atan(1) from dual;
ATAN(1)
---------
.78539816
19.CEIL
返回大于或等于给出数字的最小整数
SQL> select ceil(3.1415927) from dual;
CEIL(3.1415927)
---------------
4
20.COS
返回一个给定数字的余弦
SQL> select cos(-3.1415927) from dual;
COS(-3.1415927)
---------------
-1
21.COSH
返回一个数字反余弦值
SQL> select cosh(20) from dual;
COSH(20)
---------
242582598
22.EXP
返回一个数字e的n次方根
SQL> select exp(2),exp(1) from dual;
EXP(2) EXP(1)
--------- ---------
7.3890561 2.7182818
23.FLOOR
对给定的数字取整数
SQL> select floor(2345.67) from dual;
FLOOR(2345.67)
--------------
2345
24.LN
返回一个数字的对数值
SQL> select ln(1),ln(2),ln(2.7182818) from dual;
LN(1) LN(2) LN(2.7182818)
--------- --------- -------------
0 .69314718 .99999999
25.LOG(n1,n2)
返回一个以n1为底n2的对数
SQL> select log(2,1),log(2,4) from dual;
LOG(2,1) LOG(2,4)
--------- ---------
0 2
26.MOD(n1,n2)
返回一个n1除以n2的余数
SQL> select mod(10,3),mod(3,3),mod(2,3) from dual;
MOD(10,3) MOD(3,3) MOD(2,3)
--------- --------- ---------
1 0 2
27.POWER
返回n1的n2次方根
SQL> select power(2,10),power(3,3) from dual;
POWER(2,10) POWER(3,3)
----------- ----------
1024 27
28.ROUND和TRUNC
按照指定的精度进行舍入
SQL> select round(55.5),round(-55.4),trunc(55.5),trunc(-55.5) from dual;
ROUND(55.5) ROUND(-55.4) TRUNC(55.5) TRUNC(-55.5)
----------- ------------ ----------- ------------
56 -55 55 -55
29.SIGN
取数字n的符号,大于0返回1,小于0返回-1,等于0返回0
SQL> select sign(123),sign(-100),sign(0) from dual;
SIGN(123) SIGN(-100) SIGN(0)
--------- ---------- ---------
1 -1 0
30.SIN
返回一个数字的正弦值
SQL> select sin(1.57079) from dual;
SIN(1.57079)
------------
1
31.SIGH
返回双曲正弦的值
SQL> select sin(20),sinh(20) from dual;
SIN(20) SINH(20)
--------- ---------
.91294525 242582598
32.SQRT
返回数字n的根
SQL> select sqrt(64),sqrt(10) from dual;
SQRT(64) SQRT(10)
--------- ---------
8 3.1622777
33.TAN
返回数字的正切值
SQL> select tan(20),tan(10) from dual;
TAN(20) TAN(10)
--------- ---------
2.2371609 .64836083
34.TANH
返回数字n的双曲正切值
SQL> select tanh(20),tan(20) from dual;
TANH(20) TAN(20)
--------- ---------
1 2.2371609
35.TRUNC
按照指定的精度截取一个数
SQL> select trunc(124.1666,-2) trunc1,trunc(124.16666,2) from dual;
TRUNC1 TRUNC(124.16666,2)
--------- ------------------
100 124.16
36.ADD_MONTHS
增加或减去月份
SQL> select to_char(add_months(to_date('199912','yyyymm'),2),'yyyymm') from dual;
TO_CHA
------
200002
SQL> select to_char(add_months(to_date('199912','yyyymm'),-2),'yyyymm') from dual;
TO_CHA
------
199910
37.LAST_DAY
返回日期的最后一天
SQL> select to_char(sysdate,'yyyy.mm.dd'),to_char((sysdate)+1,'yyyy.mm.dd') from dual;
TO_CHAR(SY TO_CHAR((S
---------- ----------
2004.05.09 2004.05.10
SQL> select last_day(sysdate) from dual;
LAST_DAY(S
----------
31-5月 -04
38.MONTHS_BETWEEN(date2,date1)
给出date2-date1的月份
SQL> select months_between('19-12月-1999','19-3月-1999') mon_between from dual;
MON_BETWEEN
-----------
9
SQL>selectmonths_between(to_date('2000.05.20','yyyy.mm.dd'),to_date('2005.05.20','yyyy.mm.dd')) mon_betw from dual;
MON_BETW
---------
-60
39.NEW_TIME(date,'this','that')
给出在this时区=other时区的日期和时间
SQL> select to_char(sysdate,'yyyy.mm.dd hh24:mi:ss') bj_time,to_char(new_time
2 (sysdate,'PDT','GMT'),'yyyy.mm.dd hh24:mi:ss') los_angles from dual;
BJ_TIME LOS_ANGLES
------------------- -------------------
2004.05.09 11:05:32 2004.05.09 18:05:32
40.NEXT_DAY(date,'day')
给出日期date和星期x之后计算下一个星期的日期
SQL> select next_day('18-5月-2001','星期五') next_day from dual;
NEXT_DAY
----------
25-5月 -01
41.SYSDATE
用来得到系统的当前日期
SQL> select to_char(sysdate,'dd-mm-yyyy day') from dual;
TO_CHAR(SYSDATE,'
-----------------
09-05-2004 星期日
trunc(date,fmt)按照给出的要求将日期截断,如果fmt='mi'表示保留分,截断秒
SQL> select to_char(trunc(sysdate,'hh'),'yyyy.mm.dd hh24:mi:ss') hh,
2 to_char(trunc(sysdate,'mi'),'yyyy.mm.dd hh24:mi:ss') hhmm from dual;
HH HHMM
------------------- -------------------
2004.05.09 11:00:00 2004.05.09 11:17:00
42.CHARTOROWID
将字符数据类型转换为ROWID类型
SQL> select rowid,rowidtochar(rowid),ename from scott.emp;
ROWID ROWIDTOCHAR(ROWID) ENAME
------------------ ------------------ ----------
AAAAfKAACAAAAEqAAA AAAAfKAACAAAAEqAAA SMITH
AAAAfKAACAAAAEqAAB AAAAfKAACAAAAEqAAB ALLEN
AAAAfKAACAAAAEqAAC AAAAfKAACAAAAEqAAC WARD
AAAAfKAACAAAAEqAAD AAAAfKAACAAAAEqAAD JONES
43.CONVERT(c,dset,sset)
将源字符串 sset从一个语言字符集转换到另一个目的dset字符集
SQL> select convert('strutz','we8hp','f7dec') "conversion" from dual;
conver
------
strutz
44.HEXTORAW
将一个十六进制构成的字符串转换为二进制
45.RAWTOHEXT
将一个二进制构成的字符串转换为十六进制
46.ROWIDTOCHAR
将ROWID数据类型转换为字符类型
47.TO_CHAR(date,'format')
SQL> select to_char(sysdate,'yyyy/mm/dd hh24:mi:ss') from dual;
TO_CHAR(SYSDATE,'YY
-------------------
2004/05/09 21:14:41
48.TO_DATE(string,'format')
将字符串转化为ORACLE中的一个日期
49.TO_MULTI_BYTE
将字符串中的单字节字符转化为多字节字符
SQL> select to_multi_byte('高') from dual;
TO
--

50.TO_NUMBER
将给出的字符转换为数字
SQL> select to_number('1999') year from dual;
YEAR
---------
1999
51.BFILENAME(dir,file)
指定一个外部二进制文件
SQL>insert into file_tb1 values(bfilename('lob_dir1','image1.gif'));
52.CONVERT('x','desc','source')
将x字段或变量的源source转换为desc
SQL> select sid,serial#,username,decode(command,
2 0,'none',
3 2,'insert',
4 3,
5 'select',
6 6,'update',
7 7,'delete',
8 8,'drop',
9 'other') cmd from v$session where type!='background';
SID SERIAL# USERNAME CMD
   --------- --------- ------------------------------ ------
1 1 none
2 1 none
3 1 none
4 1 none
5 1 none
6 1 none
7 1275 none
8 1275   none
9 20 GAO select
10 40 GAO none
53.DUMP(s,fmt,start,length)
DUMP函数以fmt指定的内部数字格式返回一个VARCHAR2类型的值
SQL> col global_name for a30
SQL> col dump_string for a50
SQL> set lin 200
SQL> select global_name,dump(global_name,1017,8,5) dump_string from global_name;
GLOBAL_NAME DUMP_STRING
------------------------------ --------------------------------------------------
ORACLE.WORLD Typ=1 Len=12 CharacterSet=ZHS16GBK: W,O,R,L,D
54.EMPTY_BLOB()和EMPTY_CLOB()
这两个函数都是用来对大数据类型字段进行初始化操作的函数
55.GREATEST
返回一组表达式中的最大值,即比较字符的编码大小.
SQL> select greatest('AA','AB','AC') from dual;
GR
--
AC
SQL> select greatest('啊','安','天') from dual;
GR
--

56.LEAST
返回一组表达式中的最小值
SQL> select least('啊','安','天') from dual;
LE
--

57.UID
返回标识当前用户的唯一整数
SQL> show user
USER 为"GAO"
SQL> select username,user_id from dba_users where user_id=uid;
USERNAME USER_ID
------------------------------ ---------
GAO 25
58.USER
返回当前用户的名字
SQL> select user from dual;
USER
------------------------------
GAO
59.USEREVN
返回当前用户环境的信息,opt可以是:
ENTRYID,SESSIONID,TERMINAL,ISDBA,LABLE,LANGUAGE,CLIENT_INFO,LANG,VSIZE
ISDBA 查看当前用户是否是DBA如果是则返回true
SQL> select userenv('isdba') from dual;
USEREN
------
FALSE
SQL> select userenv('isdba') from dual;
USEREN
------
TRUE
SESSION
返回会话标志
SQL> select userenv('sessionid') from dual;
USERENV('SESSIONID')
--------------------
152
ENTRYID
返回会话人口标志
SQL> select userenv('entryid') from dual;
USERENV('ENTRYID')
------------------
0
INSTANCE
返回当前INSTANCE的标志
SQL> select userenv('instance') from dual;
USERENV('INSTANCE')
-------------------
1
LANGUAGE
返回当前环境变量
SQL> select userenv('language') from dual;
USERENV('LANGUAGE')
----------------------------------------------------
SIMPLIFIED CHINESE_CHINA.ZHS16GBK
LANG
返回当前环境的语言的缩写
SQL> select userenv('lang') from dual;
USERENV('LANG')
----------------------------------------------------
ZHS
TERMINAL
返回用户的终端或机器的标志
SQL> select userenv('terminal') from dual;
USERENV('TERMINA
----------------
GAO
VSIZE(X)
返回X的大小(字节)数
SQL> select vsize(user),user from dual;
VSIZE(USER) USER
----------- ------------------------------
6 SYSTEM
60.AVG(DISTINCT|ALL)
all表示对所有的值求平均值,distinct只对不同的值求平均值
SQLWKS> create table table3(xm varchar(8),sal number(7,2));
语句已处理。
SQLWKS> insert into table3 values('gao',1111.11);
SQLWKS> insert into table3 values('gao',1111.11);
SQLWKS> insert into table3 values('zhu',5555.55);
SQLWKS> commit;
SQL> select avg(distinct sal) from gao.table3;
AVG(DISTINCTSAL)
----------------
3333.33
SQL> select avg(all sal) from gao.table3;
AVG(ALLSAL)
-----------
2592.59
61.MAX(DISTINCT|ALL)
求最大值,ALL表示对所有的值求最大值,DISTINCT表示对不同的值求最大值,相同的只取一次
SQL> select max(distinct sal) from scott.emp;
MAX(DISTINCTSAL)
----------------
5000
62.MIN(DISTINCT|ALL)
求最小值,ALL表示对所有的值求最小值,DISTINCT表示对不同的值求最小值,相同的只取一次
SQL> select min(all sal) from gao.table3;
MIN(ALLSAL)
-----------
1111.11
63.STDDEV(distinct|all)
求标准差,ALL表示对所有的值求标准差,DISTINCT表示只对不同的值求标准差
SQL> select stddev(sal) from scott.emp;
STDDEV(SAL)
-----------
1182.5032
SQL> select stddev(distinct sal) from scott.emp;
STDDEV(DISTINCTSAL)
-------------------
1229.951
64.VARIANCE(DISTINCT|ALL)
求协方差
SQL> select variance(sal) from scott.emp;
VARIANCE(SAL)
 -------------
1398313.9
65.GROUP BY
主要用来对一组数进行统计
SQL> select deptno,count(*),sum(sal) from scott.emp group by deptno;
DEPTNO COUNT(*) SUM(SAL)
  --------- --------- ---------
10 3 8750
20 5 10875
30 6 9400
66.HAVING
对分组统计再加限制条件
SQL> select deptno,count(*),sum(sal) from scott.emp group by deptno having count(*)>=5;
DEPTNO COUNT(*) SUM(SAL)
  --------- --------- ---------
20 5 10875
30 6 9400
SQL> select deptno,count(*),sum(sal) from scott.emp having count(*)>=5 group by deptno ;
DEPTNO COUNT(*) SUM(SAL)
  --------- --------- ---------
20 5 10875
30 6 9400
67.ORDER BY
用于对查询到的结果进行排序输出
SQL> select deptno,ename,sal from scott.emp order by deptno,sal desc;
DEPTNO ENAME SAL
   --------- ---------- ---------
10 KING 5000
10 CLARK 2450
10 MILLER 1300
20 SCOTT 3000
20 FORD 3000
20 JONES 2975
20 ADAMS 1100
20 SMITH 800
30 BLAKE 2850
30 ALLEN 1600
30 TURNER 1500
30 WARD 1250
30 MARTIN 1250
30 JAMES 950 

SQL*PLUS命令的使用大全

Oracle的sql*plus是与oracle进行交互的客户端工具。在sql*plus中,可以运行sql*plus命令与sql*plus语句。
我们通常所说的DML、DDL、DCL语句都是sql*plus语句,它们执行完后,都可以保存在一个被称为sql buffer的内存区域中,并且只能保存一条最近执行的sql语句,我们可以对保存在sql buffer中的sql 语句进行修改,然后再次执行,sql*plus一般都与数据库打交道。
除了sql*plus语句,在sql*plus中执行的其它语句我们称之为sql*plus命令。它们执行完后,不保存在sql buffer的内存区域中,它们一般用来对输出的结果进行格式化显示,以便于制作报表。
下面就介绍一下一些常用的sql*plus命令:

1. 执行一个SQL脚本文件
SQL>start file_name
SQL>@ file_name
我们可以将多条sql语句保存在一个文本文件中,这样当要执行这个文件中的所有的sql语句时,用上面的任一命令即可,这类似于dos中的批处理。

@与@@的区别是什么?
@等于start命令,用来运行一个sql脚本文件。
@命令调用当前目录下的,或指定全路径,或可以通过SQLPATH环境变量搜寻到的脚本文件。该命令使用是一般要指定要执行的文件的全路径,否则从缺省路径(可用SQLPATH变量指定)下读取指定的文件。
@@用在sql脚本文件中,用来说明用@@执行的sql脚本文件与@@所在的文件在同一目录下,而不用指定要执行sql脚本文件的全路径,也不是从SQLPATH环境变量指定的路径中寻找sql脚本文件,该命令一般用在脚本文件中。
如:在c:\temp目录下有文件start.sql和nest_start.sql,start.sql脚本文件的内容为:
@@nest_start.sql - - 相当于@ c:\temp\nest_start.sql
则我们在sql*plus中,这样执行:
SQL> @ c:\temp\start.sql


2. 对当前的输入进行编辑
SQL>edit

3. 重新运行上一次运行的sql语句
SQL>/

4. 将显示的内容输出到指定文件
SQL> SPOOL file_name
在屏幕上的所有内容都包含在该文件中,包括你输入的sql语句。

5. 关闭spool输出
SQL> SPOOL OFF
只有关闭spool输出,才会在输出文件中看到输出的内容。

6.显示一个表的结构
SQL> desc table_name

7. COL命令:
主要格式化列的显示形式。
该命令有许多选项,具体如下:
COL[UMN] [{ column|expr} [ option ...]]
Option选项可以是如下的子句:
ALI[AS] alias
CLE[AR]
FOLD_A[FTER]
FOLD_B[EFORE]
FOR[MAT] format
HEA[DING] text
JUS[TIFY] {L[EFT]|C[ENTER]|C[ENTRE]|R[IGHT]}
LIKE { expr|alias}
NEWL[INE]
NEW_V[ALUE] variable
NOPRI[NT]|PRI[NT]
NUL[L] text
OLD_V[ALUE] variable
ON|OFF
WRA[PPED]|WOR[D_WRAPPED]|TRU[NCATED]

1). 改变缺省的列标题
COLUMN column_name HEADING column_heading
For example:
Sql>select * from dept;
DEPTNO DNAME LOC
---------- ---------------------------- ---------
10 ACCOUNTING NEW YORK
sql>col LOC heading location
sql>select * from dept;
DEPTNO DNAME location
--------- ---------------------------- -----------
10 ACCOUNTING NEW YORK

2). 将列名ENAME改为新列名EMPLOYEE NAME并将新列名放在两行上:
Sql>select * from emp
Department name Salary
---------- ---------- ----------
10 aaa 11
SQL> COLUMN ENAME HEADING ’Employee|Name’
Sql>select * from emp
Employee
Department name Salary
---------- ---------- ----------
10 aaa 11
note: the col heading turn into two lines from one line.

3). 改变列的显示长度:
FOR[MAT] format
Sql>select empno,ename,job from emp;
EMPNO ENAME JOB
---------- ---------- ---------
7369 SMITH CLERK
7499 ALLEN SALESMAN
7521 WARD SALESMAN
Sql> col ename format a40
EMPNO ENAME JOB
---------- ---------------------------------------- ---------
7369 SMITH CLERK
7499 ALLEN SALESMAN
7521 WARD SALESMAN

4). 设置列标题的对齐方式
JUS[TIFY] {L[EFT]|C[ENTER]|C[ENTRE]|R[IGHT]}
SQL> col ename justify center
SQL> /
EMPNO ENAME JOB
---------- ---------------------------------------- ---------
7369 SMITH CLERK
7499 ALLEN SALESMAN
7521 WARD SALESMAN
对于NUMBER型的列,列标题缺省在右边,其它类型的列标题缺省在左边

5). 不让一个列显示在屏幕上
NOPRI[NT]|PRI[NT]
SQL> col job noprint
SQL> /
EMPNO ENAME
---------- ----------------------------------------
7369 SMITH
7499 ALLEN
7521 WARD

6). 格式化NUMBER类型列的显示:
SQL> COLUMN SAL FORMAT $99,990
SQL> /
Employee
Department Name Salary Commission
---------- ---------- --------- ----------
30 ALLEN $1,600 300

7). 显示列值时,如果列值为NULL值,用text值代替NULL值
COMM NUL[L] text
SQL>COL COMM NUL[L] text

8). 设置一个列的回绕方式
WRA[PPED]|WOR[D_WRAPPED]|TRU[NCATED]
COL1
--------------------
HOW ARE YOU?

SQL>COL COL1 FORMAT A5
SQL>COL COL1 WRAPPED
COL1
-----
HOW A
RE YO
U?

SQL> COL COL1 WORD_WRAPPED
COL1
-----
HOW
ARE
YOU?

SQL> COL COL1 WORD_WRAPPED
COL1
-----
HOW A

9). 显示列的当前的显示属性值
SQL> COLUMN column_name

10). 将所有列的显示属性设为缺省值
SQL> CLEAR COLUMNS

8. 屏蔽掉一个列中显示的相同的值
BREAK ON break_column
SQL> BREAK ON DEPTNO
SQL> SELECT DEPTNO, ENAME, SAL
FROM EMP
WHERE SAL < 2500
ORDER BY DEPTNO;
DEPTNO ENAME SAL
---------- ----------- ---------
10 CLARK 2450
MILLER 1300
20 SMITH 800
ADAMS 1100

9. 在上面屏蔽掉一个列中显示的相同的值的显示中,每当列值变化时在值变化之前插入n个空行。
BREAK ON break_column SKIP n

SQL> BREAK ON DEPTNO SKIP 1
SQL> /
DEPTNO ENAME SAL
---------- ----------- ---------
10 CLARK 2450
MILLER 1300

20 SMITH 800
ADAMS 1100

10. 显示对BREAK的设置
SQL> BREAK

11. 删除6、7的设置
SQL> CLEAR BREAKS

12. Set 命令:
该命令包含许多子命令:
SET system_variable value
system_variable value 可以是如下的子句之一:
APPI[NFO]{ON|OFF|text}
ARRAY[SIZE] {15|n}
AUTO[COMMIT]{ON|OFF|IMM[EDIATE]|n}
AUTOP[RINT] {ON|OFF}
AUTORECOVERY [ON|OFF]
AUTOT[RACE] {ON|OFF|TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
BLO[CKTERMINATOR] {.|c}
CMDS[EP] {;|c|ON|OFF}
COLSEP {_|text}
COM[PATIBILITY]{V7|V8|NATIVE}
CON[CAT] {.|c|ON|OFF}
COPYC[OMMIT] {0|n}
COPYTYPECHECK {ON|OFF}
DEF[INE] {&|c|ON|OFF}
DESCRIBE [DEPTH {1|n|ALL}][LINENUM {ON|OFF}][INDENT {ON|OFF}]
ECHO {ON|OFF}
EDITF[ILE] file_name[.ext]
EMB[EDDED] {ON|OFF}
ESC[APE] {\|c|ON|OFF}
FEED[BACK] {6|n|ON|OFF}
FLAGGER {OFF|ENTRY |INTERMED[IATE]|FULL}
FLU[SH] {ON|OFF}
HEA[DING] {ON|OFF}
HEADS[EP] {||c|ON|OFF}
INSTANCE [instance_path|LOCAL]
LIN[ESIZE] {80|n}
LOBOF[FSET] {n|1}
LOGSOURCE [pathname]
LONG {80|n}
LONGC[HUNKSIZE] {80|n}
MARK[UP] HTML [ON|OFF] [HEAD text] [BODY text] [ENTMAP {ON|OFF}] [SPOOL
{ON|OFF}] [PRE[FORMAT] {ON|OFF}]
NEWP[AGE] {1|n|NONE}
NULL text
NUMF[ORMAT] format
NUM[WIDTH] {10|n}
PAGES[IZE] {24|n}
PAU[SE] {ON|OFF|text}
RECSEP {WR[APPED]|EA[CH]|OFF}
RECSEPCHAR {_|c}
SERVEROUT[PUT] {ON|OFF} [SIZE n] [FOR[MAT] {WRA[PPED]|WOR[D_
WRAPPED]|TRU[NCATED]}]
SHIFT[INOUT] {VIS[IBLE]|INV[ISIBLE]}
SHOW[MODE] {ON|OFF}
SQLBL[ANKLINES] {ON|OFF}
SQLC[ASE] {MIX[ED]|LO[WER]|UP[PER]}
SQLCO[NTINUE] {> |text}
SQLN[UMBER] {ON|OFF}
SQLPRE[FIX] {#|c}
SQLP[ROMPT] {SQL>|text}
SQLT[ERMINATOR] {;|c|ON|OFF}
SUF[FIX] {SQL|text}
TAB {ON|OFF}
TERM[OUT] {ON|OFF}
TI[ME] {ON|OFF}
TIMI[NG] {ON|OFF}
TRIM[OUT] {ON|OFF}
TRIMS[POOL] {ON|OFF}
UND[ERLINE] {-|c|ON|OFF}
VER[IFY] {ON|OFF}
WRA[P] {ON|OFF}

1). 设置当前session是否对修改的数据进行自动提交
SQL>SET AUTO[COMMIT] {ON|OFF|IMM[EDIATE]| n}

2).在用start命令执行一个sql脚本时,是否显示脚本中正在执行的SQL语句
SQL> SET ECHO {ON|OFF}

3).是否显示当前sql语句查询或修改的行数
SQL> SET FEED[BACK] {6|n|ON|OFF}
默认只有结果大于6行时才显示结果的行数。如果set feedback 1 ,则不管查询到多少行都返回。当为off 时,一律不显示查询的行数

4).是否显示列标题
SQL> SET HEA[DING] {ON|OFF}
当set heading off 时,在每页的上面不显示列标题,而是以空白行代替

5).设置一行可以容纳的字符数
SQL> SET LIN[ESIZE] {80|n}
如果一行的输出内容大于设置的一行可容纳的字符数,则折行显示。

6).设置页与页之间的分隔
SQL> SET NEWP[AGE] {1|n|NONE}
当set newpage 0 时,会在每页的开头有一个小的黑方框。
当set newpage n 时,会在页和页之间隔着n个空行。
当set newpage none 时,会在页和页之间没有任何间隔。

7).显示时,用text值代替NULL值
SQL> SET NULL text

8).设置一页有多少行数
SQL> SET PAGES[IZE] {24|n}
如果设为0,则所有的输出内容为一页并且不显示列标题

9).是否显示用DBMS_OUTPUT.PUT_LINE包进行输出的信息。
SQL> SET SERVEROUT[PUT] {ON|OFF}
在编写存储过程时,我们有时会用dbms_output.put_line将必要的信息输出,以便对存储过程进行调试,只有将serveroutput变量设为on后,信息才能显示在屏幕上。

10).当SQL语句的长度大于LINESIZE时,是否在显示时截取SQL语句。
SQL> SET WRA[P] {ON|OFF}
当输出的行的长度大于设置的行的长度时(用set linesize n命令设置),当set wrap on时,输出行的多于的字符会另起一行显示,否则,会将输出行的多于字符切除,不予显示。

11).是否在屏幕上显示输出的内容,主要用与SPOOL结合使用。
SQL> SET TERM[OUT] {ON|OFF}
在用spool命令将一个大表中的内容输出到一个文件中时,将内容输出在屏幕上会耗费大量的时间,设置set termspool off后,则输出的内容只会保存在输出文件中,不会显示在屏幕上,极大的提高了spool的速度。

12).将SPOOL输出中每行后面多余的空格去掉
SQL> SET TRIMS[OUT] {ON|OFF}

13)显示每个sql语句花费的执行时间
set TIMING {ON|OFF}

14). 遇到空行时不认为语句已经结束,从后续行接着读入。
SET SQLBLANKLINES ON
Sql*plus中, 不允许sql语句中间有空行, 这在从其它地方拷贝脚本到sql*plus中执行时很麻烦. 比如下面的脚本:
select deptno, empno, ename
from emp

where empno = '7788';
如果拷贝到sql*plus中执行, 就会出现错误。这个命令可以解决该问题

15).设置DBMS_OUTPUT的输出
SET SERVEROUTPUT ON BUFFER 20000
用dbms_output.put_line('strin_content');可以在存储过程中输出信息,对存储过程进行调试
如果想让dbms_output.put_line(' abc');的输出显示为:
SQL> abc,而不是SQL>abc,则在SET SERVEROUTPUT ON后加format wrapped参数。

16). 输出的数据为html格式
set markup html
在8.1.7版本(也许是816? 不太确定)以后, sql*plus中有一个set markup html的命令, 可以将sql*plus的输出以html格式展现.
注意其中的spool on, 当在屏幕上输出的时候, 我们看不出与不加spool on有什么区别, 但是当我们使用spool filename 输出到文件的时候, 会看到spool文件中出现了等tag.


14.修改sql buffer中的当前行中,第一个出现的字符串
C[HANGE] /old_value/new_value
SQL> l
1* select * from dept
SQL> c/dept/emp
1* select * from emp

15.编辑sql buffer中的sql语句
EDI[T]

16.显示sql buffer中的sql语句,list n显示sql buffer中的第n行,并使第n行成为当前行
L[IST] [n]

17.在sql buffer的当前行下面加一行或多行
I[NPUT]

18.将指定的文本加到sql buffer的当前行后面
A[PPEND]
SQL> select deptno,
2 dname
3 from dept;
DEPTNO DNAME
---------- --------------
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS

SQL> L 2
2* dname
SQL> a ,loc
2* dname,loc
SQL> L
1 select deptno,
2 dname,loc
3* from dept
SQL> /

DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON

19.将sql buffer中的sql语句保存到一个文件中
SAVE file_name

20.将一个文件中的sql语句导入到sql buffer中
GET file_name

21.再次执行刚才已经执行的sql语句
RUN
or
/

22.执行一个存储过程
EXECUTE procedure_name

23.在sql*plus中连接到指定的数据库
CONNECT user_name/passwd@db_alias

24.设置每个报表的顶部标题
TTITLE

25.设置每个报表的尾部标题
BTITLE

26.写一个注释
REMARK [text]

27.将指定的信息或一个空行输出到屏幕上
PROMPT [text]

28.将执行的过程暂停,等待用户响应后继续执行
PAUSE [text]

Sql>PAUSE Adjust paper and press RETURN to continue.

29.将一个数据库中的一些数据拷贝到另外一个数据库(如将一个表的数据拷贝到另一个数据库)
COPY {FROM database | TO database | FROM database TO database}
{APPEND|CREATE|INSERT|REPLACE} destination_table
[(column, column, column, ...)] USING query

sql>COPY FROM SCOTT/TIGER@HQ TO JOHN/CHROME@WEST
create emp_temp
USING SELECT * FROM EMP

30.不退出sql*plus,在sql*plus中执行一个操作系统命令:
HOST

Sql> host hostname
该命令在windows下可能被支持。

31.在sql*plus中,切换到操作系统命令提示符下,运行操作系统命令后,可以再次切换回sql*plus:
!

sql>!
$hostname
$exit
sql>

该命令在windows下不被支持。

32.显示sql*plus命令的帮助
HELP
如何安装帮助文件:
Sql>@ ?\sqlplus\admin\help\hlpbld.sql ?\sqlplus\admin\help\helpus.sql
Sql>help index

33.显示sql*plus系统变量的值或sql*plus环境变量的值
Syntax
SHO[W] option
where option represents one of the following terms or clauses:
system_variable
ALL
BTI[TLE]
ERR[ORS] [{FUNCTION|PROCEDURE|PACKAGE|PACKAGE BODY|
TRIGGER|VIEW|TYPE|TYPE BODY} [schema.]name]
LNO
PARAMETERS [parameter_name]
PNO
REL[EASE]
REPF[OOTER]
REPH[EADER]
SGA
SPOO[L]
SQLCODE
TTI[TLE]
USER

1) . 显示当前环境变量的值:
Show all

2) . 显示当前在创建函数、存储过程、触发器、包等对象的错误信息
Show error
当创建一个函数、存储过程等出错时,变可以用该命令查看在那个地方出错及相应的出错信息,进行修改后再次进行编译。

3) . 显示初始化参数的值:
show PARAMETERS [parameter_name]

4) . 显示数据库的版本:
show REL[EASE]

5) . 显示SGA的大小
show SGA

6). 显示当前的用户名
show user

34.查询一个用户下的对象
SQL>select * from tab;
SQL>select * from user_objects;

35.查询一个用户下的所有的表
SQL>select * from user_tables;

36.查询一个用户下的所有的索引
SQL>select * from user_indexes;


37. 定义一个用户变量
方法有两个:
a. define
b. COL[UMN] [{column|expr} NEW_V[ALUE] variable [NOPRI[NT]|PRI[NT]]
OLD_V[ALUE] variable [NOPRI[NT]|PRI[NT]]

下面对每种方式给予解释:
a. Syntax
DEF[INE] [variable]|[variable = text]
定义一个用户变量并且可以分配给它一个CHAR值。

assign the value MANAGER to the variable POS, type:
SQL> DEFINE POS = MANAGER

assign the CHAR value 20 to the variable DEPTNO, type:
SQL> DEFINE DEPTNO = 20

list the definition of DEPTNO, enter
SQL> DEFINE DEPTNO
―――――――――――――――
DEFINE DEPTNO = ”20” (CHAR)

定义了用户变量POS后,就可以在sql*plus中用&POS或&&POS来引用该变量的值,sql*plus不会再提示你给变量输入值。

b. COL[UMN] [{column|expr} NEW_V[ALUE] variable [NOPRI[NT]|PRI[NT]]
NEW_V[ALUE] variable
指定一个变量容纳查询出的列值。
例:column col_name new_value var_name noprint
select col_name from table_name where ……..
将下面查询出的col_name列的值赋给var_name变量.

一个综合的例子:
得到一个列值的两次查询之差(此例为10秒之内共提交了多少事务):
column redo_writes new_value commit_count

select sum(stat.value) redo_writes
from v$sesstat stat, v$statname sn
where stat.statistic# = sn.statistic#
and sn.name = 'user commits';

-- 等待一会儿(此处为10秒);
execute dbms_lock.sleep(10);

set veri off
select sum(stat.value) - &commit_count commits_added
from v$sesstat stat, v$statname sn
where stat.statistic# = sn.statistic#
and sn.name = 'user commits';


38. 定义一个绑定变量
VAR[IABLE] [variable [NUMBER|CHAR|CHAR (n)|NCHAR|NCHAR (n) |VARCHAR2 (n)|NVARCHAR2 (n)|CLOB|NCLOB|REFCURSOR]]
定义一个绑定变量,该变量可以在pl/sql中引用。
可以用print命令显示该绑定变量的信息。
如:
column inst_num heading "Inst Num" new_value inst_num format 99999;
column inst_name heading "Instance" new_value inst_name format a12;
column db_name heading "DB Name" new_value db_name format a12;
column dbid heading "DB Id" new_value dbid format 9999999999 just c;

prompt
prompt Current Instance
prompt ~~~~~~~~~~~~~~~~

select d.dbid dbid
, d.name db_name
, i.instance_number inst_num
, i.instance_name inst_name
from v$database d,
v$instance i;

variable dbid number;
variable inst_num number;
begin
:dbid := &dbid;
:inst_num := &inst_num;
end;
/
说明:
在sql*plus中,该绑定变量可以作为一个存储过程的参数,也可以在匿名PL/SQL块中直接引用。为了显示用VARIABLE命令创建的绑定变量的值,可以用print命令

注意:
绑定变量不同于变量:
1. 定义方法不同
2. 引用方法不同
绑定变量::variable_name
变量:&variable_name or &&variable_name
3.在sql*plus中,可以定义同名的绑定变量与用户变量,但是引用的方法不同。

39. &与&&的区别
&用来创建一个临时变量,每当遇到这个临时变量时,都会提示你输入一个值。
&&用来创建一个持久变量,就像用用define命令或带new_vlaue字句的column命令创建的持久变量一样。当用&&命令引用这个变量时,不会每次遇到该变量就提示用户键入值,而只是在第一次遇到时提示一次。

如,将下面三行语句存为一个脚本文件,运行该脚本文件,会提示三次,让输入deptnoval的值:
select count(*) from emp where deptno = &deptnoval;
select count(*) from emp where deptno = &deptnoval;
select count(*) from emp where deptno = &deptnoval;

将下面三行语句存为一个脚本文件,运行该脚本文件,则只会提示一次,让输入deptnoval的值:
select count(*) from emp where deptno = &&deptnoval;
select count(*) from emp where deptno = &&deptnoval;
select count(*) from emp where deptno = &&deptnoval;

40.在输入sql语句的过程中临时先运行一个sql*plus命令(摘自www.itpub.com)
#
有没有过这样的经历? 在sql*plus中敲了很长的命令后, 突然发现想不起某个列的名字了, 如果取消当前的命令,待查询后再重敲, 那太痛苦了. 当然你可以另开一个sql*plus窗口进行查询, 但这里提供的方法更简单.

比如说, 你想查工资大于4000的员工的信息, 输入了下面的语句:

SQL> select deptno, empno, ename
2 from emp
3 where
这时, 你发现你想不起来工资的列名是什么了.

这种情况下, 只要在下一行以#开头, 就可以执行一条sql*plus命令, 执行完后, 刚才的语句可以继续输入

SQL>> select deptno, empno, ename
2 from emp
3 where
6 #desc emp
Name Null? Type
----------------------------------------- -------- --------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)

6 sal > 4000;

DEPTNO EMPNO ENAME
---------- ---------- ----------
10 7839 KING

41. SQLPlus中的快速复制和粘贴技巧(摘自www.cnoug.org)
1) 鼠标移至想要复制内容的开始
2) 用右手食指按下鼠标左键
3) 向想要复制内容的另一角拖动鼠标,与Word中选取内容的方法一样
4) 内容选取完毕后(所选内容全部反显),鼠标左键按住不动,用右手中指按鼠标右键
5) 这时,所选内容会自动复制到SQL*Plus环境的最后一行

一个数据库存储过程的例子

--集計処理
CREATE PROCEDURE SET_TIMESTAMP
AS
BEGIN
--初期化TIMESTAMP_TBL
DELETE FROM TIMESTAMP_TBL;
-- 1.SOTI_BUNRUI_MSTテーブルの最新更新日をTIMESTAMP_TBLに登録
INSERT INTO TIMESTAMP_TBL (
TBL_NAME,
MEMT_TIMESTAMP,
UPD_ID,
UPD_DATE
) VALUES (
'SOTI_BUNRUI_MST',
(SELECT MAX(UPD_DATE) FROM SOTI_BUNRUI_MST),
'system',
CAST('now' AS TIMESTAMP)
);
-- 2.SOTI_MSTテーブルの最新更新日をTIMESTAMP_TBLに登録
INSERT INTO TIMESTAMP_TBL (
TBL_NAME,
MEMT_TIMESTAMP,
UPD_ID,
UPD_DATE
) VALUES (
'SOTI_MST',
(SELECT MAX(UPD_DATE) FROM SOTI_MST),
'system',
CAST('now' AS TIMESTAMP)
);
-- 3.KIKI_MSTテーブルの最新更新日をTIMESTAMP_TBLに登録
INSERT INTO TIMESTAMP_TBL (
TBL_NAME,
MEMT_TIMESTAMP,
UPD_ID,
UPD_DATE
) VALUES (
'KIKI_MST',
(SELECT MAX(UPD_DATE) FROM KIKI_MST),
'system',
CAST('now' AS TIMESTAMP)
);
-- 4.KAKAKUMST_TBLテーブルの最新更新日をTIMESTAMP_TBLに登録
INSERT INTO TIMESTAMP_TBL (
TBL_NAME,
MEMT_TIMESTAMP,
UPD_ID,
UPD_DATE
) VALUES (
'KAKAKUMST_TBL',
(SELECT MAX(UPD_DATE) FROM KAKAKUMST_TBL),
'system',
CAST('now' AS TIMESTAMP)
);
-- 5.SOTI_BUNRUI_TBLテーブルの最新更新日をTIMESTAMP_TBLに登録
INSERT INTO TIMESTAMP_TBL (
TBL_NAME,
MEMT_TIMESTAMP,
UPD_ID,
UPD_DATE
) VALUES (
'SOTI_BUNRUI_TBL',
(SELECT MAX(UPD_DATE) FROM SOTI_BUNRUI_TBL),
'system',
CAST('now' AS TIMESTAMP)
);
-- 6.SOTI_TBLテーブルの最新更新日をTIMESTAMP_TBLに登録
INSERT INTO TIMESTAMP_TBL (
TBL_NAME,
MEMT_TIMESTAMP,
UPD_ID,
UPD_DATE
) VALUES (
'SOTI_TBL',
(SELECT MAX(UPD_DATE) FROM SOTI_TBL),
'system',
CAST('now' AS TIMESTAMP)
);
-- 7.SOTIKIKI_LINK_TBLテーブルの最新更新日をTIMESTAMP_TBLに登録
INSERT INTO TIMESTAMP_TBL (
TBL_NAME,
MEMT_TIMESTAMP,
UPD_ID,
UPD_DATE
) VALUES (
'SOTIKIKI_LINK_TBL',
(SELECT MAX(UPD_DATE) FROM SOTIKIKI_LINK_TBL),
'system',
CAST('now' AS TIMESTAMP)
);
-- 8.KIKI_LINK_TBLテーブルの最新更新日をTIMESTAMP_TBLに登録
INSERT INTO TIMESTAMP_TBL (
TBL_NAME,
MEMT_TIMESTAMP,
UPD_ID,
UPD_DATE
) VALUES (
'KIKI_TBL',
(SELECT MAX(UPD_DATE) FROM KIKI_TBL),
'system',
CAST('now' AS TIMESTAMP)
);
WHEN ANY DO
BEGIN
EXCEPTION;
END
END;

2000年5月22日星期一

JDBC編

◆JDBCとは?
JDBCとはJavaからデータベースにアクセスするためのAPIです。JDBCのAPIを使用してJavaのプログラムからデータベースにSQL文を発行してデータベースのデータの操作を行うことができます。
◆データベースとは?
データベースとはデータの集まりのことです。たくさんのデータを整理、分類して管理することによってユーザーが必要なデータを簡単に検索して取り出したり、またデータを追加、更新したりできるようになります。
◆トランザクションとは?
トランザクションとはデータベースの一連の更新処理(INSERT,UPDATE,DELETE)のことです。トランザクションを開始(begin)して、トランザクション内である更新処理をした時点ではデータベースにその更新は反映されません。トランザクション(一連の更新処理)が終了しcommitしてはじめてデータベースに一連の更新処理が反映されます。また、トランザクション内でエラーが発生した場合、,rollbackすることでそこまでの処理を取り消すことができます。
◆データソースとは?
データソース(DataSource)とはプログラムとデータベースへの接続との間のインターフェースで、データベースへの接続を取得するために使用されます。JDBC 2.0から使用できるようになりました。データソース(DataSource)を取得するには通常JNDIを使用します。データベースのドライバやURLの情報は外部の設定ファイルにもち、プログラム上ではデータソース名だけを使用してデータソース(DataSource)を取得します。そのため、他のサーバーへ移動した場合やデータベースが変わった場合でもコードを変更しなくてすむメリットがあります。また、データソース(DataSource)を使用することによってコネクションプーリングや分散トランザクションを行うことができるようになります。
◆DriverManagerとDataSource
Javaでデータベースに接続する方法は2種類あります。従来から使用されているDriverManagerを使った方法とJDBC 2.0から使用できるようになったDataSourceを使った方法の2つです。
■DriverManagerを使った方法
Class.forName("org.gjt.mm.mysql.Driver");
String url = "jdbc:mysql:///hellodb?useUnicode=true&characterEncoding=SJIS";
Connection con = DriverManager.getConnection(url);

■DataSourceを使った方法
InitialContext ic = new InitialContext();
DataSource ds = (DataSource)ic.lookup("java:comp/env/jdbc/MySQL");
Connection con = ds.getConnection();

取得できるのはどちらも同じConnectionオブジェクトです。DriverManagerも従来通り使用できますが、JNDIサービスが動いていてDataSourceを使用できる環境ではDataSourceを使用してデータベースに接続することが推奨されています。また、J2EE環境ではDataSourceを使用することになっています。

参照:
http://www.hellohiro.com/jdbc.htm
http://www.hellohiro.com/datasource.htm
http://www.hellohiro.com/jdbcmysql.htm
http://www.hellohiro.com/jdbcpostgresql.htm
http://www.hellohiro.com/jdbctransaction.htm

2000年5月11日星期四

SQL增删改查处理

//查询处理
public ArrayList select() {
  ArrayList list = new ArrayList();

  PreparedStatement pstmt = null;
  ResultSet rset = null;

  String sql = " SELECT * FROM dbo.[EmployeePublic] WHERE id = ? ";

  try {
    pstmt = this.con.prepareStatement(sql);

    pstmt.setString(1, "a");

    rset = pstmt.executeQuery();

    while (rset.next()) {
      list.add(rset.getString("EmployeeNo"));
      list.add(rset.getString("EmployeeName"));
    }
  } catch (Exception e) {
    e.printStackTrace();
  } finally {
    try {
      if (pstmt != null) {
        pstmt.close();
      }
      if (rset != null) {
        rset.close();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  return list;
}

//增加,修改,删除处理
public boolean iudFunc() {
  PreparedStatement pstmt = null;
  boolean ret = true;

  String sql = " UPDATE dbo.[Organization] SET id = ? WHERE Year = ? ";

  try {
    pstmt = con.prepareStatement(sql);

    pstmt.setString(1, "a");
    pstmt.setString(2, "b");

    pstmt.execute();
  } catch (Exception e) {
    e.printStackTrace();
    ret = false;
  } finally {
    try {
      if (pstmt != null) {
        pstmt.close();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  return ret;
}

2000年5月2日星期二

SQL学习笔记

1.合理使用索引
索引是数据库中重要的数据结构,它的根本目的就是为了提高查询效率。现在大多数的数据库产品都采用IBM最先提出的ISAM索引结构。索引的使用要恰到好处,其使用原则如下:
●在经常进行连接,但是没有指定为外键的列上建立索引,而不经常连接的字段则由优化器自动生成索引。
●在频繁进行排序或分组(即进行group by或order by操作)的列上建立索引。
●在条件表达式中经常用到的不同值较多的列上建立检索,在不同值少的列上不要建立索引。比如在雇员表的“性别”列上只有“男”与“女”两个不同值,因此就无必要建立索引。如果建立索引不但不会提高查询效率,反而会严重降低更新速度。
●如果待排序的列有多个,可以在这些列上建立复合索引(compound index)。
● 使用系统工具。如Informix数据库有一个tbcheck工具,可以在可疑的索引上进行检查。在一些数据库服务器上,索引可能失效或者因为频繁操作而使得读取效率降低,如果一个使用索引的查询不明不白地慢下来,可以试着用tbcheck工具检查索引的完整性,必要时进行修复。另外,当数据库表更新大量数据后,删除并重建索引可以提高查询速度。

2.避免或简化排序
应当简化或避免对大型表进行重复的排序。当能够利用索引自动以适当的次序产生输出时,优化器就避免了排序的步骤。以下是一些影响因素:
●索引中不包括一个或几个待排序的列;
●group by或order by子句中列的次序与索引的次序不一样;
●排序的列来自不同的表。
为了避免不必要的排序,就要正确地增建索引,合理地合并数据库表(尽管有时可能影响表的规范化,但相对于效率的提高是值得的)。如果排序不可避免,那么应当试图简化它,如缩小排序的列的范围等。

3.消除对大型表行数据的顺序存取
在嵌套查询中,对表的顺序存取对查询效率可能产生致命的影响。比如采用顺序存取策略,一个嵌套3层的查询,如果每层都查询1000行,那么这个查询就要查询10亿行数据。避免这种情况的主要方法就是对连接的列进行索引。例如,两个表:学生表(学号、姓名、年龄……)和选课表(学号、课程号、成绩)。如果两个表要做连接,就要在“学号”这个连接字段上建立索引。
还可以使用并集来避免顺序存取。尽管在所有的检查列上都有索引,但某些形式的where子句强迫优化器使用顺序存取。下面的查询将强迫对orders表执行顺序操作:
SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008
虽然在customer_num和order_num上建有索引,但是在上面的语句中优化器还是使用顺序存取路径扫描整个表。因为这个语句要检索的是分离的行的集合,所以应该改为如下语句:
SELECT * FROM orders WHERE customer_num=104 AND order_num>1001
UNION
SELECT * FROM orders WHERE order_num=1008
这样就能利用索引路径处理查询。

4.避免相关子查询
一个列的标签同时在主查询和where子句中的查询中出现,那么很可能当主查询中的列值改变之后,子查询必须重新查询一次。查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的行。

5.避免困难的正规表达式
MATCHES和 LIKE关键字支持通配符匹配,技术上叫正规表达式。但这种匹配特别耗费时间。例如:SELECT * FROM customer WHERE zipcode LIKE “98_ _ _”
即使在zipcode字段上建立了索引,在这种情况下也还是采用顺序扫描的方式。如果把语句改为 SELECT * FROM customer WHERE zipcode >“98000”,在执行查询时就会利用索引来查询,显然会大大提高速度。
另外,还要避免非开始的子串。例如语句:SELECT * FROM customer WHERE zipcode[2,3] >“80”,在where子句中采用了非开始子串,因而这个语句也不会使用索引。

6.使用临时表加速查询
把表的一个子集进行排序并创建临时表,有时能加速查询。它有助于避免多重排序操作,而且在其他方面还能简化优化器的工作。例如:
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
AND cust.postcode>“98000”
ORDER BY cust.name
如果这个查询要被执行多次而不止一次,可以把所有未付款的客户找出来放在一个临时文件中,并按客户的名字进行排序:
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
ORDER BY cust.name
INTO TEMP cust_with_balance
然后以下面的方式在临时表中查询:
SELECT * FROM cust_with_balance
WHERE postcode>“98000”
临时表中的行要比主表中的行少,而且物理顺序就是所要求的顺序,减少了磁盘I/O,所以查询工作量可以得到大幅减少。
注意:临时表创建后不会反映主表的修改。在主表中数据频繁修改的情况下,注意不要丢失数据。

7.用排序来取代非顺序存取
非顺序磁盘存取是最慢的操作,表现在磁盘存取臂的来回移动。SQL语句隐藏了这一情况,使得我们在写应用程序时很容易写出要求存取大量非顺序页的查询。
有些时候,用数据库的排序能力来替代非顺序的存取能改进查询。

1.INSERT (往数据表里插入记录的语句)

INSERT INTO 表名(字段名1, 字段名2, ……) VALUES ( 值1, 值2, ……);
INSERT INTO 表名(字段名1, 字段名2, ……) SELECT (字段名1, 字段名2, ……) FROM 另外的表名;

字符串类型的字段值必须用单引号括起来, 例如: ’GOOD DAY’
如果字段值里包含单引号’ 需要进行字符串转换, 我们把它替换成两个单引号''.
字符串类型的字段值超过定义的长度会出错, 最好在插入前进行长度校验.

日期字段的字段值可以用当前数据库的系统时间SYSDATE, 精确到秒
或者用字符串转换成日期型函数TO_DATE(‘2001-08-01’,’YYYY-MM-DD’)
TO_DATE()还有很多种日期格式, 可以参看ORACLE DOC.
年-月-日 小时:分钟:秒 的格式YYYY-MM-DD HH24:MI:SS

INSERT时最大可操作的字符串长度小于等于4000个单字节, 如果要插入更长的字符串, 请考虑字段用CLOB类型,
方法借用ORACLE里自带的DBMS_LOB程序包.

INSERT 时如果要用到从1开始自动增长的序列号, 应该先建立一个序列号
CREATE SEQUENCE 序列号的名称 (最好是表名+序列号标记) INCREMENT BY 1 START WITH 1
MAXVALUE 99999 CYCLE NOCACHE;
其中最大的值按字段的长度来定, 如果定义的自动增长的序列号 NUMBER(6) , 最大值为999999
INSERT 语句插入这个字段值为: 序列号的名称.NEXTVAL

2.DELETE (删除数据表里记录的语句)

DELETE FROM表名 WHERE 条件;

注意:删除记录并不能释放ORACLE里被占用的数据块表空间. 它只把那些被删除的数据块标成unused.

如果确实要删除一个大表里的全部记录, 可以用 TRUNCATE 命令, 它可以释放占用的数据块表空间
TRUNCATE TABLE 表名;
此操作不可回退.

3.UPDATE (修改数据表里记录的语句)

UPDATE表名 SET 字段名1=值1, 字段名2=值2, …… WHERE 条件;

如果修改的值N没有赋值或定义时, 将把原来的记录内容清为NULL, 最好在修改前进行非空校验;
值N超过定义的长度会出错, 最好在插入前进行长度校验..

注意事项:
A. 以上SQL语句对表都加上了行级锁,
确认完成后, 必须加上事物处理结束的命令 COMMIT 才能正式生效,
否则改变不一定写入数据库里.
如果想撤回这些操作, 可以用命令 ROLLBACK 复原.

B. 在运行INSERT, DELETE 和 UPDATE 语句前最好估算一下可能操作的记录范围,
应该把它限定在较小 (一万条记录) 范围内,. 否则ORACLE处理这个事物用到很大的回退段.
程序响应慢甚至失去响应. 如果记录数上十万以上这些操作, 可以把这些SQL语句分段分次完成,
其间加上COMMIT 确认事物处理.

二.数据定义 (DDL) 部分

1.CREATE (创建表, 索引, 视图, 同义词, 过程, 函数, 数据库链接等)

ORACLE 常用的字段类型有
CHAR 固定长度的字符串
VARCHAR2 可变长度的字符串
NUMBER(M,N) 数字型M是位数总长度, N是小数的长度
DATE 日期类型

创建表时要把较小的不为空的字段放在前面, 可能为空的字段放在后面

创建表时可以用中文的字段名, 但最好还是用英文的字段名

创建表时可以给字段加上默认值, 例如 DEFAULT SYSDATE
这样每次插入和修改时, 不用程序操作这个字段都能得到动作的时间

创建表时可以给字段加上约束条件
例如 不允许重复 UNIQUE, 关键字 PRIMARY KEY

2.ALTER (改变表, 索引, 视图等)

改变表的名称
ALTER TABLE 表名1 TO 表名2;

在表的后面增加一个字段
ALTER TABLE表名 ADD 字段名 字段名描述;

修改表里字段的定义描述
ALTER TABLE表名 MODIFY字段名 字段名描述;

给表里的字段加上约束条件
ALTER TABLE 表名 ADD CONSTRAINT 约束名 PRIMARY KEY (字段名);
ALTER TABLE 表名 ADD CONSTRAINT 约束名 UNIQUE (字段名);

把表放在或取出数据库的内存区
ALTER TABLE 表名 CACHE;
ALTER TABLE 表名 NOCACHE;

3.DROP (删除表, 索引, 视图, 同义词, 过程, 函数, 数据库链接等)

删除表和它所有的约束条件
DROP TABLE 表名 CASCADE CONSTRAINTS;

4.TRUNCATE (清空表里的所有记录, 保留表的结构)

TRUNCATE 表名;

三.查询语句 (SELECT) 部分

SELECT 字段名1, 字段名2, …… FROM 表名1, [表名2, ……] WHERE 条件;

字段名可以带入函数
例如: COUNT(*), MIN(字段名), MAX(字段名), AVG(字段名), DISTINCT(字段名),
TO_CHAR(DATE字段名,'YYYY-MM-DD HH24:MI:SS')

NVL(EXPR1, EXPR2)函数
解释:
IF EXPR1=NULL
RETURN EXPR2
ELSE
RETURN EXPR1

DECODE(AA﹐V1﹐R1﹐V2﹐R2....) 函数
解释:
IF AA=V1 THEN RETURN R1
IF AA=V2 THEN RETURN R2
..…
ELSE
RETURN NULL

LPAD(char1,n,char2)函数
解释:
字符char1按制定的位数n显示,不足的位数用 char2字符串替换左边的空位

字段名之间可以进行算术运算
例如: (字段名1*字段名1)/3

查询语句可以嵌套
例如: SELECT …… FROM
(SELECT …… FROM表名1, [表名2, ……] WHERE 条件) WHERE 条件2;

两个查询语句的结果可以做集合操作
例如: 并集UNION(去掉重复记录), 并集UNION ALL(不去掉重复记录), 差集MINUS, 交集INTERSECT

分组查询
SELECT字段名1, 字段名2, …… FROM 表名1, [表名2, ……] GROUP BY字段名1
[HAVING 条件] ;

两个以上表之间的连接查询

SELECT 字段名1, 字段名2, …… FROM 表名1, [表名2, ……] WHERE
表名1.字段名 = 表名2. 字段名 [ AND ……] ;

SELECT字段名1, 字段名2, …… FROM 表名1, [表名2, ……] WHERE
表名1.字段名 = 表名2. 字段名(+) [ AND ……] ;

有(+)号的字段位置自动补空值

查询结果集的排序操作, 默认的排序是升序ASC, 降序是DESC

SELECT字段名1, 字段名2, …… FROM 表名1, [表名2, ……]
ORDER BY字段名1, 字段名2 DESC;

字符串模糊比较的方法

INSTR(字段名, ‘字符串’)>0
字段名 LIKE ‘字符串%’ [‘%字符串%’]

每个表都有一个隐含的字段ROWID, 它标记着记录的唯一性.

四.ORACLE 里常用的数据对象 (SCHEMA)

1.索引 (INDEX)

CREATE INDEX 索引名ON 表名 ( 字段1, [字段2, ……] );
ALTER INDEX 索引名 REBUILD;

一个表的索引最好不要超过三个 (特殊的大表除外), 最好用单字段索引, 结合SQL语句的分析执行情况,
也可以建立多字段的组合索引和基于函数的索引

ORACLE8.1.7 字符串可以索引的最大长度为1578 单字节
ORACLE8.0.6字符串可以索引的最大长度为758 单字节

ORACLE DOC上说字符串最大可以建索引的长度约是:数据块的大小(db_block_size)*40%

2.视图 (VIEW)

CREATE VIEW 视图名AS SELECT …. FROM …..;
ALTER VIEW视图名 COMPILE;

视图仅是一个 SQL查询语句, 它可以把表之间复杂的关系简洁化.

3.同义词 (SYNONMY)
CREATE SYNONYM同义词名FOR 表名;
CREATE SYNONYM同义词名FOR 表名@数据库链接名;

4.数据库链接 (DATABASE LINK)
CREATE DATABASE LINK数据库链接名CONNECT TO 用户名 IDENTIFIED BY 密码 USING ‘数据库连接字符串’;

数据库连接字符串可以用NET8 EASY CONFIG或者直接修改TNSNAMES.ORA里定义.

数据库参数global_name=true时要求数据库链接名称跟远端数据库名称一样

数据库全局名称可以用以下命令查出
SELECT * FROM GLOBAL_NAME;

查询远端数据库里的表
SELECT …… FROM 表名@数据库链接名;

五.权限管理 (DCL) 语句

1.GRANT 赋于权限
常用的系统权限集合有以下三个:
CONNECT(基本的连接), RESOURCE(程序开发), DBA(数据库管理)
常用的数据对象权限有以下五个:
ALL ON 数据对象名, SELECT ON 数据对象名, UPDATE ON 数据对象名,
DELETE ON 数据对象名, INSERT ON 数据对象名, ALTER ON 数据对象名

GRANT CONNECT, RESOURCE TO 用户名;
GRANT SELECT ON 表名 TO 用户名;
GRANT SELECT, INSERT, DELETE ON表名 TO 用户名1, 用户名2;

2.REVOKE 回收权限

REVOKE CONNECT, RESOURCE FROM 用户名;
REVOKE SELECT ON 表名 FROM 用户名;
REVOKE SELECT, INSERT, DELETE ON表名 FROM 用户名1, 用户名2;