遇事不会查文档:
https://docs.microsoft.com/zh-cn/sql/sql-server/?view=sql-server-ver15
单表查询
Select语句的元素
USE AdventureWorks2014;
GO
SELECT SH.SalesPersonID,
YEAR(SH.OrderDate) AS OrderYear,
COUNT(*) NumOrders
FROM Sales.SalesOrderHeader SH
WHERE SH.CustomerID = 29825
GROUP BY SH.SalesPersonID,
YEAR(SH.OrderDate)
HAVING COUNT(*) > 1
ORDER BY SH.SalesPersonID,
OrderYear;
谓词和运算符
TSQL可以使用逻辑表达式
- Where子句
- Having子句
- Check约束
逻辑表达式可以使用的谓词(取值为True/False/Unknown)
- in
- between
- Like
- 运算符
比较运算符
=, >,<,>=, <=, <> (!=, !>, !<为非标准写法)
逻辑运算符
or, and, not
算术运算符
+,-,*,/,%(取模)
运算符优先级
- ()
- *,/,%
- +,-,
- 比较运算符
- Not
- And
- Between,in,like,or
- =(赋值)
CASE表达式
标量表达式, 基于条件逻辑返回一个值
- 简单表达式
USE Test;
GO
SELECT *,
CASE gender
WHEN 'male' THEN
N'男生'
WHEN 'female' THEN
N'女生'
END genderInChinese
FROM dbo.student;
- 搜索表达式
USE Test;
GO
SELECT *,
CASE
WHEN DATEDIFF(YEAR, birthday, GETDATE()) <= 10 THEN
N'小于10岁'
ELSE
N'超过10岁'
END ageDesc
FROM dbo.student;
NULL值
NULL是Unkown
NULL与任何值进行运算结果是NULL
NULL取反仍是NULL
NULL的判断
- IS NULL
- IS NOT NULL
SQL Server对于唯一约束中, 多个NULL视作一个NULL
处理字符数据
1.两种数据类型
- 普通字符(char,varchar), 一个字节存储
- Unicode字符(nchar, nvarchar), 两个字节存储
2.排序规则collation - 排序规则,大小写敏感,区分重音
- Sys.fn_helpcollations()
3.运算符和函数 - 连接符+
- Left/right/len/charindex/replace/upper/lower/ltrim/rtrim/substring/replicate
4.Like谓词 - 通配符_, %
- escape
处理日期和时间数据
1.日期类型
- DATETIME/SMALLDATETIME/DATE/TIME/DATETIME2/DATETIMEOFFSET
2.字符串到日期的转换
隐式转换依赖于
- Set language
- Set DateFormat
显式转换
- Cast(‘20210613’ as datetime)
- Convert(datetime, ‘20210613’,112)
3.常用日期函数
- Year/month/day/getdate()/dateadd/datediff/datepart/datename
联接查询
- where条件丢到辅表上,外连接自动变成内连接,
- where条件丢到主表上,先过滤在连接;
- 把where条件放到on里面,不过滤表,只是一个连接条件
交叉联接
- 对输入的两个表进行操作,生成二者的笛卡尔积
- 两种语法
USE Test;
GO
SELECT *
FROM dbo.student
CROSS JOIN dbo.class;
USE Test;
GO
SELECT *
FROM dbo.student,dbo.class;
内连接
- 先像交叉联接一样生成笛卡尔积,然后根据谓词进行过滤
- 两种语法
USE Test;
GO
SELECT *
FROM dbo.student
INNER JOIN dbo.class
ON class.id=student.classid;
USE Test;
GO
SELECT *
FROM dbo.student,dbo.class
Where class.id=student.classid;
特殊的联接实例
- 组合联接:关联条件不止一个列
USE Test;
GO
SELECT *
FROM dbo.T1
INNER JOIN dbo.T2
ON T1.col1=T2.col1 and T1.col2=T2.col2;
- 不等联接:关联条件包含非等值条件
USE Test;
GO
SELECT *
FROM dbo.T1
INNER JOIN dbo.T2
ON T1.col1
- 多表联接
USE Test;
GO
SELECT *
FROM dbo.T1
INNER JOIN dbo.T2
ON T1.col1=T2.col1
INNER JOIN dbo.T3
ON T1.col1=T3.col1;
外联接
1.笛卡尔积+ON过滤+外部行
2.3种类型
- 左联接(left [outer] join)
以左表为主表
二表匹配的记录+不匹配的补充为NULL
USE Test;
GO
SELECT *
FROM dbo.class
Left JOIN dbo.student
ON class.id=student.classid;
- 右联接(right [outer] join)
以右表为主表
二表匹配的记录+不匹配的补充为NULL
USE Test;
GO
SELECT *
FROM dbo.class
right JOIN dbo.student
ON class.id=student.classid;
- 全联接(full [outer] join)
二表匹配的记录+左表不匹配的补充为NULL+右表不匹配的补充为NULL
USE Test;
GO
SELECT *
FROM dbo.class
full JOIN dbo.student
ON class.id=student.classid;
子查询
独立子查询
- 独立于其外部查询的子查询
- 独立子查询在执行外部查询之前只要先执行一次,接着外部查询再使用子查询的结果继续进行查询
USE AdventureWorks2014;
GO
SELECT s.SalesOrderNumber,
s.OrderDate,
s.CustomerID,
s.SalesPersonID
FROM sales.SalesOrderHeader s
WHERE s.SalesOrderID =
(
SELECT MAX(SalesOrderID)
FROM sales.SalesOrderHeader
);
相关子查询
- 引用了外部查询中出现的表的列的子查询
- Exists谓词
- 高级子查询
返回前/后一个记录
连续聚合 - 行为不当的子查询
NOT IN与NULL值问题
USE AdventureWorks2014;
GO
SELECT SH.CustomerID,
SH.SalesOrderID,
SH.SalesPersonID
FROM sales.SalesOrderHeader SH
WHERE SH.SalesOrderID =
(
SELECT MAX(SH2.SalesOrderID)
FROM sales.SalesOrderHeader SH2
WHERE SH.CustomerID = SH2.CustomerID
);
表表达式
派生表
1.在外部查询的FROM子句中定义
2.存在范围为定义它的外部查询,只要外部查询一结束,派生表就不存在了
3.派生表可以嵌套
4.查询语句满足的条件
- 没有order by子句(除非带TOP)
- 所有列必须有名称
- 所有列名必须唯一
USE AdventureWorks2014;
GO
SELECT *
FROM
(
SELECT s.SalesOrderID,
s.CustomerID,
s.SalesPersonID
FROM sales.SalesOrderHeader s
WHERE s.TerritoryID = 5
) AS T;
CTE
CTE:公用表表达式
用途
- 命名子查询,可以反复引用
- 实现递归查询
注意
- 多个cte之前用逗号分隔
- 实现递归时需要显式给列名
- 多个cte之前前向引用
- 递归时防止死循环option(maxrecursion n)
USE AdventureWorks2014;
GO
WITH source
AS (SELECT s.SalesOrderID,
s.CustomerID,
s.SalesPersonID
FROM sales.SalesOrderHeader s
WHERE s.TerritoryID = 5)
SELECT *
FROM source;
USE AdventureWorks2014;
GO
WITH subq (n, factorial)
AS (SELECT 1,
1
UNION ALL
SELECT n + 1,
factorial * (n + 1)
FROM subq
WHERE n < 5)
SELECT *
FROM subq;
内联表值函数
- 一种可重用的表表达式
- 支持输入参数
USE AdventureWorks2014;
GO
CREATE FUNCTION dbo.fn_getCustOrder
(
@cid INT
)
RETURNS TABLE
AS
RETURN SELECT SH.SalesOrderID,
SH.CustomerID,
SH.SalesPersonID
FROM sales.SalesOrderHeader SH
WHERE SH.CustomerID = @cid;
GO
Select * from db.fn_getCustOrder(1);
APPLY运算符
两种形式
- Cross apply:只返回匹配的记录
- Outer apply:返回匹配的记录, 不匹配的为NULL
USE AdventureWorks2014;
GO
SELECT SH.CustomerID, A.SalesOrderID, A.OrderDate
FROM sales.Customer SH
CROSS/OUTER APPLY(
SELECT TOP 3 SH2.SalesOrderID, SH2.OrderDate
FROM sales.SalesOrderHeader SH2
WHERE SH.CustomerID=SH2.CustomerID
ORDER BY SH2.OrderDate DESC, SH2.SalesOrderID DESC
) A;
集合运算
并集UNION
- 返回包含两个集合中所有元素的集合
- 注意UNION与UNION ALL的区别
UNION会去掉重复
UNION ALL 不会去掉重复
USE AdventureWorks2014;
GO
SELECT 1 id,
'a' name
UNION
SELECT 1,
‘a';
USE AdventureWorks2014;
GO
SELECT 1 id,
'a' name
UNION ALL
SELECT 2,
'b';
交集InsertSect
返回两个集合中共同的部分
USE AdventureWorks2014;
GO
SELECT d.ProductID
FROM sales.SalesOrderHeader h
INNER JOIN sales.SalesOrderDetail d
ON h.SalesOrderID = d.SalesOrderID
WHERE h.CustomerID = 29825
INTERSECT
SELECT d.ProductID
FROM sales.SalesOrderHeader h
INNER JOIN sales.SalesOrderDetail d
ON h.SalesOrderID = d.SalesOrderID
WHERE h.CustomerID = 29672;
差集except
返回两个集合不同的部分
USE AdventureWorks2014;
GO
SELECT *
FROM (
SELECT 1 id, 'a' name
UNION ALL
SELECT 2 id, 'b' name
) A
EXCEPT
SELECT *
FROM
(
SELECT 1 id, 'a' name
UNION ALL
SELECT 3 id, 'c' name
) B
集合运算的优先级
- InterSect运算比Union和Except运算优先级高
- Union和Except优先级相等
With A as (
SELECT 1 id, 'a' name
UNION ALL
SELECT 2 id, 'b' name
),B as (
SELECT 1 id, 'a' name
UNION ALL
SELECT 3 id, 'c' name
),C as (
SELECT 1 id, 'a' name
UNION ALL
SELECT 2 id, 'b' name
UNION ALL
SELECT 3 id, 'c' name
)
select *
from A
except
select *
from B
intersect
select *
from C
思维导图
实战
从AdventureWorks2014数据库,写一个单表聚合查询,表示某一年的所有地区的,产品大类的销量统计
USE AdventureWorks2014
GO
SELECT st.Name AS customTerritory,pc.Name AS productcategory,SUM(sd.OrderQty) AS totalqty
FROM Sales.SalesOrderHeader SH
INNER JOIN Sales.SalesOrderDetail SD
ON SD.SalesOrderID = SH.SalesOrderID
INNER JOIN Sales.Customer SC
ON SC.CustomerID = SH.CustomerID
INNER JOIN Sales.SalesTerritory ST
ON ST.TerritoryID = SC.TerritoryID
INNER JOIN Production.Product PP
ON PP.ProductID = SD.ProductID
INNER JOIN Production.ProductSubcategory PS
ON PS.ProductSubcategoryID = PP.ProductSubcategoryID
INNER JOIN Production.ProductCategory PC
ON PC.ProductCategoryID = PS.ProductCategoryID
WHERE SH.OrderDate BETWEEN CAST('20110101' AS DATETIME) AND CAST('20111231' AS DATETIME)
GROUP BY st.Name,pc.Name
ORDER BY totalqty desc
查看Color有多少null
SELECT
SUM(CASE WHEN pp.Color IS NULL THEN 1 ELSE 0 END) AS totalnull,
SUM(CASE WHEN pp.Color IS NOT NULL THEN 1 ELSE 0 END) AS NOTNULL
FROM Production.Product pp
展开各种颜色都有多少
SELECT pp.Color,SUM(CASE WHEN pp.Color IS NULL THEN 1 ELSE 0 END) AS total
FROM Production.Product pp
GROUP BY pp.Color
打印九九乘法表
WITH nums
AS (SELECT number
FROM master..spt_values
WHERE type = 'P'
AND number
BETWEEN 1 AND 9)
SELECT a.number,
(
SELECT CAST(b.number AS VARCHAR) + '*'+CAST(a.number AS VARCHAR)+ '=' + CAST(a.number*b.number AS VARCHAR) + ' '
FROM nums b
WHERE b.number <= a.number
ORDER BY b.number
FOR XML PATH('')
)
FROM nums a;