数据库中的所有数据存储在表中。数据表包括行和列。列决定了表中数据的类型。行包含了实际的数据。
例如,数据库pubs中的表authors有九个字段。其中的一个字段名为为au_lname,这个字段被用来存储作者的名字信息。每次向这个表中添加新作者时,作者名字就被添加到这个字段,产生一条新记录。
通过定义字段,你可以创建一个新表。每个字段有一个名字和一个特定的数据类型(数据类型在后面的“字段类型”一节中讲述),例如字段au_lname存储的是字符型数据。一个字段也可以存储其它类型的数据。
使用SQL
一、用CREATE语句创建表
注意:
如果你还没有建立自己的数据库,现在就跳回到第三章创建这个库。你绝不能向master,tempdb或任何其他任何系统数据库中添加数据。
从SQL
CREATE
如果一切正常,你会在结果窗口中看到如下的文字(如果出现异常,请参阅第三章):
This
祝贺你,你已经建立了你的第一个表!
你所创建的表名为guestbook,你可以使用这个表来存储来字你站点访问者的信息。你是用CREATE
表guestbook有三个字段:visitor,comments
Visitor
Comments
Entrydate
注意每个字段名后面都跟有一个专门的表达式。例如,字段名comments后面跟有表达式TEXT。这个表达式指定了字段的数据类型。数据类型决定了一个字段可以存储什么样的数据。因为字段comments包含文本信息,其数据类型定义为文本型。
二、字段类型
不同的字段类型用来存放不同类型的数据。创建和使用表时,你更应该理解五种常用的字段类型:字符型,文本型,数值型,逻辑性和日期型。
(1)字符型数据
字符型数据非常有用。当你需要存储短的字符串信息时,你总是要用到字符型数据。例如,你可以把从HTML
要建立一个字段用来存放可变长度的字符串信息,你可以使用表达式
CREATE
在这个例子中,字段visitor的数据类型为VARCHAR。注意跟在数据类型后面的括号中的数字。这个数字指定了这个字段所允许存放的字符串的最大长度。在这个例子中,字段visitor能存放的字符串最长为四十个字符。如果名字太长,字符串会被截断,只保留四十个字符。
VARCHAR类型可以存储的字符串最长为255个字符。要存储更长的字符串数据,可以使用文本型数据(下一节中讲述)。
另一种字符型数据用来存储固定长度的字符数据。下面是一个使用这种数据类型的例子:
CREATE
在这个例子中,字段visitor被用来存储四十个字符的固定长度字符串。表达式CHAR指定了这个字段应该是固定长度的字符串。
VARCHAR型和CHAR型数据的这个差别是细微的,但是非常重要。假如你向一个长度为四十个字符的VARCHAR型字段中输入数据Bill
现在假如你把字符串输入一个长度为四十个字符的CHAR型字段中,那么当你取出数据时,所取出的数据长度将是四十个字符。字符串的后面会被附加多余的空格。
当你建立自己的站点时,你会发现使用VARCHAR型字段要比CHAR型字段方便的多。使用VARCHAR型字段时,你不需要为剪掉你数据中多余的空格而操心。
VARCHAR型字段的另一个突出的好处是它可以比CHAR型字段占用更少的内存和硬盘空间。当你的数据库很大时,这种内存和磁盘空间的节省会变得非常重要。
(2)文本型数据
字符型数据限制了字符串的长度不能超过255个字符。而使用文本型数据,你可以存放超过二十亿个字符的字符串。当你需要存储大串的字符时,应该使用文本型数据。
这里有一个使用文本型数据的例子:
CREATE
在这个例子中,字段comments被用来存放访问者对你站点的意见。注意文本型数据没有长度,而上一节中所讲的字符型数据是有长度的。一个文本型字段中的数据通常要么为空,要么很大。
当你从HTML
警告:
一旦你向文本型字段中输入了任何数据(甚至是空值),就会有2K的空间被自动分配给该数据。除非删除该记录,否则你无法收回这部分存储空间。
(3)数值型数据
SQL
通常,当你需要在表中的存放数字时,你要使用整型(INT)数据。INT型数据的表数范围是从-2,147,483,647到2,147,483,647的整数。下面是一个如何使用INT型数据的例子:
CREATE
这个表可以用来记录你站点被访问的次数。只要没有人访问你的站点超过2,147,483,647次,nubvisits字段就可以存储访问次数。
为了节省内存空间,你可以使用SMALLINT型数据。SMALLINT
最后,如果你实在需要节省空间,你可以使用TINYINT型数据。同样,这种类型的使用方法也与INT型相同,不同的是这种类型的字段只能存储从0到255的整数。TINYINT型字段不能用来存储负数。
通常,为了节省空间,应该尽可能的使用最小的整型数据。一个TINYINT型数据只占用一个字节;一个INT型数据占用四个字节。这看起来似乎差别不大,但是在比较大的表中,字节数的增长是很快的。另一方面,一旦你已经创建了一个字段,要修改它是很困难的。因此,为安全起见,你应该预测以下,一个字段所需要存储的数值最大有可能是多大,然后选择适当的数据类型。
为了能对字段所存放的数据有更多的控制,你可以使用NUMERIC型数据来同时表示一个数的整数部分和小数部分。NUMERIC型数据使你能表示非常大的数——比INT型数据要大得多。一个NUMERIC型字段可以存储从-10^38到10^38范围内的数。NUMERIC型数据还使你能表示有小数部分的数。例如,你可以在NUMERIC型字段中存储小数3.14。
当定义一个NUMERIC型字段时,你需要同时指定整数部分的大小和小数部分的大小。这里有一个使用这种数据类型的例子:
CREATE
当这个语句执行时,将创建一个名为numeric_data的包含两个字段的表。字段bignumber可以存储直到28位的整数。字段fraction可以存储有五位整数部分和四位小数部分的小数。
一个NUMERIC型数据的整数部分最大只能有28位,小数部分的位数必须小于或等于整数部分的位数,小数部分可以是零。
你可以使用INT型或NUMERIC型数据来存储钱数。但是,专门有另外两种数据类型用于此目的。如果你希望你的网点能挣很多钱,你可以使用MONEY型数据。如果你的野心不大,你可以使用SMALLMONEY型数据。MONEY型数据可以存储从-922,337,203,685,477.5808到922,337,203,685,477.5807的钱数。如果你需要存储比这还大的金额,你可以使用NUMERIC型数据。
SMALLMONEY型数据只能存储从-214,748.3648到214,748.3647
CREATE
Discount_price
这个表可以用来存储商品的折扣和普通售价。字段price
(4)存储逻辑值
如果你使用复选框(CHECKBOX)从网页中搜集信息,你可以把此信息存储在BIT型字段中。BIT型字段只能取两个值:0或1。这里有一个如何使用这种字段的例子:
CREATE
这个表可以用来存放对你的网站进行民意调查所得的信息。访问者可以投票表示他们是否喜欢你的网站。如果他们投YES,就在BIT型字段中存入1。反之,如果他们投NO,就在字段中存入0(在下一章里,你将学会如何计算投票)。
当心,在你创建好一个表之后,你不能向表中添加BIT型字段。如果你打算在一个表中包含BIT型字段,你必须在创建表时完成。
(5)存储日期和时间
当你建立一个网站时,你也许需要记录在一段时间内的访问者数量。为了能够存储日期和时间,你需要使用DATETIME型数据,如下例所示:
CREATE
这个表可以用来记录访问者进入和离开你网站的时间和日期。一个DATETIME型的字段可以存储的日期范围是从1753年1月1日第一毫秒到9999年12月31日最后一毫秒。
如果你不需要覆盖这么大范围的日期和时间,你可以使用SMALLDATETIME型数据。它与DATETIME型数据同样使用,只不过它能表示的日期和时间范围比DATETIME型数据小,而且不如DATETIME型数据精确。一个SMALLDATETIME型的字段能够存储从1900年1月1日到2079年6月6日的日期,它只能精确到秒。
DATETIME型字段在你输入日期和时间之前并不包含实际的数据,认识这一点是重要的。在下一章,你将学习怎样使用大量的SQL函数来读取和操作日期和时间(参见下面的“缺省值”一节)。你也可以在VBScript和JScript
三、字段属性
上一节介绍了如何建立包含不同类型字段的表。在这一节中,你将学会如何使用字段的三个属性。这些属性允许你控制空值,缺省值和标识值。
(1)允许和禁止空值
大多数字段可以接受空值(NULL)。当一个字段接受了空值后,如果你不改变它,它将一直保持空值。空值(NULL)和零是不同的,严格的说,空值表示没有任何值。
为了允许一个字段接受空值,你要在字段定义的后面使用表达式NULL。例如,下面的表中两个字段都允许接受空值:
CREATE
注意:
BIT型数据不能是空值。一个这种类型的字段必须取0或者1。
有时你需要禁止一个字段使用空值。例如,假设有一个表存储着信用卡号码和信用卡有效日期,你不会希望有人输入一个信用卡号码但不输入有效日期。为了强制两个字段都输入数据,你可以用下面的方法建立这个表:
CREATE
Creditcard_expire
注意字段定义的后面跟有表达式NOT
你将会发现,在你建设自己的网站过程中,这种禁止空值的能力是非常有用的。如果你指定一个字段不能接受空值,那么当你试图输入一个空值时,会有错误警告。这些错误警告可以为程序调试提供有价值的线索。
(2)缺省值
假设有一个存储地址信息的表,这个表的字段包括街道、城市、州、邮政编码和国家。如果你预计地址的大部分是在美国,你可以把这个值作为country字段的缺省值。
为了在创建一个表时指定缺省值,你可以使用表达式DEFAULT。请看下面这个在创建表时使用缺省值的例子:
CREATE
city
state
zip
country
在这个例子中,字段country的缺省值被指定为美国。注意单引号的使用,引号指明这是字符型数据。为了给非字符型的字段指定缺省值,不要把该值扩在引号中:
CREATE
quantity
entrydate
在这个CREATE
(3)标识字段
每个表可以有一个也只能有一个标识字段。一个标识字段是唯一标识表中每条记录的特殊字段。例如,数据库pubs中的表jobs包含了一个唯一标识每个工作标识字段:
job_id
…………………………………………………………….
1
2
3
4
5
字段job_id为每个工作提供了唯一的一个数字。如果你决定增加一个新工作,新增记录的job_id字段会被自动赋给一个新的唯一值。
为了建立一个标识字段,你只需在字段定义后面加上表达式IDENTITY即可。你只能把NUMERIC型或INT型字段设为标识字段,这里有一个例子:
CREATE
这个语句所创建的表包含一个名为theid的标识字段。每当一个新的访问者名字添加到这个表中时,这个字段就被自动赋给一个新值。你可以用这个表为你的站点的每一个用户提供唯一标识。
技巧:
建立一个标示字段时,注意使用足够大的数据类型。例如你使用TINYINT型数据,那么你只能向表中添加255个记录。如果你预计一个表可能会变得很大,你应该使用NUMERIC型数据。
标识字段的存在会使你想尝试许多不可能的事情。例如,你也许想利用标识字段来对记录进行基于它们在表中位置的运算。你应该抛弃这种意图。每个记录的标识字段的值是互不相同的,但是,这并不禁止一个标识字段的标识数字之间存在间隔。例如,你永远不要试图利用一个表的标识字段来取出表中的前十个记录。这种操作会导致失败,比如说6号记录和7号记录根本不存在。
四、删除和修改表
要删除一个表,你可以使用SQL语句DROP
DROP
警告:
使用DROP
当你建设一个站点时,你很可能需要向数据库中输入测试数据。而当你准备向世界提供你的网点时,你会想清空表中的这些测试信息。如果你想清除表中的所有数据但不删除这个表,你可以使用TRUNCATE
TRUNCATE
虽然你不能删除和修改已经存在的字段,但你可以增加新字段。最容易的实现方法是使用SQL事务管理器中的Manager
ALTER
这个语句向表mytable中增加了一个新字段mynewcolumn。当你增加新字段时,你必须允许它接受空值,因为表中原来可能已经有了许多记录。
总结
1 .在查询结果中显示列名:
a.用as关键字: select name as ' 姓名 ' from students order by age
b.直接表示: select name ' 姓名 ' from students order by age
2 .精确查找:
a.用in限定范围: select * from students where native in ( ' 湖南 ' , ' 四川 ' )
b. between and : select * from students where age between 20 and 30
c.“ = ”: select * from students where name = ' 李山 '
d. like : select * from students where name like ' 李% ' (注意查询条件中有“ % ”,则说明是部分匹配,而且还有先后信息在里面,即查找以“李”开头的匹配项。所以若查询有“李”的所有对象,应该命令: ' %李% ' ;若是第二个字为李,则应为 ' _李% ' 或 ' _李 ' 或 ' _李_ ' 。)
e. [] 匹配检查符: select * from courses where cno like ' [AC]% ' (表示或的关系,与" in ()"类似,而且" [] "可以表示范围,如: select * from courses where cno like ' [A-C]% ' )
3 .对于时间类型变量的处理
a. smalldatetime :直接按照字符串处理的方式进行处理,例如:
select * from students where birth > = ' 1980-1-1 ' and birth <= ' 1980-12-31 '
4 .集函数
a. count ()求和,如: select count ( * ) from students (求学生总人数)
b. avg (列)求平均,如: select avg (mark) from grades where cno = ’B2’
c. max (列)和min(列),求最大与最小
5 .分组group
常用于统计时,如分组查总数:
select gender, count (sno)
from students
group by gender
(查看男女学生各有多少)
注意:从哪种角度分组就从哪列" group by "
对于多重分组,只需将分组规则罗列。比如查询各届各专业的男女同学人数,那么分组规则有:届别(grade)、专业(mno)和性别(gender),所以有" group by grade, mno, gender"
select grade, mno, gender, count ( * )
from students
group by grade, mno, gender
通常group还和having联用,比如查询1门课以上不及格的学生,则按学号(sno)分类有:
select sno, count ( * ) from grades
where mark < 60
group by sno
having count ( * ) > 1
6 .UNION联合
合并查询结果,如:
SELECT * FROM students
WHERE name like ‘张 % ’
UNION [ ALL ]
SELECT * FROM students
WHERE name like ‘李 % ’
7 .多表查询
a.内连接
select g.sno,s.name,c.coursename
from grades g JOIN students s ON g.sno = s.sno
JOIN courses c ON g.cno = c.cno
(注意可以引用别名)
b.外连接
b1.左连接
select courses.cno, max (coursename), count (sno)
from courses LEFT JOIN grades ON courses.cno = grades.cno
group by courses.cno
左连接特点:显示全部左边表中的所有项目,即使其中有些项中的数据未填写完全。
左外连接返回那些存在于左表而右表中却没有的行,再加上内连接的行。
b2.右连接
与左连接类似
b3.全连接
select sno,name,major
from students FULL JOIN majors ON students.mno = majors.mno
两边表中的内容全部显示
c.自身连接
select c1.cno,c1.coursename,c1.pno,c2.coursename
from courses c1,courses c2 where c1.pno = c2.cno
采用别名解决问题。
d.交叉连接
select lastname + firstname from lastname CROSS JOIN firstanme
相当于做笛卡儿积
8 .嵌套查询
a.用关键字IN,如查询李山的同乡:
select * from students
where native in ( select native from students where name = ’ 李山’)
b.使用关键字EXIST,比如,下面两句是等价的:
select * from students
where sno in ( select sno from grades where cno = ’B2’)
select * from students where exists
( select * from grades where
grades.sno = students.sno AND cno = ’B2’)
9 .关于排序order
a.对于排序order,有两种方法:asc升序和desc降序
b.对于排序order,可以按照查询条件中的某项排列,而且这项可用数字表示,如:
select sno, count ( * ) , avg (mark) from grades
group by sno
having avg (mark) > 85
order by 3
10 .其他
a.对于有空格的识别名称,应该用" [] "括住。
b.对于某列中没有数据的特定查询可以用null判断,如select sno,courseno from grades where mark IS NULL
c.注意区分在嵌套查询中使用的any与all的区别,any相当于逻辑运算“ || ”而all则相当于逻辑运算“ && ”
d.注意在做否定意义的查询是小心进入陷阱:
如,没有选修‘B2’课程的学生 :
select students. *
from students, grades
where students.sno = grades.sno
AND grades.cno <> ’B2’
上面的查询方式是错误的,正确方式见下方:
select * from students
where not exists ( select * from grades
where grades.sno = students.sno AND cno = ' B2 ' )
11 .关于有难度多重嵌套查询的解决思想:
如,选修了全部课程的学生:
select *
from students
where not exists ( select *
from courses
where NOT EXISTS
( select *
from grades
where sno = students.sno
AND cno = courses.cno))
最外一重:从学生表中选,排除那些有课没选的。用not exist。由于讨论对象是课程,所以第二重查询从course表中找,排除那些选了课的即可。
添加数据库
go
if exists ( select * from sysdatabases where name = ' test ' )
drop database mlnt
go
create database test
on
(
name = ' test_data ' ,
filename = ' D:"SQLSERVER2000"MSSQL"Data"test_data.mdf ' ,
size = 10mb,
filegrowth = 10 %
)
log on
(
name = ' test_log ' ,
filename = ' D:"SQLSERVER2000"MSSQL"Data"test_log.ldf ' ,
size = 10mb,
filegrowth = 10 %
)