sql 随笔
sql有两个组成部分:
DML data manipulation language 数据操作语言 他们是select,update,insert,delete
DDL data definition language 数据定义语言 主要命令有:create alter drop等 主要用于定义和改变标的结构、数据类型、表之间的链接和约束等初始化工作,大多在建立表时使用。
数据类型:
char 每字符1字节,最大8000字节
varchar 每字符1字节,最大8000字节
text 每字符1字节,最大2GB字节
nchar 每字符2字节,最大4000字节
nvarchar 每字符2字节,最大4000字节
ntext 每字符2字节,最大4000字节
char,nchar固定字符,长度不够用空格补充
varchar,nvarchar 可变长度字符
xml类型 最大2GB 文档最多会吃128层次
空间数据类型: geometry 存储点、直线、曲线、多边形数据 geography 存储GPS经纬度坐标和椭圆体数据
hierachyID 组织分成数据
列的属性: 3种: 排序规则,标识,允许null值 identity(1,2) 从1开始的奇数数据
创建计算列: create table test (id int ,price decimal,num int, total as price*num)
新增列 alter table test add author varchr(100)
稀疏列: 表中有些列,值允许为null,但是根据数据类型的定义,有些空间可以通过属性sparse属性来达到节约空间的效果
create table test (id int, address varchar(50) sparse null)
创建带主键约束的表:
create table test (id int identity(1,1) ,constraint pk_id primary key (id))
在现有的表中添加主键约束: alter talbe test add constraint pk_id primary key (id)
一个表中只有一个主键,主键列不能有null值
创建唯一性约束的表: create table test (id uniqueidentifier rowguidcol unique,constraint pk_id primary key (id))
聚集索引:可以定义某个索引使用表中的一列或多列规定数据在表中的物理存储顺序。 限制:定义一个索引至多使用16列 索引键最大为900字节 一张表中只能定义一个聚集索引
索引未看完
数据检索:Functions(Transact-SQL)
函数 cast convert 来改变数据类型 select cast(addressId as varchar(30)) select convert(varchar(30),addressId) convert还可以允许日期和时间数据类型指定一个格式串作为一个参数 select convert(varchar(30),getdate(),2) --13.10.10 select convert(varchar(30),getdate(),3) --10/10/13
函数ISNULL和coalesce可以用null来替换一个值 select isnull(address,'') select coalesce(address,'')
sarg (searchable arguments)用于限制搜索的一个操作
distinct查询返回唯一行集
group by查询的列必须包括在gourp by里面会限制查询结果,可以通过嵌入select语句来实现结果集的查询:
select b.id,b.title a.num from (select title ,count(*) num from test group by title ) a inner join test b on a.title=b.title
聚合结果集:
在批处理操作多个结果集时,如果结果集有相同的机构,可以使用union/union all 操作符将他们结合为单个结果集。 union操作符在结合多个结果集的同时消除了重复键,而union all 则会保留重复值。
T-SQL设计了两种操作符用于快速比较两个结果集
intersect 返回intersect操作符左右两边的两个查询都返回的所有非重复值
except则从左查询中返回有查询没有找到的所有非重复值
select productid from product intersect select productid from product2 相当于: select productid from product inner join product2 on product.productid=product2.productid select productid from product except select produtid from product2
根据union all 来进行分组
SELECT * FROM v3_pay_list2 where ( (ought_date >= '2012-12-06') and (ought_date <'2013/9/16 0:00:00') and (corp_id = '0001')) union all select 'XXXXXXXXXX', corp_id,dep_id,dep_name,vendor_id,'','', sum(amt),'','',vendor_pay,vendor_approval from (select * from v3_pay_list where ( (ought_date >= '2012-12-06') and (ought_date <'2013/9/16 0:00:00') and (corp_id = '0001')) ) u1 group by corp_id,dep_id,dep_name,vendor_id,vendor_pay,vendor_approval union all select 'YYYYYYYYYY', corp_id,dep_id,dep_name,'Z','','',sum(amt),'','',vendor_pay,vendor_approval from (select * from v3_pay_list where ( (ought_date >= '2012-12-06') and (ought_date <'2013/9/16 0:00:00') and (corp_id = '0001')) ) u2 group by corp_id,dep_id,dep_name,vendor_pay,vendor_approval union all select '','','ZZZZZZZZZZ','','','','',sum(amt),'','',max(vendor_pay),max(vendor_approval) from (select * from v3_pay_list where ( (ought_date >= '2012-12-06') and (ought_date <'2013/9/16 0:00:00') and (corp_id = '0001'))) u3 having sum(amt) is not null order by dep_id ,vendor_id ,compare_list_id
可以用后面这几列进行小计 和合计的计算
merge语句 sqlserve 2008 新特性 merge提供了一种在单个语句中执行多项insert,update和delete操作的方法。 假设表中存在某条数据,则将其更新,否则将其插入:
创建表:
CREATE TABLE productInventory ( productId INT NOT NULL, quantiry INT NOT NULL, CONSTRAINT pr_productId PRIMARY KEY CLUSTERED(productId) ) CREATE TABLE productShipment ( productId INT NOT NULL, quantiry INT NOT NULL, RECEIVEDate DATE NOT NULL CONSTRAINT df_receivedate DEFAULT GETDATE(), CONSTRAINT pk_productid PRIMARY KEY CLUSTERED (productId) ) 插入数据: INSERT INTO productInventory (productId,quantiry) VALUES(1,10) INSERT INTO productShipment (productId,quantiry) VALUES (1,20) 执行操作: MERGE productInventory AS targets USING (SELECT productId,quantiry FROM productShipment WHERE receivedate=CAST (GETDATE() AS date)) AS soruce ON targets.productid=soruce.productid WHEN MATCHED THEN UPDATE SET targets.quantiry=targets.quantiry+soruce.quantiry WHEN NOT MATCHED BY TARGET THEN INSERT (productid,quantiry) VALUES(soruce.productid,soruce.quantiry); go
matched(相配的意思)
Exec 的使用: Exec 存储过程的名称|(结构化语句)
eg:
declare @selectpr varchar(max) set @selectpr= ' select top 10 * from pr_na_b ' exec (@selectpr)
或者 Exec sp_executesql N'select top 10 * from pr_na_b'
或者 declare @selectpr nvarchar(max) --必须是ntext/nchar/nvarchar set @selectpr='select top 10 * from pr_na_b' sp_executesql @selectpr
DML触发器是基于表或者视图创建,并且为某些特定的事件(insert/update/delete)而定义。
After 触发器只能在表上定义。 Instead Of 触发器总是针对视图而建。
触发器里面可以运行在事务的上下文中
GO CREATE TRIGGER td_admi1n ON dbo.Admin_Info FOR DELETE AS IF NOT EXISTS (SELECT * FROM dbo.Admin_Info WHERE Admin_Id=2) BEGIN ROLLBACK TRANSACTION RAISERROR ('error',10,1) END ELSE BEGIN RETURN END GO
raiserror 的作用
raiserror 用于抛出一个错误
RAISERROR ( { msg_id | msg_str | @local_variable } { ,severity ,state } [ ,argument [ ,...n ] ] ) [ WITH option [ ,...n ] ])
第一个参数:{ msg_id | msg_str | @local_variable } msg_id:表示可以是一个sys.messages表中定义的消息代号; 使用 sp_addmessage 存储在 sys.messages 目录视图中的用户定义错误消息号。 用户定义错误消息的错误号应当大于 50000。
msg_str:表示也可以是一个用户定义消息,该错误消息最长可以有 2047 个字符; (如果是常量,请使用N'xxxx',因为是nvarchar的) 当指定 msg_str 时,RAISERROR 将引发一个错误号为 5000 的错误消息。
@local_variable:表示也可以是按照 msg_str 方式的格式化字符串变量。 第二个参数:severity 用户定义的与该消息关联的严重级别。(这个很重要) 任何用户都可以指定 0 到 18 之间的严重级别。 [0,10]的闭区间内,不会跳到catch; 如果是[11,19],则跳到catch; 如果[20,无穷),则直接终止数据库连接;
第三个参数:state 如果在多个位置引发相同的用户定义错误, 则针对每个位置使用唯一的状态号有助于找到引发错误的代码段。 介于 1 至 127 之间的任意整数。(state 默认值为1) 当state 值为 0 或大于 127 时会生成错误!
第四个参数:argument 用于代替 msg_str 或对应于 msg_id 的消息中的定义的变量的参数。
第五个参数:option 错误的自定义选项,可以是下表中的任一值: LOG :在错误日志和应用程序日志中记录错误; NOWAIT:将消息立即发送给客户端; SETERROR:将 @@ERROR 值和 ERROR_NUMBER 值设置为 msg_id 或 50000;
DDL 触发器:
可以在数据库级别或者实例级别定义DDL触发器。 使用 ON ALL SERVER 选项时即在实例级别定义了一个DDL触发器。 如果需要在数据库级别定义一个DDL触发器,则可以使用 ON DATABASE
eg:
GO CREATE TRIGGER ddL_tabler ON DATABASE FOR DROP_TABLE,ALTER_TABLE AS PRINT 'dd' ROLLBACK;
DML触发器可以对被插入和被删除的表进行访问,而DDL触发器可以对EVENTDATA()函数进行访问,函数返回下面的xml文档,这个xml文档可以通过xquery的value()方法进行查询
-- 创建一个Drop Table 的 DDL CREATE TRIGGER StopTableDrop ON DATABASE AFTER DROP_TABLE AS DECLARE @EventData AS xml SET @EventData = EVENTDATA() -- 必须要在rollback之前截获DDL信息 ROLLBACK PRINT 'DROP TABLE attempt in database ' + DB_NAME() + '.' INSERT INTO TriggerLog VALUES(@EventData)
执行如下删除操作:
DROP TABLE TableToDelete
会触发上面的DDL,从而回滚操作。
执行下面的Sql:
SELECT * FROM TriggerLog
查看刚才截获的DDL信息。
用实例创建触发器:
CREATE TRIGGER tddl_product ON ALL SERVER FOR logon AS begin IF (SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process=1 AND login_name =SUSER_SNAME())>5 PRINT 'cc' ROLLBACK END go