sql序列(3)基本语法
1,数据库的生命周期:
需求分析(需求说明书) -- 逻辑设计(E-R) -- 物理设计(表结构) -- 数据库实现(范式化) -- 数据修改(索引/约束) -- 数据库监控(维护)
详细可参考:http://www.cnblogs.com/samwu/archive/2011/09/07/2169829.html
2,E-R图学习:列出一些基本信息,我也是这里学习的
http://www.cnblogs.com/dekevin/archive/2012/07/18/2596745.html
3,主键:唯一标识列
特点:字段非空
字段具有唯一性
该值不允许修改(建议|【ps:改还是有办法改的】)
每个实体只能有一个主键(建议|【ps:也可以有联合主键】)
外键:连接不同实体
作用:保持数据完整性
4,数据库的三大范式(控制数据的冗余)
第一范式(1NF):确保每列保持原子性
第二范式(2NF): 确保表中的每列都和主键相关
第三范式(3NF): 确保每列都和主键列直接相关,而不是间接相关
详细可参阅:https://www.cnblogs.com/linjiqin/archive/2012/04/01/2428695.html
【PS:博主有话说>>通过故意提供冗余数据,降低连接的复杂度,获取更快的查询时间。
此时,取消规范化也是必须的。
总的来说,性能 > 规范】
5,增删改查格式:
增:INSERT INTO 表名(列名) VALUES (值)
删:DELETE FROM 表名 WHERE 条件 【PS:条件要是没加,则删除整张表数据。谨慎操作】
改:UPDATE 表名 SET 字段 = '值' WHERE 条件 【PS:条件要是没加,则修改整张表数据。谨慎操作】
查:SELECT * FROM 表名 WHERE 条件
==========================================
【PS * : 表示检索指定表中的所有列】
6, GROUP BY 子句1:用于分组输出行
ORDER BY 子句2:排序【DESC | ASC】
语句1:
--解释:根据name来分组,并且根据name来排序
--【PS:使用group by 时,查询的非聚合函数都要在group by中】
======================================================
SELECT NAME FROM USERS GROUP BY NAME ORDER BY NAME DESC
7,PIVOT: 将行旋转成列
语句2:
======================================================
SELECT [星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日]
--这里是PIVOT第三步(选择行转列后的结果集的列)这里可以用“*”表示选择所有列,也可以只选择某些列(也就是某些天)
FROM WEEK_INCOME
--这里是PIVOT第二步骤(准备原始的查询结果,因为PIVOT是对一个原始的查询结果集进行转换操作,
--所以先查询一个结果集出来)这里可以是一个select子查询,但为子查询时候要指定别名,否则语法错误
PIVOT
(
SUM(INCOME) for [week] in([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日])
--这里是PIVOT第一步骤,也是核心的地方,进行行转列操作。
--聚合函数SUM表示你需要怎样处理转换后的列的值,是总和(sum),
--还是平均(avg)还是min,max等等。例如如果week_income表中有两条数据并且其week都是“星期一”,
--其中一条的income是1000,另一条income是500,那么在这里使用sum,行转列后“星期一”这个列的值当然是1500了。
--后面的for [week] in([星期一],[星期二])中 for [week]就是说将week列的值分别转换成一个个列,
--也就是“以值变列”。但是需要转换成列的值有可能有很多,我们只想取其中几个值转换成列,那么怎样取呢?
--就是在in里面了,比如我此刻只想看工作日的收入,在in里面就只写“星期一”至“星期五”
--(注意,in里面是原来week列的值,"以值变列")。
--总的来说,SUM(INCOME) for [week] in([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日])
--这句的意思如果直译出来,
--就是说:将列[week]值为"星期一","星期二","星期三","星期四","星期五","星期六","星期日"分别转换成列,
--这些列的值取income的总和。
)TBL--别名一定要写
======================================================
【PS:以下语句as的意思是给列起别名的意思】
======================================================
语句3:
select [1] as 'v1',[2],[3],[4],[5],[6],[7],[8]
from (
select PublisherId
from books
) as tb_source
pivot(
count(PublisherId) for PublisherId in ([1],[2],[3],[4],[5],[6],[7],[8])
) as tb_pivot
8,ROW_NUMBER(): 返回一个唯一的序列号
【ps:要配合over(order by 列名);】
语句4:
==========================================================
SELECT ROW_NUMBER() OVER(ORDER BY ID),* FROM Books
9,PARTITION BY 子句3:用于将结果集划分为应用了ROW_NUMBER()函数的分区
每个分区的第一行都是从1开始的
语句5:
==========================================================
SELECT ROW_NUMBER() OVER(PARTITION BY PublisherId ORDER BY PublisherId) as rownumber,*
FROM Books WHERE PublisherId in (1,2,3)
10,通配符:% _ [] [^]
语句6:查找用户名以L开头的用户信息
==========================================================
SELECT * FROM USERS WHERE USERNAME LIKE 'L%'
11,聚合函数:SUM() --求和
COUNT() --求数量
MIN() -- 最小值
MAX() -- 最大值
AVG() -- 平均数
ROW_NUMBER() -- 获取序列号
12,日期函数:
CURRENT_TIMESTAMP --2017-11-23 19:11:03.320
GETDATE() --2017-11-23 19:11:03.320
DATEPART(YEAR, GETDATE()) --2017
YEAR(GETDATE()) --2017
13,表连接:
13.1 内连接: 语法1:SELECT * FROM A INNER JOIN B ON A.ID = B.AID;
语法2:SELECT * FROM A, B WHERE A.ID = B.ID
=============================================
【PS:以下语句是为表起别名,并且查询指定表的指定字段信息】
SELECT a.c1, b.c1 FROM A a INNER JOIN B b ON A.ID = B.AID;
=============================================
13.2 外连接:
13.2.1 左连接:SELECT * FROM A LFET JOIN B ON A.ID = B.AID;
13.2.2 右连接:SELECT * FROM A RIGHT JOIN B ON A.ID = B.AID;
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
【PS:左连接 与 右连接 是有区别的,】详情可查看:
https://www.cnblogs.com/cy163/archive/2008/10/16/1312920.html
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13.3 全连接 :SELECT * FROM 表1 FULL JOIN 表2 ON 表1.ID = 表2.表1_ID;
14,UNION JOIN :创建一个包含两个表中所有行的表
SELECT * FROM A union JOIN B ON A.ID = B.AID;
等价于:
SELECT * FROM A UNION ALL SELECT * FROM B
【PS:两表必须有相同数量的列,对应的数据类型要兼容】
15,关于空行:
语句7:(查询用户名不为空的数据行)【IS NULL : 与 IS NOT NULL 相反】
=================================================================
SELECT * FROM USERS WHERE NAME IS NOT NULL
【PS: NAME = NULL 与 NAME IS NULL 是不一样的】
语句8:查询用户表中的用户名,若为空,则用‘未知’替代
=================================================================
SELECT ISNULL(Name, '未知') FROM USERS
16,BETWEEN...AND... / IN() / NOT IN() --范围性条件
17,条件逻辑运算符:AND / OR / NOT
18,创建新表1
语句9:创建一个临时表【#temp: 表名加#,表明创建临时表,否则为永久表| 临时表的周期:查询窗口关闭即销毁】
==========================================================
SELECT ID, USERNAME, LOGINID, EMAIL INTO #TEMP FROM USERS
语句10:用途:可以复制一个表结构:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SELECT * INTO USERS_L FROM USERS --复制表结构,同时复制表数据,但是无约束,无主键
SELECT * INTO USERS_L FROM USERS WHERE 1=0 --复制表结构,但是不复制表数据,无约束
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19,操作数据:
创建表后,插入数据:使用第5点INSERT INTO;
【PS:插入的数据中,有外键列存在的话,则插入的数据在外键表中必须存在,否则插入失败。--[保证数据完整性]】
更新数据:
更新一条数据中的多个字段:
语句11:
========================================================
UPDATE A SET NAME='JAKE',LOGINID='10001' WHERE ID = 1
删除数据:
语句12:
========================================================
DELETE FROM USERS WHERE ID = 1;
数据量大时,可用:TRUNCATE TABLE
【PS:TRUNCATE不执行日志操作,不支持回复删除的数据】
【网上说使用delete误删除的: 可以使用mdfview程序回复,下载地址:http://www.minisoft.cn/mdfview.rar】
【我没试过...】