SQL点滴26—常见T-SQL面试解析

原文:SQL点滴26—常见T-SQL面试解析

它山之石可以攻玉,这一篇是读别人的博客后写下的,不是原原本本的转载,加入了自己的分析过程和演练。sql语句可以解决很多的复杂业务,避免过多的项目代码,下面几个语句很值得玩味。

  

1. 已经知道原表
year salary
2000 1000
2001 2000
2002 3000
2003 4000
怎么查询的到下面的结果,就是累积工资
year salary
2000 1000
2001 3000
2002 6000
2003 10000

思路:这个需要两个表交叉查询得到当前年的所有过往年,然后再对过往年进行聚合。代码如下:

create table #salary(years int ,salary int )insert into #salary values(2000, 1000),(2001, 2000),(2002, 3000),(2003, 4000)

select  b.years,SUM(a.salary)from #salary a,#salary bwhere a.years<=b.yearsgroup by b.yearsorder by b.years

  

还有一种方法是使用子查询,第一列是年,第二列是所有小于等于第一列这年的工资总和,也比较直接,代码如下:

select s1.years as years,(select sum(s2.salary) from #salary s2 where s2.years<=s1.years) as salary from #salary s1

  

2. 现在我们假设只有一个table,名为pages,有四个字段,id, url,title,body。里面储存了很多网页,网页的url地址,title和网页的内容,然后你用一个sql查询将url匹配的排在最前, title匹配的其次,body匹配最后,没有任何字段匹配的,不返回。

思路:做过模糊搜索对这个应该很熟悉的,可以使用union all依次向一个临时表中添加记录。这里使用order by和charindex来是实现,代码如下:

create table #page(id int, url varchar(100),title varchar(100), body varchar(100))insert into #page values(1,null,‘abcde‘,‘abcde‘),(2,null,‘abcde‘,null),(3,‘abcde‘,‘e‘,null)

select *from #page where url like ‘%e%‘ or title like ‘%e%‘ or body like ‘%e%‘order by case when (charindex(‘e‘, url)>0) then 1 else 0 end desc, case when (charindex(‘e‘, title)>0) then 1 else 0 end desc, case when (charindex(‘e‘, body)>0) then 1 else 0 end desc

  

只要出现一次就会排在前面,这种情况如果两行都出现就会比较下一个字段,以此类推。

还有一种实现,类似于记分牌的思想,如下:

select a.[id],sum(a.mark) as summark  from(select #page.*,10 as mark from #page where #page.[url] like ‘%b%‘unionselect #page.*,5 as mark from #page where #page.[title] like ‘%b%‘unionselect #page.*,1 as mark from #page where #page.[body] like ‘%b%‘) as a  group by id order by summark desc

    

3. 表内容:
2005-05-09 胜
2005-05-09 胜
2005-05-09 负
2005-05-09 负
2005-05-10 胜
2005-05-10 负
2005-05-10 负

如果要生成下列结果, 该如何写sql语句?

胜负
2005-05-09  2    2
2005-05-10  1    2

思路:首先要有group by 时间,然后是使用sum统计胜负的个数。代码如下:

create table #scores(dates varchar(10),score varchar(2))insert into #scores values(‘2005-05-09‘, ‘胜‘),(‘2005-05-09‘, ‘胜‘),(‘2005-05-09‘, ‘负‘),(‘2005-05-09‘, ‘负‘),(‘2005-05-10‘, ‘胜‘),(‘2005-05-10‘, ‘负‘),(‘2005-05-10‘, ‘负‘)

select a.dates as [比赛时间],SUM(case a.score when ‘胜‘ then 1 else 0 end) as [胜],SUM(case a.score when ‘负‘ then 1 else 0 end) as [负]from #scores agroup by a.dates

  

还有一种方法是使用子查询,先用两个子查询得到这些日期中的胜负常数,然后连接查询,代码如下:

select t1.dates as [比赛时间],t1.score as [胜],t2.score as [负]from(select a.dates as dates, COUNT(1) as score from #scores a where a.score=‘胜‘  group by a.dates) t1 inner join(select a.dates as dates, COUNT(1) as score from #scores a where a.score=‘负‘  group by a.dates) t2 on t1.dates=t2.dates

  

  

4. 表中有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列

思路:这个字面意思很简单了,就是二者选其一,使用case就可以实现,代码如下:

create table #table3(A int, B int ,C int)insert into #table3 values(2,1,3),(4,2,5)

select case when A>B then A else B end as AB,case when B>C then B else C end as BCfrom #table3

  

  

5. 请用一个sql语句得出结果

从table1,table2中取出如table3所列格式数据,注意提供的数据及结果不准确,只是作为一个格式向大家请教。

table1

月份          部门业绩

一月份      01      10

一月份      02      10

一月份      03      5

二月份      02      8

二月份      04      9

三月份      03      8

table2

部门     部门名称

01      国内业务一部

02      国内业务二部

03      国内业务三部

04      国际业务部

table3 (result)

部门部门名称  一月份      二月份      三月份

01  国内业务一部    10        null      null

02   国内业务二部   10         8        null

03   国内业务三部   null       5        8

04   国际业务部   null      null      9

思路:又是行列转换,不过这个稍微复杂一点代码如下:

create table #table4([月份] varchar(10),[部门] varchar(10),[业绩] int)insert into #table4 values(‘一月份‘,‘01‘,‘10‘),(‘一月份‘,‘02‘,‘10‘),(‘一月份‘,‘03‘,‘5‘),(‘二月份‘,‘02‘,‘8‘),(‘二月份‘,‘04‘,‘9‘),(‘三月份‘,‘03‘,‘8‘)

create table #table5([部门] varchar(10),[部门名称] varchar(50))insert into #table5 values(‘01‘,‘国内业务一部‘),(‘02‘,‘国内业务二部‘),(‘03‘,‘国内业务三部‘),(‘04‘,‘国际业务部‘)

select [部门],[部门名称],[一月份],[二月份],[三月份]from(select a.[月份] ,a.[部门] as [部门],b.[部门名称],a.[业绩]  from  #table4 a join #table5 b on a.[部门]=b.[部门] ) sod pivot(min(sod.[业绩]) for sod.[月份] in([一月份],[二月份],[三月份])) pvtorder by [部门]

  

注意,这里每个月份每个部门只有一行数据,所以pivot运算的时候可以使用min函数,使用max,min都可以。如果这里有多行数据,那么一般会让计算合计,只能用sum了

还有一种方法是使用子查询,这个代码要多一点,如下:

select a.[部门] ,b.[部门名称],SUM(case  when a.月份=‘一月份‘ then a.[业绩] else 0 end) as [一月份],SUM(case  when a.月份=‘二月份‘ then a.[业绩] else 0 end) as [二月份],SUM(case  when a.月份=‘三月份‘ then a.[业绩] else 0 end) as [三月份]from #table4 a inner join #table5 b on a.[部门] =b.[部门]group by a.[部门],b.[部门名称]

6. 表结构以及数据如下:

CREATE TABLE #table6

(ID int, 日期 varchar(11), 单据 char(3))

INSERT INTO 表 (ID , 日期 , 单据 ) VALUES ( 1 , ‘2004-08-02‘ , ‘001‘ );

INSERT INTO 表 (ID , 日期 , 单据 ) VALUES ( 2 , ‘2004-09-02‘ , ‘001‘ );

INSERT INTO 表 (ID , 日期 , 单据 ) VALUES ( 3 , ‘2004-10-02‘ , ‘002‘ );

INSERT INTO 表 (ID , 日期 , 单据 ) VALUES ( 4 , ‘2004-09-02‘ , ‘002‘ );

要求:设计一个查询,返回结果如下:

ID 日期      单据

1 2004-08-02 001

4 2004-09-02 002

思路:这个是要找到日期比较小的那一条单据,这个有多种方法实现。第一种方法是相关子查询,如下:

create table #table6 (id int, 日期varchar(11), 单据char(3))insert into #table6 (id , 日期, 单据) values ( 1 , ‘2004-08-02‘ , ‘001‘ );insert into #table6 (id , 日期, 单据) values ( 2 , ‘2004-09-02‘ , ‘001‘ );insert into #table6 (id , 日期, 单据) values ( 3 , ‘2004-10-02‘ , ‘002‘ );insert into #table6 (id , 日期, 单据) values ( 4 , ‘2004-09-02‘ , ‘002‘ );

select * from #table6 awhere a.[日期] = (select MIN(b.[日期]) from #table6 b where b.[单据] =a.[单据] )

还可以使用join连接,如下:

select a.*from #table6 a join(select b.[单据] , MIN(b.[日期]) as [日期] from #table6 b group by b.[单据]) con a.[日期] = c.[日期] and a.[单据] = c.[单据]

注意最后on条件必须是a.[日期] = c.[日期] and a.[单据] = c.[单据],因为c表只是找出来两组符合条件的数据,如果只是a.[日期] = c.[日期]的话会找出多条不符合要求的数据。

还可以不使用join连接,如下:

select a.*from #table6 a ,(select b.[单据] , MIN(b.[日期]) as [日期] from #table6 b group by b.[单据]) cwhere a.[日期] = c.[日期] and a.[单据] = c.[单据]

还可以使用谓词exist,如下:

select * from #table6 awhere not exists(select 1 from #table6 where [单据]=a.[单据] and a.[日期]>[日期])

注意not exists查询筛选得到时间最小的那条记录,注意这里不能使用exists,exists会得到多条。可以理解为a中的日期不会大于子查询中所有日期,就是那个最小的日期。还有去掉[单据]=a.[单据],也会得到更多的数据,这个和普通的情况刚好相反。因为加上这个条件整个子查询会得到更多的数据,否则只保留a.[日期]>[日期]只会得到一条数据。

    

7. 已知下面的表

id  strvalue type

1    how      1

2    are      1

3    you      1

4    fine     2

5    thank    2

6    you      2

要求用sql把它们搜索出来成为这样的

#how are you#fine thank you#

思路:这个和上一篇中的最后一题很相似,也是连接有相同字段的字符,上回使用游标实现的,这次用for xml来实现,代码如下:

create table #table7(id int,strvalue varchar(20),typ int)insert into #table7 values(1,‘how‘,1),(2,‘are‘,1),(3,‘you‘,1),(4,‘fine‘,2),(5,‘thank‘,2),(6,‘you‘,2)select * from #table7

select (select ‘#‘+replace(replace((select strvalue from #table7 t where typ = 1 for xml auto),‘<t strvalue="‘,‘‘),‘"/>‘, ‘‘)+‘#‘)+(select replace(replace((select strvalue from #table7 t where typ = 2 for xml auto),‘<t strvalue="‘,‘‘),‘"/>‘, ‘‘)+‘#‘)

或者这样

select ‘#‘+ltrim((select ‘‘+a.strvalue from #table7 a where a.typ=1 for xml path(‘‘)))+‘#‘+ltrim((select ‘‘+a.strvalue from #table7 a where a.typ=2 for xml path(‘‘)))+‘#‘

或者这样,用变量来处理

declare @value varchar(1000)=‘#‘select  @value=‘‘+@value+ a.strvalue+‘‘ from #table7 a where a.typ=1select @value=@value+‘#‘select  @value= @value+ a.strvalue+‘‘ from #table7 a where a.typ=2select @value=@value+‘#‘print @value

for xml是好东西啊,是解决这类字符连接问题的利刃

时间: 2024-08-03 10:49:37

SQL点滴26—常见T-SQL面试解析的相关文章

转:如何学习SQL(第一部分:SQL基础)

转自:http://blog.163.com/[email protected]/blog/static/285720652010950712271/ 1. 为什么学习SQL 自人类社会形成之日起,社会的运转就在不断地产生和使用各种信息(文献.档案.资料.数据等):在如今所谓的信息时代,由于计算机和互联网的作用,信息的产生和使用达到前所未有的广度和深度.如何管好和用好信息,是(而且将一直是)IT行业一块重要的领域.在过去几十年中,关系数据库一直在这一领域占主导地位,而建立在关系理论基础之上的SQ

SQL点滴25—T-SQL面试语句,练练手

原文:SQL点滴25-T-SQL面试语句,练练手 1. 用一条SQL语句查询出每门课都大于80分的学生姓名 name   kecheng    fenshu 张三     语文     81张三     数学     75李四     语文     76李四     数学     90王五     语文     81王五     数学     100王五     英语     90 思路:这里不能直接用分数>80这样的比较条件来查询的到结果,因为要求没门成绩都大于80.我们可以反过来思考,如果有

sql点滴41—mysql常见sql语法

原文:sql点滴41-mysql常见sql语法 ALTER TABLE:添加,修改,删除表的列,约束等表的定义. 查看列:desc 表名; 修改表名:alter table t_book rename to bbb; 添加列:alter table 表名 add column 列名 varchar(30); 添加带注释的列:alter table directory add index_url varchar(256) default null comment '章节书目链接' after di

SQL Server锁分区特性引发死锁解析

原文:SQL Server锁分区特性引发死锁解析 锁分区技术使得SQL Server可以更好地应对并发情形,但也有可能带来负面影响,这里通过实例为大家介绍,分析由于锁分区造成的死锁情形. 前段时间园友@JentleWang在我的博客锁分区提升并发,以及锁等待实例中问及锁分区的一些特性造成死锁的问题,这类死锁并不常见,我们在这里仔细分析下.不了解锁分区技术的朋友请先看下我的锁分区那篇实例. Code(执行测试脚本时请注意执行顺序,说明) 步骤1 创建测试数据 use tempdb go creat

sql点滴40—mysql乱码问题总结

原文:sql点滴40-mysql乱码问题总结 本文将为大家讲解如何处理Java连接过程中的MySQL中文乱码问题.一般MySQL中文乱码问题都是与字符集有关,这里作者的经历也大致差不多. MySQL默认编码是latin1 1. mysql> show variables like 'character%'; 2. +--------------------------+--------------------------+ 3. | Variable_name | Value | 4. +---

SQL点滴35—SQL语句中的exists

原文:SQL点滴35-SQL语句中的exists 比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHERE EXISTS( SELECT OrderID FROM Orders o WHERE o.CustomerID=c.CustomerID) 这里面的EXISTS是如何运作呢?子查询返回的是OrderId字段,可是外面的查询要找的是CustomerID和CompanyName字段,这两个字段肯定

SQL点滴16—SQL分页语句总结

原文:SQL点滴16-SQL分页语句总结 今天对分页语句做一个简单的总结,他们大同小异的,只要理解其中一个其他的就很好理解了. 使用top选项 selecttop10*from Orders a where a.orderid notin(selecttop10 orderid from Orders orderby orderid) orderby a.orderid 使用max函数 这种方法的前提是有唯一值的一个列. selecttop10*from Orders a where a.ord

SQL点滴22—性能优化没有那么神秘

原文:SQL点滴22-性能优化没有那么神秘 经常听说SQL Server最难的部分是性能优化,不禁让人感到优化这个工作很神秘,这种事情只有高手才能做.很早的时候我在网上看到一位高手写的博客,介绍了SQL优化的问题,从这些内容来看,优化并不都是一些很复杂的问题,掌握了基本的知识之后也可以尝试优化自己的SQL程序,甚至是其他相关的程序.优化是一些工作积累之后的经验总结和代码意识,只要平时注意积累,你也可以做优化的工作.这一篇随笔是转载,不过我强烈推荐给所有对数据库优化有兴趣的博友,读了这一篇之后下一

sql点滴42—mysql中的数据结构

MySQL 的数值数据类型可以大致划分为两个类别,一个是整数,另一个是浮点数或小数.许多不同的子类型对这些类别中的每一个都是可用的,每个子类型支持不同大小的数据,并且 MySQL 允许我们指定数值字段中的值是否有正负之分或者用零填补. 表列出了各种数值类型以及它们的允许范围和占用的内存空间. 类型 大小 范围(有符号) 范围(无符号) 用途 TINYINT 1 字节 (-128,127) (0,255) 小整数值 SMALLINT 2 字节 (-32 768,32 767) (0,65 535)