开篇废话(没时间请掠过):
这几天被老大选做部里数据库服务器管理的维护人员了(惊,难道强人都外派了?还是部里其他人太忙了?)
于是,数据库服务器的维护重任交给了某,不光需要管好数据库的备份工作,还有数据维护工作(这个才是重点)。日方那边由于customize的项目,式样一直在变更,于是列的增、删、改称为了家常便饭(也没那么夸张)。个人在工作中发现增加列的确很简单,甚至连某些约束建立都一条语句完成了,给日后维护带来许多不便(虽然根据式样excel是写了VBA自动生成SQL脚本,但是也不是万能的,必要的时候还得靠自己手写)。
好吧,让我们进入正题。
————————还是这条分割线——————
说明:
这里的T-SQL语句主要面向SQL Server 2005,如果要是2000或者Oracle数据库,可以查询一下某些对象名以及列名在相应环境下的设定,这里不详细区分。必要的说明会在脚本的后面出现。
SQL语句中的符号示例:
“[]“,表示列、表等对象
”|“,本符号的左右表示可选的多个参数,不可以省略
”()“,圆括号内的内容为可选内容,可以选择省略(这里不详细介绍默认值,必要时才说明)
正文:
1、给已经存在的表增加列
废话少说,在已经建立的数据库表中,增加列是很容易的事情。尝试一下SQL语句
ALTER TABLE TABLE_NAME ADD
[COLUMN1] DATA_TYPE(DIGIT) (NOT NULL) (DEFAULT ‘DEFAULT_VALUE’)
[COLUMN2] DATA_TYPE(DIGIT) (NOT NULL) (DEFAULT ‘DEFAULT_VALUE’)
[COLUMN3] DATA_TYPE(DIGIT) (NOT NULL) (DEFAULT ‘DEFAULT_VALUE’)
…
[COLUMNN] DATA_TYPE(DIGIT) (NOT NULL) (DEFAULT ‘DEFAULT_VALUE’)
NOTE:
这里的数据类型后面的位数括号必须要加(废话),是否允许为空以及默认值可以选择不指定。
指定表中的数据是否用新添加的或重新启用的 FOREIGN KEY 或 CHECK 约束进行验证。如果没有指定,对于新约束,假定为 WITH CHECK,对于重新启用的约束,假定为 WITH NOCHECK。
ATTENTION:
增加多列,不需要像CREATE TABLE那样在所有列两边加上括号,加了就会报错(工作中曾经加过,出现的低级错误),此外,如果设置默认值的话,则默认值的约束会以系统默认随机命名(后面会有牵涉到)。
如果报错,可能的情况一般也只有表不存在或者列重复或者单纯的语法错误了。
2、重命名列
查了比较多资料,有什么 RENAME TO的,有什么MODIFY的,试过都报错。最后还是用SS2005的系统存储过程了。尝试以下SQL语句:
sp_rename ‘([SCHEMA_NAME].)[TABLE_NAME].[OLD_COLUMN_NAME]‘,‘NEW_COLUMN_NAME’,‘OBJECT_TYPE’
NOTE:
其实这个系统存储过程是更改DBMS中大多数对象的一个方法,第一个参数为原列名,schema名可以不必写,但是表名必须写,否则将报寻找不到列的错,最后的类型可以是column,database,index,object(其中可以是constraint/foreign key/primary key/unique)。
ATTENTION:
第二个参数两个单引号里即为新列的全名,比较容易犯的错误是将这个参数写成’[column_name]‘,那么最后出现的列名即为”[column_name]“(含两边的方括号)。
有一点是,如果SS2005开启了大小写敏感,那么sp_rename这个存储过程名必须是小写的,否则会报错。
此外,如果更改的是PK中的列,那么PK也会自动更改。但是FK和trigger以及用户自定constrain不会更新,相反有constraint的列还会报错,有constrain依赖于此列。
(如果有人知道,不用次方法改而直接用SQL语句,欢迎联系某,Email:aleiphoenix@gmail.com)
3、删除列
如果欲删除的列没有任何约束,如PK、constrain以及被参照FK(似乎SS2005中参照FK也不能删),那么可以尝试使用以下SQL语句:
ALTER TABLE [TABLE_NAME] DROP COLUMN [COLUMN_NAME]
NOTE:
本句似乎没有一句完成多列操作,需要删除多列,只能重复写。
而大多数情况下,需要删除的列都会有约束,那么我们只能选择先删除依赖于此列的约束(似乎别无选择)。
凑巧我们在建立某些约束,比如默认值的时候往往不会给约束起名,那么这个过程将是特别痛苦的。
某在翻阅了一些资料以及网友的提示下找到了一个还算可以的方法来删除这些约束后删除那个该死的列。
(如果该列位于PK、FK或其他constraint内,那么我们别无选择,只能先删除约束后再重新建立,这里不再详细介绍,在本主题内不是重点:))
尝试使用以下SQL语句:
DECLARE @DFID NVARCHAR(50),
@CONSOID NVARCHAR(50)
–GET THE COLUMN ID YOU WANT TO DROP
SELECT @DFID = OBJ.DEFAULT_OBJECT_ID FROM sys.columns OBJ WHERE OBJ.NAME = ‘TESTCOLUMN2’
SELECT @CONSOID = OBJ.NAME FROM sys.objects OBJ WHERE OBJ.OBJECT_ID = @DFID AND (OBJ.TYPE IN (N’D’))
–EXECUTE DROPING COLUMN
EXEC(‘ALTER TABLE [DEMOOFDROPCOLUMN] DROP CONSTRAINT ‘+ @CONSOID)
ATTENTION:
这里的sys.columns与sys.objects为系统对象,同样在开启大小写敏感的时候必须小写。
NOTE:
这里运用T-SQL编程获得在欲删除列上的默认值约束,将其删除后就可以用之前提到的语句来删除该列了。
第一句寻找欲删列上默认值约束对象的对象ID,第二句利用这个对象ID将其定位并删除。
sys.columns对象里包含了所有该数据库的列,可以使用以下语句查看具有哪些字段:
select * from sys.columns
同样,我们也可以使用
select * from sys.objects
来查看数据库中的所有对象,它包含table、各种constrain、trigger、index等,同样可以利用其中的字段来达成某些目的。
在这里,我们使用了columns对象的default_object_id列,它指向该列默认值约束对象的object_id(不会重复,相当于PK),利用两次查询我们就可以精确获得该列的默认值约束ID,便可以将其删除。
这里是一张上例使用到的列的情况截图,相信能够帮助大家更直观的理解。
还是在那句SQL中可以看到where条件中使用了”type in (N’D’)“,这个字段表明了该对象的类型,已知的有:U代表table,D代表default等,可以利用前面的SQL语句查看还有哪些类型。
此外,我们还能用名字来寻找对象,一般我们在创建默认值约束的时候不会指定名字,而是利用系统自动分配,它的明明规则是”DF[表名或其一部分][列名或其一部分]__[6位随机字母数字(似乎是16进制的1~9以及A~F)]“,其中各部分之间有2条下划线,当表名和列名太长时只截取一部分。故而容易造成以规律编号的列中无法找到规律的默认值约束情况发生,所以还是先前提到的那段方法更通用。
最后,如果你嫌麻烦,同时数据库也不是工作中严格禁止出现设计上没有的对象时(比如这是你私人网站的数据库),那么完全可以写成一个存储过程便于日后经常调用。
——————分割线呀分割线——————
后记:
上班时候遇到的问题翻了几本书都说的太浅,身边一本Oravle必备参考却不适用于SS2005(毕竟系统对象以及系统存储过程不一样),加之公司的电脑VS居然MSDN搜索会卡死,于是经过网上翻了一些资料以及回家查MSDN后总结如上。
这里仅为一个解决问题的思想,有抛砖引玉之意,希望对迫切需要解决方案的同学有所帮助:)