SQL SERVER数据库基本知识

SQL SERVER基本知识整理

Contents

1.数据库—DDL

1.1.创建数据库-CREATE
CREATE DATABASE test_db
ON
(
    NAME = test_db,
    FILENAME = 'D:\SQL server 2019\test\test_db.mdf',
    SIZE = 6,
    MAXSIZE = 10,
    FILEGROWTH = 1
)
LOG ON
(
    NAME = test_log,
    FILENAME = 'D:\SQL server 2019\test\test_db_log',
    SIZE = 1MB,
    MAXSIZE = 2MB,
    FILEGROWTH = 1
)
GO
CREATE DATABASE [sample_db] ON PRIMARY
(
    NAME = 'sample_db',
    FILENAME = 'D:\SQL server 2019\sample\sample.mdf',
    SIZE = 512KB,
    MAXSIZE = 30MB,
    FILEGROWTH = 5%
)
LOG ON
(
    NAME = 'sample_log',
    FILENAME = 'D:\SQL server 2019\sample\sample_log.ldf',
    SIZE = 1024KB,
    MAXSIZE = 8192KB,
    FILEGROWTH = 10%
)
GO
CREATE DATABASE newDBdata on PRIMARY
(
    NAME = 'newDBdata',
    FILENAME = 'D:\SQL server 2019\newDBdata\newDBdata.mdf',
    SIZE = 2MB,
    MAXSIZE = 20MB,
    FILEGROWTH = 10%
)
LOG ON
(
    NAME = 'newDBlog',
    FILENAME = 'D:\SQL server 2019\newDBdata\newDBlog.ldf',
    SIZE = 1MB,
    FILEGROWTH = 5%
)
#关于ON PRIMARY
SQL Server中的ON PRIMARY表示将表或数据库对象存储在主文件组中。在创建表或数据库对象时,可以通过ON PRIMARY指定该对象存储在主文件组中。如果未指定文件组,则默认存储在主文件组中,因此ON PRIMARY可以省略。
1.2.创建数据表-CREATE
CREATE TABLE authors
(
    auth_id int PRIMARY KEY,                #整型,数据库主键
    auth_name VARCHAR(20) NOT NULL unique,  #可变长字符串;不能为空;不能重复
    auth_gender tinyint NOT NULL DEFAULT(1) #性别
)
USE test_db
GO
CREATE TABLE teacher
(
    id INT NOT NULL PRIMARY KEY,
    name VARCHAR(20) NOT NULL,
    birthday DATE,
    sex VARCHAR(4),
    cellphone VARCHAR(18)
)
1.3.修改数据库参数-MODIFY FILE
ALTER DATABASE sample_db
MODIFY FILE
(
    NAME=sample_db,
    SIZE=15MB                   #修改初始大小
)
GO
ALTER DATABASE sample_db
MODIFY FILE
(
    NAME=sample_db,
    MAXSIZE=50MB                 #修改最大容量
)
GO
1.4.删除数据库-DROP
DROP DATABASE sample_db;         #删除数据库
1.5.重命名数据-MODIFY NAME
ALTER DATABASE sample_db
    MODIFY NAME = sample_db2;    #修改数据库名
1.6.重命名数据库-EXEC sp_renamedb
exec sp_renamedb 'test_db','test_db1';
1.8.重命名列名-EXEC sp_rename
EXEC sp_rename 'authors.auth_name1','auth_name2','COLUMN';

2.数据表-DML

2.1.增加字段-ALTER ADD

方法一:点击表,右键设计

image-20250410172609015

方法二:存储过程增加字段

ALTER TABLE authors
ADD auth_note VARCHAR(100) NULL
ALTER TABLE AUTHORS
ADD birth DATE NOT NULL
2.2.修改字段类型-ALTER ALTER
ALTER TABLE authors
ALTER COLUMN auth_phone VARCHAR(15)
2.3.删除字段-ALTER DROP
ALTER TABLE authors DROP COLUMN birthdate
2.4.整个表删除-DROP
DROP TABLE authors
2.5.问题1:修改表后不能保存
image-20230505205449433

工具-》选项-》设计器-》取消勾选“阻止保存要求重新创建表的更改”

image-20230505205642964

2.6.数据的插入-INSERT
insert into teacher VALUES (1,'张三','1978-02-14','男','0018611')
SELECT * FROM teacher
SELECT * FROM teacher
INSERT INTO teacher VALUES (2,'李四','1978-11-21','女','0018624'),(3,'王五','1976-12-05','男','0018678'),(4,'赵纤','1980-6-5','女','0018699');
SELECT * FROM teacher
2.7.数据的更改-UPDATE
SELECT * FROM teacher WHERE id = 1;
UPDATE teacher
SET birthday = '1980-8-8',cellphone='0018600' WHERE id = 1;
SELECT * FROM teacher WHERE id = 1;
SELECT * FROM teacher;
UPDATE teacher SET cellphone = '01008611';
SELECT * FROM teacher;
2.8.数据删除-DELETE
delete from teacher where id = 1;
select * from teacher where id = 1;
select * from teacher;
delete from teacher;       #删除所有记录
select * from teacher;

3. 数据表-修改约束

3.1. 添加主键约束和唯一性约束
CREATE TABLE table_emp
(
    e_id CHAR(18) PRIMARY KEY,                      #主键
    e_name VARCHAR(25) NOT NULL,
    e_deptID INT,
    e_phone VARCHAR(15) CONSTRAINT uq_phone UNIQUE  #唯一性约束
)
3.2. 增加约束
use test_db1
alter table teacher add constraint uq_id unique(id);
3.3. 删除约束
alter table teacher drop constraint uq_id;

4. 数据查询-SELECT

4.1.查看数据库状态
select DATABASEPROPERTYEX('database_name','status') #显示“当前”数据库状态
sp_spaceused #显示“当前”数据库使用和保留空间
sp_helpdb  #查看“所有”数据库的基本信息
use test_db1
select DATABASEPROPERTYEX('test_db1','status') AS '数据库状态'
image-20230504225138472

sp_spaceused #显示数据库使用和保留空间
image-20230504225424525

sp_helpdb  #查看所有数据库的基本信息
image-20230504225811502

4.2.查看某个数据库里面的所有表
SELECT TABLE_NAME 
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_CATALOG = '你的数据库名';
4.3.常用查找方法

#先生成数据表

USE test_db1
GO
CREATE TABLE stu_info
(
    s_id INT PRIMARY KEY,
    s_name VARCHAR(40),
    s_score INT,
    s_sex CHAR(2),
    s_age VARCHAR(90)
);
INSERT INTO stu_info
VALUES (1,'许三',98,'男',18),
       (2,'张靓',70,'女',19),
       (3,'王宝',25,'男',18),
       (4,'马华',10,'男',20),
       (5,'李岩',65,'女',18),
       (6,'刘杰',88,'男',19);
USE test_db
GO
SELECT * FROM stu_info;
SELECT s_name,s_score FROM stu_info;
SELECT s_name,s_score,s_score-5 AS new_score FROM stu_info;
SELECT * FROM stu_info WHERE s_sex='男';
SELECT * FROM stu_info WHERE s_sex='男' AND s_score > 80;
SELECT * FROM stu_info WHERE s_score > 80 OR s_age > 18;
USE test_db
GO
SELECT * FROM stu_info WHERE s_name NOT LIKE '%刘%'
4.4. 消除重复-DISTINCT
USE test_db
CREATE TABLE fruits
(
f_id char(10) PRIMARY KEY,       --水果ID
s_id INT    NOT NULL,            --供应商ID
f_name VARCHAR(255)  NOT NULL,   --水果名称
f_price decimal(8,2) NOT NULL,   --水果价格
);
INSERT INTO fruits (f_id,s_id,f_name,f_price) VALUES ('a1',101,'apple',5.2),('b1',101,'blackberry',10.2),('bs1',102,'orange',11.2),('bs2',105,'melon',8.2),('t1',102,'banana',10.3),('t2',102,'grape',5.3),('o2',103,'coconut',9.2),('c0',101,'cherry',3.2),('a2',103,'apricot',2.2),('l2',104,'lemon',6.4),('b2',104,'berry',7.6),('m1',106,'mango',15.6);
SELECT f_id,s_id,f_name,f_price FROM fruits;

使用DISTINCT消除重复

SELECT DISTINCT s_id FROM fruits;
4.4.返回前n行-TOP
SELECT TOP 3 * FROM stu_info;
SELECT TOP(3) * FROM fruits;
SELECT TOP 30 PERCENT * FROM fruits;
4.5.查询别名-AS
SELECT f_name AS '名称',f_price AS '价格' from fruits;
SELECT '名称'=f_name,'价格'=f_price FROM fruits;
SELECT '供应商编号:',s_id,'水果编号:',f_id FROM fruits;
SELECT f_name,f_price 原价,f_price * 0.8 折扣价 FROM fruits;
4.6. 条件查询查询-WHERE
SELECT f_name,f_price From fruits WHERE f_price = 10.2;
SELECT f_name,f_price From fruits WHERE f_name='apple';
SELECT f_name,f_price From fruits WHERE f_price<10;
4.7. 两个数值之间-BETWEEN AND
SELECT f_name,f_price FROM fruits WHERE f_price BETWEEN 2.00 and 10.20;
4.8.匹配列出选项-IN,NOT IN
SELECT s_id,f_name,f_price FROM fruits WHERE s_id IN (101,102);
SELECT s_id,f_name,f_price FROM fruits WHERE s_id NOT IN (101,102);
4.9 模糊查询-LIKE + 通配符
SELECT f_id,f_name FROM fruits WHERE f_name LIKE 'b%'; #b字母开头的
SELECT f_id,f_name FROM fruits WHERE f_name LIKE '%g%'; #包含字母'g'的记录
SELECT f_id,f_name FROM fruits WHERE f_name LIKE 'b%y'; #b开头y结尾
SELECT f_id,f_name FROM fruits WHERE f_name LIKE '____y'; #一个_代表一个字符
SELECT f_id,f_name FROM fruits WHERE f_name LIKE '[abc]%'; #[]指定一个字符集合,只要匹配其中任何一个字符,即为所查找的文本。
SELECT f_id,f_name FROM fruits WHERE f_name LIKE '[^abc]%'; #^匹配不以指定集合中的任何字符开头
SELECT * FROM stu_info WHERE s_name like '马%';
SELECT * FROM stu_info WHERE s_name like '[张王李]%';

创建一个新的表

USE test_db
GO
CREATE TABLE customers
(
c_id char(10) PRIMARY KEY,
c_name varchar(255) NOT NULL,
c_email varchar(50) NULL,
);
INSERT INTO customers (c_id,c_name,c_email)
VALUES('10001','RedHook','LMing@163.com'),
('10002','Stars','jerry@hotmail.com'),
('10003','RedHook',NULL),
('10004','JOTO','sam@hotmail.com');
SELECT c_id,c_name,c_email FROM customers WHERE c_email IS NULL; #查找空值
SELECT c_id,c_name,c_email FROM customers WHERE c_email IS NOT NULL; #非空值
4.10. 布尔子句-EXISTS

在 SQL Server 中,EXISTS 是一个布尔子句,用于检查子查询是否返回任何行。如果子查询返回至少一行数据,EXISTS 将返回 TRUE;如果子查询没有返回任何行,EXISTS 将返回 FALSE。EXISTS 通常用于 WHERE 或 HAVING 子句中,以基于另一个查询的结果来过滤数据。

USE test_db
GO
CREATE TABLE suppliers
(
s_id char(10) PRIMARY KEY,
s_name varchar(50) NOT NULL,
s_city varchar(50) NOT NULL
);
INSERT INTO suppliers(s_id,s_name,s_city) VALUES('101','FastFruit Inc','Tianjin'),('102','LT Supplies','shanghai'),('103','ACME','beijing'),('104','FNK Inc','zhengzhou'),('105','Good Set','xinjiang'),('106','Just Eat Ours','yunnan'),('107','JOTO meoukou','guangdong');
#“EXISTS”利用子查询来判断TURE和FALSE,TURE继续外层查询,FLASE则停止。
SELECT * FROM fruits
WHERE EXISTS
(SELECT s_name FROM suppliers WHERE s_id = 107);
#子查询能进行,才能进行外层查询
SELECT * FROM fruits
WHERE f_price >10.20 AND EXISTS
(SELECT s_name FROM suppliers WHERE s_id = 107);
4.11. 升降排序-ORDER BY
SELECT f_name FROM fruits ORDER BY f_name;
#顺序排列
SELECT f_name,f_price FROM fruits ORDER BY f_name,f_price;
#多列排序
SELECT f_name,f_price FROM fruits ORDER BY f_price DESC;
#降序排列
SELECT * FROM stu_info ORDER BY s_score DESC; 
#降序排列
4.12. 分组排序-GROUP BY
SELECT s_id,COUNT(*) AS Total FROM fruits GROUP BY s_id;
#COUNT()函数,把数据分为多个逻辑组,并对每个组进行集合计算。
image-20250413100559285

SELECT s_id,f_name FROM fruits group by s_id,f_name;
#先按第一个字段来分组,再按第二个字段
image-20250413100420651

SELECT s_id,count(*) AS Total FROM fruits GROUP BY s_id HAVING count(*) >1;
#使用HAVING对分组结果再过滤
image-20250413100825249

4.13. 合并结果排序-UNION
#不使用union all
SELECT s_id,f_name,f_price FROM fruits WHERE f_price < 9.0;
image-20250413101853251

#使用union all
SELECT s_id,f_name,f_price FROM fruits WHERE f_price < 9.0 UNION ALL SELECT s_id,f_name,f_price FROM fruits WHERE s_id = 101;
image-20250413101921605

#使用union
#UNION不使用关键字ALL,执行的时候会删除重复的记录,所有返回的行都是唯一的;使用关键字ALL的作用是不删除重复行也不对结果进行自动排序
SELECT s_id,f_name,f_price FROM fruits WHERE f_price < 9.0 UNION SELECT s_id,f_name,f_price FROM fruits WHERE s_id = 101;
image-20250413102645776

4.14.查找表里的所有约束

方法一:

SELECT 
    CONSTRAINT_NAME,
    CONSTRAINT_TYPE
FROM
    INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE
    TABLE_NAME='ORDERS'
ORDER BY 
    CONSTRAINT_TYPE;
image-20250417143122592

方法二:

image-20250417143528854

image-20250417143417865

5. 嵌套查询

5.1. 使用比较运算符

#查找出产地为tianjin的水果

#查找出产地为tianjin的水果
use test_db1
select * from fruits;
select * from suppliers;
image-20250413110502722

SELECT s_id,f_name FROM fruits
WHERE s_id = 
(SELECT s1.s_id FROM suppliers AS s1 WHERE s1.s_city = 'Tianjin');

#查找出产地不是Tianjin的水果

SELECT s_id,f_name FROM fruits
WHERE s_id <>
(SELECT s1.s_id FROM suppliers AS s1 WHERE s1.s_city = 'Tianjin');
5.2 使用IN关键字
#IN相当于“=”
#找出水果表f_id='c0'相对应供应商
USE test_db
GO
SELECT s_name FROM suppliers WHERE s_id IN
(SELECT s_id FROM fruits WHERE f_id = 'c0');
#找出水果表f_id='c0'不相对应供应商
SELECT s_name FROM suppliers WHERE s_id NOT IN
(SELECT s_id FROM fruits WHERE f_id = 'c0');
5.3. 使用ANY、SOME、ALL关键字

创建表

USE test_db
GO
CREATE  table tbl1 (num1 INT NOT NULL);
CREATE table tbl2 (num2 INT NOT NULL);
INSERT INTO tbl1 values(1),(5),(13),(27);
INSERT INTO tbl2 values(6),(14),(11),(20);
#tbl1表里面的其中一个值比tbl2里面任何一个值大,都会返回数值。
SELECT num1 FROM tbl1 WHERE num1 > ANY(SELECT num2 FROM tbl2);
#“ANY”如果与子查询返回的任何值比较结果为TRUE,则返回TRUE。
image-20250414164856929

image-20250414164909407

image-20250414164943149

ANY和SOME在功能上是相同的,它们都可以用来与子查询返回的任何一个值进行比较。例如,SELECT column FROM table WHERE column > ANY (SELECT column FROM subquery) 表示如果主查询的列值大于子查询返回的任何一个值,则返回该行。
SOME是ANY的别名,主要用于区分关键字ANY和英文中的any。在实际使用中,两者可以互换使用,功能完全相桐
image-20250414165717546

#必须要满足num1的里面其中一数值必须要比tbl2的所有数值都大,才会返回结果
SELECT num1 FROM tbl1 WHERE num1 > ALL(SELECT num2 FROM tbl2);
#"ALL"使用ALL时需要同时满足所有内层查询的条件。
image-20250414165105431

6. 多表连接查询

6.1. 相等连接
#内连接
#fruits和suppliers表总都有相同含义的字段s_id,这两个数据表通过s_id字段建立联系。从fruits表中查询f_name和f_price字段,从suppliers表中查询s_id和s_name字段。

SELECT suppliers.s_id,s_name,f_name,f_price FROM fruits INNER JOIN suppliers
ON fruits.s_id = suppliers.s_id;

#依次按顺序来匹配需要的查询
image-20250414170949818

image-20250414171021265

image-20250414171839174

6.2. 不等连接
#与不是对应s_id的供应商进行连接
SELECT suppliers.s_id,s_name,f_name,f_price FROM fruits INNER JOIN suppliers ON fruits.s_id <> suppliers.s_id;
image-20250414172714091

6.3. 带选择条件的连接
SELECT fruits.s_id,suppliers.s_city FROM fruits INNER JOIN suppliers ON fruits.s_id = suppliers.s_id AND fruits.s_id = 101;

6.4. 自连接
SELECT f1.f_id,f1.f_name FROM fruits AS f1,fruits AS f2 WHERE f1.s_id = f2.s_id AND f2.f_id = 'a1';
image-20250414173700110

6.5. 外连接

实验1

USE test_db
GO
CREATE TABLE student
(
    s_id INT,
    name VARCHAR(40)
);

CREATE TABLE stu_detail
(
    s_id INT,
    class VARCHAR(40),
    addr VARCHAR(90)
);
INSERT INTO student VALUES(1,'wanglin1'),(2,''),(3,'zhanghai');
INSERT INTO stu_detail VALUES(1,'wuban','henan'),(2,'liuban','hebei'),(3,'qiban','');
image-20250414174824388

image-20250414175227686

6.5,1.左外连接
#返回包括左表中的所有记录和右表中连接字段相等记录
SELECT student.s_id,stu_detail.addr FROM student LEFT OUTER JOIN stu_detail ON student.s_id = stu_detail.s_id;
image-20250414175806054

6.5.2.右外连接
#返回包括右表中的所有记录和右表中连接字段相等记录
SELECT student.name,stu_detail.s_id FROM student RIGHT OUTER JOIN stu_detail ON student.s_id = stu_detail.s_id;
image-20250414180031283

6.5.3.全外连接
#返回两个连接中所有的记录数据
SELECT student.name,stu_detail.addr FROM student FULL OUTER JOIN stu_detail ON student.s_id = stu_detail.s_id;
image-20250414180336141

6.6.内连接,左外连接,右外连接,全外连接的区别
img

内连接,也叫等值连接, inner join得出同时存在t1表和t2表的数据集,通俗一点说就是求两个表的交集。

img

“inner join”两边的表的位置可以互换,结果都一样

img

左连接:left [outer] join,左连接从左表取出所有记录,与右表匹配。如果没有匹配,以null值代表右边表的列。outer 可以不写,默认情况下不写outer关键字。

img

“left join”两边的表的位置不可以互换,交换后结果可能不一样。需要考虑好哪个是主表,哪个是从表。写在前面的是主表

img

右连接:right [outer] join,右连接从右表取出所有记录,与左表匹配。如果没有匹配,以null值代表左边表的列。outer 可以不写,默认情况下不写outer关键字。

img

img

全连接:两个表的并集,MySQL暂不支持这种语句,不过可以使用union将两个结果集“堆一起”,利用左连接,右连接分两次将数据取出,然后用union将数据合并去重。

img

img

6.6.内容转载自:图解数据库左连接、右连接、内连接、外连接、全连接 – 积极向上的徐先生 – 博客园

7. 权限操作

7.1. 授予-GRANT
#找出数据库里面的所有用户
EXEC sp_helpuser;
image-20250415132432011

#WITH GRANT OPTION 表示该用户还可以向其他用户授予其自身拥有的权限。
GRANT UPDATE,DELETE ON stu_info TO guest WITH GRANT OPTION
7.2. 拒绝-DENY
#CASCADE:对父表进行delete,update操作时,子表也会delete,update掉关联的记录。更新/删除主表中记录时自动更新/删除子表中关联记录。
DENY UPDATE ON stu_info TO guest CASCADE;
7.3. 收回-REVOKE
REVOKE DELETE ON stu_info FROM guest CASCADE;
7.4. 声明-DECLARE
#五条指令一起执行
DECLARE @username VARCHAR(20)
DECLARE @pwd VARCHAR(20)
SET @username = 'newadmin'
SELECT @pwd = 'newpwd' #跟'set'一样
SELECT '用户名:'+ @username +' 密码:' + @pwd  
USE test_db
GO
DECLARE @stuscore INT
SELECT s_score From stu_info
SELECT @stuscore = s_score FROM stu_info #由最后的数据开始读取
SELECT @stuscore  AS Lastscore 

8. 数据输出-PRINT

DECLARE @name VARCHAR(10)='小明'
DECLARE @age INT =21
PRINT '姓名   年龄'
PRINT @name+'   '+CONVERT(VARCHAR(20),@age) #不能直接输出int的数据类型

9. 流程控制

9.1. WHILE BEGIN…END语句
WHILE @count < 10
BEGIN
    PRINT 'count = ' + CONVERT(VARCHAR(8),@count)
    SELECT @count = @count+1
END
PRINT 'loop over count = ' + CONVERT(VARCHAR(8),@count)
DECLARE @num INT;
SELECT @num=10;
WHILE @NUM > -1
BEGIN
    IF @num > 5
        BEGIN
            PRINT '@num 等于' + CONVERT(VARCHAR(4),@num)+'大于5 循环执行';
            SELECT @num = @num -1;
            CONTINUE;
        END
    ELSE
        BEGIN
            PRINT '@num 等于' + CONVERT(VARCHAR(4),@num);
            BREAK;
        END
END
PRINT '循环终止之后@num 等于 ' + CONVERT(VARCHAR(4),@num);
9.2. IF…ELSE语句
DECLARE @age INT;
SELECT @age=40
IF @age <30
    PRINT 'This is a young man!'
ELSE
    PRINT 'This is an old man!'
9.3. CASE WHEN THEN语句
在 SQL Server 中,CASE 表达式是一种用于条件逻辑判断的强大工具。它允许你在查询中基于不同的条件返回不同的值。CASE 表达式有两种主要形式:简单 CASE 表达式和搜索 CASE 表达式。然而,在大多数情况下,我们使用的是搜索 CASE 表达式,因为它允许基于多个条件进行判断。

CASE
    WHEN condition1 THEN result1
    WHEN condition2 THEN result2
    ...
    [ELSE else_result]
END

condition1, condition2, … 是你要评估的布尔表达式。
result1, result2, … 是当相应条件为真时要返回的值。
ELSE else_result 是可选的,当所有条件都不满足时返回的值。如果省略 ELSE 部分,并且没有条件为真,则 CASE 表达式返回 NULL。
USE test_db
GO
SELECT s_id,s_name,
CASE s_name
    WHEN '马华' THEN '班长'
    WHEN '许三' THEN '学习委员'
    WHEN '刘杰' THEN '体育委员'
    ELSE '无'
END
AS '职位'
FROM stu_info
USE test_db
GO
SELECT s_id,s_name,s_score,
CASE
    WHEN s_score > 90 THEN '优秀'
    WHEN s_score > 80 THEN '良好'
    WHEN s_score > 70 THEN '一般'
    WHEN s_score > 60 THEN '及格'
    ELSE '不及格'
END
AS '评价'
FROM stu_info
9.4. GOTO语句
USE test_db;
BEGIN
SELECT s_name FROM stu_info;
GOTO jump
SELECT s_score FROM stu_info;
jump:
PRINT '第二条SELECT语句没有执行'
END
9.5. WAITFOR
#延迟10秒执行
DECLARE @name VARCHAR(50);
SET @name='admin';
BEGIN
WAITFOR DELAY '00:00:10';
PRINT @name;
END;
9.6. RETURN
SQL Server中的RETURN语句用于从存储过程、批处理或语句块中无条件退出,并且执行RETURN之后的语句将不会被执行
RETURN [value]
DECLARE  @I INT
SET @I =1
WHILE (@I <=10)
    BEGIN
        IF (@I=5)
            BEGIN 
                RETURN
            END
        ELSE 
            BEGIN 
                SET @I = @I+1
            END
        END

PRINT  '@I 的值:' + CAST(@I as varchar(5))
GO
PRINT '@@@@批处理后代码@@@@'

10.定义一个数据类型

10.1. 自定义一个数据类型

方法一:图形化操作

右键“用户定义数据类型”,新建

image-20230504233923947

方法二:存储过程

use test_db1
sp_addtype HomeAddress,'varchar(128)','not null'
10.2. 删除对象
sp_droptype HomeAddress

11.使用聚合函数统计汇总

11.1. 使用SUM()函数求列的和
#查找价格小于9,s_id编号是101的水果
select s_id,f_name,f_price from fruits where f_price <9.0 union select s_id,f_name,f_price from fruits where s_id = 101;
image-20250416162145682

SELECT s_id,SUM(f_price) AS sum_price
FROM fruits
GROUP BY s_id;
image-20250416161935711

11.2. 使用AVG()函数对指定字段求平均值
SELECT AVG(f_price) AS avg_price
FROM fruits
WHERE s_id = 103;
image-20250416162540731

SELECT s_id,AVG(f_price) AS avg_price
FROM fruits
GROUP BY s_id;
image-20250416162108836

11.3. 使用MAX()函数找出指定字段中的最大值
SELECT MAX(f_price) AS max_price FROM fruits;
image-20250416163415290

select f_name,f_price from fruits where f_price = (select max(f_price) from fruits);
image-20250416163357759

SELECT s_id,MAX(f_price) AS max_price FROM fruits GROUP BY s_id;
image-20250416164003140

SELECT MAX(f_name) FROM fruits;
image-20250416164718153

#按ASCII码来计算
由结果可以看到,MAX() 函数可以对字母进行大小判断,并返回最大的字符或者字符串值。

MAX() 函数除了用来找出最大的列值或日期值之外,还可以返回任意列中的最大值,包括返回字符类型的最大值。

在对字符类型数据进行比较时,按照字符的 ASCII 码值大小进行比较,从 a~z,a 的 ASCII 码最小,z 的最大。在比较时,先比较第一个字母,如果相等,继续比较下一个字符,一直到两个字符不相等或者字符结束为止。例如,“b”与“t”比较时,“t”为最大值;“bcd”与“bca”比较时,“bcd”为最大值。
11.4. 使用MIN()函数找出指定字段中的最小值
SELECT MIN(f_price) AS min_price FROM fruits;
image-20250416164827954

SELECT s_id,MIN(f_price) AS min_price FROM fruits GROUP BY s_id;
image-20250416165011848

11.5. 使用COUNT函数统计
SELECT COUNT(*) AS '客户总数' FROM customers;
#计算表里面的总行数
SELECT COUNT(c_email) AS email_num FROM customers;
#计算有c_email的里面有数据的总行数
SELECT s_id '供应商',COUNT(f_name) '水果种类数目'
FROM fruits
GROUP BY s_id;
image-20250416165333808

12.使用排序函数

12.1. ROW_NUMBER()-为每条记录增添递增的数字序号
#ROW_NUMBER()是一个Window函数,它为结果集的分区中的每一行分配一个连续的整数。 行号以每个分区中第一行的行号开头。
select row_number() over (order by s_id asc) as ROW_ID,s_id,f_name from fruits;
image-20250416170455815

12.2. RANK()-排名
#如果两个或多个行与一个排名关联,则每个关联行将得到相同排名
SELECT RANK() OVER (ORDER BY s_id ASC) AS RANKID,s_id,f_name FROM fruits;
image-20230520181151661

12.3. DENSE_RANK()-按顺序不间断排名

返回结果集分区中行的排名,在排名中没有任何间断

SELECT DENSE_RANK() OVER (ORDER BY s_id ASC) AS DENSEID,s_id,f_name FROM fruits;
image-20230520181507055

12.4. NTILE()-用来将查询结果中的记录分为N组
SELECT NTILE(5) OVER (ORDER BY s_id ASC) AS NTILEID,s_id,f_name FROM fruits;
image-20230520181853879

select NTILE(4) OVER (ORDER BY S_ID ASC) AS NTILEID,S_ID,F_NAME FROM FRUITS;
image-20250416172251186

13. 其他各类函数(1)

13.1. ASCII()函数
ASCII()函数在SQL Server中的作用是返回字符串表达式最左侧字符的ASCII代码值。该函数接受一个字符串表达式作为参数,并返回该字符串最左侧字符的ASCII代码值。参数必须是一个char或varchar类型的字符串表达式。
#找出对应的ASCII码
SELECT ASCII('s'),ASCII('sql'),ASCII(1);
image-20250415175634813

13.2. CHAR()函数
CHAR()函数在SQL Server中的作用是将整数类型的ASCII码值转换为对应的字符。具体来说,CHAR()函数将一个整数(ASCII码值)转换为对应的字符。这个整数必须是一个介于0到255之间的值,如果输入的整数不在这个范围内,CHAR()函数将返回NULL。
#把ASCII码转字符
SELECT CHAR(115),CHAR(49);
image-20250415175603496

13.3. LEFT()函数,RIGHT()函数
LEFT函数在SQL Server中的作用是用于从字符串的左侧提取子字符串。通过指定字符数,LEFT函数能够从字符串的开头提取指定数量的字符。这对于格式化数据、处理文本和提取关键信息等任务非常有用。
SELECT LEFT('football',4)
image-20250415175515128

SQL Server中的RIGHT函数用于从字符串的右侧提取指定数量的字符。
SELECT RIGHT('football',4)
image-20250415175537834

13.4. LTRIM()和RTRIM()函数
LTRIM()函数在SQL Server中的作用是去除字符串左侧的所有空格。具体来说,LTRIM()函数会从字符串的开始位置删除所有的空白字符,直到遇到第一个非空白字符为止。
SELECT '(' + ' book ' + ')', '(' + LTRIM (' book ') + ')';
image-20250415175854767

RTRIM()函数在SQL Server中的作用是去除字符串右侧的所有空格。
SELECT '(' + ' book ' + ')', '(' + RTRIM (' book ') + ')';
image-20250415180014147

13.5. STR()函数-保留某数值的长度
STR函数在SQL Server中的作用是将数值数据转换为字符串数据。该函数可以处理带有小数点的数字,并且可以指定总长度和小数位数,从而生成符合特定格式的字符串。
#中间一位表示字符的总长度,最后1位是小数点后面的位数
#不能显示整数部分的其中一些
SELECT STR(3141.59,6,1),STR(123.45,2,2);
image-20250415180648372

13.6. REVERSE(s)-逆序输出
SELECT REVERSE('abc');
image-20250415180720857

13.7. LEN(STR)-计算字符串的长度
SELECT LEN('NO'),LEN('日期'),LEN(12345);
image-20250415203929304

13.8. CHARINDEX(x)-计算字符的所在位置
CHARINDEX ( expressionToFind , expressionToSearch [ , start_location ] )

expressionToFind :目标字符串,就是想要找到的字符串,最大长度为8000 。
expressionToSearch :用于被查找的字符串。
start_location:开始查找的位置,为空时默认从第一位开始查找。

#默认找到第一符合的结果,找到之后立马停止
SELECT CHARINDEX('a','banana'),CHARINDEX('a','banana',4),CHARINDEX('na','banana',4);
image-20250415204506790

13.9. SUBSTRING(x)-保留字符串中的某一段
SUBSTRING(expression,start,length)  
expression
是字符串、二进制字符串、text、image、列或包含列的表达式。不要使用包含聚合函数的表达式。
start
是一个整数,指定子串的开始位置。
length
是一个整数,指定子串的长度(要返回的字符数或字节数)。

substring() ——任意位置取子串
SELECT SUBSTRING('breakfast',1,5),
SUBSTRING('breakfast',LEN('breakfast')/2,LEN('breakfast'));
image-20250416095235175

13.10. UPPER(x)函数-字母小写变大写
#小写变大写
SELECT UPPER('black'),UPPER('Black');
image-20250416095452921

13.11. REPLACE(x)-替换
SELECT REPLACE('xxx.sqlserver2019.com','x','w');
image-20250416095600172

11.12. ABS(X)-返回X的绝对值
SELECT ABS(2),ABS(-3.3),ABS(-33);
image-20250416095754867

13.13. pi()函数-圆周率
SELECT pi();
image-20250416095943119

image-20250416100055935

13.14.FLOOR(X)-数据舍入
在数据分析和处理中,我们经常需要对数值进行精确控制,比如将数值舍入到特定的精度。SQL Server 提供了多种数学函数,其中 FLOOR 函数就是用来执行向上舍入操作的强大工具。FLOOR 函数是 SQL Server 中的一个内置函数,它能够将数值向上舍入到最接近的整数或指定的基数。不同于四舍五入,FLOOR 函数总是向更小的数值方向舍入。

FLOOR 函数的语法

FLOOR 函数的基本语法如下:
FLOOR(numeric_expression, [integer])
numeric_expression 是要舍入的数值表达式。
integer 是可选参数,表示舍入到哪个基数的倍数。如果省略,数值将被舍入到最接近的整数。
#函数在处理负数值时,向上舍入,直接忽略小数点,向前进位
SELECT FLOOR(-21.199776) AS Result;
image-20250416102536157

#函数在处理正数值时,直接忽略小数点,不向前进位
SELECT FLOOR(21.799776) AS Result;
image-20250416102752026

13.15. RAND(x)-随机函数
#在SQL Server中,RAND()是一个函数,用于返回一个介于 0 和 1 之间的随机浮点数。这个函数在每次调用时都会生成一个新的随机数,除非在调用之间设置了种子值。
SELECT RAND(),RAND(),RAND();
image-20250416100546920

#下面的查询将基于种子值 123 生成一个随机数。如果再次执行相同的查询,它将返回相同的随机数。
SELECT RAND(123);
#生成一个介于 1 和 100 之间的随机整数:
SELECT FLOOR(rand()*100)+ 1 AS Result;
13.16. ROUND(x,y)-返回接近于参数x的数
#返回接近于参数x的数,其值保留到小数点后面y位,但是保留原来位数用0来代替,若y为负值,则将保留x值到小数点左边y位。
#采用四舍五入的规则。
SELECT ROUND(1.38,1),ROUND(1.38,0),ROUND(232.38,-1),ROUND(232.38,-2),ROUND(232.82,1),ROUND(232.82,0);
image-20250416103528651

13.17. SIGN(x)-返回参数的符号
#返回参数的符号
SELECT SIGN(-21),SIGN(0),SIGN(21);
image-20250416103734720

13.18. CEILING(x)-向上取整
CEILING函数在SQL Server中用于将数值向上取整到最接近的整数或指定的倍数。
CEILING(number, [significance])
number:是要向上取整的数值。
significance:(可选)是取整的基数或倍数。如果省略,则默认取整到最接近的整数
#返回不小x的最小整数,不采用四舍五入
SELECT CEILING(-3.35),CEILING(3.35);
image-20250416111357990

#返回不大于x的最大整数值
SELECT FLOOR(-3.35),FLOOR(3.35);
image-20250416111523188

13.19. power(x,y)-计算数值表达式的指定幂次
SQL Server中的POWER()函数用于计算数值表达式的指定幂次。
#返回x的y次乘方的结果值
#2的负二次方=1÷2²=4分之1,2的2次方的倒数
SELECT POWER(2,3),POWER(2.00,-3)
image-20250416112239358

13.20.SQUARE(x)-开平方
SQL Server中的SQUARE()函数用于计算一个数的平方。该函数的基本语法如下:
#返回指定浮点值x的平方
SELECT SQUARE(3),SQUARE(-3),SQUARE(0);
image-20250416112303742

13.21.EXP(x)-冥运算函数
SELECT EXP(3),EXP(-3),EXP(0);
#返回e的x的乘方后的值
#e指数是一个自然常数,通常用e表示,其值约等于2.71828
13.22. SQRT(x)-返回非负数x的二次方根
#不能使用负数
SELECT SQRT(9),SQRT(40);
image-20250416112455708

13.23. LOG(x)和LOG10(x)-对数运算函数
在 SQL Server 中,LOG 函数用于计算数值的自然对数(以 e 为底的对数)。这个函数在数学和科学计算中非常有用,特别是在处理与对数相关的数据时。
LOG (float_expression [, base])
float_expression:是要求自然对数的浮点数值表达式。
base:(可选)是用于计算对数的底数。如果省略 base,则默认计算自然对数(即以 e 为底的对数)。如果指定了 base,则 LOG 函数会返回以该底数为基准的对数。

e的定义:

img

#返回x的自然对数,即返回x相对于基数e的对数
#e的多少次方为3,e的多次方是6
SELECT LOG(3),LOG(6);
image-20250416153337006

#返回x的基数为10的对数
#10的多少次方为100
SELECT LOG10(1),LOG10(100),LOG10(1000);
image-20250416153401993

13.24. RADIANS(x)、DEGREES(x)-角度与弧度相互转换的函数
#角度转弧度
SELECT RADIANS(90.0),RADIANS(180.0);
image-20250416153520001

#弧度转角度
SELECT DEGREES(PI()),DEGREES(PI()/2);
image-20250416153537909

13.25. SIN(x)和ASIN(x)
SELECT SIN(PI()/2),ROUND(SIN(PI()),0);
SELECT ASIN(1),ASIN(0);
image-20250416153615862

13.26. COS(x)和 ACOS(x)
SELECT COS(0),COS(PI()),COS(1);
SELECT ACOS(1),ACOS(0),ROUND(ACOS(0.5403023058681398),0);
image-20250416153630823

13.27. TAN(x)、ATAN(x)、COT(x) – 正切余切
SELECT TAN(0.3),ROUND(TAN(PI()/4),0);
#返回x的正切,其中x为给定的弧度值
image-20250416153655766

SELECT ATAN(0.30933624960962325),ATAN(1);
#ATAN()和TAN()互为反函数
image-20250416153714166

SELECT COT(0.3),1/TAN(0.3),COT(PI()/4);
#COT(x)返回x的余切,COT()和TAN()互为函数
image-20250416153733232

14.其他各类函数(2)

14.1. CAST() 和 CONVERT()-转换函数
SELECT CAST('201231' AS DATE),CAST(100 AS CHAR(3)),CONVERT(TIME,'2020-05-01 12:11:10');
#第一个,转换为日期类型
#第二个,转换为字符串类型
#第三个,datetime类型转换为time类型
image-20250416153822723

14.2. TEXTPTR()-文本指针
USE test_db
GO
CREATE TABLE t1 (c1 int, c2 text)
INSERT t1 VALUES('1','This is text.')



SELECT c1, TEXTPTR(c2) FROM t1 WHERE c1 = 1
#返回本指针
image-20250416154156734

14.3. TEXTVALID()-检查特定文本指针是否有效
SELECT c1, 'This is text.' = TEXTVALID('t1,c2',TEXTPTR(c2)) FROM t1;
image-20250416154218071

14.4. GETDATE()-返回数据库系统的日期和时间
SELECT GETDATE();
image-20250416154248747

14.5. UTCDATE()-返回当前的UTC日期值
SELECT GETUTCDATE();
image-20250416154304370

14.6. DAY(d)-返回月内指定日期的天数
SELECT DAY('2020-11-12 01:01:01');
#返回指定日期d是一个月中的第几天,范围是从1到31,该函数再功能上等价与DATEPAT(dd,d)
image-20250416154351963

14.7. MONTH(d)-返回指定日期d中月份的整数值
SELECT MONTH('2020-04-12 01:01:01');
image-20250416154406792

14.8. YEAR(d)-返回指定日期d中年份的整数值
SELECT YEAR('2020-02-03'),YEAR('2021-02-03');
image-20250416154427526

14.9. DATENAME(dp,d)-返回日期中定制部分的整数值
SELECT DATENAME(year,'2020-11-12 01:01:01'),DATENAME(weekday,'2020-11-12 01:01:01'),DATENAME(dayofyear,'2020-11-12 01:01:01');
image-20250416154456072

14.10. DATEADD(dp,num,d)-返回指定日期加上一个时间段的新日期
SELECT 
DATEADD(year,1,'2020-11-12 01:01:01'),
DATEADD(month,1,'2020-11-12 01:01:01'),
DATEADD(hour,1,'2020-11-12 01:01:01');
image-20250416154517025

14.11. COL_LENGTH(table,column-返回表中指定字段的长度值
USE test_db
GO
SELECT COL_LENGTH('stu_info','s_name');
image-20250416154539774

14.12. COL_NAME(table_id,column_id)-返回表中指定字段的名称
SELECT COL_NAME(OBJECT_ID('test_db.dbo.stu_info'),1);
image-20250416154600303

14.13. DATALENGTH(expression)-返回数据表达式得数据得实际长度
USE test_db;
GO
SELECT DATALENGTH(s_name) FROM stu_info WHERE s_id = 1;
image-20250416154647360

14.14. DB_ID(database_name)-返回数据库得编号
SELECT DB_ID('master'),DB_ID('test_db')
image-20250416154706334

14.15. DB_NAME(database_id)- 函数返回数据库得名称
USE master
GO
SELECT DB_NAME(),DB_NAME(DB_ID('test_db'));



USE master
GO
SELECT DB_NAME(),DB_NAME(6);
image-20250416154739108

14.16. GETANSINULL(database_name) – 返回当前数据库默认得NULL值
SELECT GETANSINULL('test_db')
image-20250416154813056

14.17. HOST_ID() – 返回计算机得标识号
SELECT HOST_ID();
image-20250416154826650

14.18. HOST_NAME – 返回服务端计算机名称
SELECT HOST_NAME();
image-20250416154839211

14.19. OBJECT_ID() – 返回数据库对象编号
#OBJECT_ID(database_name.schema_name.object_name,object type)
SELECT OBJECT_ID('test_db.dbo.stu_info');
image-20250416154907913

14.20. SUSER_ID – 返回用户的SID
SELECT SUSER_SID('DESKTOP-SL3SPO2\Administrator')
SELECT SUSER_SID('sa');
image-20250416155506274

14.21. SUSER_SNAME – 返回用户的登录名
SELECT SUSER_SNAME(0x010500000000000515000000610A28659DE1342203BC96CEF4010000);
image-20250416155559983

14.22. OBJECT_NAME – 返回数据库对象名称
SELECT OBJECT_NAME(645577338,DB_ID('test_db')),
OBJECT_ID('test_db.dbo.stu_info');
image-20250416155707711

14.23. USER_ID – 返回数据用户ID
USE test_db;
SELECT USER_ID();
image-20250416155725035

14.24. USER_NAME(1) – 返回数据库用户名
USE test_db;
SELECT USER_NAME();
image-20250416155740017

15.动态查询

USE test_db
GO
DECLARE @id INT;
DECLARE @sql varchar(8000)
SELECT @id=101;
SELECT @sql = 'SELECT f_name,f_price 
FROM fruits 
WHERE s_id = ';
exec (@sql + @id);

16.经典习题

16.1.经典习题
  1. 创建数据库Market,在Market中创建数据表customers,customers表结构如表3-2所示,按要求进行操作。
image-20230505231958890

1.创建数据库Market。
2.创建数据表customers,再c_id字段上添加主键约束,在c_birth字段上添加非空约束。
3.将c_name字段数据类型改为VARCHAR(70)。
4.将c_contact字段改名为c_phone。
5.增加c_gender字段,数据类型为CHAR(1)。
6.将表明修改为customers_info。
7.删除字段c_city。

(1)创建数据库Market

CREATE DATABASE [Market] ON PRIMARY
(
    NAME = Market,
    FILENAME = 'D:\SQL server 2019\Market\market_db.mdf',
    SIZE = 10MB,
    MAXSIZE = 50MB,
    FILEGROWTH = 5%
)
LOG ON
(
    Name = Market_log,
    FILENAME = 'D:\SQL server 2019\Market\market_log.ldf',
    SIZE = 2MB,
    FILEGROWTH = 5%
)

(2)创建数据表customers,再c_id字段上添加主键约束,在c_birth字段上添加非空约束。

USE Market
CREATE TABLE customers
(
    c_id INT PRIMARY KEY NOT NULL,
    c_name VARCHAR(50),
    c_contact VARCHAR(50),
    c_city VARCHAR(50),
    c_birth DATETIME NOT NULL
)

(3)将c_name字段数据类型改为VARCHAR(70)。

ALTER TABLE customers
ALTER COLUMN c_name VARCHAR(70)

(4)将c_contact字段改名为c_phone。

exec sp_rename 'customers.c_name','c_phone'

(5)增加c_gender字段,数据类型为CHAR(1)

ALTER TABLE customers ADD c_gender CHAR(1)

(6)将表名修改为customers_info。

exec sp_rename 'customers','customers_info'

(7)删除字段c_city。

ALTER TABLE customers_info DROP COLUMN c_city
  1. 在Market中创建数据表orders,orders表结构如表3-3所示,按要求进行操作。


    image-20230505232155186

(1)创建数据表orders,在o_num字段上添加主键约束,在c_id字段上添加外键约束,关联customers表中的主键c_id。
(2)删除orders表的外键约束,然后删除表customers。
SQL SERVER里面没有INT(11)的写法,这个写法见于MYSQL,括号里的数字表示“显示宽度”,仅控制客户端显示时补零的对齐方式(如ZEROFILL)

(1)创建数据表orders,在o_num字段上添加主键约束,在c_id字段上添加外键约束,关联customers表中的主键c_id。

USE Market
CREATE TABLE orders
(
    o_num INT PRIMARY KEY NOT NULL,
    o_date DATE,
    c_id INT,
    CONSTRAINT fk_cid FOREIGN KEY (c_id) REFERENCES customers_info(c_id)
)

(2)删除orders表的外键约束,然后删除表customers。

ALTER TABLE orders DROP CONSTRAINT fk_cid
USE Market DROP TABLE customers_info‘
16.2.经典习题
16.2.1.SQL Server系统数据类型都有哪些,各种数据类型都有什么特点?

1.整数数据类型,特点:

整数数据类型是常用的数据类型之一,主要用于存储数值,可以直接进行数据运算而不必使用函数转换。

2.浮点数据类型,特点:

浮点数据类型存储十进制小数,它是用于表示浮点数值数据的一种数据类型。浮点数据为近似值;浮点数值的数据在SQL Server中采用只入不舍的方式进行存储,即要舍入的数是一个非零数时,对其保留数字部分的最低有效位上的数字加1,并进行必要的进位。

3.字符数据类型,特点:

用来储存各种字母、数字符号和特殊符号。在使用字符数据类型时,需要在其前后加入英文单引号或者双引号。

4.日期和时间数据类型,特点:

存储用字符串表示的日期数据,可以表示0001-01-01到9999-12-31(公元元年1月1日到公元9999年12月31日)间的任意日期值。数据格式为“YYYY-MM-DD”。

5.二进制数据类型,特点:

类型:BINARY, VARBINARY, VARBINARY(MAX)
特点:
存储内容:二进制数据(如图片、文件、序列化对象等)。
固定长度:BINARY(n) 固定长度为 n 字节,不足时填充零。
可变长度:VARBINARY(n) 最大长度为 n 字节,按实际数据长度存储。
大容量存储:VARBINARY(MAX) 支持最大 2GB 数据,替代已弃用的 IMAGE 类型。
适用场景:非文本类数据(如加密数据、文件内容)。

6.特殊数据类型,特点:

常见类型:UNIQUEIDENTIFIER, TIMESTAMP, SQL_VARIANT, XML, SPATIAL(GEOMETRY/GEOGRAPHY)
特点:
UNIQUEIDENTIFIER:存储全局唯一标识符(GUID),适用于分布式系统唯一键。
TIMESTAMP:自动生成的 8 字节二进制值,反映数据修改版本(非时间戳)。
SQL_VARIANT:可存储多种数据类型(如 INT, VARCHAR),但需谨慎使用(类型转换开销大)。
XML:存储结构化 XML 数据,支持 XQuery 查询和索引优化。
空间类型:GEOMETRY(平面坐标)和 GEOGRAPHY(地理坐标),用于地理信息系统(GIS)。

7.hierarchid,特点:

用途:高效表示树形层次结构(如组织结构、目录树)。
特点:
路径编码:以二进制形式存储节点路径(如 /1/2/3/),压缩存储空间。
内置方法:提供 GetAncestor()、GetDescendant()、GetLevel() 等方法,简化层次查询。
索引友好:支持深度优先和广度优先索引策略,优化查询性能。
动态更新:支持插入、移动节点操作,无需重构整棵树。

8.用户自定义的数据类型,特点:

定义方式:
别名类型:基于现有类型扩展(如 CREATE TYPE PhoneNumber FROM VARCHAR(20))。
CLR 类型:通过 .NET 程序集创建复杂类型(需启用 CLR 集成)。
特点:
数据一致性:统一字段格式(如邮政编码、电话号码),减少冗余约束。
作用域:仅在定义它的数据库中有效。
约束与默认值:可绑定规则(Rules)或默认值(Defaults)到 UDT。
局限性:无法直接修改,需删除后重建;CLR UDT 需维护程序集。
16.2.2.局部变量和全局变量有什么区别?

局部变量是用户可自定义的变量,它的作用范围仅在程序内部。在程序中通常用来储存从表中查询到的数据,或当作程序执行过程中暂存变量使用。

全局变量是sql server(WINDOWS平台上强大的数据库平台)系统内部使用的变量,其作用范围并不局限于某一程序,而是任何程序均可随时调用全局变量通常存储一些sql server(WINDOWS平台上强大的数据库平台)的配置设定值和效能统计数据。用户可在程序中用全局变量来测试系统的设定值或Transact-SQL命令执行后的状态值。

16.2.3.SQL Server运算符有哪几类,每一种运算符的使用方法和特点是什么?

包括算术运算符、逻辑运算符、比较运算符、位运算符、其他运算符

16.3.经典习题
1.Transact-SQL语句包含哪些具体内容?
2.使用Transact-SQL语句创建名为zooDB的数据库。
3.使用Transact-SQL语句删除zooDB数据库。
4.声明整数变量@var,使用CASE流程控制语句判断@VAR值等于1、等于2,或者两者都不等。
当@var值为1时,输出字符串"var is 1";
当@var值为2时,输出字符串"var is 2";
否则输出字符串"var is not 1 or 2"。

(1)Transact-SQL语句包含哪些具体内容?

T-SQL 的核心功能包括:

数据定义(DDL)与 数据操作(DML)。
事务控制与 权限管理(DCL)。
过程化编程(流程控制、错误处理)。
代码封装(存储过程、函数)。
动态 SQL 和 高级查询优化。

(2)使用Transact-SQL语句创建名为zooDB的数据库,指定的数据库参数如下:

逻辑文件名称:zooDB_data。
主文件大小:5MB
最大增长空间:15MB
文件增长大小为:5%
CREATE DATABASE [zooDB_data] on PRIMARY
(
    NAME = zooDB_data,
    FILENAME = 'D:\SQL server 2019\zooDB\zooDB_data.mdf',
    SIZE = 5MB,
    MAXSIZE = 15MB,
    FILEGROWTH = 5%
)
LOG on
(
    NAME = zooDB_log,
    FILENAME = 'D:\SQL server 2019\zooDB\zooDB_log.ldf',
    SIZE = 5MB,
    MAXSIZE = 15MB,
    FILEGROWTH = 5%
)

(3)使用Transact-SQL语句删除zooDB数据库。

DROP DATABASE zooDB_data;

(4)声明整数变量@var,使用CASE流程控制语句判断@VAR值等于1、等于2,或者两者都不等。当@var值为1时,输出字符串”var is 1″;当@var值为2时,输出字符串”var is 2″,否则输出字符串”var is not 1 or 2″。

DECLARE @var INT;
SELECT @var = 3;
SELECT
CASE 
    WHEN @var = 1 then 'var is 1'
    WHEN @var = 2 then 'var is 2'
    ELSE 'var is not 1 or 2'
END AS RESULT
image-20250417114451661

declare @var int
select @var = 0
while @var <= 2
begin
    select @var=@var+1
    select case
        when @var=1 then 'var is 1'
        when @var=2 then 'var is 2'
        else 'var is not 1 or 2'
    end as result
end
image-20250417114357511

16.4.经典习题-计算题

(1)计算18除以5的商和余数。

SELECT FLOOR(18/5),FLOOR(18%5);
#返回不大于x的最大整数值
image-20250417151825401

(2)将弧度值PI()/4转换为角度值。

SELECT DEGREES(PI()/4);
image-20250417151841409

(3)计算9的4次方值。

SELECT SQUARE(SQUARE(9)),POWER(9,4);
image-20250417151932004

(4)保留浮点值3.14159到小数点后面2位。

SELECT ROUND(3.14159,2);
image-20250417152124160

SELECT STR(3.14159,4,2);
image-20250417152139777

(5)分别计算字符串’Hello World!’和’University’的长度

SELECT LEN('Hello World!'),LEN('University');
image-20250417153754566

(6)从字符串’Nice to meet you!’中获取子字符串’meet!’。

SELECT SUBSTRING('Nice to meet you!',9,4);
image-20250417153914636

(7)除去字符串’h e l l o’中的空格。

SELECT REPLACE('h e l l o',' ','');
image-20250417154042647

(8)将字符串’SQLServer’逆序输出。

SELECT REVERSE('SQLSever');
image-20250417154232440

(9)字符串’SQLServerSQLServer’中从第4个字母开始查找字母Q第一次出现的位置。

SELECT CHARINDEX('Q','SQLServerSQLServer',4);
image-20250417154433578

(10)计算当前日期是一年的第几天。

#dayofyear,返回当前日期是一年的几天;GETUTDATE,系统时间。
SELECT DATENAME(dayofyear,GETUTCDATE());
image-20250417154832216

(11)计算当前日期是一周中的第几个工作日

SELECT DATENAME(weekday,GETUTCDATE());
image-20250417154909645

(12)计算’1929-02-14’与当前日期之间相差的年份

SELECT YEAR(GETUTCDATE()) - YEAR('1929-02-14');
image-20250417155111758

(13)计算’1929-02-14’与当前日期之间的天数

SELECT DATEDIFF(DAY,'1929-02-14',GETUTCDATE()) AS DAYSINCESTART;
image-20250417160242137

16.5.经典练习
image-20230521144849932

image-20230521144910293

image-20230521144926862

0.创建表
1.查询销售人员(SALESMAN)的最低工资。
2.查询名字以字母N或者S结尾的记录。
3.查询在BeiJing工作的员工的姓名和职务。
4.使用左外连接方式查询employee表和dept表
5.查询所有2001到2005年入职的员工的信息,查询部门编号为20和30的员工信息并使用UNION合并两个查询结果。
6.查询所有2001到2005年入职的员工的信息,并且部门编号为20和30的员工信息的查询结果。
7.使用LIKE关键字查询员工姓名中包含字母a的记录。

创建表

#父表:
CREATE TABLE dept
(
    d_no INT NOT NULL PRIMARY KEY, --部门编号
    d_name VARCHAR(50) NOT NULL, --部门名称
    d_location VARCHAR(100) --部门地址
);
#子表:
USE test_db
GO
CREATE TABLE employee
(
    e_no INT PRIMARY KEY NOT NULL, --员工编号
    e_name VARCHAR(50) NOT NULL, --员工姓名
    e_gender CHAR(2), --员工性别
    dept_no  INT NOT NULL, --部门编号
    e_job VARCHAR(50) NOT NULL, --职位
    e_salary INT NOT NULL, --薪水
    hireDate DATE NOT NULL, --入职日期
    CONSTRAINT dno_fk FOREIGN KEY (dept_no) REFERENCES dept(d_no) 
);
#主表的字段数据类型,必须和外键表的外键字段类型要类似。

插入数据

INSERT INTO dept
values(10,'accounting','Shanghai'),
(20,'research','Beijing'),
(30,'sales','ShenZhen'),
(40,'operations','Fujian');
INSERT INTO employee VALUES('1001','SMITH','m','20','CLERK','800','2005-11-12'),
('1002','ALIEN','f','30','SALESMAN','1600','2003-05-12'),
('1003','WARD','f','30','SALESMAN','1250','2003-05-12'),
('1004','JONES','m','20','MANAGER','2975','1998-05-18'),
('1005','MARTIN','m','30','SALESMAN','1250','2001-06-12'),
('1006','BLAKE','f','30','MANAGER','2850','1997-02-15'),
('1007','CLARK','m','10','MANAGER','2450','2002-09-12'),
('1008','SCOTT','m','20','ANALYST','3000','2003-05-12'),
('1009','KING','f','10','PRESIDENT','5000','1995-01-01'),
('1010','TURNER','f','30','SALESMAN','1500','1997-10-12'),
('1011','ADAMS','m','20','CLERK','1100','1999-10-05'),
('1012','JAMES','f','30','CLERK','950','2008-06-15');

修改外键

#先删除,后添加
USE test_db
GO
ALTER TABLE dept DROP CONSTRAINT fk_dno

USE test_db
GO
ALTER TABLE employee ADD CONSTRAINT fk_dno FOREIGN KEY (dept_no) REFERENCES dept(d_no);
#添加外键,没法继续题目

操作:

(1)查询销售人员(SALESMAN)的最低工资。

USE test_db
GO
select min(e_salary) AS 'minimum wage' from employee where e_job = 'SALESMAN'
image-20250417173753110

(2)查询名字以字母N或者S结尾的记录。

USE test_db
GO
SELECT e_no,e_name FROM employee WHERE e_name LIKE '%[NG]';
image-20250417173822633

(3)查询在BeiJing工作的员工的姓名和职务。

USE test_db
GO
SELECT e_no,e_name,e_job FROM employee WHERE dept_no = (select d_no from dept where d_location = 'BeiJing');
image-20250417173845566

(4)使用左外连接方式查询employee表和dept表

select * from employee left outer join dept ON employee.dept_no = dept.d_no;
image-20250417173913792

(5)查询所有2001到2005年入职的员工的信息,查询部门编号为20和30的员工信息并使用UNION合并两个查询结果。

select * from employee where year(hireDate) between 2001 and 2005 union select * from employee where dept_no in (20,30);
image-20250417174001033

(6)查询所有2001到2005年入职的员工的信息,并且部门编号为20和30的员工信息的查询结果。

select * from employee where dept_no in (20,30) and (year(hireDate) between 2001 and 2005);
image-20250417174021845

(7)使用LIKE关键字查询员工姓名中包含字母a的记录。

select * from employee where e_name like '%a%';
image-20250417174034788

17.其他

17.1.查看当前SQL Server的版本信息和服务器名称
SELECT @@VERSION AS 'SQL server 版本信息',@@SERVERNAME AS '服务器名称'
17.2.创建局部变量
DECLARE @MyCounter INT
SELECT @MyCounter = 100
SELECT @MyCounter
GO
17.3.通过查询语句给变量赋值
DECLARE @rows int
SET @rows=(SELECT COUNT(*) FROM customers)
SELECT @rows
GO
USE test
GO
DECLARE @memberType varchar(100)
SET @memberType = 'VIP'
SELECT RTRIM(FirstName)+' '+RTRIM(LastName) AS Name, @memberType AS GRADE  #
FROM member
GO
#RTRIM 字符串函数,它返回一个删除了尾随空格的字符串。
17.4.脚本
USE test
GO
DECLARE @mycount int
CREATE TABLE person
(
    id INT NOT NULL PRIMARY KEY,
    name VARCHAR(40) NOT NULL DEFAULT '',
    age    INT NOT NULL DEFAULT 0,
    info VARCHAR(50) NULL
);
INSERT INTO person (id,name,age) VALUES (1,'Green',21);
INSERT INTO person (age,name,id,info) VALUES (22,'suse',2,'dancer');
SET @mycount =(SELECT COUNT(*) FROM person)
SELECT @mycount
GO

18.疑难解惑

18.1.排序时NULL值如何处理

在处理查询结果中没有重复值时,如果指定的列中有多个NULL值,则作为相同的值对待,显示结果中只有一个空值。对于使用ORDER BY子句排序得到的结果集中,若存在NULL值,升序排序时有NULL值的记录将显示在最前面,而降序时NULL值将显示在最后面。

18.2.DISTINCT可以应用于所有的列吗

查询结果中,如果需要对字段(即数据表的列)进行降序排序,可以使用DESC,这个关键字只能对其前面的字段降序排序。例如,要对多个字段都进行降序排序,必须要在每一字段名后面加DESC关键字。而DISTINCT不同,它不能部分使用,换句话说,DISTINCT关键字应用于所有字段而不仅是它后面的第一个指定的字段,例如,查询3个字段s_id、f_name、f_price,如果不同记录的这3个字段的组合值都不同,则所有记录都会被查询出来

18.3.父表与子表的关系

在数据库关系设计中,父表(Parent Table)子表(Child Table)是通过外键(Foreign Key)关系定义的。以下是确定两者的核心方法:


18.3.1. 外键的指向关系

父表:被外键引用的表,必须包含主键(Primary Key)或唯一键(Unique Key)。

子表:包含外键列的表,该列的值必须存在于父表的主键中。

示例:

-- 父表(部门信息)
CREATE TABLE dept (
    d_no INT PRIMARY KEY,  -- 主键,被外键引用
    d_name VARCHAR(50)
);

-- 子表(员工信息)
CREATE TABLE employee (
    e_no INT PRIMARY KEY,
    dept_no INT,  -- 外键,指向父表 dept 的主键 d_no
    FOREIGN KEY (dept_no) REFERENCES dept(d_no)
);
  • dept 是父表(被引用的主键 d_no)。
  • employee 是子表(包含外键 dept_no)。
18.3.2. 数据依赖关系
  • 父表:数据可独立存在(如部门信息)。
  • 子表:数据依赖父表存在(如员工必须属于某个部门)。

操作顺序验证:

  1. 必须先插入父表数据
    无法在子表插入 dept_no=101 的员工,除非 dept 表中已存在 d_no=101 的部门。
  2. 删除父表数据时受限
    如果子表有记录引用父表某行,默认无法直接删除父表的该行(除非使用级联删除)。

在数据库关系设计中,父表(Parent Table)子表(Child Table)是通过外键(Foreign Key)关系定义的。以下是确定两者的核心方法:


18.3.3. 外键的指向关系
  • 父表:被外键引用的表,必须包含主键(Primary Key)或唯一键(Unique Key)。
  • 子表:包含外键列的表,该列的值必须存在于父表的主键中。

示例:

-- 父表(部门信息)
CREATE TABLE dept (
    d_no INT PRIMARY KEY,  -- 主键,被外键引用
    d_name VARCHAR(50)
);

-- 子表(员工信息)
CREATE TABLE employee (
    e_no INT PRIMARY KEY,
    dept_no INT,  -- 外键,指向父表 dept 的主键 d_no
    FOREIGN KEY (dept_no) REFERENCES dept(d_no)
);
  • dept 是父表(被引用的主键 d_no)。
  • employee 是子表(包含外键 dept_no)。

18.3.4. 数据依赖关系
  • 父表:数据可独立存在(如部门信息)。
  • 子表:数据依赖父表存在(如员工必须属于某个部门)。

操作顺序验证:

  1. 必须先插入父表数据
    无法在子表插入 dept_no=101 的员工,除非 dept 表中已存在 d_no=101 的部门。
  2. 删除父表数据时受限
    如果子表有记录引用父表某行,默认无法直接删除父表的该行(除非使用级联删除)。

18.3.5. 逻辑关系分析
父表通常表示“一”的一方,子表表示“多”的一方,体现“一对多”关系。

例如:

  • 一个部门(父表)可以有多个员工(子表)。
  • 一个订单(父表)可以有多个订单项(子表)。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注