注入过程中经常会遇到UNION,很多人使用时会报错,主要是不熟悉UNION的使用规则,以下分别对UNION在不同数据库下的使用注意事项解说。
1.关于UNION 与 ORDER BY
1.1 SQL SERVER
在SQL SERVER中,只有最后一个SELECT子句允许有ORDER BY 。前面的任何SELECT子句都不能有。
比如:
select name from a order by id union select content from b
会报在关键字UNION附近有语法错误。
order by 只能加在最后的select 的后面,改成这样:
select name from a union select content from b order by id
这样就正确了。
1.2 ACCESS
ACCESS中没有强制要求ORDER BY 只能出现在最后一个SELECT子句中,所以
select name from a order by id union select content from b
在ACCESS中可以正确运行。
1.3 MYSQL
MYSQL与SQL SERVER一样,强制要求ORDER BY 只能出现在最后一个SELECT子句中。
如果出现在了前面,会报错
ERROR 1221 (HY000): Incorrect usage of UNION and ORDER BY
2.关于UNION 与FROM
2.1 SQL SERVER
只要UNION连接的几个查询的字段数一样且列的数据类型转换没有问题,就可以查询出结果。
下面这样的查询也是可以的:
select 1 union select 2;
2.2 ACCESS
ACCESS的UNION好像强制要求它所连接的查询只能是select xxx from table的这种形式,
select 1 union select 2
这种查询在ACCESS里面执行的话会提示“查询输入必须包含至少一个表或者查询”
要将查询改成:
select 1 from table union select 2 from table
查询才能成功。
但是如果不用union,只是执行select 1,是允许的。
2.3 MYSQL
与SQL SERVER基本一样。唯一不一样的地方就是,如果后面跟了where,就一定要跟from
select 1 where 1=1; 在mysql里面是会报错的,但是在sql server里面没有错误。
要改成
select 1 from table where 1=1;
3.关于数据类型的转换
3.1 SQL SERVER
SQL SERVER的数据类型转换是有优先级的,低优先级的会向高优先级的进行转换。
而并不是第一个SELECT的数据类型为准。
比如:
select 1,'f' union select 1,2
上面的语句会报错,将varchar值'f'转换为......
这证明了转换不是以第一个SELECT列的数据类型为准的,虽然最终生成的列名是以第一个SELECT所用的列名为准。
下面是摘自SQL SERVER联机丛书的:
数据类型的优先顺序
当两个不同数据类型的表达式用运算符组合后,数据类型的优先顺序规则确定哪种数据类型要向另一种转换。
优先顺序低的数据类型向优先顺序高的数据类型转换。如果此转换不是所支持的固有转换,则返回错误。
当两个操作数表达式有相同的数据类型时,运算的结果就为那种数据类型。
下面是 Microsoft SQL Server 2000 数据类型的优先顺序:
sql_variant(最高)
datetime
smalldatetime
float
real
decimal
money
smallmoney
bigint
int
smallint
tinyint
bit
ntext
text
image
timestamp
uniqueidentifier
nvarchar
nchar
varchar
char
varbinary
binary(最低)
可以发现varchar比int的优先级低,所以varchar会向int进行转换,而不是int向字符串进行转换。
遇到这种情况可以使前面的查询结果为空就可以规避数据类型转换的报错,顺利执行第二个查询了。
3.2 Access
我没发现ACCESS在使用UNION的时候会有数据类型转换的问题,好像任何类型的字段都可以UNION在一起。
3.3 MYSQL
MYSQL我没找到什么讲的比较清楚的类型转换的文章。
只简单地说一下,在字符器转换为数字类型的时候,会从字符串的第一个字符开始转换,直到遇到非数字为止。
比如7sie32 转成数字就是7,8732ds8转换数字就是8732
如果第一个字符就是非数字,就转换结果就是0。
在一些低版本的MYSQL中,下面这个查询:
select 1 union select 'a';
得到的结果是1 0,a被转换成0了。
不过这个问题在4.1以后的版本就没有了。
新版本的MYSQL具体是怎么转换的不太清楚,不过好像它会自动寻找合适的数据类型。然后将UNION的那些列进行转换。
也就是说我们基本上不用考虑它在UNION时的数据类型转换问题。