SQL 逻辑流
Select 语法
- Select语句的From部分将所有数据源组装进一个结果集,然后由Select语句的剩余部分对结果集执行操作。
- Where子句作用于From组装的记录集,根据条件筛选某些行。
- 聚合函数对数据集执行求和操作。
- Group by 子句根据在该子句中指定的列将大量数据集分组成较小的数据集。
- Having 对较小的数据组执行聚合函数。
- Order by 子句确定结果子的排列顺序。默认为升序;
|
|
查询语句的逻辑流
数据源(From) —— 条件(Where) —— 列/表达式 (col/exp) —— Order by — 谓词
From,查询首先组装初始数据集。
Where,筛选;筛选过程实际上是选择符合标准的行的where子句。
Group by,组合数据的子集 [若要分组,先对数据排序,然后根据排序后的数据进行聚合]
聚合,Aggregations,选择性地对数据进行聚合;如求平均值,按列中的值对数据分组以及筛选组;
Having,筛选数据的子集
列表达式:处理Select列,并计算任何表达式 [ 这个时候才涉及到列 ]
Order by,排序
Over,窗口函数和排名函数通过与其他聚合函数一起提供结果的单独排序的视图
Distinct,从结果集中删除任何重复的行
Top,选定行后,执行计算,并按所需的顺序排序
Insert,Update,Delete,最后一个逻辑步骤是将数据修改操作应用到查询结果。
Output,选择插入和删除的虚拟表,并返回给客户端
Union,堆叠或合并多个查询的结果
SQL编写标准
- 若需要多个表合成一个表,必须确定【唯一标识符】或者说是联接的表,从联接表中去寻找联接的字段
- 最后合并的中都必须要有这个字段
- 若出现多个主条件,先将主条件的区分变量统一到一个表中
- 其他表与这个表进行联接
- 先把各个字段单独用Select写出来
- 再合并为一个Select语句
运算符介绍
优先级
Not > 算术运算符(+-) > 条件运算符(where) > And > Or
电脑中字符优先级: 数字>字母
1a > a1 > a11 > aa1
通配符
运算符 | 含义 | 示例 |
---|---|---|
% | 任意长度的字符串 | Email Like ‘%@%.com’ |
‘_’ | 任意一个字符 | AuthorName Like ‘张_’ |
[ ] | 在指定范围内的任意一个字符 | A Like ‘A6C8[1-5]’ |
[^] | 不在指定范围内的任意一个字符 | A Like ‘A6C8[^1-6]’ |
查找含通配符的表达式:
- 必须使用Like字符
- 把通配符放入方括号[ ] 内
- 在其之前放一个转义符
注意事项与通用规则
方括号 [ ]
- why :表名或字段名如果引用了sql server中的关键字,数据库会不识别这到底是关键字还是表名(还是字段名)时就必须要加;
- 查询语句的表中加上方括号[ ] , 目的是以声明其不是保留字 ;
- 如果表名不是关键字,不用加方括号
|
|
合并:字段+表格
|
|
使用“ + ”连接多个字段,合并成一列
- 前后类型应兼容;
如果+连接数值类型,结果是数值之和
如果+连接字符串类型,结果是字符串的连接
|
|
|
|
Where条件
- 最佳实践:找到事物的最好办法就是查找,而不是先排除不是该事物的所有东西。即where条件,声明肯定的限制条件优于否定的限制条件;
|
|
惊叹号! ,不是ANSI标准的SQL;
- 布尔逻辑运算的优先次序: NOT > AND > OR
- 若where子句中同时出现 and 和 or 条件,一定要把整个or条件子句用括号括起来
|
|
不能在Where 子句中使用聚合函数。此时应用子查询来进行限定
- 先进行联合,再进行where条件的执行
|
|
Between and
|
|
ALL、SOME、ANY
- ALL,相当于And;如果子查询可能返回一个空值,那么使用ALL会判断为fasle,使用时要小心;
循环
- 一个if,一个命令的执行;并且没有Then和End来终止if命令;
|
|
if语句之后没有分号; if语句实际上是后面语句的提前;
- 使用Begin / End 有条件地执行多条语句
|
|
- 使用If Exists()作为基于存在性的条件
- If Exists() 结构使用从SQL Select语句返回的每一行作为条件。
- 因为If Exists() 结构会查找每一行,所以Select语句应当选择所有的列。一旦一个单行满足了If Exists(),查询就会继续执行
|
|
- 使用If / Else 执行替换语句
- 可选的Else定义了if条件为False时的执行代码;Else可控制下一个单个命令,后者Begin/End块
|
|
while,break,continue的使用
- 设置重复执行 SQL 语句或语句块的条件。只要指定的条件为真,就重复执行语句。可以使用 BREAK 和 CONTINUE 关键字在循环内部控制 WHILE 循环中语句的执行。
- Break :导致从最内层的WHILE循环中退出。将执行出现在END关键字后面的任何语句,END 关键字为循环结束标记。
- 如果嵌套了两个或多个 WHILE 循环,内层的 BREAK 将导致退出到下一个外层循环。首先运行内层循环结束之后的所有语句,然后下一个外层循环重新开始执行。
- Continue :使 WHILE 循环重新开始执行,忽略 CONTINUE 关键字后的任何语句。
|
|
创建与变更格式
视图
|
|
变更格式
|
|
插入、更新、删除、合并数据
创建数据
|
|
若要重新定义主键,则必须首先删除与现有主键之间的任何关系,然后才能创建新主键。 此时,将显示一条消息警告您:作为该过程的一部分,将自动删除现有关系。
|
|
插入数据
|
|
–
|
|
SQL中合并列,只要选择对应的列即可
Select a.*, b.* From a Full Join b
更新数据
|
|
删除数据
|
|
truncate 、delete与drop区别
- 相同点
- truncate和不带where子句的delete、以及drop都会删除表内的数据drop、truncate都是DDL语句(数据定义语言),执行后会自动提交。Delete是DML语句(数据库操作语言)
- 不同点
truncate 和 delete 只删除数据不删除表的结构(定义);drop 语句将删除表的结构被依赖的约束(constrain)、触发器(trigger)、索引(index);依赖于该表的存储过程/函数将保留,但是变为 invalid 状态。
delete 语句是数据库操作语言(dml),这个操作会放到 rollback segement 中,事务提交之后才生效;如果有相应的 trigger,执行的时候将被触发。truncate、drop 是数据库定义语言(ddl),操作立即生效,原数据不放到 rollback segment 中,不能回滚,操作不触发 trigger。
delete 语句不影响表所占用的 extent,高水线(high watermark)保持原位置不动。drop 语句将表所占用的空间全部释放。truncate 语句缺省情况下见空间释放到 minextents个 extent,除非使用reuse storage;truncate 会将高水线复位(回到最开始)。
速度:drop> truncate > delete
- TRUNCATE TABLE在功能上与不带WHERE子句的DELETE语句相同:二者均删除表中的全部行。但TRUNCATE TABLE 比DELETE速度快,且使用的系统和事务日志资源少。DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项。TRUNCATE TABLE 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。
安全性:
- 想保留表而将所有数据删除,如果和事务无关,用truncate即可。如果和事务有关,或者想触发trigger,还是用delete。
- 小心使用 drop 和 truncate,尤其没有备份的时候
- 使用上,想删除部分数据行用 delete,注意带上where子句. 回滚段要足够大
- 想删除表,当然用 drop
- 对于由FOREIGN KEY 约束引用的表,不能使用TRUNCATE TABLE,而应使用不带WHER 子句的DELETE语句。由于 TRUNCATE TABLE不记录在日志中,所以它不能激活触发器。
- TRUNCATE TABLE不能用于参与了索引视图的表。
判断是否存在后删除
|
|
合并数据
- Meger语句。使用 MERGE 语句在一条语句中执行插入、更新或删除操作。
- 有条件地在目标表中插入或更新行。
- 如果目标表中存在相应行,则更新一个或多个列;否则,会将数据插入新行。
- 同步两个表。根据与源数据的差别在目标表中插入、更新或删除行。
- 有条件地在目标表中插入或更新行。
|
|
返回修改后的数据
- Output子句可以访问插入的和删除的虚拟表,以及任何在From自引用的数据源来选择要返回的数据。
Output子句有一个较为高级的应用,可以把输出数据传输到外查询。
|
|
1. 查询:字符串
函数名 | 功能描述 | 举例 |
---|---|---|
LEN | 返回指定字符串的字符个数(而不是字节),其中不包含尾随空格 | SELECT LEN(‘李丽然作者’) 返回:5 |
DATALENGTH | 返回指定字符串的字节数 | SELECT DATALENGTH(‘中国人’) 返回:6 |
UPPER | 将小写字符转换成大写字符 | SELECT UPPER(‘book图书表’) 返回:BOOK图书表 |
LTRIM | 返回去掉左侧空格的字符串 | SELECT LTRIM(‘ Authors’) 返回: Authors |
CHARINDEX | 查找一个指定的字符串在另一个字符串中的起始位置 | SELECT CHARINDEX(‘L’, ‘HELLO’, 1) 返回:3 |
LEFT | 返回字符串中从左边开指定个数的字符 | SELECT LEFT(‘zhangsan’, 2) 返回:zh |
Substring | 返回字符串的一部分:从字符串串的起始位置连续取指定个数的子串 | SELECT SUBSTRING(‘我爱我的家乡’,3, 2) 返回:我的 |
Replace | 替换一个字符串中的字符 | SELECT REPLACE(‘我爱我的家乡家乡’, ‘家乡’, ‘学校’) 返回: 我爱我的学校学校 |
Stuff | 将一个字符中删除指定数量的字符,并插入另一个字符 | |
Concat | 将多个字符串组合为单个字符串 |
使用字符串字面量时,通过输入两个单引号转化为一个单引号
Replace(name, ‘’’’, ‘’) ; Life’’s Great! 被解释为 Life’s Great!
行数&字符数
|
|
去空格
|
|
|
|
取子串
|
|
返回特定位置
|
|
取出一个字符串中最后一个特殊字符右边的字符
- 涉及 翻转
reverse
和charindex
|
|
替换
|
|
合并
|
|
格式转换
|
|
格式转换 - Convert
- CONVERT (data_type[(length)], expression [, style])
length: nchar、nvarchar、char、varchar、binary 或 varbinary 数据类型的可选参数。
style:日期格式样式,借以将 datetime 或 smalldatetime 数据转换为字符数据(nchar、nvarchar、char、varchar、nchar 或 nvarchar 数据类型);或者字符串格式样式,借以将 float、real、money 或 smallmoney 数据转换为字符数据(nchar、nvarchar、char、varchar、nchar 或 nvarchar 数据类型)。
|
|
Data_type : INT / DECIMAL(10,2) / CHAR() / VARCHAR() /
格式转换 - Cast
- CAST ( expression AS data_type )
- data_type 目标系统所提供的数据类型,包括 bigint 和 sql_variant。不能使用用户定义的数据类型。
|
|
字符串 - 正则表达式
- regexp_like(x,pattern[,match_option]) :查看x是否与pattern相匹配
可选的参数match_option字符串说明默认的匹配选项。match_option的取值如下:
‘c’ 说明在进行匹配时区分大小写(缺省值);
‘i’ 说明在进行匹配时不区分大小写;
‘n’ (.)点号能表示所有单个字符,包括换行(俺还不知道什么地方有用到换行.只知道sql里面可以用chr(10)表示换行.
‘m’ 字符串存在换行的时候当作多行处理.这样$就可匹配每行的结尾.不然的话$只匹配字符串最后的位置.
|
|
- regexp_replace
- regexp_substr
- regexp_instr
2. 查询:数字相关
函数名 | 功能描述 | 举例 |
---|---|---|
ABS | 返回表达式绝对值 | SELECT ABS(-90) 返回:90 |
ROUND | 按指定的精度进行四舍五入 | SELECT ROUND(56.629, 2) 返回:56.630 |
SQRT | 返回指定表达式的平方根 | SELECT SQRT(9) 返回:3 |
FLOOR | 返回小于或等于指定数值表达式的最大整数 $\le$ | SELECT FLOOR(23.9) 返回: 23 |
CEILING | 返回大于或等于指定数值表达式的最小整数 $\ge$ | SELECT CEILING(23.9) 返回:24 |
POWER | 次方;返回x的y次方 | SELECT POWER(2,3) ; 返回8 |
EXP | 指数;e的x次方 | SELECT EXP(2) 返回e$^2$ |
LN /LOG(x,y) | 对数; | SELECT LN(e) ;返回1 |
MOD | 返回x除以y的余数 | SELECT MOD(9,2); 返回1 |
% | 返回x除以y的余数 | SELECT 9%2 |
SIGN | 判断正负;若x为正返回1;若x为负 返回-1 ; 若x为0 返回0 | SELECT SIGN(2); 返回1 |
3. 查询:聚合函数
- 聚合是在对From和Where子句筛选后的数据集进行聚合计算;即运营逻辑是在其之后执行
- 聚合函数,它的对象是多个观测值,但只返回一个值;若要出现多个观测值的聚合值,需要用到Group by 函数
- 一旦查询包含了聚合函数,那么每一列必须参与到聚合函数中。
- SELECT语句中除聚合函数外,所有列应写在Group By语句后面。否则将出现错误
函数名 | 功能描述 |
---|---|
AVG | 平均值 |
SUM | 求和 |
MAX/MIN | 求最大值/最小值 |
COUNT | 计算非空单元格( 返回 int 数据类型值) |
count_big | 计算非空单元格(返回 bigint 数据类型值) |
VAR | 方差 # 平方 |
varp | 总体方差 |
STDEV | 标准差 |
stdevp | 总体标准差 |
除Count(*)外,所有聚合函数均忽略空值NULL;
avg( ) $\ge$ $sum( ) \over count(*)$
Count(*),计数时也将NULL计入;Count(Null) 返回0;所有与NULL的计算,都返NULL
其他所有聚合函数,包括Count(col_name)的形式,计算时均已排除了NULL
表a,观测值10行,其中2个NULL;
Count(*) # 返回10;Count(列名) # 返回8
除非,可用 isnull() 函数进行转换,来计算;
例如,对表a求平均值,若直接用avg() ,其分母为8;
若想使得其分母变成10,应添加 case when isnull(col_name,0) then col_name else end
4. 查询:日期相关
函数名 | 描述 |
---|---|
Getdate | 返回当前服务器的日期和时间 |
Current_timestamp | 除了ANSI标准,等同于Getdate |
Getutcdate | 返回当前服务器的日期和时间,并转化为格林威治标准时间 |
Sysdatetime | 返回当前服务器的日期和时间 |
Sysutcdatetime | 返回当前服务器日期,并转化为格林威治标准时间 |
Sysdatetimeoffset | 返回Datetimeoffset值 |
- 日期处理函数
函数名 | 描述 | |
---|---|---|
Dateadd | 在指定的日期上累加数值得到新的日期;dateadd(datepart,number,date) | SELECT DATEADD(yyyy, 4, ‘01/09/2003’) 返回:2007-01-09 |
datepar是参数的格式:datepart=yy(年),mm(月),qq(季度);date 参数是合法的日期表达式。number 是您希望添加的间隔数;对于未来的时间,此数是正数,对于过去的时间,此数是负数。 | ||
DATEDIFF | 返回两个日期的差值 ; datediff(datepart,startdate,endate) | SELECT DATEDIFF(dd, ‘02/05/2003’, ‘02/09/2005’) 返回:735 |
DATEPART | 返回指定日期部分的整数(整数形式) | SELECT DATEPART(dd, ‘01/09/2003’) 返回:9 |
DATENAME | 返回指定日期部分的字符串(字符串形式);工作日(dw)、周(wk)、日(dd)、月(mm) | SELECT DATENAME(dw, ‘02/02/2009’) 返回: 星期一 |
Eomonth | 返回针对指定开始日期的月份的最后一天 | Select Eomonth(‘5/27/1998’) |
YEAR | 返回指定日期“年”部分整数 | SELECT YEAR(GETDATE()) 返回:当前年份整数 |
MONTH | 返回指定日期“月”部分整数 | SELECT MONTH(GETDATE()) 返回:当前月份整数 |
DAY | 返回指定日期“日”部分整数 | SELECT DAY(GETDATE()) 返回:当前日期整数 |
查询:日期的应用
|
|
时间戳
时间戳就是一个从1970-01-01 08:00:00到时间的相隔的秒数
- dateadd(s, string, format):时间戳转日期格式
- datediff(s,format,time):普通时间转时间戳
|
|
注解:北京时间与GMT时间关系
1.GMT是中央时区,北京在东8区,相差8个小时
2.所以北京时间 = GMT时间 + 八小时
12 > select DATEADD(second,1268738429 + 8 * 60 * 60,'1970-01-01 00:00:00')>
|
|
Datepart 设置周末为第一天
|
|
要注意的是 SET DATEFIRST 只在当前执行中有效,也就说比如新开一个查询页面继续查询 SELECT @@DATEFIRST 则还是显示默认值 7。
参考:日期缩写参考
- datediff / datename / datepart /dateadd
日期部分 | 缩写 |
---|---|
year | yy, yyyy |
quarter | qq, q |
month | mm, m |
dayofyear | dy, y # 查询date在当年是第多少天. 一年中的第几天; |
day | dd, d |
week | wk, ww # 查询date在当年中是第几周 / 以周为单位的间隔数 |
weekday | dw # 一周中的第几天(星期几) |
Hour | hh |
minute | mi, n |
second | ss, s |
millisecond | ms |
- convert - style的参考值
- 一位或两位数字样式提供两位数的年份;3位数字样式提供4位数字的年份;
代码 | Style 格式 |
---|---|
100 或者 0 | mon dd yyyy hh:miAM (或者 PM) |
101 | mm/dd/yy |
102 | yy.mm.dd |
103 | dd/mm/yy |
104 | dd.mm.yy |
105 | dd-mm-yy |
106 | dd mon yy |
107 | Mon dd, yy |
108 | hh:mm:ss |
109 或者 9 | mon dd yyyy hh:mi:ss:mmmAM(或者 PM) |
110 | mm-dd-yy |
111 | yy/mm/dd |
112 | yymmdd |
113 或者 13 | dd mon yyyy hh:mm:ss:mmm(24h) |
114 | hh:mi:ss:mmm(24h) |
120 或者 20 | yyyy-mm-dd hh:mi:ss(24h) |
121 或者 21 | yyyy-mm-dd hh:mi:ss.mmm(24h) |
126 | yyyy-mm-ddThh:mm:ss.mmm(没有空格) |
130 | dd mon yyyy hh:mi:ss:mmmAM |
5. 查询:表格相关
限定行数 - TOP
|
|
With Ties
- 允许最后的位置包含多行,但这多行是完全相同的
|
|
随机行选择
- 使用Top(1) 返回单行,且用Newid()随机排序结果;每次将返回一个随机值
- 涉及到较大的表时,可用Tablesample( n Percent/Rows)选项
- 由于是随机选择,可通过Repeatable()来指定 [效果同R语言中的set.seed()]
|
|
分组&排序
分组
- Group by 会根据某一列的值将数据集自动分成子集。
- 对分组集来说,汇总行是每个子集中的每个唯一值组成的行
- 数据集被分成子组之后,聚合函数在每一个子组上执行。
- 对于Group by子句,空值NULL被认为是相等的,并被分组到单个结果行
- Group by不局限于对列分组,也可以对表达式执行分组(但该表达式必须与Select中的相同)
分组后筛选
HAVING
- what :指定组或聚合的搜索条件;HAVING 通常在 GROUP BY 子句中使用,对Group by 之后的表单进行条件筛选;但针对的是所有group by 的字段,而非第一个
|
|
- 如果不使用 GROUP BY 子句,则 HAVING 的行为与 WHERE 子句一样。
|
|
排序
- Select 指定的每一列都应该出现在Group By子句中,除非对这一列使用了聚合函数;
- 排序:Order by
- 可以使用表达式来指定顺序
- 可以使用列别名指定顺序
- 可以使用列的顺序位置来进行排序
|
|
窗口函数 - Select Over()
聚合子句
|
|
|
|
在窗口内分区:Partition by
- 执行逻辑:先对查询结果进行排序,之后通过Partition by的列进行分区;
- 窗口函数只能在Select 或者 Group by 子句中
排名 - rank子句
|
|
ntile函数的分组依据(约定):
首先系统会去检查能不能对所有满足条件的记录进行平均分组,若能则直接平均分配就完成分组了;若不能,则会先分出一个组,这个组分多少条记录呢?就是 (总记录数/总组数)+1 条,之所以分配 (总记录数/总组数)+1 条是因为当不能进行平均分组时,总记录数%总组数肯定是有余的,又因为分组约定1,所以先分出去的组需要+1条。
分完之后系统会继续去比较余下的记录数和未分配的组数能不能进行平均分配,若能,则平均分配余下的记录;若不能,则再分出去一组,这个组的记录数也是(总记录数/总组数)+1条。
举个例子,将53条记录分配成5组,53%5 = 3不能平均分配,则将余数3平均分配到前3组 (余数 = 分配的组数),然后比较余下的 53-(11*3)=20 条记录能否平均分配给未分配的2组,能平均分配,则剩下的2组,每组各20/2=10 条记录,分配完成,分配结果为:11,11,11,10,10。
分页
|
|
条件查询
case when
最大的优点是可以与Select语句“内联”
若else缺失,表示其他值返回NULL
Case函数只返回第一个符合条件的值,剩下的Case部分将会被自动忽略;
- 所以,如果根据金额大小来判定等级,必须要最高的金额写在最前面;
|
|
–
|
|
- 搭配其他函数用法
|
|
联接与联合
what:将两个数据集相乘,并对结果进行限制。这样只返回两个数据集的交集。
why :横向合并两个数据集,并通过匹配一个数据源的行与另一个数据源的行,从组合中产生新的数据集。
内联接
Inner Join
在连接条件中使用等于号(=)运算符,其查询结果中列出被连接表中的所有列,包括其中的重复列。
在连接条件中使用除等于号之外运算符(>、<、<>、>=、<=、!>和!<)
多个数据源的联接(顺序并不重要)
- 所要获得字段的表要写在最前面;即From之后;
- 可实现A联接B,B联接C,C联接D;
12345Select cst.companyname, prod.nameFrom Customre As aInner join salesorderhead As b On a.customerid = b.customeridInner join salesorderdetail As c On b.salesorderid = c.salesorderidInner join product As d On c.productid = d.productidSQL内在处理逻辑:(按照排列顺序进行联接)
- 先扫描a
- Inner Join 表a 和 表b
- 然后将 a和b 联合表单 与表c Inner Join
- 最后将上面联合表 与 表d Inner Join
外联接
可多条件连接;即在原来连接的基础上再进行连接
123456 > From #a2 As a> Left Join [exchange].[GFFCC_YTX].[v_qhkh] As b> On a.手机 = b.手机> Left Join [ADHOC_YTX].[zhangcm].[期货客户属性表] As c> On b.资金号 = c.投资者代码>
what:以一个表为基准表,进行联接;
- 若使用外联接,顺序非常重要
- 慎用 不等连接
on a.id <> b.id
,因为会对每一条记录a无法匹配的b表中的行生成一条记录,最后会生成 $a \times b$ 行
1234567select * form tab1 left join tab2 on (tab1.size != tab2.size)tab1.id tab1.size tab2.size tab2.name1 10 20 BBB2 10 20 CCC2 10 (null) (null)3 20 10 AAAA......
how :无论是否匹配,外联接都包含所有数据
How :数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。
中间表是 左表与右表的所有字段
on 与 where 的区别
- on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录
select * form tab1 left join tab2 on (tab1.size = tab2.size and tab2.name=’AAA’)
表示同时满足这两个条件才能匹配到记录(必须用括号
()
括起来) ,但条件不为真也会返回左表中的记录;- 可通过where子句限定 b.x Is Not Null 来返回该条记录 或 where tb2.name=’AAA’
- where条件是在临时表生成好后,再对临时表进行过滤的条件。条件不为真的就全部过滤掉。
关于 “A LEFT JOIN B ON 条件表达式” 的一点提醒
ON 条件(“A LEFT JOIN B ON 条件表达式”中的ON)用来决定如何从 B 表中检索数据行。
如果 B 表中没有任何一行数据匹配 ON 的条件,将会额外生成一行所有列为 NULL 的数据
在匹配阶段 WHERE 子句的条件都不会被使用。仅在匹配阶段完成以后,WHERE 子句条件才会被使用。它将从匹配阶段产生的数据中检索过滤。
|
|
其实以上结果的关键原因就是left join,right join,full join的特殊性,不管on上的条件是否为真都会返回left或right表中的记录,full则具有left和right的特性的并集。 而inner jion没这个特殊性,则条件放在on中和where中,返回的结果集是相同的。
当涉及多个联接时
一定要用较小规模的数据对查询进行单元测试;
并坚持使用左外联接
外联接中的条件设置(执行逻辑)
- 当条件位于Join子句中,先包括外表的所有行,然后用条件包括第二个表中的行
- 当条件位于Where子句中,先执行联接,然后将条件应用于联接行
|
|
Left [Outer] Join
- 返回左表中的所有行,如果左表中行在右表中没有匹配行,则结果中右表中的列返回空值。
必须要表基准表放在左侧,非常重要!否则会产生大量NULL值。
Right [Outer] Join
- 恰与左连接相反,返回右表中的所有行,如果右表中行在左表中没有匹配行,则结果中左表中的列返回空值。
建议左/右外联接不要混合使用
Full [Outer] Join
- 返回左表和右表中的所有行。即返回两个数据集的所有数据。当某行在另一表中没有匹配行,则另一表中的列返回空值
交叉联接
Cross Join
- 不带WHERE条件子句,它将会返回被连接的两个表的笛卡尔积,返回结果的行数等于两个表行数的乘积
- (例如:T_student和T_class,返回4*4=16条记录)
- 如果带where,返回或显示的是匹配的行数。
差集查询
- Left Join / Null
- what:分析两个数据集之间相关性的查询;
- why :用于查找不存在或不匹配的数据
- how :一般需分两步来执行
- 联接
- 设置第二个数据集的主键为NULL
涉及where子句,or的条件子句一定要用括号
()
括起来
|
|
- Not In Like ( ) :小范围使用
|
|
- Exists & Not Exists :两个表之间;
- Exists :返回仅在左表中的数据
- Not Exists :外层查询结果不存在于关联表里的方法(返回左边不在右表里面的观测值)
注意 Where 之后没有限定列名, 条件限定在 子查询中
|
|
- EXCEPT: 返回在坐标中存在,但不在右表中的行;
- 从左查询中返回右查询没有找到的所有非重复值。
|
|
联合 - Union
- 返回每个结果集中的所有行
- Union ,表示删除重复行
- Union ALL ,表示不考虑是否存在重复行
- 每个Select必须具有相同的数量、类型;
- 列名或别名由第一个Select确定
- Order by子句放在最后,并且对所有结果进行排序,且列名必须是第一个Select语句中存在的
- 可用Select Into,但Into必须放在第一个Select语句中
列的xml数据类型必须为等效。
所有的列必须类型化为 XML 架构或是非类型化的。 如果要类型化,这些列必须类型化为相同的 XML 架构集合。
子查询
非相关子查询
what:子查询是独立运作的;
how :运行逻辑
- 非相关子查询被执行一次
- 结果传输到外查询
- 外查询被执行一次
1Select (Select 3) As subqueryvalue;
公用表表达式- CTE
- what:CTE (Comman Table Expression )
- why :确定查询结果可当做临时视图来使用;即后续的查询可以引用公共表表达式中的表及字段;
- how :CTE使用With子句,而With子句定义了CTE;在With子句内分别是名称、别名、AS、括号、Select查询语句
- CTE自身只是一个不完整的SQL语句
- 一旦With子句中定义了CTE,查询的主要部分就可以使用其名称引用CTE;就像CTE是其他任何表源一样;
- 若将多个CTE包含在相同的查询中,在主查询之前确定CTE的顺序,并用逗号分隔
,
;并且后面的CTE可以引用在它之前定义的任何CTE - CTE不能嵌套
|
|
相关子查询
- what:先执行外查询,相关子查询的运行要引用外查询中的列
- why :对于复杂的Where条件来说很有用
- how :执行逻辑
- 先执行一次外查询
- 在外查询中对每一行执行一次子查询,把外查询中的值取代为子查询的每一次执行
- 子查询的结果要整合到结果集中
子查询可出现在Select子句中,也可以出现在Where 子句中;
判断是否为相关子查询的标准为是否引用了外查询中的列;
没有引用外查询中的列,为非相关子查询;先于外查询运行
引用了外查询中的列,为相关子查询,后于外查询运行
数据透视 - Pivot
|
|
- 示例1
|
|
- 示例2
|
|
unpivot
UNPIVOT 并不完全是 PIVOT 的逆操作。PIVOT 会执行一次聚合,从而将多个可能的行合并为输出中的单个行。而 UNPIVOT 不会重现原始表值表达式的结果,因为行已经被合并了。另外,UNPIVOT 的输入中的空值不会显示在输出中,而在执行 PIVOT 操作之前,输入中可能有原始的空值。
数据清洗
去重复值
|
|
|
|
NULL
- what:空值NULL表示不存在的值,是一个未知值;并不表示0;
- how :包含空值的任何表达式结果均是一个未知值
- Null + 1 = Null
聚合函数中SUM( ) 与AVG( ) 会自动排除NULL进行计算;
Count( * ) 会计算空值;但Count( col )会排除空值
|
|
- isnull(col, 0 ):将col列中NULL值替换为0
|
|
NULL :未定义的值 / 不存在
NA :缺失数据
NaN :无意义的数,比如sqrt(-2), 0/0。
Inf :正无穷大
-Inf :负无穷大
表是否存在
|
|
在每一个数据库中都有sys.sysobjects用于包括在数据库中创建的每个对象(例如约束、默认值、日志、规则以及存储过程)。详细的说明信息参看MSDN上的帮助文档:sys.sysobjects
OBJECT_ID的作用是返回架构范围内对象的数据库对象标识号。如果找不到数据库或对象的名称,例如相应名称不存在或拼写不正确,则会返回NULL。
sys.indexes用于保存每个表格对象(例如,表、视图或表值函数)的索引或堆,详细的说明信息参看MSDN上的帮助文档:sys.indexes
数据运算与其他
两行观测值相减
|
|
|
|
已知交易日计算差值
|
|
判断表单存在并删除
|
|
计算累加和
|
|
选取重复值
- 通过
group by
之后having count(*)>1
来进行筛选
|
|
取出一个字符串中最后一个特殊字符右边的字符
- 涉及 翻转
reverse
和charindex
|
|
问题 - 函数的长度参数无效
- 用逗号的位置得到的参数-1后是负数,不能做 LEFT和SUBSTRING的参数。
通过排序来进行查看,并且用Where进行限定
12345Select *, Convert(varchar(10), createTime, 120) As createTime2, left(department, charindex('后', department,1)-1) As 老师From [crm].[YTX].[t_wx_contact_monitor]where tag = 'v11.JY.JY-QH-WECHAT-QY.0' and error_code= 0and charindex('后', department,1)-1 >0
问题 - 遇到 “遇到以零作除数错误”
- 屏蔽了“遇到以零作除数错误” 的错误信息,这样的话,遇到0是除数的情况,就是赋值为Null
|
|
系统查询相关
通过字段找表名
|
|
注释
--
双连字符;从开始到行尾均为注释;对于多行注释,必须在每一个开头多使用/*……*/
正斜杠 星号;- 可在同一行,可另起一行;在这之间的全部内容均为注释(可跨行);
- 可在代码内执行
参照文档
|
|