1.理论
只要两个表的公共字段有匹配值,就将这两个表中的记录组合起来。
个人理解:以一个共同的字段求两个表中符合要求的交集,并将每个表符合要求的记录以共同的字段为牵引合并起来。
语法
FROM table1 INNER JOIN table2 ON table1 . field1 compopr table2 . field2
INNER JOIN 操作包含以下部分:
部分 | 说明 |
table1, table2 | 要组合其中的记录的表的名称。 |
field1,field2 | 要联接的字段的名称。如果它们不是数字,则这些字段的数据类型必须相同,并且包含同类数据,但是,它们不必具有相同的名称。 |
compopr | 任何关系比较运算符:“=”、“<”、“>”、“<=”、“>=”或者“<>”。 |
说明
可以在任何 FROM 子句中使用 INNER JOIN 操作。这是最常用的联接类型。只要两个表的公共字段上存在相匹配的值,Inner 联接就会组合这些表中的记录。
可以将 INNER JOIN 用于 Departments 及 Employees 表,以选择出每个部门的所有雇员。而要选择所有部分(即使某些部门中并没有被分配雇员)或者所有雇员(即使某些雇员没有分配到任何部门),则可以通过 LEFT JOIN 或者 RIGHT JOIN 操作来创建外部联接。
如果试图联接包含备注或 OLE 对象数据的字段,将发生错误。
可以联接任何两个相似类型的数字字段。例如,可以联接自动编号和长整型字段,因为它们均是相似类型。然而,不能联接单精度型和双精度型类型字段。
下例展示了如何通过 CategoryID 字段联接 Categories 和 Products 表:
SELECT CategoryName, ProductName
FROM Categories INNER JOIN Products
ON Categories.CategoryID = Products.CategoryID;
在前面的示例中,CategoryID 是被联接字段,但是它不包含在查询输出中,因为它不包含在 SELECT 语句中。若要包含被联接字段,请在 SELECT 语句中包含该字段名,在本例中是指 Categories.CategoryID。
也可以在 JOIN 语句中链接多个 ON 子句,请使用如下语法:
SELECT fields
FROM table1 INNER JOIN table2
ON table1.field1 compopr table2.field1 AND
ON table1.field2 compopr table2.field2) OR
ON table1.field3 compopr table2.field3)];
也可以通过如下语法嵌套 JOIN 语句:
SELECT fields
FROM table1 INNER JOIN
(table2 INNER JOIN [( ]table3
[INNER JOIN [( ]tablex [INNER JOIN ...)]
ON table3.field3 compopr tablex.fieldx)]
ON table2.field2 compopr table3.field3)
ON table1.field1 compopr table2.field2;
LEFT JOIN 或 RIGHT JOIN 可以嵌套在 INNER JOIN 之中,但是 INNER JOIN 不能嵌套于 LEFT JOIN 或 RIGHT JOIN 之中。
2.操作实例
表A记录如下:
aID aNum
1 a20050111
2 a20050112
3 a20050113
4 a20050114
5 a20050115
表B记录如下:
bID bName
1 2006032401
2 2006032402
3 2006032403
4 2006032404
8 2006032408
实验如下:
1.left join
sql语句如下:
select * from A
left join B
on A.aID = B.bID
结果如下:
aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
5 a20050115 NULL NULL
(所影响的行数为 5 行)
结果说明:
left join是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的.
换句话说,左表(A)的记录将会全部表示出来,而右表(B)只会显示符合搜索条件的记录(例子中为: A.aID = B.bID).
B表记录不足的地方均为NULL.
2.right join
sql语句如下:
select * from A
right join B
on A.aID = B.bID
结果如下:
aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
NULL NULL 8 2006032408
(所影响的行数为 5 行)
结果说明:
仔细观察一下,就会发现,和left join的结果刚好相反,这次是以右表(B)为基础的,A表不足的地方用NULL填充.
3.inner join
sql语句如下:
select * from A
innerjoin B
on A.aID = B.bID
结果如下:
aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
谈用url重写的方法替代生成静态页面的好处
[color=Red]声明:这个是一篇asp.net的技术文章,为本人原创并首发。[/color]
本来不想写了,因为写了net 下的采集技术文章,没人理,有点伤自尊。但昨天发布了自已网站的全部小偷程序,有朋友支持了,有了点自信,这次再写点。请朋友们帮顶.
大家喜欢生成静态页,我从来不。生成html的好处有三点;一是减少服务器对数据响应的负荷,二速度快。三,化化引擎。问题也有两点:1,维护不方便,要手动。2。。空间占用大。3,服务器对html文件的响应也较重。
我从来不用这种方法,理由,我是业余站长,自己有几个所谓的垃圾站,维护不起。我的空间是租的,一个空间放几个站,没那么大。我的方法就是用url重写来替代.url重写技术在asp.net,php,jsp下都有,asp下我对此不太了解,就不说了.什么是url重写,就是用个虚拟url替代真实的路径。例:show.aspx?id=电脑,对于这样一个页面,引擎支持不好,用户也不好记,我们可以用这种技术生成“电脑.aspx”的虚拟url,好记了,引擎也支持得比较好了,同里,一篇文章art.aspx?id=1234,我可以写成art1234.aspx
net下有两种重写技术,其中一个可以生成任何后缀的页面如:art1234.htm,但这种方法,要服务器支持,第二种仅生成.aspx文件。我用后一种,因为是租用的空间.
关于这种技术,不是一篇文章能说得清的,可以上msdn中有一篇e文的文章,作者是net下开源blog的那个老外,并有相关类下载。
在这里重点不是谈技术,是说思路。我用这种方法得到的好处很多。说下体会:1,用这个技术,占空间小,仅数据库的空间.引擎支持和html格式没有什么差别。2,不用手动维护了,首页你不是有热点排行吗,或其它的,这样每天首页都会动,生成html,你不手动,它就不变了。3,动态页还有很多好处,比如:广告可以轮显.你可以把art1234.aspx,这个虚成n个页,如art1.aspx?id=1234,art2.aspx?,artn.aspx?id=1234id=1234,在不同的页面放不同的广告.什么点击数等,你都可以自由显示,总之是动态的,你就可以随意动。
问题:我看只有一个,那就是效率不如生成html的,但你可以用缓存技术来补偿一下。net下有三种缓存,数据的,片断的,页面的,综合用,广告页都作成用户控件加片断缓,可有效的防广告挂的问题。
最后给出我的站做例子。这是个新的垃圾站,[url]www.mn007.com[/url]。
我的站做得都不怎么样,收入也不行。但我付出的精力少,还算收入/付出比,还是很高的。我的站一般都是一两个月才管理一次。平时就是看看流量,广告等。当然,我的站里还有别的技术,是url重写,采集,自动更新,广告轮显,三种缓存技术的结合。可惜,我美工一点也不会,连图也不会处理,外观真不怎么样。技术细节先不说,等以后发,好积分落伍。
<script type="text/javascript">function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>
一,页输出缓存导致的问题
问题描述:在一个网站首页,有几个用户登录的框框,登陆后要隐藏起来,并显示用户的相关信息,因为这个是首页,考虑到访问量很大,而且页面的更新也比较少,所以使用<%@ OutputCache Duration="60" VaryByParam="none"%>来启用页输出缓存,但发现一个问题:第二用户用户登录后,看到确是第一个用户的登陆信息
问题分析:页输出缓存是在第一个用户发出请求后,把从动态页中生成的静态内容缓存在服务器的高速缓冲中,在设定的时间内,后续的请求都从该缓存中响应,所以就有可能出现上面描述的问题了
问题解决:不使用页输出缓存,这个是为个性化牺牲性能,但为了尽量减少性能
损失,除了在中间成做数据缓存外,还要对页面通过用户控件拆分,进行页片断缓存
总结:通过这个问题,我发现凡是需要显示个性化信息的地方,通常都不合适做页输出缓存,针对这个问题,为了提高性能,我有几个想法:
1,登陆区域尽量考虑放在另一个页面中进行登陆 ;
2,需要个性化的信息放在另一页,然后iframe进来,这样页面可以同时兼顾个性 话和性能,适合个性化信息比较少的情况 ;
3,如果页面确实不能做页输出缓存,那要考虑是否可以做页片断缓存,始终要
考虑是否应该进行数据缓存的问题
二,数据缓存引起的问题
问题描述 :
我们对从数据库中获取到的年纪信息进行缓存,代码如下:
public static GradeCollection GetGrades()
{
string cacheKey = "GradeCollection" ;
if (HttpRuntime.Cache[cacheKey] == null)
HttpRuntime.Cache[cacheKey] = DataProvider.GetGrades() ;
return (GradeCollection)HttpRuntime.Cache[cacheKey] ;
}
然后把数据加工后再邦定到一个dropdownlist中:
GradeCollection gc = GetGrades() ;
Grade g = new Grade() ;
g.GradeName = "所有年级" ;
gc.Insert(0,g) ;
问题就出来,运行完这段代码,别的地方再GetGrades()获得数据将会是被改动
过的数据,这并不是我们所期望的
问题解决 :不能对获取的数据进行改动,我们的目的是在dropdownlist上加上一个“所有年级”项,这个是可以在控件上实现的,就不应该对数据加工了,但问题是我们无法确定其他地方GetGrades()后会进行什么操作,一个方法的数据安全不
应该依赖于调用者的,所以需要对做了数据缓存的地方进行改动:
public static GradeCollection GetGrades()
{
string cacheKey = "GradeCollection" ;
if (HttpRuntime.Cache[cacheKey] == null)
HttpRuntime.Cache[cacheKey] = DataProvider.GetGrades() ;
GradeCollection gc = (GradeCollection)HttpRuntime.Cache[cacheKey] ;
return gc.DeepClone() ;//返回gc的深拷贝,具体方法略
}
虽然这样做,占用的内存会更多,性能上有折损,但数据更安全,程序更健壮了
同时也比不使用数据缓存性能更高一些
但同时得承认,这不是一个很好的解决方法,不知道各位大虾有没有遇到这类问题
你是怎么解决的?望指点一二,不胜感激了!
1、进程和线程的区别
进程是系统进行资源分配和调度的单位;线程是CPU调度和分派的单位,一个进程可以有多个线程,这些线程共享这个进程的资源。
2、成员变量和成员函数前加static的作用
它们被称为常成员变量和常成员函数,又称为类成员变量和类成员函数。分别用来反映类的状态。比如类成员变量可以用来统计类实例的数量
,类成员函数负责这种统计的动作。
3、malloc和new的区别
new是C++的关键字。malloc在分配内存时必须按给出的字节分配,new可以按照对象的大小自动分配,并且能调用构造函数。可以说new是对象
的对象,而malloc不是。本质上new分配内存时,还会在实际内存块的前后加上附加信息,所以new所使用的内存大小比malloc多。
4、堆和栈的区别
栈:由编译器自动分配、释放。在函数体中定义的变量通常在栈上。
堆:一般由程序员分配释放。用new、malloc等分配内存函数分配得到的就是在堆上。
栈是机器系统提供的数据结构,而堆则是C/C++函数库提供的。
栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而栈是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效
率有一定降低。栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。不同堆分配的内存无法互相操作。栈空
间分静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由alloca函数完成。栈的动态分配无需释放(
是自动的),也就没有释放函数。为可移植的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数
据空间都会被释放回系统,但是精确的申请内存/释放内存匹配是良好程序的基本要素。