9.类的使用

1.运算符重载

operatorop(augument-list)

Time operator+(const Time & t) const

Time Time::operator+(const Time & t) const

{

Time sum;

sum.minutes = minutes + t.minutes;

sum.hours = hours + t.hours + sum.minutes / 60;

sum.minutes %= 60;

return sum;

}

total = coding.operator+(fixing);

total = coding + fixing;

运算符左侧的对象是调用对象,运算符右边的对象是作为参数被传递的对象。

2.重载限制

1.必须起码有一个是用户自定义的类型。

2.使用运算符时不能违反原来的句法规则。

3.不能创建新的运算符。

4.不能重载:sizeof, ., .*, ::, ?:, typeid, const_cast, dynamic_cast, reinterpret-cast, static_cast.

3.友元

1.友元函数。

第一步将其原型放在类声明中,并在原型声明前加上关键字friend。虽然它是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用,但是它与成员函数的访问权限相同。

第二部是编写函数定义。

2.友元类。

3.友元成员函数。

3.重载负号

Vector operator-() const;

Vector Vector::operator-() const

{

return Vector (-x, -y);

}

4.类的自动转换和强制类型转换

程序将使用构造函数,创建一个临时的对象,将赋给的值作为初始值。只有接受一个参数的构造函数才能作为转换函数。两个参数时,若给后面的参数提供默认值,则可以进行转换。

explicit Stonewt(double lbs);关闭(隐式)自动类型转换,但还是允许显式类型转换。

5.转换函数

operator double();

转换函数必须是类方法。
class lime

{

private:

int m;

public:

lime(int n)

{

m = n;

}

lime()

{

m = 0;

}

operator int()

{

return m;

}

};

 

可将装换声明为显示的。explicit operator int() const;

6.重载<<运算符

ostream & operator<<(ostream & os, t temp)

{

os << temp.a << ” + ” << temp.b << endl;

return os;

}

 

 

 

8.对象和类

1.定义类

一般定义在头文件中,

#ifndef STOCK00_H_

#define STOCK00_H_

 

#endif

包括属性、成员函数的声明。

2.定义成员函数

1.使用作用域解析运算符 ::  来标识函数所属的类。

2.类方法可以访问类的private组件。

void Stock::update(double price)

新建一个cpp文件,在其中定义类的成员函数。

(内联方法:定义位于类声明中的函数都将自动成为内联函数。)

若是想让定义在外部的函数成为内联函数,要使用inline。

3.类的构造函数和析构函数

1.构造函数

Stock(const string & co, long n = 0, double pr = 0.0);

Stock::Stock(const string & co, long n = 0, double pr = 0.0)

{

company = co;

set_tot() }

程序声明对象时,将自动调用构造函数。

2.调用构造函数

(1)显式调用

Stock food = Stock(“World Cabbage”, 250, 1.25)

(2)隐式调用

Stock food(“World Cabbage”, 250, 1.25)

3.默认构造函数

默认构造函数是在未提供显式初始值时看,用来创建对象的构造函数。

Stock fluffy_the_cat;

当且仅当没有定义任何构造函数时,编译器才提供默认构造函数。如果提供了非默认构造函数,而没有提供默认构造函数,则上面的声明会出错。

Stock::Stock()

{ company = “”; … }

4.析构函数

~Stock();

Stock::~Stock(){}

5.列表初始化

Stock hot_tip = {“Derivatives Plus Plus”, 100, 45.0};

Stock jock {“Sport Age Storage, Inc”};

Stock temp {};

6.const成员函数

将const放在成员函数的后面,保证成员函数不会修改对象。

void show() const;

void stock::show() const;

4.this指针

const Stock & topval(const Stock & s) const

{

if (s.total_val > total_val)

return s;

else:

return ???? (*this)

}

this指针指向用来调用成员函数的对象。

5.对象数组

可以用构造函数来初始化数组元素:

const int STKS = 4;

Stock stocks[STKS] = {

Stock(“NanoSmart”, 12.5, 20),

Stock(“Boffo Objects”, 200, 2.0),

Stock(“Monolithic Obelisks”, 130, 3.25),

Stock(“Fleep Enterprises”, 60, 6.5)

}

可以对不同的元素调用不同的构造函数。要创建类对象数组,这个类必须有默认的构造函数。

6.类作用域

静态常量:

static const int Months = 12;

 

 

 

 

 

 

数据库完整性

1.完整性约束条件

实体完整性、参照完整性、用户定义完整性。

2.完整性检查

一般在INSERT,UPDATE,DELETE语句之后进行检查。

3.违约处理

若动作违背了完整性约束条件,则拒绝或者进行CASCADE级联处理。

4.实体完整性

在CREATE TABLE中用PRIMARY KEY定义。

5.实体完整性检查

1.检查主码值是否唯一。

2.检查主码的各个属性是否为空。有一个为空则拒绝。

6.参照完整性

在CREATE TABLE中用FOREIGN KEY定义哪些列为外码,用REFERENCE定义这些列参照哪些表的主码。

CREATE TABLE SC

(

Sno CHAR(9) NOT NULL,

Cno CHAR(4) NOT NULL,

FOREIGN KEY (Sno) REFERENCES Student(Sno),

FOREIGN KEY (Cno) REFERENCES Course(Cno)

)

7.参照完整性检查

被参照表(SC) 参照表(SC) 违约处理
可能破坏参照完整性 插入元组 拒绝
可能破坏参照完整性 修改外码值 拒绝
删除元组 可能破坏参照完整性 拒绝/级连删除/设置为空值
修改主码值 可能破坏参照完整性 拒绝/级连删除/设置为空值

1.拒绝执行

2.级连操作

3.设置为空值

对于参照完整性,除了应该定义外码,还应该定义外码是否能取空值。

显示说明违约执行:

CREATE TABLE SC

(

Sno CHAR(9) NOT NULL,

Cno CHAR(4) NOT NULL,

FOREIGN KEY (Sno) REFERENCES Student(Sno)

ON DELETE CASCADE

ON UPDATE CASCADE,

FOREIGN KEY (Cno) REFERENCES Course(Cno)

ON DELETE CASCADE

ON UPDATE CASCADE

);

8.用户定义完整性

1.属性上的约束定义

(1)NOT NULL

(2)UNIQUE  列值唯一

(3)检查列值是否满足布尔表达式(CHECK)

CREATE TABLE Student

(

Ssex CHAR(2) CHECK(Ssex IN (‘男’, ’女’)

)

2.属性上的约束条件检查和违约处理

插入或修改属性值时,不满足条件则拒绝执行。

3.元组上的约束定义

元组级的限制,可以设置不同属性之间的取值的相互约束条件。

CREATE TABLE Student

(

CHECK (Ssex = ‘女’ OR Sname NOT LIKE ‘Ms.%’)

)

当性别为男时,名字不能以Ms开头。

4.元组上的约束违约处理

插入或修改属性值时,不满足条件则拒绝执行。

9.完整性约束命名子句

CONSTRAINT <完整性约束条件名> [PRIMARY KEY 短语|FOREIGN KEY 短语|CHECK 短语]

CREATE TABLE Student

(

Sno NUMERIC(6)

CONSTRAINT C1 CHECK(Sno BETWEEN 90000 AND 99999

)

10.修改表中的完整性限制

删除C1约束:

ALTER TABLE Student

DROP CONSTRAINT C1;

修改C1约束,将学号限制变为900000-999999之间。

ALTER TABLE C1

DROP CONSTRAINT C1;

ALTER TABLE C1

ADD CONSTRAINT C1 CHECK (Sno BETWEEN 900000 AND 999999)

先删除,后加上。

11.域中的完整性限制

CREATE DOMAIN GenderDomain CHAR(2)

CHECK (VALUE IN (‘男’, ‘女’)

建立一个性别域,取值为男、女。

则可以对Ssex声明:

Ssex GenderDomain

建立一个性别域,并对其中的限制命名:

CREATE DOMAIN GenderDomain CHAR(2)

CONSTRIANT GD CHECK (VALUE IN (‘男’, ‘女’)

删除域上的限制条件:

ALTER DOMAIN GenderDomain

DROP CONSTRAINT GD;

增加域的限制条件:

ALTER DOMAIN GenderDomain

ADD CONSTRIANT GDD CHECK (VALUE IN (‘1’, ‘0’))

这样就把值限制在了0和1之间。

12.触发器

是用户定义在关系表上的一类由事件驱动的特殊过程。

1.定义触发器

CREATE TRIGGER <触发器名>

|BEFORE|AFTER|<触发事件> ON <表名>

FOR EACH |ROW |STATEMENT|

[WHEN <触发条件>]

<触发动作体>

触发事件:INSERT, DELETE, INSERT OR DELETE

UPDATE OF <触发列>

2.实例

定义一个BEFORE行级触发器,为教师表Teacher定义完整性规则,教授的工资若低于4000则改为4000.

CREATE TRIGGER Insert_Or_Update_Sal

BEFORE INSERT OR UPDATE ON Teacher

FOR EACH ROW

AS BEGIN

IF (new.Job = ‘教授’) AND (new.Sal < 4000) THEN

new.Sal:=4000;

END IF;

END;

3.激活触发器

(1)执行该表上的BEFORE触发器

(2)激活触发器的SQL语句

(3)执行该表上的ALTER触发器。

4.删除触发器

DROP TRIGGER <触发器名> ON <表名>

 

数据库安全性

1.计算机系统的三类安全性问题

1.技术安全

2.管理安全

3.政策法令

2.安全级别划分

安全级别 定义
A1 验证设计
B3 安全域
B2 结构化保护
B1 标记安全保护
C2 受控的存取保护
C1 自主安全保护
D 最小保护

3.用户标识和鉴别

1.用户标识

2.口令

4.自主存取控制方法

GRANT <权限>

ON <对象类型> <对象名>

TO <用户>

[WITH GRANT OPTION]  //如果使用这个选项,则被授予权限的还可以再授权
将  对指定操作对象的指定操作权限 授予用户。

grant select/all privileges/update(Sno)

on table Student

to U1;

REVOKE <权限>

ON <对象类型> <对象名>

FROM <用户名> [CASCADE|RESTRICT]

REVOKE UPDATE(Sno)

ON TABLE Student

FROM U4

5.创建数据库模式的权限

CREATE USER <username>

[WITH][DBA|RESOURCE|CONNECT];

CONNECT:只能连接数据库,没有权限。(默认)

RESOURCE:可以创建基本表和视图,成为所创建对象的属主。并可以将自己创建的对象的权限授予其他用户。

DBA:系统的超级用户,可以创建新的用户、创建模式、创建基本表和视图。

6.数据库角色

数据库角色就是一组被命名的与数据库操作相关的权限。

CREATE ROLE <角色名>

 

GRANT <权限>

ON <对象类型>

TO <角色>

 

GRANT <角色1>

TO <角色3>

[WITH ADMIN OPTION] //被授予的角色还可以将此权限继续授予其他角色

 

REVOKE <权限>

ON <对象类型>

FROM <角色>

7.强制存取控制方法

主体:系统中的活动实体。

客体:系统中的被动实体,是受主体操纵的,包括文件、基本表、索引、视图等。

对于主体和客体,DBMS为他们的每个实例指派一个敏感度标记。

主体:许可证级别。 客体:密级。

MAC就是通过对比主体和客体的label决定主体是否能存取客体。

(1)仅当主体的许可证级别大于等于客体的密级时才能读取相应的客体。

(2)仅当主体的许可证级别等于客体的密级时,才能写相应的客体。

8.审计

审计功能把用户对数据库的所有操作自动记录下来放入审计日志。

(用户审计:审计自己创建的表、视图。)

(系统级审计:只能由DBA设置)

9.数据加密

 

 

 

 

 

7.内存模型和名称空间

1.程序分为三部分:

1.头文件:包含结构声明和使用这些结构的函数的原型。

(函数原型、使用#define或const定义的符号常量、结构声明、类声明、模版声明、内联函数)

2.源代码文件:包含与结构有关的函数的代码。

3.源代码文件:包含调用与结构相关的函数的代码。

2.程序结构举例:

coordin.h

#ifndef COORDIN_H_

#define COORDIN

struct polar{};

struct rect{};

polar rect_to_polar();

void show_polar();

#endif

 

file1.cpp

#include <iostream>

#inlcude “coordin.h”

int main(){}

 

file2.cpp

file2.cpp

#include <iostream>

#inlcude “coordin.h”

implement of polar rect_to_polar();   void show_polar();

3.存储持续性、作用域和链接性

1.C++存储数据的方案

(1)自动存储持续性(函数定义中声明的变量)

(2)静态存储持续性(函数定义外的变量和static变量)

(3)线程存储持续性(变量使用thread_local)

(4)动态存储持续性(用new运算符分配的内存)

2.作用域和链接

函数中定义的变量可在该函数中使用,但不能在其他函数里面使用。(main函数包括在内)

链接性描述了名称如何在不同的单元间共享。

3.自动存储持续性

函数中的代码只在该函数中可见。大括号括起的代码块中的定义的变量只在大括号范围内可见,并且会覆盖外面的同名变量。
4.自动变量

程序对自动变量进行管理:留出一段内存称为栈。

5.寄存器变量

register int count_fast

旨在提高变量的访问速度。

6.静态持续变量

外部链接性:可以在其他文件中访问

代码块外面声明。

内部链接性:只能在本文件中访问

代码块外面声明,并使用static.

无链接性:只能在函数中或代码块中访问

代码块内部声明,使用static.

int global = 1000;

static int 0ne_file = 50;

int main()

{

static int count = 0;

}

7.5种变量存储方式

存储描述 持续性 作用域 链接性 如何声明
自动 自动 代码块 在代码块中
寄存器 自动 代码块 代码块中使用register
静态,无链接性 静态 代码块 代码块中使用static
静态,外部链接性 静态 文件 外部 不在任何函数中
静态,内部链接性 静态 文件 内部 不在任何函数中,使用static

8.静态变量初始化

(1)零初始化

(2)常量表达式初始化

(3)动态初始化

int x; int y = 5; long z = 12 * 12;

const double pi = 4.0*atan(1.0)

x被零初始化。y,z被静态初始化。pi由于要用到atan()函数,因此必须等到程序运行时才执行初始化。

9.外部变量(静态持续性,外部链接性)

定义一次(头文件或者函数外部)。使用时对其进行声明。

extern int blem.

在多个文件中使用时,只需要在一个文件中定义,在其他文件中用extern声明。

函数中的自动变量将隐藏外部变量。但是可以使用::(作用域解析运算符)来使用变量的全局版本。

10.文件内部变量(静态持续性,内部链接性)

链接性为内部的变量只能在其所属的文件中使用。

file1: int errors = 20 file2: static int errors = 30//valid

因为static指出标识符的链接性为内部。

11.局部持续性 变量(静态持续性, 无链接性)

将static限定符用于在代码块中创建的变量。

12.const

const类型的全部变量是内部的。(像static一样)

声明一个const变量,如果要在其他文件中使用它,则需要在定义(只有一个文件可以初始化它)时使用extern,其他文件中用extern来声明。

13.函数和链接性

所有函数的存储持续性都为自动的静态的。编译器通常使用三块内存:一块用于静态变量,一块用于自动变量,一块用于自动存储。

(1)使用new运算符初始化

int * pi = new int (6);

int * ar = new int [4] {2, 3, 5, 6};

int * pin = new int {5};

(2)new失败时

引发异常

(3)分配函数和释放函数

void * operator new(std::size_t);

void * operator new[](std::size_t)

void * operator delete(std::size_t);

void * operator delete[](std::size_t)

int * pi = new int —-> int * pi = new(sizeof(int))

int * pi = new int [40] —-> int * pi = new (40 * sizeof(int))

(4)定位new运算符

使用定位new特性,首先需要包含头文件new。

char buffer1[50]

char buffer2[500]

p2 = new (buffer1) chaff;

p4 = new (buffer2) int [20];

 

若是用定位运算符分配了其他存储区的内存,则不能用delete来释放。

4.名称空间

1.声明区域

可以在其中进行声明的区域。

2.潜在作用域

从声明点开始,到其声明区域的结尾。

3.名称空间

namespace Jack {

double pail; void fetch(); int pal;  struct Well {}

}

namespace Jill{

double bucket(double n) {…} double fetch;

int pal; struct Hill {…}

}

名称空间可以是全局的也可以位于另一个名称空间中,但不能位于代码块中。

名称空间是开放的。如Jack中提供了fetch()的原型,还可以再后面:

namespace Jack{

void fetch() {}

}

可以通过作用域解析运算符:Jack::pail来访问名称空间中的名称。

也可以使用using声明:using Jack::pail和using预编译指令:using namespace Jack。

using声明和using编译区别:

char fetch;

using Jack::fetch   //invalid

using namespace Jack //valid, fetch会覆盖外面的fetch.但是依然可以用::fetch来使得外面的变量可见。

一般来说,使用using声明更加安全。

4.嵌套名称空间

namespace element

{

namespace fire

{

int flame;…

}

}

using namespace element::fire

起别名:

namespace m = element::fire

5.未命名的名称空间

namespace

{

int ice;

int bandycoot;

}

相当于后面直接跟着一个using,等于链接性为内部的静态变量的代替品。

6.名称空间及其用途

1.使用在已命名的名称空间中声明的变量,而不是使用外部全局变量。

2.使用在已命名的名称空间中声明的变量,而不是使用静态全局变量。

3.开发的类放入名称空间中。

4.不要在头文件中使用using编译指令。

类的继承

1.类的继承

1.可使用super语句调用父类的构造方法。

2.使用super关键字调用父类的成员方法。(子类没有权限调用父类中private方法)

3.重写父类中的方法。

4.重构父类中的方法:方法名、参数类型、返回类型都一样。只有实现内容不同。

5.重写父类方法时,修改方法的权限只能从小变大。

6.重写父类方法时,可以修改方法的返回值类型。(重写的返回值类型必须是父类中同一方法返回值类型的子类。)

7.实例化子类之前要先实例化父类对象。

public class test {

public test(){

}

protected void doSomething() {

}

protected test dolt() {

return new test();

}

}

class test2 extends test{

public test2() {

super(); //调用父类构造方法

super.doSomething(); //调用父类成员方法

}

public void doSomethingnew() { //新增方法

}

public void doSomething() { //重写父类方法

}

protected test2 dolt() { //重写父类方法。

return new test2();

}

}

2.Object类

Java中所有的类都继承自java.lang.Object类,除非显示地指定了其他继承关系。

1.getClass()方法

getClass().getname();

2.toString()方法

将对象返回为字符串形式。

3.equals()方法

equals方法默认实现比较两个对象的引用地址,而不是对象的内容。

3.对象类型的转换

1.向上转型

class Second{

public static void draw(Second p) {

}

}

public class First extends Second{

public static void main(String[] args) {

First p = new First();

draw(p);

}

}

draw方法定义在Second类中,此处将First对象转化为Second对象来调用draw.

2.向下转型:将较抽象的类转化为具体的类

不能直接赋值,必须通过强制类型转换。

Second S = new Second();

First F = (First) S;

4.使用instanceof判断对象类型

使用方法:object instanceof ExampleClass.

Second p = new Second();

System.out.println(p instanceof First);

输出false.

5.方法重载

public class OverLoadTest {

public static int add(int a, int b) {

return a+b;

}

public static double add(double a, double b) {

return a+b;

}

public static int add(int a, double b) {

return 1;

}

public static int add(double a, int b) {

return 1;

}

}

构造方法重载:函数名相同,返回值相同,但是参数不同。(类型、顺序、个数)

6.多态

父类中定义一个方法,子类的不同实例均可以调用。

7.抽象类与接口

1.抽象类

一般将父类设置为抽象类。

public abstract class test2 {

abstract void testAbstract();

}

抽象类除了被继承之外,没有任何意义。只要类中有一个抽象方法,就要将这个类定义为抽象类。

但是如果是图形类来继承,父类中有一个draw()方法,子类有一些并不需要此方法,如果都继承父类,那么每个子类都需要去实现抽象方法,造成代码冗余。

2.接口

抽象类的延伸,看作纯粹的抽象类。

public interface drawTest{

void draw();

}

一个类实现一个接口:

public class Parallelogram extedns Quadrangle implements drawTest{

}

接口中定义的方法必须是public或者abstract形式。

6.函数探幽

1.内联函数

常规函数和内联函数的区别在于编译器如何将它组织到程序中。在执行到调用函数时,以往的做法是跳到函数所在的内存区域,执行完之后再调回标记好的调用函数处。

内联函数将函数代码与调用“内联”起来了。因此,程序无须跳转到另一个位置执行代码再跳回来。

代价是占用内存。例:如果程序需要在十个不同的地方调用同一个内联函数,则需存储此函数十次。

要使用内联函数,要在函数声明和定义之前都加上inline.

inline double square(double x)

{

return x * x;

}

int main() {

 

double a = square(4.0);

double b = square(5.0);

cout << a << “\t” << b << endl;

}

2.引用变量

int rats;

int & rodents = rats;

必须在声明时将引用初始化,不能像指针那样先声明再赋值。

1.将引用作为函数参数

int main() {

void swap(int & a, int & b);

int a = 2;

int b = 3;

swap(a, b);

cout << a << “\t” << b << endl;

}

 

void swap(int & a, int & b)

{

int t = a;

a = b;

b = t;

}

2.将引用作为函数参数(左值引用)

如果函数声明中将引用变量声明为const,则在调用函数时传递的实参跟形参的类型不匹配时,会生成临时变量,让形参的引用指向这个临时变量。可以处理不同类型的数据。

将引用参数声明为常量数据的引用的理由:

(1)使用const可以避免无意间修改数据。

(2)使用const能处理const和非const实参,否则只能接受非const.

(3)使用const引用使函数能正确生成并使用临时变量。

3.将引用用于结构

如果有如下结构struct free_throws

则可以声明:void display(const free_throws & ft);

返回引用:返回的是变量。返回值:返回的是常量。

注意:若在程序中定义了临时变量并创建了引用,由于返回时这个临时变量会消失。因此引用也会失效。(避免这种做法,最简单的方法是返回一个作为参数传递给函数的引用。)(或者可以使用new来分配存储空间,返回对这个变量的引用。)

4.将引用用于类对象

string实现了将char * 转换为string。

继承的另一个特性是,基类引用可以指向派生类对象。

3.默认参数

当函数调用中省略了实参时自动使用的一个值。

char * left(const char * str, int n = 1);

注意:只有原型指定了默认值。函数定义与没有默认参数时完全相同。指定默认值时从右往左。

在赋予字符串时,可以用strlen()来确定字符串的长度。因为strlen()从当前指针开始找,一直找到空字符为止。

4.函数重载

函数多态允许使用同一个函数名调用不同的函数。

重载函数的关键是参数列表:也即函数特征标。

如果在调用函数时,编译器不能区分该使用哪个函数,则会指出错误。

void print(const char * str, int width)  //1

void print(double d, int width) //2

void print(long l, int width); //3

print(2, 6)//这个调用无法执行,因为编译器无法判断要使用2还是3.

double cube(double x);

double cube(double & x);

cout << cube(x) //无法判断。因此编译器会将引用和变量视作同样的东西。

void dribble(char * bits);

void dribble(const char * cbits); //这是重载

注意:是特征标,而不是函数类型使得函数重载。因此,只有返回类型不同时,不是重载。

C++如何跟踪每一个重载函数?

名称修饰。编译程序时,C++编译器将根据函数原型中指定的形参类型对每个函数名进行加密。

5.函数模版

1.使用泛型来定义函数。

template <typename AnyType>

void Swap(AnyType &a, AnyType &b)

{

AnyType = temp;

temp = a;

a = b;

b = temp;

}

模版并不创建任何函数,而只是告诉编译器如何定义函数。

2.重载模版

重载的模版特征标必须不同。

template <typename AnyType>

void Swap(AnyType &a, AnyType &b);

重载:

template<typename AnyType>

void Swap(AnyType & a, AnyType & b, int n);

3.显式具体化

用于交换job结构的非模版函数、模版函数与具体化原型。

void Swap(job &, job &);

 

template <typename T>

void Swap(T &, T &);

 

template <> void Swap<job>(job &, job&);

//基于job类型的显式具体化版本

4.实例化和具体化。

在函数中包含模版并不会生成函数,它只是指出了生成函数的方法。编译器使用模版生成函数时,得到函数实例。

可以利用显式实例化直接命令编译器创建特定的实例。

还可通过在程序中使用函数来创建显式实例。

隐式实例化、显式实例化、显式具体化统称为具体化。

隐式实例化:

template<typename T>

void swap(T &a, T &b);

显式实例化:

template void swap<int>(int, int)

直接命令编译器去创建特定的实例。

显式具体化:

template <> void swap<int>(int, int)

不要使用swap模版来生成函数定义。显式实例化和显式具体化必须有自己的原型。

5.编译器要使用哪个函数版本:

(1)完全匹配。但是常规函数优先于模板。

(2)提升转换。小升大。

(3)标准转换。

(4)用户定义的转换。

简而言之,使用最具体的函数。

6.多个参数的函数

template<class T1, class T2>

void ft(T1 x, T2 y)

{

?type? xpy = x + y;

}

可以用decltype.

decltype(x) y.

将y定义成x的类型。

因此可以decltype(x+y) xpy.

若是不知道函数的返回类型:

auto h(T1 x, T2 y) ->decltype(x+y)

{

x+y

}

 

5.函数

1.无返回值

void FunctionName(parameterList)

{

statements;

return;

}

2.有返回值的函数(返回值不能是数组)

typeName FunctionName(parameterList)

{

statements;

return;

}

函数通过将返回值复制到指定的CPU寄存器或内存单元将其返回。

3.函数原型

typeName FunctionName(parameterList);

将返回类型、参数类型和数量都告诉编译器。(原型不要求使用变量名,有类型就足够了。)

若是括号为空,则说明没有参数。若有参数但不想指定,则需要写(…)

若是传递给它的参数类型不匹配,函数自动将参数强制转换为需要的类型。

4.函数参数

double cube(double x)

double volume = cube(side)

此处被调用时,函数会定义一个临时变量x来保存side的值。

5.函数和数组

int sum_arr(int arr[], int n)

int sum_arr(int * arr, int n)

对数组名用sizeof时,返回的是整个数组的所有元素的长度。但是传入函数后,对arr使用sizeof,返回单个指针的长度。

arr[i] == *(arr+i)

&arr[i] == arr + i

由于传递数组时,传递了原数据的保存位置。因此可以用const来保护数据。

void show_array(const double ar[], int n)

表明ar指向的是常量数据,意味着不能通过ar修改数据。

int * a = ar; 报错:const int *类型的值不能用于初始化int *

传递数组还可以使用两个指针来标明数组的开头和结尾。

int sum_arr(const int * begin, const int * end);

(超尾的概念。后面的指针指向数组的最后一个元素的后一个位置。)

6.指针和const

(1)将指针指向一个常量对象。这样禁止指针修改所指向的值。

int age = 39;

(const int *) pt = &age;

这里表明pt指向的是const int值。

之前将常规变量的地址赋给常规指针。

这里将常规变量的地址赋给const指针

那么,可以将const值赋给const指针。

但是!!!不可以将const值赋给常规指针。

(2)将指针本身声明为const, 这样可以防止改变指针指向的位置。

int sloth = 3;

const int * ps = &sloth;

(int * )const finger = &sloth;

finger不能指向其他位置,但是可以通过*finger来改变sloth的值了。

7.函数和二维数组

int data[3][4] = {}

int total = sum(data, 3)

正确的函数原型:

int sum( int (*ar2)[4], int size);

其中括号必不可少。声明ar2是一个指向(包含了四个元素的数组)的指针。

另一种格式:

int sum(int ar2[][4], int size);

8.函数和C风格字符串

字符串函数原型应该将字符串的形参声明为char*类型。

处理字符串中字符的标准方式:

while (*str)

{

statements;

str++;

}

返回字符串的函数:

char * buildstr(char c, int n);

9.函数和结构

由于有些结构较大,若是按值传递,则会增加内存需求,降低运行速度。因此倾向于利用指针。

struct travel_time

{

int hours;

int mins;

}

travel_time sum(travel_time t1, travel_time t2);

传递结构的地址:

voidshow_polar(constpolar* 捧逗啊);

10.函数和string对象

string对象和结构的用法更相似。

11.函数与array对象

void show(aarray<double, 4> da);

void fill(array<double ,4> * pa);

12.递归

int main() {

void countdown(int);

countdown(4);

return 0;

}

 

void countdown(int n)

{

cout << n << ” ” << &n << endl;;

if (n > 0)

{

countdown(n – 1);

}

cout << n << ” ” << &n << endl;

}

13.函数指针

与数据项一样,函数也有地址。函数的地址是存储其机器语言代码的内存开始地址。

1.获取函数地址

直接使用函数名即可。

process(think);

2.声明函数指针

double pam(int);

double (*pf)(int); //指向上面那个函数原型的指针。

通常,要声明某种类型的函数的指针,可以首先编写函数原型,然后用(*pt)替换函数名。

pf = pam;

3.使用指针来调用函数

double pam(int);

double (*pf)(int);

pf = pam;

double x = pam(4);

double y = (*pf)(4);

double y = pf(4)//也可以这样用。

复杂化的函数指针:

const double * f1(const double ar[], int n);

const double * f2(const double [], int);

const double * f3(cosnt double *, int);

若要声明指向这三个函数中某一个的指针:

const double * (*pt)(const double ar[], int n);

若要声明指向这三个函数所组成的一个数组:

const double * (*pa[3])(const double *, int ) = {f1, f2, f3}

*pa[3]说明pa是一个包含三个指针的数组。其他部分指出数组包含的元素是什么样子的。

创建指向整个数组的指针:

auto pb = &pa;(auto只能声明单个变量)

(若是需要自己声明:

首先(*pd)[3]表明pd指向一个包含三个元素的数组。这些元素是什么呢?

const double *  (*(*pd)[3]) (const double *, int) = &pa;

(说明:int *pa[3]创建一个数组,这个数组里面的3个元素都是指向int的指针。此处外面的函数声明反而变成了类型。

int (*pd)[3]创建一个指针,这个指针指向一个包含3个int元素的数组。

int a = 2;

int b = 3;

int c = 3;

int * p1 = &a;

int * p2 = &b;

int * p3 = &c;

int * pa[3] = { p1, p2, p3 };

int * (*pd)[3];

pd = &pa;

cout << *((*pd)[1]);

这里int * (*pd)[3]一句,表明pd是一个指向一个数组(包含3个元素)。前面int *表明数组里面的元素是int *类型的。

注意:在声明指针时,前面基本类型声明说的都是里面的元素。

可以使用typedef进行简化。

typedef const double *(*p_fun)(const double *, int);

此时,p_fun位函数指针类型的别名。

p_fun p1 = f1;

 

 

4.分支语句和逻辑语句

1.if语句

if (test-condition) test-condition会被强制转为bool

statement

if (test-conditon)

statement1

else

statement2

可嵌套。

2.条件运算符和错误防范

if (variable == value)

if (value == variable)

3.逻辑表达式

||   &&   !

逻辑运算符是个顺序点。也就是说先修改左侧的值,再对右侧的进行判定。

i++ < 6 || i == j

先进行i<6判断,然后将i加1。这时若比较运算为真,则结束语句,因为或逻辑运算有一边为真时,即可判断为真。

&&也是一个顺序点。

i++ < 6 && i == j

在进行右边的判定之前,i已经加1了。并且若是左边判断为假,右边的表达式不进行判定。

(取值范围测试)

if (17 < age < 35)从左到右进行结合。先算17<age,无论是true或者false,值都为1或者0。然后计算是否小于35,结果永远为true.

!优先级高于所有的关系运算符和算术运算符。因此如果要对表达式求反,必须要加括号。

!x > 5 表达式一定是false.因为!x先计算,一定为0或者1.

4.字符函数库cctype

函数名称 返回值
isalnum() 是否是字母或者数字。
isalpha() 是否是字母
iscntrl() 是否是控制字符
isdigit() 是否是数字
isgraph() 除了空格之外的打印字符
islower() 小写字母
isprint() 打印字符(包括空格)
ispunct() 标点符号
isspace() 标准空格字符:空格、换行、回车、水平制表符、垂直制表符
isupper() 大写字母
isxdigit() 十六进制数字
tolower() 若为大写字母则转为小写。否则返回参数。
toupper() 若为小写字母则转为大写。否则返回参数。

5.?:运算符

expression1 ? expression2 : expression3

1为true,则执行2.否则执行3.

6.switch语句

switch (integer-expression)

{

case label1 : statement(s)

case label2 : statement(s)

default  :   statement(s)

}

integer-expression必须是一个结果为整数的表达式。每个标签都必须是一个整数常量表达式。

const int a = 0;

const int b = 1;

const int c = 2;

int d;

cin >> d;

switch (d)

{

case a: cout << “a” << endl;

case b: cout << “b” << endl;

case c: cout << “c” << endl;

}

注意:标签必须是常量,或者是枚举类型。

如果要让程序在执行完某个case之后停止,必须使用break停止。可以利用这个特性,让其执行一部分语句。

switch(choice)

{

case ‘a’:

case ‘A’: cout << “a “; break;

}

利用枚举量进行判断:

switch(code)

{

case red:

case orange:

}

判断时会将枚举量提升为int型。但是输入code时必须输入整数。

7.break和continue语句

8.错误处理

判断输入是否正确。如果需要数字的地方,输入了字符,则cin返回false, 且不会将任何值放入。 这时必须用cin.clear()进行清理。具体参见P189页。

while (!(cin >> golf[i]))

{

cin.clear();

while (cin.get() != ‘\n’)

continue;

cout << “please enter a number”;

}

9.简单文件输入、输出

1.文本I/O

char ch;  cin >> ch;

输入:38.5

ch中存储了3的ASCII编码。剩下的8.5都留在输入队列中,由下一个输入去接收。

int n; cin >> n;

cin将不断读取,直到遇到非数字字符。

double x; cin >> x;

cin将不断读取,直到遇到第一个不属于浮点数的字符。

char word[50]; cin >> word;

这种情况下,cin将不断读取,直到遇到空白字符。

char word[50]; cin.getline(word, 50);

cin不断读取,直到遇到换行符。在末尾加一个空字符。

2.写入到文本文件中

包含fstream头文件(与cout用法基本一致,只是需要先与文件进行关联)

ofstream outFile;

outFile.open(“fish.txt”);

open()接收一个C-风格的参数。可以是字符串常量,也可以是存储了文件名的字符串变量。将outFile对象将此文件关联起来。

outFile << “a”;

3.读取文本文件

包含fstream头文件

ifstream inFile;

inFile.open(“fish.txt”);

ifstream.close()

同上ofstream.

检查文件是否打开:

if (!inFile.is_open())

{

exit(EXIT_FAILURE); //exit定义在头文件cstdlib中。

}

循环读入其中的数据:

inFile >> value;

while (inFile.good())

{

++count;

sum += value;

inFile >> value;

}

inFile.eof()    //到达文件尾

inFile.fail() //读取失败

在文件目录下建立fish.txt文件,内容为 123 321 abc.

ifstream InFile;

InFile.open(“fish.txt”);

if (InFile.is_open())

{

cout << “open success” << endl;

}

int ch;

InFile >> ch;

while (InFile.good())

{

cout << ch;

InFile >> ch;

}

cout << endl;

if (InFile.eof())

{

cout << “end”;

}

else if (InFile.fail())

{

cout << “error type”;

}

else

{

cout << “other reasons”;

}

SQL语句概览

1.模式的定义与删除

1.Create Schema <模式名> Authorization <用户名>

模式是数据库中全体数据的逻辑结构和特征的描述。是数据库用户的数据视图。是与某一应用有关的数据的逻辑表示。

2.Drop Schema <模式名> <CASCADE | RESTRICT>

CASCADE表示删除模式时,把该模式中的所有数据库对象一起删除。

RESTRICT表示如果该模式中已经定义了下属的数据库对象(表、视图),则拒绝执行。

3.建立一个ST 模式

create schema ST

2.基本表的定义

Create Table <表名>  (

<列名> <数据类型> [列级完整性约束条件],

<列名> <数据类型> [列级完整性约束条件],

<列名> <数据类型> [列级完整性约束条件],

<列名> <数据类型> [列级完整性约束条件],

[表级完整性约束条件] );

1.建立一个学生表

create table Student

(Sno char(9) primary key,

Sname char(20) unique,

Ssex char(2),

Sage smallint,

Sdept char(20)

)

2.建立一个课程表

CREATE TABLE Course (

Cno CHAR(4) PRIMARY KEY,

Cname CHAR(40),

Cpno CHAR(4),

Ccredit SMALLINT,

FOREIGN KEY (Cpno)

REFERENCES Course (Cno)

);

3.建立学生-选课表

CREATE TABLE SC (

Sno CHAR(9),

Cno CHAR(4),

Grade SMALLINT,

PRIMARY KEY (Sno , Cno),

FOREIGN KEY (Sno)

REFERENCES Student (Sno),

FOREIGN KEY (Cno)

REFERENCES Course (Cno)

);

3.数据类型

定义表的各个属性时,需要指明其数据类型及长度。

数据类型 含义
char(n) 长度为n的定长字符串
varchar(n) 最大长度为n的变长字符串
int 长整数
smallint 短整数
numeric(p, d) 定点数,p位数字小数点后d位
real 取决于机器精度的浮点数
double precision 取决于机器精度的双精度数
float(n) 浮点数,精度至少位n位
date 日期,YYYY-MM-DD
time 时间按,HH:MM:SS

4.模式与表

定义基本表时定义它所属的模式。

1.在表名中显式给出模式名:

create table ST.Course (….);

2.在创建模式语句的时候直接创建表。

3.设置所属的模式。

如果用户创建基本表时没有指定模式,系统根据搜索路径来确定该对象所属的模式。搜索路径包含一组模式列表,RDBMS会使用模式列表中第一个存在的模式作为数据库对象的模式名。

5.修改基本表

alter table <表名>

[add <新列名> <数据类型>  [完整性约束]]

[drop [完整性约束名]]

[alter column <列名> <数据类型>]

例子:

1.alter table Student add S_entrance Date;

2.alter table Student alter column Sage int;

3.alter table Course add unique(Cname);

6.删除基本表

drop table <表名> [Restrict | Cascade];

restrict: 不能被其他表的约束引用,不能有视图,不能有触发器,不能有存储过程或函数等。

cascade:相关依赖一起删除。

缺省情况为restrict.

7.建立索引

create [unique] [cluster] index <索引名>

on <表名> (

<列名> [<次序>],

<列名> [<次序>]);

次序表示ASC或DESC。

unique表明此索引的每一个索引值只对应唯一的数据记录。

cluster表示要建立聚簇索引。

create cluster index Stusname on Student(Sname);

8.删除索引

drop index <索引名>

9.数据查询

seletc [all | distinct] <目标列表达式>…

from <表名或者视图名> …

[ where <条件表达式> ]

[group by <列名1> [having <条件表达式>]

[order by <列名2> [ASC | DESC]

有group by时,结果将按照列名1进行分组,该属性列值相等的元组为一个组。

有order by时,还需要按照列名2进行排序。

1.查询指定列

SELECT

Sno, Sname

FROM

Student;

2.查询全部列

SELECT

*

FROM

Student;

3.查询经过计算的值(目标列表达式不仅可以是算术表达式,还可以是字符串常量、函数等)

SELECT

Sname, 2004-Sage

FROM

Student;

SELECT

Sname, ‘Year of Birth:’, 2004 – Sage, LOWER(Sdept)

FROM

Student;

还可以指定查询出来的列的别名。

SELECT

Sname, ‘Year of Birth:’ BIRTH, 2004 – Sage BIRTHDAY, LOWER(Sdept) DEPARTMENT

FROM

Student;

4.消除取值重复的行

SELECT DISTINCT

Sno

FROM

SC;

5.查询满足条件的元祖

查询条件 谓词
比较 =, >, <, >=, <=, !=, <>, !>, !<;Not+以上比较符
确定范围 between and, not between and
确定集合 in, not in
字符匹配 like, not like
空值 is null, is not null
多重条件 and, or, not

(1)比较大小

[1] =

SELECT

Sname

FROM

Student

WHERE

Sdept = ‘CS’

[2] <

SELECT

Sname, Sage

FROM

Student

WHERE

Sage < 20;

(2)确定范围

[1] between and

SELECT

Sname, Sdept, Sage

FROM

Student

WHERE

Sage BETWEEN 20 AND 23;

(3)确定集合

SELECT

Sname, Ssex

FROM

Student

WHERE

Sdept IN (‘CS’ , ‘MA’, ‘IS’)

(4)字符匹配

LIKE <匹配串> [ESCAPE <换码字符>]

%:代表任意长度的字符串

_:代表任意单个字符

SELECT

*

FROM

Student

WHERE

Sno LIKE ‘200215121’

 

SELECT

*

FROM

Student

WHERE

Sname LIKE ‘刘%’

一个汉字需要两个_。

如果要匹配的字符串里面有%或者_,则需要进行换码。

SELECT

Cno, Ccredit

FROM

Course

WHERE

Cname LIKE ‘DB/_Design’ ESCAPE ‘/’;

其中’/’之后的字符就是正常字符,而不是通配符了。

(5)空值查询

SELECT

Sno, Cno

FROM

SC

WHERE

Grade IS (NOT) NULL;

(6)多重条件查询

SELECT

Sname

FROM

Student

WHERE

Sdept = ‘CS’ AND Sage < 20

5.order by子句

SELECT

Sno, Grade

FROM

SC

WHERE

Cno = ‘3’

ORDER BY Grade DESC

6.聚集函数

函数名 作用
COUNT([DISTINCT|ALL] *) 统计元组个数
COUNT([DISTINCT|ALL]列名] 统计一列中值的个数
SUM 计算一列值的总和
AVG 计算一列值的平均值
MAX 计算一列值的最大值
MIN 计算一列值的最小值

SELECT

COUNT(*)

FROM

Student

 

SELECT

COUNT(DISTINCT Sno)

FROM

SC

 

SELECT

AVG(Grade)

FROM

SC

WHERE

Cno = ‘1’

 

SELECT

MAX(Grade)

FROM

SC

WHERE

Cno = ‘1’

在聚集函数遇到空值时,除了COUNT(*)之外,都跳过空值而处理非空值。

7.Group By子句

SELECT

Cno, COUNT(Sno)

FROM

SC

GROUP BY Cno

对每一组进行聚集函数COUNT计算,求得该组学生的人数。可以使用HAVING短语指定筛选条件。

SELECT

Sno

FROM

SC

GROUP BY Sno

HAVING COUNT(*) >= 2

这里先用group by子句按Sno分组,然后用COUNT对每一组进行计数,HAVING短语给出了选择组的条件。

WHERE子句用于基本表或者视图,从中选出满足条件的元祖。而HAVING短语作用于组,从中选出满足条件的组。

6.连接查询

对于几个表的查询。包括等值连接查询、自然连接查询、非等值连接查询、自身连接查询、外连接查询和复合条件连接查询等。

(1)等值与非等值连接查询

SELECT

Student.*, SC.*

FROM

Student,

SC

WHERE

Student.Sno = SC.Sno

若等号为其他比较运算符,则为非等值连接。

若在等值连接中把目标列中的重复值去掉则为自然连接。

SELECT

Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade

FROM

Student,

SC

WHERE

Student.Sno = SC.Sno

(2)自身连接

SELECT

FIRST.Cno, SECOND.Cpno

FROM

Course FIRST,

Course SECOND

WHERE

FIRST.Cpno = SECOND.Cno

找到先修课的先修课

(3)外连接

SELECT

Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade

FROM

Student

LEFT JOIN

SC ON (Student.Sno = SC.Sno);

左外连接列出左边关系,右外连接列出右边关系。

(4)复合条件连接

SELECT

Student.Sno, Sname

FROM

Student,

SC

WHERE

Student.Sno = SC.Sno AND SC.Cno = ‘2’

AND SC.Grade > 80;

查询选修2号课程且成绩在90分以上的学生。

多表查询:找出每个学生的学号、姓名、选修的课程名及成绩

SELECT

Student.Sno, Sname, Cname, Grade

FROM

Student,

Course,

SC

WHERE

Student.Sno = SC.Sno

AND SC.Cno = Course.Cno

7.嵌套查询

一个select from where称作一个查询块。将一个查询块嵌套在另一个查询块里,称作嵌套查询。父查询、子查询。注意子查询中不能使用order by语句。order by只能对最终结果排序。

(1)带有IN谓词的子查询

SELECT

Sno, Sname, Sdept

FROM

Student

WHERE

Sdept IN (SELECT

Sdept

FROM

Student

WHERE

Sname = ‘刘晨’)

查询选修了课程名为“信息系统”的学生学号和姓名。

SELECT

Sno, Sname

FROM

Student

WHERE

Sno IN (SELECT

Sno

FROM

SC

WHERE

Cno IN (SELECT

Cno

FROM

Course

WHERE

Cname = ‘信息系统’))

此查询用连接查询实现。。

SELECT

Student.Sno, Sname

FROM

Student, SC, Course

WHERE

Student.Sno = SC.Sno

AND SC.Cno = Course.Cno

AND Course.Cname = ‘信息系统’

(2)带有比较运算符的子查询

SELECT

Sno, Sname, Sdept

FROM

Student

WHERE

Sdept = (SELECT

Sdept

FROM

Student

WHERE

Sname = ‘刘晨’)

找出每个学生超过他平均成绩的课程号(相关子查询)

SELECT

Cno

FROM

SC x

WHERE

Grade >= (SELECT

AVG(Grade)

FROM

SC y

WHERE

x.Sno = y.Sno)

(3)带有ANY(SOME)或ALL谓词的子查询

子查询返回单值时可以用比较运算符,但返回多值时要用ANY或ALL谓词修饰符。

> ANY, < ANY, > ALL, < ALL, != ANY, !=ALL

查询其他系中比计算机科学系某一学生年龄小的学生姓名和年龄。

SELECT

Sname, Sage

FROM

Student x

WHERE

Sdept != ‘CS’ AND Sage < ANY (SELECT

Sage

FROM

Student

WHERE

Sdept = ‘CS’)

查询其他系中比计算机科学系所有学生年龄都小的学生年龄和姓名。

SELECT

Sname, Sage

FROM

Student x

WHERE

Sdept != ‘CS’ AND Sage < ALL (SELECT

Sage

FROM

Student

WHERE

Sdept = ‘CS’)

(4)带有EXISTS谓词的子查询

代表存在量词,不返回任何数据,只产生逻辑真或者假。

查询所有选修了一号课程的学生姓名。

SELECT

Sname

FROM

Student

WHERE

EXISTS( SELECT

*

FROM

SC

WHERE

Sno = Student.Sno AND Cno = ‘1’)

在Student表中依次取Sno值去SC表中检查,若存在这样的元组,其Sno值等于此Student.Sno值,并且其Cno=‘1’,则取于此对应的Student.Sname送入结果表。

查询选修了全部课程的学生姓名。

SELECT

Sname

FROM

Student

WHERE

NOT EXISTS( SELECT

*

FROM

Course

WHERE

NOT EXISTS( SELECT

*

FROM

SC

WHERE

Sno = Student.Sno AND Cno = Course.Cno))、

查询至少选修了学生200215122选修的全部课程的学生号码

SELECT DISTINCT

Sno

FROM

SC SCX

WHERE

NOT EXISTS( SELECT

*

FROM

SC SCY

WHERE

SCY.Sno = ‘200215122’

AND NOT EXISTS(

SELECT

*

FROM

SC SCZ

WHERE

SCZ.SNo = SCX.SNo AND SCZ.Cno = SCY.Cno))

8.集合查询

并集:UNION

SELECT

*

FROM

Student

WHERE

Sdept = ‘CS’

UNION SELECT

*

FROM

Student

WHERE

Sage <= 19;

9.SELECT语句的一般格式

P114页

10.数据更新

1.插入数据

insert into <表名> [(<属性列1> <属性列2>)

values (<常量1>, <常量2>)

into子句中没有出现的属性列新元组在这些列上去空值。没有指明属性列时,插入的新元组在每个列上都要有值。

插入子查询结果:

insert into Dept_age(Sdept, Avg_age)

select Sdept, avg(Sage)

from Student

group by Sdept;

2.修改数据

update <表名>

set <列名>=<表达式>  ..

where <条件>

(1)修改一个元组的值

将学生200215121的年龄改为22岁。

UPDATE Student

SET

Sage = 22

WHERE

Sno = ‘200215121’

(2)修改多个元组的值

将所有学生年龄增加一岁。

UPDATE Student

SET

Sage = Sage + 1

(3)带子查询的修改语句

将计算机科学系全体学生成绩清零。

UPDATE SC

SET

Grade = 0

WHERE

‘CS’ = (SELECT

Sdept

FROM

Student

WHERE

Student.Sno = SC.Sno)

3.删除数据

delete

from <表名>

where [条件]

(1)删除一个元组的值

DELETE FROM Student

WHERE

Sno = ‘200215128’

(2)删除多个元组的值

delete

*

FROM

SC;

(3)带子查询的删除语句

删除计算机科学系所有学生的选课记录

delete

from SC

where ‘CS’ =

(select Sdept

from Student

where Student.Sno=SC.Sno);

11.视图

视图就像一个窗口,只是一个定义,规定从哪个表里面取什么数据。当基本表里面的数据发生改变时,视图也发生变化。

1.建立视图

create view <视图名> [<列名>, <列名>]

AS <子查询>

其中,子查询可以是任意的select语句,但是不能时order by和distinct短语。组成视图的属性列名或者全部省略,或者全部指定,没有第三种选择。如果省略,则隐含该视图由子查询中select子句目标列中的诸字段组成。

CREATE VIEW IS_Student AS

SELECT

Sno, Sname, Sage

FROM

StudentIS_Student

WHERE

Sdept = ‘IS’

如果加上with check option.则之后进行修改和插入、删除操作时,必须保证依然只有信息系的学生。

建立信息系选修了1号课程的学生的视图。视图可以建立在多个基本表上。

CREATE VIEW IS_S1 (Sno , Sname , Grade) AS

SELECT

Student.Sno, Sname, Grade

FROM

Student,

SC

WHERE

Sdept = ‘IS’ AND Student.Sno = SC.Sno

AND SC.Cno = ‘1’

也可以将视图定义在另一个视图上。

create view IS_S2

as

select Sno, Sname, Grade

from IS_S1

where Grade >= 90

视图可以带表达式。

create view B…

as

select Sno, Sname, 2004-Sage

where …

还可以用带有聚集函数和group by子句的查询来定义视图。

将学生的学号和他的平均成绩定义为一个视图。

create view S_G(Sno, Gavg)

as

select Sno, AVG(Grade)

from SC

group by Sno

2.删除视图

drop view <视图名> [cascade]

将定义在此视图上的其他视图一并删除。

3.查询视图

在信息系学生的视图中找出年龄小于20的学生。

select Sno, Sage

from IS_Student

where Sage<20

这里的查询相当于转化为基本表里面的查询。

相当于:

select Sno, Sage

from Student

where Sdept=’IS’ and Sage < 20.

但是有些查询是不能进行转换的, where 子句判断时不能使用聚集函数进行判断。转换为group by … having <条件>即可。

4.更新视图

将信息系学生视图中学号200215125的学生姓名改为“刘辰”

update IS_Student

set Sname=’刘辰’

where Sno=’200215125′

为了防止用户通过视图对数据进行增加、删除、修改时,对不同视图内的基本表进行操作,可在定义时加上with check option。

向信息系学生视图中插入一条记录:

insert

into IS_Student

values(‘200215129’, ‘赵新’, 20);

转换为对基本表的更新:

insert

into Student(Sno, Sname, Sage, Sdept)

values(‘200215129’, ‘赵新’, 20, ‘IS’);

一般来说,只有行列子集视图可以更新。

5.视图的作用

(1)视图能够简化用户的操作。

(2)视图使用户能以多种角度看待统一数据。

(3)视图对重构数据库提供了一定程度的逻辑独立性。

(4)视图可以对机密数据提供安全保护。

(5)适当的利用视图可以更清晰地表达查询。