【DB2学习文档之七】SQL for DB2

作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/

1.SQL的数据操作语言data manipulation language (DML)
参见Beginning SQL Queries: From Novice to Professional, by Clare Churcher (Apress, 2008)
2.Select语句
这个语句是DB2中最简单也最复杂的语句,它包含六部分:
select :列出列名或相关结构。
from :描述从何处得到需要的数据并指出多个目标怎样被结合在一起。
where:像谓语那样描述条件。
group:描述非聚合数据在聚合数据之前是怎样被处理的。
having:可选项、相当于where语句,作为一个对group中生成的组判断的准则。
order:提供排序需求。
那我怎么知道从哪个表去取数据呢?
系统提供了以下表单进行查询:
SYSTABLES SYSIBM Information about all tables in the database
SYSINDEXES SYSIBM Information about the indexes on all tables
SYSVIEWS SYSIBM Information on all views in the database
.....类似的结构
系统还提供了以下一些视图进行查询:
TABLES SYSCAT Information about all tables in the database
INDEXES SYSCAT Information about the indexes on all tables
VIEWS SYSCAT Information on all views in the database
PROCEDURES SYSCAT Information on all stored procedures in the database
FUNCTIONS SYSCAT Information on all functions in the database
select * from sysibm.systables可以进行查看。注意这个操作不要在CLP中进行,否则会十分郁闷,原因是CLP的屏幕有限,而信息太多。
诸如select name, creator, colcount from sysibm.systables这样的命令可以在CLP中执行。
我们可以对表单的输出进行订制:
select name, creator, colcount as "No of Columns", abs(npages*4*1024) as "Bytes" from sysibm.systables
where怎么使用?
where就像一个过滤器grep那样进行过滤:select name, creator from sysibm.systables where creator = 'FUZZY'
group怎么使用?
例如你想在sample中知道每个部门给员工发的薪水的总和,你怎样告诉SUM你想对每个部门进行分别的累加呢?使用group进行就可以。
select workdept, sum(salary) as newsalary from employee group by workdept
having怎么使用?
类比where,这是对group进行的数据进行了grep。例如:
select workdept, sum(salary) DeptSal from employee group by workdept having sum(salary) > 100000
这就确定了1000000以上的薪金总和的部门了。注意这里使用having语句时,尽管我们进行了重命名,但是还是使用以前的名字salary进行重命名。
order怎么使用 ?
order来指定根据哪一列元素进行排序,例如:
select workdept, sum(salary) DeptSal from employee group by workdept having sum(salary) > 100000 order by workdept
Select的三种规模较大的语句:joins, subqueries, unions
1.Joins
使用比较、处理和使用,将不同表的相关数据结合起来,例如:
select e.firstnme, e.lastname, d.deptname, d.location from employee e inner join department d on e.workdept = d.deptno
其中e和d对数据库名称进行了简化,关于inner join在这里我们回顾一下数据库相关的三个小概念:
内联:
a inner join b on a.id=b.id
查两张表都有的id记录
左外联:
a left join b on a.id=b.id
只要表a有记录,表b没有记录的
右外联:
a right join b on a.id=b.id
只要表b有记录,表a没有记录的
2.Subqueries
是一种嵌套方式,它可以被用来进行更加复杂的where或者having,可以当做一个虚拟表或视图给from使用。例如:
select firstnme, surname from employee where empno in (select mgrno from department)
3. union
就是维恩图中的集合相并,集合相交为Intersect,集合做差集是Except,在这些操作后加上all则会保留原来的集合中的元素而不会像默认进行的那样将重复的去掉。例如:
Select firstnme from employee where salary < style="FONT-WEIGHT: bold" size="4">3.使用DB2的注册表
DB2提供了许多特殊值帮助你完成类似得到当前时间、日期等的信息,例如:
select current timestamp from sysibm.sysdummy1
使用注册表的好处我们可以举一个例子进行说明:
我们在Sample数据库的Employee这个表中加入莫扎特的好朋友Jimi Hendrix(此人不是那个著名的电吉他手),语句如下:
Insert into employee(empno, firstnme, lastname, hiredate, edlevel)Values('222222', 'Jimi', 'Hendrix', current date, 16)
其中我们使用了current date寄存器进行了设定了雇佣的时间,这比我们自己手动设置靠谱许多。
我们可以试着看看这个值是不是就是现在的时间:
---------------------------------
db2 => values current time
1--------15:56:451 条记录已选择。
-------------------------
没错!
更多的关于时间寄存器和其应用在IBM的Developerworks上有:
http://www.ibm.com/developerworks/data/library/techarticle/0211yip/0211yip3.html
除了时间寄存器外,我们在这列出所有的寄存器,希望你能用好它:
CLIENT ACCTNG
CLIENT APPLNAME
CLIENT USERID
CLIENT WRKSTNNAME
CURRENT DBPARTITIONNUM
CURRENT PATH
CURRENT SCHEMA
CURRENT SERVER
CURRENT TIME
CURRENT TIMESTAMP
CURRENT TIMEZONE
CURRENT USER
Current query optimization
SESSION USER
SYSTEM USER
USER

 

1.新建一个表的基本方法:

Create table nomination
(
nominationID INTEGER Not Null,
nominee char(6) Not Null,
nominator char(6) Not Null,
reason VARCHAR(250),
nomdate date Not Null
)

格式如下:column_name data_type constraint_details

注意列名称不能大于30,并且你如果不指定限制信息则我们允许null。

这个看似简单的操作后边隐藏着两个值得注意的地方:

第一个是所有的存储需求都要去检验是不是满足,第二个是权限检验。关于权限,你必须是这个数据库实例的SYSADM组,或者该数据库的DBADM组,或者是在该数据库中有CREATETAB权限并且在合适的表空间中使用。当然这些都可能暂时不是我们考虑的,否则我们就疯掉了…

表的名字由字母开头,不能包含非法字符,不大于128个单字,在一个schema中名字是唯一的。schema类似于一个命名空间,你要是不显示指定schema的话那么就使用你连接数据库时使用的ID作为Schema。

要是你有数据建模的背景,那么你就知道在一个给定的实体的一系列属性上应该定义一个或者多个属性为唯一标识。在定义主键上,SQL语句有如下的两种形式:

Create table nomination
(
nominationID BIGINT Not Null Primary Key,
nominee char(6) Not Null,
nominator char(6) Not Null,
reason VARCHAR(250),
nomdate date Not Null
)

或者

Create table nomination
(
nominationID BIGINT Not Null,
nominee char(6) Not Null,
nominator char(6) Not Null,
reason VARCHAR(250),
nomdate date Not Null,
Primary Key (nominationID)
)

而改变主键则使用下面的命令:

db2 => alter table nomination add primary key (nominationid)

2.外键的设置和处理

而主键则必须与另一种限制一起使用:外键(参照完整性限制)。例如:

image

第一个表是国家的表,包含世界上所有的国家。而第二个表是城市表,我们注意country_ID 和country_no是连接两个表的列。

其中country_no就是所谓外键(也叫做参照约束,Referential Constraints),用于指向父表中的主键 ,由于这种关系,country_no列不能有一个在country_ID 中不存在的值。外键的数据类型必须与父表的主键类型兼容。

CREATE TABLE country (
       country_ID      INT         NOT NULL PRIMARY KEY,
       country_Name    VARCHAR(30)   NOT NULL,
       continent_Name  CHAR(15)
       )
CREATE TABLE city (
       city_ID         INT           NOT NULL PRIMARY KEY,
       city_name    VARCHAR(30)   NOT NULL,
       country_no      INT           REFERENCES country,
       population      INT
       )

在nomination那个例子中,我们引入一个表,Category,并且改变nomination这个表去以Category为一个约束。我们先把Category表建立起来,

image

我们根据这个需求建立表单为:

image

那么我们就可以创建表单了:

Create table category
(
CategoryID INTEGER Not Null Primary Key,
CateogryName VARCHAR(50) Not Null,
Eligibility VARCHAR(250)
)

首先我们要加入一列,categoryid

db2 => alter table nomination
add column categoryid integer not null

这个时候会出现以下的错误:

SQL0193N  In an ALTER TABLE statement, the column "CATEGORYID" has been
specified as NOT NULL and either the DEFAULT clause was not specified or was
specified as DEFAULT NULL.  SQLSTATE=42601

这其中的原因是如果你使用ALTER TABLE命令强行加入一个NOT NULL 参数,DB2会认为你可能是对一个已经存在的列进行操作,但实际上DB2这个玩意也不会去检查。我们只需在后边加上一个默认值,DB2就会放行。

db2 => alter table nomination
add column categoryid integer not null default 1

我们现在利用这个列对两个表进行连接,指向Category表。

db2 => alter table nomination add foreign key CategoryExists (categoryid)
references category (categoryid)

这样我们就建立了联系,不过像其他数据库那样,DB2对于这些连接表的量也提供了一些on change规则。我们可以使用:

我们先删掉刚建立的外键:

db2 => alter table nomination drop constraint CategoryExists

我们再次建立,使用on delete rules对一旦删除了父表的参照约束,数据库怎么处理进行了约束:

db2 => alter table nomination add foreign key CategoryExists (categoryid)
references category (categoryid) on delete restrict

on delete选项后边可以跟如下参数,我们使用color和object两个表进行说明:

cascade: 一旦删除任何父表的外键,则将删除所有与其匹配的子表的行。

SET NULL: 一旦删除父表的外键,则将子表中相关的值设置为null,但该行保留。

no action: 字面上的意思是不会试图去解决任何冲突。实际上是子记录所以无法删除该记录,在下边的这个例子中Delete 操作直接failed了。

restrict: 若子表中还有父表中的参照约束,则删除动作会failed。

注意到这个与no action貌似没有任何区别,那是因为两个表之间的关系不足以说明问题,而且只有在及个别的情况下会导致区别,那么我们举这样一个例子:

T2是T3的父表,delete rule设置为CASCADE。

T1也是T3的父表,delete rule设置为:

1)RESTRICT:那么在T3中有任何一个子行有T1的参照约束的话,任何删除T1或者T2中参照约束的删除操作都会failed(SQLSTATE 23001)。也就是说,这个具有最高的优先级执行权限,在CASCADE生效之前起作用。

2)NO ACTION:当删除T2中的参照约束时,由于T2和T3是CASCADE,那么T3的相关行也可能 会被删除(之所以说“可能” 意思是:当删除T2的参照约束不足以将T3中与T1相关的行全部删除,那么也会出错。)。也就是说,它是在其他约束的动作之后执行的rule。

除了on delete规则,我们还可以设置为on update规则,当父表中的参照约束有更改的时候起作用。

ON UPDATE RESTRICT :对这个更改进行约束。

ON UPDATE NO ACTION:更新操作会成功,父表的值会根据操作改变,子表不变

我们在更改这样的约束规则时没有一个命令能直接更改,只能先删掉相关外键后重建外键。

上一节介绍了参照约束,这一节我们介绍另外一个约束以及解约束。

1.检查约束:

一旦在表上定义了表检查约束,每个UPDATE和INSERT语句都会引起限制或约束的检查。如果违反了约束条件,数据记录将不被插入或更新,并且会返回一条SQL错误信息。

基本的语法是:Check (columncolumn-constraints)

例如我们创建如下的表格:

Create table nomination
(
nominationID BIGINT Not Null Primary Key,
nominee char(6) Not Null,
nominator char(6) Not Null,
reason VARCHAR(250),
nomdate date Not Null,
categoryid INTEGER Not Null,
check (nominee != nominator),
Foreign Key CategoryExists (categoryid)
references category (categoryid) on delete restrict
)

当然我们还可以对现存的表单加入检查约束:

db2 => alter table nomination add constraint
NoSelfNomination check (nominee != nominator)

2.解约束和约束延期(Disabling Constraints and Constraint Deferral)

我们可以使用not enforced来建立解约束,使这个约束不生效。我们先将上一个部分建立的检查约束删除:

db2 => alter table nomination drop constraint NoSelfNomination

然后再建立解约束:

db2 => alter table nomination add constraint
NoSelfNomination check (nominee != nominator) not enforced

你可能比较纳闷为什么这么做,简单的说,这个可以把你的数据库性能提升上去,在某些时候使用enable query optimization 和 disable query optimization。我们在后边会学习到。这里有个小小的演示:

我们还是先将刚才建立的解约束删除:

db2 => alter table nomination drop constraint NoSelfNomination

使用上边提到的那个东东建立解约束:

db2 => alter table nomination add constraint
NoSelfNomination check (nominee != nominator)
not enforced enable query optimization

这样我们就告诉DB2,我们不使用这个约束,但是在查询时使用这个约束进行性能优化。

例如,我们这样查询:Select * from nomination where nominee = nominator

DB2就会先看看这个解约束,这个解约束告诉我们这个是不可能发生的(虽然这个约束并没有enforced),那么DB2就不会去查表了(其实这并不一定反映真实的情况,所以要慎用这个解约束功能),性能也自然得到了优化。

DB2提供了当有一行插入的时候自动在某一列添加值的功能,可以使用所谓identity rules,简单点的比如某个数值的递增填入该列中,当然也有很复杂的。使用这个一般是用作识别码的,当做定义表格的主键。generated语法则可以自定义你想怎么产生这个值的策略。

语法如下:

column definition generated {always | by default}
as {identity identity rules | using your rules}

我们先删掉上次我们建立的表格:

db2 => drop table nomination

然后再创建一个表格:

Create table nomination
(
nominationID BIGINT Not Null Primary Key generated always as identity,
nominee char(6) Not Null,
nominator char(6) Not Null,
reason VARCHAR(250),
nomdate date Not Null,
categoryid INTEGER Not Null,
check (nominee != nominator) not enforced enable query optimization,
Foreign Key CategoryExists (categoryid)
references category (categoryid) on delete restrict
)

注意黑体字,以后我们就不能使用insert或者update来显式的指定它的值了。

而DB2中的identity也提供了多种策略,具体的可以去查DB2手册,我们举例如下:

我们先删掉上次我们建立的表格:

db2 => drop table category

然后建立表单

Create table category
(
CategoryID INTEGER Primary Key  Generated Always as Identity
(Start With 1 Increment by 1 minvalue 0 maxvalue 999999999
no cycle cache 5 no order),
CateogryName VARCHAR(50) Not Null,
Eligibility VARCHAR(250)
)

黑体字中identity中的语句你都能在DB2的手册中查到,都是自然语言一看就懂了。

有时候你并不只想去做数字的填充,你可能还想处理一些字母,那么下边这个转换大写的例子就是给你的:

db2 => alter table category add column
UpperCatName VARCHAR(50) generated always as (upper(CategoryName))

关于这些在DB2的文档里都有具体说明。

1.表空间作为表的逻辑存储单元,有三种:

in:你可以指定一个表单的普通数据存放在哪个常规表空间中。

Index:你也可以指定一个独立的常规表空间存储index。

Long:你还可以分配一个大的表空间存储一个表单中大的对象。

2.语法:

Create table tablename
(various column names and attributes)
[in tablespace-name]
[Index in tablespace-name]
[Long in tablespace-name]

3.实例:

Create table AwardWinner
(AwardWinnerID integer Primary Key Generated Always as Identity
(Start With 1 Increment by 1),
DateWon Date Not Null,
TotalVotes Integer Not Null,
Picture BLOB)
in userspace1
Index in userspace1
Long in picturelobs

 

1.create table ... as select ...方法:

我们可以使用select方法从源表单中选择性的构建新表单的列,例如:

db2 => Create table EmployeeCopy
as (select firstnme, lastname from employee)
definition only

create table 的时候不同时进行数据插入。那个关键字就是指“只定义无数据 ",也就是没有数据导入。

2.create table ... like ...方法:

用于建立一个完全相同列的表。

语法如下:

CREATE TABLE [TableName ] LIKE [SourceTable ]

<[INCLUDING | EXCLUDING] COLUMN DEFAULTS>

<[INCLUDING | EXCLUDING] IDENTITY COLUMN ATTRIBUTES>

这样创建的表格是和SourceTable有相同的列(names, data types, and nullability characteristics)(也同样不导入数据),如果你不使用EXCLUDING COLUMN DEFAULTS,任何定义在源表单中的默认约束都会生效。需要注意的是其他的属性不会被复制进新的表单中,所有UNIQUE约束、参照性约束、触发器或者索引都不会复制的。

db2 =>create table EmployeeCopy3 like EmployeeCopy2

including column defaults
excluding identity column attributes

你要是想导入数据,一般是在控制中心中执行类似如下的语句:

CREATE TABLE ADDRESS2 LIKE ADDRESS
INSERT INTO ADDRESS2 SELECT * FROM ADDRESS

 

 

作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/

你可能感兴趣的:(sql)