在论坛中出现的比较难的sql问题:11(字符分拆1)

发布时间:2014-10-23 23:27:57
来源:分享查询网

最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了。 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路。 1、求一SQL语句。 http://bbs.csdn.net/topics/390496661 create table #tab ( col1 char(10), col2 char(10), item char(10), num int, [Date] varchar(10)) insert #tab values('AAA','BBB','A',50,'2013-06-10') insert #tab values('ABB','BGG','B',30,'2013-06-10') insert #tab values('AAA','BBB','C',80,'2013-06-13') 我的解法: create table tab ( col1 char(10), col2 char(10), item char(10), num int, [Date] varchar(10) ) insert tab values('AAA','BBB','A',50,'2013-06-10') insert tab values('ABB','BGG','B',30,'2013-06-10') insert tab values('AAA','BBB','C',80,'2013-06-13') --动态生成sql语句 declare @start_date varchar(10) = '2013-06-01', @end_date varchar(10) = '2013-06-30'; declare @date varchar(10), @sql varchar(max) = '', @sql1 varchar(8000), @sql2 varchar(8000); set @date = @start_date; set @sql1 = 'select case when rownum = 1 then col1 else '''' end as col1, case when rownum = 1 then col2 else '''' end as col2, item' set @sql2 = 'select col1,col2,item,row_number() over(partition by col1,col2 order by item) as rownum' while @date <= @end_date begin set @sql1 = @sql1 + ',v_' + REPLACE( right(@date,5),'-','') + ' as ''' + CAST(DATEPART(month,@date) as varchar) + '/' + CAST(DATEPART(day,@date) as varchar) +''''; set @sql2 = @sql2 + ',SUM(case when date =''' + @date + ''' then num else 0 end) as v_' + REPLACE( right(@date,5),'-','') set @date = CONVERT(varchar(10),dateadd(day,1,@date),120) end set @sql = @sql1 + ' from (' + @sql2 + ' from tab group by col1,col2,item' + ') v' --生产的动态sql语句 select @sql exec(@sql) 上面由于是动态生成语句,所以不能用局部的临时表,所以建了一个表。 下面是动态生成的sql语句,经过了格式化: select case when rownum = 1 then col1 else '' end as col1, case when rownum = 1 then col2 else '' end as col2, item, v_0601 as '6/1',v_0602 as '6/2',v_0603 as '6/3', v_0604 as '6/4',v_0605 as '6/5', v_0606 as '6/6',v_0607 as '6/7', v_0608 as '6/8',v_0609 as '6/9', v_0610 as '6/10',v_0611 as '6/11', v_0612 as '6/12',v_0613 as '6/13', v_0614 as '6/14',v_0615 as '6/15', v_0616 as '6/16',v_0617 as '6/17', v_0618 as '6/18',v_0619 as '6/19', v_0620 as '6/20',v_0621 as '6/21', v_0622 as '6/22',v_0623 as '6/23', v_0624 as '6/24',v_0625 as '6/25', v_0626 as '6/26',v_0627 as '6/27', v_0628 as '6/28',v_0629 as '6/29', v_0630 as '6/30' from ( select col1,col2,item, row_number() over(partition by col1,col2 order by item) as rownum, SUM(case when date ='2013-06-01' then num else 0 end) as v_0601, SUM(case when date ='2013-06-02' then num else 0 end) as v_0602, SUM(case when date ='2013-06-03' then num else 0 end) as v_0603, SUM(case when date ='2013-06-04' then num else 0 end) as v_0604, SUM(case when date ='2013-06-05' then num else 0 end) as v_0605, SUM(case when date ='2013-06-06' then num else 0 end) as v_0606, SUM(case when date ='2013-06-07' then num else 0 end) as v_0607, SUM(case when date ='2013-06-08' then num else 0 end) as v_0608, SUM(case when date ='2013-06-09' then num else 0 end) as v_0609, SUM(case when date ='2013-06-10' then num else 0 end) as v_0610, SUM(case when date ='2013-06-11' then num else 0 end) as v_0611, SUM(case when date ='2013-06-12' then num else 0 end) as v_0612, SUM(case when date ='2013-06-13' then num else 0 end) as v_0613, SUM(case when date ='2013-06-14' then num else 0 end) as v_0614, SUM(case when date ='2013-06-15' then num else 0 end) as v_0615, SUM(case when date ='2013-06-16' then num else 0 end) as v_0616, SUM(case when date ='2013-06-17' then num else 0 end) as v_0617, SUM(case when date ='2013-06-18' then num else 0 end) as v_0618, SUM(case when date ='2013-06-19' then num else 0 end) as v_0619, SUM(case when date ='2013-06-20' then num else 0 end) as v_0620, SUM(case when date ='2013-06-21' then num else 0 end) as v_0621, SUM(case when date ='2013-06-22' then num else 0 end) as v_0622, SUM(case when date ='2013-06-23' then num else 0 end) as v_0623, SUM(case when date ='2013-06-24' then num else 0 end) as v_0624, SUM(case when date ='2013-06-25' then num else 0 end) as v_0625, SUM(case when date ='2013-06-26' then num else 0 end) as v_0626, SUM(case when date ='2013-06-27' then num else 0 end) as v_0627, SUM(case when date ='2013-06-28' then num else 0 end) as v_0628, SUM(case when date ='2013-06-29' then num else 0 end) as v_0629, SUM(case when date ='2013-06-30' then num else 0 end) as v_0630 from tab group by col1,col2,item ) v 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_splitSTR go create function dbo.f_splitSTR ( @s varchar(8000), --要分拆的字符串 @split varchar(10) --分隔字符 ) returns @re table( --要返回的临时表 col varchar(1000) --临时表中的列 ) as begin 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 --返回临时表 end go --> 测试数据:[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 all select 2,'55,6,99,87,1000' union all select 3,'7,567567,567,43,123' union ALL SELECT 4,'2,34,45' --------------开始查询-------------------------- DECLARE @s VARCHAR(1000) SET @s= '2,34,45,345,867,4,984' ;with t as ( select t.ID, t.IndexArr, f.col, --把IndexArr按照分隔符,拆分成了多少个字符串 COUNT(*) over(PARTITION by IndexArr) as split_str_count from tb t cross apply dbo.f_splitSTR(t.IndexArr,',') f ) select t.ID, t.IndexArr from t where charindex(col, ','+@s+',') > 0 group by t.ID, t.IndexArr, t.split_str_count having COUNT(*) = t.split_str_count --比如2,34,45分拆为3个字符串, --那么在经过where条件过滤后,记录数也必须是3 --这样说明了indexarr中的字符串都在@s变量中出现了 3、这个语句怎么写? http://bbs.csdn.net/topics/390490832?page=1 我有一张表:CarRule 有下面这些列和数据 ID    Keywords 1     时速50%、 不到100% 2     违反禁令标志 3     违反规定停放、拒绝立即驶离、妨碍其他车辆 我要查询这个CarRule表,根据关键字获取ID 例如:机动车行驶超过规定时速50%以上不到100%的  就能获取到  ID=1       机动车违反禁令标志的                     就能获取到  ID=2       违反规定停放、临时停车且驾驶人不在现场或驾驶人虽在现场拒绝立即驶离,妨碍其他车辆、行人通行的          就能获取到  ID=3 这个查询我怎么写。   我的解法: --1.先建立一个函数,通过分隔符来拆分keywords成多个关键字 create function dbo.fn_splitSTR ( @s varchar(8000), --要分拆的字符串 @split varchar(10) --分隔字符 ) returns @re table( --要返回的临时表 col varchar(1000) --临时表中的列 ) as begin 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 --返回临时表 end go --2.建表 DECLARE @CarRule TABLE(id INT,Keywords VARCHAR(100)) INSERT INTO @carrule VALUES(1,'时速50%、不到100%'), (2,'违反禁令标志'), (3,'违反规定停放、拒绝立即驶离、妨碍其他车辆') ;WITH split --拆分关键字 as ( SELECT c.id, c.keywords, f.col FROM @carrule c CROSS apply dbo.fn_splitSTR(c.keywords,'、') f ) --3.第1个查询 SELECT s.id, s.keywords FROM split s INNER JOIN ( SELECT s.id, s.keywords, count(col) AS split_str_count --拆分成了几个关键字 FROM split s GROUP BY s.id, s.keywords ) ss ON s.id = ss.id WHERE charindex(s.col,'机动车行驶超过规定时速50%以上不到100%的') > 0 GROUP BY s.id, s.keywords HAVING count(*) = max(ss.split_str_count) --比如第一条记录拆分成了2个关键词,那么在匹配时要2个都匹配上了,才算为匹配 第2个查询: DECLARE @CarRule TABLE(id INT,Keywords VARCHAR(100)) INSERT INTO @carrule VALUES(1,'时速50%、不到100%'), (2,'违反禁令标志'), (3,'违反规定停放、拒绝立即驶离、妨碍其他车辆') ;WITH split --拆分关键字 as ( SELECT c.id, c.keywords, f.col FROM @carrule c CROSS apply dbo.fn_splitSTR(c.keywords,'、') f ) --3. SELECT s.id, s.keywords FROM split s INNER JOIN ( SELECT s.id, s.keywords, count(col) AS split_str_count --拆分成了几个关键字 FROM split s GROUP BY s.id, s.keywords ) ss ON s.id = ss.id WHERE charindex(s.col,'机动车违反禁令标志的') > 0 GROUP BY s.id, s.keywords HAVING count(*) = max(ss.split_str_count) --比如第一条记录拆分成了2个关键词,那么在匹配时要2个都匹配上了,才算为匹配 第3个查询: DECLARE @CarRule TABLE(id INT,Keywords VARCHAR(100)) INSERT INTO @carrule VALUES(1,'时速50%、不到100%'), (2,'违反禁令标志'), (3,'违反规定停放、拒绝立即驶离、妨碍其他车辆') ;WITH split --拆分关键字 as ( SELECT c.id, c.keywords, f.col FROM @carrule c CROSS apply dbo.fn_splitSTR(c.keywords,'、') f ) --3. SELECT s.id, s.keywords FROM split s INNER JOIN ( SELECT s.id, s.keywords, count(col) AS split_str_count --拆分成了几个关键字 FROM split s GROUP BY s.id, s.keywords ) ss ON s.id = ss.id WHERE charindex(s.col,'违反规定停放、临时停车且驾驶人不在现场或驾驶人虽在现场拒绝立即驶离,妨碍其他车辆、行人通行的就能获取到') > 0 GROUP BY s.id, s.keywords HAVING count(*) = max(ss.split_str_count) --比如第一条记录拆分成了2个关键词,那么在匹配时要2个都匹配上了,才算为匹配  

返回顶部
查看电脑版