当前位置: 代码迷 >> SQL >> 在论坛中出现的比较难的sql有关问题:1
  详细解决方案

在论坛中出现的比较难的sql有关问题:1

热度:55   发布时间:2016-05-05 11:59:19.0
在论坛中出现的比较难的sql问题:1

最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了。

所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路。


1、分组查询问题

http://bbs.csdn.net/topics/390619682?page=1#post-395835328

例子表结构数据如下:
id status date        price
1  1      2013-10-01  218
2  1      2013-10-02  218
3  0      2013-10-03  218
4  0      2013-10-04  238
5  0      2013-10-05  238
6  0      2013-10-06  238
7  0      2013-10-07  258
8  0      2013-10-08  258
9  0      2013-10-09  218


想获取的结果集一:
2013-10-01至2013-10-03  218
2013-10-04至2013-10-06  238
2013-10-07至2013-10-08  258
2013-10-09至2013-10-09  218


想获取的结果集二:
1  2013-10-01至2013-10-02  218
0  2013-10-03至2013-10-03  218
0  2013-10-04至2013-10-06  238
0  2013-10-07至2013-10-08  258
0  2013-10-09至2013-10-09  218


我的解法:

--drop table tbcreate table tb(id int,status int,date varchar(10),price int)insert into tbselect 1,  1,      '2013-10-01',  218 union allselect 2,  1,      '2013-10-02',  218 union allselect 3,  0,      '2013-10-03',  218 union allselect 4,  0,      '2013-10-04',  238 union allselect 5,  0,      '2013-10-05',  238 union allselect 6,  0,      '2013-10-06',  238 union allselect 7,  0,      '2013-10-07',  258 union allselect 8,  0,      '2013-10-08',  258 union allselect 9,  0,      '2013-10-09',  218 --union all--select 10,  0,      '2013-10-10',  218 go--第一个结果集;with tas(select *,       row_number() over(partition by price order by id) as rownum,       min(id) over(partition by price) as min_idfrom tb ),ttas(select id,       price,       a.date,       rownum - (id - min_id) as intervalfrom t a )select min(date) + '至' + max(date) as date,       pricefrom ttgroup by price,intervalorder by 1/*date	                price2013-10-01至2013-10-03	2182013-10-04至2013-10-06	2382013-10-07至2013-10-08	2582013-10-09至2013-10-09	218*/--第2个结果集;with tas(select *,       row_number() over(partition by status,price order by id) as rownum,       min(id) over(partition by status,price) as min_idfrom tb ),ttas(select id,       price,       a.date,       a.status,       rownum - (id - min_id) as intervalfrom t a )select status,min(date) + '至' + max(date),pricefrom ttgroup by status,price,intervalorder by 2/*status date	                    price1	   2013-10-01至2013-10-02	2180	   2013-10-03至2013-10-03	2180	   2013-10-04至2013-10-06	2380	   2013-10-07至2013-10-08	2580	   2013-10-09至2013-10-09	218*/


2、字符串检索问题:http://bbs.csdn.net/topics/390608926

这是 http://bbs.csdn.net/topics/390530288  问题的 一个变种


ID    IndexArr
1     1,2,3,4,5
2     55,6,99,87,1000
3     7,567567,567,43,123


IndexArr 是","分割的数字

现在有字符串 '2,34,45,345,867,4,984'  

现在要检索的是  IndexArr 中每一个数字都在 字符串中出现过的  结果集。

我的解法:

--1.函数if exists(select * from sys.objects where name = 'f_splitSTR' and type = 'tf')   drop function dbo.f_splitSTRgocreate function dbo.f_splitSTR(	@s varchar(8000),     --要分拆的字符串	@split varchar(10)    --分隔字符) returns @re table(                      --要返回的临时表                     col varchar(1000)  --临时表中的列                  )asbegin     declare @len int    set @len = LEN(@split)      --分隔符不一定就是一个字符,可能是2个字符    while CHARINDEX(@split,@s) >0  begin	insert into @re 	values(left(@s,charindex(@split,@s) - 1))		set @s = STUFF(@s,1,charindex(@split,@s) - 1 + @len ,'')    --覆盖:字符串以及分隔符  end    insert into @re values(@s)    return   --返回临时表endgo  --> 测试数据:[tb]if object_id('[tb]') is not null    drop table [tb]go create table [tb]([ID] int,[IndexArr] varchar(19))insert [tb]select 1,'1,2,3,4,5' union allselect 2,'55,6,99,87,1000' union allselect 3,'7,567567,567,43,123' union ALLSELECT 4,'2,34,45'--------------开始查询--------------------------DECLARE @s VARCHAR(1000)SET @s= '2,34,45,345,867,4,984';with tas(select t.ID,       t.IndexArr,       f.col,              --把IndexArr按照分隔符,拆分成了多少个字符串       COUNT(*) over(PARTITION by IndexArr) as split_str_countfrom tb tcross apply dbo.f_splitSTR(t.IndexArr,',') f       )select t.ID,       t.IndexArrfrom twhere charindex(col, ','+@s+',') > 0group by t.ID,         t.IndexArr,         t.split_str_counthaving COUNT(*) = t.split_str_count  --比如2,34,45分拆为3个字符串,                                     --那么在经过where条件过滤后,记录数也必须是3                                     [email protected]?

 

3、如何解决用户在线登陆时间——的小时和分钟计算问题。http://bbs.csdn.net/topics/390613823

我想得到用户在线时长,格式是:08:00和08:43这种格式的在线时长结果。



我自己尝试查了sql的文档,也百度了很多。但是没有这方面的应用。
我自己也尝试写了很多但是不行。
我只能得到在线的总分钟数,或者总秒数。无法弄成想要的格式。
这是我的代码:
select ta.[user],(DATEDIFF(mi,ta.time,tb.time)) from 
(select * from T1 where T1.operate='Login') as ta
inner join 
(select * from T1 where T1.operate='Logout') as tb
on ta.[user]=tb.[user]

------------------------------------
或者这样写:
select ta.[user], cast(datediff(hour, ta.time, tb.time) as varchar) + ':' + cast(DATEDIFF(MINUTE, ta.time, tb.time) as varchar)
from
(select [user], [time] from T1 where [operate] = 'login') as ta
inner join
(select [user], [time] from T1 where [operate] = 'logout') as tb
on ta.[user] = tb.[user];

两种写法都无法实现想要的结果。请求大神指导下,帮忙给出一种解决方法。
我测试完,发效果图。

我的解法:

方法1:

drop table t1create table T1([user] varchar(30),operate varchar(10),time datetime)insert into T1select 'LiMing','Login','2010/10/24 8:03' union allselect 'WangYi','Login','2010/10/24 8:14' union allselect 'WangYi','Logout','2010/10/24 16:14' union allselect 'LiMing','Logout','2010/10/24 16:14' select [user],       cast(cast(round(interval * 1.0 / 60,0,1) as int) as varchar) + ':' +       case when interval * 1.0 % 60 <> 0                 then cast(cast(round(interval * 1.0 % 60,0,1) as int) as varchar)            else '00'       endfrom(select T1.[user],       DATEDIFF(MINUTE,t1.time,t2.time)  as interval from T1inner join T1 t2        on t1.[user] = t2.[user]           and t1.operate = 'login'           and t2.operate = 'logout')a/*user	(无列名)LiMing	8:11WangYi	8:00*/

方法2:

--方法2.select [user],       convert(varchar(5),DATEADD(MINUTE,interval,time),114)from(select T1.[user],       convert(varchar(10),t1.time,120) as time,       DATEDIFF(MINUTE,t1.time,t2.time)  as interval from T1inner join T1 t2        on t1.[user] = t2.[user]           and t1.operate = 'login'           and t2.operate = 'logout')a/*user	(无列名)LiMing	08:11WangYi	08:00*/

 

  相关解决方案