编程技巧之where 1=1

编程技巧之where 1=1

最开始看到这个条件的使用是在项目的源代码中,有一条sql是这样写的:

total_sql := select count(*) from waves as ws where 1=1

我想为什么要加上这个“多余”的判断条件呢?

存在即合理

于是就去网上查找资料学习,除了这种形式之外,还有类似于where 1<>1这种写法,这种的逻辑判断结果就是恒为false,后面会说具体的使用场景是哪里

这个1=1的主要作用就是可以帮助我们构建动态sql,是一个非常不错的编码技巧,类似于我们使用链表的时候往往会加上一个dummy节点来帮助我们更加简洁清晰的构建程序,下面来看一个具体的例子:

...
total_sql := `select count(*) from waves as ws where 1=1`
	sql_temp := `select ws.ip, ws.zk, ws.create_time,ws.label, ws.update_time, ws.room, ws.cpu_core, ws.ram_capacity, ws.jdos_group, ws.room_zone 
                 from waves as ws where 1=1`

	args := make([]interface{}, 6)
	if len(zk) > 0 {
		condition := `and ws.zk = ?`
		sql_temp = fmt.Sprintf("%s %s", sql_temp, condition)
		total_sql = fmt.Sprintf("%s %s", total_sql, condition)
		args[0] = interface{}(zk)
	}
	if len(label) > 0 {
		condition := `and ws.label = ?`
		sql_temp = fmt.Sprintf("%s %s", sql_temp, condition)
		total_sql = fmt.Sprintf("%s %s", total_sql, condition)
		args[1] = interface{}(label)
	}
	if len(waveIp) > 0 {
		condition := `and ws.ip like ?`
		sql_temp = fmt.Sprintf("%s %s", sql_temp, condition)
		total_sql = fmt.Sprintf("%s %s", total_sql, condition)
		args[2] = interface{}("%" + waveIp + "%")
	}
	if len(group) > 0 {
		condition := `and ws.wave_group_name like ?`
		sql_temp = fmt.Sprintf("%s %s", sql_temp, condition)
		total_sql = fmt.Sprintf("%s %s", total_sql, condition)
		args[3] = interface{}("%" + group + "%")
	}
...

在上面的函数中,可以看到四个参数,分别是zk,label,waveIp,group

每个参数都有可能是空的值,也有可能是全部都有值,这四个条件可以用来检索我们的搜索记录,在这种条件下,如果是我,我会怎么做呢?

之前确实遇到类似的场景,我的做法就是在sql中将所有条件全部进行模糊匹配,使用like '%zk%'的形式,如果这个参数存在,那么可以搜索到,如果不存在,就进行全局匹配,看似没什么问题,但是我觉得这种实现方法不够灵活、不够优雅,如果要是规定我们只能进行定值匹配,不能进行模糊匹配,那么这种方法就拉跨了,而上面的代码中的方法就可以非常优雅的实现,也可以支持扩展,当有新的条件时,只需要继续拼接就可以了

貌似有点说跑题了,那么我们的where 1=1在里面起到了什么角色呢?

我们可以使用反证法的思想,如果要是没有这个条件,那么当一个参数不为空的时候,例如函数的形参zk不为空,那么就需要进行判断:

  • 如果前面已经有where条件,那么直接拼接就好
  • 如果没有,那么需要自己加上where

每个传入的参数都要做这样的判断,这样会让代码显的很臃肿,而使用where 1=1这个条件的话,如果一个参数不为空,那么直接拼接就好了,不用考虑前面的事情,因为前面永远有一个where 1=1在那里等着你,即使所有的参数都为空,那么我就仅执行where 1=1,也是没什么毛病

另外,这种形式的条件还有一个应用场景,就是用于表的拷贝:

拷贝表

create table_name as select * from Source_table where 1=1;

复制表结构

create table_name as select * from Source_table where 1 <> 1;

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://hadoo666.top/archives/编程技巧之where11md