hyqs
--###################################################################################
/*  缩写:
    DDL(Database Definition Language): 数据库定义语言
    DML(Database Manipulation Language): 数据库操作语言
    DCL(Database Control Language): 数据库控制语言
    DTM(Database Trasaction Management): 数据库事物管理

    知识概要:
            |---1.查询Select
            |
            |---2.数据库定义语言DDL: 对表,视图等的操作, 包括create,drop,alter,rename,truncate
            |
 数据库操作--|---3.数据库操作语言DML: 对记录进行的操作, 包括insert,delete,update
            |
            |---2.数据库控制语言DCL: 对访问权限等的操作, 包括grant,revoke
            |
            |---2.数据库事物管理DTM: 对事物的操作, 包括commit,rollback,savepoint

    事物的是由DML(insert,delete,update)开启的;
    而引起事物的提交或结束原因有:
    1.DTM操作: commit,rollback,savepoint
    2.系统崩溃宕机: 隐式rollback
    3.正常:    隐式commit
    4.DDL和DCL操作: DDL(create,drop,alter,rename,truncate)
                    DCL(grant,revoke)
    
    注意MS-Sql的特殊处:
    MS-Sql中的事物: 自动事物(commit)和手动事物(begin transaction). 
                    在Sql中DML(insert,delete,update)会引起自动事物commit, 而Oracle中不会
    MS-Sql的参数: 只能返回0或非0(如: 1,2)数字
    MS-Sql的存储过程: 一定会有返回值(return value), 默认返回0(成功). 在程序获取改值, 需要创建return参数对象(添加到参数列表), 并设定其方向.

    MSSqlServer的登录过程分两种:
    1. Windows集成验证: windows用户名和口令 -> SqlServer登录列表 -> 映射到用户列表    -> 登录成功
    2. SqlServer验证: Sql用户名和口令 -> 映射到用户列表 -> 登录成功
    两种登录方式的连接串:
    string connectionStr = "data source=.;database=Test;user id=sa;password=sa";
    string connectiongStr ="data source=.\sqlexpress;database=Test;integrated security=true";
    
    
    数据库设计原则:
    1. 数据库设计指导原则(关系数据库中的数据通过表来体现): 先确定表后确定业务字段.
    每个业务对象在数据库中对应一张表(若业务对象复杂则可对应多张表), 业务对象间每有一个关系也要对应一张表.
    注意: 业务字段需要跟项目结合, 例如: 学生的健康情况可以用一个字段(优、良等)表示, 但针对健康普查, 学生的健康情况需进一步划分为身高、体重、血压等
    如: 学校中的学生对象: 学院表(学院ID, 专业ID); 专业表: 专业表(专业ID, 专业名);学生表(学生ID, 学院ID,专业ID)

    2. 数据库设三大计原则:
    a. 完整性: 设计方案能够保存项目中的各种信息(要全)
    b. 低冗余: 通过主键保证记录的不重复、通过表间关系减少冗余字段
    c. 尽可能满足3范式(NormalForm): 1NF: 1个字段只能包含一个业务信息片(即项目中的业务字段表示的信息不可再分)
                                    2NF: 能找到1个或多个字段的组合, 用来唯一的确定表中的记录(即必须有主键).
                                    3NF: 主键唯一且直接确定表中的其他字段(即无传递依赖, 如: 教师id, 办公室id, 办公室电话关系中存在传递依赖)
    注意事项: 尽可能不用业务字段做主键, 通常的手段为自增列当主键, 并且末尾添加默认时间字段(getdate()).
              尽量采用SQL92代码, 保证可移植性. 如: 在Sql2000中, top函数只能跟常量(Sql2005可跟变量). 通用的解法为拼Query串, 用exec(query串)取结果

    备注:
    Sql中使用+拼接字符串, Oracle中使用||拼接字符串.
    C#数据类型:
        整数: sbyte,byte,short,ushort,int,uint,long,ulong
        实数: float,double,decimal
        字符: char,string
        布尔: boolean
        日期: datetime
        对象: object
        全局唯一标识: GUID
    Sql数据类型:
        整数: bit(0,1),tinyint(8),smallint(16),int(32),bigint(64)
        实数: float,real,numeric
        字符: char(8000),nchar(4000),varchar(8000),nvarchar(4000),ntext
        日期: smalldatetime(1900,1,1-2079,6,6),datetime(1753,1,1-9999,12,31)
        货比: money
              二进制: binary
        图像: image
        标识: uniqueidentity        
*/
--###################################################################################

--创建数据库:
if exists(select * from sysdatabases where [name]=\'TestStudent\')
    drop database TestStudent
go
create database TestStudent
on
(
    name = \'TestStudent_DB\',    --数据库逻辑名
    filename = \'D:\WorkCode\DB\TestStudent.mdf\',
    size = 3,
    filegrowth = 10,
    maxsize = 100
)
log
on
(
    name = \'TestStudent_Log\',
    filename = \'D:\WorkCode\DB\TestStudent.log\',
    size = 3,
    filegrowth = 10,
    maxsize = 100
)
go

--###################################################################################

use TestStudent
go

--创建表, 约束类型: 主键、外键、唯一、check约束、非空约束
if exists( select * from sysobjects where [name] = \'T_Student\' and [type] = \'U\')
    drop table T_Student
go
create table T_Student
(
    Sno        int identity(100,1) primary key,    --可以使用scope_identity获得刚生成的id
    Sname    nvarchar(50) not null,
    Sgender    nchar(1),
    Sage        tinyint check(Sage >= 20 and Sage <= 30),
    home    nvarchar(100) default(\'北京\'),
    idcard    nvarchar(18) unique
)
go
if exists( select * from sysobjects where [name] = \'T_Score\' and [type] = \'U\')
    drop table T_Score
go
create table T_Score
(
    id int primary key,
    Sno int identity(100,1) foreign key references T_Student(Sno),
    Score tinyint
)
go

--修改表结构
alter table T_Student
    add Education nchar(3)
go
alter table T_Student
    drop column Education
go

--修改表约束
alter table T_Student
    add constraint PK_Sno primary key(Sno),
        constraint CK_gender check(gender in(\'\',\'\')),
        constraint DF_home default(\'北京\') for home,
        constraint UQ_idcard unique(idcard)
go
alter table T_Score
    add constraint FK_Sno foreign key references T_Student(Sno)
go
--创建联合主键
alter table T_SC with nocheck 
    add constraint [PK_T_SC] primary key nonclustered(
    studentId,
    courseId
)
go

--###################################################################################

--新增(插入)数据
insert into T_Student(Sname,Sgender,Sage) values(\'张三\',\'\',23)
go
insert into T_Student(Sname,Sgender,Sage)
    select \'李四\',\'\',25 union
    select \'王五\',\'\',26 union
    select \'赵六\',\'\',28
go

--删除数据
truncate table T_Student    --只删除表的数据
delete from T_Student where sgender = \'\'

--修改数据
update T_Student set sgender = \'\' where sgender=\'\'

--###################################################################################

--查询数据
select * from T_Student where sgender = \'\'
select top 3 * from T_Student    --选择前三项, top 3是用来筛选记录的, 所以得紧跟select, 不用考虑字段顺序
select top 40 percent * from T_Student    --选择前百分之几的记录
select sname as \'姓名\', \'年龄\' = sage from T_Student    --起别名的两种方式as和=
select * from T_Student where sage >= 20 and age <= 30
select * from T_Student where sage between 20 and 30
select * from T_Student where sage is null
select sname into T_Stu from T_StuInfo    --用T_StuInfo中的sname字段创建新表
--模糊查询呢: 通配符: %(0-任意字符), _(1个字符),[abc](选择含a或b或c),[^abc](选择不含a或b或c)
select * from T_Student where sname like \'张%\'
select * from T_Student where sname like \'王_\'
select * from T_Student where sname like \'[张李]%\'
select * from T_Student where sname like \'[^张李]%\'

--###################################################################################

--排序: order by子句的结果将额外生成一个新表(2字段: 原位置索引字段和排好序的字段)
select * from T_Student order by Sage desc    --默认是升序asc

--###################################################################################

--聚合函数: 若有聚合函数, 即使不写group by 子句, 也会默认将表分为一个大组
select sum([sid]) from T_StuScore
select count([sid]) from T_StuScore    --count(*)表示记录数, 而count(字段)忽略掉null值
select avg([sid]) from T_StuScore
select max([sid]) from T_StuScore
select min([sid]) from T_StuScore

select distinct([sid]) from T_StuScore

--###################################################################################

--分组函数, where用于对记录的筛选, having用于对组的筛选
select gender,Counter = count(*) from T_Stuinfo group by gender
select gender,Counter = count(*) from T_Stuinfo group by gender having count(*) >= 2

--###################################################################################

--表连接: 笛卡尔积(m*n条记录), 内连接, 外连接(左外连接、右外连接、全外连接)
--笛卡尔积
select sname,[sid],cid,score
from T_StuInfo s cross join T_StuScore c on s.[sid] = c.[sid]

--内连接: 先从m和n中选择, 然后再连接
select sname,[sid],cid,score 
from T_StuInfo s inner join T_StuScore c on s.[sid] = c.[sid]

--左外连接(左连接): 内连接 + 左表剩余记录(右表记录置null)
select sname,[sid],cid,score 
from T_StuInfo s left join T_StuScore c on s.[sid] = c.[sid]

--右外连接(右连接): 内连接 + 右表剩余记录(左表记录置null)
select sname,[sid],cid,score 
from T_StuInfo s right join T_StuScore c on s.[sid] = c.[sid]

--全外连接(全连接): 内连接 + 左表剩余记录(右表记录置null) + 右表剩余记录(左表记录置null)
select sname,[sid],cid,score 
from T_StuInfo s full outer join T_StuScore c on s.[sid] = c.[sid]

--###################################################################################

--函数: 字符串函数、日期函数、数学函数、系统函数
--字符串函数
print charindex(\'1\',\'ab1cd\')    --Sql中下表从1开始, 类似于C#中indexof、lastindexof, 返回包含\'1\'的下表位置
print len(\'abcd\')    --C#中的length
print lower(\'ABCD\')    --ToLower(), ToUpper()
print upper(\'abcd\')    --ToUpper()
print ltrim(\' abcd\')    --LTrim()
print rtrim(\'abcd \')    --RTrim()
print rtrim(ltrim(\' abcd \'))    --Trim()
print right(\'abcd\',2)    --从右截取, C#中的SubString(length-3,2)截取下表从0开始的2个
print left(\'abcd\',2)    --SubString(0,2)
print replace(\'abcdef\',\'cd\',\'1234\')    --Replace(), 用1234替换cd
update [card] set [passWord] = Replace(Replace([PassWord] ,\'O\',\'0\'),\'i\',\'1\') from T_UserInfo
print stuff(\'abcdef\',2,3,\'#\')    --填充替换, 从第2个开始的3个字符替换成#
print cast(\'2010-11-08\' as datetime)    --数据类型转换
print convert(datetime,\'2010-11-08\')    --数据类型转换
print str(67)    --数字变字符串
print newid()    --新uniqueidentifier, 它将会为记录临时添加一列, 且内容是随机的
print getdate()    --获得当前日期

--日期函数
print getdate()    --DateTime.Now
print dateadd(yyyy,10,\'2010-1-2\')    --增加10年
print dateadd(mm,2,getdate())    --增加月, 其他可以查sql联机丛书
print datediff(yyyy,\'1985-12-13\',\'2010-10-10\')    --时间差距
print datediff(dd,\'1985-12-13\',\'2010-10-10\')    --时间差距
print datename(mm,\'2010-10-01\') + \'2\' --返回月份+\'2\'
print datepart(mm,\'2010-10-01\') + \'2\'    --日期10+2,结果为12

--数学函数
print abs(-100)    --求绝对值, Abs()
print ceiling(10.05)    --取整数, 如果有小数则进1
print floor(10.05)    --取整数, 忽略小数
print round(10.567,2)    --四舍五入
print power(10,2)    --求幂运算
print sqrt(108)    --求平方根
print rand(10)    --只能选择0-1之间的数, Random.Ran(0,1)
print rand(10)*10    --随机0-10之间的数
print sign(30)    --只返回±1

--系统函数
print \'abcd\' + convert(nvarchar(10),5)    --ToString()
print \'abcd\' + cast(5 as nvarchar(10))    --同上
print datalength(\'1+1=2\')    --返回表达式的字节数
print current_user    --返回当前登录的角色
print host_name()    --返回当前计算机名
print system_user    --返回当前用户id
print user_name()    --给定用户id返回其角色名
print isnull(filedname,0)    --替换null为0
raiserror(\'抛出异常\',16,1)    --抛出异常, 1-15被系统占用, 对应C#中的throw
select * from sysobjects where objectproperty(id,N\'IsUserTable\') = 1    --判断是否用户表(y=1,n=0), N表示后边的串为unicode字符串.
select * from sysobjects where type= \'U\'    --等价于上一行
select databasepropertyex(\'Northwind\',\'IsBrokerEnabled\')    --查询该库是否开启缓存技术中的通知机制, 1为开启, 0为关闭
alter database northwind set enable_broker    --开启数据库中, 缓存技术中的通知机制
--注意以下三个函数的用法    eg: 结果集(1,5,11,17,19,25)
select row_number() over(order by [sid]) from T_StuInfo        --1,2,3,4,5,6
select rank() over(order by [sid]) from T_StuInfo            --1,1,1,4,5,6
select dense_rank() over(order by [sid]) from T_StuInfo        --1,1,1,2,3,4
select ntile(2) over(order by [sid]) from T_StuInfo            --1,5  11,17  19,25

select row_number() over(order by [sid]) as sequence, sname, age, (case gender when \'0\' then \'\' else \'\' end) gender
from T_StuInfo s left join T_StuScore c on s.sid = c.sid
go

--###################################################################################

--范式: 1NF: 原子性, 2NF: 单主键, 3NF: 去除传递依赖
--E-R模型(表间关系): 1对1: 任何一个表添加外键; 1对多: 在多的一方添加外键; 多对多: 需要第三个表, 添加前两表的外键

--###################################################################################

--变量
--系统变量:
select * from T_StuInfo
print @@identity;    --获得结果集最大标识值
print @@error;    --有错误, 返回大于0的数; 无错误返回0
print @@rowcount;    --返回结果集的行数

--自定义变量
declare @age tinyint
declare @age2 tinyint
declare @name nvarchar(20)
declare @name2 nvarchar(20)

set @age = 15    --一次只能对一个量变赋值
select @name = \'张三\',@name2 = \'李四\'    --一次性给多个变量赋值
select @age2 = max(age) from T_StuInfo    --可以用在查询语句中

print @age
print @age2
print @name
print @name2

--###################################################################################

--条件表达式
declare @age int
set @age = 1

if (@age <20)
begin
    set @age = @age + 1
end
else
begin
    set @age = @age - 1
end

--循环
declare @index int
declare @sum int

set @index = 1
set @sum = 0

while (@index < 11)
begin
    set @sum = @sum + @index
    set @index = @index + 1
end
print @sum

--批处理Sql语句: 练习---打印三角形, 即成批处理语句+go即可, 只访问一次数据库
declare @row int
declare @col int
declare @n int    --总行数
declare @result nvarchar(2000)

set @row = 0
set @col = 0
set @n = 10        --可以修改n的值
set @result = \'\'

while (@row < @n)
begin
    set @col = 0    --复位
    set @result = \'\'
    while (@col < @n + @row)
    begin
        if (@col < @n - @row - 1)
        begin
            set @result = @result + \' \'
        end
        else
        begin
            set @result = @result + \'*\'
        end
        set @col = @col + 1
    end
    print @result
    set @row = @row + 1
end
go

--case when
--搜索case when(用于一个范围)
select \'评语\' = case when SqlServer>= 90 then \'优秀\'
                    when SqlServer >= 80 and SqlServer < 90 then \'\'
                    when SqlServer >= 60 and SqlServer < 80 then \'及格\'
                    else \'不及格\'
                end
from T_StuInfo

--简单case when(类似swtich, 用于一个定值)
declare @gender bit
set @gender = \'true\'
print case @gender when \'true\' then \'\' else \'\' end

--###################################################################################

--事物: 事物的特性ACID(一致性(Consistency)、原子性(Atomicity)、隔离性(Isolation)、持久性(Durability))
declare @errorcount int
set @errorcount = 0

begin transaction    --if控制事物的提交
begin
    update T_StuInfo set age = age + 1 where gender = \'\'
    set  @errorcount = @@error    --@@error无错误返回0, 有错误返回非0的数
    update T_StuInfo set age = age - 1 where cardno = \'\'
    set @errorcount = @errorcount + @@error
    if(@errorcount = 0)
    begin
        commit
    end
    else
    begin
        rollback
    end
end

begin transaction    --异常控制事物提交, raiserror(\'XXXXX\',16,1)用于抛出xxxx的异常
begin
    begin try
        update T_StuInfo set age = age + 1 where gender = \'\'
        update T_StuInfo set age = age - 1 where cardno = \'\'
        commit
    end try
    begin catch
        raiserror(\'性别字段输入了不合适的字符\',16,1)    --1-15级为系统使用
        rollback
    end catch
end

--###################################################################################

--索引: 聚集索引(Clustered Index)或称物理所引,非聚集索引(Nonclustered Index)或称逻辑索引,唯一索引(Unique Index),主键索引(PK Index)
--优缺点: 查询快, 但增删改慢.
--何时用: 数据量特别大的情况适合建索引; 经常查找的字段建索引(聚集索引, 此时要求取消主键索引)
--注意事项: 
--      使用索引时, 需要注意查询时的where子句: 若有索引, 先查索引, 之后再根据索引查找原表记录位置, 拼接结果; 若无索引, 则不查索引, 直接拼结果.
--      如此, 针对索引字段, 若从带where的查询结果中去掉前5项(不带where), 则会出现错误(真分页有类似情况).
--      解决方案: 在子查询中也添加排序字段的永真where条件, 如: where sortfield > -1
select top 20 sortfiled, filed1 from T_S where sortfiled not in (select top 5 sortfiled from T_S where sortfiled > -1)
            
create clustered index idx_age on T_StuInfo(age)    --创建聚集索引(每表仅一份), 将对记录排序, 而且索引将会和表保存在一起(采用二分查找)
create nonclustered index idx_age on T_StuInfo(age)    --创建非聚集索引(任意多个), 不排序但会创建独立表(含2列: 原表中的位置索引,已排序的字段) 

--###################################################################################

--视图: 将会创建一张虚拟表, 且对视图的insert、delete和update操作会修改源数据, 但工作中禁止通过视图修改源数据.
--    视图就是个Sql语句, 也就是Select结果的虚表, 视图相当于虚表的别名而已.
--    注意: 视图的别名的使用.
--优点: 代码易读; 经过预编译(存储过程也是预编译的), 效率高; 屏蔽了表结构, 比较安全性; 缺点: 增加管理开销
if exists(select * from sysobjects where [name] = \'V_SnoName\' and [type] = \'V\')
    drop view V_SnoName
go
create view V_SnoName
as
    select [sid],sname from T_StuInfo
go

select * from V_SnoName
select * from T_StuInfo
insert into V_SnoName(sname) values(\'候八\')

--###################################################################################

--存储过程(Stored Procedure): sp_help查看SP以及sp参数的信息, sp_helptext查看SP内部代码
if exists(select * from sysobjects where [name] = \'P_Triangle\' and [type] = \'P\')
    drop procedure P_Triangle
go
create procedure P_Triangle(
    @n int
) with encryption    --加密, 不影响编译但将无法查看SP内部代码(sp_helptext)
as    --局部变量
    declare @row int
    declare @col int
    declare @result nvarchar(2000)
begin
    set @row = 0
    set @col = 0
    set @result = \'\'

    while (@row < @n)
    begin
        set @col = 0    --复位
        set @result = \'\'
        while (@col < @n + @row)
        begin
            if (@col < @n - @row - 1)
            begin
                set @result = @result + \' \'
            end
            else
            begin
                set @result = @result + \'*\'
            end
            set @col = @col + 1
        end
        print @result
        set @row = @row + 1
    end
end
go
exec P_Triangle 10
sp_help P_Triangle    --查看SP及其参数的信息
sp_helptext    P_Triangle    --查看SP内部代码

declare @result int    --以下代码证明, SP默认返回值为0
set @result = -1    
exec @result = P_Triangle 15
print @result

--存储过程 + 事物 + 输出参数
if exists(select * from sysobjects where [name] = \'P_InsertRecord\' and [type] = \'P\')
    drop procedure P_InsertRecord
go
create procedure P_InsertRecord(
    @sname    nvarchar(20),
    @gender    nchar(1) = \'\',    --等号后边是默认值
    @age    tinyint,
    @status    nchar(2),
    @birdate    datetime,
    @retrunsid    int    output    --用以保存该记录的主键
)
as    --局部变量
begin transaction
begin
    begin try
        insert into T_StuInfo(sname,gender,age,[status],birdate)
            values(@sname,@gender,@age,@status,@birdate)
        set @retrunsid = @@identity
        commit
        return 0
    end try
    begin catch
        raiserror(\'插入数据异常\',16,1)
        rollback
        return 1
    end catch
end
go
declare @sid    int    --保存输出参数
declare @return int    --保存返回值

exec P_InsertRecord \'测试2\',\'\',35,\'毕业\',\'1977-06-07\',@sid output
exec @return = P_InsertRecord \'测试2\',\'\',35,\'毕业\',\'1977-06-07\',@sid output    --用@return接受SP返回值

print @sid
print @return

--###################################################################################

--触发器: 执行时将自动创建inserted或deleted临时表(update, 同时创建两表), 且均是只读的; 因为无调用痕迹, 系统调试时增加困难
if exists(select * from sysobjects where [name] = \'TR_DelStu\' and [type] = \'TR\')
    drop trigger TR_DelStu
go
create trigger TR_DelStu    --级联删除
on T_StuInfo
instead of delete    --(for,after,instead of), 注意for和after效果是一样的
as
    declare @currentid    int
begin transaction
begin
    begin try
        --set @currentid = (select [sid] from deleted)    --insert和update会用到临时表inserted
        select @currentid = [sid] from deleted
        delete from T_StuScore where [sid] = @currentid
        delete from T_StuInfo where [sid] = @currentid
        commit
    end try
    begin catch
        raiserror(\'删除失败操作异常\',16,1)
        rollback
    end catch
end
delete from T_StuInfo where [sid] = 3

--###################################################################################

--用户定义函数(User Defined Function): 标量函数、内嵌表值函数、多语句表值函数
--标量函数(Scalar Functions)
if exists(select * from sysobjects where [name]=\'GetCountByGender\' and [type] = \'FN\')
    drop function GetCountByGender
go
create function GetCountByGender
(
    @gender nchar(1)    --函数的参数列表
)
returns int    --函数的返回值类型
as
begin
    declare @count int    --返回值变量
    
    set @count = (
        select count([sid])
        from T_StuInfo
        where gender = @gender
    )

    return @count    --执行返回
end
go
select dbo.GetCountByGender(\'\') as 数量    --调用函数时, 必须加上所有者

--内嵌表值函数(Inline Table-valued Functions)
if exists(select * from sysobjects where [name]=\'GetInfoByStatus\' and [type] = \'IF\')
    drop function GetInfoByStatus
go
create function GetInfoByStatus
(
    @status nchar(2)    --参数列表
)
returns table    --返回值为数据表
as
return 
(
    select *
    from T_StuInfo
    where [status] = @status
)
go
select * from dbo.GetInfoByStatus(\'毕业\')    --调用函数时, 必须加上所有者
go

--多语句表值函数(Multistatement Table-valued Functions)
if exists(select * from sysobjects where [name]=\'GetNameBySegAge\' and [type] = \'TF\')
    drop function GetNameBySegAge
go
create function GetNameBySegAge
(
    @firstage int,    --18岁
    @secondage int,    --18-30岁
    @thirdage int    --30岁以上
)
returns @infotable table    --定义返回值变量(table类型), 以及返回值表的字段
        (
            AgeSegment nvarchar(30),
            countnum int
        )
as
begin
    --局部变量, 用于填充返回值表
    declare @currentcount int        --当前年龄段的计数
    declare @currentdesc nvarchar(30)    --当前年龄段的描述

    set @currentcount = (select count([sid]) from T_StuInfo 
        where age<@firstage)
    set @currentdesc = \'小于(含)-\'+Convert(nvarchar(10),@firstage)+\'\'
    insert into @infotable(AgeSegment,countnum) values(@currentdesc,@currentcount)

    set @currentcount = (select count([sid]) from T_StuInfo 
        where age>=@firstage and age<@secondage)
    set @currentdesc = Convert(nvarchar(10),@firstage)+\'岁(含)-\'+Convert(nvarchar(10),@secondage)+\'\'
    insert into @infotable(AgeSegment,countnum) values(@currentdesc,@currentcount)

    set @currentcount = (select count([sid]) from T_StuInfo 
        where age>=@secondage and age<@thirdage)
    set @currentdesc = Convert(nvarchar(10),@secondage)+\'岁(含)-\'+Convert(nvarchar(10),@thirdage)+\'\'
    insert into @infotable(AgeSegment,countnum) values(@currentdesc,@currentcount)

    set @currentcount = (select count([sid]) from T_StuInfo 
        where age>=@thirdage)
    set @currentdesc = Convert(nvarchar(10),@thirdage)+\'岁(含)-不限\'
    insert into @infotable(AgeSegment,countnum) values(@currentdesc,@currentcount)

    return    --执行已定义的返回值表的返回操作
end
go
select * from dbo.GetNameBySegAge(20,30,40)    --调用函数时, 必须加上所有者

--###################################################################################

--游标:
begin transaction MoveUserInfoTrans
begin
    declare @errcount int
    set @errcount = 0

    declare MoveUserInfoTwo cursor        --声明游标
    for
        select userid,userpwd from UserInfoTwo

    open MoveUserInfoTwo    --打开游标,准备开始读取操作

        declare @userid nvarchar(20),@userpwd nvarchar(30)
        fetch next from MoveUserInfoTwo into @userid,@userpwd    --执行读取
        while(@@fetch_status=0)
        begin
            insert into UserInfoOne(userid,userpwd) values (@userid,@userpwd)
            
            if(@@error!=0)    --验证单次操作的是否成功
            begin
                set @errcount = @errcount + 1
                break
            end
            fetch next from MoveUserInfoTwo into @userid,@userpwd    --取下一条
        end
    close MoveUserInfoTwo    --完成游标操作,关闭游标
    deallocate MoveUserInfoTwo    --释放游标

    if(@errcount = 0)    --用if验证事务的操作过程
    begin
        commit transaction MoveUserInfoTrans
        print \'事务已成功提交!\'
    end
    else
    begin
        rollback transaction MoveUserInfoTrans
        print \'执行过程出错,事务已回滚!\'
    end
end
go

另外说明:

row_number(),rank(),dense_rank(),ntile(num) 区别:

都是 常用于排序后新产生一列序号

例如有一数据表:gradeInfo 表中数据如下

 

1.row_number():

select gradeID,gradeName,row_number() over(order by gradeid asc) a from gradeInfo

结果是:注意:row_number()不管排序字段的值是否有重复,总是 显示的是不重复,不断续的序号(序号大小根据排序字段的方式)

2.rank():

select gradeID,gradeName,rank() over(order by gradeid asc) newNumber from gradeInfo

结果是:注意:显示的序号是有重复,并且断续的序号

3.dense_rank():

select gradeID,gradeName,dense_rank() over(order by gradeid asc) newNumber from gradeInfo

结果是:注意:显示的是重复,不断续的序号

4.ntile(num)  [num:表示序号的的最大值]

(为了能看的更明白,我们多插入一条数据到gradeInfo);

select gradeID,gradeName,ntile(3) over(order by gradeid asc) newNumber from gradeInfo  最大值只能排到3

结果:

如果:select gradeID,gradeName,ntile(4) over(order by gradeid asc) newNumber from gradeInfo  最大值为4

那么结果:

tips:ntile(num),其实是将表中的数据分为了num个组,没一组有多少个数据,至于每一组中数据条数是怎么分配的,请看

排名函数详解

分类:

技术点:

相关文章: