mysql在子查询中使用自定义变量和条件语句实现函数效果的查询语句
mysql在子查询中使用自定义变量和条件语句实现函数效果的查询语句
- 前言
- 自定义变量和条件语句语法规则
- 自定义变量规则
- 条件语句
- 例题简介
- 思路解析
- 方法1:同表多连接
- 方法2:子查询(自定义变量)
- 方法2详解
- 总结
前言
mysql
语法简单,但也正因如此,在检索稍微复杂的数据时,有时可能需要连续的子查询的嵌套以及表连接的组合应用,其逻辑上的循环嵌套远不如通过中间变量来存储易于理解。但一般情况下,我们倾向于通过一个分号来输出一次查询结果,而不是保存为视图进行二次查询。这样的情况下,对于不是特别复杂的检索逻辑我们可以尽量通过自定义变量来存储值,达到编程语言中的函数效果,而不是完全依靠where
子句进行一箩筐的添加条件让机器思考,这样既易于编写又提升了速度。
自定义变量和条件语句语法规则
自定义变量规则
@变量名:=固定值 | 函数调用 | 条件语句 别名mysql> SELECT @min_price:=MIN(price),@max_price:=MAX(price) FROM shop; # 初始化变量mysql> SELECT * FROM shop WHERE price=@min_price OR price=@max_price; # 引用变量
条件语句
在非funtion
和procedure
的一般查询语法中,sql
中的条件语句和高级编程语言中的条件语句用法上有所不同,sql
中的if
更像一个函数,而不是代表一个语句,但也有和编程语言中相差不大的条件语句,比如case
。简单介绍一下3种在一般条件语句中的用法,不做更深的理解。不深究的原因可以看下例题思路解析部分。
IF( expr1 , True_expr , False_expr ) # expr1为真返回True_expr, 假则返回False_exprIFNULL( expr1 , Null_expr ) # expr1的值不为空仍返回该值, 值为空则返回Null_exprcase when 条件1 then 结果1 when 条件2 then 结果2 else 结果N
end
例题简介
Leetcode 180:编写一个 SQL 查询,查找所有至少连续出现三次的数字。
+----+-----+
| Id | Num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
思路解析
写代码写多了,遇到这种情况程序思维就觉得很简单,if+count的组合应该很容易就解决了。但是在sql中,一方面我对if
,ifnull
, case when
等条件语句和函数不太了解,在帮助文档以及mysql应知应会这种工具书中都没有怎么提及,只能在csdn上搜索相关文档,另一方面,这类题目的逻辑并非非常复杂,我个人是不想为这种程度的逻辑去使用function
或procedure
。
一般的sql解法可能会对同一张表多次连接后加上较复杂的where子句,但我是有些不太习惯这种思维模式的,感觉过于暴力;另外一种解法是程序思维,使用自定义变量和条件语句来达到函数的效果。因此,我会列出两种方法,但对第二种方法更有倾向性。
方法1:同表多连接
无论如何,用的最多的可能还是相同表连接的查询方式来表示检索条件。
mysql> select distinct L1.Num as ConsecutiveNums-> from Logs L1, Logs L2, Logs L3-> where L1.Id = L2.Id - 1 # 条件语句-> and L2.Id = L3.Id - 1-> and L1.Num = L2.Num-> and L2.Num = L3.Num;+-----------------+
| ConsecutiveNums |
+-----------------+
| 1 |
+-----------------+
1 row in set (0.01 sec)
这里有至少有一处可以优化,就是在表连接出可以使用外连接减少检索的行数,速度的确快了,但思路上基本没有变化。
mysql> select distinct L1.Num as ConsecutiveNums-> from Logs L1 left join Logs L2 on L1.Num = L2.Num-> left join Logs L3 on L2.Num = L3.Num-> where L1.Id = L2.Id - 1-> and L2.Id = L3.Id - 1;+-----------------+
| ConsecutiveNums |
+-----------------+
| 1 |
+-----------------+
1 row in set (0.00 sec)
方法2:子查询(自定义变量)
这种解法是我希望在sql
中实现的,但在我原来的理解中,可能需要定义function
or procudure
,不过因为逻辑上又没那么复杂不想麻烦所以一直觉得没必要。但这位老兄的解法给我提供了一个类函数的查询模板让我思考。
可能因为mysql的直接堆叠的查询逻辑更容易看懂,我看到Leetcode
上数据库练习下的评论既少又表示对这种编程思维不太理解。其实包括我自己第一次看到的时候也有点懵。但看懂了以后会觉得比原来的方法更有趣也更快。
先把代码附上,接下来从子查询开始说明这种逻辑如何在sql
中更好的实现。
SELECT DISTINCT a.Num ConsecutiveNums FROM ( # 主句
SELECT t.Num , # 子表1@cnt:=IF(@pre=t.Num, @cnt+1, 1) cnt,@pre:=t.Num preFROM Logs t, (SELECT @pre:=null, @cnt:=0) b) a # 子表2WHERE a.cnt >= 3作者:hy3300
链接:https://leetcode-cn.com/problems/two-sum/solution/bu-shi-yong-idqing-kuang-xia-tong-ji-by-hy3300/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法2详解
子查询理解如果从主句开始,比较难用语言说明子查询返回的表的结构组成,所以我从子表2开始说明,并依次扩充直到主句
子表2
select @pre:=null, @cnt:=0
生成包含两个字段的表,但这两个字段本身没有意义,其主要作用是通过建立表来初始化两个自定义变量用于迭代,cnt变量用于存储当前Num出现的次数,pre用于存储当前的Num进行下一条数据比较。子表1
SELECT t.Num ,@cnt:=IF(@pre=t.Num, @cnt+1, 1) cnt,@pre:=t.Num preFROM Logs t, 子表2 b+------+------+------+| Num | cnt | pre |+------+------+------+| 1 | 1 | 1 || 1 | 2 | 1 || 1 | 3 | 1 || 2 | 1 | 2 || 1 | 1 | 1 || 2 | 1 | 2 || 2 | 2 | 2 |+------+------+------+
将子表2替换命名为b,该句可以理解为从表Logs t中选取t.Num, cnt, pre
三个字段,依次返回三个值:Num,Num出现次数,保存本条数据中的Num值。因为没有where
子句的限制,select会对每行的Num检索一次,并计算出相对应的cnt和pre值。这种结构类似于编程语言中的while-if
,每一行相当于一次循环,cnt和pre变量会在每次循环中随条件而变化,同时这里如果需要控制次数可以使用LIMIT
语句。
可以看到,子表1的效果就是函数封装的效果,相当有趣。
SELECT DISTINCT a.Num ConsecutiveNumsFROM 子表1 aWHERE a.cnt >= 3
当我们看到子表1的结果表之后,再来看主句就相当容易理解了,无外乎是一个简单的查询语句。
总结
以往我使用子查询,通常会将子查询作为计算字段来使用,比如select c1, (select c2 from t2) as c2 from t1
或 select * from t1 where t1.c1 = (select c2 from t2 where id=1)
,而在本例中,子查询起到了类似过滤的作用,即利用变量重新构建了一个新表,这种方法大大增加了子查询的易用性和可行性,未来在遇到比一般查询稍复杂一些,但逻辑上又不会过于繁杂的情况,可以尝试在子查询中使用自定义函数和条件语句,构建一个具有函数效果的sql
查询语句。
mysql在子查询中使用自定义变量和条件语句实现函数效果的查询语句相关推荐
- mysql相邻行数据计算的自定义变量@和Lead窗口函数的具体案例适应版本mysq5.7 mysql8.0
Mysql相邻数据(行)计算的自定义变量与Lead Lag窗口函数的案例 1 相邻行 我们在处理数据时有时需要对业务上定义的相邻行进行统计计算. 比如我们想统计公司里所有部门最近2年或相邻年份)的成本 ...
- 执行xpath时提示,需要命名空间管理器或XsltContext。此查询具有前缀、变量或用户定义的函数
执行xpath时提示,需要命名空间管理器或XsltContext.此查询具有前缀.变量或用户定义的函数 2012-05-05 10:45:48| 分类: 默认分类 | 标签:要命名空间管理器 x ...
- php 正则去除script,javascript正则实现php中的加入和去除反斜杠函数效果
php中要给指定的指定的字符加上或去除反斜杠,可使用现成的函数:addcslashes() & stripcslashes() 来实现,实例代码: $str="select * fr ...
- power query和mysql_在PowerQuery连接MySQL的语句中使用自定义变量的方法
最近尝试在PowerQuery查询MySQL时使用自定义变量,同样添加变量的SQL语句在Navicat可以正常执行,但在PowerQuery里面就会报错,今天解决了这个问题,方法是给变量加引号(文章末 ...
- mysql 生明变量_在 MySQL 的 SQL 文件中,定义变量与使用变量
1.现阶段存在一个新需求,需要在部署产品时,针对产品做一些初始化数据的工作.预先准备好相应的 SQL 文件.由于需要执行多条 SQL 语句,且后续的 SQL 语句依赖于之前的 SQL 语句生成的主键 ...
- Android中使用自定义的view实现圆形图片的效果
今天给大家讲的是怎么在xml文件找中通过引用自定义的view实现ImageView的圆形图片效果.首先在你的项目中新建一个类,我给它命名为:CircleImageView:然后在res目录下的valu ...
- SQL语句——分组函数和分组查询
分组函数和分组查询 一.分组函数 1.使用 2.注意 (1)null (2)count(*)和count(具体字段)的区别 (3)分组函数不能直接使用在where子句中 (4)所有分组函数可以组合起来 ...
- 想实现数据分页,就用dataTabale+jquery语句实现分页效果和查询功能和自动排序,简单实用强烈推荐
使用jquery中的dataTables实现列表的分页 dataTables是⼀个jquery的插件,可以进行分页和实时查找数据. 官⽹:https://datatables.net/ 1.引入 (1 ...
- AI回合制游戏,过程比较简单。程序中的f变量和条件语句用的很经典。
本系列文章由zhmxy555编写,转载请注明出处. 文章链接 http://blog.csdn.net/zhmxy555/article/details/7447864 作者:毛星云 邮箱: ...
- MATLAB中带有符号变量的阶乘、累加函数的表达与求解
1.求n的阶乘,方法如下: a.factorial(n) b.gamma(n+1) c.v='n!'; vpa(v) 2.求组合(数),方法如下: a.combntns(x,m) 列举出从n个元素中取 ...
最新文章
- Javascript模块化编程
- 【题解】 hdu2955 Robberies
- 查询时注意 查询字段传值参数类型,尽量和数据库字段类型一致
- Algorithm:C++语言实现之内排序、外排序相关算法(插入排序 、锦标赛排序、归并排序)
- Arduino--AS608指纹传感器
- 聚类技术---复杂网络社团检测_基于Plato高性能图计算框架的社团发现算法
- Linux也使用多线程下载
- 无线信号拓展与覆盖的解决方案
- jpa 表注释和字段注释_JPA注释–Hibernate注释
- Vue todos代办事项功能
- [Winter Vacation] 语文实词虚词练习册答案
- 牛牛之瀛洲公园(09.10)
- js中使用btoa和atob进行Base64的编码和解码
- 来自飞机座椅的实测数据
- (30)虚拟时钟create_virtual_clock
- 学计算机专业的做近视手术,一个做了飞秒近视手术四年的人来和大家分享下自己的感受...
- 半波整流变压器电流波形仿真
- [5-22]绿色精品软件每天更新[uc23整理]
- win10 录屏快捷键
- 黄良会:关于香港汽车社会发展史的那些事(上)