﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-guomingzhang2008-文章分类-Oracle</title><link>http://www.blogjava.net/guomingzhang2008/category/44303.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 14 Jul 2010 16:24:55 GMT</lastBuildDate><pubDate>Wed, 14 Jul 2010 16:24:55 GMT</pubDate><ttl>60</ttl><item><title>从【各大软件公司笔试压轴题】学习SQL语句</title><link>http://www.blogjava.net/guomingzhang2008/articles/315514.html</link><dc:creator>张国明</dc:creator><author>张国明</author><pubDate>Mon, 15 Mar 2010 11:58:00 GMT</pubDate><guid>http://www.blogjava.net/guomingzhang2008/articles/315514.html</guid><wfw:comment>http://www.blogjava.net/guomingzhang2008/comments/315514.html</wfw:comment><comments>http://www.blogjava.net/guomingzhang2008/articles/315514.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/guomingzhang2008/comments/commentRss/315514.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/guomingzhang2008/services/trackbacks/315514.html</trackback:ping><description><![CDATA[<p>从博客园中看到一篇文章，介绍大软件公司面试时常常会出的两道SQL题（见附录）。 </p>
<p><br />
我觉得受益很多，在此之前，我一直觉得，SQL2008似乎提供了这方面的支持，但更低的版本，包括2005，非游标做不出来（水平够菜）。总结心得如下： </p>
<p><br />
1、&nbsp;&nbsp;&nbsp; 强大的group by </p>
<p>1&nbsp; select stdname,<br />
2&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' 化学 '&nbsp; then Result end), 0 ) [化学],<br />
3&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' 数学 '&nbsp; then Result end), 0 ) [数学],<br />
4&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' 物理 '&nbsp; then Result end), 0 ) [物理],<br />
5&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' 语文 '&nbsp; then Result end), 0 ) [语文] <br />
6&nbsp; from #student <br />
7&nbsp; group by stdname </p>
<p>在这里，group by与sum + case结合，可以将表1中的记录（行）变成表2的字段（列）。Sum里面如果没有case，那么出来的值，只能是全部科目的总和，用了case以后，就是某科的成绩；然后这里用了好几个sum，每个科目一个sum，于是表1中本来某人某科占一条记录的&#8220;行&#8221;就变成了表2里某人一条记录，每科做一个字段了。 </p>
<p><br />
这种心思巧妙和对语法的熟练运用让人击节赞叹。 </p>
<p><br />
2、&nbsp;&nbsp;&nbsp; 利用select from (select from)的模式生成SQL语句 </p>
<p>1&nbsp; declare @sql varchar( 4000 ) <br />
2&nbsp; set&nbsp; @sql&nbsp; =&nbsp;&nbsp; ' select stdname '&nbsp; <br />
3&nbsp; select @sql&nbsp; =&nbsp; @sql&nbsp; +&nbsp;&nbsp; ' ,isnull(sum(case stdsubject when&nbsp; ''' + stdsubject + '''&nbsp; then Result end),0) [ ' + stdsubject + ' ] '&nbsp; <br />
4&nbsp; from (select distinct stdsubject from #student)&nbsp; as&nbsp; a <br />
5&nbsp; select @sql&nbsp; =&nbsp; @sql + '&nbsp; from #student group by stdname '&nbsp; <br />
6&nbsp; print @sql<br />
7&nbsp; exec(@sql) </p>
<p><br />
为了自动写上所有的科目，这里先将科目信息提炼出来： </p>
<p>4&nbsp; from (select distinct stdsubject from #student)&nbsp; as&nbsp; a </p>
<p>利用之拼接生成SQL语句。当然现实中，如果#student表很大，这种做法并不妥，应该都有一个专门的科目类别表的。 </p>
<p><br />
3、&nbsp;&nbsp;&nbsp; 在临时库中提炼出字段名。临时表是真实存在的表，保存在[tempdb]中，可以利用object_id('tempdb.dbo.表名')的方式获得字段信息。 </p>
<p>============================================ </p>
<p>附录： </p>
<p>http://www.cnblogs.com/zhanglei644213943/archive/2009/12/27/1633356.html </p>
<p>&nbsp;</p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 纵览各大社区、论坛，各大 ORM框架火得不行了，如NHibernate、LINQ to SQL、ADO.NET Entity framework等，还有最近市场上出版的一本叫《领域驱动设计与模式实战》，里面也凸显了不少NHibernate在领域驱动设计中的作用与地位，也算是第一本与NHibernate相关的书籍吧！不过就NHibernate而言还是没有官方文档介绍得详细呵呵，园子里Kiler 已经把他翻译成中文版的了，收益一大片仅仅是CET-4的人。不管你是用NHibernate也好，还是用LINQ to SQL也好，用profiler一跟踪，执行的都是SQL语句，所以所SQL是根。特别是对于那些以数据为中心的应用系统，在数据库中实现复杂的存储过程，复杂的报表查询，还是直接SQL来得痛快。当然 对于那些在基于.NET的中间层应用中，它们实现面向对象的业务模型和商业逻辑的应用，NHibernate是最有用的。不管怎样，NHibernate一定可以帮助你消除或者包装那些针对特定厂商的SQL代码，并且帮你把结果集从表格式的表示形式转换到一系列的对象去（官方文档）。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有点跑题了，不再啰嗦----直接晾出压轴题。 </p>
<p>压轴题第一问 </p>
<p>1.把表一转换为表二 </p>
<p>表一：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;</p>
<p>表二： </p>
<p>&nbsp;</p>
<p>数据库代码如下： </p>
<p>&nbsp; 代码 <br />
&nbsp;1&nbsp; DROP table #student<br />
&nbsp;2&nbsp; CREATE TABLE #student (stdname nvarchar( 10 ),stdsubject nvarchar( 10 ),result&nbsp; int )<br />
&nbsp;3&nbsp; INSERT INTO #student VALUES ( ' 张三 ' , ' 语文 ' , 80 )<br />
&nbsp;4&nbsp; INSERT INTO #student values ( ' 张三 ' , ' 数学 ' , 90 )<br />
&nbsp;5&nbsp; INSERT INTO #student VALUES ( ' 张三 ' , ' 物理 ' , 85 )<br />
&nbsp;6&nbsp; INSERT INTO #student VALUES ( ' 李四 ' , ' 语文 ' , 85 )<br />
&nbsp;7&nbsp; INSERT INTO #student values ( ' 李四 ' , ' 数学 ' , 92 )<br />
&nbsp;8&nbsp; INSERT INTO #student VALUES ( ' 李四 ' , ' 物理 ' , 82 )<br />
&nbsp;9&nbsp; INSERT INTO #student VALUES ( ' 李四 ' , ' 化学 ' , 82 )<br />
10&nbsp; INSERT INTO #student VALUES ( ' 李四 ' , ' 化学 ' , 82 )<br />
11&nbsp; SELECT&nbsp; *&nbsp; FROM #student <br />
&nbsp;可能很多老手们，一看到这题目就有了答案。当然，贴出答案来不是我的目的，我要带着SQL新手们重构到答案。用MVP李建忠老师最爱说的话就是------我不建议一上来就套用模式，而应该从重构到模式。</p>
<p>首先大家会想到分两组</p>
<p>1&nbsp; select stdname，&#183;&#183;&#183;&#183;，from #student group by stdname <br />
然后&#183;&#183;&#183;&#183;&#183;&#183;中间该写什么呢？</p>
<p>&nbsp; 代码 <br />
1&nbsp; case&nbsp; stdsubject when&nbsp; ' 化学 '&nbsp; then Result end<br />
2&nbsp; case&nbsp; stdsubject when&nbsp; ' 语文 '&nbsp; then Result end<br />
3&nbsp; case&nbsp; stdsubject when&nbsp; ' &#183;&#183;&#183; '&nbsp; then Result end<br />
4&nbsp; case&nbsp; stdsubject when&nbsp; ' &#183;&#183;&#183; '&nbsp; then Result end<br />
5&nbsp; case&nbsp; stdsubject when&nbsp; ' &#183;&#183;&#183; '&nbsp; then Result end <br />
表二里面得0是哪里来的呢？</p>
<p>&nbsp; 代码 <br />
1&nbsp; isnull(sum（ case&nbsp; stdsubject when&nbsp; ' 化学 '&nbsp; then Result end）, 0 )<br />
2&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' 语文 '&nbsp; then Result end), 0 )<br />
3&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' &#183;&#183;&#183; '&nbsp; then Result end), 0 )<br />
4&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' &#183;&#183;&#183; '&nbsp; then Result end), 0 )<br />
5&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' &#183;&#183;&#183; '&nbsp; then Result end), 0 ) <br />
所以得出：</p>
<p>&nbsp; 代码 <br />
1&nbsp; select stdname,<br />
2&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' 化学 '&nbsp; then Result end), 0 ) [化学],<br />
3&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' 数学 '&nbsp; then Result end), 0 ) [数学],<br />
4&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' 物理 '&nbsp; then Result end), 0 ) [物理],<br />
5&nbsp; isnull(sum( case&nbsp; stdsubject when&nbsp; ' 语文 '&nbsp; then Result end), 0 ) [语文] <br />
6&nbsp; from #student <br />
7&nbsp; group by stdname <br />
然后得出答案：</p>
<p>&nbsp; 代码 <br />
1&nbsp; declare @sql varchar( 4000 ) <br />
2&nbsp; set&nbsp; @sql&nbsp; =&nbsp;&nbsp; ' select stdname '&nbsp; <br />
3&nbsp; select @sql&nbsp; =&nbsp; @sql&nbsp; +&nbsp;&nbsp; ' ,isnull(sum(case stdsubject when&nbsp; ''' + stdsubject + '''&nbsp; then Result end),0) [ ' + stdsubject + ' ] '&nbsp; <br />
4&nbsp; from (select distinct stdsubject from #student)&nbsp; as&nbsp; a <br />
5&nbsp; select @sql&nbsp; =&nbsp; @sql + '&nbsp; from #student group by stdname '&nbsp; <br />
6&nbsp; print @sql<br />
7&nbsp; exec(@sql)<br />
8&nbsp; <br />
压轴题第二问：把表二转化为表一</p>
<p>表一：</p>
<p>&nbsp;</p>
<p>表二：</p>
<p>&nbsp;</p>
<p>数据库代码如下：</p>
<p>&nbsp; 代码 <br />
1&nbsp; DROP table #student2<br />
2&nbsp; CREATE TABLE #student2 (stdname nvarchar( 10 ),化学&nbsp; int ,数学&nbsp; int ,物理&nbsp; int&nbsp; ,语文&nbsp; int&nbsp; )<br />
3&nbsp; INSERT INTO #student2 VALUES ( ' 李四 ' , 164 , 92 , 82 , 85 )<br />
4&nbsp; INSERT INTO #student2 VALUES ( ' 张三 ' , 0 , 90 , 85 , 80 )<br />
5&nbsp; SELECT&nbsp; *&nbsp; FROM #student2&nbsp; <br />
看到这题，直接想到：</p>
<p>&nbsp; 代码 <br />
&nbsp;1&nbsp; SELECT ' 李四 ' as&nbsp; stdname,stdname = ' 化学 ' , 化学&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ' 李四 ' <br />
&nbsp;2&nbsp; union all<br />
&nbsp;3&nbsp; SELECT ' 李四 ' as&nbsp; stdname,stdname = ' 数学 ' , 数学&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ' 李四 ' <br />
&nbsp;4&nbsp; union all<br />
&nbsp;5&nbsp; SELECT ' 李四 ' as&nbsp; stdname,stdname = ' 物理 ' , 物理&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ' 李四 ' <br />
&nbsp;6&nbsp; union all<br />
&nbsp;7&nbsp; SELECT ' 李四 ' as&nbsp; stdname,stdname = ' 语文 ' , 语文&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ' 李四 '&nbsp;&nbsp; <br />
&nbsp; 8&nbsp; union all <br />
&nbsp;9&nbsp; SELECT ' 张三 ' as&nbsp; stdname,stdname = ' 化学 ' , 化学&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ' 张三 ' <br />
10&nbsp; union all<br />
11&nbsp; SELECT ' 张三 ' as&nbsp; stdname,stdname = ' 数学 ' , 数学&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ' 张三 ' <br />
12&nbsp; union all<br />
13&nbsp; SELECT ' 张三 ' as&nbsp; stdname,stdname = ' 物理 ' , 物理&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ' 张三 ' <br />
14&nbsp; union all<br />
15&nbsp; SELECT ' 张三 ' as&nbsp; stdname,stdname = ' 语文 ' , 语文&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ' 张三 ' <br />
&nbsp;重构到：</p>
<p>&nbsp; 代码 <br />
&nbsp;1&nbsp; declare @sql2 varchar( 4000 )<br />
&nbsp;2&nbsp;&nbsp;&nbsp; set&nbsp; @sql2&nbsp; =&nbsp;&nbsp; ''&nbsp; <br />
&nbsp;3&nbsp; SELECT @sql2 = @sql2 +&nbsp; <br />
&nbsp;4&nbsp; ' SELECT ''' + stdname + ''' as stdname,stdname= '' 化学 '' , 化学 as result from #student2 where stdname= ''' + stdname + '''<br />
&nbsp;5&nbsp; union all<br />
&nbsp;6&nbsp; SELECT ''' +stdname+ ''' as&nbsp; stdname,stdname = '' 数学 '' , 数学&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ''' +stdname+ ''' <br />
&nbsp;7&nbsp; union all<br />
&nbsp;8&nbsp; SELECT ''' +stdname+ ''' as&nbsp; stdname,stdname = '' 物理 '' , 物理&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ''' +stdname+ ''' <br />
&nbsp;9&nbsp; union all<br />
10&nbsp; SELECT ''' +stdname+ ''' as&nbsp; stdname,stdname = '' 语文 '' , 语文&nbsp; as&nbsp; result from #student2&nbsp; where&nbsp; stdname = ''' +stdname+ '''&nbsp; union all&nbsp; '<br />
11&nbsp; from (SELECT stdname FROM #student2)&nbsp; as&nbsp; a<br />
12&nbsp; SELECT @sql2&nbsp; =&nbsp; LEFT(@sql2,LEN(@sql2)&nbsp; -&nbsp;&nbsp; 10 )<br />
13&nbsp; PRINT(@sql2)<br />
14&nbsp; exec(@sql2) <br />
如果要求不能出现&nbsp; 化学&nbsp; 数学&nbsp; 物理 语文 这样的关键字，那么可以这样写：</p>
<p>&nbsp; 代码 <br />
&nbsp;1&nbsp; select [name] into #tmpCloumns<br />
&nbsp;2&nbsp; from tempdb.dbo.syscolumns<br />
&nbsp;3&nbsp; where&nbsp; id = object_id( ' tempdb.dbo.#student2 ' )<br />
&nbsp;4&nbsp; and [name] &lt;&gt; ' stdname ' <br />
&nbsp;5&nbsp; select&nbsp; *&nbsp;&nbsp; from #tmpCloumns<br />
&nbsp;6&nbsp; <br />
&nbsp;7&nbsp; declare @strSql nvarchar( 800 )<br />
&nbsp;8&nbsp; select @strSql = '' <br />
&nbsp;9&nbsp; select @strSql = @strSql + ' union all ' + char ( 10 ) + char ( 13 ) + <br />
10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ' select [stdname], ''' + [name] + '''&nbsp; as [科目],[ ' + [name] + ' ] ' + char ( 10 ) + char ( 13 ) + <br />
11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ' from [#student2] ' + char ( 10 ) + char ( 13 )<br />
12&nbsp; from #tmpCloumns<br />
13&nbsp; <br />
14&nbsp; select @strSql = substring(@strSql, 11 ,len(@strSql)) + ' order by stdname,[科目] ' <br />
15&nbsp; -- print @strSql<br />
16&nbsp; exec(@strsql)&nbsp; <br />
&nbsp;这种题目，在各种笔试中出现的概率还是非常大的，大家不用死记。以前有的朋友看着复杂的报表查询，几百行SQL,望而生畏，然后说："这是哪个SQL超人写的啊！"其实，谁一上来不可能写出那么长的SQL,也是慢慢重构--调试--重构-&#183;&#183;&#183;&#183;&#183;&#183;</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/leftfist/archive/2009/12/29/5097307.aspx</p>
<img src ="http://www.blogjava.net/guomingzhang2008/aggbug/315514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/guomingzhang2008/" target="_blank">张国明</a> 2010-03-15 19:58 <a href="http://www.blogjava.net/guomingzhang2008/articles/315514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>