create table Employee(数据库
id int primary key,express
name char(20),数据库设计
birthday Date,ide
address varchar(30),性能
city varchar(10),设计
sex char(2),索引
salary numeric(10,2),ip
dno int,ci
pno int字符串
unique(name,birthday)
);
create table Employee(
id int,
name char(20),
birthday Date,
address varchar(30),
city varchar(10),
sex char(2),
salary numeric(10,2),
dno int Reference Department(deNumber),//外键约束
pno int
unique(name,birthday)//候选键
primary key(id)//员工表的主键
);
外部键约束增长了关系数据库表的关联完整性,能够较好的保证数据库表之间的关联完整性。主键所在的表成为父表,为主控方,对应的外部键所在的表为子表,为被控方。
dno int Reference Department(deNumber)工做人员所属的部门号(dno)是相对于Department部门表的外部键。这样定义之后若想添加一个工做人员的记录,添加的记录中dno列的值必须在Department记录中存在与其相同的值,不然就没法添加记录。
也能够用另外一种方式添加外键,若对应的主键是多个列的组合,那么外部键的定义只能放在全部列以后。只能是这种定义:
create table Employee(
id int,
name char(20),
birthday Date,
address varchar(30),
city varchar(10),
sex char(2),
salary numeric(10,2),
dno int,
pno int,
unique(name,birthday)//候选键
primary key(id)//员工表的主键
foreign key(dno) references Department(deNumber)
);
在对子表中的外部键或对父表的主键进行更新时(可能会产生的关联完整性的问题的四种状况)总结:
1.在子表中添加记录:
在子表Employee中添加一个记录,其dno列的值必须与Department表中dNumber列中的一个值相同。或者添加dno列值为NULL,不然将破坏数据库的完整性。可是向父表Department中添加新记录不会产生这个问题。
2.更新子表外部键的值:用update更新后的值必须与父表中的一个主键相匹配,或者更新为NULL,不然将产生错误。
3.删除父表中的记录:从父表中删除一个记录,子表中对应该值的外部键的记录不在与父表中的任何一个主键值相匹配。例如从父表Department表中删除dNumber列值为3的记录,那么子表Employee表中全部dno列值为3的记录(即员工所在部门为3号)的记录都将产生没有匹配主键值的问题。然而从子表中删除记录并不会产生这个问题。
4.更新父表中主键的值:父表Department中更新一个主键的值后,子表Employee中与原来值相对应的外部键的值也将再也不与父表中任一主键的值相匹配。
下面是解决上面问题的方法:
1.使用Restrict关键字:父表中的主键值在子表中有许多具备该值的外部键的记录时,若在约束中指定Restrict关键字,则企图删除父表中的语句将被拒绝,企图更新父表中记录的主键值也将被拒绝。
2.CASCADE关键字:当父表中一个记录被删除时,cascade可使其子表中全部与该记录的主键值对应的记录的(例如父表Department中的dNumber为3的值被删除,在子表中外键dno为3的记录都将被删除)都将从子表中删除。而更新父表中一个主键值时,CASCADE可使其子表中对应外部键的值也自动被修改。
3.SET NULL:当父表中一个记录被删除时,SET NULL可使其子表中全部与该记录的主键值对应的外部键的值将自动被赋值为NULL。更新同理。
4.SET DEFAULT: 当父表中一个记录被删除时,SET DEFAULT可使其子表中的全部与该记录的主键值对应的外部键的值都将被赋值为缺省值。
NULL值并不表示0值或空值,而是表示一个丢失、不知道,不可用的值。
举例子说明该约束:例如,Employee表中,若是没有name就没法知道工做人员的名字,通常来讲公司都要记录工做人员的名字,所以name的值能够规定为NOT NULL,而工做人员的生日,地址,等并非必定要有的,也容许其丢失,这些列值容许为NULL。
做为区分每一个表的主键的值,不能够为空值,而对于外部键来讲,NULL值是容许存在的。
举例来讲明:在Company数据库中,Employee表中pno列是相对于Project的外部键,并非公司的一个员工都参与一个工程项目的工做,如总裁等。所以Employee表中的pno容许有NULL值存在,(员工表Employee的总裁的外部键pno能够为NULL)。
举例来讲明:在Employee增长校验约束条件
Salary NUMERIC(10,2)CHECK(Salary >1000.00 )后Employee表中拒绝小于等于1000的全部记录。
用UPDATE Employee Set Salary=900.00 where id = 2002,该语句产生错误。
在员工表中sex列通常限制男和女两个值,能够增长一个检验约束来实现对sex列的限制。
create table Employee(
id int,
name char(20),
birthday Date,
address varchar(30),
city varchar(10),
sex char(2) check(sex in('男','女')),
salary numeric(10,2),
dno int Reference Department(deNumber),//外键约束
pno int
unique(name,birthday)//候选键
primary key(id)//员工表的主键
Constraint sex_check CHECK(sex in('男','女')),
Constraint salary_check CHECK(salary > 1000.00),
);
使用Constraint关键字进行检验约束的定义。这样咱们能够在之后必要的时候对定义的约束进行激活和撤销。
举例:salary numeric(10,2) default 3000.00,当对表添加记录时,若对设有默认值的列没有指定明确的值,系统自动会进行默认的添加。
Insert into Employee values ('peter','2012-02-20','','北京','男',1004,1,3);
1.Employee 表:
create table Employee(
id int primary key,
name char(15) NOT NULL, /*员工名字*/
birthday Date, /*员工生日*/
address varchar(30), /*员工住址*/
city char(10), /*员工所在城市*/
sex char(2) check(sex in('男','女')) default '男',
salary numeric(10,2) , /*员工工资*/
dno int Reference Department(dnumber), /*外键约束 部门号*/
pno int,
foreign key(dno) references Department(pnumber), /*外键约束 项目号*/
--unique(name,birthday)//候选键
--primary key(id)//员工表的主键
Constraint sex_check CHECK(sex in('男','女')),
Constraint salary_check CHECK(salary > 1000.00),
);
2.Department部门表
Create table Department(
dnumber int primary key, /*主键约束 部门号*/
dname char(20) unique, /*公司中每一个部门的名称应该是不一样的*/
mgrid int, /*部门负责人的id号*/
mgrdate DATE /*负责人上任日期*/
);
3.Project项目表的
Create table Project(
pnumber int primary key, /*项目号*/
pname varchar(20) unique, /*项目名称*/
pmgrid int,
budget NUMRIC(10,2), /*项目预算*/
Gross NUMRIC(10,2), /*预计总收入*/
pstartime Date, /*项目开始时间*/
pendtime Date /*项目结束时间*/
);
4.Paccpeter项目接收方表:
说明:因为不一样项目的接收方能够相同,所以以pnumber列做为表的主键。同时pnumber列是Paccpeter表相对于Project表的外部键。若父表Project不存在的项目号在子表Paccpeter也不能存在。
Create table Paccpeter(
pnumber int primary key, /*项目号*/
accepter char(20) NOT NULL, /*项目接收方不容许为空*/
city char(10),
acceptdate Date, /*接收日期*/
pnumber reference Project(pnumber) /*外键pnumber*/
);
5.Dep_Pro部门和项目链接表的建立:
说明:表中只包含两列:记录部门号的dnumber和记录项目号的pnumber,该表中以两者的组合做为主键。同时dnumber是相对于Department表的外部键,而pnumber列是相对于Project表的外部键。
CREATE TABLE Dep_Pro(
dnumber INT ,
pnumber INT ,
PRIMARY KEY(dnumber,dnumber),
dnumber REFERENCES Department(dnumber),
pnumber REFERENCES Department(pnumber),
);
1.在单列上建立索引:
在员工表id列上建立索引:
CREATE INDEX id_index ON Employee(id);
Select name,sex,id,salary from Employee;
查询的结果会按照索引的顺序进行排列。
2.在多列上建立索引:
CREATE INDEX name_salary_index ON Employee(name,salary);
在多列上建立索引时将按照列出的顺序进行排列。先将按照name进行索引,而后在按照salary进行索引。
3.建立惟一索引:
惟一索引能够在单列也能够在多列上建立,惟一索引能够避免相同值的多个记录的出现,惟一索引是指两个记录中没有同一个索引值。
CREATE UNIQUE INDEX id_index ON Employee(id);
1.向表中添加列:
ALTER TABLE Tablename
ADD columnname datatype
[DEFAULT expression]
[REFERENCES Tablename(columnname)]
[CHECK constraint]
例如:若是要在 Department 表中添加city 列,默认部门所在城市为北京。
Alter table Department add city char(10) default '北京';
也能够添加新列的约束:例如,公司新规定每一个项目的预计总收入不得少于10000.00元,
则能够为Project表中添加一个约束:
ALTER TABLE Project CONSTRAINT gross_check (gross > 10000.00);
2.修改已有列
ALTER TABLE Tablename
MODIFY columnname [datatype]
[DEFAULT expression]
[REFERENCES Tablename(columnname)]
[CHECK constraint]
例如,将Employee表中的name列的长度变成30个字符长:
ALTER TABLE Employee MODIFY NAME CHAR(30) ;
不能修改数据类型,即不能从int改到 char,能够减小字符串的长度,然而,
不能长度少于已有数据中长度最大的值。
也能够修改列所具备的约束:
例如,将 Employee表中sex列的默认值从“男”修改为“女”:
ALTER TABLE Employee MODIFY sex DEFAULT '女';
在SQL 中,也可使用 ALTER TABLE 语句删除表中已有的列。
例如从Employee表中删除birthday:
ALTER TABLE Employee DROP birthday;
Drop index indexname;
使用索引的缘由总结:
使用索引是为了提升检索数据的速度,建立索引后,咱们就能够经过索引来查找数据,而没必要扫描每一个记录。这比如书的目录同样,使咱们很快就会定位到咱们要找的那一页。可是咱们不能对每一列进行索引。由于,建立和维护索引须要占用数据库的时间和空间的。
1.适合使用索引的状况:
(1)大量值:表中的记录在该列上含有大量不一样的值时,为表创建索引能够起到很好的做用。
(2)常常在查询中使用:某列在查询中使用的越多,在该列上建立的索引所能起到的加快速度的做用越明显。
(3)查询返回记录相对较少时:当返回的记录大大少于表中的记录总量的时候,索引能很好的加快查询速度。若老是返回大量的记录,因为索引自己的开销,索引并不能很好的提升检索的速度。
(4)用于两个表链接的操做:因为索引使每一个表中的记录按顺序排列,因此使用被索引的列进行链接操做,能够提升链接速度。
2.不适和创建索引的状况:
(1)小型表:对于小型表,因为表中的记录很少,而索引自身也会增长开销,经过使用索引并不能提升性能,因此小型表不使用索引。
(2)只有不多值的列不适合创建索引。
(3)用户查询方式常常变化的表不适合创建索引。
(4) 在具备较多的NULL值的列不适合建立索引。
(5) 按期更新或者修改的列不断的更新或者修改致使索引页须要进行不断的更新,额外的消耗过多。
10.多表链接查询:
1.什么是链接?
定义:链接是将多个表的数据结合到一块儿的查询,即链接操做能够在一个select语句中完成从多个表中查找和处理数据。使用链接时可使用相同名字的列,例如可使用pnumber链接Project表与Paccpter表;也可使用不一样名字的列进行链接,例如使用Employee表中的id列与Department的mgrid列进行链接。进行链接时用于链接的必须是可链接的列,即要求它们具备相同的数据类型。
通常来讲,链接的语法能够分为二种:
(1) 传统的链接语法:select from/where包含多个表的链接查询
传统的FROM/WHERE 链接语法基本格式以下:
SELECT select_list
FROM Table1name, [ Table2name, ...]
WHERE [Table1name.]column operator [Table2name.]column
用上面的表:
例如:查询部门负责人的负责的部门号、负责人名字、id 号、性别及工资。
分析:须要链接连个表:Employee表和Department表
缘由:在Employee表中并无存储谁是什么部门的负责人,负责人的id 号存储在Department 表中。(参照上面的表)
Select dnumber,name,id,sex,salary from Employee, Department where id=mgrid;
(2) SQL链接语法:join关键字来实现链接的操做JOIN CROSS JOIN及NATURAL
SELECT select_list
FROM Table1name [CROSS | NATURAL] JOIN Table2name
[ON [Table1name.]column operator [Table2name.]column]
[WHERE conditions]
● 第一行中的select_list仍然是选择的列的名称,可是须要注意的是,若是使用两
个表中有相同名称的列,则必须限定是哪一个表中的列;
● 第二行中关键字CROSS与NATURAL 是可选项,可使用也能够不使用。若是
选择了CROSS或NATURAL 关键字,那么就不能使用ON关键字;
● 单独使用JOIN 关键字时,须要使用ON关键字来设定链接的条件;
● 使用CROSS JOIN 时,不能使用关键字ON,所以必须使用WHERE子句设定连
接的条件。由于若是不设定链接条件,将返回表之间的每一种可能组合(即笛卡
尔积),链接结果将很是庞大;
● NATURAL JOIN 只 有在两个表有相同名称的列时才能使用,将在同名列上进行连
接。所以,没必要使用关键字 ON 或 WHERE 子句设定链接条件。固然,使用 WHERE
子句限制查找的行仍然是能够的。
例如查询:部门负责人的负责的部门号、负责人名字、id 号、性别及工资。
用join链接:
Select dnumber,name,sex,id,salary from Employee join Department on mgrid = id;
Results
dnumber name sex id salary
———— ————— ——— —— ————
6 魏成 男 6001 5000.00
1 林志千 男 1001 6000.00
2 陈广海 男 2001 5000.00
3 张宇 男 3001 5000.00
4 张峰 男 4001 7000.00
5 李志深 男 5001 5000.00
用cross join链接:
SELECT dnumber, name, sex, id, salary FROM Employee CROSS JOIN Department
WHERE id = mgrid
结果是与上面相同的。
可是这里不能用NATURAL JOIN链接。虽然Employee的id列和Department表mgrid列的数据类型和存储的内容相同,可是名称不相同,因此不能用天然链接。
Project的表和Paccpter表中有两个相同的列pnumber,则能够对这两个表进行NATURAL JOIN链接。
Select pnumber,accepter,budget from Project NATURAL JOIN Paccpter;
Results
pnumber accepter budget
———— ———————— —————
101 蓝科通信公司 110000.00
102 华夏技术有限公司 140000.00
103 汉升咨询公司 150000.00
104 神州发展有限公司 120000.00
105 四海贸易有限公司 100000.00
201 化天通信公司 200000.00
202 日胜公司 220000.00
203 华田汽修公司 250000.00
204 东胜有限公司 240000.00
301 科华贸易公司 300000.00
302 新安有限公司 320000.00
303 华田汽修公司 360000.00
也能够用传统的from/where循环代替:
Select pnumber,accepter,budget from Project,Paccpter where Project.pnumber = Paccpter.pnumber;
用join on代替:
Select pnumber,accepter,budget from Project join Paccpter on Project.pnumber = Paccpter.pnumber;
2处理链接:
两个表有意义的链接到一块儿,必须有公共数据。
Project表:
SELECT pnumber, budget FROM Project;
Results
pnumber budget
———— —————
101 110000.00
102 140000.00
103 150000.00
104 120000.00
105 100000.00
201 200000.00
202 220000.00
203 250000.00
204 240000.00
301 300000.00
302 320000.00
303 360000.00
Paccepter 表:
SELECT pnumber, accepter FROM Paccepter;
Results
pnumber accepter
———— ———————
101 蓝科 通信公司
102 华夏 技术有限公司
103 汉升 咨询公司
104 神州 发展有限公司
105 四海 贸易有限公司
201 化天通 讯公司
202 日胜公司
203 华田汽 修公司
204 东胜有 限公司
301 科华贸 易公司
302 新安有 限公司
303 华田汽 修公司
在理想的状况下,对数据库中的表进行链接时使用表的主键与相应外部键。由于,设计数据库时,主键与外部键在逻辑上就是互相联系的,而且主键与外部键之间具备一致性,会保持主键列与外部键列在值上的一致。主键与外部键能够很好的保持数据库完整性。
较好的链接应该符合如下要求:
● FROM 子句中必须包含用于链接的全部表,不能仅包含一部分用于链接的表;
● 进行链接的列名称能够不一样,除非要使用NATURAL JOIN,若是须要使用相同
名称的列必须为其加上表名做为限制,否则会产生混淆;
● 用于链接的列必须有相同的数据类型,或能够自动进行类型转换。不一样类型的数
据是不能进行链接的。例如,不能使用Employee表中的birthday 列与Department
表中的dname 列进行链接;
● 用于链接的列必须具备相同的意义,这是最重要的一点,没有相赞成义的列的连
接是毫无用处的。例如,虽然Employee表中的name列与Department 表中的dname
列数据类型相同,可是这两个列绝不相干,链接是没有意义的。
查询的时候必须指定查询条件:
例如:查找正工做在与项目接收方所在城市相同的工做人员。
方法一:Select id,name,sex,city from Employee,Paccepter where Employee.city = Paccepter.city;
方法二: select id,name,sex,city from Employee join Paccepter where Employee.city = Paccepter.city;
若是没有链接条件,查询的结果将是两个表的笛卡尔积。结果行数将大的惊人。
3.笛卡尔积
表一:
Results
A B C
—— —— ——
a b c
d e f
b c d
表二:
Results
D E
—— ——
d e
e f
则表一和表二的笛卡尔积为:
Results
A B C D E
—— —— —— —— ——
a b c d e
a b c e f
d e f d e
d e f e f
b c d d e
b c d e f
最后能够有:3*2=6条记录。
用于指定链接的表越多,其笛卡尔积的结果就越惊人,越须要很好的指定链接条件。
因为链接过程当中使用了笛卡尔积,所以链接操做会致使性能的降低。
使用链接时应该遵循必定的原则:
● 用于链接的列已经建立了索引。由于索引会单独保存在磁盘上,且将数据按照一
定顺序进行了排列,索引的使用能够加快访问的速度;
● 用于链接的列具备相同的数据类型,包括是否容许空值。若是须要系统自动进行
类型转换是须要花费较多时间的,特别是在表中记录不少时,类型转换所花费的
时间将会不少.
4.链接中运算符号的使用:
例如:项目Project 表中的项目完成时间penddate 列的值大于Paccepter 表中的项目
预计接收时间acceptdate列的值。
Select pnumber, accepter, penddate, acceptdate from Project,Paccepter where penddate > acceptdate AND Project.pnumber = Paccepter.pnumber;
Results:
pnumber accepter penddate accedate
———— —————— —————— ——————
201 化天通信公司 2001-12-20 2001-12-15
303 华田汽修公司 2002-04-25 2002-04-15
[2rows]
例如:Project 表中的项目完成时间penddate 列的值不等于Paccepter 表中的项目预
计接收时间accedate 列的值。
Select pnumber, accepter, penddate, acceptdate from Project,Paccepter where penddate <> acceptdate AND Project.pnumber = Paccepter.pnumber;
Results
pnumber accepter penddate accedate
———— —————— —————— ——————
201 化天通信公司 2001-12-20 2001-12-15
204 东胜有限公司 2002-08-01 2002-08-06
303 华田汽修公司 2002-04-25 2002-04-15
[3rows]
在进行链接的时候还可使用where子句限制查找到的行。
例如,只须要查看项目号小于201 的全部项目的项目编号、接收方及项目成本。
方法一:
Select pnumber, accepter, budget from Project, Paccpeter where Project.pnumber = Paccpeter.pnumber AND Project.pnumber < 201;
方法二:
Select pnumber, accepter, budget from Project join Paccpeter on Project.pnumber = Paccpeter.pnumber where Project.pnumber < 201;
Results
pnumber accepter budget
———— —————— —————
101 科华贸易公司 110000.00
102 华夏技术有限公司 140000.00
103 科华贸易公司 150000.00
104 神州发展有限公司 120000.00
105 四海贸易有限公司 100000.00
[5rows]
5.多表的链接:
须要知道工做人员自己以及其所属的部门和所参与的项目的详细信息,
Employee表、Department 表、Project 表这三个表以获得所需的信息。
可是多个表链接或者多个表链接时引发的性能降低更加严重。
例如:有三个表,每一个表都包含100行记录,则三个表链接将产生100*100*100行的组合表。处理这样的组合表要花费的时间将会长的多。
例如:将返回工做人员自己以及其所属的部门和所参与的项目的详细信息:
分析:须要链接三个表:Employee表,Department表,Project表。
Select id,name,dnumber,dname,mgrid,pnumber,pname,gross from Employee, Department, Project where dno = dnumber AND pno = pnumber;
数据库设计时介绍了三种关系和数据库链接的关系:
(1)一对一的关系:
例如:项目Project表和项目接收Paccepter表时一对一的关系:
能够经过项目号pnumber进行链接:
方法一:Select pnumber,accepter,budget from Project join Paccepter on Project.pnumber = Paccepter.pnumber where Project.pnumber = 102;
方法二:Select pnumber,accepter,budget from Project,Paccepter where Project.pnumber = Paccepter.pnumber AND Project.pnumber = 102;
Result:
pnumber accepter budget
———— —————— ————
102 华夏技术有限公司 140000.
[1row]
(2)一对多的关系:
一个表的一条记录能够对应另外一个表的若干条记录:
查询的时也能够对两个表进行链接:例如:部门和工做人员之间就是一对多的关系。
但愿由工做人员记录得出其所属的部门的信息就须要进行链接:
Select id,name,dnumber, mgrid from Employee,Department where dno = dnumber AND name = ‘lipeng’;
Select id,name,dnumber,mgrid from Employee join Department on dno = dnumber where name = ‘lipeng’;
Results
name id dnumber mgrid
————— —— ———— ———
李明 1002 1 1001
[1row]
(3) 多对多的关系:
没法对多对多的两个表进行链接,则必须使用建立数据库时专门为多对多的关系建立的链接表来实现。所以须要包含三个表的组合来链接数据。
例如:一个部门可能同时进行一个或者多个项目,一个项目可能由一个或者多个部门来配合才能很好的完成。
部门与项目间存在着多对多的关系。能够经过链接表来实现部门与项目的链接。
SELECT dnumber, mgrid, pnumber FROM Department JOIN Dep_pro
ON Department.dnumber = Dep_pro.dnumber Project JOIN Dep_pro ON Project.pnumber = Dep_pro.pnumber WHERE Project.pnumber = 301
SELECT dnumber, mgrid, pnumber FROM Department,Project,Dep_pro
WHERE Department.dnumber = Dep_pro.dnumber AND
Project.pnumber = Dep_pro.pnumber AND
Project.pnumber = 301