本文是本人学习数据库和SQL时自己做的笔记,属于基本知识,现整理出来放在这里,供自己以后学习和查看。
在SQL Server中任何可视化行为都是在后台作为SQL语句执行的
use master; --使用主数据库
if exists(select * from sysdatabases where name = 数据库名)
drop database 数据库名;--创建前先判断是否存在
create database 数据库名
on primary --在主文件组
(
name=N'逻辑名_data',--N表明是使用UniCode编码
filename=N'路径\文件名_data.mdf',--物理文件名
size=10MB,
filegrowth=1MB
)
log on--日志文件
(
name=N'逻辑名_log',
filename=N'路径\文件名_log.ldf',
size=10MB,
filegrowth=10%
);--加分号可以提高SQL语句执行的效率
go -- go不是SQL语句中的命令,他是通知数据库将前面的语句脚本一并执行
use 数据库名;
注意:执行SQL语句
先点击勾勾,检查语法
-> 检查的范围是选中的SQL语句,如果没有选中SQL语句,则检查所有的SQL语句
然后点击感叹号执行SQL语句
(1)注释: 使用–表示行注释
使用/* 表示多行注释,这个注释不允许嵌套 */
(2)分号:习惯上每一句SQL语句结束的时候加上一个分号
(3)如果限制最大大小,使用maxsize=值
(4)数据库名(使用数据库时使用)、逻辑名(操作系统逻辑)、文件名(操作系统文件)
(5)创建数据库文件的时候,不要直接放在根目录下(D:\TestDataBase.mdf)
(1) 修改数据库
修改数据库时修改数据文件和日志文件的长度,或者增加或删除操作系统文件
Alter database 数据库名
{
…
}
(2) 删除数据库
drop database 数据库名
(1) 架构属于谁的?
架构是属于数据库的,相当于命名空间,使用架构可以设置用户的访问权限
(2) T-SQL
use 数据库;
create schema 架构名 authorization dbo;
go
略
use 数据库;
if exists(select * from sysobjects where type ='U' AND name = 架构名.表名)
drop table 架构名.表名;--创建前先判断是否存在
create table 架构名.表名
(
字段1 类型1 not null或null,
字段2 类型2 not null或null,
字段3 类型3 not null或null,
...
);
1)常用的数据类型
类别 | SQL | 备注 |
---|---|---|
数字类型 | int bigint money numeric bit | |
时间类型 | datetime(date,time) | |
字节数据 | image | |
字符串类型 | 1)基于ASCII编码:char varchar数字代表能存储多少字节 2)基于Unicode编码:nchar nvarchar数字代表能存储多少个字符 |
char(数字)数字可以取0到8000,nchar(数字)可以取0到4000
如果超出这个范围,可以使用varchar(max)这个类型会在单独的一个地方存储,容量在2G左右,或者用nvarchar(max)
char(数字)ASCCII码字符,固定长度的字符,如果输入数据的长度不够末尾补空格
char(10) 1
char(10) 1234567890
一二三四五
优势,插入数据的时候不需要考虑计算
缺点,占用资源
nchar(数字) unicode字符集,结构与char一致
nchar(10) 占十个unicode字符的位置
1234567890
一二三四五六七八九十
varchar(数字) ASCCII编码,使用可变长度,只要不超过数字即可
varchar(10) 1
nvarchar(数字) unicode字符集,使用可变长度
Text和NText 存储大文本数据(在将来的SQL Server不再支持)
varchar(max)和nvarchar(max)
补充:标准中char与varchar的最大长度为8000字节,标准中nchar与nvarchar的最大长度为4000个字符,
但是varchar(max)与nvarchar(max)不一样
唯一区分
与描述数据无关的一个字段(如额外的添加的自动增长的ID)
与描述数据相关的一个字段(如描述一个人时用身份证号最为主键)
alter table 表名
add
constraint PK_表名_字段名 primary key(字段名);
testId int identity(1,1) not null
identity(1,1) 表示字段的值从1开始,每次添加数据的时候自动增长1个
set identity_insert 表名 off/on;
alter table 表名
add
constraint UQ_表名_字段名 unique(字段);
alter table 表名
add
constraint DF_表名_字段名 default(值) for 字段;
alter table 表名
add
constraint CK_表名_字段名 check(表达式);
表达式是一些判断的规则
stuAge>=0 and stuAge<=150 or stuAge is null 连接多个条件使用and和or
alter table 外键表名
add
constraint FK_外键表_主键表_字段
foreign key(外键表中的字段) references 主键表名(主键表中的字段);
alter table 表名
drop 约束名;
alter命令表示修改的意思,凡是要修改表的数据都可以使用这个命令
alter table 表名 add constraint 约束名...
alter table 表名 drop 约束名;
alter table 表名 add 字段名 类型名;
alter table 表名 drop column 字段名;
alter table 表名 alter column 字段名 类型;
select * from sys.objects;
Use 数据库
Go
Sp_rename 表 ,新的名称 –重命名数据库表
Sp_rename 表.列名 ,新的列名 –重命名数据库表中的列
alter table 表名 drop 约束名;
select top 数字 percent distinct
字段1
, 字段2
, ...
, 聚合函数
, 表达式
, 常量
from
数据源
where
条件
group by
字段
having
条件
order by
字段;
->执行顺序:From -> where -> group by -> having -> select ->distinct和Top -> order by
-> from子句
是一个查询中最先开始的地方
表示需要查询的数据源是什么
数据源可以是表、结果集、视图等
-> 注意缩进
-> 书写格式
-> where子句
是对数据源进行直接的筛选
-> 直接拿字段进行运算
-> 判断
不等于 <> != !> !<
判断优先级:在判断的时候有多个条件,多个条件使用and与or连接
-> 匹配使用通配符,命令由=改为like
_ 表示任意的一个字符
% 表示任意多个任意字符
stuName like '牛%'; -- cow
-> 如果需要匹配"_"怎么办?
stuName like '[_]'
[] 还可以表示范围 [a-z] [^a-g]
-> 处理范围
stuAge between 19 and 26; 取19岁到26岁之间的人,注意两边取得到
stuAge in (19, 21, 25); 取19岁或21岁或25岁的人
-> 空值处理
-> 任何包含null的表达式,结果都是不知道(不知道的反面还是不知道)
-> 使用is null和is not null进行判断筛选
-> 有时需要显示数据,但是不希望出现null值可以使用ISNULL()函数
-> group by子句
-> 按照什么分组就只能显示什么数据
select后面只能跟你分组的字段
-> 聚合函数,就是将组的数据进行汇总,求出平均、总和、总数、最大和最小
AVG(字段) 求平均
SUM(字段) 求数据和
COUNT(字段) 求总条数
MAX(字段) 求最大
MIN(字段) 求最小
-> 查询出名字出现3次以上的名字
-> having子句
-> having对数据分组后筛选与where都是筛选但操作不同
-> where 直接对数据源进行筛选
-> 补充一下聚合函数的使用
-> 聚合函数默认忽略NULL值
avg(字段)
count(字段)
count(*)
-> 在SQL语句中不能将聚合函数与其他字段写在一起
使用开窗函数(*难点*)
语法
select ..., avg(字段) over() from...
-> select子句
-> 将数据源的字段显示出来
-> select可以用来显示数据
-> 别名
字段 as 列名
字段 列名
列名=字段
-> 关于字段的执行顺序,同一个子句中是同时进行的
select year(getdate()) - year(stuBirthdate) as age, age+1 from Student--错误的写法
select --正确而写法
year(getdate()) - year(stuBirthdate) as age
, year(getdate()) - year(stuBirthdate)+1
from
Student
-> distinct选项
select distinct 字段 from ...
-> top选择
select top 数字 字段 from ...
显示结果的前几条数据
select top 数字 percent--百分比
字段
from ...
-> order by子句
专门排序的子句,表示使用什么字段进行排序
select ... order by 字段 [desc] --默认升序的,加desc是降序
select * from
(
values
(1, '张三', 100),
(2, '李四', 87),
(3, '赵钱', 95),
(4, '孙李', 88)
) as tbl(stuId, stuName, stuScore);
将上数据作为临时数据,求平均值 select avg(stuScore) as avgScore from
(
values
(1, '张三', 100),
(2, '李四', 87),
(3, '赵钱', 95),
(4, '孙李', 88)
) as tbl(stuId, stuName, stuScore);
得到平均分为92分,如果需要显示出所有学员成绩,并在每个学员成绩后面加上平均分 select *, avg(stuScore) as avgScore from
(
values
(1, '张三', 100),
(2, '李四', 87),
(3, '赵钱', 95),
(4, '孙李', 88)
) as tbl(stuId, stuName, stuScore);
报错,因为聚合函数只有一行数据,而学生有4条数据,两者不统一
聚合函数 over() as 别名
select *, avg(stuScore) over() as avgScore from
(
values
(1, '张三', 100),
(2, '李四', 87),
(3, '赵钱', 95),
(4, '孙李', 88)
) as tbl(stuId, stuName, stuScore);
select * from
(
values
(1, '张三', 100, '组长'),
(2, '李四', 87, '学干'),
(3, '赵钱', 95, '组长'),
(4, '孙李', 88, '学干')
) as tbl(stuId, stuName, stuScore, stuOtherName);
-- 希望平均分还要分开求,即总平均分和所有学干的平均分和所有组长的平均分分别显示
-- 可以使用
-- 聚合函数 over(partition by 字段) as 别名
-- 即
select *,
avg(stuScore) over() as 平均分,
avg(stuScore) over(partition by stuOtherName) as 分组平均分
from
(
values
(1, '张三', 100, '组长'),
(2, '李四', 87, '学干'),
(3, '赵钱', 95, '组长'),
(4, '孙李', 88, '学干')
) as tbl(stuId, stuName, stuScore, stuOtherName);
使用row_number()函数可以为数据生成一个自动增长的数字列
语法
row_number() over(order by 字段) as 别名
表示这个自动增长的列使用"字段"的排序规则添加
select
row_number() over(order by stuScore) as 序号,
*,
avg(stuScore) over() as 平均分,
avg(stuScore) over(partition by stuOtherName) as 分组平均分
from
(
values
(1, '张三', 100, '组长'),
(2, '李四', 87, '学干'),
(3, '赵钱', 95, '组长'),
(4, '孙李', 88, '学干')
) as tbl(stuId, stuName, stuScore, stuOtherName);
select
row_number() over(order by stuName) as 序号,
*,
avg(stuScore) over() as 平均分,
avg(stuScore) over(partition by stuOtherName) as 分组平均分
from
(
values
(1, '张三', 100, '组长'),
(2, '李四', 87, '学干'),
(3, '赵钱', 95, '组长'),
(4, '孙李', 88, '学干')
) as tbl(stuId, stuName, stuScore, stuOtherName);
-> 表(结果集):结果集必须有列名(无序)
-> 游标CURSOR:游标是有序的(有顺序的,order by)
-> 两本书:数据库内部底层:
《数据库系统实现》
《数据库系统概念》
case
when 包含字段的表达式1 then 值1
when 包含字段的表达式2 then 值2
...
else 值n
end
case 字段
when 值1 then 显示1
when 值2 then 显示2
...
else 显示n
end
查询1
union [all]
查询2
原始语法
insert into 表名(列名,列名….) values(值,值….);
补充语法
insert into 表名(列名,列名….) 结果集;
Update from 表名
Set 列名=新值
Where 条件
delete 表名
Where 条件
(values (值1, 值2, 值3, ...),
(值1, 值2, 值3, ...),
(值1, 值2, 值3, ...),
...
) as 表名(列1, 列2, 列3, ...)
insert into 表名(列名) values(值),(值),(值),...
select
*
into 新表名
from
表
select * into 新表 from 表 where 1 > 2;
略
函数名 | 格式 |
---|---|
datetime | yyyy-MM-dd hh:mm:ss.000 |
date | yyyy-MM-dd |
time | hh:mm:ss.000 |
datetime2 | yyyy-MM-dd hh:mm:ss.000 |
datatimeoffset | 使用标准时间+偏移时间 |
考虑数字运算,一般有字符串型的数字参与时,如果有数字则全部转换为数字计算联合结果集的时候
cast(变量或数据 as 类型);
convert(类型, 变量或数据[, 格式])
select -- 外部查询
字段
from
表1
where
字段 =
(
select top 1 字段 from 表2 -- 单值(标量)子查询
)
and
字段 in
(
select 字段 from 表3 -- 多值子查询
)
select
字段
from
表1 as t1
where
字段 =
(
select top 1 字段 from 表2 as t2 where t1.字段=t2.字段
);
内部连接:内部连接使用比较运算符,根据每个表的通用列中的值匹配两个表中的行。
外部链接:在内部连接中,只用两个表中匹配的行才能在结果集中出现,而在外部连接中可以只限制一个表,而对另一个表不加限制
交叉连接:没有where子句的交叉连接,即笛卡尔积,第一个表的行数乘以第二个表的行数等于笛卡尔积得到的结果集大小
例子:
tbl1(id, name, pwd);
tbl2(id, note);
tbl(id, name, pwd, note);
select
*
from
表1 as t1
inner join
表2 as t2
on t1.字段=t2.字段
外连接
select
*
from
表1 as t1
left join --左连接,加入表1的字段
表2 as t2
on t1.字段 = t2.字段;
select
*
from
表1 as t1
right join --右连接,加入表2的字段
表2 as t2
on t1.字段 = t2.字段;
select
*
from
表1 as t1
full join --全连接,加入表1和表2的字段
表2 as t2
on t1.字段 = t2.字段;
select
*
from
表1
cross join(join)
表2
with 表别名(列别名...可省略)
as
(
结果集
)
select * from 表别名;
注意:公用表表达式是一个定义执行的整体,使用的时候所谓的定义一次使用多次指的是紧跟定义的查询中的自连接,以及进一步定义和递归定义
create view vw_名字
as
结果集
go
视图与派生表和CTE的最大区别在与用一个别名存到了数据库中,在使用的时候可以将别名当作表直接使用
重要:视图是虚拟表,不具备存储数据的能力,在执行的时候,SQL Server底层依旧是分别处理物理表结构
问题:假定有数据60000行,每页显示10行,显示第1页,第2页,以及第n页
select top 10
*
from
Student
where
stuId not in (select top ((n-1)*10) stuId from Student order by stuId)-- 第n页
order by stuId;
性能低
select
row_number() over(order by 字段)--需要over(order by 字段)
,*
from
tbl
select ROW_NUMBER() over(order by stuId),* from Student
select
*
from
(select ROW_NUMBER() over(order by stuId) as num, * from Student) as tbl
where
tbl.num between (99-1)*10 + 1 and 99*10;--99页
create view vw_fenye1
as
select ROW_NUMBER() over(order by stuId) as num, * from Student;
go
select * from vw_fenye1 where num between 1 and 10;
create function fn_函数名
(参数名 as 类型名, ...)
returns table
as
return 结果集
-----------------------------
create function fn_FenYe2--返回index页,每页pageSize条数据
(@index as int, @pageSize as int) returns table--所有的变量都要@引导
as
return
select * from vw_fenye1
where
num between (@index - 1) * @pageSize + 1 and @index * @pageSize;
go
select * from fn_FenYe2(3,25);
select @@version --查看系统版本
局部变量(自定义变量) @变量名 --自己先定义,再复制,后使用
定义:使用declare引导变量的定义
–declare @num int; – 定义了一个变量num,是int类型(int num;)
赋值:两种方法
– ①使用set语句
– set @变量 = 标量(可以是一个数据、可以是一个子查询、也可以是表达式)
– set @num = (select COUNT() from Student);
– ②使用select语句
– select 字段 from 表 表示一个查询
– select @变量=字段 from 表 表示将查询的结果不已表的形式显示,而是赋值
– select @num=COUNT() from Student;
使用:用select
-- select @num; --使用num
注意
赋值的方式
--只能赋值一次 单值
set @num = (select top 1 t.ID --必须加top 1
from
(
select ID
from (values(123),(2),(3),(4)) as tbl(id)
) as t
);
select @num;
go
--赋值多次
declare @num int;
select @num = t.ID from (
select ID from (values(123),(2),(3),(4)) as tbl(id)
) as t
select @num;
go
-- 定义的时候直接赋值
declare @num int = 10;
select @num;
几种常见的系统变量
select @@ERROR;--系统执行最后一次的错误信息
select @@IDENTITY;--最后一次插入表中的唯一标识符;
...
while(表达式)
begin
代码
end
declare @i int=0;--赋值
declare @sum int=0;
while(@i <= 100)
begin
if(@i % 2 <> 0)--<>是不等于的意思
begin
set @sum += @i;
end
set @i += 1;
end
select @sum;
go
if(表达式)
begin
代码
end
else if(表达式)
begin
代码
end
else
begin
代码
end
update bank set balance=balance - 1000 where cid='0001'
update bank set balance=balance + 1000 where cid='0002'
begin try
可能出现错误的语句
end try
begin catch
异常的处理代码
end catch
存储过程就是存储在数据库中的过程 ,分两种:
如何定义存储过程?三种
create procedure usp_存储过程名
as
begin
SQL语句
end
有参数的存储过程
1、按照定义的顺序依次用逗号隔开
exec usp_Bank1 ‘0001’, ‘0002’, 10;
2、利用“@变量名=值”的形式提供,可以调整赋值顺序
create proc usp_存储过程名
@变量名1 类型名1,
@变量名2 类型名2,
...
as
begin
SQL语句
end
create proc usp_存储过程名
变量名1 类型名1 = 值,
变量名2 类型名2 = 值,
...
as
begin
SQL语句
end
有返回值的存储过程
create pro usp_存储过程名
@参数1 类型1 ,
@参数2 类型2 output,
...
as
begin
SQL语句
end
调用存储过程
declare @res int;
exec 存储过程名 值1, 值2, @res output, 值4
create trigger tr_触发器名 on 表名
for|after|instead of update/delete/insert
as
begin
SQL语句
end
聚集索引–聚集索引决定了数据存储的顺序
非聚集索引–与数据存储顺序无关
注意:
聚集索引与表中数据是一致的,索引一张表只允许有一个聚集索引
create nonclustered index 索引名 on student(stuBirthdate);--clustered 聚集索引,nonclustered非聚集索引
新华字典
拼音检索–聚集索引
笔画检索–非聚集索引
string connStr = @"server=机器名或IP\实例名;database=数据库名;uid=sa;pwd=123;";
string sql = "";
int count;
using(SqlConnection conn = new SqlConnection(connStr))
{
using(SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
count = cmd.ExecuteNonQuery();
}
}
```
string connStr = @"server=机器名或IP\实例名;database=数据库名;uid=sa;pwd=123;";
string sql = "";
object count;
using(SqlConnection conn = new SqlConnection(connStr))
{
using(SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
count = cmd.ExecuteScalar();
}
}
使用ExecuteScalar一般与聚合函数连用
string connStr = @"server=机器名或IP\实例名;database=数据库名;uid=sa;pwd=123;";
string sql = "";
object count;
SqlConnection conn = new SqlConnection(connStr)
using(SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
count = cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
SqlDataAdapter
-> DataSet
数据集
内存中的数据库
-> 如何创建DataSet
-> DataSet的结构
-> 使用SQL Server的类型都在命名空间System.Data.SqlClient中
-> 使用数据处理的类型均在System.Data中
-> SqlDataAdapter
-> 创建DataSet
-> 创建SqlDataAdapter,提供SQL语句和连接字符串
-> 调用一个Fill方法将数据加到DataSet中
-> 关闭释放即可
SqlDataAdapter sda = new SqlDataAdapter(sql语句, 连接字符串);
sda.Fill(DataSet对象);
-> 专门用来显示数据
-> 填充数据的方法很多,我主要介绍DataSource赋值的方法
-> 步骤
-> 拖控件,dgview
-> 得到DataSet数据,dataset
-> 赋值
dgview.DataSource = dataset.Tables[0];
-> 使用DataGridView的Columns属性可以访问某一列
得到该列以后使用Forzen属性可以冻结该列,冻结该列表示该列与其左侧的列均被冻结
-> 步骤
-> 获得数据源(即修改后的数据)
-> 得到或创建与读取数据的SqlDataAdapter一样的对象(SQL语句有主键)
-> 创建一个SqlCommandBuilder对象,处理一下sda,自动生成SQL执行对象(迷惑?)
-> 调用sda的Update方法即可
-> 步骤
-> 将原来需要字符串拼接的值,用一个@引导的变量名代替
-> 使用SqlParameter类型将参数变量与值绑定在一起,将参数与值配对
-> 将SqlParameter对象交给cmd对象的Parameters集合,cmd.Parameters.Add*();
-> 添加App.config
-> 在里面添加键值
-> 添加connectionStrings标签
-> 在里面添加add标签
-> add标签有两个属性:name、connectionString
-> name用于存储名字,也就是键。在C#中使用这个名字获得连接字符串
-> connectionString就是连接字符串
-> 添加引用System.Configuration
-> 使用ConfigurationManager类的Connections属性
-> 利用索引获得连接字符串
-> 原本是一个数据,现在变成一个数据和一个条件
-> 限制只允许是数据
-> 所谓的参数化,就是将需要值的地方,用一个参数变量表示,而操作数据库的时候,给这个参数赋值即可