preface
SQL 学过一点,但是没有怎么用,因此用的时候经常又要去看一遍教程,不如直接把经常会用到的语句给记录下来,下次直接看这一篇就行了。
本篇基于 Mysql 5.6.38,Windows 10 平台,参考廖雪峰 SQL 教程 and 菜鸟教程
操作数据库
列出所有的数据库
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| ctf |
| mysql |
| performance_schema |
| sql |
+--------------------+
5 rows in set (0.00 sec)
创建一个名叫 sql 的新数据库
mysql> CREATE DATABASE `sql`;
Query OK, 1 row affected (0.00 sec)
MySQL 中的数据库,表,字段名,一般要用 `` 包围,以区分普通字符。但有些场合不包也不会报错,因此下面有些地方我就没有用。MySQL 关键字一般用大写,但是用小写也没啥事2333
删除名叫 sql 的数据库
mysql> DROP DATABASE `sql`;
Query OK, 0 rows affected (0.00 sec)
对数据库进行操作前要切换为当前数据库
mysql> USE `ctf`;
Database changed
操作表
列出当前数据库中所有表
mysql> SHOW TABLES;
+---------------+
| Tables_in_ctf |
+---------------+
| first |
+---------------+
1 row in set (0.00 sec)
创建一个新表
mysql> CREATE TABLE IF NOT EXISTS `my_tbl`(
-> `my_id` INT UNSIGNED AUTO_INCREMENT,
-> `my_title` VARCHAR(100) NOT NULL,
-> `my_author` VARCHAR(40) NOT NULL,
-> `submission_date` DATE,
-> PRIMARY KEY ( `my_id` )
-> )ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.27 sec)
删除一个表
mysql> DROP TABLE `my_tbl`;
Query OK, 0 rows affected (0.41 sec)
查看某个表的结构
mysql> DESC first;
+--------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| name | varchar(255) | NO | | NULL | |
| age | int(10) | NO | | NULL | |
| gender | varchar(2) | NO | | NULL | |
+--------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
查看创建某个表的SQL语句
mysql> SHOW CREATE TABLE first;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table
|
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------+
| first | CREATE TABLE `first` (
`name` varchar(255) NOT NULL,
`age` int(10) NOT NULL,
`gender` varchar(2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
用 ALTER 对表进行修改
给表新增一列 birth 字段
mysql> ALTER TABLE `first` ADD COLUMN birth VARCHAR(10) NOT NULL;
Query OK, 0 rows affected (2.32 sec)
Records: 0 Duplicates: 0 Warnings: 0
修改 birth 名为 birthday,类型改为 VARCHAR(20)
mysql> ALTER TABLE `first` CHANGE COLUMN `birth` `birthday` VARCHAR(20) NOT NULL;
Query OK, 4 rows affected (2.42 sec)
Records: 4 Duplicates: 0 Warnings: 0
删除 birthday 列
mysql> ALTER TABLE `first` DROP COLUMN `birthday`;
Query OK, 0 rows affected (2.20 sec)
Records: 0 Duplicates: 0 Warnings: 0
操作数据
INSERT 插入
通用语法
INSERT INTO table_name ( field1, field2,...fieldN )
VALUES
( value1, value2,...valueN );
上面这样的话就插入了一条记录,也可以一次性插入好多条记录:
mysql> INSERT INTO first (name, gender, age)
-> VALUES
-> ('Susan', 'f', 21),
-> ('Rose', 'f', 20);
Query OK, 2 rows affected (0.89 sec)
Records: 2 Duplicates: 0 Warnings: 0
DELETE 删除
通用语法
DELETE FROM table_name [WHERE Clause]
不用 where
条件的话整个表都会被删除,可以在 where
中指定任何条件,比如下面这段代码就删除了 age 为 12 的记录:
mysql> DELETE FROM first WHERE age=12;
Query OK, 1 row affected (0.05 sec)
UPDATE 修改
通用语法
UPDATE table_name SET field1=new-value1, field2=new-value2
[WHERE Clause]
可以同时更新多个字段,一般是配合 where
使用,更新指定行的数据,下面我们更新 yuhui 的年龄:
mysql> UPDATE first SET age=18 WHERE name='yuhui';
Query OK, 1 row affected (1.69 sec)
Rows matched: 1 Changed: 1 Warnings: 0
查询一下,已经被更新了:
mysql> SELECT * FROM first WHERE name='yuhui';
+-------+-----+--------+
| name | age | gender |
+-------+-----+--------+
| yuhui | 18 | f |
+-------+-----+--------+
1 row in set (0.00 sec)
SELECT 查询
通用语法
SELECT column_name1,column_name2
FROM table_name1, table_name2
[WHERE Clause]
[LIMIT N][ OFFSET M]
查询语句可以在多个表中查询,并且可以查询多个字段,返回的是一条或多条记录,可以用 LIMIT
属性来设定返回的记录数,用 OFFSET
指定 SELECT
语句开始查询的数据偏移量,默认情况下是 0,如果想查询所有字段信息的话,可以用 *
来代替 column_name
mysql> SELECT `name`, `age` FROM `first` WHERE `gender`='f';
+-------+-----+
| name | age |
+-------+-----+
| chan | 17 |
| yuhui | 18 |
| kaiyi | 20 |
+-------+-----+
3 rows in set (0.00 sec)
limit 关键字
limit 可以限制输出记录的条数,通用语法如下
select _column,_column from _table [where Clause] [limit N][offset M]
其中,N 是指返回的记录的条数,M 是从第几条记录开始查询,默认是 0,上面的语句又可以写成下面这样表示返回 N 条记录,偏移量为 M
select _column,_column from _table [where Clause] [limit M, N]
MariaDB [security]> select * from users limit 1 offset 0;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | Dumb |
+----+----------+----------+
MariaDB [security]> select * from users limit 0, 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | Dumb |
+----+----------+----------+
和系统有关的函数
MySQL 中有些函数可以获取系统以及当前数据表的一些信息,比如 user()
获取当前登录用户,database()
获取当前数据库名,version()
获取当前数据库版本,@@version_compile_os
获取当前操作系统名,@@datadir
获取数据库所在的路径
MariaDB [security]> select database();
+------------+
| database() |
+------------+
| security |
+------------+
MariaDB [security]> select version();
+-------------------+
| version() |
+-------------------+
| 10.3.20-MariaDB-1 |
+-------------------+
MariaDB [security]> select user();
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
MariaDB [security]> select @@version_compile_os;
+----------------------+
| @@version_compile_os |
+----------------------+
| debian-linux-gnu |
+----------------------+
MariaDB [security]> select @@datadir;
+-----------------+
| @@datadir |
+-----------------+
| /var/lib/mysql/ |
+-----------------+
order by
查询的结果根据某字段进行排序,常用格式如下
SELECT field1, field2,...fieldN FROM table_name1, table_name2...
ORDER BY field1 [ASC [DESC][默认 ASC]], [field2...] [ASC [DESC][默认 ASC]]
其中呢我们可以通过 ASC 和 DESC 来指定升序还是降序,默认情况下是升序,而且也可以用数字来代替字段名,如 1 代表第一个字段,2 代表第二个字段
MariaDB [dvwa]> select first_name, last_name from users order by first_name;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| admin | admin |
| Bob | Smith |
| Gordon | Brown |
| Hack | Me |
| Pablo | Picasso |
+------------+-----------+
MariaDB [dvwa]> select first_name, last_name from users order by 1;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| admin | admin |
| Bob | Smith |
| Gordon | Brown |
| Hack | Me |
| Pablo | Picasso |
+------------+-----------+
union 联合查询
在 sql 注入中 union 注入是非常常见的一种,union 查询一般语法如下
SELECT expression1, expression2, ... expression_n
FROM tables
[WHERE conditions]
UNION [ALL | DISTINCT]
SELECT expression1, expression2, ... expression_n
FROM tables
[WHERE conditions];
也就是将多个表中查询出来的结果放在一起,但是要注意,前后查询的字段数一定要一致,否则就会报错,如果前后查询的数据有重复的话,MySQL 默认是将重复的数据给删除,这和 DISTINCT 关键字的功能一样,如果想保留相同记录的话可以用 union ALL ,返回所有的结果集
MariaDB [dvwa]> select first_name, last_name from users union select username from security.users;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
# 前后查询字段数不一样所以报错
MariaDB [dvwa]> select first_name from users union select username from security.users;
+------------+
| first_name |
+------------+
| admin |
| Gordon |
| Hack |
| Pablo |
| Bob |
| admin1 |
+------------+
MariaDB [dvwa]> select first_name from users union ALL select username from security.users;
+------------+
| first_name |
+------------+
| admin |
| Gordon |
| Hack |
| Pablo |
| Bob |
| admin |
| admin1 |
+------------+
sql 注入时经常让前面一个查询的结果是假的,这样就可以只输出后面一句查询的结果,防止无效的信息干扰
MariaDB [dvwa]> select first_name from users where 1=2 union select username from security.users;
+------------+
| first_name |
+------------+
| admin |
| admin1 |
+------------+
group by 分组
分组一般和聚合函数一起用,聚合函数就是 SUM(), AVG(), COUNT() 等用于统计的一些函数,总的来说就是用在一些有重复记录的情况,比如表的名字叫做九年级,字段有班级和名字,要想统计每个班有多少学生就可以按照班级这个字段来进行分组
我们用一个表来说明一下分组是怎么使的
mysql> select * from first;
+--------+-----+--------+
| name | age | gender |
+--------+-----+--------+
| kevin | 18 | m |
| chan | 17 | f |
| ddddhm | 20 | fk |
| yuhui | 18 | f |
| kaiyi | 20 | f |
+--------+-----+--------+
这里有些重复的字段记录,比如 gender 为 f 的有三个,我们就按照 gender 来分个组
mysql> select gender, age, name from first group by gender;
+--------+-----+--------+
| gender | age | name |
+--------+-----+--------+
| f | 17 | chan |
| fk | 20 | ddddhm |
| m | 18 | kevin |
+--------+-----+--------+
欸?怎么回事,怎么就三条记录了,其实分组之后我们可以看作单元格合并,也就是相同的 f 列的数据都合在了一个大的单元格里面,但是 select 总不能够取出两条记录来吧,所以他只取一条记录,不是说了吗,分组一般是用来统计的,所以不太关心具体的数据是啥,只关心有几条记录,用 count 来看一下
mysql> select gender, count(*) from first group by gender;
+--------+----------+
| gender | count(*) |
+--------+----------+
| f | 3 |
| fk | 1 |
| m | 1 |
+--------+----------+
这就好了, gender 为 f 的有三条记录,其余的记录为 1,这就是分组的一个简单实践