1 创建数据库并设置默认字符集编码、默认校对规则
create database mydb default character set utf8 default collate utf8_general_ci;
create database testdb default character set utf8mb4 default collate utf8mb4_unicode_ci;
2 创建表
CREATE TABLE table_name(
id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(60) NOT NULL,
score TINYINT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 设置表的存储引擎,一般常用InnoDB和MyISAM;InnoDB可靠,支持事务;MyISAM高效不支持全文检索
eg.
create table if not exists user (
id bigint unsigned not null auto_increment,
username varchar(50) not null,
password varchar(50),
name varchar(50),
primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
3 插入(多条)数据
INSERT INTO user(USERNAME,PASSWORD,NAME)
VALUES('zhangsan','111111','张三',
('lisi','222222','李四'),('wangwu','333333','王五'),
('zhaoliu','444444','赵六'),('tianqi','555555','田七');
4 准备测试数据
create database `testdb` character set utf8 collate utf8_general_ci;
use testdb;
create table A(
A_ID int primary key auto_increment,
A_NAME varchar(20) not null,
PROD_DATE date
);
insert into A values(1,'apple','2020-01-02');
insert into A values(2,'orange','2020-01-05');
insert into A values(3,'banana','2020-02-01');
create table B(
A_ID int primary key auto_increment,
B_PRICE double
);
insert into B values(1,2.30);
insert into B values(2,3.50);
insert into B values(4,null);
4 是否区分大小写
linux系统中,mysql的表的名称区分大小写,关键字、字段名称、字段的值不区分大小写。
select * from A; -- 正确
select * from a; -- ERROR 1146 (42S02): Table 'testdb.a' doesn't exist
select A_id, MAx(a_NaMe) from A GRouP bY a_ID; -- 正确
5 注释必须空格
linux中,注释 --和注释文字中间,必须空一个空格以上,否则报语法错误!
6 零散小知识点
SHOW STATUS; -- 服务器状态
SHOW VARIABLES; -- 服务器配置变量
show databases;
use testdb;
show tables;
create table name (…) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 设置表编码
CREATE TABLE tb_name2 SELECT * FROM tb_name -- 复制表
CREATE TABLE tb_names SELECT id,name FROM tb_name; -- 部分复制
CREATE TEMPORARY TABLE tb_name; -- 创建临时表
-- 临时表:客户端与服务器会话中使用处理特定事务,节省空间、私密性
DESCRIBE | DESC tb_name; 或者 SHOW COLUMNS FROM tb_name; -- 查看表结构
show create table pet; -- 校验创建表语句是否和执行的一致
DROP [ TEMPORARY ] TABLE [ IF EXISTS ] tb_name[ ,tb_name2…….]; -- 删除表
[inner] join -- 内连接,inner/outer可省略,下同
left [outer] join -- 左外连接
right [outer] join -- 右外连接
full [outer] join -- 全连接,mysql不支持
7 sql语句写了一半,又不想执行,可以在语句末尾加上'c'
8 表中导入数据
在表中导入数据的方式有两种:
第一种:将数据整理成SQL语句,insert into A ....
第二种:通过加载文件的方式将数据导入到表中,步骤如下:
- 创建文件 A.txt(注:每个字段中用tab键隔开,字段没有值的记录用N代替)
1 apple
2 orange
3 N
- 加载数据
mysql> load data local infile '/root/data/A.txt' into table A;
Query OK, 8 rows affected, 6 warnings (0.06 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 3
- 校验是否加载进去
mysql> select *from A;
9 备份(导出)和恢复(导入)数据
9.1 备份命令
在mysql的安装目录的bin目录下有mysqldump命令,可以完成对数据库的备份。
-
语法
mysqldump --default-character-set=utf8 -u用户名 -p密码 数据库名 -d --add-drop-table > 导出文件名.sql -
参数说明
- --host=host_name, -h host_name:备份主机名,默认为localhost;
- --default-character-set=utf8 指定导出数据库的字符集编码;
- --port=port_num, -P port_num:制定TCP/IP连接时的端口号;
- --user=user_name, -u user_name:用户名;
- --password[=password], -p[password]:密码;
- --all-databases, -A:备份所有数据库;
- --databases, -B:用于备份多个数据库,如果没有该选项,mysqldump把第一个名字参数作为数据库名,后面的作为表名;使用该选项,mysqldump把每个名字都当作为数据库名;
注:如果加上-B参数,则导出的.sql备份文件中,会有create database testdb
命令,下次如果用该备份文件导入时,不需要事先创建testdb数据库,导入命令中也不需要指定数据库名称testdb
(即,可以写成mysql -uroot -proot < 备份文件.sql
) - --tables:覆盖--databases (-B)参数,指定-B参数指定的数据库中,需要导出的表名,且只能针对一个数据库进行导出(即 -B参数后只能写一个数据库名);
- --no-data, -d:只导出表结构;
- --force, -f:即使发现sql错误,仍然继续备份;
- --add-drop-table --add-drop-table 在每个create语句之前增加一个drop table;
- --quick, -q:快速导出;
- -l, --lock-tables Lock all tables for read. (Defaults to on; use --skip-lock-tables to disable.)
- --xml, -X:导出为xml文件
-
注意
- 由于mysqldump命令不是sql命令,需要在操作系统命令行下使用。
- 密码可以省略,如果省略,则程序会提示输入密码。
- mysqldump 命令路径是根据你 MySQL 安装路径决定的,不过一般在任意路径下都可以使用该命令。
- 在备份数据的时候,数据库不会被删除,可以手动删除数据库;同时在恢复数据的时候,不会自动的给我们创建数据库,仅仅只会恢复数据库中的表和表中的数据,所以恢复数据库前,需要先手动创建数据库。
-
举例
mysqldump -uroot -p123456 menagerie >/root/data/menagerie.sql
# 备份多个表的数据和结构(数据,结构的单独备份方法与上同)
mysqldump -uroot -p123456 mydb t1 t2 > f:multables.sql
# 或者这样写
mysqldump -uroot -p123456 -B mydb --tables t1 t2 > f:multables.sql
9.2 恢复命令
9.2.1 方法一:操作系统命令行方法(mysql)
-
语法
mysql --default-character-set=utf8 -u用户名 -p密码 数据库名 < 导出文件名.sql -
参数说明
- --default-character-set=utf8 指定导出数据库文件的字符集编码
- 注意
- 如果备份文件.sql中,没有
create database
语句,则需要先登录到 mysql 中,并创建一个空的数据库! - 密码可以省略,如果省略,则程序会提示输入密码;
- 注意你备份的 sql 文件路径。
- 举例
# 1.还原全部数据库
mysql -uroot -p123456 < F:all.sql
mysql --default-character-set=utf8 -uroot -proot hive < /root/data/hive0626.sql
# 2.还原单个数据库(需指定数据库)
mysql -uroot -p123456 mydb < F:mydb.sql
# 3.还原单个数据库的多个表(需指定数据库)
mysql -uroot -p123456 mydb < f:multables.sql
# 4.还原多个数据库(一个备份文件里有多个数据库的备份,此时不需要指定数据库)
mysql -uroot -p123456 < f:muldbs.sql
9.2.2 方法二:mysql命令行方法(source)
-
语法
mysql --default-character-set=utf8 -u用户名 -p密码 数据库名 < 备份文件名.sql -
参数说明
- --default-character-set=utf8 指定导出数据库文件的字符集编码
- 注意
- 需要先登录到 mysql 中,并创建一个空的数据库!
- 密码可以省略,如果省略,则程序会提示输入密码;
- 注意你备份的 sql 文件路径;
source
命令也是如何在mysql中执行sql文件的语法。
- 举例
mysql> create database abc; # 创建数据库
mysql> use abc; # 使用已创建的数据库
mysql> set names utf8; # 设置编码
-- 1.还原全部数据库:
mysql>source f:all.sql
-- 2.还原单个数据库(需指定数据库)
mysql>use mydb
mysql>source f:mydb.sql
-- 3.还原单个数据库的多个表(需指定数据库)
mysql>use mydb
mysql>source f:multables.sql
-- 4.还原多个数据库(一个备份文件里有多个数据库的备份,此时不需要指定数据库)
mysql命令行:mysql>source f:muldbs.sql
10 日期字段的写法
日期字段的表示不用像oracle一样(DATE'2020-01-02'),可以直接写 '2020-01-02'
SELECT * FROM A WHERE prod_date >= '2020-01-03';
11 mysql函数
MySQL 有很多内置的函数,以下列出了这些函数的说明。
11.1 MySQL字符串函数
函数 | 描述 | 实例 |
---|---|---|
ASCII(s) | 返回字符串 s 的第一个字符的 ASCII 码。 | 返回 CustomerName 字段第一个字母的 ASCII 码:SELECT ASCII(CustomerName) AS NumCodeOfFirstCharFROM Customers; |
CHAR_LENGTH(s) | 返回字符串 s 的字符数 | 返回字符串 study 的字符数SELECT CHAR_LENGTH("study") AS LengthOfString; |
CHARACTER_LENGTH(s) | 返回字符串 s 的字符数 | 返回字符串 study 的字符数SELECT CHARACTER_LENGTH("study") AS LengthOfString; |
CONCAT(s1,s2...sn) | 字符串 s1,s2 等多个字符串合并为一个字符串 | 合并多个字符串SELECT CONCAT("SQL ", "study ", "Gooogle ", "Facebook") AS ConcatenatedString; |
CONCAT_WS(x, s1,s2...sn) | 同 CONCAT(s1,s2,...) 函数,但是每个字符串直接要加上 x,x 可以是分隔符 | 合并多个字符串,并添加分隔符:SELECT CONCAT_WS("-", "SQL", "Tutorial", "is", "fun!")AS ConcatenatedString; |
FIELD(s,s1,s2...) | 返回第一个字符串 s 在字符串列表(s1,s2...)中的位置 | 返回字符串 c 在列表值中的位置:SELECT FIELD("c", "a", "b", "c", "d", "e"); |
FIND_IN_SET(s1,s2) | 返回在字符串s2中与s1匹配的字符串的位置 | 返回字符串 c 在指定字符串中的位置:SELECT FIND_IN_SET("c", "a,b,c,d,e"); |
FORMAT(x,n) | 函数可以将数字 x 进行格式化 "#,###.##", 将 x 保留到小数点后 n 位,最后一位四舍五入。 | 格式化数字 "#,###.##" 形式:SELECT FORMAT(250500.5634, 2); -- 输出 250,500.56 |
INSERT(s1,x,len,s2) | 字符串 s2 替换 s1 的 x 位置开始长度为 len 的字符串 | 从字符串第一个位置开始的 6 个字符替换为 study:SELECT INSERT("google.com", 1, 6, "runnob"); -- 输出:runnob.com |
INSTR(str,substr) | 从字符串 str 中获取 substr 的开始位置 | 获取 b 在字符串 abc 中的位置:SELECT INSTR('abc','b') -- 2 |
LOCATE(substr,str) | 从字符串 str 中获取 substr 的开始位置 | 返回字符串 abc 中 b 的位置:SELECT LOCATE('b', 'abc') -- 2 |
POSITION(s1 IN s) | 从字符串 s 中获取 s1 的开始位置 | 返回字符串 abc 中 b 的位置:SELECT POSITION('b' in 'abc') -- 2 |
LCASE(s) | 将字符串 s 的所有字母变成小写字母 | 字符串 study 转换为小写:SELECT LOWER('study') -- study |
LOWER(s) | 将字符串 s 的所有字母变成小写字母 | 字符串 study 转换为小写:SELECT LOWER('study') -- study |
UCASE(s) | 将字符串转换为大写 | 将字符串 study 转换为大写:SELECT UCASE("study"); -- ITCAST |
UPPER(s) | 将字符串转换为大写 | 将字符串 study 转换为大写:SELECT UPPER("study"); -- ITCAST |
LPAD(s1,len,s2) | 在字符串 s1 的开始处填充字符串 s2,使字符串长度达到 len | 将字符串 xx 填充到 abc 字符串的开始处:SELECT LPAD('abc',5,'xx') -- xxabc |
LTRIM(s) | 去掉字符串 s 开始处的空格 | 去掉字符串 study开始处的空格:SELECT LTRIM(" study") AS LeftTrimmedString;-- study |
RTRIM(s) | 去掉字符串 s 结尾处的空格 | 去掉字符串 study 的末尾空格:SELECT RTRIM("study ") AS RightTrimmedString; -- study |
TRIM(s) | 去掉字符串 s 开始和结尾处的空格 | 去掉字符串 study 的首尾空格:SELECT TRIM(' study ') AS TrimmedString; |
MID(s,n,len) | 从字符串 s 的 start 位置截取长度为 length 的子字符串,同 SUBSTRING(s,n,len) | 从字符串 study 中的第 2 个位置截取 3个 字符:SELECT MID("study", 2, 3) AS ExtractString; -- tca |
REPEAT(s,n) | 将字符串 s 重复 n 次 | 将字符串 study 重复三次:SELECT REPEAT('study',3) -- study |
REPLACE(s,s1,s2) | 将字符串 s2 替代字符串 s 中的字符串 s1 | 将字符串 abc 中的字符 a 替换为字符 x:SELECT REPLACE('abc','a','x') --xbc |
REVERSE(s) | 将字符串s的顺序反过来 | 将字符串 abc 的顺序反过来:SELECT REVERSE('abc') -- cba |
LEFT(s,n) | 返回字符串 s 的前 n 个字符 | 返回字符串 study 中的前两个字符:SELECT LEFT('study',2) -- it |
RIGHT(s,n) | 返回字符串 s 的后 n 个字符 | 返回字符串 study 的后两个字符:SELECT RIGHT('study',2) -- st |
RPAD(s1,len,s2) | 在字符串 s1 的结尾处添加字符串 s1,使字符串的长度达到 len | 将字符串 xx 填充到 abc 字符串的结尾处:SELECT RPAD('abc',5,'xx') -- abcxx |
SPACE(n) | 返回 n 个空格 | 返回 10 个空格:SELECT SPACE(10); |
STRCMP(s1,s2) | 比较字符串 s1 和 s2,如果 s1 与 s2 相等返回 0 ,如果 s1>s2 返回 1,如果 s1<s2 返回 -1 | 比较字符串:SELECT STRCMP("study", "study"); -- 0 |
SUBSTR(s, start, length) | 从字符串 s 的 start 位置截取长度为 length 的子字符串 | 从字符串 study 中的第 2 个位置截取 3个 字符:SELECT SUBSTR("study", 2, 3) AS ExtractString; -- tca |
SUBSTRING(s, start, length) | 从字符串 s 的 start 位置截取长度为 length 的子字符串 | 从字符串 study 中的第 2 个位置截取 3个 字符:SELECT SUBSTRING("study", 2, 3) AS ExtractString; -- tca |
SUBSTRING_INDEX(s, delimiter, number) | 返回从字符串 s 的第 number 个出现的分隔符 delimiter 之后的子串。如果 number 是正数,返回第 number 个字符左边的字符串。如果 number 是负数,返回第(number 的绝对值(从右边数))个字符右边的字符串。 | SELECT SUBSTRING_INDEX('a*b','*',1) -- aSELECT SUBSTRING_INDEX('a*b','*',-1) -- bSELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a*b*c*d*e','*',3),'*',-1) -- c |
11.2 MySQL 数字函数
函数名 | 描述 | 实例 |
---|---|---|
ABS(x) | 返回 x 的绝对值 | 返回 -1 的绝对值:SELECT ABS(-1) -- 返回1 |
ACOS(x) | 求 x 的反余弦值(参数是弧度) | SELECT ACOS(0.25); |
ASIN(x) | 求反正弦值(参数是弧度) | SELECT ASIN(0.25); |
ATAN(x) | 求反正切值(参数是弧度) | SELECT ATAN(2.5); |
ATAN2(n, m) | 求反正切值(参数是弧度) | SELECT ATAN2(-0.8, 2); |
AVG(expression) | 返回一个表达式的平均值,expression 是一个字段 | 返回 Products 表中Price 字段的平均值:SELECT AVG(Price) AS AveragePrice FROM Products; |
CEIL(x) | 返回大于或等于 x 的最小整数 | SELECT CEIL(1.5) -- 返回2 |
CEILING(x) | 返回大于或等于 x 的最小整数 | SELECT CEIL(1.5) -- 返回2 |
COS(x) | 求余弦值(参数是弧度) | SELECT COS(2); |
COT(x) | 求余切值(参数是弧度) | SELECT COT(6); |
COUNT(expression) | 返回查询的记录总数,expression 参数是一个字段或者 * 号 | 返回 Products 表中 products 字段总共有多少条记录:SELECT COUNT(ProductID) AS NumberOfProducts FROM Products; |
DEGREES(x) | 将弧度转换为角度 | SELECT DEGREES(3.1415926535898) -- 180 |
n DIV m | 整除,n 为被除数,m 为除数 | 计算 10 除于 5:SELECT 10 DIV 5; -- 2 |
EXP(x) | 返回 e 的 x 次方 | 计算 e 的三次方:SELECT EXP(3) -- 20.085536923188 |
FLOOR(x) | 返回小于或等于 x 的最大整数 | 小于或等于 1.5 的整数:SELECT FLOOR(1.5) -- 返回1 |
GREATEST(expr1, expr2, expr3, ...) | 返回列表中的最大值 | 返回以下数字列表中的最大值:SELECT GREATEST(3, 12, 34, 8, 25); -- 34 返回以下字符串列表中的最大值:SELECT GREATEST("Google", "study", "Apple"); -- study |
LEAST(expr1, expr2, expr3, ...) | 返回列表中的最小值 | 返回以下数字列表中的最小值:SELECT LEAST(3, 12, 34, 8, 25); -- 3 返回以下字符串列表中的最小值:SELECT LEAST("Google", "study", "Apple"); -- Apple |
LN | 返回数字的自然对数 | 返回 2 的自然对数:SELECT LN(2); -- 0.6931471805599453 |
LOG(x) | 返回自然对数(以 e 为底的对数) | SELECT LOG(20.085536923188) -- 3 |
LOG10(x) | 返回以 10 为底的对数 | SELECT LOG10(100) -- 2 |
LOG2(x) | 返回以 2 为底的对数 | 返回以 2 为底 6 的对数:SELECT LOG2(6); -- 2.584962500721156 |
MAX(expression) | 返回字段 expression 中的最大值 | 返回数据表 Products 中字段 Price 的最大值:SELECT MAX(Price) AS LargestPrice FROM Products; |
MIN(expression) | 返回字段 expression 中的最小值 | 返回数据表 Products 中字段 Price 的最小值:SELECT MIN(Price) AS LargestPrice FROM Products; |
MOD(x,y) | 返回 x 除以 y 以后的余数 | 5 除于 2 的余数:SELECT MOD(5,2) -- 1 |
PI() | 返回圆周率(3.141593) | SELECT PI() --3.141593 |
POW(x,y) | 返回 x 的 y 次方 | 2 的 3 次方:SELECT POW(2,3) -- 8 |
POWER(x,y) | 返回 x 的 y 次方 | 2 的 3 次方:SELECT POWER(2,3) -- 8 |
RADIANS(x) | 将角度转换为弧度 | 180 度转换为弧度:SELECT RADIANS(180) -- 3.1415926535898 |
RAND() | 返回 0 到 1 的随机数 | SELECT RAND() --0.93099315644334 |
ROUND(x) | 返回离 x 最近的整数,其实就是round(x,0),也就是默认d为0。 | SELECT ROUND(1.23456) -- 1 |
ROUND(x,d) | x指要处理的数,d是指保留几位小数。d可以是负数,这时是指定小数点左边的d位整数位为0,同时小数位均为0。 | select round(1123.26723,2); -- 1123.27 |
SIGN(x) | 返回 x 的符号,x 是负数、0、正数分别返回 -1、0 和 1 | SELECT SIGN(-10) -- (-1) |
SIN(x) | 求正弦值(参数是弧度) | SELECT SIN(RADIANS(30)) -- 0.5 |
SQRT(x) | 返回x的平方根 | 25 的平方根:SELECT SQRT(25) -- 5 |
SUM(expression) | 返回指定字段的总和 | 计算 OrderDetails 表中字段 Quantity 的总和:SELECT SUM(Quantity) AS TotalItemsOrdered FROM OrderDetails; |
TAN(x) | 求正切值(参数是弧度) | SELECT TAN(1.75); -- -5.52037992250933 |
TRUNCATE(x,y) | 返回数值 x 保留到小数点后 y 位的值(与 ROUND 最大的区别是不会进行四舍五入) | SELECT TRUNCATE(1.23456,3) -- 1.234 |
11.3 MySQL 日期函数
函数名 | 描述 | 实例 |
---|---|---|
ADDDATE(d,n) | 计算其实日期 d 加上 n 天的日期 | SELECT ADDDATE("2017-06-15", INTERVAL 10 DAY);->2017-06-25 |
ADDTIME(t,n) | 时间 t 加上 n 秒的时间 | SELECT ADDTIME('2011-11-11 11:11:11', 5)->2011-11-11 11:11:16 (秒) |
CURDATE() | 返回当前日期 | SELECT CURDATE();-> 2018-09-19 |
CURRENT_DATE() | 返回当前日期 | SELECT CURRENT_DATE();-> 2018-09-19 |
CURRENT_TIME | 返回当前时间 | SELECT CURRENT_TIME();-> 19:59:02 |
CURRENT_TIMESTAMP() | 返回当前日期和时间 | SELECT CURRENT_TIMESTAMP()-> 2018-09-19 20:57:43 |
CURTIME() | 返回当前时间 | SELECT CURTIME();-> 19:59:02 |
DATE() | 从日期或日期时间表达式中提取日期值 | SELECT DATE("2017-06-15"); -> 2017-06-15 |
DATEDIFF(d1,d2) | 计算日期 d1->d2 之间相隔的天数 | SELECT DATEDIFF('2001-01-01','2001-02-02')-> -32 |
DATE_ADD(d,INTERVAL expr type) | 计算起始日期 d 加上一个时间段后的日期 | SELECT ADDDATE('2011-11-11 11:11:11',1)-> 2011-11-12 11:11:11 (默认是天)SELECT ADDDATE('2011-11-11 11:11:11', INTERVAL 5 MINUTE)-> 2011-11-11 11:16:11 (TYPE的取值与上面那个列出来的函数类似) |
DATE_FORMAT(d,f) | 按表达式 f的要求显示日期 d | SELECT DATE_FORMAT('2011-11-11 11:11:11','%Y-%m-%d %r')-> 2011-11-11 11:11:11 AM |
DATE_SUB(date,INTERVAL expr type) | 函数从日期减去指定的时间间隔。 | Orders 表中 OrderDate 字段减去 2 天:SELECT OrderId,DATE_SUB(OrderDate,INTERVAL 2 DAY) AS OrderPayDateFROM Orders |
DAY(d) | 返回日期值 d 的日期部分 | SELECT DAY("2017-06-15"); -> 15 |
DAYNAME(d) | 返回日期 d 是星期几,如 Monday,Tuesday | SELECT DAYNAME('2011-11-11 11:11:11')->Friday |
DAYOFMONTH(d) | 计算日期 d 是本月的第几天 | SELECT DAYOFMONTH('2011-11-11 11:11:11')->11 |
DAYOFWEEK(d) | 日期 d 今天是星期几,1 星期日,2 星期一,以此类推 | SELECT DAYOFWEEK('2011-11-11 11:11:11')->6 |
DAYOFYEAR(d) | 计算日期 d 是本年的第几天 | SELECT DAYOFYEAR('2011-11-11 11:11:11')->315 |
ROM_DAYS(n) | 计算从 0000 年 1 月 1 日开始 n 天后的日期 | SELECT FROM_DAYS(1111)-> 0003-01-16 |
HOUR(t) | 返回 t 中的小时值 | SELECT HOUR('1:2:3')-> 1 |
LAST_DAY(d) | 返回给给定日期的那一月份的最后一天 | SELECT LAST_DAY("2017-06-20");-> 2017-06-30 |
LOCALTIME() | 返回当前日期和时间 | SELECT LOCALTIME()-> 2018-09-19 20:57:43 |
LOCALTIMESTAMP() | 返回当前日期和时间 | SELECT LOCALTIMESTAMP()-> 2018-09-19 20:57:43 |
MAKEDATE(year, day-of-year) | 基于给定参数年份 year 和所在年中的天数序号 day-of-year 返回一个日期 | SELECT MAKEDATE(2017, 3);-> 2017-01-03 |
MAKETIME(hour, minute, second) | 组合时间,参数分别为小时、分钟、秒 | SELECT MAKETIME(11, 35, 4);-> 11:35:04 |
MICROSECOND(date) | 返回日期参数所对应的毫秒数 | SELECT MICROSECOND("2017-06-20 09:34:00.000023");-> 23 |
MINUTE(t) | 返回 t 中的分钟值 | SELECT MINUTE('1:2:3')-> 2 |
MONTHNAME(d) | 返回日期当中的月份名称,如 Janyary | SELECT MONTHNAME('2011-11-11 11:11:11')-> November |
MONTH(d) | 返回日期d中的月份值,1 到 12 | SELECT MONTH('2011-11-11 11:11:11')->11 |
NOW() | 返回当前日期和时间 | SELECT NOW()-> 2018-09-19 20:57:43 |
PERIOD_ADD(period, number) | 为 年-月 组合日期添加一个时段 | SELECT PERIOD_ADD(201703, 5); -> 201708 |
PERIOD_DIFF(period1, period2) | 返回两个时段之间的月份差值 | SELECT PERIOD_DIFF(201710, 201703);-> 7 |
QUARTER(d) | 返回日期d是第几季节,返回 1 到 4 | SELECT QUARTER('2011-11-11 11:11:11')-> 4 |
SECOND(t) | 返回 t 中的秒钟值 | SELECT SECOND('1:2:3')-> 3 |
SEC_TO_TIME(s) | 将以秒为单位的时间 s 转换为时分秒的格式 | SELECT SEC_TO_TIME(4320)-> 01:12:00 |
STR_TO_DATE(string, format_mask) | 将字符串转变为日期 | SELECT STR_TO_DATE("August 10 2017", "%M %d %Y");-> 2017-08-10 |
SUBDATE(d,n) | 日期 d 减去 n 天后的日期 | SELECT SUBDATE('2011-11-11 11:11:11', 1)->2011-11-10 11:11:11 (默认是天) |
SUBTIME(t,n) | 时间 t 减去 n 秒的时间 | SELECT SUBTIME('2011-11-11 11:11:11', 5)->2011-11-11 11:11:06 (秒) |
SYSDATE() | 返回当前日期和时间 | SELECT SYSDATE()-> 2018-09-19 20:57:43 |
TIME(expression) | 提取传入表达式的时间部分 | SELECT TIME("19:30:10");-> 19:30:10 |
TIME_FORMAT(t,f) | 按表达式 f 的要求显示时间 t | SELECT TIME_FORMAT('11:11:11','%r')11:11:11 AM |
TIME_TO_SEC(t) | 将时间 t 转换为秒 | SELECT TIME_TO_SEC('1:12:00')-> 4320 |
TIMEDIFF(time1, time2) | 计算时间差值 | SELECT TIMEDIFF("13:10:11", "13:10:10");-> 00:00:01 |
TIMESTAMP(expression, interval) | 单个参数时,函数返回日期或日期时间表达式;有2个参数时,将参数加和 | SELECT TIMESTAMP("2017-07-23", "13:10:11");-> 2017-07-23 13:10:11 |
TO_DAYS(d) | 计算日期 d 距离 0000 年 1 月 1 日的天数 | SELECT TO_DAYS('0001-01-01 01:01:01')-> 366 |
WEEK(d) | 计算日期 d 是本年的第几个星期,范围是 0 到 53 | SELECT WEEK('2011-11-11 11:11:11')-> 45 |
WEEKDAY(d) | 日期 d 是星期几,0 表示星期一,1 表示星期二 | SELECT WEEKDAY("2017-06-15");-> 3 |
WEEKOFYEAR(d) | 计算日期 d 是本年的第几个星期,范围是 0 到 53 | SELECT WEEKOFYEAR('2011-11-11 11:11:11')-> 45 |
YEAR(d) | 返回年份 | SELECT YEAR("2017-06-15");-> 2017 |
YEARWEEK(date, mode) | 返回年份及第几周(0到53),mode 中 0 表示周天,1表示周一,以此类推 | SELECT YEARWEEK("2017-06-15");-> 201724 |
EXTRACT(type FROM d) | 从日期 d 中获取指定的值,type 指定返回的值。 type可取值为:MICROSECOND,SECOND,MINUTE,HOUR,DAY,WEEK,MONTH,QUARTER,YEAR,SECOND_MICROSECOND,MINUTE_MICROSECOND,MINUTE_SECOND,HOUR_MICROSECOND,HOUR_SECOND,HOUR_MINUTE,DAY_MICROSECOND,DAY_SECOND,DAY_MINUTE,DAY_HOUR,YEAR_MONTH | SELECT EXTRACT(MINUTE FROM '2011-11-11 11:12:11'); -> 12 |
11.4 MySQL 高级函数
函数名 | 描述 | 实例 |
---|---|---|
BIN(x) | 返回 x 的二进制编码 | 15 的 2 进制编码:SELECT BIN(15); -- 1111 |
BINARY(s) | 将字符串 s 转换为二进制字符串 | SELECT BINARY "study";-> study |
CASE expression WHEN condition1 THEN result1 WHEN condition2 THEN result2 ... WHEN conditionN THEN resultN ELSE resultEND |
CASE 表示函数开始,END 表示函数结束。如果 condition1 成立,则返回 result1, 如果 condition2 成立,则返回 result2,当全部不成立则返回 result,而当有一个成立之后,后面的就不执行了。 | SELECT CASE WHEN 1 > 0 THEN '1 > 0' WHEN 2 > 0 THEN '2 > 0' ELSE '3 > 0' END->1 > 0 |
CAST(x AS type) | 转换数据类型 | 字符串日期转换为日期:SELECT CAST("2017-08-29" AS DATE);-> 2017-08-29 |
COALESCE(expr1, expr2, ...., expr_n) | 返回参数中的第一个非空表达式(从左向右) | SELECT COALESCE(NULL, NULL, NULL, 'study.com', NULL, 'google.com');-> study.com |
CONNECTION_ID() | 返回服务器的连接数 | SELECT CONNECTION_ID();-> 4292835 |
CONV(x,f1,f2) | 返回 f1 进制数变成 f2 进制数 | SELECT CONV(15, 10, 2);-> 1111 |
CONVERT(s USING cs) | 函数将字符串 s 的字符集变成 cs | SELECT CHARSET('ABC')->utf-8 SELECT CHARSET(CONVERT('ABC' USING gbk))->gbk |
DATABASE() | 返回当前数据库名 | SELECT DATABASE(); -> study |
IF(expr,v1,v2) | 如果表达式 expr 成立,返回结果 v1;否则,返回结果 v2。 | SELECT IF(1 > 0,'正确','错误') ->正确 |
IFNULL(v1,v2) | 如果 v1 的值不为 NULL,则返回 v1,否则返回 v2。 | SELECT IFNULL(null,'Hello Word')->Hello Word |
ISNULL(expression) | 判断表达式是否为空 | SELECT ISNULL(NULL);->1 |
LAST_INSERT_ID() | 返回最近生成的 AUTO_INCREMENT 值 | SELECT LAST_INSERT_ID();->6 |
NULLIF(expr1, expr2) | 比较两个字符串,如果字符串 expr1 与 expr2 相等 返回 NULL,否则返回 expr1 | SELECT NULLIF(25, 25);-> |
SESSION_USER() | 返回当前用户 | SELECT SESSION_USER();-> guest@% |
SYSTEM_USER() | 返回当前用户 | SELECT SYSTEM_USER();-> guest@% |
CURRENT_USER() | 返回当前用户 | SELECT CURRENT_USER();-> guest@% |
USER() | 返回当前用户 | SELECT USER();-> guest@% |
VERSION() | 返回数据库的版本号 | SELECT VERSION()-> 5.6.34 |
12 MySQL 索引
MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。
索引分单列索引和组合索引。单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。组合索引,即一个索引包含多个列。
创建索引时,你需要确保该索引是应用在SQL查询语句的条件(一般作为 WHERE 子句的条件)。
实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。
上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。
建立索引会占用磁盘空间的索引文件。
12.1 普通索引
12.1.1 创建索引
这是最基本的索引,它没有任何限制。它有以下几种创建方式:
- 直接创建
CREATE INDEX indexName ON mytable(username(length));
-- eg. 创建索引
create index id on B(A_ID);
如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length。
- 修改表结构(添加索引)
ALTER table tableName ADD INDEX indexName(columnName)
- 创建表的时候直接指定
CREATE TABLE mytable(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
INDEX [indexName] (username(length))
);
12.1.2 删除索引的语法
DROP INDEX [indexName] ON mytable;
12.2 唯一索引
它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
它有以下几种创建方式:
- 直接创建
CREATE UNIQUE INDEX indexName ON mytable(username(length))
- 修改表结构
ALTER table mytable ADD UNIQUE [indexName] (username(length))
- 创建表的时候直接指定
CREATE TABLE mytable(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
UNIQUE [indexName] (username(length))
);
12.3 联合索引
-
概念:联合索引又叫复合索引,即一个覆盖表中两列或者以上的索引。
-
特点:
- 最左匹配原则:指的就是如果你的 SQL 语句中用到了联合索引中的最左边的索引,那么这条 SQL 语句就可以利用这个联合索引去进行匹配。
- 当遇到范围查询(>、<、between、like)就会停止匹配。
- where, group by, order by 都可以使用索引,建立索引时,一定要使用前面3个子句中的字段。
-
注意事项
- 只要列中包含有NULL值都将不会被包含在索引中:复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的,所以我们在数据库设计时尽可能不要让字段的默认值为NULL。(亲测,包含null值时也能使用索引,怀疑???)
-
举例
-
如果sql为
SELECT * FROM table WHERE a = 1 and b = 2 and c = 3;
,如何建立索引?
(a,b,c)或者(c,b,a)或者(b,a,c)都可以,重点要的是将区分度高的字段放在前面,区分度低的字段放后面。像性别、状态这种字段区分度就很低,我们一般放后面。
例如假设区分度由大到小为b,a,c。那么我们就对(b,a,c)建立索引。在执行sql的时候,优化器会 帮我们调整where后a,b,c的顺序,让我们用上索引。 -
SELECT * FROM table WHERE a > 1 and b = 2;
,如何建立索引?
对(b,a)建立索引。如果你建立的是(a,b)索引,那么只有a字段能用得上索引,毕竟最左匹配原则遇到范围查询就停止匹配。(注意:范围查询的那一列还是能使用索引!比如这里a > 1
,也使用了索引,之后的列才都无法使用索引。)
如果对(b,a)建立索引那么两个字段都能用上,优化器会帮我们调整where后a,b的顺序,让我们用上索引。 -
SELECT * FROM table WHERE a > 1 and b = 2 and c > 3;
,如何建立索引?
不一定,(b,a)或者(b,c)都可以,要结合具体情况具体分析。
拓展,SELECT * FROM table WHERE a = 1 and b = 2 and c > 3;
,怎么建索引?嗯,大家一定都懂了! -
SELECT * FROM table WHERE a = 1 ORDER BY b;
,如何建立索引?
这还需要想?一看就是对(a,b)建索引,当a = 1的时候,b相对有序,可以避免再次排序!
那么,SELECT * FROM table WHERE a > 1 ORDER BY b;
,如何建立索引?
对(a)建立索引,因为a的值是一个范围,这个范围内b值是无序的,没有必要对(a,b)建立索引。
拓展,SELECT * FROM table WHERE a = 1 AND b = 2 AND c > 3 ORDER BY c;
,怎么建索引? -
SELECT * FROM table WHERE a IN (1,2,3) and b > 1;
,如何建立索引?
还是对(a,b)建立索引,因为IN在这里可以视为等值引用,不会中止索引匹配,所以还是(a,b)!
拓展,SELECT * FROM table WHERE a = 1 AND b IN (1,2,3) AND c > 3 ORDER BY c;
,如何建立索引?此时c排序是用不到索引的。 -
假设某个表有一个联合索引(c1,c2,c3,c4)以下选项哪些字段使用了该索引:
A where c1=x and c2=x and c4>x and c3=x B where c1=x and c2=x and c4=x order by c3 C where c1=x and c4= x group by c3,c2 D where c1=? and c5=? order by c2,c3 E where c1=? and c2=? and c5=? order by c2,c3
下面我们开始:
首先创建表:CREATE TABLE t( c1 CHAR(1) not null, c2 CHAR(1) not null, c3 CHAR(1) not null, c4 CHAR(1) not null, c5 CHAR(1) not null )ENGINE myisam CHARSET UTF8;
有c1到c5 5个字段,特别说明一下 字段类型都是定长char(1)类型,并且非空,字符集是utf8(与计算索引使用字节数有关)
创建索引:alter table t add index c1234(c1,c2,c3,c4);
插入2条数据:insert into t VALUES('1','1','1','1','1',('2','2','2','2','2')
使用MySql Explain开始分析题目结果:
A选项:
结果可以看出,c1,c2,c3,c4均使用到了该索引,而我们对A结果稍作更改,将c2条件去掉后:
根据索引最左原则,c2字段没有使用索引,c2之后的字段都不能使用索引。下面2图我们对比下索引最左原则:
上图结果显示直接使用c3是全表查询,无法使用该索引的,所以c3字段使用索引的前提是c1,c2两字段均使用了索引。
即是索引的最左原则(左前缀原则)。B选项:
key_len长度说明c1,c2字段用到了该索引,Extra显示并没有使用临时表进行排序,说明排序是使用了索引的,但并没有计算在key_len值中,也没有起到连接c4的作用,说明索引到c3这里是断掉的。
排序其实是利用联合索引直接完成了的,即:使用了c1234联合索引,就已经使得c1下c2,c2下c3,c3下c4是有序的了,所以实际是排序利用了索引,c3字段并没有使用该索引。(这段写的时候总感觉有点别扭,不知道我理解的对不对,还有待更深层次的研究)C选项:
使用group by 一般先生成临时文件,再进行排序,但是字段顺序为c2,c3时,并没有用临时表进行排序,而是利用索引排序好的;当group by字段为c3,c2时,由于与索引字段顺序不一致,所以分组和排序并没有利用到索引。
由key_len长度确定,只有c1一个字段使用了索引。D选项:
order by 和group by 类似,字段顺序与索引一致时,会使用索引排序;字段顺序与索引不一致时,不使用索引。
由key_len长度确定,只有c1一个字段使用了索引。E选项:
其实选项E的结果分析在上述ABCD的结果中都分析过了,这里只有c1,c2字段使用了该索引。
综上所述问题答案:
A:四个字段均使用了该索引
B:c1,c2字段使用了该索引
C:c1字段使用该索引
D:c1字段使用该索引
E:c1,c2字段使用了该索引总结:
索引的最左原则(左前缀原则),如(c1,c2,c3,c4....cN)的联合索引,where 条件按照索引建立的字段顺序来使用(不代表and条件必须按照顺序来写),如果中间某列没有条件,或使用like会导致后面的列不能使用索引。
索引也能用于分组和排序,分组要先排序,在计算平均值等等。所以在分组和排序中,如果字段顺序可以按照索引的字段顺序,即可利用索引的有序特性。
参考链接:https://blog.csdn.net/wdjxxl/article/details/79790421
-
12.4 使用ALTER 命令添加和删除索引
有四种方式来添加数据表的索引:
- ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
- ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
- ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。
- ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list): 该语句指定了索引为 FULLTEXT ,用于全文索引。
12.5 显示索引信息
你可以使用 SHOW INDEX 命令来列出表中的相关的索引信息。可以通过在末尾添加 G
来格式化输出信息。
尝试以下实例:
mysql> SHOW INDEX FROM table_name;
mysql> show index from B;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| B | 0 | PRIMARY | 1 | A_ID | A | 3 | NULL | NULL | | BTREE | | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
13 MySQL事务
13.1 概念
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
- 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
- 事务用来管理 DML(insert,update,delete) 语句
13.2 特点
一般来说,事务是必须满足4个条件(ACID):
- 原子性: (Atomicity,或称不可分割性)。一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,在中间某个环节不会结束。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性: (Consistency)。在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
- 隔离性: (Isolation,又称独立性)。数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- 持久性: (Durability)。事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
13.3 MYSQL事务处理命令
-
设置是否自动提交
- SET AUTOCOMMIT=0 禁止自动提交
- SET AUTOCOMMIT=1 开启自动提交
-
手动管理事务
- BEGIN 开始一个事务
- ROLLBACK 事务回滚
- COMMIT 事务确认
14 MySQL执行引擎
对于一个Java开发者来说执行引擎和SQL优化已经是面试必问了。
首先简单了解下MySQL执行引擎,首先MySQL执行引擎分类比较多,InnoDB(重要)、MyIsam(重要)、Memory、Mrg_Myisam、Blackhole等,虽然看着多,不过在日常学习和使用过程中只需要掌握InnoDB和MyIsam即可。下面对比InnoDB和MyISAM的区别:
- InnoDB
- 优点:InnoDB是一个事务型的存储引擎,有行级锁定和外键约束,提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别,设计目标是处理大容量数据库系统;
- 缺点:不支持全文索引,而且它没有保存表的行数,当SELECT COUNT(*) FROM TABLE时需要扫描全表;
- 适用场景:经常更新的表,适合处理多重并发的更新请求,需要事务、外键;
- MyISAM
- 优点:支持全文类型索引,索引和记录分开存储,并存储了表的行数,所以select count(*)效率很高(不加where);
- 缺点:不支持数据库事务,更新操作需要锁定整个表,不支持行级锁和外键;
- 适用场景:经常读取数据的场合,更新操作少;
15 SQL语句优化
那么如何提高数据库SQL语句执行速度呢?有人会说性能调优是数据库管理员(DBA)的事,然而性能调优跟程序员们也有莫大的关系。
-
比较运算符能用 “=”就不用“<>”
“=”增加了索引的使用几率。 -
明知只有一条查询结果,那请使用 “LIMIT 1”
“LIMIT 1”可以避免全表扫描,找到对应结果就不会再继续扫描了。 -
为列选择合适的数据类型
能用TINYINT就不用SMALLINT,能用SMALLINT就不用INT,道理你懂的,磁盘和内存消耗越小越好嘛。 -
将大的DELETE,UPDATE or INSERT 查询变成多个小查询
能写一个几十行、几百行的SQL语句是不是显得逼格很高?然而,为了达到更好的性能以及更好的数据控制,你可以将他们变成多个小查询。 -
使用UNION ALL 代替 UNION,如果结果集允许重复的话
因为 UNION ALL 不去重,效率高于 UNION。 -
为获得相同结果集的多次执行,请保持SQL语句前后一致
这样做的目的是为了充分利用查询缓冲。
比如根据地域和产品id查询产品价格,第一次使用了:
select price from order where id=123456 and region='BEIJING'
那么第二次同样的查询,请保持以上语句的一致性,比如不要将where语句里面的id和region位置调换顺序。 -
尽量避免使用 “SELECT *”
如果不查询表中所有的列,尽量避免使用 SELECT *,它将以磁盘扫描方式取出单条数据的末尾,而字段方式则会直接取到数据项。
(1)SELECT *,需要数据库先 Query Table Metadata For Columns,一定程度上为数据库增加了负担。
但是实际上,两者效率差别不大。
(2)考虑到今后的扩展性。
因为程序里面你需要使用到的列毕竟是确定的, SELECT * 只是减少了一句 SQL String 的长度,并不能减少其他地方的代码。 -
WHERE 子句里面的列尽量被索引
只是“尽量”哦,并不是说所有的列。因地制宜,根据实际情况进行调整,因为有时索引太多也会降低性能。 -
JOIN 子句里面的列尽量被索引
同样只是“尽量”哦,并不是说所有的列。 -
ORDER BY 的列尽量被索引
ORDER BY的列如果被索引,性能也会更好。 -
使用 LIMIT 实现分页逻辑
不仅提高了性能,同时减少了不必要的数据库和应用间的网络传输。 -
使用 EXPLAIN 关键字去查看执行计划
EXPLAIN 可以检查索引使用情况以及扫描的行。
EXPLAIN关键字的参考文档:https://blog.csdn.net/why15732625998/article/details/80388236
16 limit关键字
select * from table_name limit [index, ] length;
limit后面跟2个参数:
- index:索引号,从0开始计算,表示从哪一行开始;
- length:长度,表示要查询的记录条数。
17 求topN
-- 创建表并插入数据
create table tb(name varchar(10),val int,memo varchar(20));
insert into tb values('a', 2, 'a2(a的第二个值)');
insert into tb values('a', 1, 'a1--a的第一个值');
insert into tb values('a', 3, 'a3:a的第三个值');
insert into tb values('b', 1, 'b1--b的第一个值');
insert into tb values('b', 3, 'b3:b的第三个值');
insert into tb values('b', 2, 'b2b2b2b2');
insert into tb values('b', 4, 'b4b4');
insert into tb values('b', 5, 'b5b5b5b5b5');
17.1 求top1
-- 按name分组取val最大的值所在行的数据
--方法1:val=
select a.* from tb a where val = (select max(val) from tb where name = a.name) order by a.name;
--方法2:not exists
select a.* from tb a where not exists(select 1 from tb where name = a.name and val > a.val);
--方法3:from a,b
select a.* from tb a,(select name,max(val) val from tb group by name) b where a.name = b.name and a.val = b.val order by a.name;
--方法4:join
select a.* from tb a inner join (select name , max(val) val from tb group by name) b on a.name = b.name and a.val = b.val order by a.name;
--方法5:
select a.* from tb a where 1 > (select count(*) from tb where name = a.name and val > a.val ) order by a.name;
-- 结果
name val memo
--- ---- --------
a 3 a3:a的第三个值
b 5 b5b5b5b5b5
17.2 求topN
-- 按name分组取最大的两个(N个)val
-- 子查询
select a.* from tb a where 2 > (select count(*) from tb where name = a.name and val > a.val ) order by a.name,a.val;
-- 该方法不行,select top n 是ms sql server的语法,mysql中没有
select a.* from tb a where val in (select top 2 val from tb where name=a.name order by val desc) order by a.name,a.val;
-- exists (注:没有group by也能使用having!)
select a.* from tb a where exists (select count(*) from tb where name = a.name and val > a.val having count(*) < 2) order by a.name;
-- 查询结果
name val memo
-- --- -----------
a 2 a2(a的第二个值)
a 3 a3:a的第三个值
b 4 b4b4
b 5 b5b5b5b5b5
参考链接:https://www.cnblogs.com/wujin/p/6297770.html
18 mysql的sql语句练习的2个网址
- sql语句练习:
https://blog.csdn.net/mrbcy/article/details/68965271
https://blog.csdn.net/flycat296/article/details/63681089 - hive语句综合练习:
以下网址中的表为背景表,完成以下练习题:https://blog.csdn.net/mrbcy/article/details/68965271
1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数。
19 赋予root全部权限
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
flush privileges;
如果必要的话,重启mysqld服务。