MySql

基本

基本概念

关系数据库:表组成的数据库

Nosql数据库: 非关系数据库,并非由表构成,多是Key-value数据库,文件数据库,图等。

RDBMS 即关系数据库管理系统(Relational Database Management System)的特点:

  • 1.数据以表格的形式出现
  • 2.每行为各种记录名称
  • 3.每列为记录名称所对应的数据域
  • 4.许多的行和列组成一张表单
  • 5.若干的表单组成database

数据库:就是数据表的集合

数据表:表是数据的矩阵,在一个数据库的表看起来像一个简单的电子表格。

表还有功能,视图,和过程。本文着重数据表的理解

列:一列数据元素,包含了相同类型的数据

行:一行元组或记录,是一组相关的数据

冗余:存储两倍数据,冗余降低了性能,但提高了数据的安全性(可以理解为多余的重复数据?不按单条规则的存放的,单条数据废了,还能通过冗余数据推出出现错误的数据信息)

主键:主键是唯一的,一个数据表中只能包含一个主键,通过主键来查询数据(唯一性数据,比如说唯一的编号数据)

索引: 利用索引快速访问数据表中的特定信息。索引是对数据表中一列或多列的值进行排序的一种结构,所以索引也是要占存储空间的,类似书籍的目录(差异性大于男/女)。

外键

数据库服务器,提供数据库服务的服务器,

MySql 一般使用3306端口作为对外的服务端口,多个数据库服务器可以集群工作。

特点

  • 性能相对卓越,服务稳定,很少出现异常。
  • 开放源码无版权制约,自主性及使用成本低
  • 用户使用活跃,社区完善
  • 体积小,安装方便,易于维护
  • 口碑效应,十个企业无需考虑就用,LAMP,LNMP流行架构
  • 支持多种操作系统,提供多种API接口,支持多种开发语言。

使用范围

B/S系统架构,网站服务器,网站服务器再访问数据库服务器。

C/S系统架构,客户端,可直接连接数据库服务器

分布式系统软件

集群系统软件

大规模集群软件,云端服务。

演变

这是随数据量的技术演进。

  1. 简单应用,数据量比较小,访问强度低
  2. 垂直拆分,数据库多个表,多个表再拆分为服务器。
  3. 主从结构,主服务器写,多个从服务器读。
  4. 水平拆分,数据库多条数据,数据分片,上设备。
  5. 云计算,用户访问云服务器云端,云端再找多个服务器。

MySQL开发环境的配置

mysql 开发头文件和库文件

mysql的执行和关闭,都是通过官方提供的SDK 文件

可以使用MySQL的SDK ,可以使用相当于静态的mysqllient.lib。也可以使用动态库

需要注意的是,MySQL的库都是64位的。

MySQL数据库的连接

1
mysql_real_connect();
  • mysql 初始化过的mysql对象
  • host 服务器地址
  • user 连接服务器使用 用户
  • password 密码
  • db 连接服务器所使用的库
  • port 连接服务器的端口
  • unix_socket:unix的套接字的连接方式
  • clientflg 一般情况下默认为0
    • CLIENT_CAN_HANDLE_EXPLIRED_PASSWORDS 尝试旧密码
    • CLIENT_COMPRESS
    • CLIENT FOUND ROWS
    • CLIENT_IGNORE_SIGPIPE
    • CLIENT IGNORE SPACE
    • CLIENT_INTERACTIVE 超时设置。
    • CLIENT_LOCAL_FILES
    • CLIENT_MULTI_STATEMENTS 兼容多个语句
    • CLIENT_NO_SCHEMA//废弃
    • CLIENT_ODBC//废弃
    • CLIENT_OPTIONAL_RESULTSET_METADATA 高频小数据的查询应答优化
    • CLIENT_SSL
    • CLIENT_REMEMBER_OPTIONS

MySQL 数据类型以及对应的C/C++类型

mySQL 中的数据类型(INTEGER,DECIMAL,DATETIME)

INTEGER: TINYINT, SMALLINT, MEDIUMINT,INT ,BIGINT

对应的C/C++:char,short int ,int ,int64_t

DECIMAL:FLOAT,DOUBLE,DECIMAL

对应的C/C++:float,double,bouble==long double

DATETIME: DATE,TIME, YEAR,DATETIME, TIMESTAMP

对应的C/C++: struct tm ,tm, int int ,tm,time_t’

1
2
3
4
5
6
7
8
9
10
11
12
struct tm{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_ydey;
int tm_isdst;

}

MySQL 中的文本数据类型 TEXT BLOB;

TEXT: NCHAR,CHAR,NVARCHAR,VARCHAR,TINYTEXT,TEXT,MEDIUMTEXI,LONGTEXT;

对应的C/C++: unsigned char ,char, unsigned char , char ,char[256],string,string ,string.

BLOB:
BLOB, TINYBLOB,MEDIUMBLOB,LONGBLOB

对应的C/C++ : char*

MySQL 命令的执行

执行命令的过程

  • 发送SQL命令
  • 获取SQL执行结果
  • 解析获取到的结果

发送SQL命令接口

1
int STDCALL mysql_real_query(MYSQL* mysql, const char* q,unsigned long length);
  • q是SQL指令,length是指令的长度

获取SQL执行结果接口

1
MYSQL_RES  *STDCALL mysql_use_result(MYSQL * mysql);

释放结果接口

1
void STDCALL mysql_free_result(MYSQL_RES *result);

获得结果集列的数量:

1
unsigned int STDCALL mysql_num_fields(MYSQL_RES *res);

获得结果集行的数量

1
unsigned int STDCALL mysql_num_rows(MYSQL_RES *res);

取结果中的行接口

1
MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES* res);

获取每一行的长度接口

1
unsigned long* STDCALL mysql_getch_length(MYSQL_RES* res)

取结果中的列接口

1
MYSQL_FIELDS STDCALL mysql_fetch_fields(MYSQL_RES* res);

MySQL 创建用户

创建用户语句

1
CREATE USER '用户名'@'范围'IDENTIFIED BY'密码'
  • 范围包括 ip, localhost , %
  • ip只能从指定地址上登陆
  • localhost只能本机登录
  • % 表示任何地址都能路

创建用户后需要授权操作表

1
GRANT privileges ON databasename.tablename TO '用户名'@'范围'

privileges权限

  • SELECT,INSERT,UPDATE, DELETE
  • CREATE,DROP, ALTER,EXECUTE
  • INDEX,REFERENCES,ALTER ROUTINE
  • CREATE ROUTINE,CREATE TEMPORARY,
  • SHOW VIEW, LOCK TAQBLES
  • ALL

databasename是库的名字,可以填入*代表所有

tablename 是表的名字,同样可以填入*代表所有。

再学习库与表等数据创建之前需要学会的

首先就是备份

mysql的命令语句也可以使用>> 和<< 导入和导出数据库数据。

使用 SELECT … INTO OUTFILE 语句导出数据。

1
SELECT * FROM `table_name` INTO OUTFILE './data.txt';

或是输出为CSV格式

1
2
3
SELECT * FROM `table_name` INTO OUTFILE './data.txt';
FIELDS TERMINATED BY','ENCLOSED BY''''
LINES TERNUBATED BY'\r\n';

在下面的例子中,生成一个文件,各值用逗号隔开,该格式可以被许多程序使用

1
2
3
4
SELECT a,b,a+b INTO OUTFILE './data.text'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY ''''
LINES TERMINATED BY'\n'
FROM `test_table`;

需要注意的是,文件的路径,与权限。(特别是LINUX。干啥都要提权。)

windows需要写绝对路径,MySQL 安装时 my.ini 中有个设置

1
2
# Secure File Priv.
secure-file-priv="C:/ProgramData/MySQL/MySQL Server 8.0/Uploads"

输出的安全的绝对路径+ 文件名。

然后就是恢复

其实与备份一样,输入也是需要安全的绝对路径和文件名才可以恢复

MySQL提供了LOAD DATA INFILE 语句来插入数据。以下实例中将从当前目录中读取文件dump.txt ,将该文件中的数据插入到当前数据库的mytbl表中。

1
LOAD DATA LOCAl INFILE 'dump.txt' INTO TABLE `mytbl`;

如果需要指定读取的列值的分割符和行尾标记,但是默认的标记是定位符和换行符。

量个命令的FIELDS和LINES子句的语法是一样的。同时被指定是,FIELDS必须在LINES前

FIELD三种子句 TERMINATED BY | OPTIONALLY | ENCLOSED BY | ESCAPED BY 用户必须指定其中的一个

1
2
3
LOAD  DATA LOCAL INFILE 'dump.txt' INTO TABLE `mytbl`
FIELDS TERMINATED BY':'
LINES TERMINATED BY'\r\b';

LOAD DATA默认情况下是按照数据文件中的列的顺序插入数据的,如果数据文件中的列与插入表中的列不一致,需要指定列的顺序。

列的顺序是abc 但是插入表应为bca

1
2
LOAD DATA LOCAL INFILE 'dump.txt'
INTO TABLE `mytbl`(b,c,a);

以上是5版本的处理方式,而8的版本指定会报错,这是由于8的安全机制所导致的

在8的版本中,想要上传文件给服务器SQL ,需要进行额外的设置。

  • 客户端进行连接数据库时,FLAG 设置为 CLIENT_LOCAL_FILES;

  • LOAD DATA 语句出现1148错误的处理方式为:

    • 服务端设置全局的 LOCAL_INFILE 参数为 1 ;

    • 并且服务端本地执行如下CMD命令(必须服务端拿到文件)

    • ```shell
      mysqlimport.exe -u root -p password —local databasename
      “C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/table_test.txt”
      —fields-terminated-by=”,” —lines-terminated-by=”\r\n”

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13







      ## MySQL仓库基操

      ### 创建仓库

      ```mysql
      CREATE DATABASE databasename

databasename为要创建的库名字,创建好后需要赋予库的权限

1
GRANT ALL ON databasename.tablename  privileges TO 'user'@'范围'

删除库

1
DROP DATABASE databasename

切换库

1
USE databasename

MySQL表基操

创建表

:red_circle:注意:表的语句是 `` 不是 ‘’

1
2
3
4
CREATE TABLE IF NOT EXISTS `tablename` (
`列名称` 数据类型 #关键字列表 #默认值
......
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

关键字列表:

  • AUTO_INCREMENT 自动递增 适用于整型数据
  • NOT NULL 非空
  • NULL 可谓空
  • PRIMARY KEY 是主键 ,是主键需要指定数据的长度,且该数据类型必须是定长的数据类型。
  • UNSIGEND 无符号
  • DEFAULT 默认值
  • UNIQUE 唯一,要么为NULL要么唯一
  • ZEROFILL 0填充,如果没有指定,默认填充0

删除表

1
DROP TABLE `tablename`

MySQL数据基操

想MySQL 数据表插入数据通用的 INSERT INTO SQL 语法

1
2
3
INSERT INTO `table_name`(field1, field2, .... ,fieldN)
VALUES
(value1, value2, .... ,valueN);

如果是字符型数据用””表明,需要注意使用转义字符 , 和源码的编码问题。

数据删除

1
2
DELETE FROM `table_name` #WHERE Clause
DELETE FROM `table_name` WHERE `field` = value
  • 如果没有指定where的子句,MySQL表中的所有记录将被全部删除

数据更新

1
2
UPDATE `table_name` SET field1=new-value1,field2=new-value2, ....
#WHERE Clause
  • 你可以同时更新一个或者多个字段。
  • 你可以在WHERE子句中指定任何条件
  • 你可以在一个单独表中同时更新数据
  • 当你需要更新数据表中的指定行的数据是,WHERE 子句是非常有用的。

数据查询

1
2
3
4
SELECT `table_name1`.column_name,`table_name2`.cloumn_name...
FORM `table_name1`,`table_name2` ...
#WHERE Clause
#LIMIT N OFFSET M
  • 查询语句可以查询多个表,表之间都好分割,并且可以使用WHERE来设定查询条件
  • 可以使用*号代替其他字段
  • 可以使用LIMIT来设定范围记录数
  • OFFSET M指定开始查询的数据偏移量

mysql_use_result 这个函数,执行后,需要执行一次fetch,才能得到结果。

mysql_store_result 这个函数,执行后立刻查询,可以立刻得到结果。

联合查询

1
2
3
4
5
6
7
SELECT expression1,expression2, ... ,expression_n
FORM tables
#WHERE conditions
UNION #ALL| DISTNCT
SELECT expression1,expression2, ... ,expression_n
FORM tables
#WHERE conditions
  • expression1,expression2, … ,expression_n 表示要检索的列
  • tables 要检索的数据表
  • WHERE 可选的检索条件
  • DISTINCT 可选,删除结果集中重复的数据。默认情况下默认DISTINCT
  • ALL 可选,返回所有的数据(包括重复

建立索引

当数据库的表的接近百万级,数据查询的需求远远大于数据更新的需求时,可以建立索引,牺牲一定的内存占用,来提高查询效率

普通索引

1
CREATE INDEX indexName ON mytable(username(length));

最基本的索引,没有任何的限制。

唯一索引

1
CREATE UNIQUE INDEX indexName ON mytable(username(length));

索引列的值必须唯一,但也允许有空值,如果是组合索引,则列值的组合必须唯一。

乱码统一编码设置

用于设置本地控制体编码的接口函数:

1
setlocale(LC_ALL,"en_GB.UTF-8");

创建表之后执行以下

SQL语句:

1
2
SET NAMES 'utf8';
SET CHARACTER SET utf8;

并且编译源码本身也要统一编码UTF8(无签名).

MySQL事物

处理复杂的业务,复杂数据的处理,需要事务。

在MySQL中只有使用了Inoodb 数据库引擎的数据库或表才支持事物。

事物的处理可以用来维护数据库的完整性,保证成堆的SQL语句要么全部执行要么全部不执行

因此,事物用来管理insert update delete语句,并且需具有以下特性

  • 一致性
  • 原子性
  • 隔离性:多个并发事务的处理,隔离也有不同级别,读未提交,读提交,可重复读,串行化。
  • 持久性

事物控制语句

  • BEGIN 或 STARTTRANSACTION 显式的开启一个事物;
  • COMMIT 也可以使用 COMMINT WORK,两者等价。提交事务,并使数据库修改成为永久性修改
  • ROLLBACK/ROLLBACK WORK ,回滚,结束用户的食物,并撤销正在进行所有未提交的修改。
  • SAVEPOINT identifier, 在事物中创建一个保存点,一个事务可有多个保存点
  • RELEASE SAVEPOINT identifier 释放保存点。无保存点报错
  • ROLLBACK TO identifier 回滚至保存点。
  • SET TRANSANCITION 用来设置事物的隔离级别。

事物的处理的主要方法

  • BEGIN ROLLBACK COMMIT 来实现

  • 用SET 改变MySQL的自动提交模式

    • SET AUTOCOMMIT=0; 禁止自动提交
    • SET AUTOCOMMIT=1; 开启自动提交

    C++ 操作MySQL中常常禁用自动提交后进行事物操作,最后在手动提交后,再重新开启自动提交。

1
2
3
bool STDCALL mysql_commit(MYSQL* mysql);
bool STDCALL mysql_rollback(MYSQL* mysql);
bool STDCALL mysql_autocommit(MYSQL* mysql, bool auto_mode);

ROLLBACK

单独把这个拿出来说,是因为,对于自增的整形数据,ROLLBACK之后继续插入的数据。自增的值是继续被ROLLBACK的值。需要注意

MySQL触发器

创建一个触发器的语句

1
CREATE TRIGGER trigger_name trigger_time trigger_event ON `table_name` FOR EACH ROW trigger_stmt
  • trigger_name 触发器名称
  • trigger_time 触发器时机
    • BEFORE / AFTER
  • trigger_event 触发事件
    • INSERT
    • DELETE
    • UPDATA
  • table_name 触发器要建立在哪个表。
  • trigger_stmt 触发器的程序体,可以是一条SQL语句或者是用 BEGIN 和 END 包含的多条语句

根据触发器 time 和 event 的组合,可以有六种触发器。

MySQL内置函数

字符串函数

函数 描述 实例
ASCII(s) 返回字符串 s 的第一个字符的 ASCII 码。 返回 CustomerName 字段第一个字母的 ASCII 码: SELECT ASCII(CustomerName) AS NumCodeOfFirstChar``FROM Customers;
CHAR_LENGTH(s) 返回字符串 s 的字符数 返回字符串 RUNOOB 的字符数 SELECT CHAR_LENGTH("RUNOOB") AS LengthOfString;
CHARACTER_LENGTH(s) 返回字符串 s 的字符数 返回字符串 RUNOOB 的字符数 SELECT CHARACTER_LENGTH("RUNOOB") AS LengthOfString;
CONCAT(s1,s2…sn) 字符串 s1,s2 等多个字符串合并为一个字符串 合并多个字符串 SELECT CONCAT("SQL ", "Runoob ", "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 个字符替换为 runoob: SELECT INSERT("google.com", 1, 6, "runnob"); -- 输出:runoob.com
LOCATE(s1,s) 从字符串 s 中获取 s1 的开始位置 获取 b 在字符串 abc 中的位置: SELECT LOCATE('st','myteststring'); -- 5 返回字符串 abc 中 b 的位置: SELECT LOCATE('b', 'abc') -- 2
LCASE(s) 将字符串 s 的所有字母变成小写字母 字符串 RUNOOB 转换为小写: SELECT LCASE('RUNOOB') -- runoob
LEFT(s,n) 返回字符串 s 的前 n 个字符 返回字符串 runoob 中的前两个字符: SELECT LEFT('runoob',2) -- ru
LOWER(s) 将字符串 s 的所有字母变成小写字母 字符串 RUNOOB 转换为小写: SELECT LOWER('RUNOOB') -- runoob
LPAD(s1,len,s2) 在字符串 s1 的开始处填充字符串 s2,使字符串长度达到 len 将字符串 xx 填充到 abc 字符串的开始处: SELECT LPAD('abc',5,'xx') -- xxabc
LTRIM(s) 去掉字符串 s 开始处的空格 去掉字符串 RUNOOB开始处的空格: SELECT LTRIM(" RUNOOB") AS LeftTrimmedString;-- RUNOOB
MID(s,n,len) 从字符串 s 的 n 位置截取长度为 len 的子字符串,同 SUBSTRING(s,n,len) 从字符串 RUNOOB 中的第 2 个位置截取 3个 字符: SELECT MID("RUNOOB", 2, 3) AS ExtractString; -- UNO
POSITION(s1 IN s) 从字符串 s 中获取 s1 的开始位置 返回字符串 abc 中 b 的位置: SELECT POSITION('b' in 'abc') -- 2
REPEAT(s,n) 将字符串 s 重复 n 次 将字符串 runoob 重复三次: SELECT REPEAT('runoob',3) -- runoobrunoobrunoob
REPLACE(s,s1,s2) 将字符串 s2 替代字符串 s 中的字符串 s1 将字符串 abc 中的字符 a 替换为字符 x: SELECT REPLACE('abc','a','x') --xbc
REVERSE(s) 将字符串s的顺序反过来 将字符串 abc 的顺序反过来: SELECT REVERSE('abc') -- cba
RIGHT(s,n) 返回字符串 s 的后 n 个字符 返回字符串 runoob 的后两个字符: SELECT RIGHT('runoob',2) -- ob
RPAD(s1,len,s2) 在字符串 s1 的结尾处添加字符串 s2,使字符串的长度达到 len 将字符串 xx 填充到 abc 字符串的结尾处: SELECT RPAD('abc',5,'xx') -- abcxx
RTRIM(s) 去掉字符串 s 结尾处的空格 去掉字符串 RUNOOB 的末尾空格: SELECT RTRIM("RUNOOB ") AS RightTrimmedString; -- RUNOOB
SPACE(n) 返回 n 个空格 返回 10 个空格: SELECT SPACE(10);
STRCMP(s1,s2) 比较字符串 s1 和 s2,如果 s1 与 s2 相等返回 0 ,如果 s1>s2 返回 1,如果 s1<s2 返回 -1 比较字符串: SELECT STRCMP("runoob", "runoob"); -- 0
SUBSTR(s, start, length) 从字符串 s 的 start 位置截取长度为 length 的子字符串 从字符串 RUNOOB 中的第 2 个位置截取 3个 字符: SELECT SUBSTR("RUNOOB", 2, 3) AS ExtractString; -- UNO
SUBSTRING(s, start, length) 从字符串 s 的 start 位置截取长度为 length 的子字符串 从字符串 RUNOOB 中的第 2 个位置截取 3个 字符: SELECT SUBSTRING("RUNOOB", 2, 3) AS ExtractString; -- UNO
SUBSTRING_INDEX(s, delimiter, number) 返回从字符串 s 的第 number 个出现的分隔符 delimiter 之后的子串。 如果 number 是正数,返回第 number 个字符左边的字符串。 如果 number 是负数,返回第(number 的绝对值(从右边数))个字符右边的字符串。 SELECT SUBSTRING_INDEX('a*b','*',1) -- a``SELECT SUBSTRING_INDEX('a*b','*',-1) -- b``SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a*b*c*d*e','*',3),'*',-1) -- c
TRIM(s) 去掉字符串 s 开始和结尾处的空格 去掉字符串 RUNOOB 的首尾空格: SELECT TRIM(' RUNOOB ') AS TrimmedString;
UCASE(s) 将字符串转换为大写 将字符串 runoob 转换为大写: SELECT UCASE("runoob"); -- RUNOOB
UPPER(s) 将字符串转换为大写 将字符串 runoob 转换为大写: SELECT UPPER("runoob"); -- RUNOOB

数字函数

函数名 描述 实例
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 CEILING(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", "Runoob", "Apple"); -- Runoob
LEAST(expr1, expr2, expr3, …) 返回列表中的最小值 返回以下数字列表中的最小值: SELECT LEAST(3, 12, 34, 8, 25); -- 3 返回以下字符串列表中的最小值: SELECT LEAST("Google", "Runoob", "Apple"); -- Apple
LN 返回数字的自然对数,以 e 为底。 返回 2 的自然对数: SELECT LN(2); -- 0.6931471805599453
LOG(x) 或 LOG(base, x) 返回自然对数(以 e 为底的对数),如果带有 base 参数,则 base 为指定带底数。 SELECT LOG(20.085536923188) -- 3``SELECT LOG(2, 4); -- 2
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 MinPrice 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 最近的整数 SELECT ROUND(1.23456) --1
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

日期函数

函数名 描述 实例
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 OrderPayDate``FROM 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
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:11:11') -> 11
FROM_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) 返回日期当中的月份名称,如 November 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

其他函数

函数名 描述 实例
BIN(x) 返回 x 的二进制编码 15 的 2 进制编码: SELECT BIN(15); -- 1111
BINARY(s) 将字符串 s 转换为二进制字符串 SELECT BINARY "RUNOOB";-> RUNOOB
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, 'runoob.com', NULL, 'google.com');-> runoob.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
CURRENT_USER() 返回当前用户 SELECT CURRENT_USER();-> guest@%
DATABASE() 返回当前数据库名 SELECT DATABASE(); -> runoob
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) 判断表达式是否为 NULL 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@%
USER() 返回当前用户 SELECT USER();-> guest@%
VERSION() 返回数据库的版本号 SELECT VERSION()-> 5.6.34

测试demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

#include <iostream>
#include <mysql.h>

int ConnectSQL(MYSQL*& pDB,const char* host ,const char* user,const char * password, const char* name, unsigned int port = 3306,const char* unix = NULL,unsigned long flag = 0) {
MYSQL* mysql = new MYSQL();
pDB = mysql_init(mysql);
if (pDB == NULL) {
std::cout << "init_falied" << char(10);
return -1;
}
pDB = mysql_real_connect(pDB, host, user, password, name, port, unix, flag);
if (!pDB)return -1;
std::cout << "connect mysql" << pDB << char(10);
return 0;
}

void ShowResult(MYSQL_RES* res) {
unsigned nFields = mysql_num_fields(res);
my_ulonglong nRows = mysql_num_rows(res);
MYSQL_FIELD* fields = mysql_fetch_fields(res);
MYSQL_ROW row;
do
{
row = mysql_fetch_row(res);
if (row != NULL)
{
for (unsigned i = 0; i < nFields; i++)
{
std::cout << "type:" << fields[i].type <<" "<< fields[i].name << ":" << row[i] << char(10);
}
}
} while (row != NULL);
}



int ExecuteSQL(MYSQL* pDB,const std::string& sql,BOOL isShowRes = FALSE) {
int ret = mysql_real_query(pDB, sql.c_str(), (unsigned long)sql.size());
if (ret != 0)
{
std::cout << "mysql error:" << mysql_error(pDB) << char(10);
return -1;
}
MYSQL_RES* res = NULL;
res = isShowRes?mysql_store_result(pDB):mysql_use_result(pDB);
if (res != NULL) {
ShowResult(res);
std::cout << "===================================" << char(10);
mysql_free_result(res);
return 0;
}
return -1;
}


int main()
{
setlocale(LC_ALL, "en_GB.UTF-8");
MYSQL* pDB = NULL;
int ret = ConnectSQL(pDB, "localhost", "root", "suailuo", "mysql");
if (!ret) {
std::string sql;
sql = "CREATE USER IF NOT EXISTS 'hello'@'localhost' IDENTIFIED BY '123456';";
ret = ExecuteSQL(pDB, sql);
sql = "GRANT ALL ON *.* TO 'hello'@'localhost';";
ret = ExecuteSQL(pDB, sql);
sql = "CREATE DATABASE test1";
ret = ExecuteSQL(pDB, sql);
sql = "GRANT ALL ON test1.* TO 'hello'@'localhost';";
ret = ExecuteSQL(pDB, sql);
sql = "USE test1";
ret = ExecuteSQL(pDB, sql);

sql = "CREATE TABLE IF NOT EXISTS `table_test`(";
sql += "`编号` NVARCHAR(16) PRIMARY KEY,";
sql += "`age` INT NOT NULL DEFAULT 18";
sql += ")ENGINE=InnoDB DEFAULT CHARSET=utf8;";
ret = ExecuteSQL(pDB, sql);
sql = "INSERT INTO `table_test`(`编号`,`age`) VALUES(\"9527\",35);";
ret = ExecuteSQL(pDB, sql);
sql = "INSERT INTO `table_test`(`编号`,`age`) VALUES(\"9528\",99);";
ret = ExecuteSQL(pDB, sql);
sql = "INSERT INTO `table_test`(`编号`,`age`) VALUES(\"9529\",17);";
ret = ExecuteSQL(pDB, sql);
//sql = "DELETE FROM `table_test` WHERE `编号`=\"9528\";";
//ret = ExecuteSQL(pDB, sql);

//创建一个日志表
sql = "CREATE TABLE IF NOT EXISTS `logs`(";
sql += "`Id` INT(16) NOT NULL AUTO_INCREMENT,";
sql += "`log` VARCHAR(255) DEFAULT NULL COMMENT \"日志说明\",";
sql += "PRIMARY KEY(`Id`)";
sql += ")ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT = \"日志\";";
ret = ExecuteSQL(pDB, sql);
//创建触发器
sql = "CREATE TRIGGER hello_log AFTER INSERT ON `table_test` FOR EACH ROW \n \
BEGIN\n \
DECLARE s1 VARCHAR(40)character set utf8;\n \
DECLARE s2 VARCHAR(20)character set utf8;\n \
SET s2 = \" is created\";\n \
SET s1 = CONCAT(NEW.`编号`, s2);\n \
INSERT INTO logs(log) values(s1);\n \
END;";
ret = ExecuteSQL(pDB, sql);



//这一段就是事物
mysql_autocommit(pDB, false);
sql = "UPDATE `table_test` SET age=55 WHERE `编号`=\"9528\";";
ret = ExecuteSQL(pDB, sql);
sql = "UPDATE `table_test` SET age=55 WHERE `age`<18;";
ret = ExecuteSQL(pDB, sql);

sql = "INSERT INTO `table_test`(`编号`,`age`) VALUES(\"9521\",127);";
ret = ExecuteSQL(pDB, sql);

//mysql_rollback(pDB);
sql = "INSERT INTO `table_test`(`编号`,`age`) VALUES(\"9521\",127);";
ret = ExecuteSQL(pDB, sql);

sql = "CREATE TABLE IF NOT EXISTS `table_test2`(";
sql += "`职业` NVARCHAR(16) PRIMARY KEY,";
sql += "`age` INT NOT NULL DEFAULT 18";
sql += ")ENGINE=InnoDB DEFAULT CHARSET=utf8;";
ret = ExecuteSQL(pDB, sql);
sql = "INSERT INTO `table_test2`(`职业`,`age`) VALUES(\"8529\",17);";
ret = ExecuteSQL(pDB, sql);
sql = "INSERT INTO `table_test2`(`职业`,`age`) VALUES(\"9529\",17);";
ret = ExecuteSQL(pDB, sql);

mysql_commit(pDB);
mysql_autocommit(pDB, true);
//事物结尾。

sql = "SELECT * FROM `table_test`;";
ret = ExecuteSQL(pDB, sql,TRUE);
sql = "SELECT age FROM `table_test`UNION ALL SELECT age FROM `table_test2`;";
ret = ExecuteSQL(pDB, sql,TRUE);




sql = "SELECT age FROM `table_test`UNION ALL SELECT age FROM `table_test2`;";
ret = ExecuteSQL(pDB, sql, TRUE);


//sql = "DROP TABLE test1.`table_test`;";
//ret = ExecuteSQL(pDB, sql);
//sql = "DROP DATABASE test1;";
//ret = ExecuteSQL(pDB, sql);


}
mysql_close(pDB);

delete pDB;
return 0;

}