SQL高级嵌套

写了很多复杂的SQL脚本和存储过程,每次都需要花很长的时间去熟悉mysql的对应函数使用,所以很麻烦,记下来,以便后续少走弯路,提供自己和各位网友参考。

注意:

这里要非常留意,MYSQL单机环境下和MYSQL集群环境下(这里我用的MyCat数据中间件)出来的效果不一样,可能会检索出来多条记录,比如,不同的数据库执行各自的存储过程都会有一条或多条记录,最终返回给上层应用2倍的数据查询集;

以下语句为“落脚点分析”查询相关的脚本,条件:

a. 按每一天进行分组

b. 从每天的抓取记录中获取最早的一条和最晚的一条

c. 将一天抓取的最早一条和最晚一条合并为一条(一天当中出行时间最早一条和回来时间段最晚一条)

 

思路实现如下:

(1)多语句嵌套

select temp.df, temp.alarmTime from
(
	select a.id, DATE_FORMAT(a.alarmTime,'%Y-%m-%d') as df, a.alarmTime, a.deviceName, a.wifi 
	from t_wifi_alarm a 
	where a.wifi='65-05-14-0f-84-07'
	and DATE_FORMAT(a.alarmTime,'%H:%i:%S') >='08:10:10'
	order by df
) temp where temp.df='2019-04-10' and temp.alarmTime = min(temp.alarmTime);

(2)查询分组最小

方式一:通过最小值嵌套查
select b.df, b.alarmTime from
(
	select a.id, DATE_FORMAT(a.alarmTime,'%Y-%m-%d') as df, a.alarmTime, a.deviceName 
	from t_wifi_alarm a 
	where a.wifi='65-05-14-0f-84-07'
	and DATE_FORMAT(a.alarmTime,'%H:%i:%S') >='08:10:10'
	order by df
) b where b.df='2019-04-10' and b.alarmTime = 
(
	select min(d.alarmTime) 
	from t_wifi_alarm d
	where d.wifi='65-05-14-0f-84-07'
	and DATE_FORMAT(d.alarmTime,'%H:%i:%S') >='08:10:10'
);


方式二:通过升序查第一条

select b.df, b.alarmTime from
(
	select a.id, DATE_FORMAT(a.alarmTime,'%Y-%m-%d') as df, a.alarmTime, a.deviceName 
	from t_wifi_alarm a 
	where a.wifi='65-05-14-0f-84-07'
	and DATE_FORMAT(a.alarmTime,'%H:%i:%S') >='08:10:10'
	order by df
) b where b.df='2019-04-10' 
order by b.alarmTime ASC
limit 1;

(3)查询分组最大

方式一:通过最大值嵌套查
select b.df, b.alarmTime from
(
	select a.id, DATE_FORMAT(a.alarmTime,'%Y-%m-%d') as df, a.alarmTime, a.deviceName 
	from t_wifi_alarm a 
	where a.wifi='65-05-14-0f-84-07'
	and DATE_FORMAT(a.alarmTime,'%H:%i:%S') >='08:10:10'
	order by df
) b where b.df='2019-04-10' and b.alarmTime = 
(
	select max(x.alarmTime) 
	from t_wifi_alarm x
	where x.wifi='65-05-14-0f-84-07'
	and DATE_FORMAT(x.alarmTime,'%H:%i:%S') >='08:10:10'
)
#limit 1;

方式二:通过降序查第一条
select b.df, b.alarmTime from
(
	select a.id, DATE_FORMAT(a.alarmTime,'%Y-%m-%d') as df, a.alarmTime, a.deviceName 
	from t_wifi_alarm a 
	where a.wifi='65-05-14-0f-84-07'
	and DATE_FORMAT(a.alarmTime,'%H:%i:%S') >='08:10:10'
	order by df
) b where b.df='2019-04-10'
order by b.alarmTime desc 
limit 1

(3)多条记录合并

select m.df, m.alarmTime, n.df, n.alarmTime from
(
	select c.df, c.alarmTime from 
	(
		select b.df, b.alarmTime from
		(
			select a.id, DATE_FORMAT(a.alarmTime,'%Y-%m-%d') as df, a.alarmTime, a.deviceName 
			from t_wifi_alarm a 
			where a.wifi='65-05-14-0f-84-07'
			and DATE_FORMAT(a.alarmTime,'%H:%i:%S') >='08:10:10'
			order by df
		) b where b.df='2019-04-10' 
		order by b.alarmTime asc
		limit 1
	) c
	order by c.alarmTime
	limit 1
) m join 
(
	select f.df, f.alarmTime from 
	(
		select e.df, e.alarmTime from
		(
			select d.id, DATE_FORMAT(d.alarmTime,'%Y-%m-%d') as df, d.alarmTime, d.deviceName 
			from t_wifi_alarm d 
			where d.wifi='65-05-14-0f-84-07'
			and DATE_FORMAT(d.alarmTime,'%H:%i:%S') >='08:10:10'
			order by df
		) e where e.df='2019-04-10'
		order by e.alarmTime desc 
		limit 1
	) f
	order by f.alarmTime desc
	limit 1
) n on m.df=n.df;

(4)单机存储过程实现思路

这里仅仅有思路,没有具体实现

DELIMITER ||

drop procedure if exists query_first_and_last_wifi_in_one_day ||

create procedure query_first_and_last_wifi_in_one_day (in start_date_time varchar(32), in end_date_time varchar(32), in start_time_in_one_day varchar(16), in end_time_in_one_day varchar(16), in wifi varchar(32))
begin     
	
		-- 参数声明
		declare p_view_name varchar(255) default ''; 
		declare p_start_day varchar(32) default '';  
		declare p_end_day varchar(32) default ''; 
		declare p_cur_day varchar(32) default ''; 

		-- 临时视图名
		set p_view_name = CONCAT('wifi_', DATE_FORMAT(a.alarmTime,'%Y-%m-%d_%H_%i_%S'));

		set p_start_day = DATE_FORMAT(start_date_time,'%Y-%m-%d');
		set p_cur_day = DATE_FORMAT(start_date_time,'%Y-%m-%d');
		set p_end_day = DATE_FORMAT(end_date_time,'%Y-%m-%d');
	
  	-- 创建查询结果视图
    set @sql = CONCAT(' create view ', p_view_name, 
										  ' as select DATE_FORMAT(a.alarmTime,\'%Y-%m-%d\') as df, a.alarmTime, a.deviceName from t_wifi_alarm a where a.wifi=\'' , wifi, 
											'\' and a.alarmTime >=\'', start_date_time, 
											'\' and a.alarmTime <=\'', end_date_time, '\''); 
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
		DEALLOCATE PREPARE stmt;

		-- 遍历所有天
    while p_cur_day <= p_end_day do

			-- 选择第一次出现时间-满足出行时间
			-- select time from view where time ='xxx';
			set @sql=CONCAT('select alarmTime, deviceName from ', p_view_name ,' where alarmTime = \'', p_cur_day, '\' order by alarmTime asc limit 1');
			-- set @sql=CONCAT('ALTER TABLE ', tablename ,' ADD PARTITION ( PARTITION p', p_name ,' VALUES LESS THAN (',p_description,'))');
			-- 打印sql变量
			select @sql;
			-- 准备sql语句
			PREPARE stmt from @sql;
			-- 执行sql语句
			EXECUTE stmt;

			-- 选择最后一次出现时间-满足回家区间
			-- select time from view where time ='xxx';
			set @sql=CONCAT('select alarmTime, deviceName from ', p_view_name ,' where alarmTime = \'', p_cur_day, '\' order by alarmTime desc limit 1');
			-- set @sql=CONCAT('ALTER TABLE ', tablename ,' ADD PARTITION ( PARTITION p', p_name ,' VALUES LESS THAN (',p_description,'))');
			-- 打印sql变量
			select @sql;
			-- 准备sql语句
			PREPARE stmt from @sql;
			-- 执行sql语句
			EXECUTE stmt;
			-- 释放资源
			DEALLOCATE PREPARE stmt;

			-- 合并一条记录,见上合并步骤

			-- 递增变量
			set p_cur_day = DATE_ADD(p_cur_day, interval 1 day); 

    end while; 


		-- 删除视图
		set @sql = CONCAT(' drop view if exists ', p_view_name); 
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
		DEALLOCATE PREPARE stmt;
	
end ||

-- 恢复语句中断符
DELIMITER ;

(5)数据库集群

集群环境下,存储过程是无法实现的,思路有如下

a、编程实现,将部分结果放内存,然后合并成多条记录返回---大数据情况下,普通内存无法做到

b、大数据Hadoop的MapReduce和Spark实现

 

快来成为我的朋友或合作伙伴,一起交流,一起进步!
QQ群:961179337
微信:lixiang6153
邮箱:lixx2048@163.com
公众号:IT技术快餐
更多资料等你来拿!

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝壳里的沙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值