呓语的博客

不管前面的路有多艰辛多长,只要怀着一颗执着的心。成功就离你不远了!
posts - 43, comments - 2, trackbacks - 0, articles - 1

2005年12月16日

Java实用工具类库中的类java.util.Random提供了产生各种类型随机数的方法。它可以产生int、long、float、double以及Goussian等类型的随机数。这也是它与java.lang.Math中的方法Random()最大的不同之处,后者只产生double型的随机数。
  类Random中的方法十分简单,它只有两个构造方法和六个普通方法。
  构造方法:
  (1)public Random()
  (2)public Random(long seed)
  Java产生随机数需要有一个基值seed,在第一种方法中基值缺省,则将系统时间作为seed。
  普通方法:
  (1)public synonronized void setSeed(long seed)
  该方法是设定基值seed。
  (2)public int nextInt()
  该方法是产生一个整型随机数。
  (3)public long nextLong()
  该方法是产生一个long型随机数。
  (4)public float nextFloat()
  该方法是产生一个Float型随机数。
  (5)public double nextDouble()
  该方法是产生一个Double型随机数。
  (6)public synchronized double nextGoussian()
  该方法是产生一个double型的Goussian随机数。
  例2 RandomApp.java。
  //import java.lang.*;
  import java.util.Random;

  public class RandomApp{
   public static void main(String args[]){
    Random ran1=new Random();
    Random ran2=new Random(12345);
    //创建了两个类Random的对象。
    System.out.println("The 1st set of random numbers:");
    System.out.println("\t Integer:"+ran1.nextInt());
    System.out.println("\t Long:"+ran1.nextLong());
    System.out.println("\t Float:"+ran1.nextFloat());
    System.out.println("\t Double:"+ran1.nextDouble());
    System.out.println("\t Gaussian:"+ran1.nextGaussian());
    //产生各种类型的随机数
    System.out.print("The 2nd set of random numbers:");
    for(int i=0;i<5;i++){
     System.out.println(ran2.nextInt()+" ");
     if(i==2) System.out.println();
     //产生同种类型的不同的随机数。
     System.out.println();
    }
   }
}

posted @ 2006-02-13 23:24 呓语的博客 阅读(237) | 评论 (0)编辑 收藏

本章介绍Java的实用工具类库java.util包。在这个包中,Java提供了一些实用的方法和数据结构。例如,Java提供日期(Data)类、日历(Calendar)类来产生和获取日期及时间,提供随机数(Random)类产生各种类型的随机数,还提供了堆栈(Stack)、向量(Vector) 、位集合(Bitset)以及哈希表(Hashtable)等类来表示相应的数据结构。
  图8.1给出了java.util包的基本层次结构图。下面我们将具体介绍其中几个重要的类。
           ┌java.util.BitSet
           │java.util.Calendar
           │      └java.util.GregorianCalendar
           │java.util.Date
           │java.util.Dictionary
           │      └java.util.Hashtable
           │             └java.util.Properties
           │java.util.EventObject
           │java.util.ResourceBundle
       ┌普通类┤      ├java.util.ListResourceBundle
       │   │      └java.util.PropertyResourceBundle
       │   │java.util.Local
       │   │java.util.Observable
       │   │java.util.Random
       │   │java.util.StringTokenizer
       │   │java.util.Vector
       │   │      └java.util.Stack
  Java.util┤   └java.util.TimeZone
       │          └java.util.SimpleTimeZone
       │   ┌java.util.Enumeration
       ├接 口┤java.util.EventListener
       │   └java.util.Observer
       │   ┌java.util.EmptyStackException
       └异常类┤java.util.MissingResourceException
           │java.util.NoSuchElementException
           └java.util.TooManyListenersException
       图8.1 java.util包的基本层次结构


8.2 日期类Date

  Java在日期类中封装了有关日期和时间的信息,用户可以通过调用相应的方法来获取系统时间或设置日期和时间。Date类中有很多方法在JDK1.0公布后已经过时了,在8.3中我们将介绍JDK1.0中新加的用于替代Date的功能的其它类。
  在日期类中共定义了六种构造函数。
  (1)public Date()
  创建的日期类对象的日期时间被设置成创建时刻相对应的日期时间。
  例 Date today=new Date();//today被设置成创建时刻相对应的日期时间。
  (2)public Date (long date)
  long 型的参数date可以通过调用Date类中的static方法parse(String s)来获得。
  例 long l=Date.parse("Mon 6 Jan 1997 13:3:00");
    Date day=new Date(l);
  //day中时间为1997年 1月6号星期一,13:3:00。
  (3)public Date(String s)
  按字符串s产生一日期对象。s的格式与方法parse中字符串参数的模式相同。
  例 Date day=new Date("Mon 6 Jan 1997 13:3:00");
  //day 中时间为1997年1月6号星期一,13:3:00.
  (4)public Date(int year,int month,int date)
  (5)public Date(int year,int month,int date,int hrs,int min)
  (6)public Date(int year,int month,int date,int hrs,int min,int sec)
  按给定的参数创建一日期对象。
  参数说明:
  year的值为:需设定的年份-1900。例如需设定的年份是1997则year的值应为97,即1997-1900的结果。所以Date中可设定的年份最小为1900;
  month的值域为0~11,0代表1月,11表代表12月;
  date的值域在1~31之间;
  hrs的值域在0~23之间。从午夜到次日凌晨1点间hrs=0,从中午到下午1点间hrs=12;
  min和sec的值域在0~59之间。
  例 Date day=new Date(11,3,4);
  //day中的时间为:04-Apr-11 12:00:00 AM
另外,还可以给出不正确的参数。
  例 设定时间为1910年2月30日,它将被解释成3月2日。
  Date day=new Date(10,1,30,10,12,34);
  System.out.println("Day's date is:"+day);
  //打印结果为:Day's date is:Web Mar 02 10:13:34 GMT+08:00 1910
  下面我们给出一些Date类中常用方法。
  (1)public static long UTC(int year,int month,int date,int hrs. int min,int sec)
  该方法将利用给定参数计算UTC值。UTC是一种计时体制,与GMT(格林威治时间)的计时体系略有差别。UTC计时体系是基于原子时钟的,而GTMT计时体系是基于天文学观测的。计算中使用的一般为GMT计时体系。
  (2)public static long parse(String s)
  该方法将字符串s转换成一个long型的日期。在介绍构造方法Date(long date)时曾使用过这个方法。
  字符串s有一定的格式,一般为:
  (星期 日 年 时间GMT+时区)
  若不注明时区,则为本地时区。
  (3)public void setMonth(int month)
  (4)public int getMonth()
  这两个方法分别为设定和获取月份值。
  获取的月份的值域为0~11,0代表1月,11代表12月。
  (5)public String toString()
  (6)public String toLocalString()
  (7)public String toGMTString()
  将给定日期对象转换成不同格式的字符串。它们对应的具体的格式可参看例子8.1。
  (8)public int getTimezoneOffset()
  该方法用于获取日期对象的时区偏移量。
  例8.1中对上面介绍的Date类中的基本方法进行了具体的应用,并打印了相应的结果。由于使用了一些过时的方法,所以编译时会有警告信息。另外,由于本例中的时间表示与平台有关,不同的JDK版本对此处理不完全相同,因此不同版本的JDK执行本例的结果可能有细微差异。
  例8.1 DateApp.java
  import java.lang.System;
  import java.util.Date;
  public class DateApp{
   public static void main(String args[]){
    Date today=new Date();
    //today中的日期被设成创建时刻的日期和时间,假设创建时刻为1997年3月
    //23日17时51分54秒。
    System.out.println("Today's date is "+today);
    //返回一般的时间表示法,本例中结果为
    //Today's date is Fri May 23 17:51:54 1997
    System.out.println("Today's date(Internet GMT)is:"
     +today.toGMTString());
    //返回结果为GMT时间表示法,本例中结果为
    //Today's date(Internet GMT)is: 23 May 1997 09:51:54:GMT
    System.out.println("Today's date(Locale) is:"
     +today.toLocaleString());
    //返回结果为本地习惯的时间表示法,结果为
    //Today's date(Locale)is:05/23/97 17:51:54
    System.out.println("Today's year is: "+today.getYear());
    System.out.println("Today's month is: "+(today.getMonth()+1));
    System.out.println("Today's date is: "+today.getDate());
    //调用Date类中方法,获取年月日的值。
    //下面调用了不同的构造方法来创建Date类的对象。
    Date day1=new Date(100,1,23,10,12,34);
    System.out.println("Day1's date is: "+day1);
    Date day2=new Date("Sat 12 Aug 1996 13:3:00");
    System.out.println("Day2's date is: "+day2);
    long l= Date.parse("Sat 5 Aug 1996 13:3:00 GMT+0800");
    Date day3= new Date(l);
    System.out.println("Day3's date(GMT)is: "+day3.toGMTString());
    System.out.println("Day3's date(Locale)is: "
     +day3.toLocaleString());
    System.out.println("Day3's time zone offset is:"
     +day3.getTimezoneOffset());
   }
  }

  运行结果(JDK1.3版,与原文不同,原文是JDK1.0版):
  E:\java\tutorial\java01>java DateApp
  Today's date is Thu Dec 27 17:58:16 CST 2001
  Today's date(Internet GMT)is:27 Dec 2001 09:58:16 GMT
  Today's date(Locale) is:2001-12-27 17:58:16
  Today's year is: 101
  Today's month is: 12
  Today's date is: 27
  Day1's date is: Wed Feb 23 10:12:34 CST 2000
  Day2's date is: Fri Aug 12 13:03:00 CST 1996
  Day3's date(GMT)is: 5 Aug 1996 05:03:00 GMT
  Day3's date(Locale)is: 1996-8-5 13:03:00
  Day3's time zone offset is:-480

  E:\java\tutorial\java01>

8.3 日历类Calendar

  在早期的JDK版本中,日期(Date)类附有两大功能:(1)允许用年、月、日、时、分、秒来解释日期:(2)允许对表示日期的字符串进行格式化和句法分析。在JDK1.1中提供了类Calendar来完成第一种功能,类DateFormat来完成第二项功能。dateFormat是java.text包中的一个类。与Date类有所不同的是,DateFormat类接受用各种语言和不同习惯表示的日期字符串。本节将介绍java.util包中的类Calendar及其它新增加的相关的类。
  类Calendar是一个抽象类,它完成日期(Date)类和普通日期表示法(即用一组整型域如YEAR,MONTH,DAY,HOUR表示日期)之间的转换。
  由于所使用的规则不同,不同的日历系统对同一个日期的解释有所不同。在JDK1.1中提供了Calendar类一个子类GregorianCalendar??它实现了世界上普遍使用的公历系统。当然用户也可以通过继承Calendar类,并增加所需规则,以实现不同的日历系统。
  第GregorianCalendar继承了Calendar类。本节将在介绍类GregorianCalendar的同时顺带介绍Calendar类中的相关方法。
  类GregorianCalendar提供了七种构造函数:
  (1)public GregorianCalendar()
  创建的对象中的相关值被设置成指定时区,缺省地点的当前时间,即程序运行时所处的时区、地点的当前时间。
  (2)public GregorianCalendar(TimeZone zone)
  创建的对象中的相关值被设置成指定时区zone,缺省地点的当前时间。
  (3)public GregorianCalendar(Locale aLocale)
  创建的对象中的相关值被设置成缺省时区,指定地点aLocale的当前时间。
  (4)public GregorianCalendar(TimeZone zone,Local aLocale)
  创建的对象中的相关值被设置成指定时区,指定地点的当前时间。
  上面使用到的类TimeZone的性质如下:
  TimeZone是java.util包中的一个类,其中封装了有关时区的信息。每一个时区对应一组ID。类TimeZone提供了一些方法完成时区与对应ID两者之间的转换。
  (Ⅰ)已知某个特定的ID,可以调用方法
  public static synchronized TimeZone getTimeZone(String ID)
来获取对应的时区对象。
  例 太平洋时区的ID为PST,用下面的方法可获取对应于太平洋时区的时区对象:
  TimeZone tz=TimeZone.getTimeZone("PST");
  调用方法getDefault()可以获取主机所处时区的对象。
  TimeZone tz=TimeZone.getDefault();
  (Ⅱ)调用以下方法可以获取时区的ID
  ■public static synchronized String[] getavailableIDs(int rawOffset)
  根据给定时区偏移值获取ID数组。同一时区的不同地区的ID可能不同,这是由于不同地区对是否实施夏时制意见不统一而造成的。
  例String s[]=TimeZone.getAvailableIDs(-7*60*60*1000);
  打印s,结果为s[0]=PNT,s[1]=MST
  ■public static synchronized String[] getAvailableIDs()
  获取提供的所有支持的ID。
  ■public String getID()
  获取特定时区对象的ID。
  例 TimeZone tz=TimeZone.getDefault();
  String s=tz.getID();
  打印s,结果为s=CTT。
  上面使用类的对象代表了一个特定的地理、政治或文化区域。Locale只是一种机制,它用来标识一类对象,Local本身并不包含此类对象。
  要获取一个Locale的对象有两种方法:
  (Ⅰ)调用Locale类的构造方法
  Locale(String language,String country)
  Locale(String language,String country,String variant)
  参数说明:language??在ISO-639中定义的代码,由两个小写字母组成。
       country??在ISO-3166中定义的代码,由两个大写字母组成。
       variant??售货商以及特定浏览器的代码,例如使用WIN代表Windows。
  (Ⅱ)调用Locale类中定义的常量
  Local类提供了大量的常量供用户创建Locale对象。
  例 Locale.CHINA
    为中国创建一个Locale的对象。
  类TimeZone和类Locale中的其它方法,读者可查阅API。
  (5)public GregorianCalendar(int year,int month,int date)
  (6)public GregorianCalendar(int year,int month,int date,int hour,int minute)
  (7)public GregorianCalendar(int year,int month,int date,int hour,int minute,int second)
  用给定的日期和时间创建一个GregorianCalendar的对象。
  参数说明:
  year-设定日历对象的变量YEAR;month-设定日历对象的变量MONTH;
  date-设定日历对象的变量DATE;hour-设定日历对象的变量HOUR_OF_DAY;
  minute-设定日历对象的变量MINUTE;second-设定日历对象的变量SECOND。
  与Date类中不同的是year的值没有1900这个下限,而且year的值代表实际的年份。month的含义与Date类相同,0代表1月,11代表12月。
  例 GregorianCalendar cal=new GregorianCalendar(1991,2,4)
  cal的日期为1991年3月4号。
  除了与Date中类似的方法外,Calendar类还提供了有关方法对日历进行滚动计算和数学计算。计算规则由给定的日历系统决定。进行日期计算时,有时会遇到信息不足或信息不实等特殊情况。Calendar采取了相应的方法解决这些问题。当信息不足时将采用缺省设置,在GregorianCalendar类中缺省设置一般为YEAR=1970,MONTH=JANUARY,DATE=1。
  当信息不实时,Calendar将按下面的次序优先选择相应的Calendar的变量组合,并将其它有冲突的信息丢弃。
  MONTH+DAY_OF_MONTH
  MONTH+WEEK_OF_MONTH+DAY_OF_WEEK
  MONTH+DAY_OF_WEEK_OF_MONTH+DAY_OF_WEEK
  DAY_OF+YEAR
  DAY_OF_WEEK_WEEK_OF_YEAR
  HOUR_OF_DAY

8.4 随机数类Random

  Java实用工具类库中的类java.util.Random提供了产生各种类型随机数的方法。它可以产生int、long、float、double以及Goussian等类型的随机数。这也是它与java.lang.Math中的方法Random()最大的不同之处,后者只产生double型的随机数。
  类Random中的方法十分简单,它只有两个构造方法和六个普通方法。
  构造方法:
  (1)public Random()
  (2)public Random(long seed)
  Java产生随机数需要有一个基值seed,在第一种方法中基值缺省,则将系统时间作为seed。
  普通方法:
  (1)public synonronized void setSeed(long seed)
  该方法是设定基值seed。
  (2)public int nextInt()
  该方法是产生一个整型随机数。
  (3)public long nextLong()
  该方法是产生一个long型随机数。
  (4)public float nextFloat()
  该方法是产生一个Float型随机数。
  (5)public double nextDouble()
  该方法是产生一个Double型随机数。
  (6)public synchronized double nextGoussian()
  该方法是产生一个double型的Goussian随机数。
  例8.2 RandomApp.java。
  //import java.lang.*;
  import java.util.Random;

  public class RandomApp{
   public static void main(String args[]){
    Random ran1=new Random();
    Random ran2=new Random(12345);
    //创建了两个类Random的对象。
    System.out.println("The 1st set of random numbers:");
    System.out.println("\t Integer:"+ran1.nextInt());
    System.out.println("\t Long:"+ran1.nextLong());
    System.out.println("\t Float:"+ran1.nextFloat());
    System.out.println("\t Double:"+ran1.nextDouble());
    System.out.println("\t Gaussian:"+ran1.nextGaussian());
    //产生各种类型的随机数
    System.out.print("The 2nd set of random numbers:");
    for(int i=0;i<5;i++){
     System.out.println(ran2.nextInt()+" ");
     if(i==2) System.out.println();
     //产生同种类型的不同的随机数。
     System.out.println();//原文如此
    }
   }
  }

  运行结果:
  E:\java01>java RandomApp
  The 1st set of random numbers:
    Integer:-173899656
    Long:8056223819738127077
    Float:0.6293638
    Double:0.7888394520265607
    Gaussian:0.5015701094568733
  The 2nd set of random numbers:1553932502
  -2090749135
  -287790814
  -355989640
  -716867186
  E:\java01>

8.5 向量类Vector

  Java.util.Vector提供了向量(Vector)类以实现类似动态数组的功能。在Java语言中。正如在一开始就提到过,是没有指针概念的,但如果能正确灵活地使用指针又确实可以大大提高程序的质量,比如在C、C++中所谓“动态数组”一般都由指针来实现。为了弥补这点缺陷,Java提供了丰富的类库来方便编程者使用,Vector类便是其中之一。事实上,灵活使用数组也可完成向量类的功能,但向量类中提供的大量方法大大方便了用户的使用。
  创建了一个向量类的对象后,可以往其中随意地插入不同的类的对象,既不需顾及类型也不需预先选定向量的容量,并可方便地进行查找。对于预先不知或不愿预先定义数组大小,并需频繁进行查找、插入和删除工作的情况,可以考虑使用向量类。
  向量类提供了三种构造方法:
  public vector()
  public vector(int initialcapacity,int capacityIncrement)
  public vector(int initialcapacity)
  使用第一种方法,系统会自动对向量对象进行管理。若使用后两种方法,则系统将根据参数initialcapacity设定向量对象的容量(即向量对象可存储数据的大小),当真正存放的数据个数超过容量时,系统会扩充向量对象的存储容量。参数capacityIncrement给定了每次扩充的扩充值。当capacityIncrement为0时,则每次扩充一倍。利用这个功能可以优化存储。
  在Vector类中提供了各种方法方便用户使用:
  ■插入功能
  (1)public final synchronized void addElement(Object obj)
  将obj插入向量的尾部。obj可以是任何类的对象。对同一个向量对象,可在其中插入不同类的对象。但插入的应是对象而不是数值,所以插入数值时要注意将数值转换成相应的对象。
  例 要插入一个整数1时,不要直接调用v1.addElement(1),正确的方法为:
  Vector v1=new Vector();
  Integer integer1=new Integer(1);
  v1.addElement(integer1);
  (2)public final synchronized void setElementAt(object obj,int index)
  将index处的对象设成obj,原来的对象将被覆盖。
  (3)public final synchronized void insertElementAt(Object obj,int index)
  在index指定的位置插入obj,原来对象以及此后的对象依次往后顺延。
  ■删除功能
  (1)public final synchronized void removeElement(Object obj)
  从向量中删除obj。若有多个存在,则从向量头开始试,删除找到的第一个与obj相同的向量成员。
  (2)public final synchronized void removeAllElement()
  删除向量中所有的对象。
  (3)public final synchronized void removeElementlAt(int index)
  删除index所指的地方的对象。
  ■查询搜索功能
  (1)public final int indexOf(Object obj)
  从向量头开始搜索obj ,返回所遇到的第一个obj对应的下标,若不存在此obj,返回-1。
  (2)public final synchronized int indexOf(Object obj,int index)
  从index所表示的下标处开始搜索obj。
  (3)public final int lastIndexOf(Object obj)
  从向量尾部开始逆向搜索obj。
  (4)public final synchronized int lastIndexOf(Object obj,int index)
  从index所表示的下标处由尾至头逆向搜索obj。
  (5)public final synchronized Object firstElement()
  获取向量对象中的首个obj。
  (6)public final synchronized Object lastelement()
  获取向量对象中的最后一个obj。
  了解了向量的最基本的方法后,我们来看一下例8.3VectorApp.java。
  例8.3 VectorApp.java。
  import java.util.Vector;
  import java.lang.*;//这一句不应该要,但原文如此
  import java.util.Enumeration;
  public class VectorApp{
   public static void main(String[] args){
    Vector v1=new Vector();
    Integer integer1=new Integer(1);
    v1.addElement("one");
    //加入的为字符串对象
    v1.addElement(integer1);
    v1.addElement(integer1);
    //加入的为Integer的对象
    v1.addElement("two");
    v1.addElement(new Integer(2));
    v1.addElement(integer1);
    v1.addElement(integer1);
    System.out.println("The vector v1 is:\n\t"+v1);
    //将v1转换成字符串并打印
    v1.insertElementAt("three",2);
    v1.insertElementAt(new Float(3.9),3);
    System.out.println("The vector v1(used method insertElementAt()) is:\n\t "+v1);
    //往指定位置插入新的对象,指定位置后的对象依次往后顺延
    v1.setElementAt("four",2);
    System.out.println("The vector v1(used method setElementAt()) is:\n\t "+v1);
    //将指定位置的对象设置为新的对象
    v1.removeElement(integer1);
    //从向量对象v1中删除对象integer1由于存在多个integer1所以从头开始
    //找,删除找到的第一个integer1
    Enumeration enum=v1.elements();
    System.out.print("The vector v1(used method removeElement())is:");
    while(enum.hasMoreElements())
    System.out.print(enum.nextElement()+" ");
    System.out.println();
    //使用枚举类(Enumeration)的方法来获取向量对象的每个元素
    System.out.println("The position of object 1(top-to-bottom):"
     + v1.indexOf(integer1));
    System.out.println("The position of object 1(tottom-to-top):"
     +v1.lastIndexOf(integer1));
    //按不同的方向查找对象integer1所处的位置
    v1.setSize(4);
    System.out.println("The new vector(resized the vector)is:"+v1);
    //重新设置v1的大小,多余的元素被行弃
   }
  }
  运行结果:
  E:\java01>java VectorApp
  The vector v1 is:
     [one, 1, 1, two, 2, 1, 1]
  The vector v1(used method insertElementAt()) is:
     [one, 1, three, 3.9, 1, two, 2, 1, 1]
  The vector v1(used method setElementAt()) is:
     [one, 1, four, 3.9, 1, two, 2, 1, 1]
  The vector v1(used method removeElement())is:one four 3.9 1 two 2 1 1
  The position of object 1(top-to-bottom):3
  The position of object 1(tottom-to-top):7
  The new vector(resized the vector)is:[one, four, 3.9, 1]
  E:\java01>
  从例8.3运行的结果中可以清楚地了解上面各种方法的作用,另外还有几点需解释。
  (1)类Vector定义了方法
  public final int size()
  此方法用于获取向量元素的个数。它的返回值是向是中实际存在的元素个数,而非向量容量。可以调用方法capactly()来获取容量值。
  方法:
  public final synchronized void setsize(int newsize)
  此方法用来定义向量大小。若向量对象现有成员个数已超过了newsize的值,则超过部分的多余元素会丢失。
  (2)程序中定义了Enumeration类的一个对象
  Enumeration是java.util中的一个接口类,在Enumeration中封装了有关枚举数据集合的方法。
  在Enumeration中提供了方法hawMoreElement()来判断集合中是束还有其它元素和方法nextElement()来获取下一个元素。利用这两个方法可以依次获得集合中元素。
  Vector中提供方法:
  public final synchronized Enumeration elements()
  此方法将向量对象对应到一个枚举类型。java.util包中的其它类中也大都有这类方法,以便于用户获取对应的枚举类型。

8.6 栈类Stack

  Stack类是Vector类的子类。它向用户提供了堆栈这种高级的数据结构。栈的基本特性就是先进后出。即先放入栈中的元素将后被推出。Stack类中提供了相应方法完成栈的有关操作。
  基本方法:
  public Object push(Object Hem)
  将Hem压入栈中,Hem可以是任何类的对象。
  public Object pop()
  弹出一个对象。
  public Object peek()
  返回栈顶元素,但不弹出此元素。
  public int search(Object obj)
  搜索对象obj,返回它所处的位置。
  public boolean empty()
  判别栈是否为空。
  例8.4 StackApp.java使用了上面的各种方法。
  例8.4 StackApp.java。
  import java.lang.*;
  import java.util.*;
  public class StackApp{
   public static void main(String args[]){
    Stack sta=new Stack();
    sta.push("Apple");
    sta.push("banana");
    sta.push("Cherry");
    //压入的为字符串对象
    sta.push(new Integer(2));
    //压入的为Integer的对象,值为2
    sta.push(new Float(3.5));
    //压入的为Float的对象,值为3.5
    System.out.println("The stack is,"+sta);
    //对应栈sta
    System.out.println("The top of stack is:"+sta.peek());
    //对应栈顶元素,但不将此元素弹出
    System.out.println("The position of object Cherry is:"
    +sta.search("cherry"));
    //打印对象Cherry所处的位置
    System.out.print("Pop the element of the stack:");
    while(!sta.empty())
    System.out.print(sta.pop()+" ");
    System.out.println();
    //将栈中的元素依次弹出并打印。与第一次打印的sta的结果比较,可看出栈
    //先进后出的特点
   }
  }
  运行结果(略)


8.7 哈希表类Hashtable

  哈希表是一种重要的存储方式,也是一种常见的检索方法。其基本思想是将关系码的值作为自变量,通过一定的函数关系计算出对应的函数值,把这个数值解释为结点的存储地址,将结点存入计算得到存储地址所对应的存储单元。检索时采用检索关键码的方法。现在哈希表有一套完整的算法来进行插入、删除和解决冲突。在Java中哈希表用于存储对象,实现快速检索。
  Java.util.Hashtable提供了种方法让用户使用哈希表,而不需要考虑其哈希表真正如何工作。
  哈希表类中提供了三种构造方法,分别是:
  public Hashtable()
  public Hashtable(int initialcapacity)
  public Hashtable(int initialCapacity,float loadFactor)
  参数initialCapacity是Hashtable的初始容量,它的值应大于0。loadFactor又称装载因子,是一个0.0到0.1之间的float型的浮点数。它是一个百分比,表明了哈希表何时需要扩充,例如,有一哈希表,容量为100,而装载因子为0.9,那么当哈希表90%的容量已被使用时,此哈希表会自动扩充成一个更大的哈希表。如果用户不赋这些参数,系统会自动进行处理,而不需要用户操心。
  Hashtable提供了基本的插入、检索等方法。
  ■插入
  public synchronized void put(Object key,Object value)
给对象value设定一关键字key,并将其加到Hashtable中。若此关键字已经存在,则将此关键字对应的旧对象更新为新的对象Value。这表明在哈希表中相同的关键字不可能对应不同的对象(从哈希表的基本思想来看,这也是显而易见的)。
  ■检索
  public synchronized Object get(Object key)
  根据给定关键字key获取相对应的对象。
  public synchronized boolean containsKey(Object key)
  判断哈希表中是否包含关键字key。
  public synchronized boolean contains(Object value)
  判断value是否是哈希表中的一个元素。
  ■删除
  public synchronized object remove(object key)
  从哈希表中删除关键字key所对应的对象。
  public synchronized void clear()
  清除哈希表
  另外,Hashtalbe还提供方法获取相对应的枚举集合:
  public synchronized Enumeration keys()
  返回关键字对应的枚举对象。
  public synchronized Enumeration elements()
  返回元素对应的枚举对象。
  例8.5 Hashtable.java给出了使用Hashtable的例子。
  例8.5 Hashtalbe.java。
  //import java.lang.*;
  import java.util.Hashtable;
  import java.util.Enumeration;
  public class HashApp{
   public static void main(String args[]){
    Hashtable hash=new Hashtable(2,(float)0.8);
    //创建了一个哈希表的对象hash,初始容量为2,装载因子为0.8

    hash.put("Jiangsu","Nanjing");
    //将字符串对象“Jiangsu”给定一关键字“Nanjing”,并将它加入hash
    hash.put("Beijing","Beijing");
    hash.put("Zhejiang","Hangzhou");

    System.out.println("The hashtable hash1 is: "+hash);
    System.out.println("The size of this hash table is "+hash.size());
    //打印hash的内容和大小

    Enumeration enum1=hash.elements();
    System.out.print("The element of hash is: ");
    while(enum1.hasMoreElements())
     System.out.print(enum1.nextElement()+" ");
    System.out.println();
    //依次打印hash中的内容
    if(hash.containsKey("Jiangsu"))
     System.out.println("The capatial of Jiangsu is "+hash.get("Jiangsu"));
    hash.remove("Beijing");
    //删除关键字Beijing对应对象
    System.out.println("The hashtable hash2 is: "+hash);
    System.out.println("The size of this hash table is "+hash.size());
   }
  }

  运行结果:
  The hashtable hash1 is: {Beijing=Beijing, Zhejiang=Hangzhou, Jiangsu=Nanjing}
  The size of this hash table is 3
  The element of hash is: Beijing Hangzhou Nanjing
  The capatial of Jiangsu is Nanjing
  The hashtable hash2 is: {Zhejiang=Hangzhou, Jiangsu=Nanjing}
  The size of this hash table is 2

  Hashtable是Dictionary(字典)类的子类。在字典类中就把关键字对应到数据值。字典类是一个抽象类。在java.util中还有一个类Properties,它是Hashtable的子类。用它可以进行与对象属性相关的操作。

8.8 位集合类BitSet

  位集合类中封装了有关一组二进制数据的操作。
  我们先来看一下例8.6 BitSetApp.java。
  例8.6 BitSetApp.java
  //import java.lang.*;
  import java.util.BitSet;
  public class BitSetApp{
   private static int n=5;
   public static void main(String[] args){
    BitSet set1=new BitSet(n);
    for(int i=0;i<n;i++) set1.set(i);
    //将set1的各位赋1,即各位均为true
    BitSet set2= new BitSet();
    set2=(BitSet)set1.clone();
    //set2为set1的拷贝
    set1.clear(0);
    set2.clear(2);
    //将set1的第0位set2的第2位清零
    System.out.println("The set1 is: "+set1);
    //直接将set1转换成字符串输出,输出的内容是set1中值true所处的位置
    //打印结果为The set1 is:{1,2,3,4}
    System.out.println("The hash code of set2 is: "+set2.hashCode());
    //打印set2的hashCode
    printbit("set1",set1);
    printbit("set2",set2);
    //调用打印程序printbit(),打印对象中的每一个元素
    //打印set1的结果为The bit set1 is: false true true true true
    set1.and(set2);
    printbit("set1 and set2",set1);
    //完成set1 and set2,并打印结果
    set1.or(set2);
    printbit("set1 or set2",set1);
    //完成set1 or set2,并打印结果
    set1.xor(set2);
    printbit("set1 xor set2",set1);
    //完成set1 xor set2,并打印结果
   }
   //打印BitSet对象中的内容
   public static void printbit(String name,BitSet set){
    System.out.print("The bit "+name+" is: ");
    for(int i=0;i<n;i++)
     System.out.print(set.get(i)+" ");
    System.out.println();
   }
  }

  运行结果:
  The set1 is: {1, 2, 3, 4}
  The hash code of set2 is: 1225
  The bit set1 is: false true true true true
  The bit set2 is: true true false true true
  The bit set1 and set2 is: false true false true true
  The bit set1 or set2 is: true true false true true
  The bit set1 xor set2 is: false false false false false

  程序中使用了BitSet类提供的两种构造方法:
    public BitSet();
    public BitSet(int n);
  参数n代表所创建的BitSet类的对象的大小。BitSet类的对象的大小在必要时会由系统自动扩充。
  其它方法:
  public void set(int n)
  将BitSet对象的第n位设置成1。
  public void clear(int n)
  将BitSet对象的第n位清零。
  public boolean get(int n)
  读取位集合对象的第n位的值,它获取的是一个布尔值。当第n位为1时,返回true;第n位为0时,返回false。
  另外,如在程序中所示,当把一BitSet类的对象转换成字符串输出时,输出的内容是此对象中true所处的位置。
  在BitSet中提供了一组位操作,分别是:
  public void and(BitSet set)
  public void or(BitSet set)
  public void xor(BitSet set)
利用它们可以完成两个位集合之间的与、或、异或操作。
  BitSet类中有一方法public int size()来取得位集合的大小,它的返回值与初始化时设定的位集合大小n不一样,一般为64。

小结

  本章我们介绍了Java的实用工具类库java.util中一些常用的类。java.util包中还有其它一些类。它们的具体用法用户可以自行查阅API。在下一章,我们将学习利用java.awt包进行窗口程序设计。在下章的例子中我们将使用到本章介绍的各种类。

posted @ 2006-02-13 09:00 呓语的博客 阅读(162) | 评论 (0)编辑 收藏

(前言)
根据上一讲,你或许大概已经了解了Eclipse的组成,以及大致的运行机理. 这篇文章, 将
开始带您使用eclipse.

(正文)

[Eclipse的工作台使用指南]

这部分要写的话,其实要写很多,而且最好方式则是图文并茂,最好再有演示. 我这里只是
给一些总体的介绍,并给予一些使用上的指导. 个人感觉,如果你从来

没碰过eclipse, 启动之后,最好先看一下help, 这样会比较好.

具体的操作步骤是这样的, 启动eclipse后, 选 菜单里的help-> help contents, 此时
会弹出一个新的窗口,就是eclipse的帮助窗口, 这个窗口的左边是一个导航

条,选择Workbench User Guide, 里面分为Getting Started, Concepts, Tasks 和Refer
ence. 可以先看一下 Getting Started里面的Basic Tutorial. 这份

tutorial可以在最短的时间内,让你熟悉eclipse的工作台.

其实,eclipse平台ui方面有这几个组件: 菜单, 工具栏, 视图, 透视图, 编辑器

菜单和工具栏不用说了, 地球人都知道的, 视图就是view, 比如 Navigator, Outline,
Tasks 等等都是视图, 每一个视图都有自己相应的功能,你可以参看

workbench user guide来了解这些视图. 编辑器,就是editor, 比如有开发java的编辑器
, 编写文本的编辑器,等等, 最后还有一个叫透视图, 英文是perspective,

这个东东其实是不同的view,menu,toolbar,editor的排列组合. 比如你开发java, 你经
常会用到package explorer, tasks, outline等view和编写java的editor,

以及适合开发java的菜单(Source和Refactor), 那它就会布局一个适合开发java的透视
图, 以此类推.

下面我介绍一下常用菜单项:
+ File
- New: 新建文件,项目,或者其他都是从这里进入

- Import: 这个也是很有用的,比如别人开发的eclipse项目,你copy到
你机器上,可以通过import把这个项目导入工作区

- Export: 这个是导出功能, 比如你开发了一个项目,最后想导出一个
运行库,jar包之类的都可以用这个,这样你就不用自己手动的去把那些class

文件打包了

+ Window
- New Window: 你如果觉得在一个window下开发东西太挤的话,可以再开一
个,等于冒出两个workbench,其实操作的resource都是一样的.

- Open Perspective: eclipse有很多透视图如resource, java, java
browsing, cvs, debug等等,你可以根据当前开发的需要,选择你要的透视图进行开发

- Open View: 透视图毕竟有限,不可能把所有的view都帮你开好, 所以你
如果发觉你要用某一个view,但是它没有开,就用这个选项

- Customize Perspective: 毕竟每个人都有自己的习惯, 你觉得这个透视图用
的不爽, 可以自己定制的

- Reset Perspective: 给你定制的一塌糊涂, 唉, 没办法, 还原成老样子把,
就用这个

- Preference: 这个是非常重要的选项, 偶是没事就进去改的, 它保存了
很多配置方面的东西, 比如字体, 快捷键设置, 很多很多方面都要用到这个

的, 这个东西的详细介绍, 会稍后介绍.

+ Help
- Welcome: eclipse很多插件都做了welcome page,这个page对很多初学
者来说,很有用的,否则很多情况下,新的东西是无从下手的.

- Help Content: 前面讲过了,用来启动帮助系统

- Update: 这个以后会具体介绍

- About Platform: 你可以从这里了解你装了哪些features和plugins


[利用 eclipse 开发简单的 java 程序]

好了,我们一起step by step来学一下把, 很easy的

1. 菜单 new -> project, 然后在new project 对话框里选 java ->java project, 按n
ext 按钮
2. 输入 project 的名字, 按 next 按钮, 当然如果你不想把项目的根目录建在默认的
地方,也可以取消掉use default ,然后自己设定目录
3. 之后就 finish 把, 都用默认配置
4. 如果你没有在java透视图下面,它会提示你是否跳到java透视图,选择是
5. ok 一个项目就建好了
6. 之后,你就可以 new class 开始写java程序了
7. 比如你的new一个class,如下
public class A{
    public static void main(String args[]){
        System.out.println("Hello World");
    }
}

8. 编辑好保存, 然后跳到菜单 -> run -> run as -> java application
9. 你可以看到console view中就冒出Hello World了

很easy把, 当然, 你会在开发中会遇到很多问题, 这是必然的, 那这些问题只能在实践
中积累才能得到解决, 所以不用急,多用用,多玩玩,遇到问题经常到版上来问

问.

还有如果你发现问题的话, 找问题解决方案的第一个地方,应该是eclipse的帮助系统里
的Java Development User Guide, 几乎绝大多数问题,上面都有答案. 所以

有空的话还是要多读一读.

不过,很多人都说用了eclipse之后,就抛弃了其他的java ide, 说明它必有爽的地方, 那
我来介绍一下用eclipse 开发java,有哪些爽的地方


[Java Development Tool (JDT) 特色]

其实特色有很多,我也只是凭我的开发经验, 介绍一下jdt的突出功能.

1. 自动修饰代码功能
这个功能很大程度上, 把平时一些开发代码中的琐碎的工作给自动化了

打开菜单
+ Source
- Comment: 这个比较有用,比如你写java代码,发觉你有一段代码要注
释掉,那就选中那一块代码,然后选这项,他就会自动把这段代码注释掉. 快捷

健是 "Ctrl+/"

- Uncomment: 反注释, 操作方法和Comment差不多, 快捷键是 "Ctrl+\"

- Format: 这个操作项是我一直推荐的, 非常方便, 比如你写了段格
式很烂的代码, 乱七八糟的, 那你就选择这项,你会发觉, 哇~~, 我的代码怎

么一下子变漂亮了, 不信你可以试试, 快捷键是"Ctrl+Shift+F", 所以我现在都养成习
惯了,写一会儿代码,就c+s+f一下, 呵呵,很方便的.

- Sort Member: 这个不是很常用,但是如果你觉得代码太长,老是找不到函
数,,也可以试试. 他会帮你把你写的函数,变量重新排序

- Organize Import: 这个功能也是一个不用不爽的功能, 比如你编一个项目,
发现有很多import都没有用到,或者说你引用了一个类,但是你没有import,

结果编译不通过, 那都没关系, 一用这个,所有的问题迎刃而解. 至少我用这个之后, 就
从来没有写过import这类语句了. 快捷键是"Ctrl+Shift+O(是字母O,不是数

字0)", 我经常把这个和c+s+f一起用, 呵呵,人也变懒了不少

- Override/Implement Method: 这个比如你写一个类, 实现了某一个接口,但是
你还没有实现那个接口的函数, 那就用这个,它会自动搜索父类和接口的方

法,你可以选择要覆盖还是实现哪些函数

- Generate Getter and Setter: 如果你加了一个类变量, 要为它写getter和se
tter,不用那么麻烦, 用这个把,都是自动的

- Generate Delegating Method: 如果某一个field要生成代理函数,用这个把,
选一下就ok

- Add Javadoc Comment: 点中某一个你想要加javadoc的函数或类或变量,然后
选这项,它会自动帮你加好javadoc的头,包括你用的那些param或return

- surround with try/catch block: 比如你有一段代码要处理某些exception,
可你又忘了用try/catch来写,别急,选中那段代码,然后选这项,你会发觉它会

自动针测你这段代码里要抛出哪些exception,并且自动生成好所有代码

- externalize string: 这个是在做国际化的时候用的,简单的说,就是把string
包在resource bundle里, 这也是i18n的一个解决方案,我想我以后会详细介

绍这方面的东西.

2. 重构功能:
重构这两年很热, 那让我们看看jdt里面的重构到底有多强. 呵呵, 这也是eclipse最吸
引我的一个地方.

打开菜单
+ Refactor
- Rename: 如果你写了一个类,你发觉这个类某个类变量的名字起的不太好听
, 你觉得不爽, 于是你就想改名字, 那怎么改呢, 就把那个变量名改了

? 呵呵,没那么简单,因为你这个变量如果已经在某些函数里引用到,那编译要出错了, 而
且你根本就不知道你哪里引用了, 写了那么多代码,脑子都晕了, 那不是死

菜了吗? 别紧张, 用这个rename可以帮你解决一切问题, 它不仅可以帮你把变量的名字
改了,而且它还会自动搜寻所有这个变量被引用到的地方,然后把那些地方也

一起改了, 爽不爽啊, 给你省了很大的劳动力不是.

- Move: 同样, 要移动一个实现了的静态函数或变量到别的类的话,
用这个移动, 保证不出错

- Modify Method Signature: 你设计函数不可能一下子就定型的,比如你一开始这
个函数有一个参数,后来发觉不对,要用两个, 那你就要用这个来改, 这

样它还会搜寻所有已经引用这个函数的地方, 并且把这些应用的地方也改掉,否则编译也
要出错的

- Extract Interface: 它可以帮你把一个类抽象成一个接口, 规范你的代码

- Extract Method: 如果你写了一段很长的函数, 但是这个函数有些代码有
重复利用性, 你就可以把给分割出来, 选中那段代码,然后选这项,系统会问

你抽出来的函数的定义, 然后它就会生成这段函数,把实现从原来函数那里抽出来,并在
原来函数那里写一个对这个新函数的引用,以保证程序不变性.

- Extract Local Variable: 如果你发觉你函数里有些值都是通过一样的表达
式得到的,你就可以通过这项把这段表达式变成一个变量,并且把这个变量替

换到引用到表达式的地方

- Extract Constant: 抽取常量, 比如一个string= "eclipse", 你觉得很多
地方要用到, 那就抽出来变成一个常量 ECLIPSE, 就这么简单

- convert local variable to field : 这个看名字就知道, 不多说了

- encapsulate field: 这个和生成getter,setter有点类似, 但是不同的在于,
如果你有一个public的常量 var,并且已经在别处引用到了, 那你用生成

getter,setter肯定有问题, 因为引用的地方没改过来, 用这个的话,不仅会生成getter,
setter,而且还会改掉所有引用的地方, 比如把var = ...;的地方改成

setvar(...), 把 ... = var地方改成 ... = getvar(); , 呵呵,够强把...


3. 敏感帮助:

这个jb之类的ide也有, 启动方式为"alt+/" , 你如果觉得这个不爽,可以选preference-
>workbench->keys->edit->content assist 修改键值
而且,这个敏感帮助还有一个强的地方在于:
你如果想写一个for语句, 呵呵, 就打 for, 然后alt+/, 选一个for的生成方式, 一个完
成的for语句就出来了, 呵呵,eclipse多用用, 人都会变懒的
这个功能其实是jdt的模板功能,你也可以加自己用的模板, 具体在 preference->
java -> editor ->templates 加

4. Quick Fix功能:

比如我们来编一个类A, 如下:
public class A {
    
    public static void main(String args[]){
        System.out.prin("Hello World");
                   
    }
}

编译是不通过的,print方法打错了, 打成prin了

所有你会发觉那一行的左边有个红差差,说明这行有错误,你把鼠标移到那个红差差上,它
会有一个提示出来,告诉你出了什么错了

这还不止,你还发觉在红差差左边有个电灯泡, 你点那个电灯泡,它会弹出框问你是chang
e to print 还是change to println, 选择change to print, 它就自动帮

你改好了,呵呵,连改错都这么方便,太爽了. 当然,如果没有电灯泡的话,你就只能手动改
了,毕竟这东西没这么智能,可以帮你自动解决所有的问题

posted @ 2006-01-18 11:31 呓语的博客 阅读(171) | 评论 (0)编辑 收藏

(前言)
今天这篇侧重于eclipse的内部结构剖析,对于想开发插件的同志们,这些都是基础知识,
可以好好看看. 由于我写这个东西,也是随性发挥,想到什么就写什么. 而关于eclipse的
如何使用,如何用eclipse来开发一个java项目或其他项目之类的文章, 我想我会在以后
的文章中写到. 但我想对于要在开发eclipse上开发web项目,c项目或其他的话,你也要会
自己能安装相应的插件,才能开发,所以,这些基础知识的对于这些人来说还是很有必要的
.

(正文)

上一回我们且说到eclipse的下载,安装,启动. 其中讲到eclipse目录结构时,你会发现有
两个目录,一个叫plugins,一个叫features,而且你会发觉就这两个目录就占了整个eclip
se项目的9x%的空间,如果少了这两个目录,呵呵,eclipse根本就是空架子. 那这里面到底
存放了些什么东西呢, 让我们来研究一下.

[什么是 plug-in]

我们来做一个比喻, 你买了一套新房子,买过来是毛坯房,然后你稍微装修一下,铺了地板
,上了墙纸, 当然现在大家都要用家用电器, 没电咋行, 所以我们就要布好电线,装好电
源插座. 这个时候,你可以把这个房子想像成eclipse这个平台. 之后, 我们或许就要添
置家用电器了,比如电视, 音响等等, 等我们买好回家, 然后把电源往插座上一插, 那我
们就抱着孩子, 搂着老婆, 看电视, 听音乐, 舒舒服服的过上幸福美满的小生活了~~~

同样的, eclipse的plug-in 也是同样的工作原理, plug-in 只要放到/p
lugins目录下, eclipse启动后就会自动给所有在这个目录下的plug-ins, 通上电, 那这
些plug-ins就会自动的运行起来, 美妙的eclipse界面也随之呈现在你眼前.

那接下来,让我们看看eclipse这个由插件组成的平台,到底是个什么样的架构

[Eclipse 平台架构]


---------------------------------------------
| Eclipse Platform | --------
| | ---\ | |
| ----------------------- ------------ |==| _ |______| JDT |
| |Workbench | | | |==| | | |
| | | | | | ---/ --------
| | | | | |
| | ---------------| | Help | |
| | | jface | | | |
| |----------- | | | |
| | SWT | | | | |
| | | | ------------ |
| ----------------------- |
| ------------ | --------
| ------------------ | | | ---\ | |
| |Workspace | | | |==| _ |______| PDE |
| | | | Team | |==| | | |
| ------------------ | | | ---/ --------
| | | |
| ------------ |
---------------------------------------------


Eclipse Platform 就是一个房子, workbench,jface, swt, workspace, help, team,
jdt, pde都是基于这个平台的插件.

下面我介绍一下这些基础插件的基本功能:

*: workbench用来控制工作台, 负责控制工作台上包括菜单,视图,透视图等等的控制和
操作
*: SWT是一个类似AWT,SWING的java组件,是一个轻量级的组件,而且和awt,swing不同的
是,它底层实现不是基于jre,而是根据不同操作系统,有相应的动态链接库实现,所以作出
来的效果很专业, SWT主要用于workbench的ui绘制
*: jface是基于SWT的一个插件, 对SWT进行了封装, 封装实现了对话框, 视图等东东
*: workspace是用来控制工作区的,(有别于工作台), 包括对工作区内的项目的控制,删
除,添加,编译项目资源等等都由它来控制
*: help是一个eclipse帮助系统, eclipse的菜单->Help-> Help Content,就可以打开这
个帮助系统, 这个系统不是封闭的, 可以进行扩展(以后会介绍做eclipse帮助的插件)
*: team是一个cvs系统,可以和CVS server协调使用,进行版本控制
*: jdt 是 Java Development Tools, 开发java的插件
*: pde 是 plug-in development environment, 开发插件的平台

[plug-in 的基本结构]

每一个plug-in都用一个目录包起来, 而且起目录名也是有讲究的,比如plug-in的名字叫
edu.sjtu.bbs.eclipse,版本是1.0.0, 那这个目录名就是edu.sjtu.bbs.eclipse_1.0.0.

而且随便打开一个plugin目录,可以发现总有一个文件叫一个叫plugin.xml,这个文件对
于plugin来说十分重要, 它相当于定义了plugin的运行参数,没有这个,plugin无法启动,
就像你家的电冰箱如果不知道是用110V还是220V的,你也不敢乱往插座上插,所以总要有
个说明,这个说明就是plugin.xml. 至于这个文件有些什么具体结构,我想在以后介绍编
写插件的时候,我会详细介绍.

[什么是 feature]

feature是功能部件,它里面没有实际的运行的库,它只是eclipse用来管理plugins的一种
途径. 比如你家装了电灯,总要有开关控制把,比如大堂的灯有一个开关控制, 卧室的灯
也有一个开关控制, 它们分别用来控制灯的亮与灭.
同样,功能部件就是用来控制插件的启动与否. eclipse的update透视图可以设定各个功
能部件的启用或禁用状态, 所以你可以通过禁用功能部件,来禁止插件的启动. 这样有一
个好处,比如你装了很多插件在eclipse上,但是装的越多,加载就越多,启动也会变慢, 你
不信的话,可以玩玩wsad, 就知道我说的话不是假的了.
所以,我们可以把功能部件看作是插件或插件集合的开关, 用来控制插件的状态. 如果pl
ugins目录有插件没有被任何一个功能部件包络的话, 我称之为"野插件", 就是eclipse
启动,它也一定会启动, 就相当于没有开关, 电源一直连通一样.

当然,功能部件还有很多其他方面的用处,以后会有详细介绍.

posted @ 2006-01-18 11:30 呓语的博客 阅读(207) | 评论 (0)编辑 收藏

(前言)

Eclipse这个新的东东,大家都很感兴趣,为了帮助初学者揭开Eclipse的神秘面纱,也为了
总结一下自己的使用开发经验,所以打算写下来共享给大家,当然我也是在不断的摸索中,
文中如有不对之处,还望大家指正.

(正文)

Eclipse项目是IBM在2001年捐献的一个开发平台,当时此项目评估价值为40million
USD. 此东东如此值钱,可见自是有过人之处. 接下来直接转入正题, 哪里可以下到Eclip
se呢.

[Eclipse 下载]

下载Eclipse的官方网站:

http://www.eclipse.org/downloads/

这个网站上有很多mirror,你可以根据网路,选择自己最方便的下载mirror
如果你在交大的校园的话,呵呵,那就去这里

ftp://ftp.sjtu.edu.cn/mirror/sites/download.eclipse.org/

这个目录是也是一个Eclipse网站的镜像,但是为什么没有公布在Eclipse.org网站上,这
我就不清楚了
你可以从上述网站上找到Eclipse的下载包
上了网站,你会发现有许多Eclipse版本,有1.x, 2.x, 3.x,那到底该用什么版本呢?

[Eclipse 版本 (以及WSAD版本)]

IBM有个深受大家欢迎的产品,叫做Webshpere Studio Application Developer (WSAD),
当时WSAD4.0发布时用的Eclipse是1.0版本的,后来IBM把Eclipse捐献出来后,就陆续开发
了2.x版本,而且也应用到了后来的WSAD产品,现在WSAD5.0用的是Eclipse 2.0, WSAD
5.1 用的是Eclipse 2.1.1.
现在Eclipse.org Release的最近Release的版本是Eclipse 2.1.3, 相信大家平时要用Ec
lipse做开发的话,用2.1.3比较合适.
同时,如果你如果想尝尝鲜的话,就试试Eclipse 3.0版本,现在3.0还没有Release,
Eclipse 3.0的开发过程是分成10个Milestone来分的,现在已经开发到第8个Milestone,
就是Eclipse 3.0M8. 大家可以试试. 预计3.0的正式版本要到今年6月发布, 相信到时候
发布不久后, WSAD6.0就会发布了. 呵呵,期待啊 @_@

另外对于Eclipse的开发,还有一种版本标记方式,是分别已 N, I, R 打头的, 比如
N20040101之类的, 大家会觉得纳闷,这到底代表什么意思呢. 其实, N 是 Nightly
Build , I 是 Integration Build, R 是 Release Build, 特别是对于大型软件, 有时
编译一个项目要花很多时间, 所以很多时候编译的工作就放在了夜里, 所以就有了
Nightly Build 这一说, 而Nightly版本在经过集成测试,就生成了 Integration 版本.
Integration版本再经过严格的测试,最后就发布Release版本. 所以 稳定性程度: R >
I > N.

相信大家了解了这个版本后,就可以当自己想要的版本了.
等当好了之后,我们就可以安装了

[Eclipse 安装] (以 R2.1.3 版本为例)

当下来的东东是一个压缩包, 然后你要做的就是把这个压缩包解压都某一个目录,为了方
便介绍,我们叫这个目录为.

让我们展开一下这个目录看看:

|
--- /plugins 存放插件的目录 (稍后介绍)
--- /features 存放功能部件的目录 (稍后介绍)
--- /links 其他plugins和features的连接地址的存放目录 (稍后介绍)
--- /readme
--- eclipse.exe 启动Eclipse程序
--- ...


[启动 Eclipse]

但是如果你机器还没有装jre的话,那eclipse还是不能启动的
如果没有的话,去java.sun.com当一个jre,安装好jre之后才能启动
如果你同时有几个jre, 那eclipse会自动搜索注册表,并找到版本高的jre使用.

提示: 如果想指定eclipse使用你想它使用的jre的话,可以设置eclipse.exe的启动参数:

eclipse.exe -vm

然后你就可以启动eclipse了, 慢慢等, 还是挺慢的, 你可以顺便喝口茶, 欣赏欣赏eclipse的splash画面, 呵呵
启动好后, eclipse的开发平台就展现你的眼前了.

在这个启动的时候, eclipse自动创建了一个workspace, 你可以在的目
录下看到一个workspace的目录,这个目录下还有一个.metadata的目录,这个目录存着你
这个启动的工作区的所有配置.

当然,如果你不想把workspace这个工作区目录放到别的目录下,也没有问题,设置一下eclipse的启动参数:
eclipse.exe -data

以后,你如果同时要开发好几个项目, 当时有不想放一个工作区里, 学会启动的不同的工作区是必要的

posted @ 2006-01-18 11:29 呓语的博客 阅读(199) | 评论 (0)编辑 收藏

  • Vector 还是ArrayList,哪一个更好,为什么?

要回答这个问题不能一概而论,有时候使用Vector比较好;有时是ArrayList,有时候这两个都不是最好的选择。你别指望能够获得一个简单肯定答案,因为这要看你用它们干什么。下面有4个要考虑的因素:

(1)API

(2)同步处理

(3)数据增长性

(4)使用模式

下面针对这4个方面进行一一探讨

API
在由Ken Arnold等编著的《Java Programming Language》(Addison-Wesley, June 2000)一书中有这样的描述,Vector类似于ArrayList.。所有从API的角度来看这两个类非常相似。但他们之间也还是有一些主要的区别的。

同步性

Vector是同步的。这个类中的一些方法保证了Vector中的对象是线程安全的。而ArrayList则是异步的,因此ArrayList中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销。

数据增长

从内部实现机制来讲ArrayList和Vector都是使用数组(Array)来控制集合中的对象。当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据那么使用Vector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。

使用模式

在ArrayList和Vector中,从一个指定的位置(通过索引)查找数据或是在集合的末尾增加、移除一个元素所花费的时间是一样的,这个时间我们用O(1)表示。但是,如果在集合的其他位置增加或移除元素那么花费的时间会呈线形增长:O(n-i),其中n代表集合中元素的个数,i代表元素增加或移除元素的索引位置。为什么会这样呢?以为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行位移的操作。这一切意味着什么呢?

这意味着,你只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是其他操作,你最好选择其他的集合操作类。比如,LinkList集合类在增加或移除集合中任何位置的元素所花费的时间都是一样的—O(1),但它在索引一个元素的使用缺比较慢-O(i),其中i是索引的位置.使用ArrayList也很容易,因为你可以简单的使用索引来代替创建iterator对象的操作。LinkList也会为每个插入的元素创建对象,所有你要明白它也会带来额外的开销。

最后,在《Practical Java》一书中Peter Haggar建议使用一个简单的数组(Array)来代替Vector或ArrayList。尤其是对于执行效率要求高的程序更应如此。因为使用数组(Array)避免了同步、额外的方法调用和不必要的重新分配空间的操作。

posted @ 2006-01-16 09:47 呓语的博客 阅读(177) | 评论 (0)编辑 收藏

http://forum.javaeye.com/viewtopic.php?p=17108&highlight=Serializable+generate+SessionImplementor+sessionImplementor%2C#17108

看了看。真是万分高兴,可能别人用了一个星期才解决的问题。我现在就可以不劳而获。惭愧啊。。

由于担心Hibernate自身提供的increment id generator有性能影响,我对increment进行了扩展,改为InMemoryIncrement:

InMemoryIncrement.java

代码:
//Declare Classes Import here,Do not use .* to import all the classes in package.
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import java.util.Map;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.MappingException;
import net.sf.hibernate.dialect.Dialect;
import net.sf.hibernate.engine.SessionImplementor;
import net.sf.hibernate.type.Type;
import net.sf.hibernate.id.IdentifierGenerator;
import net.sf.hibernate.id.PersistentIdentifierGenerator;
import net.sf.hibernate.id.Configurable;

/**
* Hibernate high performence id generator extend IncrementGenerator.<br>
* This generator use ’select max(column) from table ’ to get id’s init value
* in first time.Then generate increment id in memory .
* <p>
* 原理:
* <li>使用long[]数组在内存中存储每个表的最大值,使用Map存储表名在数组中对应的索引值。
* <li>第一次访问某个表的id的最大值时会从数据库中取出并存放到long数组中,
* 同时在Map中保存索引值
* <li>第二次以后访问会首先从Map中读出索引值,根据索引值把long数组对应的值
* 加上递增步长并返回
* </p>
* @author fenghm
* @version $Revision$
*/
public final class InMemoryIncrement implements IdentifierGenerator, Configurable {

    private static final Log log = LogFactory.getLog(InMemoryIncrement.class);
    
    //存储最大值的数组的容量
    private static final int MAX_CAPACITY = 200;
    
    /**同步锁*/
    private static final Object lock = new Object();

    //存储表存储在数组中的索引值
    private static Map map = new HashMap();
    
    //递增步长,默认加1
    private int step = 1;
    
    //最大值数组
    private static long[] seqs = new long[MAX_CAPACITY];
    
    //最大值数组已经使用的容量
    private static int lastIndex;
    
    private String key;
    private String sql;
    private Connection connection;
    private Class returnClass;
    
    /**
     * (none java doc)
     * @see net.sf.hibernate.id.IdentifierGenerator#
     * generate(net.sf.hibernate.engine.SessionImplementor, java.lang.Object)
     */
    public Serializable generate(SessionImplementor session, Object object)
    throws SQLException, HibernateException {
        connection = session.connection();
        
        long seq = -1;
        
        //找到索引值
        int index = findIndex();
        
        //把最大值加1
        seqs[index] = seqs[index] + step;
        
        seq = seqs[index];
        
        return new Long(seq);
    }

    /**
     * 找到表中自动增长字段存储在数组中的索引值
     * @return 索引值
     */
    private int findIndex(){
        int index = 0;
        
        //首先中缓存中取出索引值
        Integer integer = (Integer)map.get(key);
        
        //如果没有找到就从数据库中读出最大值并进行cache
        if(null == integer){
            //double check lock
            synchronized(lock){
                integer = (Integer)map.get(key);
                if(null == integer){
                    long maxvalue = 1;
                    try{
                        maxvalue = getMaxvalue();
                    }catch(SQLException e){
                        log.error(e);
                    }
                    integer = new Integer(lastIndex++);
                    seqs[integer.intvalue()] = maxvalue;
                    map.put(key,integer);                
                }
            }
        }
        
        index = integer.intvalue();
        return index;
    }    
    
    /**
     * (none java doc)
     * @see net.sf.hibernate.id.Configurable#configure(net.sf.hibernate.type.Type,
     * java.util.Properties, net.sf.hibernate.dialect.Dialect)
     */
    public void configure(Type type, Properties params, Dialect d)
    throws MappingException {
        
        //取出table参数
        String table = params.getProperty("table");
        if (table == null){
            table = params.getProperty(PersistentIdentifierGenerator.TABLE);
        }
        //取出column参数
        String column = params.getProperty("column");
        if (column == null){
            column = params.getProperty(PersistentIdentifierGenerator.PK);
        }
        
        //表的sehcma参数
        String schema = params.getProperty(PersistentIdentifierGenerator.SCHEMA);
        
        returnClass = type.getReturnedClass();
        
        //取出step参数
        String stepvalue = params.getProperty("step");
        if(null != stepvalue && !"".equals(stepvalue.trim())){
            try{
                step = Integer.parseInt(stepvalue);
            }catch(Exception e){
                log.error(e);
            }
        }
        

        //构造存储在Map中的索引值的key name
        key = table + "_$_" + column;
        
        //根据参数构造取最大值的SQL
        sql = "select max(" + column + ") from ";
        if(null != schema){
            sql += schema + ".";
        }
        sql += table;
    }
    
    /**
     * 取指定表中id字段的最大值,不存在记录返回0
     * @return 最大值
     * @throws SQLException if sql error occurs.
     */
    private long getMaxvalue() throws SQLException {
        long maxvalue = 0;
        
        PreparedStatement st = connection.prepareStatement(sql);
        ResultSet rs = null;
        try {
            rs = st.executeQuery();
            if(rs.next()) {
                maxvalue = rs.getLong(1);
            }
            sql = null;
        }finally {
            if (rs != null){
                rs.close();
            }
            st.close();
        }
        return maxvalue;
    }



测试代码:
Data.java
代码:
public class Data {

    private long id;
    private String name;
    private String email;

    /**
     * @return
     */
    public String getEmail() {
        return email;
    }

    /**
     * @return
     */
    public long getId() {
        return id;
    }

    /**
     * @return
     */
    public String getName() {
        return name;
    }

    /**
     * @param string
     */
    public void setEmail(String string) {
        email = string;
    }

    /**
     * @param l
     */
    public void setId(long l) {
        id = l;
    }

    /**
     * @param string
     */
    public void setName(String string) {
        name = string;
    }
}


Data.hbm.xml
代码:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package="com.kmview.test.hibernate.model">
   <class name="Data" table="data">
      <id name="id" type="long" column="id">
         <generator class="com.kmview.test.hibernate.Generator"/>
      </id>
      <property name="name" type="java.lang.String" length="20" column="name"/>
      <property name="email" type="java.lang.String" column="email"/>
   </class>
</hibernate-mapping>



ThreadMain.java
代码:

public class ThreadMain extends Thread {

    public static void main(String[] args) {
        try{
            Configuration cfg = new Configuration().configure();
            SchemaExport schema = new SchemaExport(cfg);      
            schema.create(false,true);  

            for(int i=0;i<100;i++){
                new ThreadMain().start();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    public void run(){
        try{
            for(int i=0;i<20;i++){
            Session session = HibernateSession.openSession();

            Data data = new Data();
            data.setName("sdfsfsdf");
            data.setEmail("sdflkas;lfdalsfjasljf@d.d");

            session.save(data);
        
            session.flush();
            HibernateSession.closeSession();
            }              
        }catch(Exception e){
            e.printStackTrace();
        }
              
    }
}


HibernateSession.java
代码:
public final class HibernateSession {

    private HibernateSession(){}
    
    //synchronized lock for getSessionFactory
    private static Object lock = new Object();
    
    //common log object
    private static Log log = LogFactory.getLog(HibernateSession.class);
    
    //Hibernate SessionFactory
    private static SessionFactory sessionFactory;
    
    //Implement Hibatenate ThreadLocal pattern
    private static final ThreadLocal session = new ThreadLocal();
    
    
    /**
     * 自动在ClassPath的根路径寻找hibernate.properties与hibernate.cfg.xml文件<br>
     * 并初始化SessionFactory
     * @return SessionFactory
     */
    private static SessionFactory buildSessionFactory(){
        SessionFactory factory = null;
        try{
            Configuration config = new Configuration();
            config = config.configure();
            
            factory = config.buildSessionFactory();
            log.info("ok,SessionFactory builded!");
        }catch(HibernateException e){
            log.error(e);    
        }
        return factory;
    }
      
    /**
     * 取得当前会话的Hibernae Session对象,并打开数据库连接
     * @return Hibernate Session Object for Data Access
     * @exception HibernateException throw HibernateException
     */
    public static Session openSession() throws HibernateException{
        Session s = (Session)session.get();
        if(null == s){
            getSessionFactory();            
            if(null != sessionFactory){
                s = sessionFactory.openSession();
                session.set(s);
            }else{
                log.error("Error,SessionFactory object is not inited!");                  
            }
        }else if(!s.isConnected()){
            s.reconnect();
        }
        return s;
    }
    
    /**
     * 关闭数据库连接,在每次Session用完的时候,应该马上调用closeSession,<br>
     * 以把数据库连接归还到数据库连接池中,提高并发性能。
     */
    public static void closeSession(){
        try{
            Session s = (Session)session.get();
            if(null != s && s.isConnected()){
                s.disconnect();        
            }            
        }catch(HibernateException e ){
            log.error(e);
        }
    }
    
    /**
     * 释放Hibernate Session对象,此方法应该在当前线程消亡之前调用。<br>
     * 例如:在Web应用中可以使用filter统一在最后进行调用<br>
     * <code><pre>
     * public class HibernateFilter extends HttpServlet implements Filter{
     *  private FilterConfig filterConfig;
     *  public void init(FilterConfig filterConfig){
     *     this.filterConfig = filterConfig;
     *  }
     *
     *  public void doFilter(ServletRequest request,ServletResponse response,    
     *                       FilterChain filterChain){
     *     try{
     *        filterChain.doFilter(request,response);
     *     } catch(ServletException sx){
     *        filterConfig.getServletContext().log(sx.getMessage());
     *     } catch(IOException iox){
     *        filterConfig.getServletContext().log(iox.getMessage());
     *     }finally{
     *        HibernateSession.releaseSession();      
     *     }
     *  }
     * }
     * </pre></code>
     * 在Hibernate的API文档提到,Session的close()方法不是必须要被调用的,<br>
     * 但disconnect()方法是必须的;所以此方法也不是必须要被调用的,但是<br>
     * closeSession()方法是必须的。
     * @exception HibernateException throw HibernateException
     */
    public static void releaseSession() throws HibernateException{
        Session s = (Session)session.get();
        session.set(null);
        if(null != s){
            s.close();
        }
    }
    
    /**
     * 设置SessionFactory,提供此方法是为了可以在外部初始化SessionFactory.
     * @param factory SessionFactory
     */
    public static void setSessionFactory(SessionFactory factory){
        if(null == sessionFactory){
            sessionFactory = factory;
        }
    }
    
    /**
     * 获取SessionFactory,第一次访问时会自动在ClassPath的根路径寻找<br>
     * hibernate.properties与hibernate.cfg.xml文件并初始化。
     * @return SessionFactory
     */
    public static SessionFactory getSessionFactory(){
        //Double check lock.
        if(null == sessionFactory){
            synchronized(lock){
                if(null == sessionFactory){
                    sessionFactory = buildSessionFactory();
                }
            }
        }
        return sessionFactory;
    }
}

posted @ 2006-01-13 11:34 呓语的博客 阅读(369) | 评论 (0)编辑 收藏

从网上当了一个例子,发觉上传图片文件时图片文件中内容发生了变化,最大的变化时所有的FF变成了3F

也就是说输出时把字符当成有符号传送了?(是这样把?)

使用代码如下:

PrintWriter pw = new PrintWriter(new BufferedWriter(new

FileWriter((savePath==null? "" : savePath) + filename)));

while (i != -1 && !newLine.startsWith(boundary)) {

// 文件内容的最后一行包含换行字符

// 因此我们必须检查当前行是否是最

// 后一行

i = in.readLine(line, 0, 1280);

if ((i==boundaryLength+2 || i==boundaryLength+4)

&& (new String(line, 0, i).startsWith(boundary)))

pw.print(newLine.substring(0, newLine.length()-2));

else

pw.print(newLine);

newLine = new String(line, 0, i);

 

}

pw.close();

 

但是总是不行,后来我把PrintWriter用FileOutputStream替代,代码如下:

FileOutputStream pw=new FileOutputStream((savePath==null? "" : savePath) + filename);

//PrintWriter pw = new PrintWriter(new BufferedWriter(new

//FileWriter((savePath==null? "" : savePath) + filename)));

while (i != -1 && !newLine.startsWith(boundary)) {

// 文件内容的最后一行包含换行字符

// 因此我们必须检查当前行是否是最

// 后一行

i = in.readLine(line, 0, 1280);

if ((i==boundaryLength+2 || i==boundaryLength+4)

&& (new String(line, 0, i).startsWith(boundary)))

pw.write(newLine.substring(0, newLine.length()-2).getBytes("ISO8859_1"));

else

pw.write(newLine.getBytes("ISO8859_1"));

newLine = new String(line, 0, i,"ISO8859_1");

 

}

pw.close();

竟然就可以了,那个转换的编码还一定要上才行,不然也不干活的,真是郁闷,这跨平台就不能让写CODE的人解放解放,一个输出都N多类,看着心寒,想着简直想死啊

忙了我一个下午,原来就是这回事

 

下面把原代码附上,是把别人的代码改吧改吧放上来的,还请原作者不要见意:

Java bean 文件:

package cr.web;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.ServletInputStream;

import java.util.Dictionary;

import java.util.Hashtable;

import java.io.PrintWriter;

import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.IOException;

import java.io.*;

public class FileUploadBean {

 

private String savePath, filepath, filename, contentType;

private byte[] b;

byte t;

private Dictionary fields;

 

public String getFilename() {

return filename;

}

 

public String getFilepath() {

return filepath;

}

 

public void setSavePath(String savePath) {

this.savePath = savePath;

}

 

public String getContentType() {

return contentType;

}

 

public String getFieldValue(String fieldName) {

if (fields == null || fieldName == null)

return null;

return (String) fields.get(fieldName);

}

 

private void setFilename(String s) {

if (s==null)

return;

 

int pos = s.indexOf("filename=\"");

if (pos != -1) {

filepath = s.substring(pos+10, s.length()-1);

// Windows浏览器发送完整的文件路径和名字

// 但Linux/Unix和Mac浏览器只发送文件名字

pos = filepath.lastIndexOf("\\");

if (pos != -1)

filename = filepath.substring(pos + 1);

else

filename = filepath;

}

}

private void setContentType(String s) {

if (s==null)

return;

 

int pos = s.indexOf(": ");

if (pos != -1)

contentType = s.substring(pos+2, s.length());

}

 

public void getByte(HttpServletRequest request)

{

DataInputStream is;

 

int i=0;

try

{

is=new DataInputStream(request.getInputStream());

b=new byte[request.getContentLength()];

 

while (true)

{

try

{

t=is.readByte();

b[i]=t;

i++;

}

catch(EOFException e)

{ break;}

}

is.close();}

catch(IOException e)

{}

}

 

public void doUpload1(HttpServletRequest request) throws

IOException {

byte[] line=new byte[128];

FileOutputStream os=new FileOutputStream("c:\\Demo.out");

ServletInputStream in = request.getInputStream();

getByte(request);

String temp="";

temp=new String(b,"ISO8859_1");

byte[] img=temp.getBytes("ISO8859_1");

for (int i=0;i<img.length;i++)

{ os.write(img[i]); }

os.close();

}

 

 

 

public void doUpload(HttpServletRequest request) throws IOException {

request.setCharacterEncoding("GB2312");

ServletInputStream in = request.getInputStream();

 

byte[] line = new byte[1280];

int i = in.readLine(line, 0, 1280);

if (i < 3)

return;

int boundaryLength = i - 2;

 

String boundary = new String(line, 0, boundaryLength); //-2丢弃换行字符

fields = new Hashtable();

 

while (i != -1) {

String newLine = new String(line, 0, i);

if (newLine.startsWith("Content-Disposition: form-data; name=\"")) {

if (newLine.indexOf("filename=\"") != -1) {

setFilename(new String(line, 0, i-2));

if (filename==null)

return;

//文件内容

i = in.readLine(line, 0, 1280);

setContentType(new String(line, 0, i-2));

i = in.readLine(line, 0, 1280);

//空行

i = in.readLine(line, 0, 1280);

newLine = new String(line, 0, i,"ISO8859_1");

FileOutputStream pw=new FileOutputStream((savePath==null? "" : savePath) + filename);

//PrintWriter pw = new PrintWriter(new BufferedWriter(new

//FileWriter((savePath==null? "" : savePath) + filename)));

while (i != -1 && !newLine.startsWith(boundary)) {

// 文件内容的最后一行包含换行字符

// 因此我们必须检查当前行是否是最

// 后一行

i = in.readLine(line, 0, 1280);

if ((i==boundaryLength+2 || i==boundaryLength+4)

&& (new String(line, 0, i).startsWith(boundary)))

pw.write(newLine.substring(0, newLine.length()-2).getBytes("ISO8859_1"));

else

pw.write(newLine.getBytes("ISO8859_1"));

newLine = new String(line, 0, i,"ISO8859_1");

 

}

pw.close();

 

}

else {

// 普通表单输入元素

// 获取输入元素名字

int pos = newLine.indexOf("name=\"");

String fieldName = newLine.substring(pos+6, newLine.length()-3);

 

i = in.readLine(line, 0, 1280);

i = in.readLine(line, 0, 1280);

newLine = new String(line, 0, i);

StringBuffer fieldValue = new StringBuffer(1280);

while (i != -1 && !newLine.startsWith(boundary)) {

// 最后一行包含换行字符

// 因此我们必须检查当前行是否是最后一行

i = in.readLine(line, 0, 1280);

if ((i==boundaryLength+2 || i==boundaryLength+4)

&& (new String(line, 0, i).startsWith(boundary)))

fieldValue.append(newLine.substring(0, newLine.length()-2));

else

fieldValue.append(newLine);

newLine = new String(line, 0, i);

}

fields.put(fieldName, fieldValue.toString());

}

}

i = in.readLine(line, 0, 1280);

 

}

}

}

 

HTML页面:

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>文件上载</title>

</head>

 

<body>

<form action=jsp1.jsp enctype="MULTIPART/FORM-DATA" method=post>

作者: <input type=text name=author>

<br>

公司: <input type=text name=company>

<br>

说明: <textarea name=comment></textarea>

<br>

选择要上载的文件<input type=file name=filename>

<br>

文件描述: <input type=text name=description>

<br>

<input type=submit value="Upload">

</form>

</body>

</html>

 

JSP页面:

<%@ page contentType="text/html;charset=gb2312"%>

<jsp:useBean id="TheBean" scope="page" class="cr.web.FileUploadBean" />

<%

TheBean.setSavePath("d:\\");

 

//TheBean.doUpload1(request);

TheBean.doUpload(request);

out.println("Filename:" + TheBean.getFilename());

out.println("<BR>内容类型:" + TheBean.getContentType());

out.println("<BR>作者:" + TheBean.getFieldValue("Author"));

out.println("<BR>公司:" + TheBean.getFieldValue("Company"));

out.println("<BR>说明:" + TheBean.getFieldValue("Comment"));

%>

 

posted @ 2006-01-13 10:47 呓语的博客 阅读(194) | 评论 (0)编辑 收藏

用户定义类型

单值类型是与现存类型(它的“源”类型)共享其内部表示的用户定义数据类型,但对于大多数运算来说,认为单值类型是独立和不兼容的。例如,您可能想定义年龄类型、重量类型以及高度类型,所有这些类型都有相当不同的语义,但都使用内部数据类型 INTEGER 作为它们的内部表示。

下列示例说明了命名为 PAY 的单值类型的创建:

     CREATE DISTINCT TYPE PAY AS DECIMAL(9,2) WITH COMPARISONS

虽然 PAY 有与内部数据类型 DECIMAL(9,2)相同的表示,但还是认为它是与 DECIMAL(9,2)或任何其他类型不可比的独立类型。它只能与相同的单值类型比较。并且,会影响到按 DECIMAL 使用的运算符和函数将在此不适用。例如,具有 PAY 数据类型的值不能与具有 INTEGER 数据类型的值相乘。因此,您必须编写只应用于 PAY 数据类型的函数。

使用单值数据类型可限制偶然错误。例如,如果将 EMPLOYEE 表的 SALARY 列定义为 PAY 数据类型,则不能将该列添加至 COMM,即使它们的源类型相同。

单值数据类型支持类型转换。源类型可以转换为单值数据类型,单值数据类型也可以转换为源类型。例如,如果将表 EMPLOYEE 的 SALARY 列定义为 PAY 数据类型,则下列示例将不会在比较运算符处出错。

     SELECT * FROM EMPLOYEE
        WHERE DECIMAL(SALARY) = 41250

DECIMAL(SALARY)返回一个十进制数据类型。相反地,数字数据类型可以转换为 PAY 类型。例如,可以使用 PAY(41250) 来转换数字 41250 的类型。

用户定义函数

使用函数中所述,DB2 通用数据库提供内部函数和用户定义函数 (UDF)。然而,此函数集从不会满足所有需求。您常常需要为特别的任务创建定制函数。用户定义函数允许您创建定制函数。

用户定义函数有两种类型:外部函数

源用户定义函数允许允许用户定义类型有选择地引用另一个已为数据库所知的内部函数或用户定义函数。您可以既使用标量函数又使用列函数。

在下一示例中,基于内部 MAX 列函数来创建称为 MAX 的用户定义函数,它采用 DECIMAL 数据类型作为输入。MAX UDF 采用 PAY 类型作为输入且返回一个 PAY 类型作为输出。

     CREATE FUNCTION MAX(PAY) RETURNS PAY
        SOURCE MAX(DECIMAL)

外部用户定义函数由用户用程序设计语言编写。有外部标量函数外部表函数,在 SQL Reference 中讨论了这两个函数。

假定您已编写了一个计算字符串中字数的函数,则您可以使用 CREATE FUNCTION 语句以名称 WORDCOUNT 向数据库注册该函数。然后就可在 SQL 语句中使用此函数。

例如,下列语句返回雇员编号和他们简历的 ASCII 格式的字数。WORDCOUNT 是用户已向数据库注册并且现正在语句中使用的外部标量函数。

 
     SELECT EMPNO, WORDCOUNT(RESUME)
        FROM EMP_RESUME
        WHERE RESUME_FORMAT = 'ascii'

有关编写用户定义函数的更详细信息,参考 Application Development Guide

大对象 (LOB)

术语大对象及其缩写词 LOB 用于表示三种数据类型:BLOB、CLOB 或 DBCLOB。这些类型可以包含诸如音频、图片以及文档等对象的大量数据。

二进制大对象(BLOB)是变长字符串,以字节进行量度,最大长度可达 2 吉字节。BLOB 主要用来保存非传统数据,如图片、声音以及混合媒体等。

字符大对象(CLOB)是变长字符串,以字节进行量度,最大长度可达 2 吉字节。 CLOB 用于存储大的单字节字符集数据,如文档等。CLOB 被认为是字符串。

双字节字符大对象(DBCLOB)是最大长度可达 2 吉字节的双字节字符变长字符串(1 073 741 823 双字节字符)。 DBCLOB 用于存储大的双字节字符集数据,如文档等。DBCLOB 被认为是图形字符串。

操作大对象(LOB)

由于 LOB 值可以很大,所以将它们从数据库服务器传送至客户机应用程序可能要花费一些时间。然而,一般一次处理 LOB 值的一部分,而不是将它们作为一个整体处理。对于应用程序不需要(或不想要)将整个 LOB 值存储在应用程序内存中的那些情况,应用程序可以通过大对象定位器变量引用此值。

然后后续语句可以使用定位器对数据执行操作,而不必检索整个大对象。定位器变量用来减少应用程序的存储器需求,并通过减少客户机与服务器之间的数据流而改进性能。

另一个机制是文件引用变量。它们用来直接对文件检索大对象或直接从文件来更新表中的大对象。文件引用变量用来减少应用程序的存储器需求,因为这些变量不必存储大对象数据。有关更多信息,参考 Application Development GuideSQL Reference

专用寄存器

专用寄存器是由数据库管理程序为连接定义的存储区,用于存储可以用 SQL 语句引用的信息。下列是几个较常用的专用寄存器的示例。有关所有专用寄存器的列表和更详细的信息,参考 SQL Reference

  • CURRENT DATE:保存对应于执行 SQL 语句时的日时钟的日期。

  • CURRENT FUNCTION PATH:保存一个指定用于分解函数和数据类型引用的函数路径的值。

  • CURRENT SERVER:指定当前应用程序服务器。

  • CURRENT TIME:保存对应于执行 SQL 语句时的日时钟的时间。

  • CURRENT TIMESTAMP:指定对应于执行 SQL 语句时的日时钟的时间戳记。

  • CURRENT TIMEZONE:指定世界时与应用程序服务器本地时间之间的差别。

  • USER:指定运行期权限 ID。

您可以用 VALUES 语句显示专用寄存器的内容。例如:

     VALUES (CURRENT TIMESTAMP)

也可以使用:

     SELECT CURRENT TIMESTAMP FROM ORG

这将为表中的每一行项返回 TIMESTAMP。

目录视图的介绍

DB2 为每个数据库创建并维护一个系统目录表扩充集。这些表包含关于数据库对象(如表、视图、程序包、参考完整性关系、函数、单值类型以及触发器等)的逻辑结构和物理结构的信息。这些表是在创建数据库时创建的,并在正常操作过程中得到更新。不能显式创建或卸下它们,但可以查询和查看其内容。

有关更多信息,参考 SQL Reference

从系统目录中选择行

目录视图象任何其他数据库视图一样。可以使用 SQL 语句来查看数据,确切地说,就是使用查看系统中任何其他视图的相同方式。

可以在 SYSCAT.TABLES 目录中找到关于表的非常有用的信息。要寻找已创建的现存表的名称,发出一个类似以下的语句:

 
     SELECT TABNAME, TYPE, CREATE_TIME
        FROM SYSCAT.TABLES
        WHERE DEFINER = USER

此语句产生下列结果:

     TABNAME            TYPE CREATE_TIME
     ------------------ ---- --------------------------
     ORG                T    1997-05-22-11.15.27.850000
     STAFF              T    1997-05-22-11.15.29.470000
     DEPARTMENT         T    1997-05-22-11.15.30.850000
     EMPLOYEE           T    1997-05-22-11.15.31.310000
     EMP_ACT            T    1997-05-22-11.15.32.850000
     PROJECT            T    1997-05-22-11.15.34.410007
     EMP_PHOTO          T    1997-05-22-11.15.35.190000
     EMP_RESUME         T    1997-05-22-11.15.40.600000
     SALES              T    1997-05-22-11.15.43.000000

下列列表包括与本书讨论的与主题有关的目录视图。还有很多其他目录视图,它们详细地在 SQL Reference管理指南中列出。
说明 目录视图
检查约束 SYSCAT.CHECKS
SYSCAT.COLUMNS
检查约束引用的列 SYSCAT.COLCHECKS
关键字中使用的列 SYSCAT.KEYCOLUSE
数据类型 SYSCAT.DATATYPES
函数参数或函数结果 SYSCAT.FUNCPARMS
参考约束 SYSCAT.REFERENCES
模式 SYSCAT.SCHEMATA
表约束 SYSCAT.TABCONST
SYSCAT.TABLES
触发器 SYSCAT.TRIGGERS
用户定义函数 SYSCAT.FUNCTIONS
视图 SYSCAT.VIEWS

posted @ 2006-01-10 20:29 呓语的博客 阅读(172) | 评论 (0)编辑 收藏

用约束和触发器实施商业规则

在商界,我们的确通常需要确保始终实施某些规则。例如,参与项目的雇员必须被雇用。或者想要某些事件有计划地发生。例如,如果销售员售出一批商品,则应增加其佣金。

DB2 通用数据库为此提供了一套有用的方法。 唯一约束是禁止在表的一列或多列中出现重复值的规则。 参考完整性约束确保在整个指定的表中数据一致性。 表检查约束是一些条件,它们定义为表定义的一部分,限制一列或多列中使用的值。触发器允许您定义一组操作,这些操作通过对指定的表进行删除、插入或更新操作来执行或触发。触发器可用于写入其他表、修改输入值以及发布警报信息。

第一节提供关键字的概念性概述。接着,通过示例和图表进一步探讨参考完整性、约束以及触发器。

关键字

关键字是可用来标识或存取特定行的一组列。

由不止一列组成的关键字称为组合关键字。在具有组合关键字的表中,组合关键字中各列的排序不受这些列在表中排序的约束。

唯一关键字

唯一关键字被定义为它的任何值都不相同。唯一关键字的列不能包含空值。在执行 INSERT 和 UPDATE 语句期间,数据库管理程序强制执行该约束。一个表可以有多个唯一关键字。唯一关键字是可选的,并且可在 CREATE TABLE 或 ALTER TABLE 语句中定义。

主关键字

主关键字是一种唯一关键字,表定义的一部分。一个表不能有多个主关键字,并且主关键字的列不能包含空值。主关键字是可选的,并且可在 CREATE TABLE 或 ALTER TABLE 语句中定义。

外部关键字

外部关键字在参考约束的定义中指定。一个表可以有零个或多个外部关键字。如果组合外部关键字的值的任何部分为空,则该值为空。外部关键字是可选的,并且可在 CREATE TABLE 语句或 ALTER TABLE 语句中定义。

唯一约束

唯一约束确保关键字的值在表中是唯一的。唯一约束是可选的,并且可以通过使用指定 PRIMARY KEY 或 UNIQUE 子句的 CREATE TABLE 或 ALTER TABLE 语句来定义唯一约束。例如,可在一个表的雇员编号列上定义一个唯一约束,以确保每个雇员有唯一的编号。

参考完整性约束

通过定义唯一约束和外部关键字,可以定义表与表之间的关系,从而实施某些商业规则。唯一关键和外部关键字约束的组合通常称为参考完整性约束。外部关键字所引用的唯一约束称为父关键字。外部关键字表示特定的父关键字,或与特定的父关键字相关。例如,某规则可能规定每个雇员(EMPLOYEE 表)必须属于某现存的部门(DEPARTMENT 表)。因此,将 EMPLOYEE 表中的“部门号”定义为外部关键字,而将 DEPARTMENT 表中的“部门号”定义为主关键字。下列图表提供参考完整性约束的直观说明。

图 4. 外部约束和主约束定义关系并保护数据

表检查约束

表检查约束指定对于表的每行都要进行判定的条件。可对个别列指定检查约束。可使用 CREATE 或 ALTER TABLE 语句添加检查约束。

下列语句创建具有下列约束的表:

  • 部门编号的值必须在范围 10 至 100 内
  • 雇员的职务只能为下列之一: "Sales"、"Mgr"或"Clerk"
  • 1986 年之前雇用的每个雇员的工资必须超过 $40,500。

 
     CREATE TABLE EMP
           (ID           SMALLINT NOT NULL,
            NAME         VARCHAR(9),
            DEPT         SMALLINT CHECK (DEPT BETWEEN 10 AND 100),
            JOB          CHAR(5)   CHECK (JOB IN ('Sales', 'Mgr', 'Clerk')),
            HIREDATE     DATE,
            SALARY       DECIMAL(7,2),
            COMM         DECIMAL(7,2),
            PRIMARY KEY (ID),
            CONSTRAINT YEARSAL CHECK (YEAR(HIREDATE) >= 1986 OR SALARY > 40500) )

仅当条件判定为假时才会违反约束。例如,如果插入行的 DEPT 为空值,则插入继续进行而不出错,尽管 DEPT 的值应该象约束中定义的那样在 10 和 100 之间。

下列语句将一个约束添加至名为 COMP 的 EMPLOYEE 表中,该约束为雇员的总报酬必须超过 $15,000:

 
     ALTER TABLE EMP
        ADD CONSTRAINT COMP CHECK (SALARY + COMM > 15000)

将检查表中现存的行以确保这些行不违反新约束。可通过使用如下的 SET CONSTRAINTS 语句将此检查延期:

     SET CONSTRAINTS FOR EMP OFF
     ALTER TABLE EMP ADD CONSTRAINT COMP CHECK (SALARY + COMM > 15000)
     SET CONSTRAINTS FOR EMP IMMEDIATE CHECKED
 

首先使用 SET CONSTRAINTS 语句以延期对表的约束检查。然后可将一个或多个约束添加至表而不检查这些约束。接着再次发出 SET CONSTRAINTS 语句,反过来将约束检查打开并执行任何延期的约束检查。

触发器

一个触发器定义一组操作,这组操作通过修改指定基表中数据的操作来激活。

可使用触发器来执行对输入数据的验证;自动生成新插入行的值;为了交叉引用而读取其他表;为了审查跟踪而写入其他表;或通过电子邮件信息支持警报。使用触发器将导致应用程序开发及商业规则的全面实施更快速并且应用程序和数据的维护更容易。

DB2 通用数据库支持几种类型的触发器。可定义触发器在 DELETE、INSERT 或 UPDATE 操作之前或之后激活。每个触发器包括一组称为触发操作的 SQL 语句,这组语句可包括一个可选的搜索条件。

可进一步定义后触发器以对每一行都执行触发操作,或对语句执行一次触发操作,而前触发器总是对每一行都执行触发操作。

在 INSERT、UPDATE 或 DELETE 语句之前使用触发器,以便在执行触发操作之前检查某些条件,或在将输入值存储在表中之前更改输入值。使用后触发器,以便在必要时传播值或执行其他任务,如发送信息等,这些任务可能是触发器操作所要求的。

下列示例说明了前触发器和后触发器的使用。考虑一个记录并跟踪股票价格波动的应用程序。该数据库包含两个表,CURRENTQUOTE 和 QUOTEHISTORY,定义如下:

 
     CREATE TABLE CURRENTQUOTE
     (SYMBOL VARCHAR(10),
      QUOTE DECIMAL(5,2),
      STATUS VARCHAR(9))
     
     CREATE TABLE  QUOTEHISTORY
     (SYMBOL VARCHAR(10),
      QUOTE DECIMAL(5,2),
      TIMESTAMP TIMESTAMP)

当使用如下语句更新 CURRENTQUOTE 的 QUOTE 列时:

 
     UPDATE CURRENTQUOTE
        SET QUOTE = 68.5
        WHERE SYMBOL = 'IBM'

应更新 CURRENTQUOTE 的 STATUS 列以反映股票是否:

  • 在升值
  • 处于本年度的新高
  • 在下跌
  • 处于本年度的新低
  • 价位稳定

这通过使用下列前触发器来实现:

(1)

     CREATE TRIGGER STOCK_STATUS
        NO CASCADE BEFORE UPDATE OF QUOTE ON CURRENTQUOTE
        REFERENCING NEW AS NEWQUOTE OLD AS OLDQUOTE
     FOR EACH ROW MODE DB2SQL                                   

(2)

      SET NEWQUOTE.STATUS =

(3)

         CASE

(4)

            WHEN NEWQUOTE.QUOTE >=
                      (SELECT MAX(QUOTE)
                          FROM QUOTEHISTORY         
                          WHERE SYMBOL = NEWQUOTE.SYMBOL                 
                          AND YEAR(TIMESTAMP) = YEAR(CURRENT DATE) )     
            THEN 'High'

(5)

          WHEN NEWQUOTE.QUOTE <=                             
                      (SELECT MIN(QUOTE)
                          FROM QUOTEHISTORY
                          WHERE SYMBOL = NEWQUOTE.SYMBOL                       
                          AND YEAR(TIMESTAMP) = YEAR(CURRENT DATE) )      
          THEN 'Low'

(6)

          WHEN NEWQUOTE.QUOTE > OLDQUOTE.QUOTE
             THEN 'Rising'
          WHEN NEWQUOTE.QUOTE < OLDQUOTE.QUOTE                       
             THEN 'Dropping'
          WHEN NEWQUOTE.QUOTE = OLDQUOTE.QUOTE
             THEN 'Steady'
     END                                                  
 

(1)
此代码块将名为 STOCK_STATUS 的触发器定义为一个应该在更新 CURRENTQUOTE 表的 QUOTE 列之前激活的触发器。第二行指定,在将 CURRENTQUOTE 表的实际更新所引起的任何更改应用于数据库之前,要应用触发操作。第二行也意味着触发操作将不会激活任何其他触发器。第三行指定一些名称,必须将这些名称作为列名的限定符用于新值 (NEWQUOTE) 和旧值 (OLDQUOTE)。用这些相关名(NEWQUOTE 和 OLDQUOTE)限定的列名称为转换变量。第四行表示应对每一行都执行触发操作。

(2)
这标记此触发器的触发操作中第一个也是唯一的一个 SQL 语句的开始。 SET 转换变量语句在一个触发器中用来将值赋给表的行中的列,该表正在由激活该触发器的语句进行更新。此语句正将一个值赋给 CURRENTQUOTE 表的 STATUS 列。

(3)
该赋值语句右边使用的表达式为 CASE 表达式。 CASE 表达式扩充为 END 关键字。

(4)
第一种情况检查新报价 (NEWQUOTE.QUOTE) 是否超过当前日历年度中股票符号的最高价。子查询正在使用由跟在后面的后触发器更新的 QUOTEHISTORY 表。

(5)
第二种情况检查新报价 (NEWQUOTE.QUOTE) 是否小于当前日历年度中股票符号的最低价。子查询正在使用由跟在后面的后触发器更新的 QUOTEHISTORY 表。

(6)
最后三种情况将新报价 (NEWQUOTE.QUOTE) 与表 (OLDQUOTE.QUOTE) 中的报价比较,以确定新报价是大于、小于还是等于旧报价。 SET 转换变量语句在此处结束。

除了更新 CURRENTQUOTE 表中的项之外,还需要通过将新报价连同时间戳记一起复制到 QUOTEHISTORY 表中来创建一个审查记录。这通过使用下列后触发器来实现:

(1)

     CREATE TRIGGER RECORD_HISTORY
     AFTER UPDATE OF QUOTE ON CURRENTQUOTE
     REFERENCING NEW AS NEWQUOTE
     FOR EACH ROW MODE DB2SQL
     BEGIN ATOMIC

(2)

     INSERT INTO QUOTEHISTORY
        VALUES (NEWQUOTE.SYMBOL, NEWQUOTE.QUOTE, CURRENT TIMESTAMP);
     END

(1)
此代码块将命名为 RECORD_HISTORY 的触发器定义为应该在更新 CURRENTQUOTE 表的 QUOTE 列之后激活的触发器。第三行指定应该作为列名的限定符用于新值 (NEWQUOTE) 的名称。第四行表示应对每一行都执行触发操作。

(2)
此触发器的触发操作包括单个 SQL 语句,该语句使用已更新的行中的数据(NEWQUOTE.SYMBOL 和 NEWQUOTE.QUOTE)和当前的时间戳记将该行插入 QUOTEHISTORY 表。

CURRENT TIMESTAMP 是包含时间戳记的专用寄存器。专用寄存器中提供了列表和解释。

连接

从两个或更多个表中组合数据的过程称为连接表。数据库管理程序从指定的表中形成行的所有组合。对于每个组合,它都测试连接条件。连接条件是带有一些约束的搜索条件。有关约束的列表,参考 SQL Reference

注意:连接条件涉及的列的数据类型不必相同;然而,这些数据类型必须相容。计算连接条件的方式与计算其他搜索条件的方式相同,并且使用相同的比较规则。

如果未指定连接条件,则返回在 FROM 子句中列出的表中行的所有组合,即使这些行可能完全不相关。该结果称为这两个表的交叉积

本节中的示例基于下面两个表。这两个表只是样本数据库中表的简化形式,在样本数据库中并不存在。这两个表一般用来概述关于连接的重点。 SAMP_STAFF 列出未作为合同工雇用的雇员的姓名以及这些雇员的职务说明,而 SAMP_PROJECT 则列出雇员(合同工和全职人员)的姓名以及这些雇员所参与的项目。

这些表如下:

图 5. SAMP_PROJECT 表


REQTEXT

图 6. SAMP_STAFF 表


REQTEXT

下列示例产生两个表的交叉积。因未指定连接条件,所以给出了行的所有组合:

     SELECT SAMP_PROJECT.NAME,
            SAMP_PROJECT.PROJ, SAMP_STAFF.NAME, SAMP_STAFF.JOB
        FROM SAMP_PROJECT, SAMP_STAFF

此语句产生下列结果:

     NAME       PROJ   NAME       JOB
     ---------- ------ ---------- --------
     Haas       AD3100 Haas       PRES
     Thompson   PL2100 Haas       PRES
     Walker     MA2112 Haas       PRES
     Lutz       MA2111 Haas       PRES
     Haas       AD3100 Thompson   MANAGER
     Thompson   PL2100 Thompson   MANAGER
     Walker     MA2112 Thompson   MANAGER
     Lutz       MA2111 Thompson   MANAGER
     Haas       AD3100 Lucchessi  SALESREP
     Thompson   PL2100 Lucchessi  SALESREP
     Walker     MA2112 Lucchessi  SALESREP
     Lutz       MA2111 Lucchessi  SALESREP
     Haas       AD3100 Nicholls   ANALYST
     Thompson   PL2100 Nicholls   ANALYST
     Walker     MA2112 Nicholls   ANALYST
     Lutz       MA2111 Nicholls   ANALYST

两个主要的连接类型是内连接外连接。到目前为止,所有示例中使用的都是内连接。内连接只保留交叉积中满足连接条件的那些行。如果某行在一个表中存在,但在另一个表中不存在,则结果表中不包括该信息。

下列示例产生两个表的内连接。该内连接列出分配给某个项目的全职雇员信息:

     SELECT SAMP_PROJECT.NAME,
            SAMP_PROJECT.PROJ, SAMP_STAFF.NAME, SAMP_STAFF.JOB
        FROM SAMP_PROJECT, SAMP_STAFF
        WHERE SAMP_STAFF.NAME = SAMP_PROJECT.NAME

或者,也可以指定如下内连接:

     SELECT SAMP_PROJECT.NAME,
            SAMP_PROJECT.PROJ, SAMP_STAFF.NAME, SAMP_STAFF.JOB
        FROM SAMP_PROJECT INNER JOIN SAMP_STAFF
          ON SAMP_STAFF.NAME = SAMP_PROJECT.NAME

结果是:

     NAME       PROJ   NAME       JOB
     ---------- ------ ---------- --------
     Haas       AD3100 Haas       PRES
     Thompson   PL2100 Thompson   MANAGER

注意:该内连接的结果由右表和左表中姓名列的值匹配的行组成- 'Haas' 和 'Thompson' 都包括在列出所有全职雇员的 SAMP_STAFF 表中以及列出分配给某个项目的专职和合同雇员的 SAMP_PROJECT 表中。

外连接是内连接和左表和/或右表中未包括内连接中的那些行的并置。当对两个表执行外连接时,可任意将一个表指定为左表而将另一个表指定为右表。外连接有三种类型:

  1. 左外连接包括内连接和左表中未包括在内连接中的那些行。

  2. 右外连接包括内连接和右表中未包括在内连接中的那些行。

  3. 全外连接包括内连接以及左表和右表中未包括在内连接中的行。

使用 SELECT 语句来指定要显示的列。在 FROM 子句中,列出后跟关键字 LEFT OUTER JOIN、RIGHT OUTER JOIN 或 FULL OUTER JOIN 的第一个表的名称。接着需要指定后跟 ON 关键字的第二个表。在 ON 关键字后面,指定表示要连接的表之间关系的连接条件。

在下列示例中,将 SAMP_STAFF 指定为右表,而 SAMP_PROJECT 则被指定为左表。通过使用 LEFT OUTER JOIN,列出所有全职和合同雇员(在 SAMP_PROJECT 中列出)的姓名和项目编号,如果是全职雇员(在 SAMP_STAFF 中列出),还列出这些雇员的职位:

     SELECT SAMP_PROJECT.NAME, SAMP_PROJECT.PROJ,
            SAMP_STAFF.NAME, SAMP_STAFF.JOB
        FROM SAMP_PROJECT LEFT OUTER JOIN SAMP_STAFF
          ON SAMP_STAFF.NAME = SAMP_PROJECT.NAME

此语句产生下列结果:

     NAME       PROJ                 NAME       JOB
     ---------- -------------------- ---------- --------------------
     Haas       AD3100               Haas       PRES
     Lutz       MA2111               -          -
     Thompson   PL2100               Thompson   MANAGER
     Walker     MA2112               -          -

所有列中都具有值的那些行是该内连接的结果。这些都是满足连接条件的行: 'Haas' 和 'Thompson' 既在 SAMP_PROJECT(左表)中列出又在 SAMP_STAFF(右表)中列出。对于不满足连接条件的行,右表的列上出现空值: 'Lutz' 和 'Walker' 都是在 SAMP_PROJECT 表中列出的合同雇员,因而未在 SAMP_STAFF 表中列出。注意:左表中的所有行都包括在结果集中。

在下一个示例中,将 SAMP_STAFF 指定为右表而 SAMP_PROJECT 则被指定为左表。通过使用 RIGHT OUTER JOIN 列出所有专职雇员(在 SAMP_STAFF 中列出)的姓名和工作职位,如果将这些雇员分配给了某个项目(在 SAMP_PROJECT 中列出),还列出他们的项目编号:

     SELECT SAMP_PROJECT.NAME,
            SAMP_PROJECT.PROJ, SAMP_STAFF.NAME, SAMP_STAFF.JOB
        FROM SAMP_PROJECT RIGHT OUTER JOIN SAMP_STAFF
          ON SAMP_STAFF.NAME = SAMP_PROJECT.NAME

结果为:

    NAME       PROJ                 NAME       JOB
    ---------- -------------------- ---------- --------------------
    Haas       AD3100               Haas       PRES
    -          -                    Lucchessi  SALESREP
    -          -                    Nicholls   ANALYST
    Thompson   PL2100               Thompson   MANAGER

象在左外连接中一样,所有列中都具有值的那些行是内连接的结果。这些都是满足连接条件的行: 'Haas'和'Thompson'既在 SAMP_PROJECT(左表)中列出又在 SAMP_STAFF(右表)中列出。对于不满足连接条件的行,右表的列上出现空值: 'Lucchessi'和'Nicholls'都是未分配项目的专职雇员。虽然他们在 SAMP_STAFF 中列出,但未在 SAMP_PROJECT 中列出。注意:右表中的所有行都包括在结果集中。

下一个示例对 SAMP_PROJECT 表和 SAMP_STAFF 表使用 FULL OUTER JOIN。该示例列出所有专职雇员(包括未分配项目的雇员)和合同雇员的姓名:

     SELECT SAMP_PROJECT.NAME, SAMP_PROJECT.PROJ,
            SAMP_STAFF.NAME, SAMP_STAFF.JOB
        FROM SAMP_PROJECT FULL OUTER JOIN SAMP_STAFF
          ON SAMP_STAFF.NAME = SAMP_PROJECT.NAME

结果为:

     NAME       PROJ                 NAME       JOB
     ---------- -------------------- ---------- --------------------
     Haas       AD3100               Haas       PRES
     -          -                    Lucchessi  SALESREP
     -          -                    Nicholls   ANALYST
     Thompson   PL2100               Thompson   MANAGER
     Lutz       MA2111               -          -
     Walker     MA2112               -          -

此结果包括左外连接、右外连接以及内连接。列出所有专职雇员和合同雇员。正如左外连接和右外连接一样,对于不满足连接条件的值,相应列中出现空值。 SAMP_STAFF 和 SAMP_PROJECT 中的每一行都包括在结果集中。

复杂查询

DB2 通用数据库允许您通过使用 ROLLUP 和 CUBE 分组、合并及查看单个结果集中的多列。这种新型而强大的功能增强并简化了基于数据分析的 SQL。

有很多方法可从数据库中抽取有用信息。可执行递归查询从现存数据集中产生结果表。

ROLLUP 和 CUBE 查询

在查询的 GROUP BY 子句中指定 ROLLUP 和 CUBE 运算。 ROLLUP 分组产生包含常规分组行和小计行的结果集。CUBE 分组产生包含来自 ROLLUP 和交叉制表行中的行的结果集。所以对于 ROLLUP,可获取每人每月的销售量以及每月销售总量和总部总量。对于 CUBE,将包括每人销售总量的附加行。参见 SQL Reference 以了解更详细的情况。

递归查询

递归查询是迭代使用结果数据来确定进一步结果的查询。可以把这想象成在一棵树上或一幅图中来回移动。使用递归查询的常见示例包括材料单应用程序、订票系统、网络计划和调度。递归查询是使用包括引用自己名称的的公共表表达式来编写的。参见 SQL Reference 以获取递归查询的示例。

posted @ 2006-01-10 20:28 呓语的博客 阅读(224) | 评论 (0)编辑 收藏

用集合运算符组合查询

UNION、EXCEPT 以及 INTERSECT 集合运算符使您能够将两个或更多外层查询组合成单个查询。执行用这些集合运算符连接的每个查询并组合各个查询的结果。根据运算符不同,产生不同的结果。

UNION 运算符

UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重复行而派生出一个结果表。当 ALL 随 UNION 一起使用时(即 UNION ALL),不消除重复行。两种情况下,派生表的每一行不是来自 TABLE1 就是来自 TABLE2。

在下列 UNION 运算符的示例中,查询返回薪水高于 $21,000、有管理责任且工龄少于 8 年的人员的姓名:

(1)

     SELECT ID, NAME FROM STAFF WHERE SALARY > 21000
     UNION

(2)

     SELECT ID, NAME FROM STAFF WHERE JOB='Mgr' AND YEARS < 8
     ORDER BY ID
     

各个查询的结果如下:

(1)

                                                                          
     ID     NAME
     ------ ---------                                                        
        140 Fraye
        160 Molinare
        260 Jones
                                                                               

(2)

     ID     NAME
     ------ --------- 
         10 Sanders
         30 Marenghi
        100 Plotz
        140 Fraye
        160 Molinare
        240 Daniels

数据库管理程序组合这两个查询的结果,消除重复行,并按升序返回最终结果。

                                            
     ID     NAME
     ------ ---------
         10 Sanders
         30 Marenghi
        100 Plotz
        140 Fraye
        160 Molinare
        240 Daniels
        260 Jones

如果在带有任何集合运算符的查询中使用 ORDER BY 子句,则必须在最后一个查询之后写该子句。系统对组合的回答集进行排序。如果两个表中的列名不同,则组合的结果表没有相应列的名称。替代地,将这些列按其出现的顺序编号。因此,如果想要对结果表进行排序,则必须在 ORDER BY 子句中指定列号。

EXCEPT 运算符

EXCEPT 运算符通过包括所有在 TABLE1 中但不在 TABLE2 中的行并消除所有重复行而派生出一个结果表。当 ALL 随 EXCEPT 一起使用时 (EXCEPT ALL),不消除重复行。

在下列 EXCEPT 运算符的示例中,查询返回收入超过 $21,000 但没有经理职位且工龄为 8 年或更长的所有人员的姓名。

     SELECT ID, NAME FROM STAFF WHERE SALARY > 21000
     EXCEPT
     SELECT ID, NAME FROM STAFF WHERE JOB='Mgr' AND YEARS < 8
     

各个查询的结果在关于 UNION 的一节中列出。上面的语句产生下列结果:

     ID     NAME
     ------ ---------
        260 Jones
 

INTERSECT 运算符

INTERSECT 运算符通过只包括 TABLE1 和 TABLE2 中都有的行并消除所有重复行而派生出一个结果表。当 ALL 随 INTERSECT 一起使用时 (INTERSECT ALL),不消除重复行。

在下列 INTERSECT 运算符的示例中,查询返回收入超过 $21,000 有管理责任且工龄少于8年的雇员的姓名和 ID。

     SELECT ID, NAME FROM STAFF WHERE SALARY > 21000
     INTERSECT
     SELECT ID, NAME FROM STAFF WHERE JOB='Mgr' AND YEARS < 8

各个查询的结果在关于 UNION 的一节中列出。这两个使用 INTERSECT 的查询的结果为:

     ID     NAME
     ------ ---------
        140 Fraye
        160 Molinare
     

当使用 UNION、EXCEPT 以及 INTERSECT 运算符时,记住下列事项:

  • 运算符的查询选择列表中的所有对应项必须是相容的。有关更多信息,参见 SQL Reference 中的数据类型相容性表。

  • ORDER BY 子句(如果使用该子句的话)必须放在最后一个带有集合运算符的查询后面。对于每个运算符来说,如果列的名称与查询的选择列表中对应项的名称相同,则该列名只能在 ORDER BY 子句中使用。

  • 在具有相同数据类型和相同长度的列之间进行的运算会产生一个具有该类型和长度的列。针对 UNION、EXCEPT 以及 INTERSECT 集合运算符的结果,参见 SQL Reference 中结果数据类型的规则。

谓词

谓词允许您构造条件,以便只处理满足这些条件的那些行。基本谓词在选择行讨论。本节讨论 IN、BETWEEN、LIKE、EXISTS 以及定量谓词。

使用 IN 谓词

使用 IN 谓词将一个值与其他几个值进行比较。例如:

     SELECT NAME
        FROM STAFF
        WHERE DEPT IN (20, 15)

此示例相当于:

     SELECT NAME
        FROM STAFF
        WHERE DEPT = 20  OR DEPT = 15

当子查询返回一组值时,可使用 IN 和 NOT IN 运算符。例如,下列查询列出负责项目 MA2100 和 OP2012 的雇员的姓:

     SELECT LASTNAME
            FROM EMPLOYEE
        WHERE EMPNO IN
           (SELECT RESPEMP
               FROM PROJECT
               WHERE PROJNO = 'MA2100'
               OR PROJNO = 'OP2012')

计算一次子查询,并将结果列表直接代入外层查询。例如,上面的子查询选择雇员编号 10 和 330,对外层查询进行计算,就好象 WHERE 子句如下:

     WHERE EMPNO IN (10, 330)

子查询返回的值列表可包含零个、一个或多个值。

使用 BETWEEN 谓词

使用 BETWEEN 谓词将一个值与某个范围内的值进行比较。范围两边的值是包括在内的,并考虑 BETWEEN 谓词中用于比较的两个表达式。

下一示例寻找收入在 $10,000 和 $20,000 之间的雇员的姓名:

     SELECT LASTNAME
            FROM EMPLOYEE
        WHERE SALARY BETWEEN 10000 AND 20000

这相当于:

     SELECT LASTNAME
            FROM EMPLOYEE
        WHERE SALARY >= 10000 AND SALARY <= 20000

下一个示例寻找收入少于 $10,000 或超过 $20,000 的雇员的姓名:

     SELECT LASTNAME
            FROM EMPLOYEE
        WHERE SALARY NOT BETWEEN 10000 AND 20000

使用 LIKE 谓词

使用 LIKE 谓词搜索具有某些模式的字符串。通过百分号和下划线指定模式。

  • 下划线字符(_)表示任何单个字符。

  • 百分号(%)表示零或多个字符的字符串。

  • 任何其他表示本身的字符。

下列示例选择以字母'S'开头长度为 7 个字母的雇员名:

     SELECT NAME
        FROM STAFF
        WHERE NAME LIKE 'S_ _ _ _ _ _'

下一个示例选择不以字母'S'开头的雇员名:

     SELECT NAME
        FROM STAFF
        WHERE NAME  NOT LIKE 'S%'

使用 EXISTS 谓词

可使用子查询来测试满足某个条件的行的存在性。在此情况下,谓词 EXISTS 或 NOT EXISTS 将子查询链接到外层查询。

当用 EXISTS 谓词将子查询链接到外层查询时,该子查询不返回值。相反,如果子查询的回答集包含一个或更多个行,则 EXISTS 谓词为真;如果回答集不包含任何行,则 EXISTS 谓词为假。

通常将 EXISTS 谓词与相关子查询一起使用。下面示例列出当前在项目(PROJECT) 表中没有项的部门:

     SELECT DEPTNO, DEPTNAME
        FROM DEPARTMENT X
        WHERE NOT EXISTS
                 (SELECT *
                     FROM PROJECT
                     WHERE DEPTNO = X.DEPTNO)
        ORDER BY DEPTNO

可通过在外层查询的 WHERE 子句中使用 AND 和 OR 将 EXISTS 和 NOT EXISTS 谓词与其他谓词连接起来。

定量谓词

定量谓词将一个值和值的集合进行比较。如果全查询返回多个值,则必须通过附加后缀 ALL、ANY 或 SOME 来修改谓词中的比较运算符。这些后缀确定如何在外层谓词中处理返回的这组值。使用>比较运算符作为示例(下面的注释也适用于其他运算符):

表达式 > ALL (全查询)
如果该表达式大于由全查询返回的每个单值,则该谓词为真。如果全查询未返回值,则该谓词为真。如果指定的关系至少对一个值为假,则结果为假。注意:<>ALL 定量谓词相当于 NOT IN 谓词。

下列示例使用子查询和> ALL 比较来寻找收入超过所有经理的所有雇员的姓名和职业:

     SELECT LASTNAME, JOB
            FROM EMPLOYEE
        WHERE SALARY > ALL
        (SELECT SALARY
            FROM EMPLOYEE
            WHERE JOB='MANAGER')

表达式 > ANY (全查询)
如果表达式至少大于由全查询返回的值之一,则该谓词为真。如果全查询未返回值,则该谓词为假。注意:=ANY 定量运算符相当于 IN 谓词。

表达式 > SOME(全查询)
SOME 与 ANY 同义。

posted @ 2006-01-10 20:27 呓语的博客 阅读(284) | 评论 (0)编辑 收藏

标量全查询

标量全查询是在括号中的全查询,该查询返回的一行只包含一个列值。标量全查询对从数据库中检索数据值供表达式使用是很有用的。

  • 下列示例列出其薪水超过全部雇员平均薪水的雇员的姓名:
     
         SELECT LASTNAME, FIRSTNME
            FROM EMPLOYEE
            WHERE  SALARY > (SELECT AVG(SALARY)
                               FROM EMPLOYEE)
    

  • 下列示例在两个不同的表中查寻雇员的平均薪水:
     
         SELECT AVG(SALARY) AS "Average_Employee",
                (SELECT AVG(SALARY) AS "Average_Staff" FROM STAFF)
                    FROM EMPLOYEE
    

转换数据类型

有时可能需要将一些值从一种数据类型转换成另一种数据类型,例如,从数字值转换成字符串。要将一个值转换成另一个不同的类型,使用 CAST 说明。

转换说明的另一个可能用途是截断很长的字符串。在 EMP_RESUME 表中,RESUME 列是 CLOB(5K)。您可能只想显示包含应聘者个人信息的前 370 个字符。要从 EMP_RESUME 表中显示简历的 ASCII 格式的前 370 个字符,发出下列请求:

 
     SELECT EMPNO, CAST(RESUME AS VARCHAR(370))
        FROM EMP_RESUME
        WHERE RESUME_FORMAT = 'ascii'

会发出一个警告,通知您超过 370 个字符的值被截断。

可将空值转换为更便于在查询中进行处理的其他数据类型。 公共表表达式是一个为此目的使用转换的示例。

条件表达式

可在 SQL 语句中使用 CASE 表达式以便于处理表的数据表示。这提供了一种功能强大的条件表达式能力,在概念上与某些程序设计语言中的 CASE 语句类似。

  • 要从 ORG 表中的 DEPTNAME 列将部门编号更改为有意义的词,输入下列查询:

         SELECT DEPTNAME,
            CASE DEPTNUMB
              WHEN 10 THEN 'Marketing'
              WHEN 15 THEN 'Research'
              WHEN 20 THEN 'Development'
              WHEN 38 THEN 'Accounting'
              ELSE 'Sales'
            END  AS FUNCTION
            FROM ORG
    

    结果为:

         DEPTNAME       FUNCTION
         -------------- -----------
         Head Office    Marketing
         New England    Research
         Mid Atlantic   Development
         South Atlantic Accounting
         Great Lakes    Sales
         Plains         Sales
         Pacific        Sales
         Mountain       Sales
    

  • 可使用 CASE 表达式来防止出现异常情况,如被零除等。在下列示例中,如果雇员没有奖金或佣金报酬,则语句条件通过避免除法运算来防止出错:

     
         SELECT LASTNAME, WORKDEPT FROM EMPLOYEE
            WHERE(CASE
                     WHEN BONUS+COMM=0 THEN NULL
                     ELSE SALARY/(BONUS+COMM)
                  END ) > 10
    

  • 可在单个语句中使用 CASE 表达式,根据一个列中值的子集的总和与该列中所有值的总和的比来产生一个比率。使用 CASE 表达式的语句只需要传送数据一次。在没有 CASE 表达式的情况下,执行同样的计算至少需要传送两次。

    下列示例使用 CASE 表达式计算部门 20 的薪水之和与全部薪水总额的比率:

         SELECT CAST(CAST (SUM(CASE
                                  WHEN DEPT = 20 THEN SALARY
                                  ELSE 0
                               END) AS DECIMAL(7,2))/
                           SUM(SALARY) AS DECIMAL (3,2))
            FROM STAFF
    

    结果为 0.11。注意:CAST 函数确保结果的精度得到保持。

  • 可使用 CASE 表达式来计算简单的函数,而不必调用函数本身,调用函数将需要额外开销。例如:

         CASE
            WHEN X<0 THEN -1
            WHEN X=0 THEN 0
            WHEN X>0 THEN 1
         END
    

    此表达式与 SYSFUN 模式中 SIGN 用户定义函数有相同的结果。

表表达式

如果只需要单个查询的视图定义,可使用表表达式

表表达式是临时的,只在 SQL 语句的使用期限内有效;表表达式不能共享,但它们比视图更灵活。任何授权的用户都可共享视图定义。

本节描述如何在查询中使用公共表表达式和嵌套表表达式。

嵌套表表达式

嵌套表表达式是一个临时视图,其中的定义被嵌套(直接定义)在主查询的 FROM子 句中。

下列查询使用嵌套表表达式来寻找那些教育级别超过 16 的雇员的平均总收入、教育级别以及雇用年份:

 
     SELECT EDLEVEL, HIREYEAR, DECIMAL(AVG(TOTAL_PAY), 7,2)
        FROM (SELECT YEAR(HIREDATE) AS HIREYEAR, EDLEVEL,
                     SALARY+BONUS+COMM AS TOTAL_PAY
                 FROM EMPLOYEE
                 WHERE EDLEVEL > 16 )  AS PAY_LEVEL
        GROUP BY EDLEVEL, HIREYEAR
        ORDER BY EDLEVEL, HIREYEAR
 

结果如下:

     EDLEVEL HIREYEAR    3
     ------- ----------- ---------
          17        1967  28850.00
          17        1973  23547.00
          17        1977  24430.00
          17        1979  25896.50
          18        1965  57970.00
          18        1968  32827.00
          18        1973  45350.00
          18        1976  31294.00
          19        1958  51120.00
          20        1975  42110.00

此查询使用嵌套表表达式,首先从 HIREDATE 列中抽取雇用年份,以便可以在后续的 GROUP BY 子句中使用该雇用年份。您可能不想将此查询作为视图来创建,因为您打算用不同的 EDLEVEL 值来执行相似查询。

此示例中使用了标量内部函数 DECIMAL。 DECIMAL 返回数字或字符串的十进制表示。有关函数的更多详情,参考 SQL Reference

公共表表达式

公共表表达式是在全查询的开头使用 WITH 关键字定义的命名结果表。公共表表达式是您创建以在复杂查询之中使用的表表达式。在查询的开头使用 WITH 子句定义并命名公共表表达式。对公共表表达式的重复引用使用同一个结果集。相比之下,如果使用嵌套表表达式或视图,则每次都将重新生成结果集,其结果可能各不相同。

下列示例列出公司中教育级别大于 16、平均工资比那些同时雇用的且有同样教育级别的人低的所有人。在该查询后面会更详细地描述查询的各个部分。

(1)

     WITH
           PAYLEVEL AS
              (SELECT EMPNO, YEAR(HIREDATE) AS HIREYEAR, EDLEVEL,
                      SALARY+BONUS+COMM AS TOTAL_PAY
                  FROM EMPLOYEE
                  WHERE EDLEVEL > 16),
(2)
           PAYBYED (EDUC_LEVEL, YEAR_OF_HIRE, AVG_TOTAL_PAY) AS
              (SELECT EDLEVEL, HIREYEAR, AVG(TOTAL_PAY)
                  FROM PAYLEVEL
                  GROUP BY EDLEVEL, HIREYEAR)

(3)

     SELECT EMPNO, EDLEVEL, YEAR_OF_HIRE, TOTAL_PAY, DECIMAL(AVG_TOTAL_PAY,7,2)
        FROM PAYLEVEL, PAYBYED
        WHERE EDLEVEL=EDUC_LEVEL
          AND HIREYEAR = YEAR_OF_HIRE
          AND TOTAL_PAY < AVG_TOTAL_PAY                        

(1)
这是名为 PAYLEVEL 的公共表表达式。此结果表包括雇用某个人的年份、该雇员的总收入以及他(或她)的教育级别。只包括雇员的教育级别大于 16 的那些行。

(2)
这是名为 PAYBYED(或 PAY by education)的公共表表达式。该表达式使用在前一个公共表表达式中创建的 PAYLEVEL 表来确定每个教育级别同一年雇用的雇员的教育级别、雇用年份以及平均收入。此表返回的列被赋予的名称与选择列表中所使用的列名不同(如 EDUC_LEVEL)。这会生成命名为 PAYBYED 的结果集,与嵌套表表达式示例中产生的结果相同。

(3)
最后,我们获得能产生期望结果的实际查询。连接这两个表(PAYLEVEL,PAYBYED)以确定总收入比同年雇用的人的平均收入低的那些人。注意:PAYBYED 是以 PAYLEVEL 为基础。所以在完整语句中有效地存取了 PAYLEVEL 两次。两次都使用同一组行来计算查询。

最终结果如下:

     EMPNO  EDLEVEL YEAR_OF_HIRE TOTAL_PAY     5
     ------ ------- ------------ ------------- ---------
     000210      17         1979      20132.00  25896.50

相关名

相关名是用于识别一个对象的多种用途的标识符。可在查询的 FROM 子句中和 UPDATE 或 DELETE 语句的第一个子句中定义相关名。相关名可与表、视图或嵌套表表达式关联,但只限于定义相关名的上下文中。

例如,子句 FROM STAFF S、ORG O 分别指定 S 和 O 作为 STAFF 和 ORG 的相关名。

      SELECT NAME, DEPTNAME
         FROM STAFF S, ORG O
         WHERE O.MANAGER = S.ID

一旦定义了相关名,则只可以使用相关名来限定对象。例如,上例中如果写成 ORG.MANAGER=STAFF.ID 的话,则该语句就会失效。

也可以使用相关名作为表示数据库对象的简称。只输入 S 比输入 STAFF 更容易。

通过使用相关名,可复制对象。这在需要将表中各项与自己本身作比较时很有用。在下列示例中,EMPLOYEE 表与它自己的另一个实例比较以寻找所有雇员的经理。该示例显示非设计员的雇员的姓名、这些雇员的经理的姓名以及部门编号。

     SELECT E2.FIRSTNME, E2.LASTNAME,
            E2.JOB, E1.FIRSTNME, E1.LASTNAME, E1.WORKDEPT
        FROM EMPLOYEE E1, EMPLOYEE E2
        WHERE E1.WORKDEPT = E2.WORKDEPT
          AND E1.JOB = 'MANAGER'
          AND E2.JOB <> 'MANAGER'
          AND E2.JOB <> 'DESIGNER'
 

此语句产生下列结果:

     FIRSTNME     LASTNAME        JOB      FIRSTNME     LASTNAME        WORKDEPT
     ------------ --------------- -------- ------------ --------------- --------
     DOLORES      QUINTANA        ANALYST  SALLY        KWAN            C01
     HEATHER      NICHOLLS        ANALYST  SALLY        KWAN            C01
     JAMES        JEFFERSON       CLERK    EVA          PULASKI         D21
     MARIA        PEREZ           CLERK    EVA          PULASKI         D21
     SYBIL        JOHNSON         CLERK    EVA          PULASKI         D21
     DANIEL       SMITH           CLERK    EVA          PULASKI         D21
     SALVATORE    MARINO          CLERK    EVA          PULASKI         D21
     ETHEL        SCHNEIDER       OPERATOR EILEEN       HENDERSON       E11
     MAUDE        SETRIGHT        OPERATOR EILEEN       HENDERSON       E11
     PHILIP       SMITH           OPERATOR EILEEN       HENDERSON       E11
     JOHN         PARKER          OPERATOR EILEEN       HENDERSON       E11
     RAMLAL       MEHTA           FIELDREP THEODORE     SPENSER         E21
     JASON        GOUNOT          FIELDREP THEODORE     SPENSER         E21
     WING         LEE             FIELDREP THEODORE     SPENSER         E21

相关子查询

允许引用先前提到的任何表的子查询称为相关子查询。我们也说该子查询具有对主查询中表的相关引用

下列示例是一个不相关子查询,该子查询列出部门 'A00' 中薪水超过该部门平均薪水的雇员的雇员编号和姓名:

 
     SELECT EMPNO, LASTNAME
        FROM EMPLOYEE
        WHERE WORKDEPT = 'A00'
          AND SALARY > (SELECT AVG(SALARY)
                           FROM EMPLOYEE
                           WHERE WORKDEPT = 'A00')

如果想要知道每个部门的平均薪水,则需要对每个部门计算一次子查询。对在外层查询中标识的表的每一行,各使用一次 SQL 的相关功能(该能力允许您编写重复执行的子查询),就可做到这一点。此类型的相关子查询用来计算外层表的每一行的某个特性,该特性是在子查询中计算谓词所需要的。

此示例显示薪水高于部门平均薪水的所有雇员:

 
     SELECT E1.EMPNO, E1.LASTNAME, E1.WORKDEPT
        FROM EMPLOYEE E1
        WHERE SALARY > (SELECT AVG(SALARY)
                           FROM EMPLOYEE E2
                           WHERE E2.WORKDEPT = E1.WORKDEPT)
        ORDER BY E1.WORKDEPT

在此查询中,对每个部门计算一次子查询。结果为:

     EMPNO  LASTNAME        WORKDEPT
     ------ --------------- --------
     000010 HAAS            A00
     000110 LUCCHESSI       A00
     000030 KWAN            C01
     000060 STERN           D11
     000220 LUTZ            D11
     000200 BROWN           D11
     000170 YOSHIMURA       D11
     000150 ADAMSON         D11
     000070 PULASKI         D21
     000270 PEREZ           D21
     000240 MARINO          D21
     000090 HENDERSON       E11
     000280 SCHNEIDER       E11
     000100 SPENSER         E21
     000340 GOUNOT          E21
     000330 LEE             E21

要编写带有相关子查询的查询,使用与带有子查询的普通外部查询相同的基本格式。然而,在外部查询的 FROM 子句中,只是在表名后面放置一个相关名。于是子查询可能包含由该相关名限定的列引用。例如,如果 E1 是相关名,则 E1.WORKDEPT 表示外部查询中表的当前行的工作部门值。在外部查询中对表的每一行(概念上)重新计算子查询。

通过使用相关子查询,可以使系统为您工作并减少需要在应用程序中编写的代码量。

DB2 中允许非限定相关引用。例如,表 EMPLOYEE 有一个命名为 LASTNAME 的列,表 SALES 有一个命名为 SALES_PERSON 的列,但没有命名为 LASTNAME 的列。

 
     SELECT LASTNAME, FIRSTNME, COMM
        FROM EMPLOYEE
        WHERE 3 > (SELECT AVG(SALES)
                      FROM SALES
                      WHERE LASTNAME = SALES_PERSON)

在此示例中,系统检查最内层的 FROM 子句,以获取 LASTNAME 列。如果未找到 LASTNAME 列,则系统检查次最内层的 FROM 子句(此情况下为外部 FROM 子句)。虽然不总是必要的,还是建议限定相关引用以改进查询的可读性并确保获取想要的结果。

实现相关子查询

想何时使用相关子查询?列函数的使用有时是一条线索。

假定您想要列出教育级别高于部门平均值的雇员。

首先,您必须确定选择列表项。问题为 "List the employees"。这隐含着来自 EMPLOYEE 表中的 EMPNO 应该足以唯一标识雇员。该问题也将 EDLEVEL 和雇员的部门 WORKDEPT 说明为条件。当问题未明确要求显示列时,在选择列表中包括这些列将会有助于说明解法。现在可构造查询的一部分:

     SELECT LASTNAME, WORKDEPT, EDLEVEL
        FROM EMPLOYEE

接着需要搜索条件(WHERE子句)。问题语句为 "...whose level of education is higher than the average for that employee's department"。这意味着对于表中每个雇员,必须计算该雇员所在部门的平均教育级别。此语句适合相关子查询的说明。正在对每行计算某个特性(当前雇员所在部门的平均教育级别)。 EMPLOYEE 表需要相关名:

     SELECT LASTNAME, WORKDEPT, EDLEVEL
        FROM EMPLOYEE E1

需要的子查询较简单。该子查询计算每个部门的平均教育级别。完整的 SQL 语句为:

     SELECT LASTNAME, WORKDEPT, EDLEVEL
        FROM EMPLOYEE E1
        WHERE EDLEVEL > (SELECT AVG(EDLEVEL)
                            FROM EMPLOYEE  E2
                            WHERE E2.WORKDEPT = E1.WORKDEPT)

结果为:

     LASTNAME        WORKDEPT EDLEVEL
     --------------- -------- -------
     HAAS            A00           18
     KWAN            C01           20
     PULASKI         D21           16
     HENDERSON       E11           16
     LUCCHESSI       A00           19
     PIANKA          D11           17
     SCOUTTEN        D11           17
     JONES           D11           17
     LUTZ            D11           18
     MARINO          D21           17
     JOHNSON         D21           16
     SCHNEIDER       E11           17
     MEHTA           E21           16
     GOUNOT          E21           16

假定不列出雇员的部门编号,则应列出部门名称。需要的信息(DEPTNAME)在独立表(DEPARTMENT)中。定义相关变量的外层查询也可以是连接查询(参见从多个表中选择数据以了解详情)。

当在外层查询中使用连接时,列出要在 FROM 子句中连接的表,并将相关名放在这些表名的任何一个表名旁边。

要修改查询以列出部门名称而不是部门编号,在选择列表中用 DEPTNAME 替换 WORKDEPT。 FROM 子句现在也必须包括 DEPARTMENT 表,并且 WHERE 子句必须表示适当的连接条件。

以下是修改的查询:

     SELECT LASTNAME, DEPTNAME, EDLEVEL
        FROM EMPLOYEE E1, DEPARTMENT
        WHERE E1.WORKDEPT = DEPARTMENT.DEPTNO
        AND EDLEVEL > (SELECT AVG(EDLEVEL)
                          FROM EMPLOYEE E2
                          WHERE E2.WORKDEPT = E1.WORKDEPT)

上例显示,必须在包含相关子查询的某个查询的 FROM 子句中定义用于子查询中的相关名。然而,这种包含可能涉及若干层嵌套。

假定某些部门只有几个雇员,因此这些部门的平均教育级别可能是错误的。可以决定,为了使平均教育级别在用于比较雇员时是有意义的数字,一个部门中必须至少有 5 个雇员。因此现在必须列出教育级别高于雇员所在部门平均值的雇员,并只考虑至少有 5 个雇员的部门。

该问题暗含另一个子查询,因为对于外层查询中每个雇员来说,必须计算该雇员所在部门的雇员总数:

     SELECT COUNT(*)
        FROM EMPLOYEE E3
        WHERE E3.WORKDEPT = E1.WORKDEPT

仅当计数大于或等于 5 时才计算平均值:

     SELECT AVG(EDLEVEL)
        FROM EMPLOYEE E2
        WHERE E2.WORKDEPT = E1.WORKDEPT
        AND 5 <= (SELECT COUNT(*)
                     FROM EMPLOYEE  E3
                     WHERE E3.WORKDEPT = E1.WORKDEPT)

最后,只包括其教育级别高于部门平均值的那些雇员:

     SELECT LASTNAME, DEPTNAME, EDLEVEL
        FROM EMPLOYEE E1, DEPARTMENT
        WHERE E1.WORKDEPT = DEPARTMENT.DEPTNO
        AND EDLEVEL >
        (SELECT AVG(EDLEVEL)
            FROM EMPLOYEE E2
            WHERE E2.WORKDEPT = E1.WORKDEPT
            AND 5 <=
            (SELECT COUNT(*)
                FROM EMPLOYEE E3
                WHERE E3.WORKDEPT = E1.WORKDEPT))

此语句产生下列结果:

     LASTNAME        DEPTNAME                      EDLEVEL
     --------------- ----------------------------- -------
     PIANKA          MANUFACTURING SYSTEMS              17
     LUTZ            MANUFACTURING SYSTEMS              18
     JONES           MANUFACTURING SYSTEMS              17
     SCOUTTEN        MANUFACTURING SYSTEMS              17
     PULASKI         ADMINISTRATION SYSTEMS             16
     JOHNSON         ADMINISTRATION SYSTEMS             16
     MARINO          ADMINISTRATION SYSTEMS             17
     HENDERSON       OPERATIONS                         16
     SCHNEIDER       OPERATIONS                         17

posted @ 2006-01-10 20:26 呓语的博客 阅读(316) | 评论 (0)编辑 收藏

连接数据库

您必须先与数据库连接,才能使用 SQL 语句来查询或操作该数据库。CONNECT 语句使数据库连接与用户名相关联。

例如,要连接 SAMPLE 数据库,在 DB2 命令行处理器中输入下列命令:

  CONNECT TO SAMPLE USER USERID USING  PASSWORD

(确保选择服务器系统上有效的 USER 和 USING 值)。

在此示例中,USER 的值为 USERID,USING 的值为 PASSWORD。

下列信息告诉您连接成功:

        数据库连接信息
                                                    
           数据库产品             = DB2/6000 6.0.0
           SQL 权限 ID            = USERID
           本地数据库别名         = SAMPLE
 

通过 CONNECT 语句设置连接时,建立显式连接。在隐式连接中已设置缺省服务器。在此情况下可以使用 CONNECT,或开始发出语句,将自动建立连接。

一旦连接上,就可以开始操作数据库。有关隐式和显式连接的详情,参考 SQL Reference 中的 CONNECT 语句。

调查错误

无论何时在任何示例中输入出错时,或者如果执行 SQL 语句期间出错,则数据库管理程序返回错误信息。错误信息由信息标识符、简要说明以及 SQLSTATE 组成。

SQLSTATE 是 DB2 系列产品的公共错误码。 SQLSTATE 符合 ISO/ANSI SQL92 标准。

例如,如果 CONNECT 语句中用户名或口令不正确,则数据库管理程序将返回信息标识符 SQL1403N 和 SQLSTATE 为 08004。该信息如下:

     SQL1403N 提供的用户名和/或口令不正确。  SQLSTATE=08004

可以通过输入一个问号(?),然后输入信息标识符或 SQLSTATE 来获取关于错误信息的更多信息:

        ? SQL1403N
或
        ? SQL1403
或
        ? 08004

注意:错误 SQL1403N 的说明中倒数第二行表明 SQLCODE为-1403。 SQLCODE 为产品特定错误码。以 N(通知)或 C(严重)结尾的信息标识符表示一个错误,并且具有负 SQLCODE。以 W(警告)结尾的信息标识符表示一个警告,并且具有正 SQLCODE。

选择列

使用 SELECT 语句从表中选择特定的列。在该语句中指定用逗号分隔的列名列表。此列表称为选择列表

下列语句从 SAMPLE 数据库的 ORG 表中选择部门名称 (DEPTNAME) 和部门号 (DEPTNUMB):

 
     SELECT DEPTNAME, DEPTNUMB
        FROM ORG

上面语句产生下列结果:

 
     DEPTNAME       DEPTNUMB
     -------------- --------
     Head Office          10
     New England          15
     Mid Atlantic         20
     South Atlantic       38
     Great Lakes          42
     Plains               51
     Pacific              66
     Mountain             84
 

通过使用星号 (*) 可从表中选择所有列。下一个示例列出 ORG 表中的所有的列和行:

   
     SELECT *
        FROM ORG

此语句产生下列结果:

       DEPTNUMB DEPTNAME       MANAGER DIVISION   LOCATION
       -------- -------------- ------- ---------- -------------
             10 Head Office        160 Corporate  New York
             15 New England         50 Eastern    Boston
             20 Mid Atlantic        10 Eastern    Washington
             38 South Atlantic      30 Eastern    Atlanta
             42 Great Lakes        100 Midwest    Chicago
             51 Plains             140 Midwest    Dallas
             66 Pacific            270 Western    San Francisco
             84 Mountain           290 Western    Denver

选择行

要从表中选择特定行,在 SELECT 语句之后使用 WHERE 子句指定要选择的行必须满足的条件。从表中选择行的标准是搜索条件

搜索条件由一个或多个谓词组成。谓词指定关于某一行是真或是假(或未知)的条件。可使用下列基本谓词在 WHERE 子句中指定条件:


谓词 功能
x = y x 等于 y
x <> y x 不等于 y
x < y x 小于 y
x > y x 大于 y
x <= y x 小于或等于 y
x >= y x 大于或等于 y
IS NULL/IS NOT NULL 测试空值

在构造搜索条件时,要注意只对数字数据类型执行算术运算,并只在相容数据类型之间进行比较。例如,不能将字符串与数字进行比较。

如果正在基于字符值来选择行,则该值必须用单引号括起来(例如,WHERE JOB = 'Clerk'),并且输入的每个字符值必须与数据库中的完全一样。如果数据值在数据库中是小写的,而您用大写形式来输入它,则将不选择行。如果正在基于数字值来选择行,则该值不得用引号括起来(例如,WHERE DEPT = 20)。

下列示例只从 STAFF 表中选择部门 20 的行:

     SELECT DEPT, NAME, JOB
        FROM STAFF
        WHERE DEPT = 20

此语句产生下列结果:

      DEPT   NAME      JOB
      ------ --------- -----
          20 Sanders   Mgr
          20 Pernal    Sales
          20 James     Clerk
          20 Sneider   Clerk

下一示例使用 AND 来指定多个条件。可以指定任意多个条件。该示例从 STAFF 表中选择部门 20 中的 clerk:

   
     SELECT DEPT, NAME, JOB
        FROM STAFF
        WHERE JOB = 'Clerk'
        AND DEPT = 20

此语句产生下列结果:

     DEPT   NAME      JOB
     ------ --------- -----
         20 James     Clerk
         20 Sneider   Clerk
 

未在其中输入值且不支持缺省值的列中出现空值。将值特别设置为空值的地方也可以出现空值。空值只能在定义为支持空值的列中出现。在表中定义和支持空值在创建表中讨论。

使用谓词 IS NULL 和 IS NOT NULL 来检查空值。

下列语句列出佣金未知的雇员:

     SELECT ID, NAME
        FROM STAFF
        WHERE COMM IS NULL

此语句产生下列结果:

     ID     NAME
     ------ ---------
         10 Sanders
         30 Marenghi
         50 Hanes
        100 Plotz
        140 Fraye
        160 Molinare
        210 Lu
        240 Daniels
        260 Jones
        270 Lea
        290 Quill
        

值零与空值不相同。下列语句选择表中佣金为零的每个人:

     SELECT ID, NAME
        FROM STAFF
        WHERE COMM = 0
     

因为样本表中的 COMM 列中没有零值,所以返回的结果集为空。

下一个示例选择 STAFF 表中 YEARS 的值大于 9 的所有行:

     SELECT NAME, SALARY, YEARS
        FROM STAFF
        WHERE YEARS > 9
     

此语句产生下列结果:

     NAME      SALARY    YEARS
     --------- --------- ------
     Hanes      20659.80     10
     Lu         20010.00     10
     Jones      21234.00     12
     Quill      19818.00     10
     Graham     21000.00     13

将行进行排序

您可能想要信息按特定次序返回。使用 ORDER BY 子句将信息按一个或多个列中的值进行排序。

下列语句显示部门 84 中按雇用年数排序的雇员:

     SELECT NAME, JOB, YEARS
        FROM STAFF
        WHERE DEPT = 84
        ORDER BY YEARS

此语句产生下列结果:

     NAME      JOB   YEARS
     --------- ----- ------
     Davis     Sales      5
     Gafney    Clerk      5
     Edwards   Sales      7
     Quill     Mgr       10

指定 ORDER BY 作为整个 SELECT 语句中的最后一个子句。在此子句中命名的列可以是表达式或表的任何列。ORDER BY 子句中的列名不必在选择列表中指定。

可通过在 ORDER BY 子句中显式指定 ASC 或 DESC 将行按升序或降序进行排序。如果既未指定 ASC,也未指定 DESC,则自动按升序将行进行排序。下列语句按雇用年数以降序显示部门 84 中的雇员:

     SELECT NAME, JOB, YEARS
        FROM STAFF
        WHERE DEPT = 84
        ORDER BY YEARS DESC

此语句产生下列结果:

     NAME      JOB   YEARS
     --------- ----- ------
     Quill     Mgr       10
     Edwards   Sales      7
     Davis     Sales      5
     Gafney    Clerk      5

可以按字符值以及数字值将行进行排序。下列语句按姓名字母顺序显示部门 84 的雇员:

     SELECT NAME, JOB, YEARS
        FROM STAFF
        WHERE DEPT = 84
        ORDER BY NAME

此语句产生下列结果:

 
     NAME      JOB   YEARS
     --------- ----- ------
     Davis     Sales      5
     Edwards   Sales      7
     Gafney    Clerk      5
     Quill     Mgr       10

除去重复行

当使用 SELECT 语句时,您可能不想要返回重复信息。例如,STAFF 有一个其中多次列出了几个部门编号的 DEPT 列,以及一个其中多次列出了几个工作说明的 JOB 列。

要消除重复行,在 SELECT 子句上使用 DISTINCT 选项。例如,如果将 DISTINCT 插入该语句,则部门中的每项工作仅列出一次:

     SELECT DISTINCT DEPT, JOB
        FROM STAFF
        WHERE DEPT < 30
        ORDER BY DEPT, JOB

此语句产生下列结果:

     DEPT   JOB
     ------ -----
         10 Mgr
         15 Clerk
         15 Mgr
         15 Sales
         20 Clerk
         20 Mgr
         20 Sales

DISTINCT 已消除了在 SELECT 语句中指定的一组列中所有包含重复数据的行。

运算次序

考虑运算次序是很重要的。一个子句的输出是下一个子句的输入,如下面列表中所示。给表达式命名中给出一个要考虑其中运算次序的示例。

并且注意,此说明允许以一种更直观的方式对查询进行考虑。此说明不一定是在内部执行运算的方式。运算顺序如下:

  1. FROM 子句

  2. WHERE 子句

  3. GROUP BY 子句

  4. HAVING 子句

  5. SELECT 子句

使用表达式来计算值

表达式是包括在语句中的计算或函数。下列语句计算,如果部门 38 中每个雇员都收到 $500 的奖金,则每人的薪水将是多少:

  
     SELECT DEPT, NAME, SALARY + 500
        FROM STAFF
        WHERE DEPT = 38
        ORDER BY 3

此结果为:

     DEPT   NAME      3
     ------ --------- ----------------
         38 Abrahams          12509.75
         38 Naughton          13454.75
         38 Quigley           17308.30
         38 Marenghi          18006.75
         38 O'Brien           18506.00

注意第三列的列名是一个数字。这是一个系统生成的数字,因为 SALARY+500 未指定列名。以后此数字在 ORDER BY 子句中用来表示第三列。给表达式命名论及如何给表达式取有意义的名称。

可使用基本算术运算符加(+)、减(-)、乘(*)、除(/)来形成算术表达式。

这些运算符可对几种不同类型操作数的值进行运算,其中某些操作数为:

  • 列名(例如在 RATE*HOURS 中)
  • 常数值(例如在 RATE*1.07 中)
  • 标量函数(例如在 LENGTH(NAME) + 1 中)。

给表达式命名

可选的 AS 子句允许您给表达式指定有意义的名称,这就使得以后再引用该表达式更容易。可使用 AS 子句为选择列表中的任何项提供名称。

下列语句显示其薪水加佣金少于 $13,000 的所有雇员。表达式 SALARY + COMM 命名为 PAY:

     SELECT NAME, JOB, SALARY + COMM AS PAY
        FROM STAFF
        WHERE (SALARY + COMM) < 13000
        ORDER BY PAY

此语句产生下列结果:

     NAME      JOB   PAY
     --------- ----- ----------
     Yamaguchi Clerk   10581.50
     Burke     Clerk   11043.50
     Scoutten  Clerk   11592.80
     Abrahams  Clerk   12246.25
     Kermisch  Clerk   12368.60
     Ngan      Clerk   12714.80

通过使用 AS 子句,可以在 ORDER BY 子句中引用特定的列名而不是系统生成的数字。在此示例中,我们在 WHERE 子句中将(SALARY + COMM)与 13000 进行比较,而不是使用名称 PAY。这是运算次序的结果。在将(SALARY + COMM)命名为 PAY 之前计算 WHERE 子句的值。因此,不能在该谓词中使用 PAY。

从多个表中选择数据

可使用 SELECT 语句从两个或多个表中生成包含信息的报告。这通常称为 连接。例如,可以连接 STAFF 和 ORG 表中的数据以形成一个新表。要连接两个表,在 SELECT 子句中指定想要显示的列,在 FROM 子句中指定表名,在 WHERE 子句中指定搜索条件。WHERE 子句是可选的。

下一个示例使每个经理的姓名与部门名称关联。需要从两个表中选择信息,因为雇员信息(STAFF 表)和部门信息(ORG 表)是独立存储的。下列查询分别选择 STAFF 和 ORG 表的 NAME 和 DEPTNAME 列。搜索条件将选择范围缩小为 MANAGER 列中的值与 ID 列中的值相同的行:

     SELECT DEPTNAME, NAME
        FROM ORG, STAFF
        WHERE MANAGER = ID

图 3演示如何比较两个不同表中的列。加框线的值表示满足搜索条件的匹配项。

图 3. 从 STAFF 和 ORG 表中选择

SELECT 语句产生下列结果:

     DEPTNAME       NAME
     -------------- --------- 
     Mid Atlantic   Sanders
     South Atlantic Marenghi
     New England    Hanes
     Great Lakes    Plotz
     Plains         Fraye
     Head Office    Molinare
     Pacific        Lea
     Mountain       Quill

该结果列出每个经理的姓名和他或她的部门。

使用子查询

在编写 SELECT 语句时,可在 WHERE 子句中放置另一个 SELECT 语句。每个附加的 SELECT 启动一个子查询

子查询本身又可包括其值代入其 WHERE 子句的另一个子查询。另外,WHERE 子句可将子查询包括在多个搜索条件中。子查询可引用与主查询中所使用的不同的表和列。

下列语句从 ORG 表中选择 STAFF 表中其 ID 为 280 的雇员的分部和位置:

     SELECT DIVISION, LOCATION
        FROM ORG
        WHERE DEPTNUMB = (SELECT DEPT
                             FROM STAFF
                             WHERE ID = 280)

在处理此语句时,DB2 首先确定子查询的结果。结果为 66,因为具有 ID 280 的雇员在部门 66。则最终结果从其部门号列具有值 66 的 ORG 表的行中得出。最终结果是:

     DIVISION   LOCATION
     ---------- -------------
     Western    San Francisco

当使用子查询时,数据库管理程序计算该子查询并将结果值直接代入 WHERE 子句。

相关子查询中进一步讨论子查询。

使用函数

本节简要介绍了将用于全书示例的函数。 数据库函数是一组输入数据值和一个结果值之间的关系。

函数可以是内部的或用户定义的。 DB2 通用数据库提供很多内部函数和预安装的用户定义函数。可找到 SYSIBM 模式的内部函数和 SYSFUN 模式的预安装的用户定义函数。SYSIBM 和 SYSFUN 是保留模式。

内部函数和预安装的用户定义函数从不会满足所有需求。所以应用程序开发者可能需要创建自己的一套特定于他们的应用程序的函数。用户定义函数使这成为可能,例如通过扩展 DB2 通用数据库的范围以包括定制的商业或科学函数。这在用户定义函数中进一步讨论。

列函数

列函数对列中的一组值进行运算以得到单个结果值。下列就是一些列函数的示例。有关完整列表,参考 SQL Reference

AVG
返回某一组中的值除以该组中值的个数的和

COUNT
返回一组行或值中行或值的个数

MAX
返回一组值中的最大值

MIN
返回一组值中的最小值

下列语句从 STAFF 表中选择最高薪水:

     SELECT MAX(SALARY)
        FROM STAFF

此语句从员工 STAFF 样本表中返回值 22959.20。

下一个示例选择其收入超过平均收入但在公司的年数少于平均年数的雇员姓名和薪水。

     SELECT NAME, SALARY
        FROM STAFF
        WHERE SALARY > (SELECT AVG(SALARY) FROM STAFF)
        AND YEARS < (SELECT AVG(YEARS) FROM STAFF)

此语句产生下列结果:

      NAME      SALARY
     --------- ---------
     Marenghi   17506.75
     Daniels    19260.25
     Gonzales   16858.20

在上面示例中的 WHERE 子句中,与直接实现列函数 (WHERE SALARY > AVG(SALARY)) 相反,在子查询中说明列函数。不能在 WHERE 子句中说明列函数。这是由于运算次序的结果。可认为 WHERE 子句是在 SELECT 子句之前进行计算的。因此,当正在计算 WHERE 子句时,列函数没有对该组值的存取权。稍后由 SELECT 子句选择这组值。

可指定 DISTINCT 作为列函数自变量的一部分,以在应用函数之前消除重复值。因此,COUNT(DISTINCT WORKDEPT) 计算不同部门的个数。

标量函数

标量函数对值进行某个运算以返回另一个值。下列就是一些由DB2 通用数据库提供的标量函数的示例。

ABS
返回数的绝对值

HEX
返回值的十六进制表示

LENGTH
返回自变量中的字节数(对于图形字符串则返回双字节字符数。)

YEAR
抽取日期时间值的年份部分

有关标量函数的详细列表和说明,参考 SQL Reference

下列语句返回 ORG 表中的部门名称以及其每个名称的长度:

     SELECT DEPTNAME, LENGTH(DEPTNAME)
        FROM ORG

此语句产生下列结果:

     DEPTNAME       2
     -------------- -----------
     Head Office             11
     New England             11
     Mid Atlantic            12
     South Atlantic          14
     Great Lakes             11
     Plains                   6
     Pacific                  7
     Mountain                 8

注意:由于未使用 AS 子句给 LENGTH(DEPTNAME) 取一个有意义的名称,所以第二列中出现系统生成的数字。

分组

DB2 通用数据库具有基于表的特定列对数据进行分析的能力。

可按照在 GROUP BY 子句中定义的组对行进行分组。以其最简单的形式,组由称为分组列的列组成。 SELECT 子句中的列名必须为分组列或列函数。列函数对于 GROUP BY 子句定义的每个组各返回一个结果。下列示例产生一个列出每个部门编号的最高薪水的结果:

     SELECT DEPT, MAX(SALARY) AS MAXIMUM
        FROM STAFF
        GROUP BY DEPT

此语句产生下列结果:

     DEPT   MAXIMUM
     ------ ---------
         10  22959.20
         15  20659.80
         20  18357.50
         38  18006.00
         42  18352.80
         51  21150.00
         66  21000.00
         84  19818.00

注意:计算的是每个部门(由 GROUP BY 子句定义的组)而不是整个公司的 MAX(SALARY)。

将 WHERE 子句与 GROUP BY 子句一起使用

分组查询可以在形成组和计算列函数之前具有消除非限定行的标准 WHERE 子句。必须GROUP BY 子句之前指定 WHERE 子句。例如:

     SELECT WORKDEPT, EDLEVEL, MAX(SALARY) AS MAXIMUM
        FROM EMPLOYEE
        WHERE HIREDATE > '1979-01-01'
        GROUP BY WORKDEPT, EDLEVEL
        ORDER BY WORKDEPT, EDLEVEL
 

结果为:

     WORKDEPT EDLEVEL MAXIMUM
     -------- ------- -----------
     D11           17    18270.00
     D21           15    27380.00
     D21           16    36170.00
     D21           17    28760.00
     E11           12    15340.00
     E21           14    26150.00

注意:在 SELECT 语句中指定的每个列名也在 GROUP BY 子句中提到。未在这两个地方提到的列名将产生错误。GROUP BY 子句对 WORKDEPT 和 EDLEVEL 的每个唯一组合各返回一行。

在 GROUP BY 子句之后使用 HAVING 子句

可应用限定条件进行分组,以便系统仅对满足条件的组返回结果。为此,GROUP BY 子句后面包含一个 HAVING 子句。 HAVING 子句可包含一个或多个用 AND 和 OR 连接的谓词。每个谓词将组特性(如 AVG(SALARY))与下列之一进行比较:

  • 该组的另一个特性

    例如:

    HAVING AVG(SALARY) > 2 * MIN(SALARY)
    

  • 常数

    例如:

     HAVING AVG(SALARY) > 20000
    

例如,下列查询寻找雇员数超过 4 的部门的最高和最低薪水:

     SELECT WORKDEPT, MAX(SALARY) AS MAXIMUM, MIN(SALARY) AS MINIMUM
        FROM EMPLOYEE
        GROUP BY WORKDEPT
        HAVING COUNT(*) > 4
        ORDER BY WORKDEPT

此语句产生下列结果:

     WORKDEPT MAXIMUM     MINIMUM
     -------- ----------- -----------
     D11         32250.00    18270.00
     D21         36170.00    17250.00
     E11         29750.00    15340.00

有可能(虽然很少见)查询有 HAVING 子句但没有 GROUP BY 子句。在此情况下,DB2 将整个表看作一个组。因为该表被看作是单个组,所以最多可以有一个结果行。如果 HAVING 条件对整个表为真,则返回选择的结果(该结果必须整个由列函数组成);否则不返回任何行。

posted @ 2006-01-10 20:24 呓语的博客 阅读(544) | 评论 (0)编辑 收藏

创建表

使用 CREATE TABLE 语句创建自己的表,指定列名和类型以及约束。约束在用约束和触发器实施商业规则中讨论。

下列语句创建一个命名为 PERS 的表,该表与 STAFF 表类似,但有一个附加列 BIRTH_DATE 。

     CREATE TABLE PERS
         ( ID              SMALLINT        NOT NULL,
           NAME            VARCHAR(9),
           DEPT            SMALLINT WITH DEFAULT 10,
           JOB             CHAR(5),
           YEARS           SMALLINT,
           SALARY          DECIMAL(7,2),
           COMM            DECIMAL(7,2),
           BIRTH_DATE      DATE) 

此语句创建一个其中无数据的表。下一节描述如何将数据插入新表。

如示例中所示,为每一列都指定名称和数据类型。数据类型在数据类型中讨论。 NOT NULL 是可选的,可以指定它以表示列中不允许有空值。缺省值也是可选的。

可以在 CREATE TABLE 语句中指定许多其他选项,如唯一约束或参考约束。有关所有选项的详情,参见 SQL Reference 中的 CREATE TABLE 语句。

插入数据

当创建新表时,新表不包含任何数据。要将新的行输入表中,使用 INSERT 语句。此语句有两种一般格式:

  • 一种格式,使用 VALUES 子句来指定一行或多行的列值。下面三个示例使用此一般格式将数据插入表中。

  • 另一种格式,指定全查询而非指定 VALUES 来标识来自包含在其他表和/或视图中的行的列。

全查询是 INSERT 或 CREATE VIEW 语句中所使用的选择语句、或者是跟在谓词后面的选择语句。括在括号中的全查询一般称为子查询。

根据创建表时已选择的缺省选项,对于每个插入的行,为每一列提供一个值或者接受一个缺省值。各种数据类型的缺省值在 SQL Reference 中讨论。

下列语句使用 VALUES 子句将一行数据插入 PERS 表中:

  
     INSERT INTO PERS
        VALUES (12, 'Harris', 20, 'Sales', 5, 18000, 1000, '1950-1-1')
     

下列语句使用 VALUES 子句将三行插入其中只有 ID、名称以及工作是已知的 PERS 表中。如果列定义为 NOT NULL 且没有缺省值,则必须为该列指定一个值。 CREATE TABLE 语句中的列定义上的 NOT NULL 子句可以用单词 WITH DEFAULT 扩充。如果某一列定义为 NOT NULL WITH DEFAULT 或常数缺省值(如 WITH DEFAULT 10),并且您未在列列表中指定该列,则缺省值插入至已插入行的该列中。例如,在 CREATE TABLE 语句中,仅为 DEPT 列指定了缺省值并将该值定义为 10。因此,DEPT 设置为 10 而所有其他列都为空。

 
     INSERT INTO PERS (NAME, JOB, ID)
        VALUES ('Swagerman', 'Prgmr', 500),
               ('Limoges', 'Prgmr', 510),
               ('Li', 'Prgmr', 520)

下列语句返回插入的结果:

     SELECT *
        FROM PERS
 
     ID     NAME      DEPT   JOB   YEARS  SALARY    COMM      BIRTH_DATE
     ------ --------- ------ ----- ------ --------- --------- ----------
         12 Harris        20 Sales      5  18000.00   1000.00 01/01/1950
        500 Swagerman     10 Prgmr      -         -         - -
        510 Limoges       10 Prgmr      -         -         - -
        520 Li            10 Prgmr      -         -         - -

注意:在此情况下,并未给每个列指定值。空值显示为 -。为此,列名列表的次序和数据类型都必须与 VALUES 子句中提供的值对应。如果省略列名列表(如第一个示例中那样),则 VALUES 之后的数据值列表的次序必须与它们所插入至的表中的列次序相同,值的数目必须等于表中列的数目。

每个值必须与它所插入至的列的数据类型相容。如果某列定义为可空,且未指定该列的值,则将空值赋给插入行中的该列。

下列示例将空值插入 YEARS、COMM 和 BIRTH_DATE 中,因为未给行中的那些列指定值。

     INSERT INTO PERS (ID, NAME, JOB, DEPT, SALARY)
        VALUES (410, 'Perna', 'Sales', 20, 20000)

INSERT 语句的第二种格式对于用来自另一表中行的值填充表非常方便。如所述的那样,指定全查询而非指定 VALUES 以标识来自包含在其他表和/或视图中的行中的列。

下列示例从员工 STAFF 表中选择部门 38 的成员的数据,并将它插入 PERS 表中:

  
     INSERT INTO PERS (ID, NAME, DEPT, JOB, YEARS, SALARY)
        SELECT ID, NAME, DEPT, JOB, YEARS, SALARY
           FROM STAFF
           WHERE DEPT = 38

在此插入之后,下列 SELECT 语句与 INSERT 语句中全查询产生的结果相同。

     SELECT ID, NAME, DEPT, JOB, YEARS, SALARY
        FROM PERS
        WHERE DEPT = 38
 

结果为:

                                                                               
ID     NAME      DEPT   JOB   YEARS  SALARY
------ --------- ------ ----- ------ ---------
    30 Marenghi      38 Mgr        5  17506.75
    40 O'Brien       38 Sales      6  18006.00
    60 Quigley       38 Sales      -  16808.30
   120 Naughton      38 Clerk      -  12954.75
   180 Abrahams      38 Clerk      3  12009.75

更改数据

使用 UPDATE 语句来更改表中的数据。使用此语句,可以更改满足 WHERE 子句搜索条件的每行中的一列或多列的值。

下列示例更新其 ID 为 410 的雇员的信息:

     UPDATE PERS
        SET JOB='Prgmr', SALARY = SALARY + 300
        WHERE ID = 410

SET 子句指定要更新的列并提供值。

WHERE 子句是可选的,它指定要更新的行。如果省略 WHERE 子句,则数据库管理程序用您提供的值更新表或视图中的每一行。

在此示例中,首先命名表 (PERS),然后指定要更新行的条件。雇员编号 410 的信息已更改:该雇员的工作职位更改为 Prgmr,它的薪水增加了 300$。

可以通过包括应用于两行或更多行的 WHERE 子句来更改多行数据。下列示例给每个销售员的薪水增加 15%:

     UPDATE PERS
        SET SALARY = SALARY * 1.15
        WHERE JOB = 'Sales'

删除数据

使用 DELETE 语句,基于在 WHERE 子句中指定的搜索条件从表中删除数据行。下列示例删除其中雇员 ID 为 120 的行:

 
     DELETE FROM PERS
        WHERE ID = 120

WHERE 子句是可选的,它指定要删除的行。如果省略 WHERE 子句,则数据库管理程序删除表或视图中的所有行。

可以使用 DELETE 语句删除多行。下列示例删除其中雇员部门 (DEPT) 为 20 的所有行:

     DELETE FROM PERS
        WHERE DEPT = 20

当删除某一行时,是除去整行,而不是除去行中的特定列值。

要删除表的定义及其内容,发出 DROP TABLE 语句,如 SQL Reference 中所述。

创建视图

视图中所讨论的,视图提供在一个或多个表中查看数据的替代方法。通过创建视图,可以对想要各种用户查看的信息进行限制。下列图表显示视图和表之间的关系。

图 2. 表和视图之间的关系

图 2中,View_A 被限制仅存取 TABLE_A 的列 AC1 和 AC2。 View_AB 允许存取 TABLE_A 中的列 AC3 和 TABLE_B 中的列 BC2。通过创建 View_A,将用户可以具有的存取权限制于 TABLE_A,通过创建 VIEW_AB,将存取权限制于某些列并创建查看数据的替代方式。

下列语句创建 STAFF 表 中 20 部门的非经理人员视图,其中薪水和佣金不通过基表显示。

  
     CREATE VIEW STAFF_ONLY
        AS SELECT ID, NAME, DEPT, JOB, YEARS
              FROM STAFF
              WHERE JOB <> 'Mgr' AND DEPT=20

在创建视图之后,下列语句显示视图的内容:

     SELECT *
        FROM STAFF_ONLY

此语句产生下列结果:

      
ID     NAME      DEPT   JOB   YEARS
------ --------- ------ ----- ------
    20 Pernal        20 Sales      8
    80 James         20 Clerk      -
   190 Sneider       20 Clerk      8

早些时候,我们把 STAFF 和 ORG 表连接起来产生一个列出每个部门名称及其部门经理姓名的结果。下列语句创建可重复用于相同目的的视图:

  
     CREATE VIEW DEPARTMENT_MGRS
        AS SELECT NAME, DEPTNAME
              FROM STAFF, ORG
              WHERE MANAGER = ID

创建视图时,可以使用 WITH CHECK OPTION 子句将附加约束添加到通过视图插入和更新表。此子句导致数据库管理程序验证对视图的任何更新或插入是否符合该视图的定义,并拒绝那些不符合定义的更新或插入。如果省略此子句,则不检查违反视图定义的插入和更新。有关 WITH CHECK OPTION 如何起作用的详情,参考 SQL Reference 中的 CREATE VIEW 语句。

使用视图来处理数据

象 SELECT 语句一样,INSERT、DELETE 以及 UPDATE 语句可以应用于视图,就好象视图是一个实表一样。这些语句处理基本基表中的数据。因此当再次存取该视图时,使用最新的基表对它进行计算。如果未使用 WITH CHECK OPTION,则使用视图修改的数据可能由于不再满足原始视图定义而不在视图的重复存取中出现。

下列是一个将更新应用于视图 FIXED_INCOME 的示例:

FIXED_INCOME 的视图定义:

     CREATE VIEW FIXED_INCOME (LNAME, DEPART, JOBTITLE, NEWSALARY)
        AS SELECT NAME, DEPT, JOB, SALARY
              FROM PERS
              WHERE JOB <> 'Sales' WITH CHECK OPTION

     UPDATE FIXED_INCOME
        SET NEWSALARY = 19000
        WHERE LNAME = 'Li'

除了校验选项以外,先前视图中的更新等效于对基表 PERS 的更新:

     UPDATE PERS
        SET SALARY = SALARY * 1.10
        WHERE NAME = 'Li'
          AND JOB <> 'Sales'

注意:由于视图是在 CREATE VIEW FIXED_INCOME 中对约束 JOB <> 'Sales'使用 WITH CHECK OPTION 创建的,所以当 Limoges 调去做销售时不允许下列更新:

     UPDATE FIXED_INCOME
        SET JOBTITLE = 'Sales'
        WHERE LNAME = 'Limoges'

不能更新由表达式 SALARY + COMM or SALARY * 1.25 定义的列。如果定义的视图包含一列或多个这样的列,则拥有者不接受对这些列的更新(UPDATE)特权。在包含这样的列的视图上不允许 INSERT 语句,但允许 DELETE 语句。

考虑一个没有一列定义为 NOT NULL 的 PERS 表。可以通过 FIXED_INCOME 视图将行插入 PERS 表中,即使该视图不包含基本表 PERS 的 ID、YEARS、COMM 或 BIRTHDATE。整个视图中看不到的列被适当地设置为空值或缺省值。

然而,PERS 表确实已将列 ID 定义为 NOT NULL。如果尝试通过 FIXED_INCOME 视图插入行,则系统试图将空值插入在整个视图中“看不到”的所有 PERS 列。由于 ID 列未包括在视图中并且该列不允许空值,所以系统不允许通过该视图进行插入。

posted @ 2006-01-10 20:21 呓语的博客 阅读(644) | 评论 (0)编辑 收藏

表是由定义的列数和可变的行数组成的逻辑结构。是一组相同数据类型的值。在表中不必对行进行排序。要对结果集进行排序,必须在从表中选择数据的 SQL 语句中显式指定排序。在每个列和行的相交处是一个称为的特定数据项。在图 1中,'Sanders' 是表中值的一个示例。

基表是用 CREATE TABLE 语句创建的,用于保存用户数据。结果表是一组行,数据库管理程序从一个或多个基表选择或生成这组行以满足查询要求。

图 1说明了表的一部分。列和行已标记。

图 1. 表的可视化

视图

视图提供了在一个或多个表中查看数据的替代方法。它是表上的一个动态窗口。

视图允许多个用户查看同一数据的不同表示。例如,几个用户可以同时存取一个关于雇员的数据表。一个用户可以查看关于某些雇员而非其他雇员的数据,而另一个用户可以查看关于所有雇员的某些数据而非他们的薪水。这些用户的每一个都在操作一个从该实表派生的视图。每个视图都显示为一个表并有自己的名称。

使用视图的优点是您可以使用它们来控制对敏感数据的存取。所以,不同的人可以存取数据的不同列或行。

模式

模式是命名对象的集合,并提供了数据库中对象的逻辑分类。模式可以包含数据库对象,如表和视图等。

模式本身也可以认为是数据库中的一个对象。当创建表或视图时隐式创建了模式。或者,可以使用 CREATE SCHEMA 语句显式创建它。

创建对象时,可以用特定模式的名称来限定对象的名称。命名对象有两部分名称,其中第一部分名称是指定给对象的模式名。如果未指定模式名,则给对象指定其名称是用户执行语句的权限 ID 的缺省模式。对于交互式 SQL,该方法用于执行本书中的示例,权限 ID 为用 CONNECT 语句指定的用户 ID。例如,如果表名为 STAFF,CONNECT 语句中指定的用户 ID 为 USERID,则限定名为 USERID.STAFF。参见连接数据库以获取关于 CONNECT 语句的详情。

某些模式名是系统保留的。例如,当预安装的用户定义函数 属于 SYSFUN 模式时,内部函数处于 SYSIBM 模式。参考 SQL Reference 以获取关于 CREATE SCHEMA 语句的详情。

数据类型

数据类型定义常数、列、宿主变量、函数、表达式以及专用寄存器可接受的值。本节描述示例中引用的数据类型。有关其他数据类型的完整列表和说明,参考 SQL Reference

字符串

字符串为一个字节序列。字符串的长度为序列中的字节数。如果长度为零,则该字符串的值称为空字符串
定长字符串

CHAR(x)是定长字符串。长度属性 x 必须在 1 和 254 之间,并包括 1 和 254。

变长字符串

变长字符串有三种类型:VARCHAR、LONG VARCHAR 以及 CLOB。 VARCHAR(x)类型是变长字符串,因此,可以将长度为 9 的字符串插入 VARCHAR(15)中,而该字符串的长度将仍然为 9。参见大对象 (LOB)以获取关于 CLOB 的详情。

图形字符串

图形字符串是一个双字节字符数据序列。

定长图形字符串

GRAPHIC(x)是定长字符串。长度属性 x 必须在 1 和 127 之间,并包括 1 和 127。

变长图形字符串

变长图形字符串有三种类型:VARGRAPHIC、LONG VARGRAPHIC 以及 DBCLOB。参见大对象 (LOB)以获取关于 DBCLOB 的详情。

二进制字符串

二进制字符串是一个字节序列。它用于保存非传统数据,如图象等。“二进制大对象”(BLOB)是二进制字符串。参见大对象 (LOB)以了解更多信息。

数字

所有数字都有符号和精度。精度是除符号位以外的位数或数字数。

SMALLINT
SMALLINT(小型整数)是精度为 5 位的两字节整数。

INTEGER
INTEGER(大型整数)是精度为 10 位的四字节整数。

REAL
REAL(单精度浮点数)是实数的 32 位近似值。

DOUBLE
DOUBLE(双精度浮点数)是实数的 64 位近似值。 DOUBLE 也称 FLOAT。

DECIMAL(p,s)

DECIMAL 是一个十进制数。小数点的位置由数字的 精度(p)小数位(s) 确定。精度是数字的总位数,必须小于 32。小数位是小数部分数字的位数且总是小于或等于精度值。如果未指定精度和小数位,则十进制值的缺省精度为 5,缺省小数位为 0。

日期时间值

日期时间值是日期、时间以及时间戳记的表示。日期时间值可以用于某些算术运算和字符串运算并且与某些字符串是相容的,然而它们既非字符串也非数字。 (1)

日期
日期值分为三个部分(年、月以及日)。

时间
时间是用 24 小时制式来指定一天内的时间的值,分为三个部分(小时、分钟以及秒)。

时间戳记
时间戳记为指定日期和时间的值,分为七个部分(年、月、日、小时、分钟、秒以及微秒)。

值是一个区别于所有非空值的特殊值。它意味着行中的那一列无任何其他值。所有数据类型都存在空值。

下表突出显示示例中所使用的数据类型的特性。所有数字数据类型都定义在某一确定范围内。该数字数据类型范围也包括在此表中。可以使用此表作为正确数据类型用法的快速参考。
数据类型 类型 特性 示例或范围
CHAR(15)

定长字符串

最大长度为 254

'Sunny day      '

VARCHAR(15)

变长字符

最大长度为 4000

'Sunny day'

SMALLINT

数字

长度为 2 字节
精度为 5 位

范围为-32768 至 32767

INTEGER

数字

长度为 4 字节
精度为 10 位

范围为-2147483648 至 2147483647

REAL

数字

单精度
浮点
32 位近似值

范围为 
-3.402E+38 至-1.175E-37
或 1.175E-37 至-3.402E+38
或零

DOUBLE

数字

双精度
浮点
64 位近似值
范围为
-1.79769E+308 至-2.225E-307
或 2.225E-307 至 1.79769E+308
或零

DECIMAL(5,2)

数字
精度为 5
小数位为 2

范围为 
-10**31+1 至 10**31-1
DATE

日期时间

三部分值

1991-10-27

TIME

日期时间

三部分值

13.30.05

TIMESTAMP

日期时间

七部分值

1991-10-27-13.30.05.000000

posted @ 2006-01-10 20:20 呓语的博客 阅读(182) | 评论 (0)编辑 收藏

第1章 关系数据库和SQL
    关系数据库中,数据存储在表中。表是行和列的集合。 结构化查询语言(SQL)通过指定列、表以及它们之间的各种关系来检索或更新数据。
 
    SQL 是在关系数据库中定义和处理数据的标准化语言。SQL 语句由数据库管理程序执行。数据库管理程序是管理数据的计算机程序。 

    分区关系数据库是在多个分区(也称为节点)上管理数据的关系数据库。本书中我们将把重点集中在单个分区数据库上。 

    可以使用一个象命令行处理器(CLP)或命令中心那样的界面,通过交互式 SQL 来存取样本数据库并试验本书中的所有示例。 

 

posted @ 2006-01-10 20:16 呓语的博客 阅读(169) | 评论 (0)编辑 收藏

final关键字最基本的含义就是表明“这个东西不能改变”。之所以这样,可能是考虑到两方面的因素:设计或效率。

final关键字可应用在三种场合: 数据、方法以及类

1. final数据

表明某个数据是“常数”,永远不会改变。使用final定义,编译器可以直接将常数值封装到需要的计算过程里。也就是说,计算可以在编译期前执行,从而节省运行时的开销。在JAVA中,这些常数必须属于基本数据类型。并且在对这样的一个常数进行定义的时候,必须给出一个值。

而当对象句柄使用final时,必须将句柄初始化到一个具体的对象,而且永远不能将句柄指向另一个对象。然而,对象本身可以修改。

空白final

Java允许创建“空白final”。即不赋初始值,但空白final必须在实际使用前得到正确的初始化。如果将赋初始值的语句放在不同的构造器中,则final字段可以随着调用不同的构造器而获得不同的初始值。但一旦确定,值将无法改变。

final数据无法更改:

{
  final int i=5;
  i=6;
}

以上语句会在编译期间出错:
:cannot assign a value to final variable i=6;

final自变量

JAVA允许将自变量设成final属性。即在方法的变量列表中进行声明。这样意味着在一个方法内部,不能改变自变量句柄所指向的东西。

2. final 方法

将一个方法标识为final,则可防止任何继承类改变这个方法的本来含义。即不可被覆盖或改写。

同时将一个方法设置成final后,编译器可以把对那个方法的所有调用都嵌入到调用里,即采用常规的代码插入方法。因此可以提高程序效率。当然,如果方法体积太大,那么程序就会变的臃肿。

因此,通常只有在方法的代码量非常少,或者想明确禁止方法被覆盖的时候,才应考虑将一个方法设置为final 。

类中所有的private方法都自动成为final。因为我们不能从类外访问final方法,所以它绝对不会被其他方法覆盖。

3. final类

若在整个类定义前冠以final关键字,表明不希望从这个类继承。而final类的数据成员既可以是final的,也可以不是。因为final类禁止了继承,所以final类中的所有方法都默认为final。因为此时不可能覆盖它们。(当然可以再为final类中的方法添加final指示符号,但这样做没有任何意义)

posted @ 2006-01-06 22:27 呓语的博客 阅读(3364) | 评论 (0)编辑 收藏

ArticleContent1_ArticleContent1_lblContent">ArrayList是List接口的一个可变长数组实现。实现了所有List接口的操作,并允许存储null值。除了没有进行同步,ArrayList基本等同于Vector。在Vector中几乎对所有的方法都进行了同步,但ArrayList仅对writeObject和readObject进行了同步,其它比如add(Object)、remove(int)等都没有同步。

1.存储
ArrayList使用一个Object的数组存储元素。
private transient Object elementData[];
ArrayList实现了java.io.Serializable接口,这儿的transient标示这个属性不需要自动序列化。下面会在writeObject()方法中详细讲解为什么要这样作。

2.add和remove


    public boolean add(Object o) { 
    ensureCapacity(size + 1);  // Increments modCount!! 
    elementData[size++] = o; 
    return true; 
    } 

注意这儿的ensureCapacity()方法,它的作用是保证elementData数组的长度可以容纳一个新元素。在“自动变长机制”中将详细讲解。

    public Object remove(int index) { 
    RangeCheck(index); 
    modCount++; 
    Object oldValue = elementData[index]; 
    int numMoved = size - index - 1; 
    if (numMoved > 0) 
        System.arraycopy(elementData, index+1, elementData, index, 
                 numMoved); 
    elementData[--size] = null; // Let gc do its work 
    return oldValue; 
    } 

RangeCheck()的作用是进行边界检查。由于ArrayList采用一个对象数组存储元素,所以在删除一个元素时需要把后面的元素前移。删除一个元素时只是把该元素在elementData数组中的引用置为null,具体的对象的销毁由垃圾收集器负责。
modCount的作用将在下面的“iterator()中的同步”中说明。
注:在前移时使用了System提供的一个实用方法:arraycopy(),在本例中可以看出System.arraycopy()方法可以对同一个数组进行操作,这个方法是一个native方法,如果对同一个数组进行操作时,会首先把从源部分拷贝到一个临时数组,在把临时数组的元素拷贝到目标位置。

3.自动变长机制
在实例化一个ArrayList时,你可以指定一个初始容量。这个容量就是elementData数组的初始长度。如果你使用:

    ArrayList list = new ArrayList(); 

则使用缺省的容量:10。

    public ArrayList() { 
    this(10); 
    } 

ArrayList提供了四种add()方法,

public boolean add(Object o)

public void add(int index, Object element)

public boolean addAll(Collection c)

public boolean addAll(int index, Collection c)

在每一种add()方法中,都首先调用了一个ensureCapacity(int miniCapacity)方法,这个方法保证elementData数组的长度不小于miniCapacity。ArrayList的自动变长机制就是在这个方法中实现的。

    public void ensureCapacity(int minCapacity) { 
    modCount++; 
    int oldCapacity = elementData.length; 
    if (minCapacity > oldCapacity) { 
        Object oldData[] = elementData; 
        int newCapacity = (oldCapacity * 3)/2 + 1; 
            if (newCapacity < minCapacity) 
        newCapacity = minCapacity; 
        elementData = new Object[newCapacity]; 
        System.arraycopy(oldData, 0, elementData, 0, size); 
    } 
    } 

从这个方法实现中可以看出ArrayList每次扩容,都扩大到原来大小的1.5倍。
每种add()方法的实现都大同小异,下面给出add(Object)方法的实现:

    public boolean add(Object o) { 
    ensureCapacity(size + 1);  // Increments modCount!! 
    elementData[size++] = o; 
    return true; 
    } 


4.iterator()中的同步
在父类AbstractList中定义了一个int型的属性:modCount,记录了ArrayList结构性变化的次数。

    protected transient int modCount = 0; 

在ArrayList的所有涉及结构变化的方法中都增加modCount的值,包括:add()、remove()、addAll()、removeRange()及clear()方法。这些方法每调用一次,modCount的值就加1。
注:add()及addAll()方法的modCount的值是在其中调用的ensureCapacity()方法中增加的。

AbstractList中的iterator()方法(ArrayList直接继承了这个方法)使用了一个私有内部成员类Itr,生成一个Itr对象(Iterator接口)返回:

    public Iterator iterator() { 
    return new Itr(); 
    } 

Itr实现了Iterator()接口,其中也定义了一个int型的属性:expectedModCount,这个属性在Itr类初始化时被赋予ArrayList对象的modCount属性的值。

    int expectedModCount = modCount; 

注:内部成员类Itr也是ArrayList类的一个成员,它可以访问所有的AbstractList的属性和方法。理解了这一点,Itr类的实现就容易理解了。

在Itr.hasNext()方法中:

    public boolean hasNext() { 
        return cursor != size(); 
    } 

调用了AbstractList的size()方法,比较当前光标位置是否越界。

在Itr.next()方法中,Itr也调用了定义在AbstractList中的get(int)方法,返回当前光标处的元素:

    public Object next() { 
        try { 
        Object next = get(cursor); 
        checkForComodification(); 
        lastRet = cursor++; 
        return next; 
        } catch(IndexOutOfBoundsException e) { 
        checkForComodification(); 
        throw new NoSuchElementException(); 
        } 
    } 

注意,在next()方法中调用了checkForComodification()方法,进行对修改的同步检查:

    final void checkForComodification() { 
        if (modCount != expectedModCount) 
        throw new ConcurrentModificationException(); 
    } 

现在对modCount和expectedModCount的作用应该非常清楚了。在对一个集合对象进行跌代操作的同时,并不限制对集合对象的元素进行操作,这些操作包括一些可能引起跌代错误的add()或remove()等危险操作。在AbstractList中,使用了一个简单的机制来规避这些风险。这就是modCount和expectedModCount的作用所在。

5.序列化支持
ArrayList实现了java.io.Serializable接口,所以ArrayList对象可以序列化到持久存储介质中。ArrayList的主要属性定义如下:

private static final long serialVersionUID = 8683452581122892189L;

private transient Object elementData[];

private int size;

可以看出serialVersionUID和size都将自动序列化到介质中,但elementData数组对象却定义为transient了。也就是说ArrayList中的所有这些元素都不会自动系列化到介质中。为什么要这样实现?因为elementData数组中存储的“元素”其实仅是对这些元素的一个引用,并不是真正的对象,序列化一个对象的引用是毫无意义的,因为序列化是为了反序列化,当你反序列化时,这些对象的引用已经不可能指向原来的对象了。所以在这儿需要手工的对ArrayList的元素进行序列化操作。这就是writeObject()的作用。

    private synchronized void writeObject(java.io.ObjectOutputStream s) 
        throws java.io.IOException{ 
    // Write out element count, and any hidden stuff 
    s.defaultWriteObject(); 
   // Write out array length 
    s.writeInt(elementData.length); 
    // Write out all elements in the proper order. 
    for (int i=0; i<size; i++) 
            s.writeObject(elementData[i]); 
    } 

这样元素数组elementData中的所以元素对象就可以正确地序列化到存储介质了。
对应的readObject()也按照writeObject()方法的顺序从输入流中读取:

    private synchronized void readObject(java.io.ObjectInputStream s) 
        throws java.io.IOException, ClassNotFoundException { 
    // Read in size, and any hidden stuff 
    s.defaultReadObject(); 
    // Read in array length and allocate array 
    int arrayLength = s.readInt(); 
    elementData = new Object[arrayLength]; 
    // Read in all elements in the proper order. 
    for (int i=0; i<size; i++) 
            elementData[i] = s.readObject(); 
    } 

posted @ 2006-01-06 22:03 呓语的博客 阅读(195) | 评论 (0)编辑 收藏

META标签是HTML语言HEAD区的一个辅助性标签,它位于HTML文档头部的<HEAD>标记和<TITLE>标记之间,它提供用户不可见的信息。meta标签通常用来为搜索引擎robots定义页面主题,或者是定义用户浏览器上的cookie;它可以用于鉴别作者,设定页面格式,标注内容提要和关键字;还可以设置页面使其可以根据你定义的时间间隔刷新自己,以及设置RASC内容等级,等等。  

  详细介绍  

  下面介绍一些有关  标记的例子及解释。  

  META标签分两大部分:HTTP标题信息(HTTP-EQUIV)和页面描述信息(NAME)。  

  ★HTTP-EQUIV  

  HTTP-EQUIV类似于HTTP的头部协议,它回应给浏览器一些有用的信息,以帮助正确和精确地显示网页内容。常用的HTTP-EQUIV类型有:  

  1、Content-Type和Content-Language  (显示字符集的设定)  

  说明:设定页面使用的字符集,用以说明主页制作所使用的文字已经语言,浏览器会根据此来调用相应的字符集显示page内容。  

  用法:<Meta  http-equiv="Content-Type"  Content="text/html;  Charset=gb2312">
      <Meta  http-equiv="Content-Language"  Content="zh-CN">  

  注意: 该META标签定义了HTML页面所使用的字符集为GB2132,就是国标汉字码。如果将其中的“charset=GB2312”替换成“BIG5”,则该页面所用的字符集就是繁体中文Big5码。当你浏览一些国外的站点时,IE浏览器会提示你要正确显示该页面需要下载xx语支持。这个功能就是通过读取HTML页面META标签的Content-Type属性而得知需要使用哪种字符集显示该页面的。如果系统里没有装相应的字符集,则IE就提示下载。其他的语言也对应不同的charset,比如日文的字符集是“iso-2022-jp  ”,韩文的是“ks_c_5601”。
      
  Content-Type的Content还可以是:text/xml等文档类型;
  Charset选项:ISO-8859-1(英文)、BIG5、UTF-8、SHIFT-Jis、Euc、Koi8-2、us-ascii,  x-mac-roman,  iso-8859-2,  x-mac-ce,  iso-2022-jp,  x-sjis,  x-euc-jp,euc-kr,  iso-2022-kr,  gb2312,  gb_2312-80,  x-euc-tw,  x-cns11643-1,x-cns11643-2等字符集;Content-Language的Content还可以是:EN、FR等语言代码。  

  2、Refresh  (刷新)  

   说明:让网页多长时间(秒)刷新自己,或在多长时间后让网页自动链接到其它网页。
   用法:<Meta  http-equiv="Refresh"  Content="30">
      <Meta  http-equiv="Refresh"  Content="5;  Url=http://www.xia8.net">
   注意:其中的5是指停留5秒钟后自动刷新到URL网址。  

  3、Expires  (期限)  

   说明:指定网页在缓存中的过期时间,一旦网页过期,必须到服务器上重新调阅。
   用法:<Meta  http-equiv="Expires"  Content="0">
      <Meta  http-equiv="Expires"  Content="Wed,  26  Feb  1997  08:21:57  GMT">
   注意:必须使用GMT的时间格式,或直接设为0(数字表示多少时间后过期)。  

  4、Pragma  (cach模式)  

   说明:禁止浏览器从本地机的缓存中调阅页面内容。
   用法:<Meta  http-equiv="Pragma"  Content="No-cach">
   注意:网页不保存在缓存中,每次访问都刷新页面。这样设定,访问者将无法脱机浏览。  

  5、Set-Cookie  (cookie设定)  

  说明:浏览器访问某个页面时会将它存在缓存中,下次再次访问时就可从缓存中读取,以提高速度。当你希望访问者每次都刷新你广告的图标,或每次都刷新你的计数器,就要禁用缓存了。通常HTML文件没有必要禁用缓存,对于ASP等页面,就可以使用禁用缓存,因为每次看到的页面都是在服务器动态生成的,缓存就失去意义。如果网页过期,那么存盘的cookie将被删除。
   用法:<Meta  http-equiv="Set-Cookie"  Content="cookievalue=xxx;  expires=Wednesday,
        21-Oct-98  16:14:21  GMT;  path=/">
   注意:必须使用GMT的时间格式。  

  6、Window-target  (显示窗口的设定)  

   说明:强制页面在当前窗口以独立页面显示。
   用法:<Meta  http-equiv="Widow-target"  Content="_top">
   注意:这个属性是用来防止别人在框架里调用你的页面。Content选项:_blank、_top、_self、_parent。  

  7、Pics-label  (网页RSAC等级评定)
   说明:在IE的Internet选项中有一项内容设置,可以防止浏览一些受限制的网站,而网站的限制级
      别就是通过该参数来设置的。
   用法:<META  http-equiv="Pics-label"  Contect=
               "(PICS-1.1'http://www.rsac.org/ratingsv01.html'
        I  gen  comment  'RSACi  North  America  Sever'  by  'inet@microsoft.com'  
       for  'http://www.microsoft.com'  on  '1997.06.30T14:21-0500'  r(n0  s0  v0  l0))">  

   注意:不要将级别设置的太高。RSAC的评估系统提供了一种用来评价Web站点内容的标准。用户可以设置Microsoft  Internet  Explorer(IE3.0以上)来排除包含有色情和暴力内容的站点。上面这个例子中的HTML取自Microsoft的主页。代码中的(n  0  s  0  v  0  l  0)表示该站点不包含不健康内容。级别的评定是由RSAC,即美国娱乐委员会的评级机构评定的,如果你想进一步了解RSAC评估系统的等级内容,或者你需要评价自己的网站,可以访问RSAC的站点:http://www.rsac.org/。  

  8、Page-Enter、Page-Exit  (进入与退出)  

   说明:这个是页面被载入和调出时的一些特效。
   用法:<Meta  http-equiv="Page-Enter"  Content="blendTrans(Duration=0.5)">
      <Meta  http-equiv="Page-Exit"  Content="blendTrans(Duration=0.5)">
   注意:blendTrans是动态滤镜的一种,产生渐隐效果。另一种动态滤镜RevealTrans也可以用于页面进入与退出效果:  

      <Meta  http-equiv="Page-Enter"  Content="revealTrans(duration=x,  transition=y)">
      <Meta  http-equiv="Page-Exit"  Content="revealTrans(duration=x,  transition=y)">  

       Duration  表示滤镜特效的持续时间(单位:秒)
       Transition 滤镜类型。表示使用哪种特效,取值为0-23。  

       0  矩形缩小
       1  矩形扩大
       2  圆形缩小
       3  圆形扩大
       4  下到上刷新
       5  上到下刷新
       6  左到右刷新
       7  右到左刷新
       8  竖百叶窗
       9  横百叶窗
        10  错位横百叶窗
        11  错位竖百叶窗
        12  点扩散
        13  左右到中间刷新
        14  中间到左右刷新
        15  中间到上下
        16  上下到中间
        17  右下到左上
        18  右上到左下
        19  左上到右下
        20  左下到右上
        21  横条
        22  竖条
        23  以上22种随机选择一种  

  9、MSThemeCompatible  (XP主题)
   说明:是否在IE中关闭  xp  的主题
   用法:<Meta  http-equiv="MSThemeCompatible"  Content="Yes">
   注意:关闭  xp  的蓝色立体按钮系统显示样式,从而和win2k  很象。  

  10、IE6  (页面生成器)
   说明:页面生成器generator,是ie6
   用法:<Meta  http-equiv="IE6"  Content="Generator">
   注意:用什么东西做的,类似商品出厂厂商。  

  11、Content-Script-Type  (脚本相关)
   说明:这是近来W3C的规范,指明页面中脚本的类型。
   用法:<Meta  http-equiv="Content-Script-Type"  Content="text/javascript">
   注意:  

  ★NAME变量  

  name是描述网页的,对应于Content(网页内容),以便于搜索引擎机器人查找、分类(目前几乎所有的搜索引擎都使用网上机器人自动查找meta值来给网页分类)。
  name的value值(name="")指定所提供信息的类型。有些值是已经定义好的。例如description(说明)、keyword(关键字)、refresh(刷新)等。还可以指定其他任意值,如:creationdate(创建日期)  、
document  ID(文档编号)和level(等级)等。
  name的content指定实际内容。如:如果指定level(等级)为value(值),则Content可能是beginner(初级)、intermediate(中级)、advanced(高级)。  

  1、Keywords  (关键字)
   说明:为搜索引擎提供的关键字列表
   用法:<Meta  name="Keywords"  Content="关键词1,关键词2,关键词3,关键词4,……">
   注意:各关键词间用英文逗号“,”隔开。META的通常用处是指定搜索引擎用来提高搜索质量的关键词。当数个META元素提供文档语言从属信息时,搜索引擎会使用lang特性来过滤并通过用户的语言优先参照来显示搜索结果。例如:
      <Meta  name="Kyewords"  Lang="EN"  Content="vacation,greece,sunshine">
      <Meta  name="Kyewords"  Lang="FR"  Content="vacances,grè:ce,soleil">  

  2、Description  (简介)
   说明:Description用来告诉搜索引擎你的网站主要内容。
   用法:<Meta  name="Description"  Content="你网页的简述">
   注意:  

  3、Robots  (机器人向导)
   说明:Robots用来告诉搜索机器人哪些页面需要索引,哪些页面不需要索引。Content的参数有all、none、index、noindex、follow、nofollow。默认是all。
   用法:<Meta  name="Robots"  Content="All|None|Index|Noindex|Follow|Nofollow">
   注意:许多搜索引擎都通过放出robot/spider搜索来登录网站,这些robot/spider就要用到meta元素的一些特性来决定怎样登录。  

     all:文件将被检索,且页面上的链接可以被查询;
     none:文件将不被检索,且页面上的链接不可以被查询;(和  "noindex,  no  follow"  起相同作用)
     index:文件将被检索;(让robot/spider登录)
     follow:页面上的链接可以被查询;
     noindex:文件将不被检索,但页面上的链接可以被查询;(不让robot/spider登录)
   nofollow:文件将不被检索,页面上的链接可以被查询。(不让robot/spider顺着此页的连接往下探找)  

  4、Author  (作者)
   说明:标注网页的作者或制作组
   用法:<Meta  name="Author"  Content="张三,abc@sina.com">
   注意:Content可以是:你或你的制作组的名字,或Email  

  5、Copyright  (版权)
   说明:标注版权
   用法:<Meta  name="Copyright"  Content="本页版权归Zerospace所有。All  Rights  Reserved">
   注意:  

  6、Generator  (编辑器)
   说明:编辑器的说明
   用法:<Meta  name="Generator"  Content="PCDATA|FrontPage|">
   注意:Content="你所用编辑器"  

  7、revisit-after  (重访)
   说明:
   用法:<META  name="revisit-after"  CONTENT="7  days"  >
   注意:  

  ★Head中的其它一些用法  

  1、scheme  (方案)
   说明:scheme  can  be  used  when  name  is  used  to  specify  how  the  value  of  content  should
      be  interpreted.
   用法:<meta  scheme="ISBN"  name="identifier"  content="0-14-043205-1"  />
   注意:  

  2、Link  (链接)
   说明:链接到文件
   用法:<Link  href="soim.ico"  rel="Shortcut  Icon">
   注意:很多网站如果你把她保存在收件夹中后,会发现它连带着一个小图标,如果再次点击进入之后还会发现地址栏中也有个小图标。现在只要在你的页头加上这段话,就能轻松实现这一功能。<LINK>  用来将目前文件与其它  URL  作连结,但不会有连结按钮,用於  <HEAD>  标记间,  格式如下:  
       <link  href="URL"  rel="relationship">  
       <link  href="URL"  rev="relationship">  

  3、Base  (基链接)
   说明:插入网页基链接属性
   用法:<Base  href="http://www.xia8.net/"  target="_blank">
   注意:你网页上的所有相对路径在链接时都将在前面加上“http://www.cn8cn.com/”。其中target="_blank"是链接文件在新的窗口中打开,你可以做其他设置。将“_blank”改为“_parent”是链接文件将在当前窗口的父级窗口中打开;改为“_self”链接文件在当前窗口(帧)中打开;改为“_top”链接文件全屏显示。  

  以上是META标签的一些基本用法,其中最重要的就是:Keywords和Description的设定。为什么呢?道理很简单,这两个语句可以让搜索引擎能准确的发现你,吸引更多的人访问你的站点!根据现在流行搜索引擎(Google,Lycos,AltaVista等)的工作原理,搜索引擎先派机器人自动在WWW上搜索,当发现新的网站时,便于检索页面中的Keywords和Description,并将其加入到自己的数据库,然后再根据关键词的密度将网站排序。  

  由此看来,我们必须记住添加Keywords和Description的META标签,并尽可能写好关键字和简介。否则,
后果就会是:
  
  ● 如果你的页面中根本没有Keywords和Description的META标签,那么机器人是无法将你的站点加入数
    据库,网友也就不可能搜索到你的站点。  

  ● 如果你的关键字选的不好,关键字的密度不高,被排列在几十甚至几百万个站点的后面被点击的可
    能性也是非常小的。  

  写好Keywords(关键字)要注意以下几点:  

  ● 不要用常见词汇。例如www、homepage、net、web等。  

  ● 不要用形容词,副词。例如最好的,最大的等。  

  ● 不要用笼统的词汇,要尽量精确。例如“爱立信手机”,改用“T28SC”会更好。  

  “三人之行,必有我师”,寻找合适关键词的技巧是:到Google、Lycos、Alta等著名搜索引擎,搜索与
你的网站内容相仿的网站,查看排名前十位的网站的META关键字,将它们用在你的网站上,效果可想而知了。  

  ★小窍门  

  为了提高搜索点击率,这里还有一些“捷径”可以帮得到你:  

  ● 为了增加关键词的密度,将关键字隐藏在页面里(将文字颜色定义成与背景颜色一样)。  

  ● 在图像的ALT注释语句中加入关键字。如:<IMG  SRC="xxx.gif"  Alt="Keywords">  

  ● 利用HTML的注释语句,在页面代码里加入大量关键字。用法:  <!--  这里插入关键字  -->  

<head>  <title>文件头,显示在浏览器标题区</title>  <meta  http-equiv="Content-Language"  content="zh-cn">  <meta  http-equiv="Content-Type"  content="text/html;  charset=gb2312">  <meta  name="GENERATOR"  content="Microsoft  FrontPage  4.0">  <meta  name="ProgId"  content="FrontPage.Editor.Document">  <meta  name="制作人"  content="唐蓉生">  <meta  name="主题词"  content="HTML  网页制作  课件"></head>

posted @ 2006-01-03 10:08 呓语的博客 阅读(178) | 评论 (0)编辑 收藏

Expires 属性
Expires 属性指定了在浏览器上缓冲存储的页距过期还有多少时间。如果用户在某个页过期之前又回到此页,就会显示缓冲区中的版本

语法
Response.Expires [= number]
 
参数
number 
距过期还有多少分钟。将此参数设置为 0 可使缓存的页立即过期。 
注释
若此属性在一页上设置了多次,则使用最短的时间。
 
应用于
Response 对象

  Response.expires=0也表示立即过期,但如果client和server不在一个时区或者client的时间早于server上的时间,则不能立即过期。所以用负数或者用Response.ExpiresAbsolute=now()-1来表示立即过期,response.expires=1表示在1分钟后过期。

posted @ 2005-12-29 12:34 呓语的博客 阅读(605) | 评论 (0)编辑 收藏

不知道大家对Buffer了解多少,很多人对这个概念都比较模糊,尤其是在asp中。很多初学者在编写asp程序时很少用到这条语句,下面我就来说说Buffer的用途以及它在asp程序中的作用。

一、Buffer

Buffer从英文直译过来的意思是“缓冲区”,这里我们将它称为缓冲,因为它不仅是个名词,还是个动词。
缓冲区是存储一系列的数据的地方,客户端所获得的数据可以从程序的执行结果直接输出,也可以从缓冲区输出。但是这两种方式在速度上是有差异的:在web中,当一个asp程序被请求的次数不多时,二者基本上没有什么差异,至少我们感觉不出来。但是当有很多人请求一个asp程序时,速度可就不一样了。如果没有缓冲区,那么每个请求asp程序的人的客户端所得到的结果都是asp程序执行一次所得到的结果,而如果预先将asp程序缓冲,那么每个客户端所得到的结果就是缓冲区的结果,不是执行一次程序的结果。比如有1000个用户同时访问一个asp页面,如果这个asp程序没有缓冲,那么程序将被执行一千次,这样服务器的负荷就回加大,从而导致客户端打开页面速度变慢;如果这个asp程序被缓冲了,那么结果就不一样了,每个客户端直接从缓冲区获得数据,服务器将不会因为访问增加而增加程序执行次数,因此客户端打开页面的速度也就比上一种情况要快。这就是Buffer的好处。

二、如何将asp程序缓冲

这个问题其实很简单,只要在asp程序的第一行加上:
<% Response.Buffer = True %>
就可以了。
这句话的意思就是指明输出页面是否被缓冲,当属性值为True时,服务器将不会向客户端发送任何信息,直到所有程序执行完或者遇到
<% Response.Flush %>或<% Response.End %>
语句,才会释放缓冲区的信息。


三、总结

Response的Buffer属性虽然能够提高页面显示速度,但是也要分什么情况。如果你正在制作一个普通的个人主页,访问量不是很高,并且没有什么复杂的执行程序,那么用不用这个属性就不是很重要,因为将数据缓冲也需要一段时间,只不过我们感觉不到罢了;但是如果你正在制作一个大型论坛或者一个产品展示或其他的商务站点,并且访问量很高,那么我建议在程序的第一行加入
<% Response.Buffer = True %>
这句话,因为这样能够让客户在有效的时间内获得更多的数据。

posted @ 2005-12-29 11:56 呓语的博客 阅读(178) | 评论 (0)编辑 收藏

在我们学习Java的过程中,掌握其中的基本概念对我们的学习无论是J2SE,J2EE,J2ME都是很重要的,J2SE是Java的基础,所以有必要对其中的基本概念做以归纳,以便大家在以后的学习过程中更好的理解java的精髓,在此我总结了30条基本的概念。

Java概述:

   目前Java主要应用于中间件的开发(middleware)---处理客户机于服务器之间的通信技术,早期的实践证明,Java不适合pc应用程序的开发,其发展逐渐变成在开发手持设备,互联网信息站,及车载计算机的开发.Java于其他语言所不同的是程序运行时提供了平台的独立性,称许可以在windows,solaris,linux其他操作系统上使用完全相同的代码.Java的语法与C++语法类似,C++/C程序员很容易掌握,而且Java是完全的彻底的面向对象的,其中提出了很好的GC(Garbage Collector)垃圾处理机制,防止内存溢出。

   Java的白皮书为我们提出了Java语言的11个关键特性。

   (1)Easy:Java的语法比C++的相对简单,另一个方面就是Java能使软件在很小的机器上运行,基础解释其和类库的支持的大小约为40kb,增加基本的标准库和线程支持的内存需要增加125kb。

   (2)分布式:Java带有很强大的TCP/IP协议族的例程库,Java应用程序能够通过URL来穿过网络来访问远程对象,由于servlet机制的出现,使Java编程非常的高效,现在许多的大的web server都支持servlet。

   (3)O面向对象设计是把重点放在对象及对象的接口上的一个编程技术.其面向对象和C++有很多不同,在与多重继承的处理及Java的原类模型。

   (4)健壮特性:Java采取了一个安全指针模型,能减小重写内存和数据崩溃的可能型。

   (5)安全:Java用来设计网路和分布系统,这带来了新的安全问题,Java可以用来构建防病毒和防攻击的System.事实证明Java在防毒这一方面做的比较好。

   (6)中立体系结构:Java编译其生成体系结构中立的目标文件格式可以在很多处理器上执行,编译器产生的指令字节码(Javabytecode)实现此特性,此字节码可以在任何机器上解释执行。

   (7)可移植性:Java中对基本数据结构类型的大小和算法都有严格的规定所以可移植性很好。

   (8)多线程:Java处理多线程的过程很简单,Java把多线程实现交给底下操作系统或线程程序完成.所以多线程是Java作为服务器端开发语言的流行原因之一。

   (9)Applet和servlet:能够在网页上执行的程序叫Applet,需要支持Java的浏览器很多,而applet支持动态的网页,这是很多其他语言所不能做到的。

基本概念:

   1.OOP中唯一关系的是对象的接口是什么,就像计算机的销售商她不管电源内部结构是怎样的,他只关系能否给你提供电就行了,也就是只要知道can or not而不是how and why.所有的程序是由一定的属性和行为对象组成的,不同的对象的访问通过函数调用来完成,对象间所有的交流都是通过方法调用,通过对封装对象数据,很大限度上提高复用率。

   2.OOP中最重要的思想是类,类是模板是蓝图,从类中构造一个对象,即创建了这个类的一个实例(instance)。

   3.封装:就是把数据和行为结合起在一个包中)并对对象使用者隐藏数据的实现过程,一个对象中的数据叫他的实例字段(instance field)。

   4.通过扩展一个类来获得一个新类叫继承(inheritance),而所有的类都是由Object根超类扩展而得,根超类下文会做介绍。

   5.对象的3个主要特性

   behavior---说明这个对象能做什么.
   state---当对象施加方法时对象的反映.
   identity---与其他相似行为对象的区分标志.
   每个对象有唯一的indentity 而这3者之间相互影响.

   6.类之间的关系:

use-a :依赖关系
has-a :聚合关系
is-a :继承关系--例:A类继承了B类,此时A类不仅有了B类的方法,还有其自己的方法.(个性存在于共性中)

   7.构造对象使用构造器:构造器的提出,构造器是一种特殊的方法,构造对象并对其初始化。

   例:Data类的构造器叫Data

    new Data()---构造一个新对象,且初始化当前时间.
    Data happyday=new Data()---把一个对象赋值给一个变量happyday,从而使该对象能够多次使用,此处要声明的使变量与对象变量二者是不同的.new返回的值是一个引用。

   构造器特点:构造器可以有0个,一个或多个参数
   构造器和类有相同的名字
   一个类可以有多个构造器
   构造器没有返回值
   构造器总是和new运算符一起使用.

   8.重载:当多个方法具有相同的名字而含有不同的参数时,便发生重载.编译器必须挑选出调用哪个方法。

   9.包(package)Java允许把一个或多个类收集在一起成为一组,称作包,以便于组织任务,标准Java库分为许多包.java.lang java.util java,net等,包是分层次的所有的java包都在java和javax包层次内。

   10.继承思想:允许在已经存在的类的基础上构建新的类,当你继承一个已经存在的类时,那么你就复用了这个类的方法和字段,同时你可以在新类中添加新的方法和字段。

   11.扩展类:扩展类充分体现了is-a的继承关系. 形式为:class (子类) extends (基类)。

   12.多态:在java中,对象变量是多态的.而java中不支持多重继承。

   13.动态绑定:调用对象方法的机制。

   (1)编译器检查对象声明的类型和方法名。

   (2)编译器检查方法调用的参数类型。

   (3)静态绑定:若方法类型为priavte static final 编译器会准确知道该调用哪个方法。

   (4)当程序运行并且使用动态绑定来调用一个方法时,那么虚拟机必须调用x所指向的对象的实际类型相匹配的方法版本。

   (5)动态绑定:是很重要的特性,它能使程序变得可扩展而不需要重编译已存代码。

   14.final类:为防止他人从你的类上派生新类,此类是不可扩展的。

   15.动态调用比静态调用花费的时间要长。

   16.抽象类:规定一个或多个抽象方法的类本身必须定义为abstract。

   例: public abstract string getDescripition

   17.Java中的每一个类都是从Object类扩展而来的。

   18.object类中的equal和toString方法。

   equal用于测试一个对象是否同另一个对象相等。

   toString返回一个代表该对象的字符串,几乎每一个类都会重载该方法,以便返回当前状态的正确表示.
(toString 方法是一个很重要的方法)

   19.通用编程:任何类类型的所有值都可以同object类性的变量来代替。

   20.数组列表:ArrayList动态数组列表,是一个类库,定义在java.uitl包中,可自动调节数组的大小。

   21.class类 object类中的getclass方法返回ckass类型的一个实例,程序启动时包含在main方法的类会被加载,虚拟机要加载他需要的所有类,每一个加载的类都要加载它需要的类。

   22.class类为编写可动态操纵java代码的程序提供了强大的功能反射,这项功能为JavaBeans特别有用,使用反射Java能支持VB程序员习惯使用的工具。

   能够分析类能力的程序叫反射器,Java中提供此功能的包叫Java.lang.reflect反射机制十分强大.

   1.在运行时分析类的能力。
   2.在运行时探察类的对象。
   3.实现通用数组操纵代码。
   4.提供方法对象。

   而此机制主要针对是工具者而不是应用及程序。

   反射机制中的最重要的部分是允许你检查类的结构.用到的API有:

java.lang.reflect.Field 返回字段.
java.reflect.Method 返回方法.
java.lang.reflect.Constructor 返回参数.

   方法指针:java没有方法指针,把一个方法的地址传给另一个方法,可以在后面调用它,而接口是更好的解决方案。

   23.接口(Interface)说明类该做什么而不指定如何去做,一个类可以实现一个或多个interface。

   24.接口不是一个类,而是对符合接口要求的类的一套规范。

   若实现一个接口需要2个步骤: 

   1.声明类需要实现的指定接口。
   2.提供接口中的所有方法的定义。

   声明一个类实现一个接口需要使用implements 关键字

   class actionB implements Comparable 其actionb需要提供CompareTo方法,接口不是类,不能用new实例化一个接口.

   25.一个类只有一个超类,但一个类能实现多个接口。Java中的一个重要接口:Cloneable

   26.接口和回调.编程一个常用的模式是回调模式,在这种模式中你可以指定当一个特定时间发生时回调对象上的方法。

   例:ActionListener 接口监听.
   类似的API有:java.swing.JOptionPane

    java.swing.Timer
    java.awt.Tookit

   27.对象clone:clone方法是object一个保护方法,这意味着你的代码不能简单的调用它。

   28.内部类:一个内部类的定义是定义在另一个内部的类。

   原因是:

   1.一个内部类的对象能够访问创建它的对象的实现,包括私有数据。

   2.对于同一个包中的其他类来说,内部类能够隐藏起来。

   3.匿名内部类可以很方便的定义回调。

   4.使用内部类可以非常方便的编写事件驱动程序。

   29.代理类(proxy):

   1.指定接口要求所有代码

   2.object类定义的所有的方法(toString equals)

   30.数据类型:Java是强调类型的语言,每个变量都必须先申明它都类型,java中总共有8个基本类型.4种是整型,2种是浮点型,一种是字符型,被用于Unicode编码中的字符,布尔型。

posted @ 2005-12-28 09:35 呓语的博客 阅读(174) | 评论 (0)编辑 收藏

1.document.write(""); 输出语句
2.JS中的注释为//
3.传统的HTML文档顺序是:document->html->(head,body)
4.一个浏览器窗口中的DOM顺序是:window->(navigator,screen,history,location,document)
5.得到表单中元素的名称和值:document.getElementById("表单中元素的ID号").name(或value)
6.一个小写转大写的JS: document.getElementById("output").value = document.getElementById("input").value.toUpperCase();
7.JS中的值类型:String,Number,Boolean,Null,Object,Function
8.JS中的字符型转换成数值型:parseInt(),parseFloat()
9.JS中的数字转换成字符型:(""+变量)
10.JS中的取字符串长度是:(length)
11.JS中的字符与字符相连接使用+号.
12.JS中的比较操作符有:==等于,!=不等于,>,>=,<.<=
13.JS中声明变量使用:var来进行声明
14.JS中的判断语句结构:if(condition){}else{}
15.JS中的循环结构:for([initial expression];[condition];[upadte expression]) {inside loop}
16.循环中止的命令是:break
17.JS中的函数定义:function functionName([parameter],...){statement[s]}
18.当文件中出现多个form表单时.可以用document.forms[0],document.forms[1]来代替.
19.窗口:打开窗口window.open(), 关闭一个窗口:window.close(), 窗口本身:self
20.状态栏的设置:window.status="字符";
21.弹出提示信息:window.alert("字符");
22.弹出确认框:window.confirm();
23.弹出输入提示框:window.prompt();
24.指定当前显示链接的位置:window.location.href="URL"
25.取出窗体中的所有表单的数量:document.forms.length
26.关闭文档的输出流:document.close();
27.字符串追加连接符:+=
28.创建一个文档元素:document.createElement(),document.createTextNode()
29.得到元素的方法:document.getElementById()
30.设置表单中所有文本型的成员的值为空:
var form = window.document.forms[0]
for (var i = 0; i<form.elements.length;i++){
    if (form.elements.type == "text"){
        form.elements.value = "";
    }
}
31.复选按钮在JS中判断是否选中:document.forms[0].checkThis.checked (checked属性代表为是否选中返回TRUE或FALSE)
32.单选按钮组(单选按钮的名称必须相同):取单选按钮组的长度document.forms[0].groupName.length
33.单选按钮组判断是否被选中也是用checked.
34.下拉列表框的值:document.forms[0].selectName.options[n].value (n有时用下拉列表框名称加上.selectedIndex来确定被选中的值)
35.字符串的定义:var myString = new String("This is lightsword");
36.字符串转成大写:string.toUpperCase(); 字符串转成小写:string.toLowerCase();
37.返回字符串2在字符串1中出现的位置:String1.indexOf("String2")!=-1则说明没找到.
38.取字符串中指定位置的一个字符:StringA.charAt(9);
39.取出字符串中指定起点和终点的子字符串:stringA.substring(2,6);
40.数学函数:Math.PI(返回圆周率),Math.SQRT2(返回开方),Math.max(value1,value2)返回两个数中的最在值,Math.pow(value1,10)返回value1的十次方,Math.round(value1)四舍五入函数,Math.floor(Math.random()*(n+1))返回随机数
41.定义日期型变量:var today = new Date();
42.日期函数列表:dateObj.getTime()得到时间,dateObj.getYear()得到年份,dateObj.getFullYear()得到四位的年份,dateObj.getMonth()得到月份,dateObj.getDate()得到日,dateObj.getDay()得到日期几,dateObj.getHours()得到小时,dateObj.getMinutes()得到分,dateObj.getSeconds()得到秒,dateObj.setTime(value)设置时间,dateObj.setYear(val)设置年,dateObj.setMonth(val)设置月,dateObj.setDate(val)设置日,dateObj.setDay(val)设置星期几,dateObj.setHours设置小时,dateObj.setMinutes(val)设置分,dateObj.setSeconds(val)设置秒  [注意:此日期时间从0开始计]
43.FRAME的表示方式: [window.]frames[n].ObjFuncVarName,frames["frameName"].ObjFuncVarName,frameName.ObjFuncVarName
44.parent代表父亲对象,top代表最顶端对象
45.打开子窗口的父窗口为:opener
46.表示当前所属的位置:this
47.当在超链接中调用JS函数时用:(javascript :)来开头后面加函数名
48.在老的浏览器中不执行此JS:<!--      //-->
49.引用一个文件式的JS:<script type="text/javascript" src="aaa.js"></script>
50.指定在不支持脚本的浏览器显示的HTML:<noscript></noscript>
51.当超链和onCLICK事件都有时,则老版本的浏览器转向a.html,否则转向b.html.例:<a href="a.html" onclick="location.href='b.html';return false">dfsadf</a>
52.JS的内建对象有:Array,Boolean,Date,Error,EvalError,Function,Math,Number,Object,RangeError,ReferenceError,RegExp,String,SyntaxError,TypeError,URIError
53.JS中的换行:\n
54.窗口全屏大小:<script>function fullScreen(){ this.moveTo(0,0);this.outerWidth=screen.availWidth;this.outerHeight=screen.availHeight;}window.maximize=fullScreen;</script>
55.JS中的all代表其下层的全部元素
56.JS中的焦点顺序:document.getElementByid("表单元素").tabIndex = 1
57.innerHTML的值是表单元素的值:如<p id="para">"how are <em>you</em>"</p>,则innerHTML的值就是:how are <em>you</em>
58.innerTEXT的值和上面的一样,只不过不会把<em>这种标记显示出来.
59.contentEditable可设置元素是否可被修改,isContentEditable返回是否可修改的状态.
60.isDisabled判断是否为禁止状态.disabled设置禁止状态
61.length取得长度,返回整型数值
62.addBehavior()是一种JS调用的外部函数文件其扩展名为.htc
63.window.focus()使当前的窗口在所有窗口之前.
64.blur()指失去焦点.与FOCUS()相反.
65.select()指元素为选中状态.
66.防止用户对文本框中输入文本:onfocus="this.blur()"
67.取出该元素在页面中出现的数量:document.all.tags("div(或其它HTML标记符)").length
68.JS中分为两种窗体输出:模态和非模态.window.showModaldialog(),window.showModeless()
69.状态栏文字的设置:window.status='文字',默认的状态栏文字设置:window.defaultStatus = '文字.';
70.添加到收藏夹:external.AddFavorite("http://www.dannyg.com";,"jaskdlf");
71.JS中遇到脚本错误时不做任何操作:window.onerror = doNothing; 指定错误句柄的语法为:window.onerror = handleError;
72.JS中指定当前打开窗口的父窗口:window.opener,支持opener.opener...的多重继续.
73.JS中的self指的是当前的窗口
74.JS中状态栏显示内容:window.status="内容"
75.JS中的top指的是框架集中最顶层的框架
76.JS中关闭当前的窗口:window.close();
77.JS中提出是否确认的框:if(confirm("Are you sure?")){alert("ok");}else{alert("Not Ok");}
78.JS中的窗口重定向:window.navigate("http://www.sina.com.cn";);
79.JS中的打印:window.print()
80.JS中的提示输入框:window.prompt("message","defaultReply");
81.JS中的窗口滚动条:window.scroll(x,y)
82.JS中的窗口滚动到位置:window.scrollby
83.JS中设置时间间隔:setInterval("expr",msecDelay)或setInterval(funcRef,msecDelay)或setTimeout
84.JS中的模态显示在IE4+行,在NN中不行:showModalDialog("URL"[,arguments][,features]);
85.JS中的退出之前使用的句柄:function verifyClose(){event.returnValue="we really like you and hope you will stay longer.";}}  window.onbeforeunload=verifyClose;
86.当窗体第一次调用时使用的文件句柄:onload()
87.当窗体关闭时调用的文件句柄:onunload()
88.window.location的属性: protocol(http:),hostname(www.example.com),port(80),host(www.example.com:80),pathname("/a/a.html"),hash("#giantGizmo",指跳转到相应的锚记),href(全部的信息)
89.window.location.reload()刷新当前页面.
90.window.history.back()返回上一页,window.history.forward()返回下一页,window.history.go(返回第几页,也可以使用访问过的URL)
91.document.write()不换行的输出,document.writeln()换行输出
92.document.body.noWrap=true;防止链接文字折行.
93.变量名.charAt(第几位),取该变量的第几位的字符.
94."abc".charCodeAt(第几个),返回第几个字符的ASCii码值.
95.字符串连接:string.concat(string2),或用+=进行连接
96.变量.indexOf("字符",起始位置),返回第一个出现的位置(从0开始计算)
97.string.lastIndexOf(searchString[,startIndex])最后一次出现的位置.
98.string.match(regExpression),判断字符是否匹配.
99.string.replace(regExpression,replaceString)替换现有字符串.
100.string.split(分隔符)返回一个数组存储值.
101.string.substr(start[,length])取从第几位到指定长度的字符串.
102.string.toLowerCase()使字符串全部变为小写.
103.string.toUpperCase()使全部字符变为大写.
104.parseInt(string[,radix(代表进制)])强制转换成整型.
105.parseFloat(string[,radix])强制转换成浮点型.
106.isNaN(变量):测试是否为数值型.
107.定义常量的关键字:const,定义变量的关键字:var

posted @ 2005-12-19 12:24 呓语的博客 阅读(207) | 评论 (0)编辑 收藏

CSS是“Cascading Style Sheets”的简称,中文翻译为“串接样式表”,也有人翻译 为“样式表”。CSS用以作为网页的排版和风格设计,在web标准建站中,对CSS的熟悉和使用 是相当重要的一个内容。CSS的作用是弥补HTML的不足,让网页的设计更为灵活。

  这个文章只是为您介绍CSS的基础应用,指引您的一个入门的基础教程,主要目的是为 推进web标准贡献自己的微薄之力。

  说点我自己的体会,现在有好多人都在推广WEB标准,其实对初学者来说,不需要刚学 的时候就学标准,学点简单的还是容易入门的,因为现在HTML还在照样用啊,所以我希望初学 者学习时不要非遵循标准,当你入门之后,你做网页的时候,发现使用表格特麻烦的时候你就 该去寻求简单方法了,到时再学也不晚啊,如果你喜欢新技术那么你初学时就学标准吧,按个 人的实际来行动吧。下面开始学习了

  一、如何在HTML中应用CSS。

  您可以利用下列 3 种方式将 CSS 指定的格式加入到HTML中:

  1. 在 HTML 文件里加一个超级连结,连接到外部的 CSS 文档。(外部连结 CSS)

  这个方法最方便管理整个网站的网页风格,它让网页的文字内容与版面设计分开。您 只要在一个 CSS 文档内(扩展名为 .CSS)定义好网页的风格,然后在网页中加一个超级连接 连接到该文档,那么你的网页会按在CSS文档内定义好的风格显示出来了。

  具体的使用防范是:

  <HTML>

  <HEAD>

  <TITLE>网页文件的标题</TITLE>

  <LINK REL="stylesheet" HREF="style.css" TYPE="text/css">

  </HEAD>

  注意:style.css文件的位置。

  2. 在 HTML 文件内的 <HEAD>.......</HEAD> 标签之间,加一段 CSS 的描述内容。(内定义CSS)

  这个方法适用于指定某个网页,除了表现外部的 CSS 文档定义好的网页风格外,同时 还要表现本身 HTML 文档内指定的 CSS 。

  如果内在添加的 CSS 描述与外部连接的 CSS 描述相冲突的话,网页的表现将以内在 添加的 CSS 描述为主,也就是外部的描述就不再起作用了。

  具体使用方法是:

  <HTML>

  <HEAD>

  <TITLE>网页标题</TITLE>

  <STYLE TYPE="text/css">

  <!--

  BODY {font: 12pt}

  H1 {font: 16pt}

  P {font-weight: bold;

  color: green}

  -->

  </STYLE>

  </HEAD>

  <BODY>

  网页内容…

  </BODY>

  </HTML>

  值得注意的是,为了防止不支持 CSS 的浏览器误将标签间的 CSS 风格描述当成普通 字串,而表现于网页上,您最好将 CSS 的叙述文字插入在<!--和-->之间。

  3. 在 HTML 文件的文本内容中,随时有需要,随时加一小段 CSS 的描述指定风格。( 文本间CSS)

  这个方法适用于指定网页内的某一小段文字的呈现风格。

  外部CSS与内定义CSS如果和此定义有相同的项,那么以此定义的 CSS 风格表现,外部 CSS文档与内定义CSS和此定义的没相同的项时那么还会正常显示,同时还会显示文本内容间的 CSS 风格。

  具体使用方法是:

  <HTML>

  <HEAD>

  <TITLE>网页标题</TITLE>

  </HEAD>

  <BODY>

  <P STYLE="color: red">

  本页内容…

  </P>

  </BODY>

  </HTML>

  上述的 3 种 CSS,可以同时并用,也可以择您所好,单一或成双地使用。如果各 CSS 间的叙述相冲突,则内在定义的 CSS 会覆盖外部连结的 CSS ,文本间的 CSS 会覆盖内在定 义的 CSS 。

  二、挑选者、属性和值。

  先举个例子:H3{ COLOR : BLUE }表示在文本中只要使用H3标签的文字的颜色都是绿 色。其中H3为挑选者,COLOR为属性,BLUE为COLOR属性的值。挑选者是套用样式的元件,通常 为外部CSS或内定义CSS定义的风格的一个名字,在这个初级教程里理解为一个标签的名字也可 以。属性是用语描述挑选者的特性,相当于HTML语法中的标签的属性。值就是属性的具体内容 。

  在CSS中当我们使用到属性值的时候,通常值是有一个度量依据的,也就是说值是有单 位的。比如我们通常说你从家到学校走1,1什么呢?米,公里,还是走1小时。通常在CSS中的 单位有:相对单位与绝对单位两种单位具体如下:

  “em” (比如 font-size: 2em) :相对于字母高度的比例因子。

  “%” (比如 font-size: 80%): 相对于长度单位(通常是目前字型的大小)的百分 比例。

  

  'px' (比如 font-size: 12px) :像素(系统预设单位)。

  'pt' (比如 font-size: 12pt): 像点。

  此外还有 'pc' (印刷活字单位), 'cm' (公分), 'mm' (公厘) 和 'in' (英寸)等单位 。

  当值为0时,我们就不需要设置单位了,比如你不想要边框那么我们直接设置border=0 。

  在这我多说一句,就是强调单位的使用时,当我自己制作的网页想在分辨率改变时, 字体大小也随着改变那么我们就使用单位%和em,如果你想时你的网页不管怎么调分辨率都是 固定大小的那么我们使用px、pt等元素了。呵呵!

  三、颜色的设置和使用。

  CSS提供了16,777,216种颜色可以供我们来使用,通常表现颜色的方式有三种:颜色名 字、RGB(red/green/blue) 数值和十六进制数形式,具体表现如下:

  红色可以表示为:red、RGB(255,0,0)、rgb(100%,0%,0%)、#ff0000 和 #f00 五种方 式。

  #RRGGBB:以三个00到FF的十六进位值分别表示0到255十进位值的红、绿、蓝三原色数 值。

  #RGB:简略表示法,只用三个0到F的十六进位值分别表示红、绿、蓝三原色数值。而 事实上,浏览器会自动扩展为六个十六进位的值,如『#ABC』将变为『#AABBCC』。但是,显 见这样的 表示法并不精确。

  rgb(R,G,B):以0到255十进位值的红、绿、蓝三原色数值来表示颜色。

  rgb(R%,G%,B%):以红、绿、蓝彼此相对的数值比例来表示颜色,如rgb (60%,100%,75%)。

  Color_Name: 直接以颜色名称来表示颜色,共有141种标准的颜色名称。

  通常我们在设置颜色的时候通常是设置文字的颜色还有一个就是背景色。如按下图进 行设置:

  我们可以保存一下文荡然后浏览你就可以看到效果了。

  四、关于文本的设置。

  我们可以使用多种属性来改变网页文本的大小和形状,以使网页文本内容看起来更加美 观。

  font-family:设定文字字型 可以取family-name值,范例:SPAN { family-name : " 楷体" }或范例:<SPAN style="family-name:楷体">。

  font-style:设定字体样式,可以取的值有normal 普通字、italic 斜体字;范例: SPAN { font-style : italic }。

  font-weight:设定字型份量;可以取的值有normal 普通字 、bold 粗体字 、bolder 相对于父元素稍粗 、lighter 相对于父元素稍细 、100,200,300,400,500,600,700,800,900 数字由小到大代表笔画由细到粗,例如:normal=400 bold=700 ;范例:SPAN { font- weight : bolder }。

  font-size:设定文字大小。

  text-decoration:设定文字修饰,可能值有 none 普通字 、underline 文字加底线 、overline 文字加顶线 、line-through 文字加删除线 、blink 设定文字闪烁 ;范例: SPAN { text-decoration : blink }

  text-transform:设定文字转换 ;可能值有none 普通字 、capitalize 将英文单字 地一个字母转换为大写 、uppercase 将所有文字转换为大写 、lowercase 将所有文字转换为 小写 ;范例:SPAN { text-transform : uppercase }。

  

  五、边缘和区块的设置。

  MARGIN:边缘,虽然是通透的部份,但是可以藉由边缘宽度的调整来达到内容元素位 置调整的目的。PADDING:补白,也就是内容元素与框架之间的这段距离与空间,也可以利用 CSS指令去控制大小。

  把代码改为如图:

   他们的属性有:margin-top(上边缘宽度), margin-right(右边缘宽度), margin- bottom(下边缘宽度), margin-left(左边缘宽度), padding-top(上方补白宽度), padding- right(右方补白宽度), padding-bottom(下方补白宽度) 和 padding-left(左方补白宽度)。

  下面通过一个图来给大家说明:

  看看上图理解点了吧!下面我们开始讲讲边框。

  六、边框border性质设定。

  边框也能应用到大多数的HTML标签中,可以来使网页更加美观,边框的具体属性有 border-top:综合设定上边框性质 、border-right:综合设定右边框性质 、border-bottom :综合设定下边框性质、 border-left:综合设定左边框性质。

  border-style 综合设定边框样式 ,可能值:solid(实线), dotted(虚线), dashed( 短直线), double(双直线), groove (3d凹线), ridge (3d凸线), inset (3d嵌入) 和 outset (3d隆起)。

  border-width 综合设定边框宽度,可以设置的有 border-top-width(设定上边框宽度 ), border-right-width(设定右边框宽度), border-bottom-width(设定下边框宽度) 和 border-left-width(设定左边框宽度).

  border-color 综合设定边框颜色。

  把下面代码加到你的网页中可以看到效果了:

  这片文章就介绍到这里了,因为是一个初学者的入门教程,所以内容显得少的可怜。 以后会给大家介绍一些比较高级的内容,希望大家支持我啊!


属性名称

字体属性(Font)
font-family
font-style
font-variant
font-weight
font-size


颜色和背景属性
Color
Background-color
Background-image
Background-repeat
Background-attachment
Background-position


文本属性
Word-spacing
Letter-spacing
Text-decoration

Vertical-align

Text-transform

Text-align
Text-indent
Line-height


边距属性
Margin-top
Margin-right
Margin-bottom
Margin-left

填充距属性
Padding-top
Padding-right
Padding-bottom
Padding-left

边框属性
Border-top-width
Border-right-width
Border-bottom-width
Border-left-width
Border-width
Border-color
Border-style
Border-top
Border-right
Border-bottom
Border-left
Width
Height
Float
Clear

分级属性
Display
White-space
List-style-type
List-style-image
List-style-position
List-style

鼠标(Cursor)属性
属性含义


使用什么字体
字体是否斜体
是否用小体大写
字体的粗细
字体的大小



定义前景色
定义背景色
定义背景图案
重复方式
设置滚动
初始位置



单词之间的间距
字母之间的间距
文字的装饰样式

垂直方向的位置

文本转换

对齐方式
首行的缩进方式
文本的行高



顶端边距
右侧边距
底端边距
左侧边距


顶端填充距
右侧填充距
底端填充距
左侧填充距


顶端边框宽度
右侧边框宽度
底端边框宽度
左侧边框宽度
一次定义宽度
设置边框颜色
设置边框样式
一次定义顶端
一次定义右侧
一次定义底端
一次定义左侧
定义宽度属性
定义高度属性
文字环绕
哪一边环绕


定义是否显示
怎样处理空白
加项目编号
加图案
第二行起始位置
一次定义列表


自动
定位“十”字
默认指针
手形
移动
箭头朝右方
箭头朝右上方
箭头朝左上方
箭头朝上方
箭头朝右下方
箭头朝左下方
箭头朝下方
箭头朝左方
文本“I”形
等待
帮助

posted @ 2005-12-16 16:06 呓语的博客 阅读(223) | 评论 (0)编辑 收藏