千一图书2006精品百分百(v1.1)

值此2006新春之际，千一网络 精选近半年来网站四大版块的50篇文章，组成这本《千一图书2006精品百分百》(v1.1)。

本手册内容专注于网站开发应用，从小现象看大问题，专门探讨看似简单却常常被错误认识的问题，其中也提供了一些资料性文献供网站开发人员参考。

站点更新 更多

您有任何建议或意见，请与我们联系

千一网络 www.cfTea.com 专业探讨【ASP、JavaScript、XHTML+CSS、SQL Server】


ASP指定下载文件的文件名

标题：ASP指定下载文件的文件名
作者：vkvi
来源：千一网络
从数据库中读取二进制数据，然后进行下载时，其文件名是当前的ASP页面文件名，使用以下代码，可以指定下载框中的文件名。
Response.ContentType="application/octet-stream"
Response.AddHeader "Content-Disposition:", "attachment; filename='test.csv'"


ASP中 "+" 和 "&"

标题：ASP中 "+" 和 "&"
作者：vkvi
来源：千一网络

在ASP中，或者准确的说在VBScript中，"+"有两个意思，一是四则运算里的加号，二是字符串连接符。"&"的意思是字符串连接符。

那么 "+" 的字符串连接与 "&" 的字符串连接有什么区别呢？

n = 2
response.Write("2" + n) '这里显示为4，把字符串转换成数字类型
response.Write("2" & n) '这里显示为22，把数字类型转换成字符串

response.Write("2" + 2) '这里显示为4，把字符串转换成数字类型
response.Write("2" & 2) '这里显示为22，注意如果把"2" & 2写成"2"&2将出错

b = "2"
response.Write("2" + b) '这里显示为22
response.Write("2" & b) '这里显示为22

response.Write("2" + "2") '这里显示为22
response.Write("2" & "2") '这里显示为22

response.Write("a" + 2) '出错，因为强制转换"a"为数字类型时失败

上面举了这么多例子，总结我就不说了，只说一点，不要用"+"来作字符串连接符，统一使用"&"来作字符串连接符。


Fix、Int、Round、CInt

标题：Fix、Int、Round、CInt
作者：vkvi
来源：千一网络
Fix(number)和Int(number)都是返回数字的整数部分。

number为正数时，二者返回值一样。
比如：Fix(3.6)=3，Int(3.6)=3。

number为负数时，Fix直接去除小数部分，Int返回小于或等于number的第一个负整数。
比如：Fix(-3.6)=-3，Int(-3.6)=-4。
----------------------------------------
Round(number, numdecimalplaces)，第二个参数表示从小数点右边第几位开始实行四舍五入，可以省略，默认是0，即四舍五入返回整数。
CInt(number)利用四舍五入的方式删除小数部分。

如果Round的第二个参数省略，那么Round和CInt功能是一样的。

number为正数时，Round(3.6)=4，CInt(3.6)=4。
注意，当小数部分恰好是0.5时，总是将其四舍五入为最接近的偶数。
比如Round(3.5)=4，Round(4.5)=4。

number为负数时，可以这样理解：
假设n为正数，
Round(-n) = -Round(n)，比如：Round(-3.5) = -4。
CInt(-n) = -CInt(n)，比如：CInt(-99.8) = -100。


关于on error resume next的一些笔记

标题：关于on error resume next的一些笔记
作者：leen
来源：千一网络
on error resume next 起的作用是block级的，并不是全局的。
例：
function Foo()
on error resume next
b = 1/0 '这里产生异常会继续执行下面的代码
a = "ddd"
end function
call Foo()
a = 1/0 '由于在全局范围内没有on error resume next，所以这里产生异常会中断执行。

Sub1中有on error resume next语句，Sub2没有，当Sub1内部代码调用Sub2时，如果Sub2中产生异常，也不会中断执行。

虽然on error resume next的作用不是全局的，err对象却是一个全局的对象。

如果 err.number <> 0，那么表示错误发生。

clear方法的说明。在使用on error resume next时会自动调用clear方法，但 exit sub、exit function 不会自动调用clear方法。所以如果异常发生，就要执行 exit sub、exit function 之前要调用clear方法，除非你是特意的。


IE也是多窗口程序

标题：IE也是多窗口程序
作者：梦云
来源：千一网络

有人说IE是单窗口的程序，占用资源，不如TT之类的多窗口程序。其实不然，IE的单窗口只是表面上的，实质上，它也是多窗口的。

打开IE，按Ctrl+N新建一个窗口，再打开任务管理器，在进程里面是不是只有一个IEXPLORER.EXE。你非正常、强制结束其中的一个窗口时，另一个窗口是不是也关闭了，当然，因为它们本来就是一个进程。

双击桌面上的IE，再次双击桌面上的IE，有两个窗口对吧。打开任务管理器，切换到进程标签，是不是有两个IEXPLORER.EXE。当你非正常、强制结束其中一个窗口时，另一个窗口仍然平安无事。

如果是Ctrl+N新建的窗口，那么这两个窗口的SESSION是通的，也就是说，你在第一个窗口里登录邮箱，在第二个窗口中仍然正常使用。

如果你是两次启动IE，它们的SESSION则不是通的，你在第一个窗口中登录邮箱，在第二个窗口中直接输入地址查看邮件，是办不到的，还得让你再登录。


server.Transfer优缺点

标题：server.Transfer优缺点
作者：飞飞鱼
来源：千一网络

server.Transfer与response.Redirect的作用都是重定向，我认为它与response.Redirect相比有两个优点、一个缺点。

优点：
一、它在服务器端直接重定向，不用像response.Redirect一样先与浏览器通信再重定向，效率高。
二、它可以传递上一个页面的提交值。比如：A页面提交值到B页面，B页面Transfer到C页面，C页面同样可以收到A页面提交的值。

缺点：(2006-1-10修改)
不能刷新页面，比如：A页面提交登录信息到B页面，B页面处理后Transfer再到A，A页面得不到刷新，指定了过期也不行。如果A、B页面不在同一个目录下，我们还会发现更多意想不到的结果，使用相对链接的图片、超链接的指向都改变了，造成这种原因是B页面读取A页面内容却以B页面的身份输出，所以路径改变了。


利用ASP保护JavaScript脚本

标题：利用ASP保护JavaScript脚本
作者：飞飞鱼
来源：千一网络

以前遇到一种现象直接下载.js文件时说连接失败，可是又能被网页上的文件引用，不知道是不是服务器配置的原因，还望各位高手指点。如果不能实现这种配置，可以利用ASP来实现这种效果。

JavaScript代码放到一个单独的文件中，但扩展名不用.js，而用.asp，在文件的开头写：
====================
if StrComp(request.ServerVariables("HTTP_REFERER"), "http://.../index.asp", 1) <> 0 then
response.End
end if
下面是javascript代码……
====================

这样，这个文件就只能被index.asp利用<script type="text/javascript" language="javascript" src="文件名.asp"></script>来引用了。

直接下载会得到空白的结果。

编者著：StrComp是字符串比较函数，两字符串相等返回0，第三个参数：1表示文本比较，0表示二进制比较。另，此法并不能完全保证JS代码安全，因为HTTP_REFERER可以伪造。


更改FSO名称是否有必要

标题：更改FSO名称是否有必要
作者：vkvi
来源：千一网络

FSO即Scripting.FileSystemObject组件的简称，它可以操作服务器上的文件，是个很危险（双刃剑）的组件，但又常常不得不用，于是有人常常将这个ProgId改成另外一个名字，只让自己或信任的人知道。

我认为这样不能有效地避免别人使用，因为恶意操作的人可以通过ClsId来使用这个组件，而ClsId是不能通过修改注册表来更改的。

还有个组件是ADODB.Stream，也是服务器内置组件，也可以对文件操作，即使FSO完全被删除了，恶意操作者还可以使用这个组件。

另外改名后，其实还给自己带来很多麻烦，自己的程序要移植到其它机子时，比如服务器转移、重装系统、安装到笔记本演示等等，不得不再修改与ProgId有关的程序或注册表项，很麻烦。

要避免FSO的危害，基本是要设置好NTFS权限，我看过一些提供虚拟主机的服务器，没有真正地将NTFS权限用起来：所有的网站共用一个来宾帐户，Everyone对所有文件夹均有读权限，非常的危险。


上传文件时，如何正确获取文件名

标题：上传文件时，如何正确获取文件名
作者：vkvi
来源：千一网络

本文中约定：
文件路径(filePath)形如：C:\Windows\ecm.ini
文件目录(fileDir)形如：C:\Windows
文件名(fileName)形如：boot.ini

在服务器端把二进制转换成文本，得到文件路径，如filePath = "D:\Games\ea.rar"，那么如何得到文件名呢？以前常用如下代码：
pos = InStrRev(filePath, "\")
if pos > 0 then
fileName = Mid(filePath, pos+1)
end if

初看无误，其实由于在Windows目录中"\"与"/"具有相同的意义，所以以上代码存在一定的安全隐患。客户端，假如要上传的文件位于D盘根目录下，文件名为index.asp。现在使用者上传时，把文件路径故意写成D:\abc\../index.asp，由于../表示上一级目录，那么它指向的实际位置就是D盘根目录下的index.asp文件，于是文件上传是成功的，可是它给服务器端报告的文件路径是D:\abc\../index.asp，根据以上代码，服务端程序在解析文件名时变成了"../index.asp"，可是这并不是真正的文件名，并且若依此文件名来保存，便会保存到意想不到的目录，甚至覆盖你真正想要的文件。

所以以上代码并不是良好的代码，使用以下方法能够正确获取文件名：
dim xgPos, fxgPos
xgPos = InStrRev(filename,"\")
fxgPos = InStrRev(filename,"/")
if xgPos > fxgPos then
fileName = Mid(filePath, xgPos + 1)
else
fileName = Mid(filePath, fxgPos + 1)
end if


如何正确传送URL

标题：如何正确传送URL
作者：vkvi
来源：千一网络

比如查看一篇文章，如果没登录就跳到login.asp进行登录，登录成功后再自动跳到刚才的那篇文章。

虽然是个很简单的功能，很多论坛上也有此功能，但要保证参数正确的传送需要注意几点。

文章页面：
if 没有权限 then
'作必要处理，如释放对象

url = "http://" & _
request.ServerVariables("HTTP_HOST") & _
request.ServerVariables("URL") & _
"?" & _
request.ServerVariables("QUERY_STRING")
'除非你确信传递的参数不需要编码，否则都应该调用URLEncode函数
response.Redirect("login.asp?url=" & server.URLEncode(url))
end if

登录页面：
url = request.QueryString("url")

<form action="login_process.asp" method="post">
文本框中使用HTMLEncode函数
<input type="hidden" name="url" value="<%=server.HTMLEncode(url)%>">
...
</form>

<a href="chngPasswd.asp?url=<%=server.URLEncode(url)%>">修改密码</a>


网上如何破解MD5

标题：网上如何破解MD5
作者：
来源：千一网络

MD5逆算法是没有的，也就是说不存在这样一个破解机，输入任意一个MD5散列就可以计算出明文。

不过网上有不过网站致力于MD5字典收集，也就是将字符串与对应的MD5散列存储于数据库中，根据MD5散列来寻找字符串以寻找解密，当然如果数据库中没有，也就无法解密了，下面介绍三个。
http://md5.rednoize.com
http://www.xmd5.org/index_cn.htm
http://www.neeao.com/md5/

第一个是英文站点，目前已经有三百多万条数据。

第二个为多语言站点，据其介绍目前已经有两千多万条数据。

第三个为中文站点。


列表操作后的返回问题

标题：列表操作后的返回问题
作者：vkvi
来源：千一网络

比如文章管理系统的文章列表页，在每个文章标题旁边一般都有“编辑”和“删除”，假如我们翻到第三页，点击“删除”后，希望还是返回第三页，还不是第一页，这是比较好的，也是常用的。但这里所提的更上升了一级，不仅返回操作前所在的页，还定位到操作前滚动条所在的位置，不会再去拖动滚动条再往下找。

在文章列表页，加入如下代码：
<script type="text/javascript" language="javascript">
<!--
function SetScroll()
{
tranForm.windowScrollTop.value = document.body.scrollTop;
}

function ScrollWindow(y)
{
if (y > 0)
{
window.scrollTo(0, y);
}
}

window.onscroll = SetScroll;
setTimeout("ScrollWindow(<%=y%>)", 200);
//-->
</script>

当滚动条滚动时，将其所在的位置记录到tranForm.windowScrollTop中，tranForm是FORM，windowsScrollTop是HIDDEN。当处理页处理完工作时，将windowScrollTop值取出来再传递给该列表页，列表页Request这个值，并将其赋给变量y。ScrollWindow()函数滚动滚动条就实现了想要的效果。


在ASP中使用含"%>"的字符串

标题：在ASP中使用含"%>"的字符串
作者：vkvi
来源：千一网络

我们知道%>是ASP的结束标记符，在字符串中直接使用%>会产生错误。比如：
<%
response.Write("%>") '错误：未结束的字符串常量
%>

那么要正确输出%>该怎么写呢？有人说利用Chr(charcode)函数，但利用函数，还不如直接利用字符串连接符，这个不是今天我们要讨论的，我们介绍第二种，如下：
<%
response.Write("%\>") '正确，输出%>
%>

将%>变成%\>就可以了。那么要输出%\>又怎么写呢？
<%
response.Write("%\\>") '输出什么？
%>
不对，我们看到上述输出的结果是%\\>，说明\并非转义字符。
我认为要输出%\>，可以将它分开写，比如：
<%
response.Write("%\" & ">") '输出%\>
%>


搜索中的谓词处理（连载二）

标题：搜索中的谓词处理（连载二）
作者：chilleen
来源：千一网络

来源：千一网络（www.cftea.com）

在处理相邻谓词时，前面的方法是取第一个谓词，其实不是最好的，比如"农业 + 工业"，用户的目的很可能是要搜索“农业”或“工业”，“+”两边的空格完全是出于一种单词间的间隔，并不是它要将空格作为谓词，所以下面的程序作了些改进，降低了空格的级别，当它与加号或减号相遇时，取加号或减号。

示例（VBScript语言）

[Ctrl+A 全部选择 提示：你可先修改部分代码，再按运行]

连载二结束


英语单词拼写检查（连载三）

标题：英语单词拼写检查（连载三）
作者：chilleen
来源：千一网络

来源：千一网络（www.cftea.com）

现将代码转换成VBScript语言。

[Ctrl+A 全部选择 提示：你可先修改部分代码，再按运行]

连载三结束


javascript中字符串连接的同时数字相加

标题：javascript中字符串连接的同时数字相加
作者：chilleen
来源：千一网络

document.write("<img src='images/" + i + 1 + ".jpg'>")

假如i=1，以上代码输出为<img src='images/11.jpg'>

如果想输出为2.jpg，应该这样写

document.write("<img src='images/" + (i+1) + ".jpg'>")


JavaScript拖拽（连载四）

标题：JavaScript拖拽（连载四）
作者：chilleen
来源：千一网络
拖拽时原层保持不动，复制一个内容层，运行代码看看。

[Ctrl+A 全部选择 提示：你可先修改部分代码，再按运行]


一句话判断字符串中是否有汉字

标题：一句话判断字符串中是否有汉字
作者：chilleen
来源：千一网络
if (escape(str).indexOf("%u") < 0)
{
//字符串 str 中含有汉字
}

    escape对字符串进行编码，字符值大于 255 的以 %u**** 格式存储，而字符值大于 255 的恰好是非英文字符（一般是中文字符，非中文字符也可以当作中文字符考虑）。
    indexOf用以判断在字符串中是否存在某子字符串，找不到返回 -1。


window.open左、上、宽、高参数探索

标题：window.open左、上、宽、高参数探索
作者：chilleen
来源：千一网络
看如下语句：
window.open(url, name, "left=100, top=100, width=100, height=100");

看参数left和top，分别指什么呢，它们指窗口左边界到屏幕最左边和窗口上边界到屏幕最上端的距离。它们是不能为负的，如果为负值，会自动以0处理。
window.moveTo(x, y)是可以为负值的。
所以要弹出一个窗口并且上半部分要隐藏起来，可以选用window.open，再使用moveTo。

width和height指什么的大小呢，起初我们以为是窗口的大小，其实不是，是窗口客户区的大小，即document.body.clientWidth的大小。
resizeTo(x, y)，这里改变窗口大小时x, y才是窗口的大小。
所以要弹出一个窗口是多少多少的窗口，应该先window.open，再使用resizeto。


如何正确利用超链接调用javascript函数

标题：如何正确利用超链接调用javascript函数
作者：chilleen
来源：千一网络
点击超链接调用javascript函数，一般人都用<a href="javascript:function();">
但这有个缺点，就是点击链接后，页面上的GIF动画将静止。

试看如下代码：
<script language="javascript">
<!--
function Foo()
{
//do something
}
//-->
</script>
<img src="http://****/logo.gif">
<a href="javascript:Foo();">使GIF动画静止的链接</a>

解决方法探讨：
<a onclick="javascript:Foo();">链接</a>
此时不影响动画显示，但鼠标移上去后，鼠标及超链接样式不发生变化，虽然可以利用样式表来改变鼠标及超链接样式，但毕竟有些繁琐，况且这种思路也不好。
再考查如下代码：
<a onclick="javascript:Foo();" href="#">链接</a>
我们可以发现，虽然点击链接后不影响动画显示，但页面总是滚到最上面，这种效果也不是我们想要的。

最终解决方法：
<a onclick="javascript:Foo(); return false;" href="#">不影响GIF的链接</a>
由于点接链接后，先触发onclick，再执行href属性对应的值，在onclick中加上return false;中断了执行，所以页面就不会跳到最上部了。


网页风格切换

标题：网页风格切换
作者：chilleen
来源：千一网络
常见论坛都有风格切换的功能，通过点击按钮，网页由一种配色方案跳到另一种方案。
下面通过代码展示其原理。
首先准备两个CSS分别控制不同的风格。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>css</title>
<LINK title="C1" rel="stylesheet" href="C1.css" type="text/css" />
<link title="C2" rel="alternate stylesheet" href="C2.css" type="text/css" />
</head>

<body>
<span class="foo">文字</span>
<script type="text/javascript" language="javascript">
<!--
function SetActiveStyleSheet(title)
{
for (var i=0; i<document.getElementsByTagName("link").length; i++)
{
//循环所有名称为link的标签
var e = document.getElementsByTagName("link")[i];
if (e.getAttribute("rel").indexOf("style") != -1)
{
//这个link标签的rel属性含style，证明其作用是链接CSS文件的
if (e.getAttribute("title") == title)
{
//当前link对应的CSS就是要使用的CSS，将disabled属性设置为false表示启用
e.disabled = false;
}
else
{
e.disabled = true;
}
}
}
}
-->
</script>
<input type="button" value="C1" onclick="SetActiveStyleSheet(this.value);">
<input type="button" value="C2" onclick="SetActiveStyleSheet(this.value);">
</body>

</html>


CSS光标属性一览

标题：CSS光标属性一览
作者：vkvi
来源：千一网络

使用cursor:CSS描述，如cursor:default;

光标描述（可预览） | CSS描述
默认 | default
自动 | auto
文字/编辑 | text
手形 | pointer, hand(hand是IE专有)
可移动对象 | move
不允许 | not-allowed
无法释放 | no-drop
等待/沙漏 | wait
帮助 | help
十字准星 | crosshair
向上改变大小(North) | n-resize
向下改变大小(South) | s_resize 与n-resize效果相同
向左改变大小(West) | w-resize
向右改变大小(East) | e-resize 与w-resize效果相同
向左上改变大小（NorthWest） | nw-resize
向左下改变大小（SouthWest） | sw-resize
向右上改变大小（NorthEast） | ne-resize 与sw-resize效果相同
向右下改变大小（SouthEast） | se-resize 与nw-resize效果相同
自定义光标 | url('光标地址')


CSS选择符

标题：CSS选择符
作者：vkvi
来源：千一网络

CSS 的选择符有很多，不过目前浏览器普遍支持的只有 6 种。

一、类型选择符 Type Selector
Element 直接将 HTML 标签作为选择符，如 p{color:red;}

二、后代选择符 Descendant Selector
Element1 Element2 两个 Element 间用空格隔开，表示位于 Element1 下的 Element2 才有效。如 td p{color:red;}，只有位于 td 内部的 p 字体才是红色，如果 p 是直接在 body 下面，则不使用此样式表。Element 可以为 class 或 id。

三、联合选择符 Multiple Selectors
Element1, Element2 两个 Element 间用逗号隔开，表示这两个 Element 使用同一个样式表。 Element 可以是 HTML 标签，也可以是 class 或 id。

四、伪类选择符 Pseudo-class Selector
Element:Pseudo-class 最熟悉的是 a:link 了。

五、类选择符 Class Selector
Element.value 如 p.title，则<p class="title">会响应此样式，如果不要Element，则所有 class 为 title 的标签皆响应此样式。

六、ID选择符 ID Selector
Element#value 如 p#title，则<p id="title">会响应此样式，由于 id 在文档中唯一，所以Element也可以不写。


让ul不受浏览器影响

标题：让ul不受浏览器影响
作者：chilleen
来源：千一网络
当我们使用无序列表ul时，常常出现在不同浏览器中显示效果不一样的现象。究其原因是各浏览器对ul的margin和padding等默认值解释不同。我们对四大浏览器进行测试，将结果列表如下：

浏览器　版本
IE：6
NS：7.1
FireFox：1.0
Opera：7.6

列表标记是否在ul内
 | IE | NS | FireFox | Opera
列表标记是否在ul内 | 否 | 是 | 是 | 否

各浏览器中ul的margin默认值
 | IE | NS | FireFox | Opera
margin-top | 0 | 0 | 0 | >0
margin-right | 0 | 0 | 0 | 0
margin-bottom | >0 | 0 | 0 | 0
margin-left | >0 | 0 | 0 | >0

各浏览器中ul的padding默认值
 | IE | NS | FireFox | Opera
padding-top | 0 | 0 | 0 | 0
padding-right | 0 | 0 | 0 | 0
padding-bottom | 0 | 0 | 0 | 0
padding-left | 0 | >0 | >0 | 0

由此可见，各浏览器对ul的默认值解释差异非常大，所以在使用ul时，必须使用样式表格式化它，使各浏览器使用相同margin和padding值。

下面是我常用的样式表，效果不错。
ul
{
margin:0px 0px 0px 0px;
padding:0px 0px 0px 20px;
}


为什么使用px而不使用pt？

标题：为什么使用px而不使用pt？
作者：chilleen
来源：千一网络

在样式表中定义字体大小，有人用px有人用pt，效果似乎都是一样的，那么到底使用哪个好呢？答案是使用px好些。

效果真的是一样的吗？如果真的一样，那么使用哪个都可以了。我们在桌面上点右键，属性，高级，常规，DPI设置中一般使用的是“正常尺寸”，现在我们把它改为“大尺寸”，然后重新启动计算机，浏览网页时，就会发现，很多使用pt的网页都出现了页面错位。HTML中，图片的宽度(width)、表格宽度(width)等等长度属性，虽然没有写出单位，但他们使用的单位都是px，px不受DPI的影响，也就是说这些图片、表格等的大小不受DPI影响，而字体却受到了影响，这必然引起排版错位。

px表像素，是个相对长度单位，常用于显示；pt表点数，是个绝对长度单位，常用于印刷。打开www.macromedia.com，我们查看其样式表，可以发现font-size属性后面跟着的都是px或em（em也是相对长度单位，相对于当前对象内文本的字体尺寸）。


为什么要将HTML标签的属性值用双引号引起来

标题：为什么要将HTML标签的属性值用双引号引起来
作者：chilleen
来源：千一网络
以 IMG 为例，正确的写法是（为了明显，我们指定了width和height属性）：
<img src="..." alt="中国 西安" width="100" height="50" />
中国 西安

假如alt属性不要引号，效果如下：
<img src="..." alt=中国 西安 width="100" height="50" />
中国
可以看出alt属性值在空格处中断了。

假如alt属性使用单引号，属性中也含有单引号时，效果如下：
<img src="..." alt='xi'an' width="100" height="50" />
xi
可以看出alt属性值在单引号处中断了。

所以应该使用双引号把属性值括起来，当在属性值中遇到双引号时，用&quot;代替
<img src="..." alt="&quot;" width="100" height="50" />
"
正确！


你到底有多宽？

标题：你到底有多宽？
作者：飞飞鱼
来源：千一网络

也不知道是什么原因，出了这么多“面积”，套内面积、套内墙体面积、建筑面积、公摊面积……搞得如此精确，那么如果有人问这房子多大面积，你该如何回答？

不止是房地产，网页上也遇到了此类问题，请看下面样式表：
padding:10px;
width:100px;
border:10px solid #FF0000;

IE和Opera中解释成如下图如示：

FireFox和NetScape中解释成如下图如下：

我们只看宽度，可以发现，对以上样式表的解释分为两派。以IE为代表的一派认为width包括padding和border。以FireFox为代表的一派认为width不包括padding和border。

IE说树干的大小当然应该包括树皮了。

FF说体检啦，都脱衣服脱鞋子啦。

好像大家都说得有道理，W3C的标准是FF对的。但何为标准？有牛人说我就是标准！强悍！有道理！IE从来都不按标准出牌，因为我自己就是标准。

就我个人而言，我倾向于IE，MS产品一向都好用，也许有时这种好用适得其反，但我认为这里是对了。

网页不是户外的广告牌，它的宽度受空间限制，也就是说我们做一个网页时，一开始考虑的是网页的宽度，然后再分块。

在IE里面，在这个块里调整border、padding，除了影响整体视觉外，并不影响其它块的布局（恶意的除外，竖方向一般不考虑）。

对于FF情况就不同了，先得到了块的大小，然后画确定划多少给border，多少给padding，多少给width。一旦划定了，可是要更改整个设置时，就麻烦了。你说width你好，这个padding变大了，你能不能自动缩小一点，免得咱这车厢挤爆了。width说，没门！于是你一怒之下，还得去调整width，是不是很麻烦。


样式表中url()的相对路径使用（8月11日修正）

标题：样式表中url()的相对路径使用（8月11日修正）
作者：vkvi
来源：千一网络

比如：
list-style-image:url(http://www.***.com/images/ag.gif);
list-style-image:url(images/ag.gif);

第一个使用绝对路径，第二个使用相对路径。绝对路径当然不会出问题了，但使用相对路径时要注意了：如果你的样式表是单独以一个文件存在的，也就是说写在了***.css里面的，那么图片路径就要相对于这个样式表来写，而不是相对于引用它的文件来写。


正确设置1px高的DIV

标题：正确设置1px高的DIV
作者：vkvi
来源：千一网络
如果为一个 div 设置样式height:1px，在 FireFox 和 NetScape 能够如愿显示，可是在 IE 中则不止 1 像素高。原因是 IE 有个最小高度，就是文字的高度，如果对样式表添加一个 font-size:1px 就能解决问题了，如 <div style="height:1px;font-size:1px;"></div>


SCOPE_IDENTITY()取出的记录

标题：SCOPE_IDENTITY()取出的记录
作者：leen
来源：千一网络
在SQL Server中要取出刚刚插入的记录ID，我们常用select SCOPE_IDENTITY() as lastIndex，但IsNumeric(rs("lastIndex"))是FALSE，它就像numeric类型一样，通过RecordSet取出来后，虽然样子像个数字，实际上IsNumeric判断却为假，这给后面的使用带来不便，所以我们一般直接强制类型转换id = CLng(rs("lastIndex"))。


smalldatetime和datetime存储

标题：smalldatetime和datetime存储
作者：leen
来源：千一网络

在SQL Server中，smalldatetime只能精确到分钟，而datatime可以精确到3%秒（3.33毫秒）。

smalldatetime占用4个字节，前2个字节存储base date（1900年1月1日）之后的天数。后2个字节存储午夜后的分钟数。

datetime占用8个字节，前4个字节存储base date（即1900年1月1日）之前或之后的天数，后4个字节存储午夜后的毫秒数。

由于datetime的精度是3%秒，这就涉及到小数，毫秒之前可以是冒号，也可以是小数点。使用冒号时表示的意义同时分秒间隔，11:11:11:21表示021毫秒，前面的0省略，而小数点表示的意义同数学上的小数点，如11:11:11.21表示210毫秒，省略的是后面的0。

毫秒必须是.000、.003、或 .007的整数倍，如果不是，那么将会自动调整。


SQL Server几个数字类型的插入与取值

标题：SQL Server几个数字类型的插入与取值
作者：leen
来源：千一网络
bit
对bit赋值时，使用0或1。
利用RecordSet将值取出来后是布尔类型。

numeric
对numeric赋值时，既可像文本一样加单引号，也可像数字一样不加单引号。
利用RecordSet将值取出来后，用IsNumeric判断，返回false。

decimal
和numeric同义。

money
对money赋值时，只能以数字的形式赋值。
利用RecordSet将值取出来后，用IsNumeric判断，返回true。


SQL Server中bit数据类型应用

标题：SQL Server中bit数据类型应用
作者：leen
来源：千一网络

使用过 Access 的朋友都知道，Access 里有个“是/否”数据类型，在 SQL Server 中，没有这个名称，而使用 bit。在使用过程中有几点需要注意的：

１、bit 与 SQL Server 的整型和数字数据相似的数字数据，但 bit 列只能存储 0 和 1。

２、在插入、修改 bit 数据时，使用 0 或 1 ，而不是 false 或 true，bit 字段放在 where 查询条件中也是这样。

３、利用 RecordSet 将 bit 字段中的数据取出来后，它是 boolean 类型，而不是数字类型，即在判断时应该使用 if rs("bitField") then，而不是 if rs("bitField")=1 then。


SQL Server中timestamp（时间戳）

标题：SQL Server中timestamp（时间戳）
作者：leen
来源：千一网络

在SQL Server中联机丛书是这样说的：

SQL Server timestamp 数据类型与时间和日期无关。SQL Server timestamp 是二进制数字，它表明数据库中数据修改发生的相对顺序。实现 timestamp 数据类型最初是为了支持 SQL Server 恢复算法。每次修改页时，都会使用当前的 @@DBTS 值对其做一次标记，然后 @@DBTS 加1。这样做足以帮助恢复过程确定页修改的相对次序，但是 timestamp 值与时间没有任何关系。

我用口水话解释一下便于理解：

我们知道数字类型有个“标识”属性，设置好“标识种子”、“标识递增量”，每增加一条记录时，这个字段的值就会在最近的一个标识值基础上自动增加，这样我们可以知道哪些记录是先添加的，哪些记录是后添加的，但是我们无法知道哪些记录修改过。timestamp这个类型的字段呢，每增加一条记录时，它会在最近的一个时间戳基础上自动增加，当修改某条记录时，它也会在最近的一个时间戳基础上自动增加，所以我们就知道哪些记录修改过了。


如何显示timestamp的值

标题：如何显示timestamp的值
作者：leen
来源：千一网络

关于timestamp数据类型，请参见SQL Server中timestamp（时间戳）

有朋友反应response.Write(rs("[timestamp]"))，是一片空白，可是在查询分析器中看到的是一串数字。这种情况下，在写SQL语句时这样写，select (字段名+0) as 别名，输出时就会有显示了。


查看、更改SQL Server许可证数

标题：查看、更改SQL Server许可证数
作者：leen
来源：千一网络

在SQL Server企业版中，有一个许可模式概念，有两种许可模式：“处理器许可证”和“每客户”模式。“处理器许可证”模式表示允许几个CPU运行SQL Server，“每客户”决定的是客户端连接数。要查看、更改许可证数，则打开“控制面板”，双击“SQL Server 2000许可安装”（如果没有这一项说明版本不同，不需要涉及许可模式）。注意不要与Windows的授权弄混了，虽然图标是一样的。

弹出如下一个对话框，注意，我们只能更改许可证数（越大需要的Money越多），不可更改许可模式，许可模式是在安装是确定的。


TRUNCATE TABLE和DELETE

标题：TRUNCATE TABLE和DELETE
作者：leen
来源：千一网络

TRUNCATE TABLE和不带WHERE的DELETE功能是一样的，都是删除表中的所有数据，不过TRUNCATE TABLE速度更快，占用的日志更少，这是因为TRUNCATE TABLE直接释放数据页并且在事务日志中也只记录数据页的释放，而DELETE是一行一行地删除，在事务日志中要记录每一条记录的删除。

那么可不可以用TRUNCATE TABLE代替不带WHERE的DELETE呢？在以下情况是不行的：
1、要保留标识的情况下不能用TRUNCATE TABLE，因为TRUNCATE TABLE会重置标识。
2、需要使用触发器的情况下不能使用TRUNCATE TABLE，它不会激发触发器。
3、对于由 FOREIGN KEY 约束引用的表不能使用TRUNCATE TABLE。
4、对于参与了索引视图的表不能使用TRUNCATE TABLE，注意指索引视图，并非普通视图。


查询子句只包含被忽略的词

标题：查询子句只包含被忽略的词
作者：leen
来源：千一网络

在使用全文索引时，出现如下消息：
服务器: 消息 7619，级别 16，状态 1，行 2
查询子句只包含被忽略的词。

1、搜索词是否属噪声词，如“的”、“我”、“is"等较简单的词语，如果是，请换用非噪声词搜索或在搜索前对噪声词作过滤。（噪声词，SQL Server全文索引不会对某些简单的词语作索引，这些词语保存在Microsoft SQL Server安装目录\MSSQL\FTDATA\SQLServer\Config之下，以noise为文件标识符，以语言缩写为文件扩展名）。

2、用任何搜索词时均出现上述错误。检查噪声词目录下是否有noise.chs文件（如果你在配置全文索引时选择的单词断字符是“中文（中国）”），如果没有，请新建一个，或从其它地方上复制一个。如果有，请检查是否有内容。

3、有相应的噪声词文件，并且其内容不为空。重建全文目录。


SQL Server“吃内存”的解决

标题：SQL Server“吃内存”的解决
作者：leen
来源：千一网络
    现象：Web服务器中SQL Server占用内存非常高，加内存后，SQL Server又吃掉新加的内存，好像内存永远不够用一样。

    分析：其实这并不一定是由于SQL Server活动过度造成的，在启动SQL Server后，SQL Server内存使用量会持续稳定上升，即使服务器上活动很少也不会下降，直到物理内存仅剩下4到10M为止，这是SQL Server缓冲池的预期行为，正常现象。

    解决：不过这种现象使得服务器应付峰值的能力降低，当突然有较大的活动时，可能使得服务器当机。要限制缓冲池的内存使用量，可以打开“SQL Server属性”->“内存”，在这一页中降低“最大值”，点击“确定”。点击“运行值”，可以发现“最大值”没有变化，说明刚才的设置并没有生效，实际上该设置更改后要重新启动SQL Server才能生效，重新启动SQL Server。

    注意：这里的内存，并不是指SQL Server整个占用的内存，而是指SQL Server缓冲池所用的内存，所以SQL Server实际所占内存要大于此值。


解决日志占用大量空间问题

标题：解决日志占用大量空间问题
作者：leen
来源：千一网络
    随着数据库的运行，数据库占用的磁盘空间越来越大，这是由于日志所造成的，简单使用收缩数据库，往往无法减小日志。使用如下代码：

BACKUP LOG 数据库名 WITH NO_LOG
BACKUP LOG 数据库名 WITH TRUNCATE_ONLY
DBCC SHRINKDATABASE (数据库名)

NO_LOG和TRUNCATE_ONLY
无须备份复制日志即删除不活动的日志部分，并且截断日志。NO_LOG 和 TRUNCATE_ONLY 是同义的，任选一个使用。使用 NO_LOG 或 TRUNCATE_ONLY 备份日志后，记录在日志中的更改不可恢复。为了恢复，请立即执行 BACKUP DATABASE。注意，这只对简单恢复模式的数据库有效。如果要对完全恢复模式和大容量恢复模式的数据库进行日志截断，请参见“收缩数据库”。

DBCC SHRINKDATABSE
收缩数据库。


三种故障还原模型

标题：三种故障还原模型
作者：leen
来源：千一网络

打开SQL Server企业管理器，展开“数据库”树型菜单，在任一数据库上点右键，选择“属性”，切换到“选项”标签，我们就可以看到“故障还原”里有一个下拉列表框，包括“大容量日志记录的”、“简单”、“完全”，这就是我们要说的三种故障还原模型。

简单恢复，使用简单恢复模型可以将数据库恢复到上次备份的即时点，不过无法将数据库还原到故障点或特定的即时点。使用简单恢复模型时，我们可以使用完整数据库备份，也可以使用差异备份，但不能使用事务日志备份。比如说你要将数据库恢复到9:10时的数据，那么除非你在9:10备份了数据库，否则在简单恢复模式下是无法办到。

完全恢复模型可以使用完整数据库备份、差异备份和事务日志备份。正因为它可以备份事务日志，所以它可以将数据库还原到特定的即时点。

如果没有大容量复制操作，那么大容量日志记录恢复模型和完全恢复模型是一样的，当进行了大容量复制操作后，再备份日志，那么就不能在这个日志备份集中使用即时点还原（完全恢复模型则可以），这正是与完全恢复模型不同的地方，正因为如此，它备份日志时所需的空间不会多余完全恢复模型下所用的空间。
大容量复制操作：
SELECT INTO。
大容量装载操作（bcp 和 BULK INSERT）。
CREATE INDEX（包括索引视图）。
text 和 image 操作（WRITETEXT 和 UPDATETEXT）。


索引为什么要有顺序

标题：索引为什么要有顺序
作者：leen
来源：千一网络

在建立索引时，有一个参数就是用以指定索引的顺序是升序还是降序，那么索引的升序还是降序对查询的性能有何影响呢。

当ORDER BY子句只有一个字段时，索引的顺序就没有什么影响了，因为不管我们是按升序还是降序排列，SQL Server都可以使用从头扫描至尾或从尾扫描至头的方式来到达最好的性能。

假如ORDER BY子句有多个字段，情况就非常复杂了。假设表中有索引：
CREATE CLUSTERED INDEX UPKCL_taind ON titleauthor(au_id DESC, title_id DESC)

我们在使用如下查询语句时：
select * from titleauthor order by au_id desc, title_id desc

再比较如下语句
select * from titleauthor order by au_id desc, title_id asc

这时我们发现多了Bookmark Lookup（根据表的情况和查询的语句的不同，可能此步骤也不同），这是因为无法一次完全使用索引造成的。我们再把索引改成
CREATE CLUSTERED INDEX UPKCL_taind ON titleauthor(au_id DESC, title_id ASC)
使用第二个查询语句就不会有Bookmark Lookup步骤了，因为它的索引顺序和查询排序一样。

我们上面使用的是聚集索引，如果是非聚集索引，可能会得到如下的结果。可以看到产生了全表扫描，所以说索引的顺序也是非常重要的。

注意建立组合索引时不应该只考虑order by，也应该把where考虑进来。


整理索引碎片，提升SQL Server速度

标题：整理索引碎片，提升SQL Server速度
作者：leen
来源：千一网络

数据库表A有十万条记录，查询速度本来还可以，但导入一千条数据后，问题出现了。当选择的数据在原十万条记录之间时，速度还是挺快的；但当选择的数据在这一千条数据之间时，速度变得奇慢。

凭经验，这是索引碎片问题。检查索引碎片DBCC SHOWCONTIG(表)，得到如下结果：

DBCC SHOWCONTIG 正在扫描 'A' 表...
表: 'A'（884198200）；索引 ID: 1，数据库 ID: 13
已执行 TABLE 级别的扫描。
- 扫描页数.....................................: 3127
- 扫描扩展盘区数...............................: 403
- 扩展盘区开关数...............................: 1615
- 每个扩展盘区上的平均页数.....................: 7.8
- 扫描密度［最佳值:实际值］....................: 24.20%［391:1616］
- 逻辑扫描碎片.................................: 68.02%
- 扩展盘区扫描碎片.............................: 38.46%
- 每页上的平均可用字节数.......................: 2073.2
- 平均页密度（完整）...........................: 74.39%
DBCC 执行完毕。如果 DBCC 输出了错误信息，请与系统管理员联系。

由上我们看出，逻辑扫描碎片和扩展盘区扫描碎片都非常大，果真需要对索引碎片进行处理了。

一般有两种方法解决，一是利用DBCC INDEXDEFRAG整理索引碎片，二是利用DBCC DBREINDEX重建索引。二者各有优缺点。调用微软的原话如下：
DBCC INDEXDEFRAG 命令是联机操作，所以索引只有在该命令正在运行时才可用。而且可以在不丢失已完成工作的情况下中断该操作。这种方法的缺点是在重新组织数据方面没有聚集索引的除去/重新创建操作有效。

重新创建聚集索引将对数据进行重新组织，其结果是使数据页填满。填满程度可以使用 FILLFACTOR 选项进行配置。这种方法的缺点是索引在除去/重新创建周期内为脱机状态，并且操作属原子级。如果中断索引创建，则不会重新创建该索引。

也就是说，要想获得好的效果，还是得用重建索引，所以决定重建索引。
DBCC DBREINDEX(表，索引名，填充因子）
第一个参数，可以是表名，也可以是表ID。
第二个参数，如果是''，表示影响该表的所有索引。
第三个参数，填充因子，即索引页的数据填充程度。如果是100，表示每一个索引页都全部填满，此时select效率最高，但以后要插入索引时，就得移动后面的所有页，效率很低。如果是0，表示使用先前的填充因子值。

DBCC DBREINDEX(A，''，100)
重新测试查询速度，飞快。

另：一般来说填充因子使用系统默认的值即可。


小说SQL的Count

标题：小说SQL的Count
作者：leen
来源：千一网络

Count(*) 统计所有记录的行数，即使某一记录的所有字段为NULL也要记入统计。

Count(字段) 统计所有记录中这一字段值不为NULL的行数。

Count(DISTINCT 字段) 统计所有记录中这一字段值不重复的行数，NULL算作一条。


由SQL的like说开去(1)

标题：由SQL的like说开去(1)
作者：leen
来源：千一网络

要选取表tbl中字段fld以"t_"开头的记录，使用"select * from tbl where fld like 't_%'"，然而结果却不如我们的意，它选出的是所有以"t"开头的记录，而不是以"t_"开头的记录。

原来"_"是通配符，表示零个或一个任何字符。虽然我们都知道"_"是个通配符，但在这里使用时往往会疏忽，尤其是关键词来自客户端输入时。这里正确的写法应该是"select * from tbl where fld lik 't[_]%'"。

"[]"表指定范围 (如[a-f]) 或集合 (如[abcdef]) 中的任何单个字符。
"[^]"表不属于指定范围 (如[a-f]) 或集合 (如[abcdef]) 的任何单个字符。

那么我们不想将"["、"]"作为通配符时又如何写呢？
    搜索"["用 like '[[]'
    搜索"]"用 like ']'
    比如我们要选取表tbl中字段fld含有"[1]"的记录，使用"select * from tbl where fld like '%[[]1]%'"。


由SQL的like说开去(2)

标题：由SQL的like说开去(2)
作者：leen
来源：千一网络

当使用 LIKE 进行字符串比较时，模式字符串中的所有字符都有意义，包括起始或尾随空格。如果查询中的比较要返回包含"abc "（abc 后有一个空格）的所有行，则将不会返回包含"abc"（abc 后没有空格）的列所在行。但是可以忽略模式所要匹配的表达式中的尾随空格。如果查询中的比较要返回包含"abc"（abc 后没有空格）的所有行，则将返回以"abc"开始且具有零个或多个尾随空格的所有行。

假设表tbl中含有字段fld（varchar类型），表共有三条记录，各记录的fld值分别是："abc　"（abc后有一中文空格），"abc "（abc后有一英文空格），"abc"，" abc"（abc前一有英文空格）。那么：
    select * from tbl where fld like 'abc'，将取出前三条记录，记录中的尾随空格被忽略。
    select * from tbl where fld like 'abc　'（abc后有一中文空格），那么将取出前两条记录，模式字符串中的尾随空格不能忽略。
    select * from tbl where fld like 'abc '（abc后有一英文空格），那么将取出前两条记录。
    select * from tbl where fld like ' abc'（abc后有一中文空格），那么将取出第四条记录。

如果上例中fld字段类型为char(20)，那么第三、三条SQL语句将取出前三条记录，因为char类型字段会在记录后以空格补足长度，其它一样。


由SQL的like说开去(3)

标题：由SQL的like说开去(3)
作者：leen
来源：千一网络

在前面我们介绍搜索通配符字符时，使用"[]"，比如要搜索"_"字符，就用"[_]"，这里介绍另一种方法——自定义转义符。我们知道要搜索英文单引号（"'"），我们用两个英文单引号，其中第一个就是转义符。在SQL中，自定义转义符的关键字是escape。

比如我们要选取表tbl中字段fld含有"1_"的记录，使用"select * from tbl where fld like '%1/_%' escape '/'"，这样就把'/'当作转义符了，"_"也就不会当作通配符了。

转义符忽略大小写吗？
    不！如下两句结果是不一样的：
    select * from tbl where fld like '%1d_%' escape 'd'
    select * from tbl where fld like '%1D_%' escape 'd'

两个转义字符在一起，两个字符都是转义字符吗？
    不！看下面的例子：
    select * from tbl where fld like '%1ddd_%' escape 'd'
    它搜索fld含有"1d_"的记录。


由SQL的like说开去(4)

标题：由SQL的like说开去(4)
作者：leen
来源：千一网络

与UNICODE字符运算
    表tbl字段fld类型为nvarchar(20)
    declare @key varchar(20)
    set @key = 'abc'
    select * from tbl where fld like '%'+@key+'%'
    会选取出字段fld含有'abc'的记录。

与float类型运算
    我们知道float存储的是近似值，假如值3.0，可能是按2.99999...来存储的，但这只是它的存储方面，在使用like比较之前，它会按存储的值转换成实际的float值，然后再转换成varchar值。所以这时我们使用like '2.99%'和like '3.0'都找不到这条记录的。应该用like '3'。

与datetime类型运算
    同样，是先将存储的值转换成datetime格式，再转换成varchar，然后进行like运算。
    比如将2005-03-04 11:21:49转换成varchar为03 4 2005 11:21AM，我们就可以进行like运算。smalldatetime也是一样的。

与null值
    试图用"select * from tbl where fld like null"来提取表tbl中字段fld为null的记录是错误的用法，因为有null参与的运算同样返回null，我们应该用"select * from tbl where fld is null"。


在TEXT中使用CHARINDEX或LIKE

标题：在TEXT中使用CHARINDEX或LIKE
作者：leen
来源：千一网络

CHARINDEX是用于字符串类型的，在text、ntext中不适用，对于text、ntext类型用PATINDEX。语法：PATINDEX('%pattern%', expression)，找到返回位置，没有找到返回0。

比如：select * from tbl where PATINDEX('%本月%',content)>0，就找出了content含有"本月"的记录。"%"是通配符，另外还有"_"通配符，就像like语句一样。注意记录多时不适用，记录多时应该用全文索引。


在TEXT中使用LEN

标题：在TEXT中使用LEN
作者：leen
来源：千一网络
对text、ntext、image类型的字段，是不允许使用LEN函数来计算长度的，使用DATALENGTH()函数。