1.w3School SQL简单回顾
一.基础
select
distict
where:=,<>,>,<,>=,<=,between,like
and & or:
order by : desc降序/asc升序(默认)
insert:insert into tableName values(v1,v2,...);
update:update tableName set col=newVal where col=value;
delete:delete from tableName where col=value;
二.高级
limit:(sql server:top,select top 50 percent * from person:查询表中50%的记录数);
like(not like):配合通配符%,_使用;
通配符:配合like使用;
%:替代一个或多个字符
_:仅替代一个字符
[charlist]:字符列中的任意单一字符
[^charlist]/[!charlist]:不在字符列中的单一字符
slect * from person where name like '[!LW]%';
#查询所有名字不以L,W开头的人;
in:
between...and...(not between...and...):
如下:
SELECT * FROM Persons
WHERE LastName
BETWEEN 'Adams' AND 'Carter';
以字母顺序显示介于 "Adams"(包括)和 "Carter"(不包括)之间的人
aliases:别名
select name as stu_name
from student
where age<10;
JOIN(INNER JOIN): 如果表中有至少一个匹配,则返回行
LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
FULL JOIN: 只要其中一个表中存在匹配,就返回行
SELECT INTO用法(mysql当前不支持该语法)
select *
into persons_backup [in internal_database]
from persons;
#将persons表中的数据全部复制到internal_database(省略则表示当前库)数据库的persons_backup表中;
#实例1:将当前数据库的persons复制到backup数据库的persons表
select *
into persons in 'backup.mdb'
from persons;
#实例2:将person和order表中的数据汇总到数据库person_order_backup.mdb的person_order表中;
select person.lastName,order.orderNo
into person_order in 'person_order_backup.mdb'
from person
inner join order
on person.id=order.id;
#mysql语法
create new_table
from (
select *
from old_table
)
创建约束
#mysql语法
CREATE TABLE Persons
(
Id_P int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255),
UNIQUE (Id_P) #放在后面指定一列
CONSTRAINT uc_PersonID UNIQUE (Id_P,LastName) #指定多列
)
#SQL Server / Oracle / MS Access语法
CREATE TABLE Persons
(
Id_P int NOT NULL UNIQUE, 注意:在这里
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255)
)
#修改添加单个约束
ALTER TABLE Persons
ADD UNIQUE (Id_P)
#修改 添加多个约束
ALTER TABLE Persons
ADD CONSTRAINT uc_PersonID UNIQUE (Id_P,LastName)
#删除约束,mysql语法
ALTER TABLE Persons
DROP INDEX uc_PersonID
#删除约束,SQL Server / Oracle / MS Access语法
ALTER TABLE Persons
DROP CONSTRAINT uc_PersonID
创建索引
#降序创建索引
create index order_name_index
on table_name(order_name desc);
#删除索引
alter table table_name drop index index_name;
alter语句
#添加列
alter table table_name
add column_name datatype;
#删除列
alter table table_name
drop COLUMN column_name;
#如果不支持alter...drop..语法,则
alter table table_name
alter COLUMN column_name datatype;
date函数(mysql)
now():返回当前日期和时间;
curdate():返回当前日期;
curtime():返回当前时间;
date():提取日期或日期/时间表达式的日期部分;
extract():返回日期/时间按的单独部分
date_add():给日期添加指定的时间间隔;
date_sub():从日期减去指定的时间间隔;
datediff():返回两个日期之间的天数;
date_format():不同的格式显示日期/时间;
DATE - 格式 YYYY-MM-DD
DATETIME - 格式: YYYY-MM-DD HH:MM:SS
TIMESTAMP - 格式: YYYY-MM-DD HH:MM:SS
YEAR - 格式 YYYY 或 YY
group by:用于结合合计函数,根据一个或多个列对结果集进行分组
#我们拥有下面这个 "Orders" 表:
#O_Id OrderDate OrderPrice Customer
#1 2008/12/29 1000 Bush
#2 2008/11/23 1600 Carter
#3 2008/10/05 700 Bush
#4 2008/09/28 300 Bush
#5 2008/08/06 2000 Adams
#6 2008/07/21 100 Carter
#现在,我们希望查找每个客户的总金额(总订单)。
#我们想要使用 GROUP BY 语句对客户进行组合。
select Customer ,sum(OrderPrice)
from Orders
group by Customer;
#得到结果集如下:
#Customer SUM(OrderPrice)
#Bush 2000
#Carter 1700
#Adams 2000
having:在sql中增加having子句的原因是,where关键字无法与合计函数一起使用
SELECT Customer,SUM(OrderPrice) FROM Orders
GROUP BY Customer
HAVING SUM(OrderPrice)<2000
format语法:
SELECT FORMAT(column_name,format) FROM table_name;
#参数 描述
#column_name 必需。要格式化的字段。
#format 必需。规定格式。
TRUNCATE TABLE table_name
删除表中的数据(只是删除数据)
2.mysql手册学习补充
1.基础
mysql>#查看版本和当前日期
mysql>select version(),current_day;
mysql>select version;select now();select user();
1.1.创建数据库/表等
mysql>show databasses;
mysql>create database dbName;
mysql>use dbName;
mysql>show tables;
mysql>create table pet (name varchar(20),owner varchar(20),sex char(10),birth DATE);
mysql>show tables;
mysql>describe pet
mysql>#加载本地问价到mysql中
mysql>load data local infile '/path/pet.txt' into table pet lines terminated by '\r\n';
mysql>insert into pet values('puffball','diane','f','1999-03-30');
1.2.从表检索信息
mysql>select * from pet;
mysql>delete from pet;#只删除元组数据
mysql>drop from pet;#会删除表关系
mysql>update pet set brith='1989-08-31' where name='bowser';
日期计算
要想确定每个宠物有多大,可以计算当前日期的年和出生日期之间的差。如果当前日期的日历年比出生日期早,则减去一年。以下查询显示了每个宠物的出生日期、当前日期和年龄数值的年数字。
select name,birth,curdate(),
(year(curdate())-year(brith)-(right(curdate())<right(birth)) as age
from pet
order by name;
#year()提取日期的年份;
#right()在这里提起日期的后5位进行比较,比较的结果为0(false),1(true)
+----------+------------+------------+------+
| name | birth | CURDATE() | age |
+----------+------------+------------+------+
| Bowser | 1989-08-31 | 2003-08-19 | 13 |
| Buffy | 1989-05-13 | 2003-08-19 | 14 |
| Chirpy | 1998-09-11 | 2003-08-19 | 4 |
| Claws | 1994-03-17 | 2003-08-19 | 9 |
| Fang | 1990-08-27 | 2003-08-19 | 12 |
| Fluffy | 1993-02-04 | 2003-08-19 | 10 |
| Puffball | 1999-03-30 | 2003-08-19 | 4 |
| Slim | 1996-04-29 | 2003-08-19 | 7 |
| Whistler | 1997-12-09 | 2003-08-19 | 5 |
+----------+------------+------------+------+
提起时间函数
YEAR( )
MONTH( )
DAYOFMONTH( )
QUARTER(date) :季度
MONTHNAME(date) :返回date是几月(按英文名返回),如February
DAYNAME(date) :返回date是星期几(按英文名返回),如Thursday
找出下个月生日的动物.如果当前月份是12月,就有点复杂了
select name,brith from pet
where month(brith)=month(date_add(month(curdate(),interval 1 month));
#另一个方法是加1以得出当前月份的下一个月(在使用取模函数(MOD)后,如果月份当前值是12,则“回滚”到值0):
#MONTH返回在1和12之间的一个数字,MOD(something,12)返回在0和11之间的一个数字,因此必须在MOD( )以后加1
select name,brith from pet
where month(birth)=mod(month(curdate()),12) +1;
模式匹配
%:匹配任意数目字符,包括领字符;
_:匹配任何单一字符;
MySQL提供的模式匹配的其它类型是使用扩展正则表达式。当你对这类模式进行匹配测试时,使用REGEXP和NOT REGEXP操作符(或RLIKE和NOT RLIKE,它们是同义词)。
‘.’匹配任何单个的字符。
“[...]”匹配在方括号内的任何字符;例如,“[abc]”匹配“a”、“b”或“c”。为了命名字符的范围,使用一个“-”。“[a-z]”匹配任何字母,而“[0-9]”匹配任何数字;
“ * ”匹配零个或多个在它前面的字符。例如,“x*”匹配任何数量的“x”字符,“[0-9]*”匹配任何数量的数字,而“.*”匹配任何数量的任何字符;
#不区分大小写的查找以“b”开头的名字,使用“^”匹配名字的开始:
select * from pet where name regexp '^b';
#区分大小写的查找以b开头的名字
SELECT * FROM pet WHERE name REGEXP BINARY '^b';
#查找以fy结尾的名字
SELECT * FROM pet WHERE name REGEXP 'fy$';
#找出包含一个“w”的名字,使用以下查询:
select * from pet where name regexp 'w';
#为了找出包含正好5个字符的名字,使用“^”和“$”匹配名字的开始和结尾,和5个“.”实例在两者之间:
SELECT * FROM pet WHERE name REGEXP '^.{5}$';
2.获取数据库和表信息
#查看当前使用数据库
select database();
#查看表
show tables;
#查看表结构
describe table_name;
#查看表的索引信息
show index from table_name;
3.批处理模式下使用SQL
#批处理基本语句
shell> mysql < batch-file
#Windows下运行mysql,并且文件中有一些可以造成问题的特殊字符,可以这样操作:
C:\> mysql -e "source batch-file"
#命令行上指定连接参数,命令应为 h:主机ip
shell> mysql -h host -u user -p < batch-file
shell> Enter password: ********
#如果你有一个产生多个输出的查询,你可以通过一个分页器而不是盯着它翻屏到屏幕的顶端来运行输出:
mysql < batch-file | more
#你可以捕捉文件中的输出以便进行进一步的处理:
mysql < batch-file > mysql.out
#如果你想要在批模式中得到交互输出格式,使用mysql -t。为了回显以输出被执行的命令,使用mysql -vvv
#你还可以使用源代码或 \.命令从mysql提示符运行脚本:
mysql> source path/filename.sql;
mysql> \. path/filename.sql;
4.常用例子
任务:找出最贵物品的编号、销售商和价格
SELECT article, dealer, price
FROM shop
WHERE price=(SELECT MAX(price) FROM shop);
#或者
SELECT article, dealer, price
FROM shop
ORDER BY price DESC
LIMIT 1;
#注:如果有多项最贵的物品( 例如每个的价格为19.95),LIMIT解决方案仅仅显示其中一个!
任务:每项物品的的最高价格是多少?
SELECT article, MAX(price) AS price
FROM shop
GROUP BY article
任务:对每项物品,找出最贵价格的物品的经销商。
SELECT article, dealer, price
FROM shop s1
WHERE price=(SELECT MAX(s2.price)
FROM shop s2
WHERE s1.article = s2.article);
使用用户变量
例如,要找出价格最高或最低的物品的,其方法是:
mysql>select @min_price := min(price),@max_price := max(price);
mysql>select * from shop where price = @min_price or price = @max_price;
3.sql优化
1.数据类型及尺寸优化
MySQL能更高效地在声明具有相同类型和尺寸的列上使用索引;
如把两个varchar类型的索引长度均设为20;
2.Analyze Table table_name:
MySQL 的Optimizer(优化元件)在优化SQL语句时,首先需要收集一些相关信息,其中就包括表的cardinality(可以翻译为“散列程度”),它表示某个索引对应的列包含多少个不同的值——如果cardinality大大少于数据的实际散列程度,那么索引就基本失效了。
我们可以使用SHOW INDEX语句来查看索引的散列程度
SHOW INDEX FROM PLAYERS;
mysql> show index from t_user_message\G;
*************************** 1. row ***************************
Table: t_user_message
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 15
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec);
这个时候就可以使用Analyze Table语句修复索引:
analyze table players;
再次show index from players;
*************************** 1. row ***************************
Table: t_user_message
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 1000
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec);
#需要注意的是,如果开启了binlog,那么Analyze Table的结果也会写入binlog,我们可以在analyze和table之间添加关键字local取消写入。
Optimize Table
经常更新数据的磁盘需要整理碎片,数据库也是这样,Optimize Table语句对MyISAM和InnoDB类型的表都有效。
如果表经常更新,就应当定期运行Optimize Table语句,保证效率。
与Analyze Table一样,Optimize Table也可以使用local来取消写入binlog。!
3.估计查询性能
在大多数情况下,可以通过计算磁盘搜索来估计性能。对小的表,通常能在1次磁盘搜索中找到行(因为索引可能被缓存)。对更大的表,可以使用B-树索引进行估计,将需要log(row_count)/log(index_block_length/3 * 2/(index_length + data_pointer_length))+1次搜索才能找到行。
在MySQL中,索引块通常是1024个字节,数据指针通常是4个字节,这对于有一个长度为3(中等整数)的索引的500,000行的表,通过公式可以计算出log(500,000)/log(1024/3*2/(3+4))+1= 4次搜索。
上面的索引需要大约500,000 * 7 * 3/2 = 5.2MB,(假设典型情况下索引缓存区填充率为2/3),可以将大部分索引保存在内存中,仅需要1-2调用从OS读数据来找出行。
然而对于写,将需要4次搜索请求(如上)来找到在哪儿存放新索引,并且通常需要2次搜索来更新这个索引并且写入行。
注意,上述讨论并不意味着应用程序的性能将缓慢地以logN 退化!当表格变得更大时,所有内容缓存到OS或SQL服务器后,将仅仅或多或少地更慢。在数据变得太大不能缓存后,将逐渐变得更慢,直到应用程序只能进行磁盘搜索(以logN增加)。为了避免这个问题,随数据增加而增加 键高速缓冲区大小。对于MyISAM表, 由key_buffer_size系统变量控制 键高速缓冲区大小。
4.索引合并优化
4.1.索引合并交集
4.2.索引合并并集
4.3.索引合并排序并集
索引合并方法用于通过range扫描搜索行并将结果合成一个。合并会产生并集、交集或者正在进行的扫描的交集的并集。
在EXPLAIN输出中,该方法表现为type列内的index_merge。在这种情况下,key列包含一列使用的索引,key_len包含这些索引的最长的关键元素。
注释:索引合并优化算法具有以下几个已知缺陷:
` 如果可以对某些关键字进行范围扫描,则不考虑索引合并。例如,下面的查询:
SELECT * FROM t1 WHERE (goodkey1 < 10 OR goodkey2 < 20) AND badkey < 30;
对于该查询,可以有两个方案:
1. 使用(goodkey1 < 10 OR goodkey2 < 20)条件进行索引合并扫描。
2. 使用badkey < 30条件进行范围扫描。
然而,优化器只考虑第2个方案。如果这不是你想要的,你可以通过使用IGNORE INDEX或FORCE INDEX让优化器考虑index_merge。下面的查询使用索引合并执行:
SELECT * FROM t1 FORCE INDEX(goodkey1,goodkey2)
WHERE (goodkey1 < 10 OR goodkey2 < 20) AND badkey < 30
SELECT * FROM t1 IGNORE INDEX(badkey)
WHERE (goodkey1 < 10 OR goodkey2 < 20) AND badkey < 30;
5.order by索引优化
在某些情况下,MySQL不能使用索引来解决ORDER BY,尽管它仍然使用索引来找到匹配WHERE子句的行。这些情况包括:
·对不同的关键字使用ORDER BY:
· SELECT * FROM t1 ORDER BY key1, key2;
·对关键字的非连续元素使用ORDER BY:
· SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2;
·混合ASC和DESC:
· SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
·用于查询行的关键字与ORDER BY中所使用的不相同:
· SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
·你正联接许多表,并且ORDER BY中的列并不是全部来自第1个用于搜索行的非常量表。(这是EXPLAIN输出中的没有 const联接类型的第1个表)。
·有不同的ORDER BY和GROUP BY表达式。
·使用的表索引的类型不能按顺序保存行。例如,对于HEAP表的HASH索引情况即如此。
·使用的表索引的类型不能按顺序保存行。例如,对于HEAP表的HASH索引情况即如此。
文件排序优化不仅用于记录排序关键字和行的位置,并且还记录查询需要的列。这样可以避免两次读取行。文件排序算法的工作象这样:
1.读行匹配WHERE子句的行,如前面所示。
2.对于每个行,记录构成排序关键字和行位置的一系列值,并且记录查询需要的列。
3.根据排序关键字排序元组
4.按排序的顺序检索行,但直接从排序的元组读取需要的列,而不是再一次访问表。
如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。如果不能,可以尝试下面的策略:
·增加sort_buffer_size变量的大小。
·增加read_rnd_buffer_size变量的大小。
默认情况下,MySQL排序所有GROUP BY col1,col2,...查询的方法如同在查询中指定ORDER BY col1,col2,...。如果显式包括一个包含相同的列的ORDER BY子句,MySQL可以毫不减速地对它进行优化,尽管仍然进行排序。如果查询包括GROUP BY但你想要避免排序结果的消耗,你可以指定ORDER BY NULL禁止排序。例如:
INSERT INTO foo
SELECT a, COUNT(*) FROM bar GROUP BY a ORDER BY NULL
6.GROUP BY优化
6.1.松散索引扫面
6.2.紧凑索引扫描
7.如何避免表扫描
EXPLAIN的输出显示了当MySQL使用表扫描来解决查询时使用的所有类型列。这通常在如下条件下发生:
·表很小,扫描表比查找关键字速度快。这对于少于10行并且行较短的表比较普遍。
·在ON或WHERE子句中没有适用的索引列的约束。
·正用常量值比较索引列,并且MySQL已经计算到(基于索引树)常数覆盖了表的很大部分并且表扫描将会比较快。参见7.2.4节,“MySQL怎样优化WHERE子句”。
·你正通过另一个列使用一个低的集的势的关键字(许多行匹配关键字)。在这种情况下,MySQL假设通过使用关键字 它可能会进行许多关键字查找,表扫描将会更快。
对于小表,表扫描通常合适。对于大表,尝试下面的技巧以避免优化器错选了表扫描:
·使用ANALYZE TABLE tbl_name为扫描的表更新关键字分布。参见13.5.2.1节,“ANALYZE TABLE语法”。
·对扫描的表使用FORCE INDEX告知MySQL,相对于使用给定的索引表扫描将非常耗时。参见13.2.7节,“SELECT语法”。
·SELECT * FROM t1, t2 FORCE INDEX (index_for_column)
·WHERE t1.col_name=t2.col_name;
·用--max-seeks-for-key=1000选项启动mysqld或使用SET max_seeks_for_key=1000告知优化器假设关键字扫描不会超过1,000次关键字搜索。参见5.3.3节,“服务器系统变量”。
4.存储过程
mysql> delimiter //
mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
-> BEGIN
-> SELECT COUNT(*) INTO param1 FROM t;
-> END
-> //
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
mysql> CALL simpleproc(@a);
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @a;
+------+
| @a |
+------+
| 3 |
+------+
1 row in set (0.00 sec)
当使用delimiter命令时,你应该避免使用反斜杠(‘\’)字符,因为那是MySQL的转义字符。
下列是一个例子,一个采用参数的函数使用一个SQL函数执行一个操作,并返回结果:
mysql> delimiter //
mysql> CREATE FUNCTION hello (s CHAR(20)) RETURNS CHAR(50)
-> RETURN CONCAT('Hello, ',s,'!');
-> //
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
mysql> SELECT hello('world');
+----------------+
| hello('world') |
+----------------+
| Hello, world! |
+----------------+
1 row in set (0.00 sec)
SHOW PROCEDURE STATUS和SHOW FUNCTION STATUS
SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']
这个语句是一个MySQL的扩展。它返回子程序的特征,如数据库,名字,类型,创建者及创建和修改日期。如果没有指定样式,根据你使用的语句,所有存储程序和所有存储函数的信息都被列出。
SHOW FUNCTION STATUS LIKE 'hello'\G
存储过程语法
1.CALL语句
2.BEGIN ... END复合语句;
3.DECLARE语句
4.存储程序中的变量
4.1.DECLARE局部变量:DECLARE var_name[,...] type [DEFAULT value];
4.2.变量SET语句:SET var_name = expr [, var_name = expr] ...
4.3.SELECT ... INTO语句:SELECT col_name[,...] INTO var_name[,...] table_expr
如:SELECT id,data INTO x,y FROM test.t1 LIMIT 1;
重要: SQL变量名不能和列名一样。如果SELECT ... INTO这样的SQL语句包含一个对列的参考,并包含一个与列相同名字的局部变量,MySQL当前把参考解释为一个变量的名字。
5.条件和处理程序
5.1. DECLARE条件
5.2. DECLARE处理程序
6.光标
6.1.声明光标:DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
6.2. 光标OPEN语句: OPEN cur1;
6.3. 光标FETCH语句:FETCH cur1 INTO a, b;
6.4. 光标CLOSE语句: CLOSE cur1;
CREATE PROCEDURE curdemo()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE a CHAR(16);
DECLARE b,c INT;
DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN cur1;
OPEN cur2;
REPEAT
FETCH cur1 INTO a, b;
FETCH cur2 INTO c;
IF NOT done THEN
IF b < c THEN
INSERT INTO test.t3 VALUES (a,b);
ELSE
INSERT INTO test.t3 VALUES (a,c);
END IF;
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
CLOSE cur2;
END
7.流程控制构造
7.1. IF语句
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF
7.2. CASE语句
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
Or: 或者:
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
7.3. LOOP语句
[begin_label:] LOOP
statement_list
END LOOP [end_label]
7.4. LEAVE语句
LEAVE label
7.5. ITERATE语句
ITERATE只可以出现在LOOP, REPEAT, 和WHILE语句内。ITERATE意思为:“再次循环。”
7.6. REPEAT语句
[begin_label:] REPEAT
statement_list
UNTIL search_condition
END REPEAT [end_label]
7.7. WHILE语句
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
网友评论