她当时教我最厉害的一招利用sql生成sql最终执行查询,大致就是通过sys.table查出表名,生成sql并合并,最后exec执行。感觉还是比较有用。假设数据库中有一堆命名规范且结构相似的表,要查出这批表的数据,就可以考虑一下用这样的方式
首先从把表名查出来
select name from sys.tables where name like '%表名的模式%' and type= 'u'
上面的通配符什么的就不说了,接下来就是要把查询数据的sql语句拼接出来了。原来还可以这样用,看来以前是没开窍或者是太老实了。
select ' union select * from '+ name from sys.tables where name like '%表名的模式%' and type='u'
这样查询出来的结果就是最终sql的半成品。但上面我觉得尽量不要用*,这里有表的结构不一样,union就会出错了。接下来还需要经过组合和截取,这里就用到了两个函数,一个是 for xml path(''),另一个是stuff(),顺序是先让上面的结果合并成一个字符串,再去截取。sql就成下面的样子
declare @sql varchar(max)
set @sql= select ' union select * from '+ name from sys.tables where name like '%表名的模式%' and type='u' for xml path('')
set @sql=stuff(@sql,1,7,' ')
select @sql
这样就可以把sql语句显示出来了,需要执行的话只需要exec(@sql)就可以了。
这样语句不光可以用于查询数据,加入我要批量删除某一类的表 这样的操作也可以,但有个弊端,就是varchar(max)的容量有限,假如表或者语句太大,varchar(max)放不下的话,最终执行的sql肯定达不到效果啦!
关联子查询
在上一家公司里面,彬哥教导我们,不要用子查询,会让查询速度变慢的,但是这位dba教我用了联表子查询,原本的子查询放在form子句中;dba教导的是把子查询放到join子句中,当我提到说影响效率,dba说不会,我也不明白了。这种语句说应用场景也比较多,我举个例子。
假如现在有一张成绩表,需要查询每个同学去除他整个学期所有测试中最高和最低分的结果,这种情况,关联的子查询适合了
select a.* from exam as a left join
(select [name],max(score) as maxscore,min(score) as minscore from exam group by [name] having max(score)min(score) ) as b
on a.name=b.name and a.scoreb.maxscore and a.scoreb.minscore
where b.name is not null
从下面开始则是个人积累阶段了
去除重复
去除重复会涉及到子查询,但子查询会分在from子句关联的子查询和直接在where子句里面。共同点在于把视为重复的若干列先分组把他们的键查出来,然后在另一个查询中把最大或最小的保留,其余的delete,又拿exam(id,name,score,subject)表为例,单科只需要一个成绩,其余的去掉。
delete from exam where id not in ( select min(id) from exam group by name,subject )
另外一种在from子句的关联删除会在联表删除中列出来,假如没有主键,或组合主键不便于值用一个值去唯一标识这一行的,我想到的另一个办法是:建临时表#temptable,然后insert #temptable select destinct ,接着把原表删除,最后把临时表的数据insert去原表并把临时表删掉就得了,这个用在大数据量不知是否会合适。
联表更新
联表更新只是很基本的sql语法而已,只是鄙人基本功不够扎实,就记录一下
update a set a.value=b.monvalue where table1 as a inner join table2 as b on a.id=b.id where …….
在这里顺便几下sqlite的
update table1 set value=(select monvalue from table2 where id=table1.id )
还有mysql的
update table1 as a,table2 as b set a.value=b.monvalue where a.id=b.id
联表删除
与上面说的删除重复数据相照应,直接上sql
delete a from exam as a left join ( select min(id) from exam group by name,subject ) as b on a.id=b.id where b.id is null
case when
case when 实际上有两种格式,简单一点的是case函数形式,如下面情况
case sex
when '1' then '男'
when '2' then '女'
else '其他' end
另外一种形式叫case搜索函数,就像下面这样子
case when sex='1' then ''
when sex='2' then '女'
else '其他' end
个人认为case when 在查询中实现了分支判断的效果,单纯从外观语法上case函数形式会简介,但从效果来说case函数适合于分支判定是离散的值时适合;case搜索函数是适合于一定的范围,或者说自由度更广的一些判定条件,当然这个也包含了离散的值这个状况。但是case 搜索函数在判定好一个条件符合之后则会屏蔽后面合适的条件。像下面这条语句是能分清各个成绩的等级的
select *,case
when score >90 then '优秀'
when score>80 then '良好'
when score>60 then '合格'
else '不合格' end from exam
但是下面就只有合格与不合格两种等级了
select *,case
when score>60 then '合格'
when score>80 then '良好'
when score >90 then '优秀'
else '不合格' end from exam
之前鄙人一直在写case when … is null 这样的语句,老是不断尝试看语法又没出错,区分好case函数和case 搜索函数之后就明白,该用case when … is null 而不是case … when is null这样了。
行转列
现在数据库里面的表老是说横向表,纵向表,横向表就例如下面的表结构subjecttest(id,name,subject,score)。假如要展示的结果是(学生,语文,数学,英语)这样的结果时则需要用到行转列
行转列有用到上面case when语句,大概是先把记录按姓名去分组,然后从分组中把各个分数用case分离出来,再用聚集函数求最值或者是求和,语句就这样子
select name, max( case [subject] when '语文' then [score] else 0 end ) as '语文',
max( case [subject] when '数学' then [score] else 0 end ) as '数学',
max( case [subject] when '英语' then [score] else 0 end ) as '英语',
sum([score]) as '总分',
avg([score]) as '平均分'
from subjecttest
group by [name]
原来也就这么一回事,当科目多了,max除了要多写几次外,还可以用用dba妹子教的sql拼凑生成把语句生成出来在执行,可惜视图view不支持这样子,唉!
在sql server 2005以上有另外一种方式pivot,直接上语句
select * from subjecttest pivot( sum(score) for [subject] in( 语文,数学,英语 ) ) a
我很奇怪网上说的结果都是合并好的,而我的结果却是这个样子
有行转列,也会有列转行,不过这个更没意思,但顺带也说说unpiovt
select name,'语文',语文 as score from subjecttest
union all
select name,'数学',数学 as score from subjecttest
union all
select name,'英语',英语 as score from subjecttest
select * from subjecttest unpivot ( score for [subject] in (语文,数学,英语) ) a
month year day 函数
这几个函数用于求日期的相应部分,顾名思义是月份,年份,天数
declare @testtimepoint datetime
set @testtimepoint='2015-10-23'
select year(@testtimepoint) as 年,month(@testtimepoint) as 月,day(@testtimepoint) as 日
cast函数
cast函数用于作为数据类型转换,使用它有三点要注意
(1)两个表达式的数据类型完全相同。;
(2)两个表达式可隐性转换。
(3)必须显式转换数据类型。
像下面这样子是会报错的
select cast('12.3' as int)
因为'12.3'只能转到浮点数,不能转成整形,但是浮点数能转成整形,要让它能成功转,就得这样子
select cast( cast('12.3' as float) as int)
