sql语句中的where 1=1
接触到实际的代码以后,在一些数据库的查询语句中,有时候会在语句的where 关键字的后面,紧跟上一句"1=1",在这里,写一下我的一些思考
where后面加"1=1"还是不加
比如现在有一个场景,DB数据库中有一张表(table_name),想把table_name表中的所有记录查询出来,那么可以有两种方式操作。一种写法是where关键词什么也不加,另一种写法是where关键词后面加"1=1",写法如下:
- where关键词什么也不加
select * from table_name;
- where关键词后面加 "1=1"
select * from table_name where 1 = 1;
这两种SQL语句查询所得到的结果完全没有区别。那为什么要在where关键字后面添加"1=1"呢?
不用where 1=1 在多条件查询的困扰
举个例子,如果你想查看当前表中某条记录时,那么按照平时的查询语句的 动态构造,代码大体如下:
select * from table_name where <if test="null != id"> id = #{req.id} </if> <if test=' null != req.name and req.name !="" ' > and name = #{req.rname} </if>
如果上述的两个if判断语句均为true时,那么最终的动态SQL语句为:
select * from table_name where id = ** and name = *** ;
可以看出来这是一条完整的正确的SQL查询语句,能够正确执行。
如果上述的两个if判断语句均为false时,那么最终的动态SQL语句为:
select * from table_name where;
如果第一个条件错误,会生成如下语句
select * from table_name where and name=***
此时我们看看后面这两条生成的SQL语句,由于where关键字后面需要使用条件,但是这条语句根本不存在,所以这两条语句出现语法错误,不能被执行,不仅报错,同时还查不到任何数据。
使用where 1=1 的好处
如果我们在where条件后加上1=1:
select * from table_name where 1=1 <if test="null != id"> and id = #{req.id} </if> <if test=' null != req.name and req.name !="" ' > and name = #{req.name} </if>
当条件 1和条件 2都为真时,上面被执行的SQL代码为:
select * from table_name where 1=1 and id = ** and name = *** ;
可以看出来这是一条完整的正确的SQL查询语句,能够正确执行。
如果上述的两个if判断语句均为false时,那么最终的动态SQL语句为:
select * from table_name where 1=1;
如果第一个条件错误,会生成如下语句
select * from table_name where 1=1 and name=***
其实,where 1=1的应用,不是什么高级的应用,也不是所谓的智能化的构造,仅仅只是为了满足多条件查询页面中不确定的各种因素而采用的一种构造一条正确能运行的动态SQL语句的一种方法。
使用where 1=1 的坏处
我们在写SQL时,加上了1=1后虽然可以保证语法不会出错!
select * from table_name where 1=1;
但是因为table中根本就没有名称为1的字段,该SQL其实等效于select * from table,这个SQL语句很明显是全表扫描,需要大量的IO操作,数据量越大越慢。
所以在查询时,where1=1的后面需要增加其它条件,并且给这些条件建立适当的索引,效率就会大大提高。
但是,更重要的是,如果这句话在使用sql注入时,配合or运算符,会造成巨大的破坏性
例如,当我们要删除数据时
delete from table_name where id = 1
数据库会正确删除指定的这条数据,但是,如果配合where 1=1 的条件,结果因为添加了or 1=1的永真条件,会导致整张表里的记录都被删除了。
delete from table_name where id = 1 or 1=1
注意delete的时候这种事千万注意,这里只是为了表述where 1=1的作用之一。
在一个and链接的操作里,select会不会影响效率
不会,对于大部分的数据库来说,优化器会将该语句优化掉,
例如,在mysql中,
EXPLAIN EXTENDED SELECT id FROM room_info WHERE 1=1 and id <10; SHOW WARNINGS;
优化后的语句是
select `test`.`abc`.`id` AS `id` from `test`.`abc` where (`test`.`abc`.`id` < 10)
你会发现 1=1 被优化器移除了。
其他作用
建表可以用到:
create table table_abc as select * from abc_table where 1<>1
建成一个table_abc与abc_table 结构相同的表,但是不要abc_table 里的数据。
create table table_abc as select * from abc_table where 1=1
建成一个table_abc与abc_table 结构相同的表,但是需要abc_table 里的数据。
建议
为了防止sql注入等问题,建议尽量少使用where 1=1
在mybatis也提供了<where>来解决多条件查询拼接的问题,例如:
select * from table_name <where> <if test = " id != null "> and id = #{id} </if> <if test = " name != null and name != '' "> and name = #{name} </if> </where>
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入WHERE子句。而且,若语句的开头为AND或OR,where 元素也会将它们去除。