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

简介: 原文:SQL点滴26—常见T-SQL面试解析  它山之石可以攻玉,这一篇是读别人的博客后写下的,不是原原本本的转载,加入了自己的分析过程和演练。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 b
where a.years<=b.years
group by b.years
order 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 bycharindex来是实现,代码如下:

 

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%'
union
select #page.*,5 as mark from #page where #page.[title] like '%b%'
union
select #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 a
group 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 BC
from #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([一月份],[二月份],[三月份])) pvt
order by [部门]

  

注意,这里每个月份每个部门只有一行数据,所以pivot运算的时候可以使用min函数,使用maxmin都可以。如果这里有多行数据,那么一般会让计算合计,只能用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 a
where 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.[单据]) c
on 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.[单据]) c
where a.[日期] = c.[日期] and a.[单据] = c.[单据]

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

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

注意not exists查询筛选得到时间最小的那条记录,注意这里不能使用existsexists会得到多条。可以理解为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=1
select @value=@value+'#'
select @value= @value+ a.strvalue+'' from #table7 a where a.typ=2
select @value=@value+'#'
print @value

 

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

 






 

 

目录
相关文章
|
5月前
|
存储 缓存 NoSQL
Redis常见面试题全解析
Redis面试高频考点全解析:从过期删除、内存淘汰策略,到缓存雪崩、击穿、穿透及BigKey问题,深入原理与实战解决方案,助你轻松应对技术挑战,提升系统性能与稳定性。(238字)
|
6月前
|
SQL 数据可视化 关系型数据库
MCP与PolarDB集成技术分析:降低SQL门槛与简化数据可视化流程的机制解析
阿里云PolarDB与MCP协议融合,打造“自然语言即分析”的新范式。通过云原生数据库与标准化AI接口协同,实现零代码、分钟级从数据到可视化洞察,打破技术壁垒,提升分析效率99%,推动企业数据能力普惠化。
520 3
|
7月前
|
存储 安全 测试技术
Python面试题精选及解析
本文详解Python面试中的六大道经典问题,涵盖列表与元组区别、深浅拷贝、`__new__`与`__init__`、GIL影响、协程原理及可变与不可变类型,助你提升逻辑思维与问题解决能力,全面备战Python技术面试。
334 0
|
9月前
|
Web App开发 缓存 前端开发
浏览器常见面试题目及详细答案解析
本文围绕浏览器常见面试题及答案展开,深入解析浏览器组成、内核、渲染机制与缓存等核心知识点。内容涵盖浏览器的主要组成部分(如用户界面、呈现引擎、JavaScript解释器等)、主流浏览器内核及其特点、从输入URL到页面呈现的全过程,以及CSS加载对渲染的影响等。结合实际应用场景,帮助读者全面掌握浏览器工作原理,为前端开发和面试提供扎实的知识储备。
366 4
|
5月前
|
监控 Java 关系型数据库
面试性能测试总被刷?学员真实遇到的高频问题全解析!
面试常被性能测试题难住?其实考的不是工具,而是分析思维。从脚本编写到瓶颈定位,企业更看重系统理解与实战能力。本文拆解高频面试题,揭示背后考察逻辑,并通过真实项目训练,帮你构建性能测试完整知识体系,实现从“会操作”到“能解决问题”的跨越。
|
9月前
|
存储 安全 Java
2025 最新史上最全 Java 面试题独家整理带详细答案及解析
本文从Java基础、面向对象、多线程与并发等方面详细解析常见面试题及答案,并结合实际应用帮助理解。内容涵盖基本数据类型、自动装箱拆箱、String类区别,面向对象三大特性(封装、继承、多态),线程创建与安全问题解决方法,以及集合框架如ArrayList与LinkedList的对比和HashMap工作原理。适合准备面试或深入学习Java的开发者参考。附代码获取链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
5127 50
|
9月前
|
前端开发 JavaScript 开发者
2025 最新 100 道 CSS 面试题及答案解析续篇
本文整理了100道CSS面试题及其答案,涵盖CSS基础与进阶知识。内容包括CSS引入方式、盒模型、选择器优先级等核心知识点,并通过按钮、卡片、导航栏等组件封装实例,讲解单一职责原则、样式隔离、响应式设计等最佳实践。适合前端开发者巩固基础、备战面试或提升组件化开发能力。资源地址:[点击下载](https://pan.quark.cn/s/50438c9ee7c0)。
205 5
2025 最新 100 道 CSS 面试题及答案解析续篇
|
9月前
|
缓存 NoSQL Java
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
497 6
|
9月前
|
NoSQL Java 微服务
2025 年最新 Java 面试从基础到微服务实战指南全解析
《Java面试实战指南:高并发与微服务架构解析》 本文针对Java开发者提供2025版面试技术要点,涵盖高并发电商系统设计、微服务架构实现及性能优化方案。核心内容包括:1)基于Spring Cloud和云原生技术的系统架构设计;2)JWT认证、Seata分布式事务等核心模块代码实现;3)数据库查询优化与高并发处理方案,响应时间从500ms优化至80ms;4)微服务调用可靠性保障方案。文章通过实战案例展现Java最新技术栈(Java 17/Spring Boot 3.2)的应用.
754 9
|
9月前
|
设计模式 安全 Java
Java 基础知识面试题全解析之技术方案与应用实例详解
本内容结合Java 8+新特性与实际场景,涵盖函数式编程、Stream API、模块化、并发工具等技术。通过Lambda表达式、Stream集合操作、Optional空值处理、CompletableFuture异步编程等完整示例代码,助你掌握现代Java应用开发。附面试题解析与技术方案,提升实战能力。代码示例涵盖计算器、员工信息统计、用户查询、模块化系统设计等,助你轻松应对技术挑战。
283 9

推荐镜像

更多
  • DNS