SQL Server数据库

使用SQL语句进行的一系列操作

1、建库

最简单的创建数据库的方式:

create database 数据库名

这种方式可以快速地创建数据库,唯一的缺点就是创建数据库的路径为当前SQLserver的安装目录下C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA中,不方便查找。

除了上面那种用SQL语句创建数据库,还可以在它的基础上添加一些参数,指定路径,大小等等属性。

create database ProductDB
on
(
	name='ProductDB', --主数据文件(.mdf)的逻辑名称
	filename='D:\SQL server\datebase\ProductDB.mdf', --主数据文件的物理名称(存放路径)
	size=5mb ,  -- 设置主数据文件的初始大小
	maxsize=100mb , --设置主数据文件的最大值
	filegrowth=20%   --主数据文件的增长率

)
log on
(
	name='ProductDB_log', --日志文件(.ldf)的逻辑名称,这里在名称里面加一个_log表示这是一个日志文件
	filename='D:\SQL server\datebase\ProductDB_log.ldf', --日志文件的物理名称(存放路径)
	size=3mb ,  -- 设置日志文件的初始大小
	maxsize=30mb , --设置日志文件的最大值
	filegrowth=20%   --日志文件的增长率
)

参数:

  • name:主数据文件和日志文件的名称

  • filename:存放路径,建议把主数据文件和日志文件存放在一起,方便管理

  • size:设置文件的初始大小(这里的初始大小代表它在磁盘中占用内存大小,但不代表着数据库文件中存放的数据有5MB)

  • maxsize:文件在磁盘占用内存的最大值,当文件中的数据达到最大值,则不能再往里面添加数据

  • filegrowth:当数据库文件中数据达到初始大小后(也就是5MB时,是这里的设定),它会以filegrowth设定的值进行递增,直到达到最大值为止。

    例如,这里主数据文件设置的初始大小为5MB,当文件中数据达到5MB,再往里面插入数据,它会以15%的比例进行递增。第一次超过为6MB,第二次超过为7.2MB,第三次超过为8.64MB .....

当我需要创建数据库,但是这个同名的数据库已经存在了,我想要删除它并创建新的数据库,该怎么实现?

if exists(select * from sysdatabases where name='ProductDB') --判断是否存在,存在就删除
	drop database ProductDB
else --不存在创建数据库
create database ProductDB
on
(...)
log on(....)

2、建表

use ProductDB go --表示将当前使用数据库设置为ProductDB

这样写的好处是,当你要执行某些SQL语句时,它是在ProductDB数据库中执行的,而不是master

2.1表格关系

这里我将所有表的信息列出来,方便后面理解SQL语句:

T_product:

字段名 说明 类型 约束
product_id 产品编号 int PK,identity
category_id 类别编号 int FK
product_name 产品名称 varchar(50) not null
price 产品价格 money check约束(1-1000)
remark 产品描述 varchar(2000) null
register_date 录入日期 datetime default

T_category:

字段名 说明 类型 约束
category_id 类别编号 int PK,identity
category_name 类别名称 varchar(50) not null
register_date 录入日期 datetime default

T_product_review:

字段名 说明 类型 约束
review_id 评论编号 int PK,identity
product_id 产品编号 int FK
review 评论内容 varchar(200) null
register_date 录入日期 datetime default
2.2 SQL建表

创建数据表:

1.添加T_category商品类别表:

--判断要创建的表是否已经存在
if exists(select * from sysobjects where name='T_category')
	begin
		select '该表已经存在'  --以表格的形式打印该消息
		print '该表已经存在'	 --以字符串的形式打印出消息
		drop table T_category  --删除
	end
else 
	begin
		create table T_category --创建表
		(
			category_id int primary key identity(1,1),
			category_name varchar(50) not null,
			register_date datetime not null
		)
	end
go

if-else:条件语句,需要注意的是,if语句中是没有 else-if结构的。

begin..end之间的是一个语句块,一般Begin...End用在 ( 相当于 {})

go:官方说法是:GO只是SQL Server管理器(SSMS)中用来提交T-SQL语句的一个标志。我的理解是,go为SQL语句的结束标志,它可以将多条SQL语句进行分割,互不关联。

2.添加T_product商品表:

if exists(select * from sysobjects where name='T_product')
	begin
	....
	end
else 
	begin
		create table T_product --创建表
		(
			....
		)
	end
go

3.添加T_product_review商品评论表:

if exists(select * from sysobjects where name='T_product_review')
	begin
		...
	end
else 
	begin
		create table T_product_review
		(
			...
		)
	end
go
2.3 给表添加约束
1.default
--给三个表的register_date设置一个默认值,提交时间为当前时间
alter table T_product add constraint registertime default (getdate()) for register_date
alter table T_category add constraint registertime1 default (getdate()) for register_date
alter table T_product_review add constraint registertime2 default (getdate()) for register_date
2.check
--限制price的范围只能在1~1000之内
alter table T_product add  constraint CHK_price check(price>=1 and price<=1000) 
3.foreign key
--T_product的类别id设置为T_category的外键
alter table T_product add constraint FK_product_category Foreign key references 
T_category(category_id)

--T_product_review的产品id设置为T_product的外键
alter table T_product_review add constraint FK_review_product Foreign key references
T_product(product_id)

3、创建视图

语法格式:

create view 视图名
as
(SQL语句)

这里创建名为product_view1的视图,视图中的数据包括录入日期在2011年3月到6月之间的产品数据信息。

if exists(select * from sys.views where name='product_view1') --存在该视图的时候就删除
	drop view product_view1
go
create view product_view1 
as
select * from T_product where register_date>= dateadd(day,0,'2011-03-01') 
and register_date<= dateadd(day,0,'2011-06-01') 
go

当我们需要查询视图中数据的时候,可以通过select语法像查询数据表一样的方式去查询视图

select * from product_view1

4、创建存储过程

1、什么是存储过程?

系统存储过程是系统创建的存储过程,目的在于能够方便的从系统表中查询信息或完成与更新数据库表相关的管理任务或其他的系统管理任务。系统存储过程主要存储在master数据库中,以“sp”下划线开头的存储过程。尽管这些系统存储过程在master数据库中,但我们在其他数据库还是可以调用系统存储过程。有一些系统存储过程会在创建新的数据库的时候被自动创建在当前数据库中。

2、存储过程运行流程
image-20221022174811872
3、存储过程的分类

存储过程是由一些SQL语句和控制语句组成的被封装的过程,它驻留在数据库中,可以被客户应用程序调用,也可以从另一个过程或者触发器调用。它的参数可以被传递和返回,与编程语言中函数的传参和返回值过程类似。存储过程可以通过存储过程名称来调用,而且存储过程同样有输入参数输出参数

根据存储过程返回值类型的不同,可以分为三类:

  • 返回结果集:存储过程的执行结果返回的是一个结果集,典型的例子就是从数据表中检索出符合某一个或多个条件的多条记录。
  • 返回数值:存储过程执行完毕之后返回一个值,例如在数据库中执行一个由返回值的函数或者命令
  • 行为存储过程:仅仅使用来实现数据库的某个功能,而没有返回值,例如在数据库中的更新和删除操作。
4、理解存储过程

个人认为,存储过程就是一个已经预编译好的复杂SQL语句的组合,其中附加了逻辑和控制。

但是,存储过程在处理一些比较复杂的业务时比较实用,例如:

如果你在前台处理请求数据时,可能会涉及到多次的数据库连接。但是如果你使用存储过程,就只有一次,从响应时间来说有优势。

存储过程可以给我们带来运行效率提高的好处

另外,程序容易出现bug不稳定,而存储过程,只要数据库不出问题,基本上不会有问题。从安全上而言,使用了存储过程可以让系统更加稳定。

那么,问题也来了,什么时候可以使用存储过程?对于数据量不是很大以及业务处理不是很复杂的小项目就不需要了吗?

肯定是否定的。存储过程不仅适用于大型项目,对于中小型项目,使用存储过程也是非常有必要的。

其主要优势体现在以下几点:

  • 执行效率快:存储过程只在创建的时候会进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
  • 响应速度快:当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query,Delete 时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。这些操作,如果用程序来完成,就变成了一条条的 SQL 语句,可能要多次连接数据库。而换成存储,只需要连接一次数据库就可以了。
  • 重复使用:可减少数据库开发人员的工作量。
  • 安全性高:可设定只有某此用户才具有对指定存储过程的使用权。
  • 减少网络通信量:调用一个行数不多的存储过程与直接调用SQL语句的网络通信量可能不会有很大的差别,可是如果存储过程包含上百行SQL语句,那么其性能绝对比一条一条的调用SQL语句要高得多。
  • 执行速度更快:有两个原因:首先,在存储过程创建的时候,数据库已经对其进行了一次解析和优化。其次,存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接调用。
  • 更强的适应性::由于存储过程对数据库的访问是通过存储过程来进行的,因此数据库开发人员可以在不改动存储过程接口的情况下对数据库进行任何改动,而这些改动不会对应用程序造成影响。
  • 分布式工作:应用程序和数据库的编码工作可以分别独立进行,而不会相互压制

当前,存储过程有优势也同样有缺点:

  1. 运行速度: 大多数高级的数据库系统都有statement cache的,所以编译sql的花费没什么影响。但是执行存储过程要比直接执行sql花费更多(检查权限等),所以对于很简单的sql,存储过程没有什么优势。
  2. 网络负荷:如果在存储过程中没有多次数据交互,那么实际上网络传输量和直接sql是一样的。
  3. 团队开发:很遗憾,比起成熟的IDE,没有什么很好存储过程IDE工具来支持,也就是说,这些必须手工完成。
  4. 安全机制:对于传统的C/S结构,连接数据库的用户可以不同,所以安全机制有用;但是在web的三层架构中,数据库用户不是给用户用的,所以基本上,只有一个用户,拥有所有权限(最多还有一个开发用户)。这个时候,安全机制有点多余。
  5. 用户满意:实际上这个只是要将访问数据库的接口统一,是用存储过程,还是EJB,没太大关系,也就是说,在三层结构中,单独设计出一个数据访问层,同样能实现这个目标。
  6. 开发调试:一样由于IDE的问题,存储过程的开发调试要比一般程序困难(老版本DB2还只能用C写存储过程,更是一个灾难)。
  7. 移植性:算了,这个不用提,反正一般的应用总是绑定某个数据库的,不然就无法靠优化数据库访问来提高性能了。
  8. 维护性:的确,存储过程有些时候比程序容易维护,这是因为可以实时更新DB端的存储过程,但是在3层结构下,更新server端的数据访问层一样能实现这个目标,可惜现在很多平台不支持实时更新而已。
5、常用的系统存储过程
exec sp_databases; --查看数据库
exec sp_tables;        --查看表
exec sp_columns student;--查看列
exec sp_helpIndex student;--查看索引
exec sp_helpConstraint student;--约束
exec sp_stored_procedures;
exec sp_helptext 'sp_stored_procedures';--查看存储过程创建、定义语句
exec sp_rename student, stuInfo;--修改表、索引、列的名称
exec sp_renamedb myTempDB, myDB;--更改数据库名称
exec sp_defaultdb 'master', 'myDB';--更改登录名的默认数据库
exec sp_helpdb;--数据库帮助,查询数据库信息
exec sp_helpdb master;

下面是系统存储过程的一些示例:

--表重命名
exec sp_rename 'T_goods','goods' -- sp_rename 'old name' , 'new name'
select * from goods

--列重命名
execute sp_rename 'goods.goods_name','Name','column'
exec sp_help 'goods' --查看对应表的详细信息


--查询所有存储过程
select * from sys.objects where type = 'P';
select * from sys.objects where type_desc like '%pro%' and name like 'sp%';
6、用户自定义存储过程

语法:

create proc | procedure pro_name
    [{@参数数据类型} [=默认值] [output],
     {@参数数据类型} [=默认值] [output],
     ....
    ]
as
    SQL_statements
1.创建不带参数的存储过程
--创建存储过程
if exists(select * from sysobjects where name='proc_get_student')
	drop proc/procdure proc_get_student --proc是procedure的简写
go
create proc proc_get_student
as
    select * from student;

--调用、执行存储过程
exec proc_get_student; --exec 是 execute简写
2.修改存储过程
--修改存储过程
alter proc proc_get_student
as 
select * from student
3.带参存储过程
--带参存储过程
if (object_id('proc_find_stu', 'P') is not null)
    drop proc proc_find_stu
go
create proc proc_find_stu(@startId int, @endId int)
as
    select * from student where id between @startId and @endId
go

exec proc_find_stu 2, 4;  -- 2 是@startId ,4是@endId 变量
4、带通配符参数存储过程
--带通配符参数存储过程
if (object_id('proc_findStudentByName', 'P') is not null)
    drop proc proc_findStudentByName
go
create proc proc_findStudentByName(@name varchar(20) = '%j%', @nextName varchar(20) = '%')
as
    select * from student where name like @name and name like @nextName;
go

exec proc_findStudentByName;
exec proc_findStudentByName '%o%', 't%';
5、带输出参数存储过程
if (object_id('proc_getStudentRecord', 'P') is not null)
    drop proc proc_getStudentRecord
go
create proc proc_getStudentRecord(
    @id int, --默认输入参数
    @name varchar(20) out, --输出参数
    @age varchar(20) output--输入输出参数
)
as
    select @name = name, @age = age  from student where id = @id and sex = @age;
go

-- 
declare @id int,
        @name varchar(20),
        @temp varchar(20);
set @id = 7; 
set @temp = 1;
exec proc_getStudentRecord @id, @name out, @temp output;
select @name, @temp;
print @name + '#' + @temp;
6、不缓存存储过程
--WITH RECOMPILE 不缓存
if (object_id('proc_temp', 'P') is not null)
    drop proc proc_temp
go
create proc proc_temp
with recompile
as
    select * from student;
go

exec proc_temp;
7、加密存储过程
--加密WITH ENCRYPTION 
if (object_id('proc_temp_encryption', 'P') is not null)
    drop proc proc_temp_encryption
go
create proc proc_temp_encryption
with encryption
as
    select * from student;
go

exec proc_temp_encryption;
exec sp_helptext 'proc_temp';
exec sp_helptext 'proc_temp_encryption';
8、带游标参数存储过程
if (object_id('proc_cursor', 'P') is not null)
    drop proc proc_cursor
go
create proc proc_cursor
    @cur cursor varying output
as
    set @cur = cursor forward_only static for
    select id, name, age from student;
    open @cur;
go
--调用
declare @exec_cur cursor;
declare @id int,
        @name varchar(20),
        @age int;
exec proc_cursor @cur = @exec_cur output;--调用存储过程
fetch next from @exec_cur into @id, @name, @age;
while (@@fetch_status = 0)
begin
    fetch next from @exec_cur into @id, @name, @age;
    print 'id: ' + convert(varchar, @id) + ', name: ' + @name + ', age: ' + convert(char, @age);
end
close @exec_cur;
deallocate @exec_cur;--删除游标
9、分页存储过程
---存储过程、row_number完成分页
if (object_id('pro_page', 'P') is not null)
    drop proc proc_cursor
go
create proc pro_page
    @startIndex int,
    @endIndex int
as
    select count(*) from product
;    
    select * from (
        select row_number() over(order by pid) as rowId, * from product 
    ) temp
    where temp.rowId between @startIndex and @endIndex
go
--drop proc pro_page
exec pro_page 1, 4
--
--分页存储过程
if (object_id('pro_page', 'P') is not null)
    drop proc pro_stu
go
create procedure pro_stu(
    @pageIndex int,
    @pageSize int
)
as
    declare @startRow int, @endRow int
    set @startRow = (@pageIndex - 1) * @pageSize +1
    set @endRow = @startRow + @pageSize -1
    select * from (
        select *, row_number() over (order by id asc) as number from student 
    ) t
    where t.number between @startRow and @endRow;

exec pro_stu 2, 2;
10、Raiserror返回用户定义的错误信息,可以指定严重级别,设置系统变量记录所发生的错误。
Raiserror({msg_id | msg_str | @local_variable}
  {, severity, state}
  [,argument[,…n]]
  [with option[,…n]]
)

# msg_id:在sysmessages系统表中指定的用户定义错误信息

# msg_str:用户定义的信息,信息最大长度在2047个字符。

# severity:用户定义与该消息关联的严重级别。当使用msg_id引发使用sp_addmessage创建的用户定义消息时,raiserror上指定严重性将覆盖sp_addmessage中定义的严重性。

任何用户可以指定0-18直接的严重级别。只有sysadmin固定服务器角色常用或具有alter trace权限的用户才能指定19-25直接的严重级别。19-25之间的安全级别需要使用with log选项。
1

# state:介于1至127直接的任何整数。State默认值是1。

raiserror('is error', 16, 1);
select * from sys.messages;
--使用sysmessages中定义的消息
raiserror(33003, 16, 1);
raiserror(33006, 16, 1);

5、创建事务

1.什么是事务?

事务是在数据库上按照一定的逻辑顺序执行的任务序列,是恢复和控制并发的基本单位,既可以由用户手动执行,也可以由某种数据库程序自动执行

2.事务的属性
1、原子性

保证任务中的所有操作都执行完毕;否则,事务会在出现错误时终止,并回滚之前所有操作到原始状态。

2、一致性

事务必须使数据库从一个一致性状态变换到另一个一致性状态。

3、隔离性

保证不同的事务相互独立、透明地执行。

(1)事务不隔离会导致的问题

  • 脏读

    一个事务正在对一条记录做修改,在这个事务完成并提交之前,这条数据是处于待定状态的(可能提交也可能回滚)。然后又有其它事务来读取这条没有提交的数据,并进行了操作。

  • 幻读

  • 不可重复读

(2)事务的隔离级别

  • 未提交读取(Read Uncommitted)

    事务不彼此隔离。 如果 DBMS 支持其他事务隔离级别,则它会忽略用于实现这些级别的任何机制。 因此,它们不会对其他事务产生不利影响,在读取未提交级别运行的事务通常是只读的。

  • 已提交读取(Read Committed)

    SQL Server的默认隔离级别

    可以防止读取脏数据。

  • 可重复读取(Repeatable Read)

    确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。

  • 可序列化(Serializable)

    事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能。

  • 快照

  • 已提交读取快照(Read Committed Snapshot)

4、持久性

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

3.事务分类
1、显式事务

用 begin transaction 明确指定事务的开始,由 commit transaction 提交事务、rollback transaction 回滚事务到事务结束。

2、隐式事务

通过设置 set implicit_transactions on 语句,将隐式事务模式设置为打开。当以隐式事务模式操作时,不必使用 begin transaction 开启事务,当一个事务结束后,这个模式会自动启用下一个事务。只需使用 commit transaction 提交事务或 rollback transaction 回滚事务即可。

3、自动提交事务

SQL Server的默认模式,它将每条单独的T-SQL语句视为一个事务。如果成功执行,则自动提交,否则回滚。

6、对表的数据进行增删改查(crud)

1.查

在数据库中,涉及逻辑最多的就是查询。例如,连接多张表进行查询,筛选条件查询,子查询等等。

1.单表查询
  • 通过表中的若干列查询数据

    --查询指定列
    --查询名为'菠萝手机'的价格和上架时间
    select price ,register_date from T_product where product_name='菠萝手机'
    
    --查询全部列 通配符'*'在这里指的是该表的所有列
    select * from T_product
    
    --查询经过计算的数据
    --查询录入日期在2011年3月到6月之间的产品数据。
    select * from T_product where register_date>= dateadd(day,0,'2011-03-01') and
    register_date<= dateadd(day,0,'2011-06-01') 
    
    
    --设置别名进行查询
    select product_name ProName, price ,register_date from T_product where ProName='菠萝手机'
    
  • 选择表中的若干 元组(行)

    distinct消除重复的行(仅仅是不显示,并非删除)

    这里用其他表来展示:

    select country from Student
    
    image-20221021171340585
    --使用distinct消除重复行
    select distinct from Student
    
    image-20221021171437329

    查询满足条件的元组(数据行):

    select sname from Student where sdept='cs'
    

    这里讲下执行查询的一种可能过程:

    对表进行全表扫描,取出一个元组(一行数据),检查是否满足条件。满足,取出sname列的值,形成新的元组(数据行)输出。不满足,取下一个元组(数据行)。

    为什么说这是可能过程呢,因为具体的操作可能会根据优化器优化,利用索引或者根据某些规则来作出选择,进行优化。

    具体sql如何执行查询操作可以参考下面两篇文章:
    SQL查询操作处理流程
    一条select的查询的过程

    --between的使用
    --在Student表中查询20到30的所有数据行(元组) 这里between..and是包括20和30边界值的。
    select sname from Student 
    where age betweet 20 and 30 
    
    --确定集合 in 在一个集合中取符合集合中数据的元组 
    select sname from Student 
    where sdept in('cs','ma','is') --输出表中sdept值为'cs','ma','is'的元组 
    --in 和 not in可以用来查询属性值属于指定集合的元组,本质就是取了几个符合指定的元组(数据行)
    
    --和上面sql语句相同,也可以用or来表示
    select sname from Student
    where sdept='cs' or sdept='ma' or sdept='is'
    
    
    --模糊查询(字符匹配)
    select * from Student where sname like '陈%' 
    -- %是通配符(长度可以为0,亦或者任意字符)
    -- _是单个字符(长度可以为0或者1)
    
    --空值查询
    select sno, cno
    from sc
    where grade is null;
    --注意,不能用=替换
    
    --多重条件查询
    --用and 或 or, 其实in就是多个or的缩写
    
  • Order by

    对查询的结果进行排序,ASC升序(默认) 或者 DESC(降序)

    select * from  T_product   order by register_Date
    
  • 聚集函数

    count, sum, avg, max, min

    
    

    聚集函数处理会自动跳过空值
    聚集函数只能用在select字句和group by中的having字句

  • group by子句

    一般group by都是用来分组的

2.多表查询
  • 笛卡尔积

  • 自身连接

3.子查询(嵌套查询)
4.集合查询
5.基于派生表的查询
2.删
1.drop

在上面的例子中多个地方都用到了它,这里提一下drop删除数据表:

语法:

drop table 表名

删除表中的数据和定义,释放空间,最暴力不保留任何东西(等于把整个表给删除了)或者直接理解成删除表一个道理的,也是最干净的删除操作。

2.delete

语法:

delete from 表名 [where 条件筛选]

这里如果不指定删除的条件,则会把整个表的数据删除,破坏表的结构。

delete from T_product  --删除整张表的数据

delete删除表中数据不删除定义,不释放空间。例如:表中有自增的字段,当自增的字段到达5的时候,我们使用delete进行删除,只单纯的把数据删除了,在下一次添加数据的时候,主键的自增从最后一个自增的数据开始加起(例如:最后一个自增到5,删除了,是从6开始的)以此类推。

删除单条数据

将产品中名为‘菠萝手机’的数据删除:

delete from T_product where product_name='菠萝手机'
3.truncate

上面的例子中也使用到了它,简单提一下它的用法和功能:

语法:

truncate table 表名

删除表中数据、释放空间但不删除定义(不能单独删除某一行数据 )。

4.总结

区别能直接看出,就不写出来了,自行比较。

上面所属的空间就是与自增有关,如果不清空就会一直自增下去,所以学会利用好相对应的删除,才能更好的对数据进行操作,也能避免一些bug的发生。

3.改

语法:

update 表名 set [列名=列值,列名2=列值2,....]  [where 筛选条件]

例如,下面用一个栗子解释一下:将旺仔牛皮糖的价格下降10%

修改前:

image-20221021161016780

修改后:

update T_product set price-=price*0.1 where product_name='旺仔牛皮糖'
image-20221021161208983

更新多个字段:

将旺仔牛皮糖改为旺仔牛逼糖 ,价格改为10

update T_product set product_name='旺仔牛逼糖',price=10 where product_name='旺仔牛皮糖'
image-20221021162121564

有这样的一个场景: 我们要更新的一个表的多个字段,这几个在字段的值都需要子查询来获得,且子查询的写法都是一样的,往往实现需要这样去写:

update table set coumn1 = (select value1 from tableb d where table.column3= d.columnx),
coumn2 = (select value2 from tableb d where table.column3= d.columnx)
where column2 = "test";

子查询都是一样的,我们却得写多次,所以我们可以这样去写:

update t set t.coumn1 = d.value1,t.colum2 = d.value2
from table t 
left join 
tableb d 
on t.column3 = d.columnx
where  t.column2 = "test";

借鉴链接:https://blog.csdn.net/maaici/article/details/84941434

4.增

增加数据的SQL语句里面很少涉及到较难的逻辑性问题,只需要注意表与表之间的约束(主键、外键),表中列有没有设置约束(唯一约束unique,默认约束default,检索约束check)

语法:

insert [into] 表名(列名) values(列值)

这里我们把上面所建的表的数据添加一下:

根据表之间的关系,我们先添加T_category表中的数据=>

insert into T_category(category_name) values('饮料')
insert into T_category(category_name) values('零食')
insert into T_category(category_name) values('电子产品')
truncate table T_category --使用的时候,需要删除其他表中的外键(category_id)
select * from T_category

然后添加T_product表的数据=>

insert into T_product(category_id,product_name,price,remark) values(2,'旺仔牛皮糖',10,'让你越吃越流鼻')
insert into T_product(category_id,product_name,price,remark) values(1,'6个核弹',63,'越喝越聪明')
insert into T_product(category_id,product_name,price,remark) values(3,'菠萝手机',1000,'你值得拥有')
truncate table T_product
select * from T_product

最后添加T_product_review表的数据=>

insert into T_product_review(product_id,review) values(1,'没错,是真的!我吃了以后越来越流鼻了!O(∩_∩)O')
insert into T_product_review(product_id,review) values(2,'孩子喝了以后感觉不错,越来越机灵了!')
insert into T_product_review(product_id,review) values(3,'让我们一起支持菠萝手机,支持国产货!')
select * from T_product_review

这三个表按照这样的顺序来添加数据?

因为前面在T_product表添加了category_id,并设置了它为T_category的外键

T_product_review里面添加了product_id,设置它为T_product的外键

所以导致了三表之间存在依赖关系,T_category<=T_product<=T_product_review

如果不这样顺序地添加数据,会外键报错

5.总结
  • 增用到insert,改用到update,删用到delete,查用到select
  • 从上面多个例子我们在使用对应的语法时,需要根据不同的场景来去随机应变地使用他们。方法不是单一,要多思考,争取可以提高对应操作的效率。
posted @ 2022-11-09 16:00  travellerα  阅读(43)  评论(0)    收藏  举报