SQL金典

ps:补充自己的基础知识,大神请无视..

~~~~~~~~~~~~~~~~~~~~~

DataBase Management System,DBMS。。。。
Catalog 。。。库
Table。。。。表
Column。。。列--Field 字段,每个列描述数据的一个特性。
DataType 。。。数据类型
Record。。。。记录---Row行,
PrimaryKey。。。主键-----多个字段才唯一标识一列时,称为复合主键
Index 。。。索引-不建立索引是全表扫描,速度慢;建立索引只扫描索引,速度快;
    缺点:占据一定磁盘空间,减慢了插入和删除速度(更新索引);
表关联:两张表通过字段关联,关联到其他表的主键的字段称为 外键;
SQL的4个功能:创建库并定义表结构,查询数据,更新、删除指定数据,控制数据库安全。
1、入门

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1、数据类型
    整型、数值类型、
    字符相关类型(固定长度char、可变长度varchar、多语言可变长度nvarchar、可变长度字符串text、ntext可变大字符)、
    日期时间类型datetime/smalldatetime/timestamp时间戳、
    二进制类型:图片、视频等,非常大的,没有固定结构的数据,设置和读取也需要宿主语言的辅助。如 image(MS sqlServer),其他是blob。
    
2、通过SQL 管理数据表
    创建表 create table name{
        字段名1 字段类型, 
        字段名2 字段类型,
         .....
        约束定义1,
        约束定义2,
        .....
        }
    定义非空约束,在类型定义后增加 NOT NULL ,
    定义默认值,------------增加 DEFAULT ,
    定义主键,在所有字段定义之后, PRIMARY KEY(字段名),
    联合主键:两个字段联合起来作为主键,(复合主键),PRIMARY KEY(字段名1,字段名2),
        缺点:    效率低,增删改查都需要处理两个字段,大大降低了数据处理速度,
            结构糟糕,联合主键会有业务含义,与“使用逻辑主键不是业务主键”的最佳实践冲突,开发和维护麻烦,
            外键麻烦或无法创建,
            开发难度很大,工具和框架对单主键支持良好,对多主键复杂特殊处理。
    定义外键:所有字段之后,FOREIGN KEY 外键字段名 REFERENCES 目标表名(被关联的字段名)
    修改已有数据表:    ALTER TABLE 待修改的表名 ADD 字段名 字段类型 
            ALTER TABLE 待修改的表名 DROP 待删除的字段名            
    删除数据表 DROP table 表名

    
2、数据表的创建和管理

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

insert into tableName(A,B,C) values(a,b,c)
insert into tableName(a,b,c) 按照定义表中字段顺序进行插入,不推荐。
非空值必须插入,主键必须唯一不重复,外键值必须在目标表中存在。--所以不推荐在数据库中生成外键,有程序控制更灵活。
update tableName set A=a,B=b,C=c 
    where X=x
非空值不能更新为NULL,主键不能更新为重复,外键不能不存在。
delete from tableName where X=x 有外键时,必须先删除引用,不然删除失败。
delete只删除数据,drop 删除数据和表结构。
3、数据的增删改

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

select * from tableName where X
select A,B from tableName where X
 列名 as 别名  ,as 可省略,但要保留空格。

过滤问题:可程序控制,缺点是 全取出对内存网络消耗都大,程序实现复杂,关联其他表的情况不能处理。所以用数据库提供的最好。

数据汇总 
聚合函数 MAX MIN AVG SUM COUNT
count(*)结果集的总条数,count(列名)  列名的值不为NULL的总记录数,不一定相等。
order by  A asc/desc, B asc/desc 先A,再B 排序----推荐显式指定排序,防止不同数据库之间差异影响结果。

通配符过滤:
like 二元操作符,左边为列名,右边为表达式, 
    单字符匹配 下划线 _ ,如 b_d,匹配第一个字符为b,第二个字符任意,第三个字符为d的字符串。
    多字符匹配 百分号 % , 如 like%abc%’.
    可一起使用,如 like '%n_'
集合匹配 只MS SQL Server 支持,方括号[] ,与字符集中任意一字符想匹配的字符, 如 [bt],有点像..正则表达式啊?
    还可以使用否定符取反,[^bt],匹配不是bt的串,
    在其他库上可用 or语句实现。
    缺点:效率低,不要过多使用。
空值检测  select A,B,C from tableName where X is/is not NULL
反义运算符 ! 作用于运算符的取反,只有MS SQL 和DB2支持,
    NOT 作用于表达式的取反, NOT(表达式),推荐使用。
多值检测  or或 inIN(值1,值2,值3....)
范围值检测  < >between and, 字段名 between leftValue and rightValue ,包括范围边界值。性能好,优先考虑。
低效的where 1=1 :数据库系统无法使用索引等查询优化策略,只能每行数据进行扫描(全表扫描),大大降低了性能。

数据分组:用来将数据分为多个逻辑组,每个组是所有记录的一个子集,从而对每组进行聚合运算。Group by 分组字段。一般放在语句最后。 
    分组语句必须和聚合函数一起使用?又可以分开使用?
    需要分组的所有列,都必须位于group by子句列名列表中,没有出现的列,不能放在select语句后的列名列表中。
        select A,B from tableName group by A ,是错误的,A分组了,但B没有,不一样的B但一样的A的无法显示。
        select A,sum(B) from tableName group by A,正确,聚合函数得出一样的B值,就能显示。
        很多列时是 逐层分组,组中组,结果集是以最末一级分组来进行输出的。
    列:select A,B,count(*) as M from tableName group by A,B order by A
Having语句 对部分分组的过滤,
    聚合函数不能用于where语句,改为having即可,having 可使用复杂的过滤条件,orand in 等。
    语法和where几乎一样,只是和group by的位置不一样,where在group by 之前,having 在group by 之后,
    having语句不能包含未分组的列名,
    应该能同时用吧?

限制结果集行数 只检索结果集中的部分行,主流数据库都支持,但差异很大。
    MySQL  关键字 limit 放在select语句最后 ,limit 首行行号, 要返回结果集的最大数目   --行号从0开始
        例子: select * from tableName order by X desc limit 2,5
    SQLServer2000 关键字TOP NUM  结果集中的前N条记录,用子查询实现区间范围功能,
        例:select top 3 * froom tableName
            where A NOT IN 
                ( select top 5 A from tableName order by X desc)
            order by X desc --查询按X排序的第6开始的3条结果。
    SQLserver2005 兼容2000,另外还有窗口函数 row_number(),计算每一行数据在结果集中的行号(从1开始),
        语法:row_number() over(排序规则)    --只出现在select或order by 子句中
        例:(select row_number() over(order by A) as rownum,A,B,C,D from tableName ) as M
        配合子查询使用 
            select * from M where rownum >=3 and rownum<=5
    Oracle 窗口函数 row_number(),与sqlserver2005一样,但是不用 as定义别名,
        另外:Oracle为每个结果集都默认增加行号的列rownum,所以前N条记录可以用 where rownum<=N 实现,
        但是 取中间值必须用窗口函数,因为Oracle会把不符合的剔除结果集,后面的rownum会自动减一,一致都不满足。
    DB2 窗口函数支持,还有关键字 Fetch,用来提取前N行,放在order by后面,
        例:select * from tableName order by X desc fetch first 6 rows only
        可用fetch配合子查询实现区间。
    数据库分页    核心就是 限制结果集行数
        每页数据条数 PageSize,当前页(从0开始计数)CurrentIndex, 一次只查询从P*C开始的P条数据。

抑制数据重复    distinct 关键字是对整个结果集进行数据重复抑制的,不是针对一列。

计算字段:数据默认展现方式不完全符合应用要求时,经计算、转换、格式化等再使用,比用宿主语言处理性能高很多。
    常量字段 值确定的一个值作为字段,可用as 。
    字段间计算,加减乘除等,可用于where子句,
    数据处理函数 
        字符串长度,length,(在ms sql server中是len)
        字符串子串 substring(Oracle和DB2中是substr),
        字符串连接 
            MYSQL会把+ 转化为数值,不能用,应该用函数 concat(),concat_ws()可加入指定分隔符。
            MS SQL Server 用+,
            Oracle 使用|| 双竖线,也提供concat(),
            DB2 双竖线 || ,和concat()。

计算字段的其他用途: 数据过滤、删除、更新中,都可以使用计算字段。

不从实体表中取的数据:
    MYSQL和MS SQL Server 允许使用不带FROM子句的select语句来查询 不属于任何实体表的数据,
        例: select 1    /select length('abc') 
    Oracle不允许,但可以使用系统表来作为from子句,常用DUAL。
        例: select 1,length('abc') from DUAL
    DB2 的系统表是 SYSIBM.SYSDUMMY1

联合结果集:    UNION 两个完全不同的查询结果集的组合,显示在一个结果集中。相当于select 语句+起来,一般用于各种报表。
    select A,B,C from table1 
    Union select X,Y,Z from table2
    原则:结果集的列数相同,不同时补常量字段;对应列的类型相容,相同或者能转换为同一类型--推荐类型完全相同。
    Union 会把完全重复的数据合并为一条,(自带distinct啊...),不需要合并的使用Union all.

        
        
            
4、数据检索

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

数学函数 
    绝对值 ABS(),指数power(),平方根sqrt(),
    随机数    select rand()--Mysql,
        select rand(随机数种子) --MS SQL server,
        select dbms_random.value from dual --Oracle没有内置随机数函数
        还有 dbms_random.value(low,high) ,dbms_random.normal正态分布的一组数,偏差1,期望为0
        dbms_random.string(opt,len)随机字符串。
        select SYSFUN.rand() from sysibm.sysdummy1 --DB2.
    Round()四舍五入
    圆周率π, PI(),Oracle等不支持的用 ACOS(-1)代替:-1的反余弦值等于π值。
    求符号:SIGN(),大于0,则1,小于0,则-1,等于0,则0.
    求整除余数:MOD(),--MS SQLserver中为 操作符%.
    自然对数: LOG()  --Oracle中为 LN().
        LOG10() 计算一个以10为底的对数值 --Oracle中为LOG(m,n),以m为底n的对数。
    Power(X,Y)用来计算X的Y次幂。

字符串函数:
    长度:length(),----或len(),
    小写:lower(),---DB2中为 Lcase().
    大写:Upper(),---DB2中为Ucase().
    截去左侧空格:LTRIM(),右侧空格:RTRIM(),两侧空格:TRIM()或者组合左右实现。
    子串:substring(S,start,length),substr().
    计算子串位置:Instr(string,substring),不在返回0,---MS SQL server中为charindex,---DB2中为locate(subs,S).
    从左侧取子串:left(s,length),从右侧取子串:right(),
    字符串替换:Replace(S,tobeS,toS),toS是空的话就是删除功能。
    得到字符的ASCⅡ码:ASCⅡ(), 反过来是 CHAR(),--Oracle中为CHR(),
    发音匹配:soundex()计算发音特征值,返回4个字节的字符串,第一个字符总是初始字符串的第一字符,后面是3位数字。
        difference()--MS sql server和DB2中额外提供的函数。

日期时间函数: 
    类型有4种 日期Date、时间Time、日期时间DateTime、时间戳TimeStamp。
    一般字符串可自动转化为对应类型,但Oracle需要函数To_Date(),
    当前日期时间 
        MySQL  NOW(), ---等同于 SYSDATE()、CURRENT_TIMESTAMP,
               CURDATE()日期, CURRENT_DATE.
               CURTIME()时间,
        MS SQL SERVER
            getdate(),配合convert()使用。
            select convert(varchar(50),getdate(),101) as 当前日期,
            select convert(varchar(50),getdate(),108) as 当前时间,
        Oracle  使用系统表 DUAL中查询SYSTIMESTAMP来得到当前时间戳,SYSDATE得到日期时间,
            配合TO_CHAR(时间日期值,'YYYY-MM-DD'),TO_CHAR(时间日期值,'HH24:MI:SS')。
        DB2 系统表SYSIBM.SYSDUMMY1中的 CURRENT TIMESTAMP/DATE/TIME。
    日期增减  MS SQL Server 中 DATEADD(datepart,number,date)
    日期差额 MS SQL Server 中 DATEDIFF(datepart,startdate,enddate)返回以datepart为单位的差额
        例:select DATEDIFF(S,convert(varchar(50),getdate(),101),getdate())--今天过了多少秒。
    计算日期是星期几:
        MYSQL dayNAME()
        MS SQL server : select datename(dw,getdate()), --dw 工作日,
        Oracle: TO_CHAR(DATE,format)--day 会返回周几
    取得日期特定部分: MS SQL中 DATENAME() 和DATEPART(),

其他函数:
    类型转换,尽量显式转换,避免隐式转换。
        MYSQL 中 CAST(expression as type)和Convert(ex,type),
        MS SQL server,CAST(expression as type)和Convert(type,ex)。
    空值处理:
        coalesce(表达式,value1,value2...),返回所有参数中第一个非空表达式,
        coalesce()的简化版,两个参数
            IFNULL(EX,value)--MYSQL
            ISNULL(ex,value)--MS SQL Server
            NVL(ex,value)--Oracle
        NULLIF(ex1,ex2) 如果表达式不等价,返回ex1的值,如等价,返回ex1类型的空值。
    CASE函数:
        用法1, case expression
                when value1 then returnvalue1
                when value2 then returnvalue2
            else defaultreturnvalue
            end
        用法2,case 
                when condition1 then returnvalue1
                when...
            else defaultreturnvalue
            end    --只能对一个表达式进行判断。
各数据库系统独有函数:
    MS SQL server ,辅助函数 app_name()返回当前回话的应用程序名称;
            current_user 当前登录用户名
            host_name()返回工作站名。
            newid()生成全局唯一字符串,
            
        
            
            
函数

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1、索引 针对字段,必须指定字段,可以为多字段创建一个索引,
    创建表 create table t_person(
    fnumber varchar(20), fname varchar(20), fage int)
    创建索引 create index 索引名 on 表名(字段1,字段2,...)
    create index idx_person_name on t_person(fname)
    删除索引用 drop index 表名.索引名
2、约束 非空 NOT NULL、
    唯一 Unique约束 防止一个特定列中两个记录具有同样的值,分为单字段唯一与复合唯一
        单字段唯一的 语句是 字段后加 UNIQUE--该字段不能有重复值
        复合唯一是 constraint 约束名 unique(字段1,字段2...)--字段1和字段2,单个可以重复,但是不能同时重复。
        在已经创建好的表上添加新约束 alter table 表名 add constraint 约束名 unique(字段1,..)
                删除约束 alter table 表名 drop constraint 约束名
    CHECK约束 检查输入到记录中的值是否满足一个条件, 任意有效的SQL表达式,
         例: age int check(age>0), number varchar(20) check (length(number)>12)
        如CHECK子句要使用其他列,则在create table末尾使用 constraint关键字定义。
        constraint 约束名 check(条件),
        例:create table t1(A INT, B INT,C INT,  Cconstraint ck_AB Check(A<B))
    主键约束 唯一标识,不空,PRIMARY KEY,
    外键: 语法,foreign key 外键字段 references 外键表名(外键表的主键字段)
        或 alter table tName add constraint fk_A_B 
            foreign key (外键字段) references 外键表名(外键表的主键字段)
6、索引与约束

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

join类型: 交叉连接(cross join)、内链接(inner join)、外连接(outter join),部分数据库系统还支持联合连接(union join)。
1、内连接:语法 inner join tableName on condition --进行连接时的条件,
    例:select A,B from table1 
        inner join table2  on table1.M=table2.N where table1.X=x 
    inner 是可选的,默认就是内连接。
2、不等值连接:连接的条件中可以使用< > <> 等运算符,以及like between and,和函数。
    不等值连接是 2个表的笛卡尔运算,一般需配合等值连接匹配条件使用。
3、交叉连接:所有表所有记录包含在结果集中,不存在on子句,分隐式和显式连接。
    隐式: select t1.A,t2.B from t1,t2
    显示: select t1.A,t2.B from t1 cross join t2。 一般只用隐式连接。
4、自连接:表与自身连接,通常需处理的问题是 一个记录和自己相同,或者A与B相同时B也与A相同的问题。会写成 o1.id<o2.id.
5、外部连接:主要用来解决空值匹配的问题,不需要两个表具有匹配记录,这样可以指定某个表中的记录总是放到结果集中。
    分为3种类型:右外 right outer join,左外left outer join,全外full outer join。
        左外返回左表中部复合连接条件的数据,右外返回右表中,全外是两个合集。--以关键字join分左右。
    
    
    
7、表连接

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

以结果集供其他SQL语句使用,--嵌套内的查询。
只返回单值的,和返回一个数据集的.
1、单值的又叫标量子查询,可用于列表、表达式、where等场合
2、列值子查询,表子查询,可用于from、insert、连接、IN子句等场合。
    select id,name,(select max(X) from B where B.id=A.id) from A 
        --通过where子句,子查询连接到外部的select,不能单独执行。--相关子查询。
3、集合运算符与子查询
    in 匹配某一项,
    =any 等价于in, <>any 等价于 NOT IN, any不能与固定的集合想匹配,
    All 也需要带比较符,比较的值需要匹配子查询中所有值,不能与固定集合想匹配。
        如匹配集合为空,不论什么比较,ALL都返回true。
    exists 单目运算符,检查每一行是否匹配子查询,只有和相关子查询一起使用。
        select A,B from t1 where exists ( select * from t2 where t2.id=t1.id and t2.X<x)
4、子查询应用 
    insert into t1(A,B) select A,B from t2   --列序对应。
    A或者B换成 case 子句,可实现 数据处理,
    
8、子查询

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1、SQL注入漏洞攻防 :用户在输入中拼接字符串,偶后转入数据库去执行这字符串,造成不可预测影响。 
    过滤敏感字符和使用参数化SQL;
    过滤 or/and/select/delete等关键字,--麻烦且不严谨。
2、SQL调优 :
    二八原则:找出消耗性能的语句,优化。
    索引:最根本的优化方法,内功! 
        聚簇索引:数据表的物理顺序与索引顺序相同; 字典里拼音和偏旁部首都是索引,前一是聚簇的,
    存储碎片-重建索引,reindex/rebuild ,
    尽量减少全表扫描,创建必要索引,使用预编译查询(参数化SQL)、
    调整where子句连接顺序-DBMS一般采用自下而上的顺序解析WHERE子句,表连接最好写在其他where条件之前,以过滤掉最大数量记录后再连接,
    select中不使用*,尽量压缩SQL到一条语句且一次执行。
    用where 替换 having--后者只会在检索出所有记录后才对结果集过滤,
    使用表别名,前缀每个列,减少解析时间和错误。
    用exists替代IN--in子句执行一个子查询内部的排序和合并,
    用表连接替换exists
    避免在索引列上使用计算--
    使用UNION all 替换union--在确保结果不重时,不实用检索的自动去重功能。
    避免隐式类型转换造成全表扫描--查询条件中使用匹配的类型值,
    防止检索范围过宽--使用is not null 或 不等于判断,可能造成优化器假设匹配记录数太多,或使用like的带 %c 形式,不能有效评估匹配数量。
3、事务:原子操作,transaction,原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability,简称 ACID特性。
    启动、提交、回滚..制定锁粒度、隔离级别..
    例: set transaction isolation level read uncommited 
        begin transaction
            ....
        commit
4、自动增长字段: MS SQLserver 中 关键字为 identity(startvalue,step)起始数字,步长。
    业务主键后期维护不方便,逻辑主角不能合并表。
6、NULL的学问:NULL表示未知,而不是没有值,和任何运算都是NULL,出现在where子句是False, 在聚合函数中会被忽略。
7、开窗函数: 函数名(列) over(选项) --
    select A,B,COUNT(*) OVER() from t1 where X<x 
    partition by 子句 ,定义行的分区,从而进行聚合计算,创建的分区独立于结果集,位于over的选项内。
    可多次使用,结果互不影响。
    select A,B,COUNT(*) OVER(partition by A),COUNT(*) OVER(partition by B)  from t1.
8、with子句和子查询:降低使用子查询的次数可以优化性能,
    SQL提供了with子句用于为子查询定义一个别名,一次定义多次使用。
    DRY don't repeat yourself. 
    格式: with 别名 as (子查询) --是SQL语句,不是存储过程,可远程调用。
    还可以定义列别名: with 别名(f1,f2) as (子查询) 
9、表复制: create table t2 as select * from t1 where 1<>1
       select * into t2 from t1 where 1<>1
10、高级话题
原文地址:https://www.cnblogs.com/dacude/p/4668643.html