论坛经常有人会问到用CSS如何美化Select标签,其实但凡你看到很酷的都是用javascript来实现的。昨天试着做了一下,基本实现的初级功能。拿出来和大家一起分享一下。
先可以看一下预览效果:http://www.iwcn.net/demo/select
功能需求
1、调用要方便,做好之后应该像这样:
function loadSelect(selectobj){
//传入一个select对象就能将他的样式美化
}
2、不改变原有表单项,表单的页面代码不去破坏:
<form name="f" onsubmit="getResult();">
<fieldset>
<legend>用户注册</legend>
<div>
<label for="username">帐号</label>
<input type="text" id="username" name="username" />
</div>
<div>
<label for="pwd">密码</label>
<input type="password" name="pwd" id="pwd" />
</div>
<div>
<label for="province">省份</label>
<select id="province" name="province">
<option value="10">江西</option>
<option value="11">福建</option>
<option value="12">广东</option>
<option value="13">浙江</option>
</select>
</div>
</fieldset>
<input type="submit" value="提交" name="btnSub" />
</form>
实现思路
- 第一步:将表单中的select隐藏起来。
为什么?很简单,因为这家伙太顽固了,用css根本搞不出来你想要的。所以把它杀掉。 - 第二步:用脚本找到select标签在网页上的绝对位置。
我们在那个位置上用DIV标签做个假的、好看点的来当他的替身。 - 第三步:用脚本把select标签中的值读出来。
虽然藏起来了,但它里边的options我们还有用呢,统统取过来。 - 第四步:当用户点击select标签的替身,也就是div的时候。我们再用一个div浮在上一个div的下边,这个就是options的替身了。
大致上就是这样了,接下来我们一步一步去实现它!
准备工作
- 1、想好你要把select美化成什么样子,并准备好相应的图片。我准备了两张小图,就是下拉箭头1和下拉箭头2,1是默认样式,2是鼠标移过来的样式。
- 2、写好一个普通的表单递交页面,比如下边这个。注意我给select定义了基本的CSS样式、在头部添加了调用js文件的代码、在body中添加了调用函数的脚本。
运行代码框
编写javascript
<script type="text/javascript" src="select.js"></script>
新建一个js文件并保存为select.js,剩下的工作我们全部在这个js中去完成。
函数名:loadSelect(obj);
参数:select对象
相关函数:
//取标签的绝对位置
{
var t = e.offsetTop;
var l = e.offsetLeft;
var w = e.offsetWidth;
var h = e.offsetHeight-2;
while(e=e.offsetParent)
{
t =e.offsetTop;
l =e.offsetLeft;
}
return {
top : t,
left : l,
width : w,
height : h
}
}
第一步:把select的绝对位置记录下来。一会替身上来就知道应该站那里了。
var offset=Offset(obj);
//这里解释一下Offset是一个函数,用来获取对象的绝对位置。写在loadSelect()函数外边的。他有四个属性分别是top/left/width/height。
第二步:将select隐藏。
obj.style.display="none";
第三步:虚拟一个div出来代替select
var iDiv = document.createElement("div");
iDiv.id="selectof" obj.name;
iDiv.style.position = "absolute";
iDiv.style.width=offset.width "px";
iDiv.style.height=offset.height "px";
iDiv.style.top=offset.top "px";
iDiv.style.left=offset.left "px";
iDiv.style.background="url(icon_select.gif) no-repeat right 4px";
iDiv.style.border="1px solid #3366ff";
iDiv.style.fontSize="12px";
iDiv.style.lineHeight=offset.height "px";
iDiv.style.textIndent="4px";
document.body.appendChild(iDiv);
第四步:把原始select没人选中的值给它。
iDiv.innerHTML=obj.options[obj.selectedIndex].innerHTML;
第五步:为替身添加鼠标移过样式。
iDiv.onmouseover=function(){//鼠标移到
iDiv.style.background="url(icon_select_focus.gif) no-repeat right 4px";
}
iDiv.onmouseout=function(){//鼠标移走
iDiv.style.background="url(icon_select.gif) no-repeat right 4px";
}
第六步:添加关键的鼠标点击事件。
iDiv.onclick=function(){//鼠标点击
if (document.getElementById("selectchild" obj.name)){
//判断是否创建过div
if (childCreate){
//判断当前的下拉是不是打开状态,如果是打开的就关闭掉。是关闭的就打开。
document.getElementById("selectchild" obj.name).style.display="none";
childCreate=false;
}else{
document.getElementById("selectchild" obj.name).style.display="";
childCreate=true;
}
}else{
//初始一个div放在上一个div下边,当options的替身。
var cDiv = document.createElement("div");
cDiv.id="selectchild" obj.name;
cDiv.style.position = "absolute";
cDiv.style.width=offset.width "px";
cDiv.style.height=obj.options.length *20 "px";
cDiv.style.top=(offset.top offset.height 2) "px";
cDiv.style.left=offset.left "px";
cDiv.style.background="#f7f7f7";
cDiv.style.border="1px solid silver";
var uUl = document.createElement("ul");
uUl.id="uUlchild" obj.name;
uUl.style.listStyle="none";
uUl.style.margin="0";
uUl.style.padding="0";
uUl.style.fontSize="12px";
cDiv.appendChild(uUl);
document.body.appendChild(cDiv);
childCreate=true;
for (var i=0;i<obj.options.length;i ){
//将原始的select标签中的options添加到li中
var lLi=document.createElement("li");
lLi.id=obj.options[i].value;
lLi.style.textIndent="4px";
lLi.style.height="20px";
lLi.style.lineHeight="20px";
lLi.innerHTML=obj.options[i].innerHTML;
uUl.appendChild(lLi);
}
var liObj=document.getElementById("uUlchild" obj.name).getElementsByTagName("li");
for (var j=0;j<obj.options.length;j ){
//为li标签添加鼠标事件
liObj[j].onmouseover=function(){
this.style.background="gray";
this.style.color="white";
}
liObj[j].onmouseout=function(){
this.style.background="white";
this.style.color="black";
}
liObj[j].onclick=function(){
//做两件事情,一是将用户选择的保存到原始select标签中,要不做的再好看表单递交后也获取不到select的值了。
obj.options.length=0;
obj.options[0]=new Option(this.innerHTML,this.id);
//同时我们把下拉的关闭掉。
document.getElementById("selectchild" obj.name).style.display="none";
childCreate=false;
iDiv.innerHTML=this.innerHTML;
}
}
}
}
最后这个比较复杂一点,再解释一下,我们在做这一步之前,select的样子已经出来了,下一步就是再加一个div去模仿select被点击之后出现的下拉选项了。我们可以讲select标签的options通过javascript提取出来,把它写成这样:
<div>
<ul>
<li>optionName</li>
<li>optionName</li>
<li>optionName</li>
</ul>
</div>
基本上就这样了。还有些缺陷,有时间大家可以一起补充!
层叠式样表(CSS)正迅速成为网页布局与定位的实际标准。它们易于使用、不需要任何特殊的软件、并可在大多数主要的浏览器上应用。但是,正确使用它们需要全面了解一个特殊布局的功能性目的,保证生成的样式表在逻辑和功能上都能正确使用,并能够与各种浏览器和查看设备兼容。
通常,Web开发者往往无法理解式样表的这个特殊问题,导致要在代码中使用大量的“hack”才能获得预期的结果。为解决这个问题,很值得花一些时间来理解CSS的一些核心驱动程序和概念。开发者需要了解的一个最重要的概念是所谓的浮动元素,它在对齐和定位网页元素方面发挥着重要的作用。
本文简单介绍这些浮动元素,解释CSS float和clear命令,并提供它们的一些应用实例,以更好的定位网页中的HTML元素。
浮动元素
基本上,一个属性为float的元素移出了网页的正常流程以外,它在空间“飘浮”,周围环绕着一些内容。因此,一个向左浮动的元素有文本在它的右侧运动,并环绕着它的底边;一个向右浮动的元素将有内容在它的左侧移动。
float属性可以取三个可能的值:left,使元素向左浮动;right,使元素向右浮动;none,消除浮动。对一个元素应用float属性会自动将它转变成一个块级元素。其它非式样元素忽略浮动,就好像它不存在一样。如果一个浮动撞上文件中在前面生成的同一侧的另一个浮动,它必须要么保持向前面生成的浮动右侧浮动(如果有足够的空间),要么在它下面浮动(如果空间不够)。
例1:在图像周围环绕文本
为了更好的理解浮动,我们来看一个简单的例子:用CSS的float属性代替HTML的ALIGN属性。查看下面的例子(列表A),它向左浮动一幅图片,并用描述性的文本环绕四周:
列表A
<html>
<head>
<style type="text/css">
.floater {
float: left;
border: solid 1px black;
padding: 5px;
margin: 5px;
width: 100px;
height: 75px;
}
</style>
</head>
<body>
<img class="floater" src="pix2180.jpg" />
Loremipsum dolor sit amet, consecteturadipisicingelit, sed do eiusmodtemporincididuntutlabore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteursintoccaecatcupidatat non proident, sunt in culpa qui officiadeseruntmollitanim id estlaborum. Loremipsumdolor sitamet, consecteturadipisicingelit, sed do eiusmodtemporincididuntutlabore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
</body>
</html>
图A显示输出结果。

在这种情况下,图片向左浮动,使得周围的内容流向右边然后包围它的下方。而且,当你改变浏览器窗口大小时,保存文本的“方框”的大小也随之动态地调整。
例2:两栏布局,两边都有图片
让我们看一个复杂一些的例子,建立一个两栏布局,每一栏中包含一幅图片和一些文字内容(列表B)。为增加趣味性,我们将左栏中的图片设为左对齐,右栏中的图片设为右对齐。
列表B
<html>
<head>
<style type="text/css">
div {
width: 48%;
padding: 5px;
}
img {
padding: 5px;
margin: 5px 15px 5px 5px;
width: 100px;
height: 75px;
}
</style>
</head>
<body>
<div style="float: left">
<img style="float: left" src="pix2180.jpg" />
Loremipsum dolor sit amet, consecteturadipisicingelit, sed do eiusmodtemporincididuntutlabore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteursintoccaecatcupidatat non proident, sunt in culpa qui officiadeseruntmollitanim id estlaborum.
</div>
<div style="float: right">
<img style="float: right" src="http://www.melonfire.com/account/tools/ig/galleries/Places/Greece/Santorini/IMG_2180.JPG" />
Loremipsum dolor sit amet, consecteturadipisicingelit, sed do eiusmodtemporincididuntutlaboreetdolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteursintoccaecatcupidatat non proident, sunt in culpa qui officiadeseruntmollitanim id estlaborum.
</div>
</body>
</html>
应用浮动,实现这个页面并不特别困难:只要为每一栏建立一个<div>,然后在每个<div>里面放一幅浮动的图片和一些文字。接下来,浮动<div>本身,一个向左,另一个向右。图B显示输出结果。
图B

清除元素
float属性的一个同伴是clear属性,它控制跟随一个浮动的元素的位置。这个属性中用来防止内容跟随一个浮动的元素,迫使它移动到浮动的下一行。
clear属性可以取四个值:left,它把元素推到前面生成的向左浮动的元素下面;right,它把元素推到前面生成的向右浮动的元素下面;both,它把元素推到前面生成的所有元素下面;和none,它取消前面的定位。有趣的是,clear属性不像人们认为的那样,仅限于非浮动元素;相反,它还可以用来控制浮动元素的行为,把一个浮动元素推到其它浮动元素下面。
例3:垂直图片栏,周围环绕文本
要理解这种情况,请看下面的例子(列表C),它创造性的使用float和clear属性,将一组图片垂直排列。
列表C
<html>
<head>
<style type="text/css">
.floater {
float: left;
clear: left;
border: solid 1px black;
padding: 5px;
margin: 5px 15px 5px 5px;
width: 100px;
height: 75px;
}
</style>
</head>
<body>
<img class="floater" src="pix2180.jpg" />
<img class="floater" src="pix2181.jpg" />
Loremipsum dolor sit amet, consecteturadipisicingelit, sed do eiusmodtemporincididuntutlabore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteursintoccaecatcupidatat non proident, sunt in culpa qui officiadeseruntmollitanim id estlaborum. Loremipsumdolor sitamet, consecteturadipisicingelit, sed do eiusmodtemporincididuntutlabore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
</body>
</html>
这里的所有图片都向左浮动,clear的使用情况:第二幅图片的left属性保证它被推到第一幅图片下面,建立一种垂直结构。注意,第一幅图片也使用了clear属性,但因为它上面没有图片,所以没有产生效果。使用float属性也保证页面(重要的是,它是非式样页面)中的文本块围绕在图片栏周围。
以下是输出结果(图C):

当然,这三个例子只是浮动元素应用的冰山一角。应用float和clear属性,还可以实现更多布局和更灵活的界面设计。但是,上面的例子应能让你了解这些属性的实际应用,你现在应该有足够的知识开始自己的实践。那你还等什么?开始吧——编码快乐!
在以前的web开发栏目中,我介绍了不少处理HTML表格的方法,尽管现在使用表格来布局网页的方法已经不再时髦了,但是您依然可以使用表格来显示表列数据。
显示和样式化表格的方法有很多种,在这篇文章中,我将介绍使用CSS对表格边框进行样式化的方法。
链接
CSS2表格模型是基于HTML 4.01表格模型的。表格包含了一个可选的锚标记和单元格以及数据行,表格模型包含以下的元素:表格、锚、数据行、数据行组、数据列、数据列组和单元格。这篇文章将集中讲解表格中各个元素的边框处理方法。
边框
根据不同的需求,您可以对表格和单元格应用不同的边框。您可以定义整个表格的边框也可以对单独的单元格分别进行定义。CSS的边框属性可以指定边框的大小以及颜色和类型。以下的代码定义了宽度为5个像素的黑色实线边框:
TABLE
除此以外,您还可以使用相同的语法为表格中单独的单元格分别指定边框属性。您可以使用以下的属性值来定义边框类型:
l none: 指定表格没有边框,所以边框宽度为0。
l dotted: 由点线组成的表格边框。
l dashed: 由虚线组成的表格边框。
l solid: 由实线组成的表格边框。
l Double: 由双实线组成的表格边框。
l Groove: 槽线效果边框。
l ridge: 脊线效果边框,和槽线效果相反。
l inset: 内凹效果边框。
l outset: 外凸效果边框,和内凹效果相反。
每个边框类型都可以指定一种颜色,边框是绘制在背景颜色上的,列表A使用边框属性来样式化整个表格以及锚标记和单独的单元格。
<html>
<head><title>HTML Table</title></head>
<style type="text/css">
TABLE {
background: blue;
border-collapse: separate;
border-spacing:
border: 5px solid red; }
TD, TH {
background: white;
border: inset
horizontal-align: right; }
CAPTION
</style><body>
<table summary="TechRepublic.com - Tables and CSS">
<caption>First Quarter Sales</caption>
<thead><tr>
<thabbr="salesperson" scope="col">Person</th>
<thabbr="sales" scope="col">Sales</th>
</tr></thead>
<tbody><tr>
<td>Mr. Smith</td>
<td>600.00</td>
</tr><tr>
<td>Mr. Jones</td>
<td>0000.00</td>
</tr><tr>
<td>Ms. Williams</td>
<td>0000.00</td>
</tr></tbody>
<tfoot><tr>
<td colspan="2">Let's sale, sale, sale!</td>
</tr></tfoot></table></body></html>
列表A
这个例子展示了很多可供使用的表格边框的选项,您可以使用您熟悉的度量单位(像素、磅,行长单位等)。设定边框的尺寸,您可以使用十六进制数值或颜色名称来指定边框颜色。以下的例子演示了定义边框的方法。
border: 5px solid red;
在这一条语句中融合了宽度、样式和颜色属性的定义,但是您也可以对这些元素进行单独定义,如下所示:
border-width: 5px;
border-style: solid;
border-color: red;
除了将表格作为一个整体进行定义,您也可以将表格边框的四个部分分别进行定义,包括顶部、底部、左边和右边。列表B中的代码将刚才的例子中的表格分成四个部分单独定义。
<html><head><title>HTML Table</title></head>
<style type="text/css">
TABLE {
background: blue;
border-collapse: separate;
border-spacing:
border-top: 15px solid red;
border-left: 15px solid red;
border-right: 5px dashed black;
border-bottom: 10px dashed blue; }
TD, TH {
background: white;
border: outset
horizontal-align: right; }
CAPTION {
border: ridge
border-top: ridge
</style><body>
<table summary="TechRepublic.com - Tables and CSS">
<caption>First Quarter Sales</caption>
<thead><tr>
<thabbr="salesperson" scope="col">Person</th>
<thabbr="sales" scope="col">Sales</th>
</tr></thead>
<tbody><tr>
<td>Mr. Smith</td>
<td>600.00</td>
</tr><tr>
<td>Mr. Jones</td>
<td>0000.00</td>
</tr><tr>
<td>Ms. Williams</td>
<td>0000.00</td>
</tr></tbody>
<tfoot><tr>
<td colspan="2">Let's sale, sale, sale!</td>
</tr></tfoot></table></body></html>
列表B
您可能注意到了整个CAPTION元素的边框定义为蓝色
除此以外,在上一个例子中,通过分配TABLE元素的边框属性,可以在一个表格中实现多重边框(锚标记、表格主体、表头、单独的单元格等等)。
边框间距
您可以通过边框间距属性来指定相邻的单元格之间的距离,您可以指定一个或两个值,如果指定了一个值,那么水平和垂直间距都将使用这一个值;如果指定了两个值,那么第一个值规定了水平间距而第二个值指定了垂直间距。这些值不能是负值,我在这个例子中使用了
表格行为
边框的collapse属性设定了表格的边框模型,该属性的默认值是独立的边框模型,单独的边框模型使用border-spacing属性作为不同边框之间的间距,该间距使用表格元素作为填充背景。
对于边框模型中,万维网联盟(World Wide Web Consortium)定义了以下的规则来解决表格样式的冲突:
l 使用‘隐藏’边框属性的边框优先于其他的边框属性,任何使用‘隐藏’属性的边框比其它的边框属性处理优先级要高。
l 使用‘无样式’边框的优先级最低,如果在同一位置所有元素的边框属性都是‘无样式’,表格边框才会被忽略。(注意,‘无样式’是边框样式的默认值。)
l 如果没有样式设置为‘隐藏’而且至少有一个样式没有设置为‘无样式’,那么宽边框的优先级高于细边框。边框样式的优先级如下:双实线、单实线、虚线、点线、脊线、外凸、槽线,级别最低的是内凹。
l 如果边框样式只有颜色不同,那么单元格的样式优先级高于行的优先级,而且高于行组、列、列组和整个表格。
边框
表格和其他的HTML元素一样,拥有很多CSS样式选项。表格和单元格的边框是一个很好的例子,CSS应当可以满足您对表格样式的需要。但是使用CSS格式化的表格在不同的浏览器中会显示出不同的效果,因此需要进行广泛的测试。
您是CSS的‘粉丝’么?您在HTML表格的样式上使用了那些选项?请在文章的讨论区共享您的经验。
你也许已经意识到,你可以通过指定每一键接的不同风格以建立CSS翻滚效果,这些链接包括普通的链接link (normal), 访问,翻转,以及激活。并且,你可能也知道CSS类型的顺序可以产生效果上的差别,CSS代码后顺序的风格将会取代针对于相同元素的前顺序的风格。建立翻滚效果的类型顺序显得相当重要。
现在让我们看看如何安排链接状态的类型在不产生冲突的情况下支持正常的翻滚效果,并且如何重新安排这些类型顺序以获得不同的翻滚效果。
链接状态
典型的CSS翻滚效果依赖于超链接中四个状态之一的独立类型。可以建立附带CSS预先类的<a>(超链接)类型以指定链接状态:
为了能够使典型的CSS翻滚效果正常工作,CSS代码中的CSS类型顺序显得非常重要,无论它是一个外部类型表格或者是嵌入在HIML页标题栏中的类型规则。
a:link类型出现的时间为最早,因为它可应用于所有的链接。a:visited类型排第二,它将取代任何链接的a:link格式。(如果a:link类型紧跟着的是a:visited,a:link可能会取代a:visited类型。)其次是a:hover类型,此类型只应用于访问鼠标下的链接。最后是a:active,所以,当链接被点击时,它可以取代所有其它的类型。
以下CSS所示的翻滚效果:
a:link {
color: #0000FF;
text-decoration: underline;
font-weight: normal;
font-style: normal;
}
a:visited {
color: #3399FF;
text-decoration: underline;
background-color: #FFFFFF;
font-weight: normal;
font-style: italic;
}
a:hover {
color: #0000FF;
text-decoration: underline;
background-color: #FFFF00;
font-weight: bold;
font-style: normal;
}
a:active {
color: #FF0000;
text-decoration: none;
background-color: #CCCCCC;
font-weight: bold;
font-style: normal;
}
在CSS代码中的类型顺序确定了每一种类型如何取代其它的类型,即更多的类型可以应用到特定的元素。正常情况下,a:hover类型处于a:link和a:visited类型之后,所以hover状态的类型可以应用于常规和访问的链接。但是,它也并非必须遵循这一方式,你可以改变类型顺序实现不同的效果。
假设你想在非访问链接中使用翻滚效果,但不想影响到其它访问链接,你或许想到通过代码来处理这种外形上改变,然而你所要做的是重新组织CSS代码。
从访问链接中移除翻滚效果,可以通过很简单地移除a:visited类型。如以下代码改变CSS代码中类型顺序可以改变访问链接中翻滚效果:
a:link {
color: #0000FF;
text-decoration: underline;
font-weight: normal;
font-style: normal;
}
a:hover {
color: #0000FF;
text-decoration: underline;
background-color: #FFFF00;
font-weight: bold;
font-style: normal;
}
a:visited {
color: #3399FF;
text-decoration: underline;
background-color: #FFFFFF;
font-style: italic;
font-weight: normal;
}
a:active {
color: #FF0000;
text-decoration: none;
background-color: #CCCCCC;
font-weight: bold;
font-style: normal;
}
注意,a:visited类型中包含指定所有与a:hover相同属性的规则,否则,当访问者的鼠标通过一个访问链接时,没有被a:visited类型取代的任何a:hover类型属性将会继续再现。
增添其它效果
除非被其它顺序的类型取代,以前的类型将会继续使用相同的元素。所以,仔细选择链接状态类型的特征和顺序可以让你对非访问和访问链接建立不同的翻滚效果。
例如,删除背景颜色:#FFFFFF,以上第二个范例代码中的a:visited类型规则将允许背景颜色从a:hover类型应用到访问链接。结果为非访问链接的翻转效果添加了背景颜色和粗体文本。
三栏布局是目前最常见的网页布局,主要页内容放在中间一栏,边上的两栏放置导航链接之类的内容。基本布局一般是标题之下放置三栏,三栏占据整个页面的宽度,最后在页的底端放置页脚,页脚也占据整个页面宽度。
绝大多数网页设计者都熟悉传统的网页设计技术,用这些技术可以生成带有表格、创建固定宽度布局或者“液态”(它可以根据用户浏览器窗口宽度自动伸缩)布局的网页。
现在,我们都开始抛弃基于表格的布局技术,许多网络设计者正在从XHTML标记和CSS格式这一新范例中寻找创建三栏布局的方法。用绝对定位的方法从CSS中得到固定宽度的布局并不困难;但是得到液态布局就有点困难了。因此,本文介绍一种用CSS的float和clear属性来获得三栏液态布局的方法。
基本方法
基本的布局包含五个div,即标题、页脚和三栏。标题和页脚占据整个页宽。左栏div和右栏div都是固定宽度的,并且用float属性来把它们挤压到浏览器窗口的左侧和右侧。中栏实际上占据了整个页宽,中栏的内容在左、右两栏之间“流淌”。由于中栏div的宽度并不固定,因此它可以根据浏览器窗口的改变进行必要的伸缩。中栏div的左侧和右侧的填充(padding)属性保证内容安排在一个整齐的栏中,甚至当它伸展到边栏(左栏或者右栏)的底端也是这样。
三栏布局的一个例子
请看看用本文所介绍的技术进行三栏布局的例子。这个例子用鲜艳的颜色来区分布局的各个div。下面是XHTML代码:
<body>
<div id="header">
<h1>Header</h1>
</div>
<div id="left">
Port side text...
</div>
<div id="right">
Starboard side text...
</div>
<div id="middle">
Middle column text...
</div>
<div id="footer">
Footer text...
</div>
</body>
下面是CSS代码:
body {
margin: 0px;
padding: 0px;
}
div#header {
clear: both;
height: 50px;
background-color: aqua;
padding: 1px;
}
div#left {
float: left;
width: 150px;
background-color: red;
}
div#right {
float: right;
width: 150px;
background-color: green;
}
div#middle {
padding: 0px 160px 5px 160px;
margin: 0px;
background-color: silver;
}
div#footer {
clear: both;
background-color: yellow;
}
代码说明
HTML代码中各部分出现的顺序是非常重要的。左栏和右栏div必须在中栏之前出现。这样才可以让这两个边栏浮动到它们的位置上(屏幕两侧),并让中栏的内容将“流”入它们之间的空间。如果浏览器在一个或者两个边栏div之前先发现中栏,那么中栏将占据屏幕的一侧或者两侧,这样浮动的部分就会跑到中栏的下面而不是中栏的旁边了。
div#header和div#footer样式(style)中的clear:both申明用来确保这浮动部分不会占据标题和页脚的空间。div#header样式中的padding:1px申明用来消除页头背景色中的异常边,如果padding设置为零,那么在Netscape浏览器中就会看到这个异常。
div#left样式中的float:left申明是用来把左栏挤压到左侧。width:150px申明用来设置栏的固定宽度,不过你也可以把它的宽度设置为其它具体值。类似的,div#right样式中的float:right申明用来把右栏div挤压到右侧。在本例中,float把左栏和右栏完全挤压到浏览器窗口的左边缘和右边缘。然而,如果这些div被其它div包含,那么float将会把它们挤压到包含它们的div的边缘。
在div#middle样式中,clear申明允许中栏的内容“流淌”在两个边栏之间。padding:0px 160px 5px 160px申明设置了到左栏和右栏的填充,这样允许150象素宽度的栏div,在加上10象素的间距。
这个例子非常粗糙和简单,但是它很好的演示了用浮动div来创建三栏液态布局的边栏这一基本技术。
理解和应用层叠样式表的一个重要细节是它的名字中的层叠方面。也就是说,它是如何为同一个元素处理多种规则的?本周,我将详细的介绍CSS这方面的特性,并举例说明。
优先性
CSS属性比HTML属性有更大的优先权。你可以在没有CSS支持的浏览器中使用HTML属性,但是在浏览器中添加CSS支持也不会有什么影响。在使用CSS时,深刻理解一个CSS规则的来源是很重要的。
来源
当考虑CSS规则的应用时,通常有两个方面。第一个是读者,也就是对应于通过他们喜欢的浏览器查看web应用的用户。第二个方面是作者,也就是开发了web应用的实际web 开发人员。
读者的参数选择有用户来处理,也就是,他们可以开发自己的样式表,然后同过浏览器设置分配它们。例如,因特网浏览器IE 6用户可以通过工具 | Internet选项 | 访问菜单来指定一个用户样式表,这样他们就可以使用自己的样式表。Web开发人员通过开发自己的CSS来指定规则并在网页中应用。同时,浏览器也常有内置的规则。
层叠
缩写词CSS中的层叠方面指的是不同来源的规则间合并与覆盖过程。当同时使用多个样式表时,每个样式表定义的选择器之间会相互争夺控制。下面列表指名了顺序,这样就解决了样式表选择器之间的冲突,其中第一项是最重要的。
重要性:选择器是否被指定为重要?
规则来源:规则在那里定义的?
特性:规则的特性是什么?
顺序:最后定义的是什么?
重要的特性
添加关键字important可以增加你的声明的重要性。增加重要性的声明会覆盖与它们对应的标准或非重要声明。如果读者和作者的样式表都包含了重要声明语句,那么作者声明将会覆盖读者声明。下面的例子演示了声明一个CSS属性为重要。
<html>
<head>
<title> Cascading</title>
<style type="text/css">
H1 {font-face: arial; font-size: 12pt; color: red ! important;}
</style>
</head>
<body>
<h1 style="color: blue;">TechRepublic.com</h1>
</body>
</html>
在上面的例子中,你可以注意到分配给样式H1的颜色red总是有用的,因为它被声明为重要的。值得注意的是,当一个项目在读者和作者样式表中均被声明为重要时,作者的声明将会覆盖读者的声明。
规则来源
一个web用户可以创建和使用他/她自己的样式表。在这种情况下,在用户样式表和web应用样式表之间将会产生冲突。当这些冲突发生时,web应用的设置胜过当所有项目拥有同样的重要性时。可以使用重要的声明胜过对应非重要的声明,但是,当都声明为重要时,就意味着web应用会赢。
特性
当CSS规则的特性,更有特殊性的规则会赢得优先。因此,如果选择器都是一样的,那么最后一个就会赢得优先。所以下面的例子中总是定义H1为绿色。
<html>
<head>
<title>Cascading</title>
<style type="text/css">
H1 {color: red;}
H1 {color: green;}
</style></head>
<body>
<h1>TechRepublic.com</h1>
</body></html>
另一方面,下面例子中包含在BODY中的H1有一个特殊的定义,所以元素H1显示为红色。
<html><head>
<title>Cascading</title>
<style type="text/css">
BODY H1 {color: red;}
H1 {color: green;}
</style></head>
<body>
<h1>TechRepublic.com</h1>
</body></html>
当显示一个页面时,越具特色的选择器,越有更大的优先权。实际上,有专门用于估算元素特性的规则,基本上,数字值被分配给某些CSS选择器,每个选择器的值为100,类选择器的值为10,每个HTML选择器的值为1。如果你将这些值赋给CSS规则,那么值大的会赢得优先。下面的计算对应前面的例子。BODY H1有两个HTML选择器,因此值为1 1=2。H1包含一个HTML选择器,因此值为1,在每个实例中,2恒大于1,所以元素H1(包含在BODY中的)都是红色。
顺序
规范的顺序很简单:当两个规则有相同的重要性时,后一个规则优先性大。当有多个样式表来源时,使用这个规则可能会导致混淆。因此下面的操作顺序十分有用:
浏览器默认:第一,使用了浏览器默认或者用户自定义CSS规则。
外部样式表:使用了外部定义的样式表
内部样式表(在<head>标签中指名)
内嵌样式表(在一个HTML元素的内部):使用了应用于每个HTML元素的特别样式
注意
目前,CSS是大多数web应用的一个标准特征。随着web应用的增加,大量的CSS来源被使用。为此,你需要深入了解用户系统是如何处理多种CSS规则的。这样就确保了对你或者对用户都不会产生惊讶。
在CSS出现以前,Web开发者只能对页面和背景元素进行少量的控制。当然,那时候他们能使用background属性将一个图像在整个页面上进行平铺,他们能用bgcolor属性来控制图像的背景颜色。但是他们的控制仅仅这些——例如,他们不能调节页面背景图像的位置,不能控制平铺(tiling),也不能生成页面水印。
现在有了CSS,这些都得到了改变,它可以通过一组background-*指令准确控制页面和元素背景。另外,它还提供了大量优化了的函数。使用CSS指令控制背景元素有很多优势:它不需要任何特别的软件,它能在大部分浏览器上工作,它可以对网站的背景图像和颜色进行集中控制。
听起来是不是很有趣?接下来,我们来看看这些是怎么回事,这篇文章介绍了CSS的background属性,这个属性为老的background属性提供了另外一个选择,它对控制页面和元素背景的位置、颜色和布局来说是一个非常好的工具。
控制背景颜色
首先,让我们来看看背景颜色属性,该属性定义了元素所应用的背景颜色。这个指令既可以接受十六进制的RGB值,也可以接受像red、silver或者blue这样的“颜色单词”。ListingA给了我们这样的一个示例:
Listing A
<html>
<head>
<style type="text/css">
.author {
background-color: #FFE303
}
.quote {
font-style: italic;
background-color: lime
}
</style>
</head>
<body>
<div class="author">William Shakespeare said:</div>
<p />
<div class="quote">To be or not to be, that is the question.</div>
</body>
</html>
它运行后的结果如Figure A所示:
Figure A

Listing A的示例
控制背景图像
如果你想使用背景图像来替代单一的颜色,可以使用background-image指令,这个指令允许你指定背景图像的URL。
Listing B
<html>
<head>
<style type="text/css">
body {
background-image: url('mylogo.gif');
}
</style>
</head>
<body>
</body>
</html>
Figure B就是它运行后的结果:
Figure B

Listing B 示例
你也可以为一个特殊元素指定它的URL,就如Listing C所示:
Listing C
<html>
<head>
<style type="text/css">
.header {
width: 100%;
height: 60%;
border: solid 1px red;
background-image: url('mylogo.gif');
}
</style>
</head>
<body>
<div class="header"></div>
</body>
</html>
运行的结果如Figure C所示:
Figure C

Listing C 示例
控制背景图像重现
默认地,background-image指令可以对所选择的图像进行水平和垂直方向两个方向上的平铺。通常,这些才是你想要的——在先前的例子中,假如你想使用公司的logo作为背景,同时可以控制它只出现一次,或者,只将背景图像设计成了垂直方向的。
对于所有的这些情况,CSS提过了background-repeat指令,这个指令接受下面四个值之一:repeat-x (只在水平方向重复), repeat-y (只在垂直方向重复), no-repeat (没有重复), and repeat (在水平和垂直两个方向重复)。
下面来看看它的实现,如Listing D所示,在第一个<div>中将平铺(tiling)关闭了,也就是不进行重复,在第二个<div>中将logo水平重复。
Listing D
<html>
<head>
<style type="text/css">
.header1 {
width: 100%;
height: 35%;
border: solid 2px red;
background-image: url('mylogo.gif');
background-repeat: no-repeat;
}
.header2 {
width: 100%;
height: 60%;
border: solid 2px black;
background-image: url('mylogo.gif');
background-repeat: repeat-x;
}
</style>
</head>
<body>
<div class="header1"></div>
<p />
<div class="header2"></div>
</body>
</html>
Figure D给我们展示了它的运行结果:
Figure D

Listing D 示例
控制背景图像位置
它也可能控制背景图像相关元素放置的位置。background-position指令既可以接受百分比,也可以接受长度,还可以接受像top, bottom, left, right和center这样的关键字。现在我们来看看它是如何工作的,如Listing E所示,在这个示例中将背景图像放置在容器元素的右下角。
Listing E
<html>
<head>
<style type="text/css">
.header {
width: 100%;
height: 80%;
border: solid 2px red;
background-image: url('mylogo.gif');
background-repeat: no-repeat;
background-position: bottom right;
}
</style>
</head>
<body>
<div class="header"></div>
</body>
</html>
Figure E就是上面程序运行的结果:
Figure E

Listing E 示例
不必说,在放置单个背景图像时候,例如,在网页上放置公司图标的时候,这个指令是非常有用的。
控制背景图像滚动
最后,在CSS中,你可以设置在容器元素滚动的时候背景图像是否滚动。这个应用大部分使用在水印网页上,它使用background-attachment指令,可以接受scroll 或者fixed这两个值。Listing F这个例子告诉你如何产生一个出现在页面右上角的水印。
Listing F
<html>
<head>
<style type="text/css">
body {
background-image: url('mylogo.gif');
background-repeat: no-repeat;
background-position: top right;
background-attachment: fixed;
}
</style>
</head>
<body>
Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here.
<p />
Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here.
<p />
Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here. Content goes here.
</body>
</html>
现在,当你试图滚动这个页面的时候,右上角的图像会相对于浏览器窗口保持固定,它不会随页面上的其它内容滚动下来。
Figure F

Listing F 示例
当然,这些例子只是CSS背景应用中很小的一部分。然而,它们应该给了你一个在实际应用中使用这些属性的方法,你现在也应该能将这些属性应用到你的程序中了。所以,现在你还等什么呢?开始编写这些令人愉悦的代码吧!
同义字是SQL Server 2005的一个新对象。它为一个已经存在的对象建立一个别名。例如,如果你有一个名为SalesHistoryFromArchiveFiscalBusinessYear的表,你可以建立一个叫做Sales05的同义字指向那个对象。这意味着你不用写下面这个查询:
SELECT * FROM SalesHistoryFromArchiveFiscalBusinessYear2005
而只要用以下代码完成查询:
SELECT * FROM Sales05
优点
前面的例子表明,你可以用同义字给名称较复杂的对象建立一个更加易懂的名称,从而简化数据库开发。
同义字的主要优点在于,你可以用它在基本的对象和同义字间建立一个抽象层。例如,你可以建立一个名为SalesHistory的同义字,开发者在所有销售报告中都要用到它。这个同义字可以通过一个连接服务器引用一个本地视图或表,或一个远程视图或表。与数据复制组合使用时,这种同义字-对象关联可以成为一个非常强大的工具。下面的例子说明了这个问题。
实例
由于业务和可扩展性需求不断扩张,你认为最好是把SalesHistory表从当前的Inventory数据库中删除,把它放到一个名为SalesData的独立数据库中。在Inventory数据库中有许多代码引用SalesHistory表。多数代码都是简单的查询,仅从SalesHistory表中读取数据。由于项目最终期限很快就临近,因此很难改变所有现有的代码,让其引用新数据库中的表。以下我来说明如何使用一个同义字显著缩短开发时间。
假设你已经把SalesHistory表复制到新的SalesData数据库中,并对Inventory数据库中当前的SalesHistory表进行了重命名。(我总是喜欢首先重命名我打算删除的表。这使我有机会发现系统中由删除表造成的错误。)
重命名SalesHistory表后,你可以建立一个引用你已经放到新数据库中的SalesHistory表的同义字。其脚本如下:
USE Inventory
GO
CREATE SYNONYM SalesHistory
FOR SalesData.dbo.SalesHistory;
GO
这个同义字建立一个指向新SalesData数据库的SalesHistory表的指针;但是,因为同义字位于Inventory数据库中,且名为SalesHistory,那么,任何对SalesHistory同义字执行的查询或DML语句实际上是对SalesData数据库的SalesHistory表执行操作。
合理组织SQL数据可以使你可以进行有效的数据分析,这就要求对如何使用某些SQL语句和操作有一个很好的了解。本文的这些技巧可以帮助你解决如何设计SQL语句以得到你需要结果的问题。
以一种有意义的方式组织数据可能是一项挑战。有时你需要的可能是一个简单的排序,但是通常你需要做更多,你需要分组来进行分析和统计。幸运的是,SQL提供了大量语句和操作来进行排序,分组和摘要。下面的一些技巧将会帮助你识别什么时候排序,什么时候分组,什么时候以及如何统计。
通常,你的所有数据真正需要的仅仅是按某种顺序排列。SQL的ORDER BY语句可以以字母或数字顺序组织数据。因此,相似的值按组排序在一起。然而,这个分组时排序的结果,并不是真的分组。ORDER BY显示每条记录而分组可能代表很多记录。
#2:进行分组除去重复值
排序和分组之间的最大区别是:排序的数据显示所有记录(在限定标准范围之内),而分组数据不是显示所有记录。GROUP BY语句对于同样的值只显示一条记录。例如,下面的语句中的GROUP BY语句对数据源中重复出现的数据只返回唯一的zip编码列。
SELECT ZIP FROM Customers GROUP BY ZIP
只包括由GROUP BY和SELECT语句共同定义的那些记录,换句话说,SELECT列表必须满足GROUP BY列表,但是有一个例外就是SELECT列表可以包含聚合函数(GROUP BY语句不允许使用聚合函数)。需要注意的是GROUP BY语句不会对结果分组进行排序。为了使分组按字母或数字有序排列,需要添加ORDER BY语句。此外,在GROUP BY语句中不能引用使用了别名的字段。分组栏目必须是潜在的数据,但它们并不需要显示在结果中。
#3在分组之前进行数据筛选
你可以添加一个WHERE语句来筛选有GROUP BY所得分组中的数据。例如,下面的语句只返回肯塔基州顾客的唯一ZIP编码列。
SELECT ZIP FROM CustomersWHEREState = 'KY' GROUP BY ZIP
必须注意的是WHERE语句是在GROUP BY语句求值之前进行数据过滤的。与GROUP BY语句一样,WHERE语句也不支持聚合函数。
#4:返回所有分组
当你使用WHERE语句过滤数据时,结果分组中只显示你指定的那些记录,而符合分组定义但是不满足过滤条件的数据不会包含在某个分组中。当你想在分组中包含所有数据时添加关键字ALL即可,这时WHERE条件就不起作用。例如,在前面的例子中添加关键字ALL就会返回所有的ZIP分组,而不是仅在肯塔基州的那些。
SELECT ZIP FROM CustomersWHEREState = 'KY' GROUP BY ALL ZIP
这样看来,这两个语句存在冲突,你可能不会以这种方式使用关键字ALL。当你使用聚合函数计算某一列时,使用ALL关键字可能会很方便。例如,下面的语句计算每个肯塔基州ZIP中的顾客数,同时,还会显示其它的ZIP值。
SELECT ZIP, Count(ZIP) AS KYCustomersByZIP FROM CustomersWHEREState = 'KY' GROUP BY ALL ZIP
结果分组包括潜在数据中的所有ZIP值,然而,对于那些不是肯塔基州ZIP分组的聚合列(KYCustomersByZIP)将会显示0。远程查询不支持GROUP BY ALL。
#5:分组后筛选数据
WHERE语句在GROUP BY语句之前进行计算。当你需要在分组之后筛选数据时,可以使用HAVING语句。通常情况下,WHERE语句和HAVING语句的返回结果是一样的,但是值得注意的是这两个语句不可互换。当你迷惑时,可以遵循下面的说明:使用WHERE语句过滤记录,使用HAVING语句过滤分组。
一般情况,你会使用HAVING语句和某个聚合函数计算一个分组。例如,下面的语句返回一个唯一的ZIP编码列,但是可能不会包含潜在数据源中所有的ZIP。
SELECT ZIP, Count(ZIP) AS CustomersByZIP FROM Customers GROUP BY ZIP HAVING Count(ZIP) = 1
只有那些包含一位顾客的分组显示在结果中。
#6:进一步了解WHERE和HAVING语句
如果你对何时应该使用WHERE,何时使用HAVING仍旧很迷惑,请遵照下面的说明:
WHERE语句在GROUP BY语句之前;SQL会在分组之前计算WHERE语句。
HAVING语句在GROUP BY语句之后;SQL会在分组之后计算HAVING语句。
#7:使用聚合函数统计分组数据
分组数据可以帮助我们分析数据,但是有时我们可能需要更多的信息而不仅仅是分组。你可以使用聚合函数来统计分组数据。例如,下面的语句显示每批订购单的总价钱。
SELECT OrderID, Sum(Cost * Quantity) AS OrderTotal FROM Orders GROUP BY OrderID
对于其它的分组来说,SELECT和GROUP BY列必须匹配。而SELECT语句包含聚合函数时这一规则是一个例外。
#8:统计聚合数据
你可以继续统计数据为每个分组显示一个分类统计。SQL的ROLLUP操作符可以为每个分组显示一个额外的分类统计。这个分类统计是使用聚合函数计算每个分组中的所有记录得到的结果。下面的语句为每个分组计算OrderTotal:
SELECT Customer, OrderNumber, Sum(Cost * Quantity) AS OrderTotal FROM Orders GROUP BY Customer, OrderNumber WITH ROLLUP
对于有两个分别为20和25 OderTotal值的分组,ROLLUP显示一个OrderTotal值45。ROLLUP结果中的第一条记录是唯一的,因为它是计算所有分组记录,这个值是整个记录集的总值。
ROLLUP在聚合函数中不支持 DISTINCT,也不支持GROUP BY ALL语句。
#9:统计每个列
CUBE操作符比ROLLUP更进一步,它返回每个分组中重复值的个数。它的结果和ROLLUP相同,但是对每位客户的每一列CUBE包含一个额外的记录。下面的语句显示每个分组的统计和额外每位客户的统计。
SELECT Customer, OrderNumber, Sum(Cost * Quantity) AS OrderTotal FROM Orders GROUP BY Customer, OrderNumber WITH CUBE
CUBE可以给最综合的统计。它不仅完成聚合和ROLLUP的功能,还可以计算定义分组的其它列,换句话说,CUBE统计每个可能的列组合。
CUBE不支持GROUP BY ALL语句。
#10:对统计结果排序
当CUBE的结果令人迷惑时(它经常是这样),可以添加一个GROUPING函数,如下所示:
SELECT GROUPING(Customer), OrderNumber, Sum(Cost * Quantity) AS OrderTotal FROM Orders GROUP BY Customer, OrderNumber WITH CUBE
结果中每行包含两个额外的值:
值1表示左边的值是一个统计值,是ROLLUP或CUBE的操作符。
值0表示左边的值是一条由最初的GROUP BY语句产生的详细记录。
数据库管理员(DBA)的一项基本的技能是对SQL数据库引擎的系统数据库的深刻理解。数据库开发人员了解SQLSERVER自带的系统数据库也是十分有用的。下面就列出了其中的一些系统数据库。(注:如果你决定研究一下这些系统数据库,那么你需要有一个开发数据库。)
Master
Master数据库保存有放在SQLSERVER实体上的所有数据库,它还是将引擎固定起来的粘合剂。由于如果不使用主数据库,SQLSERVER就不能启动,所以你必须要小心地管理好这个数据库。因此,对这个数据库进行常规备份是十分必要的。
这个数据库包括了诸如系统登录、配置设置、已连接的SERVER等信息,以及用于该实体的其他系统和用户数据库的一般信息。主数据库还存有扩展存储过程,它能够访问外部进程,从而让你能够与磁盘子系统和系统API调用等特性交互。这些过程一般都用像C 这样的现代编程语言。
如果不幸碰到系统崩溃而必须恢复主数据库的情况,你可以参看MCSE/MCDBA Steven Warren在TechRepublic上发表的文章。这篇文章讲得十分透彻,它解释了恢复这一重要数据库所需要的一些特殊步骤。
Model
Model是一个用来在实体上创建新用户数据库的模版数据库。你可以把任何存储过程、视图、用户等放在模型数据库里,这样在创建新数据库的时候,新数据库就会包含你放在模型数据库里的所有对象了。
Tempdb
正如其名字所提示的,tempdb存有临时对象,例如全局和本地临时表格和存储过程。
这个数据库在SQLSERVER每次重启的时候都会被重新创建,而其中包含的对象是依据模型数据库里定义的对象被创建的。除了这些对象,tempdb还存有其他对象,例如表格变量、来自表格值函数的结果集,以及临时表格变量。由于tempdb会保留SQLSERVER实体上所有数据库的这些对象类型,所以对数据库进行优化配置是非常重要的。
在SQL Server 2005里,tempdb数据库还有一项额外的任务;它还被用作一些特性的版本库,例如新的快照隔离层和在线索引操作等。关于新的隔离层的简要说明,请参考我关于SQL Server 2005高级特性的文章。
Distribution
当你的SQLSERVER实体被配置为复制分发SERVER时,这个数据库就会被添加到你的系统里。在默认情况下,数据库的名字就是distribution,但是你可以更改它的名字。这个数据库用来保存历史和快照、合并和事务复制等的元数据。
Msdb
Msdb数据库用来保存于数据库备份、SQL Agent信息、DTS程序包、SQLSERVER任务等信息,以及诸如日志转移这样的复制信息。
结束语
在过去几年里,我发现理解SQLSERVER的最佳方法是研究系统数据库的工作原理。作为一条普遍的规律,我不建议你直接在SQLSERVER里查询系统表格;但是通过研究这些系统数据库里的表格,你可以学习到很多关于SQLSERVER工作原理的知识。
研究发现,oracle数据库使用的索引不会超过总数的25%,或者不易他们期望被使用的方式使用。通过 监控数据库索引的使用,释放那些未被使用的索引,从而节省维护索引的开销,优化性能。
1、在oracle8i中,确定使用了那个索引的方法意味着要对存在语共享SQL区中的所有语句运行EXPLIAN PALN,然后查询计划表中的OPERATION列,从而识别有OBJECT_OWNER和OBJECT_NAME列所确定的那个索引上的索引访问。
下面是一个监控索引使用的脚本,这个脚本仅仅是一个样品,在某种条件下成立:
条件:
运行这个脚本的用户拥有权限解释所有的v$sqlarea中的sql,除了不是被SYS装载的。plan_table.remarks能够别用来决定与特权习惯的错误。对所有的共享池中SQL,参数OPTIMIZER_GOAL是一个常量,无视v$sqlarea.optimizer_mode。两次快照之间,统计资料被再次分析过。没有语句别截断。所有的对象都是局部的。所有被引用的表或视图或者是被运行脚本的用户所拥有,或者完全有资格的名字或同义词被使用。自从上次快照以来,没有不受"欢迎"的语句被冲洗出共享池(例如,在装载)。对于所有的语句,v$sqlarea.version_count = 1 (children)。
脚本:
Code: [Copy to clipboard] set echo off Rem Drop and recreate PLAN_TABLE for EXPLAIN PLAN drop table plan_table; create table PLAN_TABLE ( statement_id varchar2(30), timestamp date, remarks varchar2(80), operation varchar2(30), options varchar2(255), object_node varchar2(128), object_owner varchar2(30), object_name varchar2(30), object_instance numeric, object_type varchar2(30), optimizer varchar2(255), search_columns number, id numeric, parent_id numeric, position numeric, cost numeric, cardinality numeric, bytes numeric, other_tag varchar2(255), partition_start varchar2(255), partition_stop varchar2(255), partition_id numeric, other long, distribution varchar2(30), cpu_cost numeric, io_cost numeric, temp_space numeric, access_predicates varchar2(4000), filter_predicates varchar2(4000)); Rem Drop and recreate SQLTEMP for taking a snapshot of the SQLAREA drop table sqltemp; create table sqltemp ( ADDR VARCHAR2 (16), SQL_TEXT VARCHAR2 (2000), DISK_READS NUMBER, EXECUTIONS NUMBER, PARSE_CALLS NUMBER); set echo on Rem Create procedure to populate the plan_table by executing Rem explain plan...for 'sqltext' dynamically create or replace procedure do_explain ( addr IN varchar2, sqltext IN varchar2) as dummy varchar2 (1100); mycursor integer; ret integer; my_sqlerrm varchar2 (85); begin dummy:='EXPLAIN PLAN SET STATEMENT_ID=' ; dummy:=dummy||''''||addr||'''' ||' FOR '||sqltext; mycursor := dbms_sql.open_cursor; dbms_sql.parse(mycursor,dummy,dbms_sql.v7); ret := dbms_sql.execute(mycursor); dbms_sql.close_cursor(mycursor); commit; exception -- Insert errors into PLAN_TABLE... when others then my_sqlerrm := substr(sqlerrm,1,80); insert into plan_table(statement_id, remarks) values (addr,my_sqlerrm); -- close cursor if exception raised on EXPLAIN PLAN dbms_sql.close_cursor(mycursor); end; / Rem Start EXPLAINing all S/I/U/D statements in the shared pool declare -- exclude statements with v$sqlarea.parsing_schema_id = 0 (SYS) cursor c1 is select address, sql_text, DISK_READS, EXECUTIONS, PARSE_CALLS from v$sqlarea where command_type in (2,3,6,7) and parsing_schema_id != 0; cursor c2 is select addr, sql_text from sqltemp; addr2 varchar(16); sqltext v$sqlarea.sql_text%type; dreads v$sqlarea.disk_reads%type; execs v$sqlarea.executions%type; pcalls v$sqlarea.parse_calls%type; begin open c1; fetch c1 into addr2,sqltext, dreads,execs,pcalls; while (c1%found) loop insert into sqltemp values (addr2,sqltext,dreads,execs,pcalls); commit; fetch c1 into addr2, sqltext,dreads,execs,pcalls; end loop; close c1; open c2; fetch c2 into addr2, sqltext; while (c2%found) loop do_explain(addr2,sqltext); fetch c2 into addr2, sqltext; end loop; close c2; end; / Rem Generate a report of index usage based on the number of times Rem a SQL statement using that index was executed select p.owner, p.name, sum(s.executions) totexec from sqltemp s, (select distinct statement_id stid, object_owner owner, object_name name from plan_table where operation = 'INDEX') p where s.addr = p.stid group by p.owner, p.name order by 2 desc; Rem Perform cleanup on exit (optional) delete from plan_table where statement_id in ( select addr from sqltemp ); drop table sqltemp;
关于这个脚本,有几个重要的地方需要注意,即它可能一起明显的开销,因此,应该在仔细地进行 权衡后才把它应用到繁忙的生产应用系统中区。
2、oracle9i中如何确定索引的使用情况:
在oracle9i中,情况会简单得多,因为有一个新得字典视图V$SQL_PLAN存储了实际计划,这些计划用于执行共享SQL区中得语句。V$SQL_PLAN视图很类似与计划表,但V$SQL_PLAN使用ADDRESS和HASH_VALUE列 来识别语句, 而计划表使用用户提供得STATEMENT_ID来识别语句。下面的SQL显示了在一个oracle9i数据库中,由出现在共享SQL区中语句使用的所有索引。
select object_owner, object_name, options, count(*) from v$sql_plan where operation='INDEX' and object_owner!='SYS' group by object_owner, object_name, operation, options order by count(*) desc;
所有基于共享SQL区中的信心来识别索引使用情况的方法, 都可能会收集到不完整的信息。共享SQL区是一 个动态结构,除非能对它进行足够频繁的采样, 否则在有关索引使用的情况的信息被收集之前,SQL语句可 能就已经(因为老化)被移出缓存了。oracle9i提供了解决这个问题的方案,即它为alter index提供了一个monitoring usage子句。当启用monitoring usage 时,oralce记录简单的yes或no值,以指出在监控间隔 期间某个索引是否被使用。
为了演示这个新特性,你可以使用下面的例子:
(a) Create and populate a small test table
(b) Create Primary Key index on that table
(c) Query v$object_usage: the monitoring has not started yet
(d) Start monitoring of the index usage
(e) Query v$object_usage to see the monitoring in progress
(f) Issue the SELECT statement which uses the index
(g) Query v$object_usage again to see that the index has been used
(h) Stop monitoring of the index usage
(i) Query v$object_usage to see that the monitoring sDetailed steps
(a) Create and populate a small test table create table products ( prod_id number(3), prod_name_code varchar2(5)); insert into products values(1,'aaaaa'); insert into products values(2,'bbbbb'); insert into products values(3,'ccccc'); insert into products values(4,'ddddd'); commit; (b) Create Primary Key index on that table alter table products add (constraint products_pk primary key (prod_id)); (c) Query v$object_usage: the monitoring has not started yet column
可能很多使用Oracle的客户都会遇到想把某用户所有表导出的情况,本文就提供这样一个方法帮你轻松解决这个问题。
首先在sqlplus下以该用户登录到Oracle数据库,然后将以下内容粘贴到sqlplus中:


