﻿<?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-Java天空 任我翱翔-随笔分类-SQL</title><link>http://www.blogjava.net/persister/category/35521.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 21 Sep 2010 21:58:31 GMT</lastBuildDate><pubDate>Tue, 21 Sep 2010 21:58:31 GMT</pubDate><ttl>60</ttl><item><title>SQL中分组函数的使用及前N条记录的查询方法</title><link>http://www.blogjava.net/persister/archive/2010/05/28/322113.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Fri, 28 May 2010 02:27:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2010/05/28/322113.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/322113.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2010/05/28/322113.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/322113.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/322113.html</trackback:ping><description><![CDATA[在面试的时候我经常会给毕业生出这样一道SQL题：<br />
<br />
有一张表studentgrade，包含三个字段name,subject和grade，如下所示：<br />
<br />
name subject grade<br />
a&nbsp;&nbsp;&nbsp; 数学&nbsp;&nbsp;&nbsp; 99<br />
b&nbsp;&nbsp;&nbsp; 英语&nbsp;&nbsp;&nbsp; 67<br />
a&nbsp;&nbsp;&nbsp; 英语&nbsp;&nbsp;&nbsp; 77 <br />
<br />
题目要求应试者写出sql，查询每个人的最高分和最高分的科目，比如<br />
<br />
a&nbsp;&nbsp; 数学&nbsp; 99<br />
<br />
下面分析这个SQL的查询方法，分组函数是最常使用的，下面的分组函数可以得到最高分，姓名<br />
select name,max(grade) from studentgrade group by name;<br />
<br />
这样显然得不到具体的科目，要得到科目怎么办呢？使用临时表就是一个方案：<br />
<br />
select b.name,b.grade,b.subject from<br />
<br />
(select name, max(grade) grade from studentgrade group by name ) a,<br />
<br />
studentgrade b<br />
<br />
where a.name = b.name and a.grade = b.grade；<br />
<br />
如果是需要查询每个人前三个最高分的成绩和科目呢？分组函数ms就无能为力了。下面是是几个不错的方式：<br />
<br />
1、对每条记录进行检验，查询这条记录是不是排在前三位的<br />
<br />
select a.* from studentgrade a where 3 &gt; (select count(*) from studentgrade where name=a.name and grade&lt; a.grade) order by a.name,a.grade;<br />
<br />
为提高查询效率，在name和grade上面建立联合索引。<br />
<br />
2、先把每个同学最大的三个科目分数查询出来形成一个集合，然后对每条记录进行检验，查看是否在这个集合里面。这种方式是mysql特有的，使用了top关键字。<br />
<br />
select a.* from studentgrade a where grade in (select top 3 grade from studentgrade where
name=a.name order by grade) order by a.name,a.grade;<br />
<br />
3、和第一种方式差不多，但使用的exists关键字。<br />
<br />
select a.* from studentgrade a where exists (select count(*) from studentgrade where name=a.name and grade&lt;a.grade having Count(*) &lt; 2) order by a.name;<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/322113.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2010-05-28 10:27 <a href="http://www.blogjava.net/persister/archive/2010/05/28/322113.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL 中where和左关联用法需要注意的一个地方</title><link>http://www.blogjava.net/persister/archive/2010/01/29/311228.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Fri, 29 Jan 2010 07:39:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2010/01/29/311228.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/311228.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2010/01/29/311228.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/311228.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/311228.html</trackback:ping><description><![CDATA[<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 128, 128);">1</span>&nbsp;<span style="color: rgb(0, 0, 255);">select</span><span style="color: rgb(0, 0, 0);">&nbsp;sre.</span><span style="color: rgb(128, 128, 128);">*</span><span style="color: rgb(0, 0, 0);">,&nbsp;co.description </span><span style="color: rgb(0, 0, 255);"><br />
2 from</span><span style="color: rgb(0, 0, 0);">&nbsp;subscribedratingelement&nbsp;sre&nbsp;</span><span style="color: rgb(255, 0, 255);">left</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">outer</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">join</span><span style="color: rgb(0, 0, 0);">&nbsp;custom_options&nbsp;co&nbsp;</span><span style="color: rgb(0, 0, 255);">on</span><span style="color: rgb(0, 0, 0);">&nbsp;sre.locationInCdr</span><span style="color: rgb(128, 128, 128);">=</span><span style="color: rgb(0, 0, 0);">co.optionvalue&nbsp;<br />
3 </span><span style="color: rgb(0, 0, 255);">where</span><span style="color: rgb(0, 0, 0);">&nbsp;co.optionname</span><span style="color: rgb(128, 128, 128);">=</span><span style="color: rgb(255, 0, 0);">'</span><span style="color: rgb(255, 0, 0);">LocationInCdr</span><span style="color: rgb(255, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">;<br />
</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 128);">4</span>&nbsp;<span style="color: rgb(0, 0, 255);">select</span><span style="color: rgb(0, 0, 0);">&nbsp;sre.</span><span style="color: rgb(128, 128, 128);">*</span><span style="color: rgb(0, 0, 0);">,&nbsp;co.description&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">5</span>&nbsp;<span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);">&nbsp;subscribedratingelement&nbsp;sre&nbsp;</span><span style="color: rgb(255, 0, 255);">left</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">outer</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">join</span><span style="color: rgb(0, 0, 0);">&nbsp;custom_options&nbsp;co&nbsp;<br />
</span><span style="color: rgb(0, 128, 128);">6</span>&nbsp;<span style="color: rgb(0, 0, 255);">on</span><span style="color: rgb(0, 0, 0);"> (sre.locationInCdr</span><span style="color: rgb(128, 128, 128);">=</span><span style="color: rgb(0, 0, 0);">co.optionvalue&nbsp;</span><span style="color: rgb(128, 128, 128);">and</span><span style="color: rgb(0, 0, 0);">&nbsp;co.optionname</span><span style="color: rgb(128, 128, 128);">=</span><span style="color: rgb(255, 0, 0);">'</span><span style="color: rgb(255, 0, 0);">LocationInCdr</span><span style="color: rgb(255, 0, 0);">');</span></div>
<br />
第一条SQL是一个左外连接，然后进行where过滤。仔细分析这个SQL会发现，最后的结果不是所期望的，custom_options表中不符合条件的记录本来是以null表示的，由于where中的过滤，导致查询出来的记录为null的部分都没有查询出来。这个左外连接就和内连接没有任何区别了。<br />
<span style="color: rgb(0, 0, 0);"><br />
第二个SQL语句就可以满足要求。做连接的时候就过滤了右边的一些记录，这样就算右表不符合条件的左表记录也可以查询出来。<br />
</span><br />
<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/311228.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2010-01-29 15:39 <a href="http://www.blogjava.net/persister/archive/2010/01/29/311228.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个SQL左联接的题（查询在一个表而不在另一个表中的记录）</title><link>http://www.blogjava.net/persister/archive/2009/01/06/250182.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 06 Jan 2009 13:57:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/01/06/250182.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/250182.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/01/06/250182.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/250182.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/250182.html</trackback:ping><description><![CDATA[问题：<br />
<br />
查询一个表（tb1）的字段记录不在另一个表（tb2）中 &nbsp; <br />
&nbsp; 条件：tb1的字段key的值不在tbl2表中 &nbsp; <br />
&nbsp; －－－－－－－－－－－－－－－－－－－－－－&nbsp;&nbsp;&nbsp;<br />
最原始的写法： &nbsp; <br />
&nbsp; select &nbsp; A.* &nbsp; from &nbsp; tbl1&nbsp;A&nbsp;where &nbsp; A.key &nbsp; not &nbsp; in &nbsp; (select &nbsp; key &nbsp; from &nbsp; tbl2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp; <br />
如果tbl2表中数据量很大，比如数据上百万条，每次都这样匹配效率会非常低。&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; <br />
<br />
解决问题：<br />
<br />
<p>SELECT tb1.* FROM tb1 LEFT JOIN tb2 ON tb1.id=tb2.id WHERE tb2.id IS NULL;</p>
<br />
关于sql语句中的连接（join）关键字，是较为常用而又不太容易理解的关键字，下面这个例子<br />
<br />
给出了一个简单的解释，相信会对你有所启示。<br />
<br />
<br />
--建表table1,table2：<br />
create table table1(id int,name varchar(10))<br />
create table table2(id int,score int)<br />
insert into table1 select 1,'lee'<br />
insert into table1 select 2,'zhang'<br />
insert into table1 select 4,'wang'<br />
insert into table2 select 1,90<br />
insert into table2 select 2,100<br />
insert into table2 select 3,70<br />
如表<br />
-------------------------------------------------<br />
&nbsp;table1&nbsp; | table2&nbsp; |<br />
-------------------------------------------------<br />
id&nbsp; name |id&nbsp; score |<br />
1&nbsp; lee |1&nbsp; 90 |<br />
2&nbsp; zhang |2&nbsp; 100 |<br />
4&nbsp; wang |3&nbsp; 70 |<br />
-------------------------------------------------<br />
<br />
以下均在查询分析器中执行<br />
<br />
一、外连接<br />
1.概念：包括左向外联接、右向外联接或完整外部联接<br />
<br />
2.左连接：left join 或 left outer join<br />
(1)左向外联接的结果集包括 LEFT OUTER 子句中指定的左表的所有行，而不仅仅是联接列所匹<br />
<br />
配的行。如果左表的某行在右表中没有匹配行，则在相关联的结果集行中右表的所有选择列表列<br />
<br />
均为空值(null)。<br />
(2)sql语句<br />
select * from table1 left join table2 on table1.id=table2.id<br />
-------------结果-------------<br />
id name id score<br />
------------------------------<br />
1 lee 1 90<br />
2 zhang 2 100<br />
4 wang NULL NULL<br />
------------------------------<br />
注释：包含table1的所有子句，根据指定条件返回table2相应的字段，不符合的以null显示<br />
<br />
3.右连接：right join 或 right outer join<br />
(1)右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有<br />
<br />
匹配行，则将为左表返回空值。<br />
(2)sql语句<br />
select * from table1 right join table2 on table1.id=table2.id<br />
-------------结果-------------<br />
id name id score<br />
------------------------------<br />
1 lee 1 90<br />
2 zhang 2 100<br />
NULL NULL 3 70<br />
------------------------------<br />
注释：包含table2的所有子句，根据指定条件返回table1相应的字段，不符合的以null显示<br />
<br />
4.完整外部联接:full join 或 full outer join<br />
(1)完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时，则另一个表<br />
<br />
的选择列表列包含空值。如果表之间有匹配行，则整个结果集行包含基表的数据值。<br />
(2)sql语句<br />
select * from table1 full join table2 on table1.id=table2.id<br />
-------------结果-------------<br />
id name id score<br />
------------------------------<br />
1 lee 1 90<br />
2 zhang 2 100<br />
4 wang NULL NULL<br />
NULL NULL 3 70<br />
------------------------------<br />
注释：返回左右连接的和（见上左、右连接）<br />
<br />
二、内连接<br />
1.概念：内联接是用比较运算符比较要联接列的值的联接<br />
<br />
2.内连接：join 或 inner join<br />
<br />
3.sql语句<br />
select * from table1 join table2 on table1.id=table2.id<br />
-------------结果-------------<br />
id name id score<br />
------------------------------<br />
1 lee 1 90<br />
2 zhang 2 100<br />
------------------------------<br />
注释：只返回符合条件的table1和table2的列<br />
<br />
4.等价（与下列执行效果相同）<br />
A:select a.*,b.* from table1 a,table2 b where a.id=b.id<br />
B:select * from table1 cross join table2 where table1.id=table2.id&nbsp; (注：cross join<br />
<br />
后加条件只能用where,不能用on)<br />
<br />
三、交叉连接(完全)<br />
<br />
1.概念：没有 WHERE 子句的交叉联接将产生联接所涉及的表的笛卡尔积。第一个表的行数乘以<br />
<br />
第二个表的行数等于笛卡尔积结果集的大小。（table1和table2交叉连接产生3*3=9条记录）<br />
<br />
2.交叉连接：cross join (不带条件where...)<br />
<br />
3.sql语句<br />
select * from table1 cross join table2<br />
-------------结果-------------<br />
id name id score<br />
------------------------------<br />
1 lee 1 90<br />
2 zhang 1 90<br />
4 wang 1 90<br />
1 lee 2 100<br />
2 zhang 2 100<br />
4 wang 2 100<br />
1 lee 3 70<br />
2 zhang 3 70<br />
4 wang 3 70<br />
------------------------------<br />
注释：返回3*3=9条记录，即笛卡尔积<br />
<br />
4.等价（与下列执行效果相同）<br />
A:select * from table1,table2<br />
<br />
<br />
左连接如果要关联三张表，那么接连使用两个left outer join和on组合。<br />
<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/250182.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-01-06 21:57 <a href="http://www.blogjava.net/persister/archive/2009/01/06/250182.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>union和union all用法及效率</title><link>http://www.blogjava.net/persister/archive/2007/09/27/148533.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Thu, 27 Sep 2007 02:19:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2007/09/27/148533.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/148533.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2007/09/27/148533.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/148533.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/148533.html</trackback:ping><description><![CDATA[<a href="http://sql.1keydata.com/cn/sql-union.php">union</a>和<a href="http://sql.1keydata.com/cn/sql-unionall.php">union all</a>的语法不说了，只是强调一下两者的区别：<br />
union all的执行效率要比sql union效率要高很多，这是因为，使用union需要进行排重，而union all是不需要排重的，这一点非常重要，因为对于一些单纯地使用分表来提高效率的查询，完全可以使用union all。
<br />
还有，如果使用了union，无论是union还是union all一定要记住对数据库表加上索引。<br />
<img src ="http://www.blogjava.net/persister/aggbug/148533.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2007-09-27 10:19 <a href="http://www.blogjava.net/persister/archive/2007/09/27/148533.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>