SQL 基础语法的详细归纳

栏目: 数据库 · 发布时间: 5年前

内容简介:做安全最困难的恐怕就是知识点过于杂碎,涉及面过于广阔,所以趁还记得,没事就总结完善备忘一下(参考一些资料,并加入一些自己使用过程中的理解),以防老了失忆,平时短路了拿出来查一下也是不错的。mysql 中 select 命令中允许不出现数据库或者数据表的名字,也就是可以没有 from ,这种情况下能将执行结果返回成一个单行单列的表格,例如 select now();返回当前时间。select count(列) … 可以确定数据表中的记录条数

做安全最困难的恐怕就是知识点过于杂碎,涉及面过于广阔,所以趁还记得,没事就总结完善备忘一下(参考一些资料,并加入一些自己使用过程中的理解),以防老了失忆,平时短路了拿出来查一下也是不错的。

0X01 基本语法

这一小节主要介绍的是一些增删改查的基本语法

(1)select

mysql 中 select 命令中允许不出现数据库或者数据表的名字,也就是可以没有 from ,这种情况下能将执行结果返回成一个单行单列的表格,例如 select now();返回当前时间。

(2)count()

select count(列) … 可以确定数据表中的记录条数

(3)limit offset,n

limit offset,n 指定输出从 offset 开始的 n 条数据 , 其中 offset 是从 0 开始的 ,例如 limit 2,2 表示跳过两条数据,从第三条数据开始输出第三第四条数据(offset 不写时,默认为0)

(4)order by

order by column 表示按照某一列对查询结果进行排序

(5)where/having

where/having 表示对行进行筛选,其中 where 的优先级高于 Having ,having 可以和 group by 配合使用,但是 where 不可以

(6)join

select table1.xxx,table2.xxx from table1 left join table2 on table1.yyy=table2.zzz/using(xxx); 是用来扩展查询结果的列的,两个表有键值是关联的,如果没有关联就相当于笛卡尔积,没什么太大的意义

下表是常用的一些语句模型

SQL 基础语法的详细归纳

(7)union

union 实现的是行的扩展,它将两个查询的结果合并在一起,并要求两个查询的列个数相同,数据类型相同,如果不同,系统将会自动将 union 后面的数据的类型转换成前面的对应类型(union 是 mysql 中唯一的集合分隔符)

(8)group by

group by 配合如 count() sum() min() max() 等统计函数 计算有相同字段的行的另一些字段的统计数据,如果是想输出有相同字段的行的另一字段的所有数据,可以使用 group_concat() 这个统计函数,否则只能输出第一个,group by … with rollup 可以在结果的最后一行添加一个计算总和的行

(9)备份与还原数据表

备份:

create table newtable select * from oldtable;

还原:

delete from oldtable;
insert into oldtable select * from newtable;

(10)备份和还原数据库

使用外部工具 mysqldump

备份:

mysqldump -u loginame -p   dbname > backupfile

还原:

没有专门的恢复工具,我们直接使用下面的命令

mysql -u loginame -p   dbname < backupfile

或者我们直接就能在交互模式下重建

create database dbname;
use dbname;
source backupfile;

(11)插入数据

intert into tablename(column1,column2...) values (value1,value2...),(value3,value4...);

(12)更新数据

update tablename set column1=value1,column2=value2,...where columnID=ID;

(13)删除数据

delect from tablename where ID=ID;

(14)修改数据表

增加一个数据列:

alert table tablename add columnname clotype clooptions;

修改一个数据列:

alert table tablename change oldcolname newcolname coltype coloptions;

(15)information_schema 数据表家族

这是在 mysql5.0 以后引入的机制,有了这个机制,我们能在这些数据表中使用 select 命令检索有关数据库、数据表、数据列的元数据。

这是一个非常重要的机制,最明显的体现就在于使用 sqlmap 跑 MySQL 数据库的时候为什么那么方便,分分钟就能把所有的数据库和表列出来,有些名字甚至是很复杂的都没有丝毫的影响,但是如果你尝试跑 sql server 的数据库,你就会发现情况大不相同, sqlmap 会告诉你需要进行暴力破解,然后就会从他自带的字典中开始遍历,不仅时间非常的长,而且效果也很差,一些自定义的不常见的名字永远都不可能猜出来。

注意一下, information_schema 这个数据库是虚拟的,是在计算机上没有对应的文件的(我们知道数据库也是一个文件,都存储在计算机上,只不过不是纯文本文件罢了,有时候我们还能利用这个文件进行

getshell操作)

所以我们也不能直接使用 use information_schema 、show databases 、select * from information_schema.schemata 来查看有关信息

但是我们能通过 show tables from information_schema 、show columns from information_schema.columns 查看这个数据库内部的信息

mysql> select * from information_schema.schemata;
+--------------+--------------------+----------------------------+------------------------+----------+
| CATALOG_NAME | SCHEMA_NAME        | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH |
+--------------+--------------------+----------------------------+------------------------+----------+
| def          | information_schema | utf8                       | utf8_general_ci        | NULL     |
| def          | ctf                | utf8                       | utf8_general_ci        | NULL     |
| def          | employees          | utf8                       | utf8_general_ci        | NULL     |
| def          | mysql              | utf8                       | utf8_general_ci        | NULL     |
| def          | performance_schema | utf8                       | utf8_general_ci        | NULL     |
| def          | test               | latin1                     | latin1_swedish_ci      | NULL     |
| def          | world              | utf8                       | utf8_general_ci        | NULL     |
+--------------+--------------------+----------------------------+------------------------+----------+
7 rows in set (0.00 sec)

我们来看看这个数据库中有哪些表,它们分别对应着什么数据

SQL 基础语法的详细归纳

还要补充的一点是,information_schema 数据表对所有用户开放而无视权限

0X02 解决方案

这一小节主要介绍的是一些一些实用的函数或者技巧

1.字符串操作

(1)合并字符串

concat(str1,str,str3...);
concat_ws(separator ,str1 ,str2 ,…);

(2)截取字符串

1.substring(str,pos,n);/substr(str,pos,n);/mid(str,pos,n);

mysql> select substring('www.baidu.com','5',5);
+----------------------------------+
| substring('www.baidu.com','5',5) |
+----------------------------------+
| baidu                            |
+----------------------------------+
1 row in set (0.00 sec)

注意:

(1)这里的 pos 是从 1 开始的,而不是从 0;

(2)n 不写时表示取到字符串末尾

2.letf(str,len); 返回从第一个字符开始的 len 个字符

3.right(str,len); 返回从最后一个字符开始的len 个字符

4.substring_index(str,delim,count);

mysql> select substring_index('www.baidu.com','.',1);
+----------------------------------------+
| substring_index('www.baidu.com','.',1) |
+----------------------------------------+
| www                                    |
+----------------------------------------+
1 row in set (0.00 sec)

mysql> select substring_index('www.baidu.com','.',2);
+----------------------------------------+
| substring_index('www.baidu.com','.',2) |
+----------------------------------------+
| www.baidu                              |
+----------------------------------------+
1 row in set (0.00 sec)

mysql> select substring_index('www.baidu.com','.',-2);
+-----------------------------------------+
| substring_index('www.baidu.com','.',-2) |
+-----------------------------------------+
| baidu.com                               |
+-----------------------------------------+
1 row in set (0.10 sec)

(3)计算字符串长度

char_length()/character_length() 和 length()/octet_length()

注意:char_length()/character_length() 计算的是字符的个数,而length()/octet_length() 计算的是字节的长度

但是我在测试的时候发现即使使用中文两者的结果还是一样的,都是按照字节去计算的,可能需要进一步考证

mysql> select LENGTH('你好');
+----------------+
| LENGTH('你好')     |
+----------------+
|              4 |
+----------------+
1 row in set, 1 warning (0.00 sec)

mysql> select CHAR_LENGTH('你好');
+---------------------+
| CHAR_LENGTH('你好')     |
+---------------------+
|                   4 |
+---------------------+
1 row in set, 1 warning (0.00 sec)

(4)改变存储的字符串

将 colname 列的双引号换成单引号

replace(colname,'"','\'');

(5)判断子字符串在字符串中出现的位置

1.locate()

返回子串 substr 在字符串 str 中第一次出现的位置。如果子串 substr 在 str 中不存在,返回值为 0:

LOCATE(substr,str);

例如:

mysql> SELECT LOCATE('bar', ‘foobarbar'); 
-> 4 
mysql> SELECT LOCATE('xbar', ‘foobar'); 
-> 0

返回子串 substr 在字符串 str 中的第 pos 位置后第一次出现的位置。如果 substr 不在 str 中返回 0 :

LOCATE(substr,str,pos)

例如:

mysql> SELECT LOCATE('bar', ‘foobarbar',5); 
-> 7

2.instr()

在一个字符串 str 中搜索指定的字符 substr,返回其第一次出现的位置 index ,其中 index 从 1 开始,如果不存在返回 0 ;

instr(str,substr);

例如:

instr('123', '12');
->1  

instr('123', '23');
->2

3.position()

是 locate() 的别名,用法完全一样

4.find_in_set()

FIND_IN_SET(str,strlist)
  1. 假如字符串str在由N子链组成的字符串列表strlist中,则返回值的范围在1到N之间。

  2. 一个字符串列表就是一个由一些被‘,’符号分开的自链组成的字符串。

  3. 如果第一个参数是一个常数字符串,而第二个是typeSET列,则FIND_IN_SET()函数被优化,使用比特计算。

  4. 如果str不在strlist或strlist为空字符串,则返回值为0。

  5. 如任意一个参数为NULL,则返回值为NULL。这个函数在第一个参数包含一个逗号(‘,’)时将无法正常运行。

注:strlist:一个由英文逗号“,”链接的字符串,例如:”a,b,c,d”,该字符串形式上类似于SET类型的值被逗号给链接起来。

例如:

SELECT FIND_IN_SET('b','a,b,c,d'); //返回值为2,即第2个值

(6)正则匹配

1.like

like 常用通配符:% 、_ 、escape

% : 匹配0个或任意多个字符

_ : 匹配任意一个字符

escape : 转义字符,可匹配%和_。如SELECT * FROM table_name WHERE column_name LIKE '/%/_%_' ESCAPE'/'

2.regexp/rlike

rlike和regexp:常用通配符:. 、* 、 [] 、 ^ 、 $ 、{n}

. : 匹配任意单个字符

* : 匹配0个或多个前一个得到的字符

[] : 匹配任意一个[]内的字符,[ab]*可匹配空串、a、b、或者由任意个a和b组成的字符串。

^ : 匹配开头,如^s匹配以s或者S开头的字符串。

$ : 匹配结尾,如s$匹配以s结尾的字符串。

{n} : 匹配前一个字符反复n次。

注意:

(1)rlike 和 regexp 并不是完全匹配,而是只要模板匹配字符串的一部分就可以了,但是 like 是完全匹配

(2) Like 和 rlike 和 regexp 都是不区分大小写的

3.字符串的二进制比较

我们想要区分大小写就要通过这种二进制比较的方式

mysql> select "A" = "a";
+-----------+
| "A" = "a" |
+-----------+
|         1 |
+-----------+
1 row in set (0.00 sec)

mysql> select "A" = BINARY "a";
+------------------+
| "A" = BINARY "a" |
+------------------+
|                0 |
+------------------+
1 row in set (0.10 sec)

(7)自定义排序

1.elt()

ELT(N ,str1 ,str2 ,str3 ,…)

函数使用说明:若 N = 1 ,则返回值为 str1 ,若 N = 2 ,则返回值为 str2 ,以此类推。 若 N 小于 1 或大于参数的数目,则返回值为 NULL 。 ELT() 是 FIELD() 的补数

mysql> SELECT ELT(3,'hello','halo','test','world');
+--------------------------------------+
| ELT(3,'hello','halo','test','world') |
+--------------------------------------+
| test                                 |
+--------------------------------------+
1 row in set

盲注中我们可以这样将其作为开关

mysql> select ELT(1,1);
+----------+
| ELT(1,1) |
+----------+
| 1        |
+----------+
1 row in set (0.00 sec)

mysql> select ELT(1,0);
+----------+
| ELT(1,0) |
+----------+
| 0        |
+----------+
1 row in set (0.00 sec)

2.field()

FIELD(str, str1, str2, str3, ……)

order by field(str,str1,str2,str3,str4……),str与str1,str2,str3,str4比较,其中str指的是字段名字,

意为:字段str按照字符串str1,str2,str3,str4的顺序返回查询到的结果集。如果表中str字段值不存在于str1,str2,str3,str4中的记录,放在结果集最前面返回。

假如说表是这样的:

root@localhost|iris>select * from ta;
+----+--------+------+-------+
| id | name   | age  | class |
+----+--------+------+-------+
|  1 | iris   |   11 | a1    |
|  2 | iris   |   22 | a2    |
|  3 | seiki  |   33 | a3    |
|  4 | seiki  |   44 | a4    |
|  5 | xuding |   55 | a5    |
|  6 | xut    |   66 | a6    |
|  7 | iris   |   12 | a2    |
|  8 | iris   |   24 | a4    |
|  9 | seiki  |   36 | a6    |
| 10 | seiki  |   48 | a8    |
| 11 | xuding |   50 | a0    |
| 12 | xut    |   77 | a7    |
+----+--------+------+-------+
12 rows in set (0.00 sec)

按照’seiki’,’iris’,’xut’来排序,结果如下:

root@localhost|iris>select * from ta order by field(name,'seiki','iris','xut');
+----+--------+------+-------+
| id | name   | age  | class |
+----+--------+------+-------+#不在str1,str2,str3中的内容,放在最前面返回,str值相同按照主键的顺序
|  5 | xuding |   55 | a5    |
| 11 | xuding |   50 | a0    |
|  3 | seiki  |   33 | a3    |
|  4 | seiki  |   44 | a4    |
|  9 | seiki  |   36 | a6    |
| 10 | seiki  |   48 | a8    |
|  1 | iris   |   11 | a1    |
|  2 | iris   |   22 | a2    |
|  7 | iris   |   12 | a2    |
|  8 | iris   |   24 | a4    |
|  6 | xut    |   66 | a6    |
| 12 | xut    |   77 | a7    |
+----+--------+------+-------+
12 rows in set (0.00 sec)

当然这是正常的用法,但是其实还可以这样理解,这个函数返回的是str 在后面这些字符串中的索引

mysql> SELECT FIELD('halo','hello','halo','test','world');
+---------------------------------------------+
| FIELD('halo','hello','halo','test','world') |
+---------------------------------------------+
|                                           2 |
+---------------------------------------------+
1 row in set

其实我们还可以把这个函数看成是一个开关,或许在盲注的时候能代替 if ,例如下面这样

mysql> select FIELD(1,0);
+------------+
| FIELD(1,0) |
+------------+
|          0 |
+------------+
1 row in set (0.00 sec)

mysql> select FIELD(1,1);
+------------+
| FIELD(1,1) |
+------------+
|          1 |
+------------+
1 row in set (0.00 sec)

这里的第二个参数决定了这条语句的执行结果,和 if 还是比较类似的,有时候出现 NULL 的时候还可以配合 isnull() 这个函数将其转换成 布尔值,这里提一下,说不定也能用的到。

2.变量与条件表达式

(1)变量

mysql 5.0 以后开始支持存储过程,变量是存储过程中比较重要的元素,MySQL 的变量分为三个类型

1.变量类型:

1.普通变量:以@开头,在 sql 连接关闭时失去内容

2.系统变量:以@@开头,表示的是mysql 服务器的工作状态和属性,许多系统变量有两种形式,一种表示当前连接 @@session.wait_timeout,另一种表示mysql 服务器 @@global.wait_timeout

mysql> select @@session.wait_timeout;
+------------------------+
| @@session.wait_timeout |
+------------------------+
|                  28800 |
+------------------------+
1 row in set (0.00 sec)

mysql> select @@global.wait_timeout;
+-----------------------+
| @@global.wait_timeout |
+-----------------------+
|                 28800 |
+-----------------------+
1 row in set (0.00 sec)

3.存储过程的局部变量:没有特殊的标志,只在存储过程内有效

2.变量赋值:

变量赋值有两种方式

1.set 赋值的时候 使用 =

2.select 赋值的时候使用 := 或者是 into

mysql> set @varname = 3;
Query OK, 0 rows affected (0.00 sec)

mysql> select @varname;
+----------+
| @varname |
+----------+
|        3 |
+----------+
1 row in set (0.00 sec)

mysql> select @varname := 4;
+---------------+
| @varname := 4 |
+---------------+
|             4 |
+---------------+
1 row in set (0.00 sec)

mysql> select @varname;
+----------+
| @varname |
+----------+
|        4 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from bsqli into @varname;
Query OK, 1 row affected (0.32 sec)

mysql> select @varname;
+----------+
| @varname |
+----------+
|        2 |
+----------+
1 row in set (0.00 sec)

2.变量赋值:

我们可以使用表达式给变量赋值,请看下面的实验

mysql> select ID ,@rownum:=@rownum+1 as rownum from city order by ID limit 10;
+----+--------+
| ID | rownum |
+----+--------+
|  1 |     11 |
|  2 |     12 |
|  3 |     13 |
|  4 |     14 |
|  5 |     15 |
|  6 |     16 |
|  7 |     17 |
|  8 |     18 |
|  9 |     19 |
| 10 |     20 |
+----+--------+
10 rows in set (0.00 sec)

这样就实现了逐个增加,是不是很神奇?我们再来看下面的测试

mysql> select @b:=@b is not null;
+--------------------+
| @b:=@b is not null |
+--------------------+
|                  0 |
+--------------------+
1 row in set (0.00 sec)

mysql> select @b:=@b is not null;
+--------------------+
| @b:=@b is not null |
+--------------------+
|                  1 |
+--------------------+
1 row in set (0.00 sec)

这个怎么理解呢?我们先来看赋值号后面的这个表达式

@b is not null

由于 @b 并没有在当前的会话中定义过,于是一开始是 null ,然后我们做了个判断,判断 @b 不是 null ,很明显这个得到的是假,也就是 0 ,那么再执行完这个语句之后 @b 就被赋值为 0 ,当第二次再执行的时候就是判断 0 不是 Null ,这次肯定是真,于是返回1 此时 @b 就被赋值为1

这样就达到了在同一个会话中,相同的语句执行结果不同的效果,之前在 LCTF2018 中有一道题就是利用这种方式去做的,但是没人解出来。

(2)条件表达式

1.if(condition,result1,result2);

当 condition 结果为真时返回 result1 否则返回 result2,这常常用作我们盲注的开关函数,

mysql> select if(1,1,0);
+-----------+
| if(1,1,0) |
+-----------+
|         1 |
+-----------+
1 row in set (0.00 sec)

mysql> select if(0,1,0);
+-----------+
| if(0,1,0) |
+-----------+
|         0 |
+-----------+
1 row in set (0.00 sec)

2.case(…)when…then…else…end

case 有两种变体

(1)case expr when val1 then result1 when val2 then result2 else result3 end;

就是会判断 expr 的结果 ,根据结果是 val1 还是 val2 或者其他,来执行不同的语句

(2)case when condition1 then result1 when condition2 result2 else result3 end;

这种就是不判断值,直接根据不同情况进行选择

比如可以构造这样一条注入语句

select * from test where id =-1 union select 1,case when username like 'a%' then 0 else 2222222222222222222 end,3,4 from tdb_admin

3.子查询

(1)模板一

select ... from ... where col = [any|all](select...);

1.在这个变体里,子查询的返回结果必须是一个离散值(一行一列),用来和 col 进行比较操作,这里的比较操作符=还可以是 > >= < <= <>

2.当前面有修饰符的时候,前面的修饰符可以是 any/some( 这两个同义)和 all,这时子查询可以返回多个值,col = any… 等同于 col = in … ,当前面的修饰符是 all 的时候只有两种情况能让 operator all 的返回结果为真,一种是在所有的值都能满足这个 operator 条件时,另一种是在 select 子查询没有任何返回结果时

(2)模板二

select ....from ... where col [not]in(select...);

此时select 子查询的返回结果可以是一个离散值的列表

(3)模板三

select row(value1,valu2...) = [any/some](select col1,col2...);

该语句查询数据表中师傅存在一条对应的记录,子查询返回的结果是一组离散值,但是当使用 any 或者其同义词 some 修饰的时候可以返回多组离散值,其中只要有一组满足条件结果则为真

(4)模板四

select ... from ...where col [not]exists(select...);

(5)模板五

select ... from (select ...) as name where ...

外层 select 查询的是内层 select 查询出来的临时表,MySQL 要求这种临时表必须通过 as name 的形式给予别名

注意:mysql 不允许在子查询中使用 limit ,limit 一定是在最外层并且最后运行的

(6)补充

当然除了上面这几种类别以外,子查询的位置还能放在 select 后面作为选择列,或者放在 order by 后面作为拍序列,但是在 sql 注入中子查询的缺点是不能回显,union 倒是可以,只要有回显位,但是现在能回显的越来越少了,一般都是盲注什么的。

0X03 其他细节

(1)命名规则:

数据库、数据表、数据字段等数据库对象的名字长度最多达到64字符,允许使用的字符是 MySQL 允许使用的字符集中的所有数字字母符号以及 _ 和 $

注意:

(1)包含特殊字符和保留字的名字一般不被使用,但是还是可以通过添加 反引号的方式来使用,但是同样这样的字段是没法直接用命令行查询的,查询的时候也要带上反引号

(2)当使用不在该数据库的数据表的时候,要使用 数据库.数据表 的形式,同理,如果遇到不能区分的列,也要使用类似的方式进行区分

(2)字符串

字符串可以用单引号包裹也可以用双引号,当出现引号里面还有引号的使用,必须使用不同的引号加以区分,或者使用反斜杠进行转义

MySQL 支持使用 16进制值表示对象

(3)数值

1.MySQL 支持十进制使用小数点,并且可以使用 用e 表示的科学计数法表示很大或者很小的数值

2.MYSQL 支持使用 0x 或者 x’12121’ 表示16进制数据

mysql> select 0x4142434445464748494a;
+------------------------+
| 0x4142434445464748494a |
+------------------------+
| ABCDEFGHIJ             |
+------------------------+
1 row in set (0.00 sec)

mysql> select x'4142434445464748494a';
+-------------------------+
| x'4142434445464748494a' |
+-------------------------+
| ABCDEFGHIJ              |
+-------------------------+
1 row in set (0.00 sec)

3.MySQL 支持进制之间的隐式转换,比如 16进制加一个十进制的数会变成十进制

mysql> select 0x41;
+------+
| 0x41 |
+------+
| A    |
+------+
1 row in set (0.00 sec)

mysql> select 0x41+0;
+--------+
| 0x41+0 |
+--------+
|     65 |
+--------+
1 row in set (0.00 sec)

4.MySQL 支持字符串和数值之间的转换,字符串在和数值运算时会将字符串转换成数值(开头部分是数值则转化成对应数值,如果不是数值则自动转化成0)

mysql> select "112.3456asdasd"+1;
+--------------------+
| "112.3456asdasd"+1 |
+--------------------+
|           113.3456 |
+--------------------+
1 row in set, 1 warning (0.00 sec)

5.MySQL 5.03 开始支持二进制数值,可以表示为 b’100110’ 的形式

(4)注释

1.单行注释:# 和 – (后面有一个空格)

2.多行注释:/

*/

3.内联注释:`/

!*/`

以上所述就是小编给大家介绍的《SQL 基础语法的详细归纳》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

AI极简经济学

AI极简经济学

阿杰伊·阿格拉沃尔、乔舒亚·甘斯、阿维·戈德法布 / 闾佳 / 湖南科技出版社 / 2018-12-1 / 58.00

人工智能正在以不可阻挡的态势席卷全球。无论是iPhone的神经网络引擎、AlphaGo的围棋算法,还是无人驾驶、深度学习……毫无疑问,人工智能正在改写行业形态。如同此前个人电脑、互联网、大数据的风行一般,技术创新又一次极大地改变了我们的工作与生活。 那么,究竟应该如何看待人工智能?在《AI极简经济学》一书中,三位深耕人工智能和决策领域的经济学家给出了清晰的答案。他们以坚实的经济学理论剖析动态,把握......一起来看看 《AI极简经济学》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具