Andy Niu Help
1.0.0.0
|
变量 | |
Mysql内外连接 | |
MySQL的Embedded模式 | |
mysql下划线和中划线 | |
Mysql的两种连接方式 | |
Mysql默认的数据库 | |
Mysql有时候为什么要flush | |
Mysql的有关日志 | |
mysql表的复制 | |
根据已有的记录增加新的记录 | |
执行sql文件,添加数据乱码 | |
查看字符串的16进制取值 | |
Sql_Mode | |
Sql注入 | |
分割求总数 | |
分割后求第n个元素 | |
删除重复记录_保存Id最小的一条 | |
详细描述
变量说明
mysql下划线和中划线 |
1、通过select或者show variables 可以看到系统变量单词之间的分隔符是下划线,如下: mysql> show variables like 'event%'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | event_scheduler | ON | +-----------------+-------+ 1 row in set (0.00 sec) mysql> select @@event_scheduler; +-------------------+ | @@event_scheduler | +-------------------+ | ON | +-------------------+ 1 row in set (0.00 sec) 2、在配置文件 my.cnf中,使用下划线或者中划线都是可以的。如下: lower_case_table_names=1 default-character-set=utf8 event-scheduler=on 3、另外对于开关变量,比如event-scheduler,使用on或者1也都是可以的。 event-scheduler=1 或者 event-scheduler=on 4、但是在执行命令,使用选项参数的时候,必须使用中划线。 两个中划线是全写方式,选项和取值之间必须有=号或者空格,但是有些必须使用=号,比如密码之类。 单中划线是简写方式,选项和取值之间不能使用=号,可以有空格也可以没有空格,但是有些必须没有空格,比如密码之类。 如下: mysql --user=root --password=123456 mysql --user root --password=123456 mysql -u root -p123456 mysql -uroot -p123456
Mysql内外连接 |
mysql> desc student; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | ID | int(11) | NO | PRI | 0 | | | NAME | varchar(16) | YES | | NULL | | | AGE | int(11) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set mysql> desc sc; +-------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+----------------+ | ID | int(11) | NO | PRI | NULL | auto_increment | | SID | int(11) | YES | | NULL | | | CID | int(11) | YES | MUL | NULL | | | SCORE | int(11) | YES | | NULL | | +-------+---------+------+-----+---------+----------------+ 4 rows in set mysql> select * from student; +-------+----------+-----+ | ID | NAME | AGE | +-------+----------+-----+ | 10001 | Andy | 26 | | 10002 | Bill | 27 | | 10003 | Caroline | 34 | | 10004 | David | 46 | +-------+----------+-----+ 4 rows in set mysql> select * from sc; +----+-------+-----+-------+ | ID | SID | CID | SCORE | +----+-------+-----+-------+ | 1 | 10001 | 101 | 78 | | 2 | 10001 | 102 | 67 | | 3 | 10008 | 103 | 100 | +----+-------+-----+-------+ 3 rows in set ----------------------------------------------------------------------------------------------------------------- 内连接 mysql> select student.*, sc.* from student inner join sc on student.id = sc.sid; +-------+------+-----+----+-------+-----+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+------+-----+----+-------+-----+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10001 | Andy | 26 | 2 | 10001 | 102 | 67 | +-------+------+-----+----+-------+-----+-------+ 2 rows in set 内连接等价于我们平时的自然连接,也就是: mysql> select student.*, sc.* from student,sc where student.id = sc.sid; +-------+------+-----+----+-------+-----+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+------+-----+----+-------+-----+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10001 | Andy | 26 | 2 | 10001 | 102 | 67 | +-------+------+-----+----+-------+-----+-------+ 2 rows in set ----------------------------------------------------------------------------------------------------------------- 左连接 考虑下面的需求,我想列出所有学生对应的成绩,一个学生可能多个成绩,也可能没有成绩。有多个成绩把多个成绩列出来,没有成绩的话,成绩这些字段的值使用NULL填充。怎么解决这个问题? 使用左连接,student表 left join sc表,如下: mysql> select student.*, sc.* from student left join sc on student.id = sc.sid; +-------+----------+-----+------+-------+------+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+----------+-----+------+-------+------+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10001 | Andy | 26 | 2 | 10001 | 102 | 67 | | 10002 | Bill | 27 | NULL | NULL | NULL | NULL | | 10003 | Caroline | 34 | NULL | NULL | NULL | NULL | | 10004 | David | 46 | NULL | NULL | NULL | NULL | +-------+----------+-----+------+-------+------+-------+ 5 rows in set ----------------------------------------------------------------------------------------------------------------- 右连接 考虑下面的需求,我想列出所有成绩对应的学生,一个成绩有对应的学生,也可能没有对应的学生,比如这个学生开除了。有学生就把学生列出来,没有学生的话,学生这些字段的值使用NULL填充。怎么解决这个问题? 使用右连接,student表 right join sc表,如下: mysql> select student.*, sc.* from student right join sc on student.id = sc.sid; +-------+------+------+----+-------+-----+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+------+------+----+-------+-----+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10001 | Andy | 26 | 2 | 10001 | 102 | 67 | | NULL | NULL | NULL | 3 | 10008 | 103 | 100 | +-------+------+------+----+-------+-----+-------+ 3 rows in set 根据对称性,A left join B 等价于 B right join A ----------------------------------------------------------------------------------------------------------------- 外连接 左连接也叫左外连接(同理右连接),这里的外连接也叫全外连接。 考虑下面的需求,我想列出所有学生对应的所有成绩,这里存在学生可能没有成绩,成绩也可能没有对应的学生,没有的话,也要列出来,这些字段的值使用NULL填充。 目前,mysql不支持外连接,解决办法是使用union组合查询,把左连接和右连接的结果合并。如下: mysql> select student.*, sc.* from student left join sc on student.id = sc.sid union select student.*, sc.* from student right join sc on student.id = sc.sid; +-------+----------+------+------+-------+------+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+----------+------+------+-------+------+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10001 | Andy | 26 | 2 | 10001 | 102 | 67 | | 10002 | Bill | 27 | NULL | NULL | NULL | NULL | | 10003 | Caroline | 34 | NULL | NULL | NULL | NULL | | 10004 | David | 46 | NULL | NULL | NULL | NULL | | NULL | NULL | NULL | 3 | 10008 | 103 | 100 | +-------+----------+------+------+-------+------+-------+ 6 rows in set 注意:这里的union自动去除了重复行,如果不想去除重复行,使用union all ----------------------------------------------------------------------------------------------------------------- 还有一点需要注意:就是on 之后的条件,如下: mysql> select student.*, sc.* from student left join sc on student.id = sc.sid; +-------+----------+-----+------+-------+------+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+----------+-----+------+-------+------+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10001 | Andy | 26 | 2 | 10001 | 102 | 67 | | 10002 | Bill | 27 | NULL | NULL | NULL | NULL | | 10003 | Caroline | 34 | NULL | NULL | NULL | NULL | | 10004 | David | 46 | NULL | NULL | NULL | NULL | +-------+----------+-----+------+-------+------+-------+ 5 rows in set mysql> select student.*, sc.* from student left join sc on student.id = sc.sid and sc.cid=101; +-------+----------+-----+------+-------+------+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+----------+-----+------+-------+------+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10002 | Bill | 27 | NULL | NULL | NULL | NULL | | 10003 | Caroline | 34 | NULL | NULL | NULL | NULL | | 10004 | David | 46 | NULL | NULL | NULL | NULL | +-------+----------+-----+------+-------+------+-------+ 4 rows in set mysql> select student.*, sc.* from student left join sc on student.id = sc.sid where sc.cid=101; +-------+------+-----+----+-------+-----+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+------+-----+----+-------+-----+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | +-------+------+-----+----+-------+-----+-------+ 1 row in set 这里看出第二个查询和第三个查询的区别,换一种写法就很清楚了。 mysql> select student.*, sc.* from student left join sc on (student.id = sc.sid and sc.cid=101); +-------+----------+-----+------+-------+------+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+----------+-----+------+-------+------+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10002 | Bill | 27 | NULL | NULL | NULL | NULL | | 10003 | Caroline | 34 | NULL | NULL | NULL | NULL | | 10004 | David | 46 | NULL | NULL | NULL | NULL | +-------+----------+-----+------+-------+------+-------+ 4 rows in set mysql> select student.*, sc.* from student left join sc on (student.id = sc.sid) where sc.cid=101; +-------+------+-----+----+-------+-----+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+------+-----+----+-------+-----+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | +-------+------+-----+----+-------+-----+-------+ 1 row in set mysql> select student.*, sc.* from student left join sc on (student.id = sc.sid where sc.cid=101); 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where sc.cid=101)' at line 1 ----------------------------------------------------------------------------------------------------------------- select student.*, sc.* from student left join sc on (student.id = sc.sid and sc.cid=101); 相当于: 1、内部连接 mysql> select student.*, sc.* from student inner join sc on student.id = sc.sid; +-------+------+-----+----+-------+-----+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+------+-----+----+-------+-----+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10001 | Andy | 26 | 2 | 10001 | 102 | 67 | +-------+------+-----+----+-------+-----+-------+ 2 rows in set 2、选择出sc.cid=101,再进行左连接,没有成绩的使用NULL填充 ----------------------------------------------------------------------------------------------------------------- select student.*, sc.* from student left join sc on (student.id = sc.sid) where sc.cid=101; 相当于: 1、左连接 mysql> select student.*, sc.* from student left join sc on student.id = sc.sid; +-------+----------+-----+------+-------+------+-------+ | ID | NAME | AGE | ID | SID | CID | SCORE | +-------+----------+-----+------+-------+------+-------+ | 10001 | Andy | 26 | 1 | 10001 | 101 | 78 | | 10001 | Andy | 26 | 2 | 10001 | 102 | 67 | | 10002 | Bill | 27 | NULL | NULL | NULL | NULL | | 10003 | Caroline | 34 | NULL | NULL | NULL | NULL | | 10004 | David | 46 | NULL | NULL | NULL | NULL | +-------+----------+-----+------+-------+------+-------+ 5 rows in set 2、再选出 sc.cid=101
- 参见
Mysql有时候为什么要flush |
1、为了性能考虑,mysql服务启动的时候,会把常用的信息从数据库中加载到内存。 这样以后在查询或者操作的时候,直接在内存中操作就行了,大大提高效率。 dmu的做法也是这样的。 2、对于GRANT、REVOKE、SET PASSWORD操作,mysql会更新数据库中对应的表,同时刷新内存中的数据。 但是对于手工修改表的数据,比如insert、update,mysql内存中的数据并不会更新,导致内存和表的数据不一致。 客户端的请求,mysql还是在内存中进行,表现为insert,update操作没有起作用。 3、怎么解决这个问题? 第一种方法是:重启mysql 第二种方法是:进行相应的flush,比如flush privileges,将数据库中的信息刷新到内存中。 4、测试如下: mysql> drop user niu; Query OK, 0 rows affected (0.00 sec) mysql> create user niu; Query OK, 0 rows affected (0.00 sec) mysql> update user set password=password('123') where user='niu'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 登录mysql -uniu -p123 报错,如下: [root@localhost ~]# mysql -uniu -p123 Warning: Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'niu'@'localhost' (using password: YES) 进行flush privileges 登录mysql -uniu -p123成功 使用 mysql> set password for niu=password('456'); Query OK, 0 rows affected (0.00 sec) 登录mysql -uniu -p456成功
MySQL的Embedded模式 |
1、一般情况下,我们通过CS模式,调用MySQL客户端mysqlclient和MySQL服务交互。 2、但是这种C/S的数据服务不适合于一些轻量级的应用,可以使用MySQL的Embedded模式,相当于以库的方式调用。 3、这两种方式的区别是: CS模式,客户端链接mysqlclient库,调用mysqlclient的接口,经过网络和mysql服务交互。 Embedded模式,客户端链接mysqld库,调用mysqld的接口,都在在本地操作。 4、CS模式 sudo apt-get install libmysqlclient-dev g++ -o Embed Embed.cc `mysql_config --include --libs` -std=c++11 5、Embedded模式 sudo apt install libmysqld-dev g++ -o Embed Embed.cc `mysql_config --include --libmysqld-libs` -std=c++11 6、可以看一下,mysql_config的输出,如下: niuzibin@ubuntu:~/work/CPP_2/Embed$ mysql_config Usage: /usr/bin/mysql_config [OPTIONS] Options: --cflags [-I/usr/include/mysql -DBIG_JOINS=1 -fno-strict-aliasing -g -DNDEBUG] --include [-I/usr/include/mysql] --libs [-L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -lz -lm -ldl] --libs_r [-L/usr/lib/x86_64-linux-gnu -lmysqlclient_r -lpthread -lz -lm -ldl] --plugindir [/usr/lib/mysql/plugin] --socket [/var/run/mysqld/mysqld.sock] --port [0] --version [5.5.59] --libmysqld-libs [-L/usr/lib/x86_64-linux-gnu -lmysqld -lpthread -lz -lm -lwrap -lcrypt -ldl -laio] --variable=VAR VAR is one of: pkgincludedir [/usr/include/mysql] pkglibdir [/usr/lib/x86_64-linux-gnu] plugindir [/usr/lib/mysql/plugin]
Mysql的两种连接方式 |
1、mysql是典型的的CS架构,连接mysql服务有两种方式: TCP/IP套接字和Unix域套接字 2、TCP/IP套接字是MySQL在任何平台都提供的一种连接方式,也是网络中使用最多的一种方式。 这种方式通过TCP/IP建立网络连接,一般情况下客户端在一台服务器上,而MySQL实例在另外一台服务器上,如下: mysql -h127.0.0.1 -uroot -p123456 使用netstat可以看到TCP连接,在Linux使用tcpdump抓包可以看到交互的数据(在Windows下抓不到环回包) 3、如果mysql客户端和数据库实例在同一台服务器上,可以使用Unix域套接字连接。 注:Unix域套接字其实不是网络协议,mysql客户端和数据库实例之间没有TCP连接。 查看socket文件,如下: mysql> show variables like 'socket'; +---------------+---------------------------+ | Variable_name | Value | +---------------+---------------------------+ | socket | /var/lib/mysql/mysql.sock | +---------------+---------------------------+ 使用UNIX域套接字连接,如下: mysql -uroot -p123456 -S /var/lib/mysql/mysql.sock UNIX域套接字比TCP/IP套接字效率更高,mysql默认使用Unix域套接字来连接,下面的方式都是使用Unix域套接字。 mysql -uroot -p123456 mysql -hlocalhost -uroot -p123456 4、通过TCP/IP套接字连接,抓包可以获取交互信息 a、抓包获取的内容如下: "......select serverid,title from serversmanagement; .....P.... def.ibp_niu1.serversmanagement.serversmanagement.serverid.SERVERID.?.......B...J.... def.ibp_niu1.serversmanagement.serversmanagement.title.TITLE.!.,................ "......10.VTDU.....11.DMU.....18.VRU......." b、具体内容,请求是select serverid,title from serversmanagement; 回复包括槽位的信息,以及返回的数据集合。 c、注意:登录的时候,密码字段是加密的。
Mysql的有关日志 |
1、普通日志 mysql> show variables like 'general%'; +------------------+------------------------------+ | Variable_name | Value | +------------------+------------------------------+ | general_log | ON | | general_log_file | /var/lib/mysql/localhost.log | +------------------+------------------------------+ 2 rows in set (0.00 sec) 2、注意:普通日志,不仅记录select查询语句,还记录insert,update等语句,查看普通日志,如下: [root@localhost ~]# tail /var/lib/mysql/localhost.log 89 Query show tables 89 Field List a 89 Field List b 89 Field List t1 89 Field List t2 160625 11:28:28 89 Query create table t1(ID int) 160625 11:28:33 89 Query create table t100(ID int) 160625 11:37:25 89 Query insert t100 values(52) 160625 11:37:42 89 Query show variables like 'general%' 160625 11:38:09 89 Query update t100 set id=456 3、慢查询日志 mysql> show global variables like '%_query%'; +------------------------------+-----------------------------------+ | Variable_name | Value | +------------------------------+-----------------------------------+ | binlog_rows_query_log_events | OFF | | ft_query_expansion_limit | 20 | | have_query_cache | YES | | long_query_time | 4.000000 | | slow_query_log | ON | | slow_query_log_file | /var/lib/mysql/localhost-slow.log | +------------------------------+-----------------------------------+ 6 rows in set (0.01 sec) mysql> set global long_query_time=3; Query OK, 0 rows affected (0.00 sec) mysql> show global variables like '%_query%'; +------------------------------+-----------------------------------+ | Variable_name | Value | +------------------------------+-----------------------------------+ | binlog_rows_query_log_events | OFF | | ft_query_expansion_limit | 20 | | have_query_cache | YES | | long_query_time | 3.000000 | | slow_query_log | ON | | slow_query_log_file | /var/lib/mysql/localhost-slow.log | +------------------------------+-----------------------------------+ 6 rows in set (0.00 sec) mysql> select sleep(5); +----------+ | sleep(5) | +----------+ | 0 | +----------+ 1 row in set (5.00 sec) 4、查看慢查询日志: [root@localhost ~]# tail /var/lib/mysql/localhost-slow.log Time Id Command Argument # Time: 160625 12:22:23 # User@Host: root[root] @ localhost [] Id: 89 # Query_time: 5.002054 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0 use niu1; SET timestamp=1466828543; select sleep(5); /usr/sbin/mysqld, Version: 5.6.15 (MySQL Community Server (GPL)). started with: Tcp port: 3306 Unix socket: /var/lib/mysql/mysql.sock Time Id Command Argument
mysql表的复制 |
1、create table xxx as select xxx,创建新表,没有原表的完整约束,会把原表的数据拷贝一份,如下: mysql> desc stu; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | Id | int(9) | NO | PRI | NULL | auto_increment | | Name | varchar(100) | NO | | NULL | | | Age | int(9) | NO | | 0 | | | updatetime | datetime | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ 4 rows in set mysql> select * from stu; +----+------+-----+---------------------+ | Id | Name | Age | updatetime | +----+------+-----+---------------------+ | 1 | Andy | 28 | 2015-03-19 15:42:09 | +----+------+-----+---------------------+ 1 row in set mysql> create table stu2 as select * from stu; Query OK, 1 row affected Records: 1 Duplicates: 0 Warnings: 0 mysql> desc stu2; +------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+-------+ | Id | int(9) | NO | | 0 | | | Name | varchar(100) | NO | | NULL | | | Age | int(9) | NO | | 0 | | | updatetime | datetime | YES | | NULL | | +------------+--------------+------+-----+---------+-------+ 4 rows in set mysql> select * from stu2; +----+------+-----+---------------------+ | Id | Name | Age | updatetime | +----+------+-----+---------------------+ | 1 | Andy | 28 | 2015-03-19 15:42:09 | +----+------+-----+---------------------+ 1 row in set 2、create table xxx like xxx,创建新表,约束和原表相同,只拷贝表结构,没有拷贝表的数据,如下: mysql> desc stu; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | Id | int(9) | NO | PRI | NULL | auto_increment | | Name | varchar(100) | NO | | NULL | | | Age | int(9) | NO | | 0 | | | updatetime | datetime | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ 4 rows in set mysql> select * from stu; +----+------+-----+---------------------+ | Id | Name | Age | updatetime | +----+------+-----+---------------------+ | 1 | Andy | 28 | 2015-03-19 15:42:09 | +----+------+-----+---------------------+ 1 row in set mysql> create table stu3 like stu; Query OK, 0 rows affected mysql> desc stu3; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | Id | int(9) | NO | PRI | NULL | auto_increment | | Name | varchar(100) | NO | | NULL | | | Age | int(9) | NO | | 0 | | | updatetime | datetime | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ 4 rows in set mysql> select * from stu3; Empty set 3、如果我想拷贝表的结构(约束和原表相同),同时拷贝表的数据,怎么办? 先create table xxx like xxx,创建表结构,再insert into xxx select xxx 拷贝数据。注意:这里没有as mysql> desc stu; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | Id | int(9) | NO | PRI | NULL | auto_increment | | Name | varchar(100) | NO | | NULL | | | Age | int(9) | NO | | 0 | | | updatetime | datetime | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ 4 rows in set mysql> select * from stu; +----+------+-----+---------------------+ | Id | Name | Age | updatetime | +----+------+-----+---------------------+ | 1 | Andy | 28 | 2015-03-19 15:42:09 | +----+------+-----+---------------------+ 1 row in set mysql> create table stu4 like stu; Query OK, 0 rows affected mysql> desc stu4; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | Id | int(9) | NO | PRI | NULL | auto_increment | | Name | varchar(100) | NO | | NULL | | | Age | int(9) | NO | | 0 | | | updatetime | datetime | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ 4 rows in set mysql> select * from stu4; Empty set mysql> insert into stu4(name,age,updatetime) select name,age,updatetime from stu; Query OK, 1 row affected Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from stu4; +----+------+-----+---------------------+ | Id | Name | Age | updatetime | +----+------+-----+---------------------+ | 1 | Andy | 28 | 2015-03-19 15:42:09 | +----+------+-----+---------------------+ 1 row in set
Mysql默认的数据库 |
1、数据库mysql,保存的信息有: 用户,帮助信息,普通日志,慢查询日志,时区有关。 2、数据库information_schema,保存的信息有: schemata,tables,columns,funcs,procedures,events,partitions,triggers,各种privileges, 全局和会话的status和variables,processlist,innodb的事务和锁 注意:有些表并没有实际的物理文件,而是对应着内存中的一些信息。 3、数据库performance_schema,保存的信息有: 性能统计和分析
Sql_Mode |
1、Sql Mode(Sql模式),mysql可以运行在不同的Sql Mode下,不同的Sql Mode定义了不同的Sql语法和数据校验。 2、举例来说, mysql> select @@session.sql_mode; +-------------------------------------------------------------+ | @@session.sql_mode | +-------------------------------------------------------------+ | REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI | +-------------------------------------------------------------+ 1 row in set mysql> select * from user; +----+------+----------+------------+ | ID | NAME | PASSWORD | UPDATETIME | +----+------+----------+------------+ | 1 | Andy | 123456 | NULL | +----+------+----------+------------+ 1 row in set mysql> update user set updatetime='2015-04-31 15:0:0'; Database changed Rows matched: 1 Changed: 1 Warnings: 1 mysql> show warnings; +---------+------+-----------------------------------------------------+ | Level | Code | Message | +---------+------+-----------------------------------------------------+ | Warning | 1264 | Out of range value for column 'UPDATETIME' at row 1 | +---------+------+-----------------------------------------------------+ 1 row in set mysql> select * from user; +----+------+----------+---------------------+ | ID | NAME | PASSWORD | UPDATETIME | +----+------+----------+---------------------+ | 1 | Andy | 123456 | 0000-00-00 00:00:00 | +----+------+----------+---------------------+ 1 row in set 在ansi模式下,更新一个无效的datetime,mysql给出一个warning,更新的时间为 0000-00-00 00:00:00 3、Sql模式设置为 strict_trans_tables,如下: mysql> set @@session.sql_mode='strict_trans_tables'; Query OK, 0 rows affected mysql> update user set updatetime='2015-04-31 15:0:0'; 1292 - Incorrect datetime value: '2015-04-31 15:0:0' for column 'UPDATETIME' at row 1 直接报错,error,不允许更新 考虑事务的情况,如下: mysql> start transaction; Query OK, 0 rows affected mysql> update user set name='Bill' where id=1; Database changed Rows matched: 1 Changed: 1 Warnings: 0 mysql> update user set updatetime='2015-04-31 15:0:0'; 1292 - Incorrect datetime value: '2015-04-31 15:0:0' for column 'UPDATETIME' at row 1 mysql> commit; Query OK, 0 rows affected mysql> select * from user; +----+------+----------+---------------------+ | ID | NAME | PASSWORD | UPDATETIME | +----+------+----------+---------------------+ | 1 | Bill | 123456 | 0000-00-00 00:00:00 | +----+------+----------+---------------------+ 1 row in set 出现错误,不影响前面的操作,提交有效的操作。 4、strict_trans_tables比ansi严格,traditional比strict_trans_tables更严格。 5、需要说明的,ansi,strict_trans_tables,traditional是一些原子模式的组合,如下: mysql> set @@session.sql_mode='ansi'; Query OK, 0 rows affected mysql> select @@session.sql_mode; +-------------------------------------------------------------+ | @@session.sql_mode | +-------------------------------------------------------------+ | REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI | +-------------------------------------------------------------+ 1 row in set mysql> set @@session.sql_mode='strict_trans_tables'; Query OK, 0 rows affected mysql> select @@session.sql_mode; +---------------------+ | @@session.sql_mode | +---------------------+ | STRICT_TRANS_TABLES | +---------------------+ 1 row in set mysql> set @@session.sql_mode='traditional'; Query OK, 0 rows affected mysql> select @@session.sql_mode; +------------------------------------------------------------------------------------------------------------------------------------------------------+ | @@session.sql_mode | +------------------------------------------------------------------------------------------------------------------------------------------------------+ | STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | +------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set 6、mysql默认的sql mode是STRICT_TRANS_TABLES再加上两个原子模式NO_AUTO_CREATE_USER和NO_ENGINE_SUBSTITUTION,如下: mysql> select @@global.sql_mode; +----------------------------------------------------------------+ | @@global.sql_mode | +----------------------------------------------------------------+ | STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | +----------------------------------------------------------------+ 1 row in set mysql> show global variables like '%mode%'; +--------------------------+----------------------------------------------------------------+ | Variable_name | Value | +--------------------------+----------------------------------------------------------------+ | innodb_autoinc_lock_mode | 1 | | innodb_strict_mode | OFF | | slave_exec_mode | STRICT | | sql_mode | STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | +--------------------------+----------------------------------------------------------------+ 4 rows in set
Sql注入 |
1、利用sql的语法特点,绕过正常的处理流程,入侵数据库。 2、举例来说: void TestSqlInject(otl_connect& otlConn) { // 使用or string name="Andy"; string password="1' or 1='1"; // 使用注释 //string name="Andy'/*"; //string password="*/'"; char sql[1024] = {0}; sprintf(sql,"select id from user where name='%s' and password='%s'", name.c_str(), password.c_str()); otl_stream stream(1, sql, otlConn); int userId = -1; stream>>userId; } 这种情况,在只有用户名的情况就可以登入系统。 原因是拼接的sql语句,绕过了正常的条件检查。通过给name和password设置特殊的值,可以造成各种各样的sql注入, 在没有用户名的情况下,也可以登入系统。 3、sql注入产生的原因是:对用户的输入没有严格检查,导致拼接的sql语句表达了其他的语义。怎么解决? 4、方法1:不要拼接sql语句,而是使用绑定变量。 这种方法相当于,发给mysql一个框架,把空留着,MySQL解析,然后填空。在这种情况下,用户的输入,只是变量, 不能再表达其他的语义。如下: void RefuseSqlInject(otl_connect& otlConn) { // 使用or string name="Andy"; string password="1' or 1='1"; // 使用注释 //string name="Andy'/*"; //string password="*/'"; char sql[1024] = {0}; sprintf(sql,"select id from user " "where name=:Name<char[100]> and password=:Password<char[100]>"); otl_stream stream(1, sql, otlConn); int userId = -1; stream<<name<<password; stream>>userId; } 5、检查用户的输入,就是检查name,password是否包含/ * or 这一类的特殊字符或者是关键字,包含直接返回错误。 可以使用mysql自带的检查方法,也可以自己实现方法,更针对性检查。
分割后求第n个元素 |
1、考虑下面的需求,类似Andy;Bill;Caroline,用分号分割,求出第2个元素,即Bill。 2、思路:使用substring_index,substring_index(src,delimer,n)返回一个子串,子串从src的起始,到第n个delimiter结束。 对于Andy;Bill;Caroline,使用substring_index(src,';',2),取出Andy;Bill reverse,为lliB;ydnA 对于lliB;ydnA,使用substring_index(src,';',1),取出lliB 再reverse,为Bill 3、总的调用,select reverse(substring_index(reverse(substring_index('Andy;Bill;Caroline',';',2)),';',1));
- 参见
分割求总数 |
1、考虑下面的需求,类似Andy;Bill;Caroline,用分号分割,求出总数。 2、简单的思路,求出原字符串长度,将分号替换为空,求出二者的长度差,如下: select length('Andy;Bill;Caroline') - length(replace('Andy;Bill;Caroline',';','')) + 1; 注:加1是因为,三个空,会有4个栏杆。
- 参见
删除重复记录_保存Id最小的一条 |
方法1: 1、创建一个临时表,选取需要的数据。 2、清空原表。 3、临时表数据导入到原表。 4、删除临时表。 mysql> select * from student; +----+------+ | ID | NAME | +----+------+ | 11 | aa | | 12 | aa | | 13 | bb | | 14 | bb | | 15 | bb | | 16 | cc | +----+------+ 6 rows in set mysql> create temporary table temp as select min(id),name from student group by name; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0 mysql> truncate table student; Query OK, 0 rows affected mysql> insert into student select * from temp; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from student; +----+------+ | ID | NAME | +----+------+ | 11 | aa | | 13 | bb | | 16 | cc | +----+------+ 3 rows in set mysql> drop temporary table temp; Query OK, 0 rows affected 这个方法,显然存在效率问题。 方法2:按name分组,把最小的id保存到临时表,删除id不在最小id集合的记录,如下: mysql> create temporary table temp as select min(id) as MINID from student group by name; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0 mysql> delete from student where id not in (select minid from temp); Query OK, 3 rows affected mysql> select * from student; +----+------+ | ID | NAME | +----+------+ | 11 | aa | | 13 | bb | | 16 | cc | +----+------+ 3 rows in set 方法3:直接在原表上操作,容易想到的sql语句如下: mysql> delete from student where id not in (select min(id) from student group by name); 执行报错:1093 - You can't specify target table 'student' for update in FROM clause 原因是:更新数据时使用了查询,而查询的数据又做了更新的条件,mysql不支持这种方式。 怎么规避这个问题? 再加一层封装,如下: mysql> delete from student where id not in (select minid from (select min(id) as minid from student group by name) b); Query OK, 3 rows affected mysql> select * from student; +----+------+ | ID | NAME | +----+------+ | 11 | aa | | 13 | bb | | 16 | cc | +----+------+ 3 rows in set
执行sql文件,添加数据乱码 |
1、使用navicat执行sql文件,中文没有乱码。 2、直接在linux下使用mysql客户端执行,如下: mysql -uroot -p123456 --database=niu1 <t1.sql 插入的记录显示乱码 3、怎么解决? 在sql文件的开头加上 /*!40101 SET NAMES utf8 */;
查看字符串的16进制取值 |
1、使用hex可以查看字符串的16进制取值,如下: mysql> select username from user where userid=5; +----------+ | username | +----------+ | 吕欣盈 | +----------+ 1 row in set mysql> select hex(username) from user where userid=5; +---------------+ | hex(username) | +---------------+ | C2C0D0C0D3AF | +---------------+ 1 row in set 可以看到存储格式是gb2312,因为每个中文字符占用2个字节。 2、将username字段的存储格式修改为utf8,查询16进制取值,如下: mysql> select hex(username) from user where userid=5; +--------------------+ | hex(username) | +--------------------+ | E59095E6ACA3E79B88 | +--------------------+ 1 row in set 可以看到是utf8编码格式,对于utf8编码格式,一个中文字符占用3个字节。 另外:中文字符的utf8编码前4bit的取值都是E,这是因为在unicode的标准中,中文字符被框定在一个范围,前4bit都是E。
根据已有的记录增加新的记录 |
1、考虑下面的需求,根据已有的记录,增加新的记录,但是有些字段取值不一样。 2、示例如下: mysql> select * from t2; +----+----+----+---------------------+ | c1 | c2 | c3 | time | +----+----+----+---------------------+ | 1 | 1 | 1 | 2016-04-19 20:14:45 | +----+----+----+---------------------+ 1 row in set mysql> insert into t2(c1,c2,c3,time) select 5555,c2,c3,time from t2 where c1=1; Query OK, 1 row affected Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from t2; +------+----+----+---------------------+ | c1 | c2 | c3 | time | +------+----+----+---------------------+ | 1 | 1 | 1 | 2016-04-19 20:14:45 | | 5555 | 1 | 1 | 2016-04-19 20:14:45 | +------+----+----+---------------------+ 2 rows in set
Copyright (c) 2015~2016, Andy Niu @All rights reserved. By Andy Niu Edit.