前言
SQL以前学得马马虎虎。算是基本记得它们的原理,但是好久不写还是会经常写错。特别是遇到SQL Server与MYSQL与标准SQL都不兼容的情况下,还要去查不同的手册,查不同的语法。所以决定用BLOG的形式重述一下基本的语句结构,以后没事常看看。
常见的语法标记,"[]"代表可选项,“|”代表多选一,"{}"代表强制选择的一组之一。
一、MYSQL的一些技术参数。
MYSQL使用C++写成,拥有多种语言API。它的基本默认存储引擎以前是MYISAM,现在是InnoDB,共支持八种引擎。是使用B树的磁盘表。MYISAM是ISAM的升级版,比较倾向于小的数据库工程,对于一般的查询支持非常的快。但是因为它不支持事务,不支持行级锁,所以渐渐被支持事务安全的InnoDB引擎所取代。InnoDB支持的细粒度锁专门为ACID事务提供支持,特别适合大规模数据库的最高性能。
MYSQL理论上支持所有的标准SQL、聚合函数、左右外连接、DML、DDL、DCL与ODBC。
MYSQL的服务器是MYSQLD。
二、一些具体的值得注意的地方。
1 关于约束,SQL语法的约束有很多种,比如NOT NULL、PRIMARY KEY、等等,都相当于一个可以直接加进Col名后面的约束,可以直接加,公式大概是:表名(Col 约束,Col 约束,Col 约束);
2 关于括号, 凡是涉及多个Col连接的,都要使用"()"把Col包起来,比如
insert into 表名 (Col,Col)
values(v,v);
3 多余的对象要和表名的位置对称。如上。
4 关于表的各种关键字权限:
(1) 比较神奇的是,select关键字可以对表达式求值 ,例如select 1 +1 ;可以得到2。
(2) 可以用create routine、alter routine之类的关键字来创建和更改程序,用execute来执行。
(3)增加账户的两种方法,一是直接插入user表,另一种就是如下
GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost' IDENTIFIED BY '123456' WITH GRANT OPTION;(注意这个grant to结构,必须用root权限登录)。目前MySQL支持八种特权,如果全部都grant了,就相当于root了。
5 提到用户的地方,最好使用 用户名@ip地址 的形式。
三、关于查询优化
1 你的许可设置得越复杂,所需要的开销就越大。可以用benchmark(count,expresion)的形式来进行基准测试,找到有问题的表达式。
2 可以用explain语法来对select语句进行分析,它将解释select语句如何被执行。提醒我们要设置索引之类的东西(设置索引是提高查询速度的第一思路,MYSQL中所有的列类型都可以被索引,包括BLOB)。它的结果是一张表。
3 有时候MYSQL会把连接强制置为Straight Join。
4 MYSQL对MYISAM表进行表级锁,对BDB进行页级锁,对于InnoDB进行行级锁。有意思的是,MYSQL不会出现表死锁的情况,因为它会采取一次获取所有锁的策略。
5 多数的数据库将行数据域索引文件保存在一起,但是MYSQL为了适应现代操作系统,特地把它们分开摆放。
四、如何设计数据库?
使数据尽可能地小,使用尽可能地小的类型、尽可能地使用Not NULL(为什么?)、使用尽可能小的索引、使用变长列。
五、关于MYSQL中的索引。
索引的目的是什么?不是每次都查询每一条记录的整条,而是直接读索引列来找到特定匹配值!这样可以只把索引取到内存中,增加效率。
创建索引的SQL语句。
CREATE TABLE test (
id INT NOT NULL,
last_name CHAR(30) NOT NULL,
first_name CHAR(30) NOT NULL,
PRIMARY KEY (id),
INDEX NAME(last_name,first_name)/*把索引当作约束来写*/
);
可以为一列做索引,也可以为多列做索引,最多位15列做索引。
六、MYSQL的语言结构
1 字符串,MYSQL中''与‘是一个意思。
2 MYSQL中有一个 b ‘0101111’类型的位字段值类型。可以用这样的语句实现:
CREATE TABLE t (b BIT(8));/*八位字段值*/
1与2说明的是MYSQL的文字值,与下面的列类型不同。
3 有意思的是,可以用'`'(反勾号)来将关键字作为标示符存入数据库中,这意味着我们可以用“select”来作为表名或者数据库名!!但是,不可以用标示符做函数名。
如:CREATE TABLE `select`(a INT);/*不需要指定主键和其他约束,居然也可以有表!*/
4 关于大小写敏感性,操作系统的大小写敏感性决定数据库名和表名的大小写敏感性。Unix是大小写敏感的,Windows是大小写不敏感的。
5 用户变量,每个客户端可以拥有自己独立的用户变量,只有本客户端可以看到和使用,可以把值从一个语句传递到另一个语句。
可以用 set @var1 := exp, @var2 = exp ;//可以赋给用户变量整数、实数、字符串和NULL。
例如:
SET @t1 = 0, @t2 = 2, @t3 = 0;
SELECT @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3;
有意思的是,因为用户变量往往在发送到客户端以后才开始计算结果(而且你并不知道实际上的执行顺序),所以在一个语句的一部分设置一个变量,并在语句的另一部分中使用它们并一定能得到自己想要的结果。要避免这种情况,就要在之前的地方提前声明变量并给它赋值。这样可以保证这个赋值操作起码可以先执行。
6 从用户变量引申出去,可以用
set GLOBAL(@@global) var_name来设置全局变量;
set SESSION (@@session) var_name来设置会话(或Local)变量。
7 注释方法
#字符到行尾
-- 字符到行尾
/**/包夹住注释
8 嵌入式SQL可能引发一个问题,例如a ()可以是一个表定义,去掉这个空格,就可能变成一个函数调用。
七、列类型。
分为
1 数值型类型(不同长度的整数、浮点数)。
数值类型用M来表示宽度,它代表着一定意义上的精度范围。用D表示位数。
假设不考虑符号性。至少有BIT、TINYINT=BOOL、SMALLINT、MEDIUMINT、INT=INTEGER、BIGINT、FLOAT[(M,D)](4字节)、DOUBLE[(M,D)](8字节)、DECIMAL=NUMERIC(M,D)(必须知道确切精度,比如货币,实际上Numeric在MYSQL中并不被支持,是其他数据库引擎定义的,映射到Decimal上面)。
2 日期与时间类型。
分为
DATE 纯粹的日期
DATETIME 日期和时间
TIMESTAMP 格式上与DATETIME几乎一样,但是它专门设计出来为INSERT和UPDATE操作进行时间戳记录。它有一种专有的特性,就是可以自动更新。
TIME 单独的时间。
YEAR 单独的年份。
关于设置时间戳:
可以选择将时间戳设置为一个缺省的默认值,或者当前值。
CREATE TABLE t2 (a TIMESTAMP);
CACHE TABLE t3 (a TIMESTAMP DEFAULT 0, b TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);
INSERT INTO t2 VALUES(NOW());
3 字符串(字符)类型。
char(M) 定长char序列,如果指定了长度,不足的部分也会用空格补足,但检索时空格会被去掉。
CREATE TABLE binaryc (c BINARY(3));
INSERT INTO binaryc VALUES ('a');
SELECT c = 'a', c = 'a\0\0' FROM binaryc;
返回结果为 0 和 1。 0x00在转义成字符以后即为\0。
char = char(1)
binary(M) 保存二进制字节字符串,长度不是按照字符数而是按照字节数。没有字符集,所以也就没有响应的校对规则。插入时自动补全0x00像空格一样,而且在选择和比较时都不会删去。
varchar(M) 不定长,不会用空格补足。但是需要一个或者多余的字节存储字段的长度。
varbinary(M) 保存二进制字节字符串
tinytext text列
blob 二进制大对象,可视为足够大的varbinary列
text 可视为足够大的varchar列
blob与text在保存或检索时不删除尾部空格。
mediumblob
mediumtext
longblob
longtext
enum 字符串,和我们常见的枚举类型一样。但是在定义表结构的时候,就已经设定了可选的枚举值。插入错误的枚举值会存入空值。
set 字符串集合,有点像枚举值,但是可以使用复合的成员作组合。
如set(‘a’,‘b’) not null
的值可以有
‘’
‘a’
‘b’
‘a,b’
set
DROP TABLE IF EXISTS myset;
CREATE TABLE myset (col SET ('a', 'b','c', 'd') );
INSERT INTO myset VALUES ('a,d'), ('d,a'), ('d,a,d');
SELECT * FROM myset;
最后的出来的结果,都是根据字母排过序的(‘a,d’);
这些成对出现的类型,都有着相应的最大长度和存储需求。
有意思的是char在被取出数据库的时候,会自动去掉所有空格,不管是插入时故意留进去的,还是系统自动增加进去的,所以要保存空格,一定要使用varchar。
例如:
DROP TABLE IF EXISTS vc;
CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
INSERT INTO vc VALUES("ab ","ab ");
SELECT CONCAT(v,'+'), CONCAT(c,'+') FROM vc;
这会返回 “ab +”与“ab+”。
因为char类型与varchar类型的对比规则是padspace是不考虑任何尾部空格。
DROP TABLE IF EXISTS NAMES;
CREATE TABLE NAMES (myname CHAR(10), yourname VARCHAR(10));
INSERT INTO NAMES VALUES ("monty ","monty ");
SELECT myname = "monty",yourname = "monty " FROM NAMES;
不管这里面多少个空格,返回结果都能找到两个1。
七、MYSQL中的函数与操作符
在select语句的order by子句或having 子句或者在select、delete、update语句的set和where子句中都要遇到表达式。可以用文本值、column值、null值、函数、操作符来书写表达式。一般来说,带有null的表达式总会返回null。如果可以函数调用时,函数名和括号之间千万不要有空格。
1 操作符。
:=
||,OR,XOR
&&,AND
NOT
BETWEEN,CASE,WHEN,THEN,ELSE
=,<=>(NULL SAFE EQUAL), >=,>,<=,<,<>,!=,is like,regexp,in,
|
&
<<,>>
-,+
*,/,DIV,%,MOD
^
-(一元减号),~(一元比特反转)
!
BINARY,COLLATE
(1)大于号
SELECT 1>"6x";--返回0
SELECT 7>"6x";--返回1
--值得注意的是,字符串和数字是可以相互转换自由比较的。
(2) 等于号
SELECT 0='0';
(3)安全等于号
SELECT 1<=>'1', NULL <=> NULL,1 <=> NULL;
--非安全的等于号,第二个查询结果会返回NULL,而安全的等于号第二个查询结果会返回1。注意NULL不等于0。
(4)检验布尔值。用is来做检验是否为某个布尔值。从以下查询可以清楚地看到一一对应的关系。