SQL-Server使用点滴(二-系统表)
二,对象的建立和使用
1,了解MSSql的【系统表】
对于SQL-Server中的所有对象,包括数据库,数据表,记录,字段,触发器,索引,数据类型等元素,均有对应的系统表记性记录。系统表是禁止直接删改的,它的内容会随着各种系统级别的操作由系统自动更新其内容。虽然我们不能直接更改,但是我们可以读到其中的内容,这对我们对当前系统中的各种元素的增删改可以起着动态判断的作用。所以对系统表的了解是十分必要的。SQL-Server的系统表非常多,但是常用的只有几个视图:
1>,sysobjects 这是个系统视图,但是可以省略掉系统库前缀sys.。这是我们访问频率最高的系统表,包含几乎全部的对象主属性。sysobjects在SqlServer2000中是一个系统表,但是到了SqlServer2005当中,就变成了一个视图,同时它可以映射到sys.objects,并且sysobjects是在每一个库中都可以默认访问的,可以省略sys.而sys.objects不能省略。
a>[Name]字段,对象名,对应当前SQL库中的所有对象。
b>[id]字段,主键,几乎所有其他的系统表都会保留一个对应此主键的外键。
c>[xtype]字段,记录每一个对象的类型。其标志意义为:
AF(用户自定义的聚合函数CLR),C(Check约束),D(默认值约束),F(外键约束),FN(标量函数),FS(CLR标量函数),FT(CLR表值函数),
IF(内联表函数,相当于一个有参数的视图,或动态结构的表值函数),IT(外部表),P(存储过程),PK(主键约束),RF(系统表),SN(服务队列),
S(系统函数),SO(序列),TA(CLR触发器),TR(DML触发器),TF(表值函数),TT(表类型),U(用户表),UQ(唯一性约束),V(视图),
d>[type]兼容系统视图sys.objects,但是与其有些不同。
2>,syscolumns 同样是从SqlServer2000由系统表过度过来的视图,映射sys.columns,其中记录着所有的字段信息。其对应字段如下:
a>[Name]字段,字段名称,对同一个表是唯一的。
b>[id]字段,外键,关联着sysobjects中的主键,一般来说,关联的记录都是用户表,也有可能是系统表,表值函数,视图等等。
c>[xtype][xusertype],对于常规的标量字段,这两个字段是一致的。但是对于具有用户自定义类型的字段,xtype代码的是数据库物理存储类型,而xusertype是用户类型。
d>[length]字段,占用的物理字段长度,一般来说int是4字节,decimal(19,x)是9字节,varchar(n)长度是n,而nvarchar(n),长度是2*n,bit长度是1,时间datatime长度是8.
e>[xprec]字段,数据的10进制有效位数,也称为精度。这个属性只针对数值型的字段(时间其实也是实型存储)有效,其他的都是0。int精度是10,decimal(n,x)精度是n,bit精度是1,时间精度是23.
f>[colid]字段,这个字段对于同一张表是唯一的,代表着每个字段的顺序号,可以认为[id]+[colid]就可以构成此系统视图的组合键值。
值得注意的是,SQL2008以前,直接按对应表查询syscolumns的信息,其默认排序都是跟建表顺序规则一致的(即一个表字段从左到右的默认顺序),是自动按照colid排序的。但是从SQL2012开始,查询syscolumns信息时,必须使用order by colid才能保证顺序。
g>[cdefault]字段,外键默认约束ID,对应着系统表sys.default_constraints的[OBJECT_ID]字段,或者sysconstraints表的constid字段。
h>[domain]字段,外键Check约束ID,对应着系统表sys.check_constraints的[OBJECT_ID]字段,或者sysconstraints表的constid字段。
i>[type]字段,兼容sys.columns的type字段属性。
j>[usertype]字段,外键用户定义类型表,对应的系统表systypes的uid字段,如果是系统默认的标量类型,uid=4。
k>[scale]字段,小数位数。
l>[iscomputed]字段,是否计算字段。
m>[isnullable]字段,是否允许空值。
n>[collation]字段,字符编码区位代码。简体一般是Chinese_PRC_CI_AS。
3>,systypes表,记录着所有系统数据类型的定义,映射sys.types,其具体属性字段跟syscolumns类似,只是少了一些与字段有关的信息,这里不作细讲,仅列出常用的查询字段:name,xtype,xusertype,length,xprec,xscale,tdefault,domain,uid,reserved,collationid,usertype,allownulls,type,prec,scale,collation。
4>,sysdatabases表,记录着当前服务器中所有数据库信息。
a>[Name],数据库名。
b>[dbid],数据库的主键。
c>[sid],数据库创建者的ID,关联系统表sysusers中的uid。
d>[crdate],创建数据库的日期。
e>[filename],数据库文件的路径及文件名。
f>[version],创建数据库时的SqlServer内部版本号。
5>,其他的有用的系统表
a>syslanguages: 系统多语言表。
b>sysindexes: 系统索引信息表,映射sys.indexes.
c>sysusers:系统用户表。
d>sysaltfiles:当前服务器中,所有数据库文件清单。
e>syslockinfo:系统锁定信息表,映射dm_tran_locks.
f>syslogins: 用户登录信息表。
g>sysmessages : Sql消息表。
h>sysservers : SQL服务列表。
i>syscomments: 保存所有的过程,函数,约束,视图的文字代码信息。
j>sysconstraints:触发器关系表,映射sys.check_constraints,sys.default_constraints,sys.key_constraints,sys.foreign_keys,相当于sysobjects子集。
k>sysfiles : 当前库的数据库文件列表。
l>sysreferences :外键信息表,映射sys.foreign_keys。
2,了解【元数据函数】,所有的元数据函数都是基于1中的系统表进行查询操作的,但是作为内部函数,比用Select查询系统表的速度更快。注意:所有的元数据函数均为不确定性函数(其返回值会随系统环境的变化而改变)。
1>,COL_LENGTH,COL_NAME,COLUMNPROPERTY:这三个函数是跟字段有关的,相当于是查询syscolumns表,分别为返回字段的长度,名称,指定属性等等。参数格式如下:
a>COL_LENGTH ( 'table' , 'column' ) 。 根据表名,字段名返回字段长度。
b>COL_NAME ( table_id , column_id )。根据表id,列id返回字段名。
c>COLUMNPROPERTY ( id , column , property )。id为表id,column为列名称,property为一个枚举组,大都返回True或者False值(0,1)。枚举表为:
AllowsNull(是否可空),IsComputed(是否计算列),IsCursorType(表参数是否游标),IsDeterministic(是否确定性,只对视图计算列有效,否则返回null),
IsFulltextIndexed(是否为全文索引列),IsIdentity(是否自增列),IsIdNotForRepl(对自增列,是否检查IDENTITY_INSERT设置),IsIndexable(该列是否可索引),
IsOutParam(是否为输入参数),IsPrecise(是否精确列,只针对确定列),IsRowGuidCol(是否为RowGuidCol定义的UniqueIdentifier列),Precision(精度),
Scale(小数位),UsesAnsiTrim(ANSI填充设置是否为ON)。
2>,DB_ID,DB_NAME;OBJECT_ID,OBJECT_NAME; FILE_ID,FILE_NAME;FILEGROUP_ID,FILEGROUP_NAME:这几组函数都是对应和互逆的,就是ID和NAME的互相转换,其函数的返回值恰恰可以作为ID或NAME对应函数的参数。其信息对应的系统表分别为sysdatabases,sysobjects,sysfiles,sys.filegroups。
3>,OBJECTPROPERTY,TYPEPROPERTY,DATABASEPROPERTY,DATABASEPROPERTYEX,FILEPROPERTY, FILEGROUPPROPERTY, FULLTEXTCATALOGPROPERTY: 这组函数,全部都是针对某对象查其特定属性的函数,参数都是(Name,Property)形式,分别是查对应的对象,数据类型,数据库,文件,全文目录等内容。
4>,INDEX_COL,INDEXKEY_PROPERTY,INDEXPROPERT:前两个用得比较少,第三个用的比较多,都是查询有关索引内容的。
5>,SQL_VARIANT_PROPERTY :返回SQL_VARIANT类型表达式的属性信息。
6>,@@PROCID:用在过程的创建语句当中,有点类似Delphi的Self或者C#的this,可以得到该过程的ID值。
3,数据表,函数,过程,触发器,序列,索引,约束,映射服务器等SQL对象的智能创建。
结合系统表和元数据函数,我们可以制作智能创建对象的脚本,这样的脚本可以反复运行,有利于工程中进行自动升级更新的设置。
1>,数据库的创建:
IF NOT EXISTS(SELECT 1 FROM sysdatabases WHERE name='DBName')
CREATE DATABASE DBName
1>,数据表的创建:
IF NOT EXISTS(SELECT 1 FROM sysobjects WHERE name='TBName' AND xtype='U')
CREATE TABLE TBName(...)
2>,字段的增删与类型更改:
增删判断:
IF NOT EXISTS(SELECT 1 FROM syscolumns WHERE id=object_id('TbName') AND name='ColName')
ALTER TABLE TbName ADD ColName ColType
更改字段类型:(这个需要肯定这个字段已经存在的前提下,否则需要进行跟增删判断一样的第一步)
IF COLUMNPROPERTY(OBJECT_ID('TbName'),'ColName','PRECISION')=20 //常用于Decimal或nvarchar类型的长度更改。
Alter table TbName ALTER COLUMN ColName TypeName
IF EXISTS(SELECT 1 FROM syscolumns A INNER JOIN systypes B ON A.xtype=B.xtype //常用于完全并不兼容的数据类型的转换。
WHERE A.id=OBJECT_ID('TbName') AND A.name='ColName' AND B.name='TypeName')
Alter table TbName ALTER COLUMN ColName TypeName
3> ,判断存储过程,函数,视图,触发器,序列,约束等对象是否存在
IF NOT EXISTS(SELECT 1 FROM sysobjects WHERE name='TBName' AND xtype='Sign')
这里的Sign常用P,FN,V,TR,SO,PK,D,UQ,C,
由于常用CLR或表值函数等,所以对函数的判断也常写作:xtype in ('FN','IF','TF','FS')
IF NOT EXISTS(SELECT 1 FROM sysobjects WHERE name='SEQ_NewIden' AND xtype='SO')
CREATE SEQUENCE dbo.SEQ_NewIden AS BIGINT START WITH 10000
4>,判断临时表是否存在
IF object_id('tempdb..#TbName') IS NOT NULL
也可以用:
IF EXISTS(SELECT 1 FROM tempdb.sys.objects WHERE TYPE='U' AND name='#TbName')
5>,判断是否自增列
IF COLUMNPROPERTY(OBJECT_ID('TbName'),'ColName','IsIdentity')=1
6>,判断表是否存在索引
IF NOT EXISTS(SELECT 1 FROM sysindexes WHERE id=OBJECT_ID('TbName') AND name='IxName')
Create Index ixName On TbName(ColName)
7>,删除默认约束名(因为系统自动添加的约束,名称是乱的,不方便控制),这里可以用动态SQL实现。
IF EXISTS(SELECT 1 FROM sysobjects WHERE parent_obj=OBJECT_ID('TbName') AND xtype='PK')
BEGIN
DECLARE @name sysname
SET @name=(SELECT name FROM sysobjects WHERE xtype='PK' AND parent_obj=OBJECT_ID('TbName'))
EXEC(N' ALTER TABLE TbName DROP CONSTRAINT '+@name)
End
4,几个有用的系统表过程事例
1>,返回一个表的全部字段名串,常用于插入语句的字段列表录入
CREATE PROC P_columnList
@object sysname
--WITH ENCRYPTION
AS
SET NOCOUNT ON
DECLARE @columns VARCHAR(4000)
set @columns=''
SELECT @columns=@columns+','+b.name
FROM sysobjects a,syscolumns b
WHERE a.name=@object and a.xtype='U' and a.[id]=b.[id]
ORDER BY b.colid
PRINT @columns
SET NOCOUNT OFF
RETURN 0
2>, 返回一个表的全部信息,可以用来制作数据字典:
If Exists(Select top 1 1 From sysobjects Where Name='P_TableStructure' and Type='P')
Drop Proc P_TableStructure
Go
CREATE PROC P_TableStructure
@TableName VARCHAR(255)
WITH ENCRYPTION
AS
select
--
[表名]=case when a.column_id=1 then c.Name else '' end,
[表说明]=case when a.column_id=1 then ISNULL(f.[value],'') else '' end,
[列序号]=a.column_id,
[列名]=a.Name,
[标识]=case when is_identity=1 then'√' else '' end,
[主键]=case when exists(select 1 from sys.objects x join sys.indexes y
on x.type=N'PK' and x.name=y.name join sysindexkeys z
on z.id=a.
object_id and z.indid=y.index_id and z.colid=a.column_id)
then '√' else '' end,
[类型]=b.Name,
[长度]=Case when a.[max_length]=-1 and b.Name!='xml' then 'max/2G' when b.name='xml'
then '2^31-1字节/2G' else RTRIM(a.[max_length]) end,
[精度]=case when COLUMNPROPERTY(a.object_id,a.name,'precision')=-1 then '2^31-1'
else RTRIM(columnproperty(a.object_id,a.name,'precision')) end,
[小数]=ISNULL(columnproperty(a.object_id,a.name,'scale'),0),
[可空]=case when a.is_nullable=1 then '√' else '' end,
[默认值]=ISNULL(d.text,''),
[描述]=ISNULL(e.[value],'')
from
sys.columns a
left join
sys.types b on a.user_type_id=b.user_type_id
inner join
sys.objects c on a.object_id=c.object_id and c.type='U'
left join
syscomments d on a.default_object_id=d.id
left join
sys.extended_properties e on e.major_id=c.object_id and e.minor_id=a.column_id and e.class=1
left join
sys.extended_properties f on f.major_id=c.object_id and f.minor_id=0 and f.class=1
where c.name=@TableName ---这里加上要查的表名
ORDER BY 列序号
3> 这里再讲一个有用的系统视图INFORMATION_SCHEMA.KEY_COLUMN_USAGE,它可以查询所有的键值和唯一约束信息
先把这个视图内容列一下:
CREATE VIEW INFORMATION_SCHEMA.KEY_COLUMN_USAGE
AS
SELECT
DB_NAME() AS CONSTRAINT_CATALOG,
SCHEMA_NAME(f.schema_id) AS CONSTRAINT_SCHEMA,
f.name AS CONSTRAINT_NAME,
DB_NAME() AS TABLE_CATALOG,
SCHEMA_NAME(p.schema_id) AS TABLE_SCHEMA,
p.name AS TABLE_NAME,
col_name(k.parent_object_id, k.parent_column_id)
AS COLUMN_NAME,
k.constraint_column_id AS ORDINAL_POSITION
FROM
sys.foreign_keys f JOIN sys.foreign_key_columns k
ON k.constraint_object_id = f.object_id
JOIN sys.tables p ON p.object_id = f.parent_object_id
UNION
SELECT
DB_NAME() AS CONSTRAINT_CATALOG,
SCHEMA_NAME(k.schema_id) AS CONSTRAINT_SCHEMA,
k.name AS CONSTRAINT_NAME,
DB_NAME() AS TABLE_CATALOG,
SCHEMA_NAME(t.schema_id) AS TABLE_SCHEMA,
t.name AS TABLE_NAME,
col_name(c.object_id, c.column_id) AS COLUMN_NAME,
c.key_ordinal AS ORDINAL_POSITION
FROM
sys.key_constraints k JOIN sys.index_columns c
ON c.object_id = k.parent_object_id
AND c.index_id = k.unique_index_id
JOIN sys.tables t ON t.object_id = k.parent_object_id
我们可以看到,这个视图中,引用了另外的5个视图,并把主要的信息列出来,我们通过它可以对那些系统自动命名的键值和索引进行操作。
例如,我们要给一个表的主键改名或者重建,但是并不清楚其主键约束名,假设表名为TbNameX, 我们要建的新主键约束名为PK_TbNameX_PrimaryKey
IF EXISTS(select 1 from information_schema.key_column_usage where TABLE_NAME='TbNameX' AND COLUMN_NAME='uGuid')
IF exists(SELECT TOP 1 CONSTRAINT_NAME from information_schema.key_column_usage
where TABLE_NAME='TbNameX' AND COLUMN_NAME='uGuid' AND CONSTRAINT_NAME<>'PK_TbNameX_PrimaryKey')
BEGIN
DECLARE @PK_primary_temp VARCHAR(255), @SqlTemp VARCHAR(2048)
SET @PK_primary_temp=(SELECT TOP 1 CONSTRAINT_NAME from information_schema.key_column_usage where TABLE_NAME='TbNameX')
SET @SqlTemp =' ALTER TABLE TbNameX DROP CONSTRAINT '+@PK_primary_temp
EXEC(@SqlTemp)
END
GO
--为从表建立主键约束
if not exists(select * from sysindexes where id=object_id('TbNameX') and name='PK_TbNameX_PrimaryKey')
ALTER TABLE TbNameX ADD CONSTRAINT PK_TbNameX_PrimaryKey PRIMARY KEY CLUSTERED([uGuid])
GO