webform后台判断金额必须为数字_webform后台控制元素 - CSDN
精华内容
参与话题
  • Web中绘制图形的方法大致有:1. VML方式:功能强大,但是非常麻烦。 推荐:http://www.elook.net.cn/vml/ 2.使用控件:Dandus, Aspose.chart,ComponentOne使用方便。虽然有破解,但非开源。ComponetOne: ...

    Web中绘制图形的方法大致有:

    1. VML方式:功能强大,但是非常麻烦。

         推荐:http://www.elook.net.cn/vml/ 

    2.使用控件:Dandus, Aspose.chart,ComponentOne使用方便。虽然有破解,但非开源。

    ComponetOne: http://blog.csdn.net/ChengKing/category/146827.aspx

    3.结合OFFICE Web Components开发。

    4.使用商用工控组件。

    5.自己编写程序。

    数据棒图实现

    棒图实现最简单,用颜色填充<span>元素即可。

    <span id="Draw0">&nbsp;</span>

    <span id="Draw1">&nbsp;</span>

    <span id="Draw2">&nbsp;</span>


    //开始画棒图
      for(i=0;i<20;++i){
        totalCost1[i]=Math.abs(totalCost[i])*100/sum*1.25;        //正值-蓝色显示
         if(totalCost[i]>0)
         {
         parent.rightFrame.eval("Draw"+[i]).innerHTML = "<img src=images/blue.gif height=12 width=" + totalCost1[i] + ">"
         }
         else                                                //负值-红色显示
         parent.rightFrame.eval("Draw"+[i]).innerHTML = "<img src=images/red.gif height=12 width=" + totalCost1[i] + ">"
      }
    }


    数据饼图实现

    来自 Terrylee的技术专栏

    ASP.NET之所以能够在客户端浏览器中形成各种数据图片,是因为在ASP.NET中提供了绘图功能,具体的作法是先在服务器端创建一个Bitmap实例,然后利用ASP.NET中提供的绘图功能,按照要生成的图片的模样,进行绘制,最后把绘制好的实例以数据流的方式传送到客户端的浏览器上,并形成图片显示出来。本文要介绍的在ASP.NET页面中实现数据饼图采用的基本也是这种方法。饼图有时称为"Pie"图,本文要实现的数据饼图模样具体如图01所示:

    图01:在ASP.NET页面中产生的数据饼图

      一.本文程序设计和运行的软件环境:

      (1).微软公司视窗2000服务器版。

      (2).Visual Studio .Net正式版,.Net FrameWork SDK版本号3705。

      (3).MDAC 2.6(Microsoft Data Acess Component)以上版本。

      二.数据字典:
    为了方便起见,本文选择的数据库类型为本地数据库--Access 2000,如果你使用的是其他数据库类型,只需对下面介绍的程序中的关于数据库连接的代码进行相应的修改就可以了。Access数据库名称为"db2.mdb",在此数据库中只定义了一张数据表"MonthSale",此表的结构如表01所示:

    字段名称 类型 说明
    ID 自动编号 主键 ,递增
    YF 数字 销售月份
    SL 数字 销量

             表01:MonthSale数据表的结构

      在定义完"db2.mdb"数据库中的"MonthSale"数据表后,在MonthSale数据表中按照表02所示添加记录:

    ID YF SL
    1 1 12
    2 2 5
    3 3 7
    4 4 20
    5 5 16
    6 6 10
    7 7 19
    8 8 8
    9 9 7
    10 10 13
    11 11 11
    12 12 15

          表02:MonthSale数据表中的记录情况

      在MonthSale数据表中添加完这12条记录后,保存"db2.mdb"数据库到C盘的根目录中。

    下面就要解决根据从数据库中读取的数据绘制Pie图的方法。

      (1).绘制数据Pie图的实现方法:

      图01所示的Pie图看似是由一个圆形按照从数据库中得到数据值的大小分割而成的,其实在具体实现时并非如此,图01所示的Pie图其实由许多根据从数据库中数值大小,绘制相应的扇型,并由这些扇型组合而成的

      (2).简介ASP.NET页面中绘制扇型要使用到的类及其方法:

      在本文和前文中,在ASP.NET页面中实现绘图功能主要使用的是Graphics类,Graphics类被封装在命名空间"System.Drawing"中。Graphics类中定义了很多方法和属性,这些方法和属性都与绘图有关,Graphics类中的常用成员具体可参阅表01和表02,表01是Graphics类中的常用方法及其说明,表02是Graphics类中常用属性及其说明:

    方法 说明
    Clear 清除整个绘图面并以指定背景色填充。
    Dispose 释放由此Graphics对象使用的所有资源。
    DrawArc 绘制一段弧线,它表示由一对坐标、宽度和高度指定的椭圆部分。
    DrawEllipse 绘制一个由边框定义的椭圆。
    DrawIcon 在指定坐标处绘制由指定的Icon对象表示的图像。
    DrawIconUnstretched 绘制指定的Icon对象表示的图像,而不缩放该图像。
    DrawImage 在指定位置并且按原始大小绘制指定的Image对象。
    DrawImageUnscaled 在坐标对所指定的位置并且按其原始大小绘制指定的Image对象。
    DrawLine 绘制一条连接由坐标对指定的两个点的线条。
    DrawLines 绘制一系列连接一组Point结构的线段。
    DrawPie 绘制一个扇形,该扇形由一个坐标对、宽度和高度以及两条射线所指定的椭圆定义。
    DrawPolygon 绘制由一组Point结构定义的多边形。
    DrawRectangle 绘制由坐标对、宽度和高度指定的矩形。
    DrawRectangles 绘制一系列由Rectangle结构指定的矩形。
    DrawString 在指定位置并且用指定的Brush和Font对象绘制指定的文本字符串。
    FillClosedCurve 填充由Point结构数组定义的闭合基数样条曲线的内部。
    FillEllipse 填充边框所定义的椭圆的内部,该边框由一对坐标、一个宽度和一个高度指定。
    FillPie 填充由一对坐标、一个宽度、一个高度以及两条射线指定的椭圆所定义的扇形区的内部。
    FillPolygon
    填充Point结构指定的点数组所定义的多边形的内部。
    FillRectangle 填充由一对坐标、一个宽度和一个高度指定的矩形的内部。
    FillRectangles 填充由Rectangle结构指定的一系列矩形的内部。
    FillRegion 填充Region 对象的内部。
    Flush 强制执行所有挂起的图形操作并立即返回而不等待操作完成。
    FromHdc 从设备上下文的指定句柄创建新的Graphics对象。
    FromHwnd 从窗口的指定句柄创建新的Graphics对象。
    FromImage 从指定的Image对象创建新Graphics对象。
    GetHdc 获取与此Graphics对象关联的设备上下文的句柄。
    ReleaseHdc 释放通过以前对此Graphics对象GetHdc方法的调用获得的设备上下文句柄。
    ResetClip 将此Graphics对象的剪辑区域重置为无限区域。
    ResetTransform 将此Graphics对象的全局变换矩阵重置为单位矩阵。


               表01:Graphics类中的常用方法及其说明

      在本文中使用最多,也是最重要的方法就是:FillPie和DrawPie方法。这二个方法的具体使用方法,在下文中又详细介绍。

    属性 说明
    Clip 获取或设置Region对象,该对象限定此Graphics对象的绘图区域。
    ClipBounds 获取RectangleF结构,该结构限定此Graphics对象的剪辑区域。
    DpiX 获取此Graphics对象的水平分辨率。
    DpiY 获取此Graphics对象的垂直分辨率。
    PageScale 获取或设置此Graphics对象的全局单位和页单位之间的比例。
    PageUnit 获取或设置用于此Graphics对象中的页坐标的度量单位。
    PixelOffsetMode 获取或设置一个值,该值指定在呈现此Graphics对象的过程中像素如何偏移。
    RenderingOrigin 为抵色处理和阴影画笔获取或设置此Graphics对象的呈现原点。
    SmoothingMode 获取或设置此Graphics对象的呈现质量。
    TextRenderingHint 获取或设置与此Graphics对象关联的文本的呈现模式。
    Transform 获取或设置此Graphics对象的全局变换。
    VisibleClipBounds 获取或设置此Graphics对象的可见剪辑区域的边框。

                 表02:Graphics类中的常用属性及其说明

      (3).利用FillPie和DrawPie方法绘制扇型的具体方法:

      DrawPie方法功能是绘制一个扇型,下面是 DrawPie方法的一种调用语法,此语法也是本文中主要的调用方式,具体如下:

      public void DrawPie ( Pen , float , float , float , float , float , float ) ;

      此种DrawPie调用方法是由七个参数组成,这七个参数的具体说明如下:

      第一个参数:定义绘制扇型的画笔类型;

      第二和第三个参数:定义扇型的坐标;

      第四和第五个参数:定义组成扇型的二个射线的长度;

      第六和第七个参数:定义扇型的开始角度和扇型旋转的角度大小。其中把X坐标的正方向定为0度角,计算扇型的开始角度的按照顺时针方向旋转,最先到达的扇型的那条射线和0度角之间的夹角。

      下列代码就是在ASP.NET页面中绘制一个扇型:

    Bitmap bm = new Bitmap ( 600 , 300 ) ;
    //创建一个长度为600,宽带为300的Bitmap实例
    Graphics g ;
    g = Graphics.FromImage ( bm ) ;
    //由此Bitmap实例创建Graphic实例
    g . Clear ( Color . Snow ) ;
    g.DrawPie ( Pens.Red , 50 , 50 , 150 , 150 , 0 , 30 ) ;

     四.ASP.NET页面中实现数据Pie图实现步骤

      在实现数据Pie图之前,首先要确保在C盘的根目录存在"db.mdb"数据库,并且此数据库已经设定完毕,并且存在《在ASP.NET页面中实现数据棒图》一文中的数据。下面是ASP.NET实现数据Pie图的具体步骤,开发工具使用的是Visual Studio .Net,采用的是C#语言。

      1. 启动Visual Studio .Net。

      2. 选择菜单【文件】|【新建】|【项目】后,弹出【新建项目】对话框。

      3. 将【项目类型】设置为【Visual C#项目】。

      4. 将【模板】设置为【ASP.NET Web 应用程序】。

      5. 在【位置】的文本框中输入"http://localhost/Pie"。然后单击【确定】按钮,这样在Visual Studio .Net就会在当前项目文件所在目录中建立一个名称为"Pie"文件夹,里面存放是此项目的项目文件,项目中的其他文件存放的位置是计算机Internet信息服务的默认的Web站点所在的目录中新建的一个名称为"WebPieDemo"的文件夹中
     6. 把Visual Studio .Net的当前窗口切换到WebForm的代码编辑窗口,即:WebForm1.aspx.cs文件的编辑窗口。

      7. 在WebForm1.aspx.cs文件首部,用下列代码替换WebForm1.aspx.cs中导入命名空间的代码:

    1//下面程序中使用的ImageFormat类所在的命名空间
    2using System . Drawing . Imaging ;
    3//下面程序中使用到关于数据库方面的类所在的命名空间
    4using System . Data . OleDb ;

    8. WebForm1.aspx.cs文件中的Page_Load事件处理代码中添加下列代码,下列代码的作用是打开数据库,读取数据,并以此数据形成数据Pie图:

      1private void Page_Load(object sender, System.EventArgs e)
      2        {
      3            // 在此处放置用户代码以初始化页面
      4            string sRouter = "c://db2.mdb" ;
      5
      6            //获得当前Access数据库在服务器端的绝对路径
      7            string strCon = " Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " + sRouter ;
      8
      9            //创建一个数据库连接
     10            OleDbConnection myConn = new OleDbConnection ( strCon ) ;
     11            string strCom = " SELECT YF ,SL FROM MonthSale ORDER BY YF" ;
     12            myConn.Open ( ) ;
     13            OleDbCommand myCommand = new OleDbCommand ( strCom , myConn ) ;
     14            OleDbDataReader myOleDbDataReader = myCommand.ExecuteReader ( ) ;
     15            //创建OleDbDataReader实例,并以此实例来获取数据库中各条记录数据
     16
     17            int [ ] iXiaoSH = new int [ 12 ] ;
     18            //定义一个数组,用以存放从数据库中读取的销售数据
     19
     20            string [ ] sMoth = new string [ 12 ] ;
     21            //定义一个数组,用以存放从数据库中读取的销售月份
     22
     23            int iIndex = 0 ;
     24            while ( myOleDbDataReader.Read ( ) ) 
     25            {
     26                iXiaoSH [ iIndex ] = myOleDbDataReader.GetInt32 ( 1 ) ;
     27                sMoth [ iIndex ] = myOleDbDataReader.GetInt32 ( 0 ) . ToString() + "" ;
     28                iIndex++ ;
     29            }

     30            //读取Table01数据表中的各条数据,并存放在先前定义的二个数组中
     31
     32            myConn . Close ( ) ;
     33            myOleDbDataReader . Close ( ) ;
     34 
     35            Bitmap bm = new Bitmap ( 600 , 300 ) ;
     36            //创建一个长度为600,宽带为300的Bitmap实例
     37
     38            Graphics g ;
     39            g = Graphics.FromImage ( bm ) ;
     40            g . Clear ( Color . Snow ) ;
     41            g . DrawString ( " ××公司××××年度销售情况一览表" , new Font ( "宋体" , 16 ) , Brushes . Black , new Point ( 5 , 5 ) ) ;
     42            //在绘画图面的指定位置,以指定的字体、指定的颜色绘制指定的字符串。即为图表标题
     43
     44            //以下代码是是实现图01中的右上部区域
     45            //以上是在图01中为下面绘制定位
     46            Point myRec = new Point ( 515 , 30 ) ;
     47            Point myDec = new Point ( 540 , 30 ) ;
     48            Point myTxt = new Point ( 565 , 30 ) ;
     49            g . DrawString ( "单位:万套" , new Font ( "宋体" , 9 ) , Brushes . Black , new Point ( 515 , 12 ) ) ;
     50            for ( int i = 0 ; i < sMoth.Length ; i++ ) 
     51            {
     52                g . FillRectangle ( new SolidBrush ( GetColor ( i ) ) , myRec . X , myRec . Y , 20 , 10 ) ;
     53                //填充小方块
     54
     55                g . DrawRectangle ( Pens.Black , myRec . X , myRec . Y , 20 , 10 ) ;
     56                //绘制小方块
     57
     58                g . DrawString ( sMoth [ i ] . ToString ( ) , new Font ( "宋体"9 ) , Brushes . Black , myDec ) ;
     59                //绘制小方块右边的文字
     60
     61                g . DrawString ( iXiaoSH[i].ToString (), new Font ( "宋体"9 ) , Brushes . Black , myTxt ) ;
     62                myRec . Y += 15 ;
     63                myDec . Y += 15 ;
     64                myTxt . Y += 15 ;
     65            }

     66
     67            //以下代码是根据从数据库中得到的数值大小,绘制扇型,并以相应色彩填充扇型,//从而构成图01中的Pie图
     68            int iTatal = 0 ; 
     69            float fCurrentAngle = 0 ;
     70            float fStartAngle = 0;
     71            for ( int i = 0 ; i < iXiaoSH . Length ; i++ )
     72            {
     73                iTatal = iTatal + iXiaoSH [ i ] ;
     74            }

     75            for ( int i = 0 ; i < iXiaoSH . Length ; i++ )
     76            {
     77                //以下代码是获得要绘制扇型的开始角度
     78                if ( i == iXiaoSH . Length - 1 )
     79                {
     80                    fCurrentAngle = 360- fStartAngle ;
     81                }

     82                else
     83                {
     84                    int iTemp = iXiaoSH [ i ] ;
     85                    fCurrentAngle = ( iTemp * 360 ) / iTatal ;
     86                }

     87                //根据参数绘制扇型
     88
     89                g.DrawPie ( Pens.Black , 100 , 40 , 250 , 250 , fStartAngle , fCurrentAngle ) ;
     90                //以指定色彩填充绘制的扇型
     91
     92                g.FillPie ( new SolidBrush ( GetColor ( i ) ) , 100 , 40 , 250 , 250 , fStartAngle , fCurrentAngle ) ;
     93                fStartAngle += fCurrentAngle ;
     94            }

     95
     96            //画出图片的边框
     97            Pen p = new Pen ( Color.Black , 2 ) ;
     98            g . DrawRectangle ( p , 1 , 1 , 598 , 298 ) ;
     99
    100            //向客户端输出数据流,并以此数据流形成Jpeg图片
    101            bm.Save ( Response . OutputStream , ImageFormat . Jpeg ) ;
    102        }


    9. WebForm1.aspx.cs文件中的InitializeComponent过程之后,添加下列代码,下列代码的作用是定义一个名称为GetColor函数,此函数的功能根据索引号得到相应的系统颜色:

     1/// <summary>
     2        /// 获取颜色
     3        /// </summary>
     4        /// <param name="itemIndex">数组的索引</param>
     5        /// <returns></returns>

     6        private Color GetColor ( int itemIndex ) 
     7        {
     8             Color MyColor ;
     9             int i = itemIndex ;
    10            switch (i) 
    11             {
    12                  case 0 :
    13                   MyColor = Color.Green;
    14                   return MyColor;
    15                  case 1 :
    16                   MyColor = Color.Red;
    17                    return MyColor;
    18                  case 2:
    19                   MyColor = Color.Yellow;
    20                   return MyColor;
    21                  case 3 :
    22                   MyColor = Color.Blue;
    23                   return MyColor;
    24                  case 4 :
    25                   MyColor = Color.Orange;
    26                   return MyColor;
    27                 case 5 :
    28                   MyColor = Color.Aqua;
    29                   return MyColor;
    30                  case 6:
    31                   MyColor = Color.SkyBlue;
    32                   return MyColor;
    33                  case 7:
    34                   MyColor = Color.DeepPink;
    35                   return MyColor;
    36                  case 8:
    37                   MyColor = Color.Azure;
    38                   return MyColor;
    39                  case 9:
    40                   MyColor = Color.Brown;
    41                   return MyColor;
    42                  case 10:
    43                   MyColor = Color.Pink;
    44                   return MyColor;
    45                  case 11:
    46                   MyColor = Color.BurlyWood;
    47                   return MyColor;
    48                  case 12:
    49                   MyColor = Color.Chartreuse;
    50                   return MyColor;
    51                  default:
    52                   MyColor = Color.Pink;
    53                   return MyColor;
    54            }

    55        }


    至此,在上述步骤都正确执行后,在ASP.NET页面中实现数据Pie图的全部工作就完成了。此时单击快捷键F5,就可以得到如图01所示的数据Pie图了。

      五.总结:

      由于ASP.NET提供了丰富的绘图功能,所以结合这二篇文章的介绍,我想再实现其他的数据图表,应该也不算很困难。

    完整的例子代码:

      1using System;
      2using System.Collections;
      3using System.ComponentModel;
      4using System.Data;
      5using System.Drawing;
      6using System.Web;
      7using System.Web.SessionState;
      8using System.Web.UI;
      9using System.Web.UI.WebControls;
     10using System.Web.UI.HtmlControls;
     11//下面程序中使用的ImageFormat类所在的命名空间
     12using System . Drawing . Imaging ;
     13//下面程序中使用到关于数据库方面的类所在的命名空间
     14using System . Data . OleDb ;
     15
     16
     17namespace WebPieDemo
     18{
     19    /// <summary>
     20    /// WebForm1 的摘要说明。
     21    /// </summary>

     22    public class WebForm1 : System.Web.UI.Page
     23    {
     24        private void Page_Load(object sender, System.EventArgs e)
     25        {
     26            // 在此处放置用户代码以初始化页面
     27            string sRouter = "c://db2.mdb" ;
     28
     29            //获得当前Access数据库在服务器端的绝对路径
     30            string strCon = " Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " + sRouter ;
     31
     32            //创建一个数据库连接
     33            OleDbConnection myConn = new OleDbConnection ( strCon ) ;
     34            string strCom = " SELECT YF ,SL FROM MonthSale ORDER BY YF" ;
     35            myConn.Open ( ) ;
     36            OleDbCommand myCommand = new OleDbCommand ( strCom , myConn ) ;
     37            OleDbDataReader myOleDbDataReader = myCommand.ExecuteReader ( ) ;
     38            //创建OleDbDataReader实例,并以此实例来获取数据库中各条记录数据
     39
     40            int [ ] iXiaoSH = new int [ 12 ] ;
     41            //定义一个数组,用以存放从数据库中读取的销售数据
     42
     43            string [ ] sMoth = new string [ 12 ] ;
     44            //定义一个数组,用以存放从数据库中读取的销售月份
     45
     46            int iIndex = 0 ;
     47            while ( myOleDbDataReader.Read ( ) ) 
     48            {
     49                iXiaoSH [ iIndex ] = myOleDbDataReader.GetInt32 ( 1 ) ;
     50                sMoth [ iIndex ] = myOleDbDataReader.GetInt32 ( 0 ) . ToString() + "" ;
     51                iIndex++ ;
     52            }

     53            //读取Table01数据表中的各条数据,并存放在先前定义的二个数组中
     54
     55            myConn . Close ( ) ;
     56            myOleDbDataReader . Close ( ) ;
     57 
     58            Bitmap bm = new Bitmap ( 600 , 300 ) ;
     59            //创建一个长度为600,宽带为300的Bitmap实例
     60
     61            Graphics g ;
     62            g = Graphics.FromImage ( bm ) ;
     63            g . Clear ( Color . Snow ) ;
     64            g . DrawString ( " ××公司××××年度销售情况一览表" , new Font ( "宋体" , 16 ) , Brushes . Black , new Point ( 5 , 5 ) ) ;
     65            //在绘画图面的指定位置,以指定的字体、指定的颜色绘制指定的字符串。即为图表标题
     66
     67            //以下代码是是实现图01中的右上部区域
     68            //以上是在图01中为下面绘制定位
     69            Point myRec = new Point ( 515 , 30 ) ;
     70            Point myDec = new Point ( 540 , 30 ) ;
     71            Point myTxt = new Point ( 565 , 30 ) ;
     72            g . DrawString ( "单位:万套" , new Font ( "宋体" , 9 ) , Brushes . Black , new Point ( 515 , 12 ) ) ;
     73            for ( int i = 0 ; i < sMoth.Length ; i++ ) 
     74            {
     75                g . FillRectangle ( new SolidBrush ( GetColor ( i ) ) , myRec . X , myRec . Y , 20 , 10 ) ;
     76                //填充小方块
     77
     78                g . DrawRectangle ( Pens.Black , myRec . X , myRec . Y , 20 , 10 ) ;
     79                //绘制小方块
     80
     81                g . DrawString ( sMoth [ i ] . ToString ( ) , new Font ( "宋体"9 ) , Brushes . Black , myDec ) ;
     82                //绘制小方块右边的文字
     83
     84                g . DrawString ( iXiaoSH[i].ToString (), new Font ( "宋体"9 ) , Brushes . Black , myTxt ) ;
     85                myRec . Y += 15 ;
     86                myDec . Y += 15 ;
     87                myTxt . Y += 15 ;
     88            }

     89
     90            //以下代码是根据从数据库中得到的数值大小,绘制扇型,并以相应色彩填充扇型,//从而构成图01中的Pie图
     91            int iTatal = 0 ; 
     92            float fCurrentAngle = 0 ;
     93            float fStartAngle = 0;
     94            for ( int i = 0 ; i < iXiaoSH . Length ; i++ )
     95            {
     96                iTatal = iTatal + iXiaoSH [ i ] ;
     97            }

     98            for ( int i = 0 ; i < iXiaoSH . Length ; i++ )
     99            {
    100                //以下代码是获得要绘制扇型的开始角度
    101                if ( i == iXiaoSH . Length - 1 )
    102                {
    103                    fCurrentAngle = 360- fStartAngle ;
    104                }

    105                else
    106                {
    107                    int iTemp = iXiaoSH [ i ] ;
    108                    fCurrentAngle = ( iTemp * 360 ) / iTatal ;
    109                }

    110                //根据参数绘制扇型
    111
    112                g.DrawPie ( Pens.Black , 100 , 40 , 250 , 250 , fStartAngle , fCurrentAngle ) ;
    113                //以指定色彩填充绘制的扇型
    114
    115                g.FillPie ( new SolidBrush ( GetColor ( i ) ) , 100 , 40 , 250 , 250 , fStartAngle , fCurrentAngle ) ;
    116                fStartAngle += fCurrentAngle ;
    117            }

    118
    119            //画出图片的边框
    120            Pen p = new Pen ( Color.Black , 2 ) ;
    121            g . DrawRectangle ( p , 1 , 1 , 598 , 298 ) ;
    122
    123            //向客户端输出数据流,并以此数据流形成Jpeg图片
    124            bm.Save ( Response . OutputStream , ImageFormat . Jpeg ) ;
    125        }

    126
    127        Web 窗体设计器生成的代码
    146
    147        /// <summary>
    148        /// 获取颜色
    149        /// </summary>
    150        /// <param name="itemIndex">数组的索引</param>
    151        /// <returns></returns>

    152        private Color GetColor ( int itemIndex ) 
    153        {
    154             Color MyColor ;
    155             int i = itemIndex ;
    156            switch (i) 
    157             {
    158                  case 0 :
    159                   MyColor = Color.Green;
    160                   return MyColor;
    161                  case 1 :
    162                   MyColor = Color.Red;
    163                    return MyColor;
    164                  case 2:
    165                   MyColor = Color.Yellow;
    166                   return MyColor;
    167                  case 3 :
    168                   MyColor = Color.Blue;
    169                   return MyColor;
    170                  case 4 :
    171                   MyColor = Color.Orange;
    172                   return MyColor;
    173                 case 5 :
    174                   MyColor = Color.Aqua;
    175                   return MyColor;
    176                  case 6:
    177                   MyColor = Color.SkyBlue;
    178                   return MyColor;
    179                  case 7:
    180                   MyColor = Color.DeepPink;
    181                   return MyColor;
    182                  case 8:
    183                   MyColor = Color.Azure;
    184                   return MyColor;
    185                  case 9:
    186                   MyColor = Color.Brown;
    187                   return MyColor;
    188                  case 10:
    189                   MyColor = Color.Pink;
    190                   return MyColor;
    191                  case 11:
    192                   MyColor = Color.BurlyWood;
    193                   return MyColor;
    194                  case 12:
    195                   MyColor = Color.Chartreuse;
    196                   return MyColor;
    197                  default:
    198                   MyColor = Color.Pink;
    199                   return MyColor;
    200            }

    201        }

    202    }

    203}

    204

     

    在ASP.NET页面中实现数据柱状图

    棒图有时又称为"Bar"图,在ASP.NET中拥有了一个新功能--绘图功能,通过此功能就能够按照要实现的图表的模样来绘制,最后在客户端的浏览器中形成一个图片,从而显示出图表来。

      本文就是介绍在ASP.NET页面中实现Bar图的具体方法。希望本篇文章能够让您领会到ASP.NET中强大的绘图功能,而我们知道图表只有在和数据库关联以后,才能够显示出更强大的优势。下面就来介绍在ASP.NET页面中从数据库中提起数据,并以此数据形成Bar图的具体实现方法。

     一.本文程序设计和运行的软件环境:

      (1).微软公司视窗2000服务器版。

      (2).Visual Studio .Net正式版,.Net FrameWork SDK版本号3705。

      (3).MDAC 2.6(Microsoft Data Acess Component)以上版本。

      二.建立数据源

      为了方便起见,本文选择的数据库类型为本地数据库--Access 2000,如果你使用的是其他数据库类型,只需对下面介绍的程序中的关于数据库连接的代码进行相应的修改就可以了。Access数据库名称为"db2.mdb",在此数据库中只定义了一张数据表"MonthSale",此表的结构如表01所示:

    字段名称 类型 说明
    ID 自动编号 主键 ,递增
    YF 数字 销售月份
    SL 数字 销量

             表01:MonthSale数据表的结构

      在定义完"db2.mdb"数据库中的"MonthSale"数据表后,在MonthSale数据表中按照表02所示添加记录:

    ID YF SL
    1 1 12
    2 2 5
    3 3 7
    4 4 20
    5 5 16
    6 6 10
    7 7 19
    8 8 8
    9 9 7
    10 10 13
    11 11 11
    12 12 15

          表02:Table01数据表中的记录情况

      在MonthSale数据表中添加完这12条记录后,保存"db2.mdb"数据库到C盘的根目录中。
    三.ASP.NET页面中实现数据Bar图的关键步骤及其实现方法:

      在ASP.NET页面中实现数据Bar图首先必须解决二大问题:

      (1).首先要解决在ASP.NET页面中实现数据库连接和从数据库中读取数据的方法。

      程序要实现从数据库中一条条的读取数据,则要使用OleDbDataReader类,OleDbDataReader类提供了从数据库中逐条读取数据的方法。下面代码是连接C盘根目录下的"db2.mdb"数据库,逐条读取MonthSale数据表中的记录,并把数据存放到定义的二个数组中:

     1string sRouter = "c://db2.mdb" ;
     2            //获得当前Access数据库在服务器端的绝对路径
     3
     4            string strCon = " Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " + sRouter ;
     5            //创建一个数据库连接
     6
     7            OleDbConnection myConn = new OleDbConnection ( strCon ) ;
     8            string strCom = " SELECT YF ,SL FROM MonthSale ORDER BY YF" ;
     9            myConn.Open ( ) ;
    10            OleDbCommand myCommand = new OleDbCommand ( strCom , myConn ) ;
    11            OleDbDataReader myOleDbDataReader = myCommand.ExecuteReader ( ) ;
    12            //创建OleDbDataReader实例,并以此实例来获取数据库中各条记录数据
    13
    14            int [ ] iXiaoSH = new int [ 12 ] ;
    15            //定义一个数组,用以存放从数据库中读取的销售数据
    16
    17            string [ ] sMoth = new string [ 12 ] ;
    18            //定义一个数组,用以存放从数据库中读取的销售月份
    19
    20            int iIndex = 0 ;
    21            while ( myOleDbDataReader.Read ( ) ) 
    22            {
    23                iXiaoSH [ iIndex ] = myOleDbDataReader.GetInt32 ( 1 ) ;
    24                sMoth [ iIndex ] = myOleDbDataReader.GetInt32 ( 0 ) . ToString ( ) + "" ;
    25                iIndex++ ;
    26            }

    27            //读取Table01数据表中的各条数据,并存放在先前定义的二个数组中
    28
    29            myConn . Close ( ) ;
    30            myOleDbDataReader . Close ( ) ;
    31            //关闭各种资源


    (2).根据得到数据,绘制图片,并显示出来:

      通过第一步,已经把从数据库中的读取的数据存放到"iXiaoSH"和"sMoth"数组中。下面就要解决依据这些数据绘制出Bar图?首先先了解一下在ASP.NET页面中将要实现的数据Bar图的模样。具体可如图01所示:

    图01:在ASP.NET中实现的数据Bar图

      程序中把图01所示各个元素,按照区域分成了五个部分,这五个部分将在后面介绍的程序中分别实现:

      1. 构建整个图片

      首先要创建一Bitmap实例,并以此来构建一个Graphics实例,Graphics实例提供了各种绘制方法,这样才能按照数据的要求在Bitmap实例上绘制各种图形。下面代码是在ASP.NET中创建Bitmap实例,并以此实例来构建 Graphics实例的具体方法:

    1Bitmap bm = new Bitmap ( 600 , 250 ) ;
    2            //创建一个长度为600,宽带为250的Bitmap实例
    3
    4            Graphics g ;
    5            g = Graphics.FromImage ( bm ) ;
    6            //由此Bitmap实例创建Graphic实例
    7
    8            g . Clear ( Color.Snow) ;
    9            //用Snow色彩为背景色填充此绘画图面

    2. 图01中的标题部分文字:

      这是通过Graphics实例中提供的DrawString方法以指定的字体、颜色、在指定的位置绘制指定的字符串。下面代码的作用是绘制图01中标题:

    1g . DrawString ( " ××公司××××年度销售情况统计表" , new Font ( "黑体" , 16 ) , Brushes . Black , new Point ( 5 , 5 ) ) ;
    2            //在绘画图面的指定位置,以指定的字体、指定的颜色绘制指定的字符串。即为图表标题
    3

    3. 图01中的提示区域,即图01中的右上角显示的内容:

      要绘制这部分内容首先要定位,可以把这部分要绘制的内容分成三个小部分:

      其一,是图01中的"单位:万套"文字,这部分处理起来比较简单,当选定要在图片中输出的文字坐标后,调用Graphics实例中提供的DrawString方法就可以了;
      
      其二,是绘制图01中的小方块,首先要调用Graphics实例中的DrawRectangle方法在指定位置,以指定的颜色,绘制指定大小的方块,然后再条约Graphics实例中的FillRectangle填充这个小方块就完成了;

      其三,是绘制小方块右边的文字。同样要使用Graphics实例中提供的DrawString方法,只不过位置坐标和字体要进行相应改变罢了。下面代码功能是绘制图01右上角显示的内容:

     1//以下代码是是实现图右上部
     2            Point myRec = new Point ( 535 , 30 ) ;
     3            Point myDec = new Point ( 560 , 26 ) ;
     4
     5            //以上是在图01中为下面绘制定位
     6            g . DrawString ( "单位:万套" , new Font ( "宋体" , 9 ) , Brushes . Black , new Point ( 525 , 12 ) ) ;
     7   
     8   
     9            for ( int i = 0 ; i < sMoth.Length ; i++ ) 
    10            {
    11                g . DrawRectangle ( Pens.Black , myRec . X , myRec . Y , 20 , 10 ) ;
    12                //绘制小方块
    13
    14                g . FillRectangle ( new SolidBrush ( GetColor ( i ) ) , myRec.X , myRec.Y , 20 , 10 ) ;
    15                //填充小方块
    16
    17                g . DrawString ( sMoth [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , myDec ) ;
    18                //绘制小方块右边的文字
    19
    20                myRec . Y += 15 ;
    21                myDec . Y += 15 ;
    22            }


    4. 根据从数据库中读取的数据,绘制数据Bar图:

      此部分与第三部分比较类似,最主要的区别在于,绘制的位置不相同,下面代码是在图01中绘制数据Bar图,并提示Bar图所代表的数量:

     

     1//以下代码是绘制Bar图,及其销售数量
     2            int iBarWidth = 40 ;
     3            int scale = 10 ;
     4            for ( int i = 0 ; i < iXiaoSH . Length ; i++ ) 
     5            {
     6                g . DrawRectangle ( Pens.Black, ( i * iBarWidth ) + 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) + 5 ) ;
     7                //绘制Bar图
     8
     9                g . FillRectangle ( new SolidBrush (GetColor ( i )) , ( i * iBarWidth ) + 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) + 5 ) ;
    10                //以指定的色彩填充Bar图
    11
    12                g . DrawString ( iXiaoSH [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , ( i * iBarWidth ) + 20 , 235 - ( iXiaoSH [ i ] * scale ) ) ;
    13                //显示Bar图代表的数据
    14            }

    5. 绘制图片边框,并形成Jpeg文件格式在客户端显示:

      绘制图片边框,使用的Graphics实例中的DrawRectangle方法。至于采用Jpeg格式文件在客户端显示,是因为Jpeg文件占用的空间较小,利于网络传送。下面代码是绘制图01中的边框,并形成Jpeg文件:

    1//以下代码是绘制边框,并形成Jpeg文件,供浏览器显示出来
    2            Pen p = new Pen ( Color.Black , 2 ) ;
    3            g . DrawRectangle ( p , 1 , 1 , 598 , 248 ) ;
    4            bm.Save ( Response . OutputStream , ImageFormat.Gif) ;


    四.ASP.NET页面中实现数据Bar图实现步骤:

      掌握了上面的关键步骤及其解决方法后,在ASP.NET实现数据Bar相对就容易许多了,下面是ASP.NET页面中实现数据Bar图的具体实现步骤,在开发工具上选用的是Visual Stuido .Net企业构建版,采用的开发语言是C#。

      1. 启动Visual Studio .Net

      2. 选择菜单【文件】|【新建】|【项目】后,弹出【新建项目】对话框

      3. 将【项目类型】设置为【Visual C#项目】

      4. 将【模板】设置为【ASP.NET Web 应用程序】

      5. 在【位置】的文本框中输入"http://localhost/Bar"。然后单击【确定】按钮,这样在Visual Studio .Net就会在当前项目文件所在目录中建立一个名称为"WebBarDemo"文件夹,里面存放是此项目的项目文件,项目中的其他文件存放的位置是计算机Internet信息服务的默认的Web站点所在的目录中新建的一个名称为"WebBarDemo"的文件夹中。具体如图02所示:

     图02:新建一个ASP.NET项目对话框

      6. 把Visual Studio .Net的当前窗口切换到WebForm的代码编辑窗口,即:WebForm1.aspx.cs文件的编辑窗口。

      7. 在WebForm1.aspx.cs文件首部,用下列代码替换WebForm1.aspx.cs中导入命名空间的代码

    1//下面程序中使用的ImageFormat类所在的命名空间
    2using System.Drawing.Imaging;
    3//下面程序中使用到关于数据库方面的类所在的命名空间
    4using System.Data.OleDb;

     8. WebForm1.aspx.cs文件中的Page_Load事件处理代码中添加下列代码,下列代码的作用是打开数据库,读取数据,并以此数据形成数据Bar图:

     1private void Page_Load(object sender, System.EventArgs e)
     2        {
     3            // 在此处放置用户代码以初始化页面
     4
     5            string sRouter = "c://db2.mdb" ;
     6            //获得当前Access数据库在服务器端的绝对路径
     7
     8            string strCon = " Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " + sRouter ;
     9            //创建一个数据库连接
    10
    11            OleDbConnection myConn = new OleDbConnection ( strCon ) ;
    12            string strCom = " SELECT YF ,SL FROM MonthSale ORDER BY YF" ;
    13            myConn.Open ( ) ;
    14            OleDbCommand myCommand = new OleDbCommand ( strCom , myConn ) ;
    15            OleDbDataReader myOleDbDataReader = myCommand.ExecuteReader ( ) ;
    16            //创建OleDbDataReader实例,并以此实例来获取数据库中各条记录数据
    17
    18            int [ ] iXiaoSH = new int [ 12 ] ;
    19            //定义一个数组,用以存放从数据库中读取的销售数据
    20
    21            string [ ] sMoth = new string [ 12 ] ;
    22            //定义一个数组,用以存放从数据库中读取的销售月份
    23
    24            int iIndex = 0 ;
    25            while ( myOleDbDataReader.Read ( ) ) 
    26            {
    27                iXiaoSH [ iIndex ] = myOleDbDataReader.GetInt32 ( 1 ) ;
    28                sMoth [ iIndex ] = myOleDbDataReader.GetInt32 ( 0 ) . ToString ( ) + "" ;
    29                iIndex++ ;
    30            }

    31            //读取Table01数据表中的各条数据,并存放在先前定义的二个数组中
    32
    33            myConn . Close ( ) ;
    34            myOleDbDataReader . Close ( ) ;
    35            //关闭各种资源
    36
    37            Bitmap bm = new Bitmap ( 600 , 250 ) ;
    38            //创建一个长度为600,宽带为250的Bitmap实例
    39
    40            Graphics g ;
    41            g = Graphics.FromImage ( bm ) ;
    42            //由此Bitmap实例创建Graphic实例
    43
    44            g . Clear ( Color.Snow) ;
    45            //用Snow色彩为背景色填充此绘画图面
    46
    47            g . DrawString ( " ××公司××××年度销售情况统计表" , new Font ( "黑体" , 16 ) , Brushes . Black , new Point ( 5 , 5 ) ) ;
    48            //在绘画图面的指定位置,以指定的字体、指定的颜色绘制指定的字符串。即为图表标题
    49
    50            //以下代码是是实现图右上部
    51            Point myRec = new Point ( 535 , 30 ) ;
    52            Point myDec = new Point ( 560 , 26 ) ;
    53
    54            //以上是在图01中为下面绘制定位
    55            g . DrawString ( "单位:万套" , new Font ( "宋体" , 9 ) , Brushes . Black , new Point ( 525 , 12 ) ) ;
    56   
    57   
    58            for ( int i = 0 ; i < sMoth.Length ; i++ ) 
    59            {
    60                g . DrawRectangle ( Pens.Black , myRec . X , myRec . Y , 20 , 10 ) ;
    61                //绘制小方块
    62
    63                g . FillRectangle ( new SolidBrush ( GetColor ( i ) ) , myRec.X , myRec.Y , 20 , 10 ) ;
    64                //填充小方块
    65
    66                g . DrawString ( sMoth [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , myDec ) ;
    67                //绘制小方块右边的文字
    68
    69                myRec . Y += 15 ;
    70                myDec . Y += 15 ;
    71            }

    72
    73            //以下代码是绘制Bar图,及其销售数量
    74            int iBarWidth = 40 ;
    75            int scale = 10 ;
    76            for ( int i = 0 ; i < iXiaoSH . Length ; i++ ) 
    77            {
    78                g . DrawRectangle ( Pens.Black, ( i * iBarWidth ) + 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) + 5 ) ;
    79                //绘制Bar图
    80
    81                g . FillRectangle ( new SolidBrush (GetColor ( i )) , ( i * iBarWidth ) + 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) + 5 ) ;
    82                //以指定的色彩填充Bar图
    83
    84                g . DrawString ( iXiaoSH [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , ( i * iBarWidth ) + 20 , 235 - ( iXiaoSH [ i ] * scale ) ) ;
    85                //显示Bar图代表的数据
    86            }

    87
    88            //以下代码是绘制边框,并形成Jpeg文件,供浏览器显示出来
    89            Pen p = new Pen ( Color.Black , 2 ) ;
    90            g . DrawRectangle ( p , 1 , 1 , 598 , 248 ) ;
    91            bm.Save ( Response . OutputStream , ImageFormat.Gif) ;
    92        }


    9. WebForm1.aspx.cs文件中的InitializeComponent过程之后,添加下列代码,下列代码的作用是定义一个名称为GetColor函数,此函数的功能根据索引号得到相应的系统颜色:

     1/// <summary>
     2        /// 获取颜色
     3        /// </summary>
     4        /// <param name="itemIndex">数组的索引</param>
     5        /// <returns></returns>

     6        private Color GetColor ( int itemIndex ) 
     7        {
     8             Color MyColor ;
     9             int i = itemIndex ;
    10            switch (i) 
    11             {
    12                  case 0 :
    13                   MyColor = Color.Green;
    14                   return MyColor;
    15                  case 1 :
    16                   MyColor = Color.Red;
    17                    return MyColor;
    18                  case 2:
    19                   MyColor = Color.Yellow;
    20                   return MyColor;
    21                  case 3 :
    22                   MyColor = Color.Blue;
    23                   return MyColor;
    24                  case 4 :
    25                   MyColor = Color.Orange;
    26                   return MyColor;
    27                 case 5 :
    28                   MyColor = Color.Aqua;
    29                   return MyColor;
    30                  case 6:
    31                   MyColor = Color.SkyBlue;
    32                   return MyColor;
    33                  case 7:
    34                   MyColor = Color.DeepPink;
    35                   return MyColor;
    36                  case 8:
    37                   MyColor = Color.Azure;
    38                   return MyColor;
    39                  case 9:
    40                   MyColor = Color.Brown;
    41                   return MyColor;
    42                  case 10:
    43                   MyColor = Color.Pink;
    44                   return MyColor;
    45                  case 11:
    46                   MyColor = Color.BurlyWood;
    47                   return MyColor;
    48                  case 12:
    49                   MyColor = Color.Chartreuse;
    50                   return MyColor;
    51                  default:
    52                   MyColor = Color.Pink;
    53                   return MyColor;
    54            }

    55        }


    10. 至此,在上述步骤都正确执行后,在ASP.NET页面中实现数据Bar图的全部工作就完成了。在确定上面建立的Access数据库"db.mdb"位于C盘的根目录中之后,单击快捷键F5,就可以得到如图01所示的数据Bar图了。

      五.总结:

      在ASP.NET页面中实现各种图表,其所使用的就是ASP.NET的绘图功能,而这一功能是ASP.NET的前一个版本所不具备的。上面的这些介绍,不仅介绍了在ASP.NET绘制各种图片的方法,还介绍了数据库连接和从数据库中逐条读取记录的方法。这些方法对您了解和掌握在ASP.NET中操作数据库是非常有用的。

    完整的例子程序:

      1using System;
      2using System.Collections;
      3using System.ComponentModel;
      4using System.Data;
      5using System.Drawing;
      6using System.Web;
      7using System.Web.SessionState;
      8using System.Web.UI;
      9using System.Web.UI.WebControls;
     10using System.Web.UI.HtmlControls;
     11
     12//下面程序中使用的ImageFormat类所在的命名空间
     13using System.Drawing.Imaging;
     14//下面程序中使用到关于数据库方面的类所在的命名空间
     15using System.Data.OleDb;
     16
     17namespace WebBarDemo
     18{
     19    /// <summary>
     20    /// WebForm1 的摘要说明。
     21    /// </summary>

     22    public class WebForm1 : System.Web.UI.Page
     23    {
     24        private void Page_Load(object sender, System.EventArgs e)
     25        {
     26            // 在此处放置用户代码以初始化页面
     27
     28            string sRouter = "c://db2.mdb" ;
     29            //获得当前Access数据库在服务器端的绝对路径
     30
     31            string strCon = " Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " + sRouter ;
     32            //创建一个数据库连接
     33
     34            OleDbConnection myConn = new OleDbConnection ( strCon ) ;
     35            string strCom = " SELECT YF ,SL FROM MonthSale ORDER BY YF" ;
     36            myConn.Open ( ) ;
     37            OleDbCommand myCommand = new OleDbCommand ( strCom , myConn ) ;
     38            OleDbDataReader myOleDbDataReader = myCommand.ExecuteReader ( ) ;
     39            //创建OleDbDataReader实例,并以此实例来获取数据库中各条记录数据
     40
     41            int [ ] iXiaoSH = new int [ 12 ] ;
     42            //定义一个数组,用以存放从数据库中读取的销售数据
     43
     44            string [ ] sMoth = new string [ 12 ] ;
     45            //定义一个数组,用以存放从数据库中读取的销售月份
     46
     47            int iIndex = 0 ;
     48            while ( myOleDbDataReader.Read ( ) ) 
     49            {
     50                iXiaoSH [ iIndex ] = myOleDbDataReader.GetInt32 ( 1 ) ;
     51                sMoth [ iIndex ] = myOleDbDataReader.GetInt32 ( 0 ) . ToString ( ) + "" ;
     52                iIndex++ ;
     53            }

     54            //读取Table01数据表中的各条数据,并存放在先前定义的二个数组中
     55
     56            myConn . Close ( ) ;
     57            myOleDbDataReader . Close ( ) ;
     58            //关闭各种资源
     59
     60            Bitmap bm = new Bitmap ( 600 , 250 ) ;
     61            //创建一个长度为600,宽带为250的Bitmap实例
     62
     63            Graphics g ;
     64            g = Graphics.FromImage ( bm ) ;
     65            //由此Bitmap实例创建Graphic实例
     66
     67            g . Clear ( Color.Snow) ;
     68            //用Snow色彩为背景色填充此绘画图面
     69
     70            g . DrawString ( " ××公司××××年度销售情况统计表" , new Font ( "黑体" , 16 ) , Brushes . Black , new Point ( 5 , 5 ) ) ;
     71            //在绘画图面的指定位置,以指定的字体、指定的颜色绘制指定的字符串。即为图表标题
     72
     73            //以下代码是是实现图右上部
     74            Point myRec = new Point ( 535 , 30 ) ;
     75            Point myDec = new Point ( 560 , 26 ) ;
     76
     77            //以上是在图01中为下面绘制定位
     78            g . DrawString ( "单位:万套" , new Font ( "宋体" , 9 ) , Brushes . Black , new Point ( 525 , 12 ) ) ;
     79   
     80   
     81            for ( int i = 0 ; i < sMoth.Length ; i++ ) 
     82            {
     83                g . DrawRectangle ( Pens.Black , myRec . X , myRec . Y , 20 , 10 ) ;
     84                //绘制小方块
     85
     86                g . FillRectangle ( new SolidBrush ( GetColor ( i ) ) , myRec.X , myRec.Y , 20 , 10 ) ;
     87                //填充小方块
     88
     89                g . DrawString ( sMoth [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , myDec ) ;
     90                //绘制小方块右边的文字
     91
     92                myRec . Y += 15 ;
     93                myDec . Y += 15 ;
     94            }

     95
     96            //以下代码是绘制Bar图,及其销售数量
     97            int iBarWidth = 40 ;
     98            int scale = 10 ;
     99            for ( int i = 0 ; i < iXiaoSH . Length ; i++ ) 
    100            {
    101                g . DrawRectangle ( Pens.Black, ( i * iBarWidth ) + 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) + 5 ) ;
    102                //绘制Bar图
    103
    104                g . FillRectangle ( new SolidBrush (GetColor ( i )) , ( i * iBarWidth ) + 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) + 5 ) ;
    105                //以指定的色彩填充Bar图
    106
    107                g . DrawString ( iXiaoSH [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , ( i * iBarWidth ) + 20 , 235 - ( iXiaoSH [ i ] * scale ) ) ;
    108                //显示Bar图代表的数据
    109            }

    110
    111            //以下代码是绘制边框,并形成Jpeg文件,供浏览器显示出来
    112            Pen p = new Pen ( Color.Black , 2 ) ;
    113            g . DrawRectangle ( p , 1 , 1 , 598 , 248 ) ;
    114            bm.Save ( Response . OutputStream , ImageFormat.Gif) ;
    115        }

    116
    117        Web 窗体设计器生成的代码
    136        
    137        /// <summary>
    138        /// 获取颜色
    139        /// </summary>
    140        /// <param name="itemIndex">数组的索引</param>
    141        /// <returns></returns>

    142        private Color GetColor ( int itemIndex ) 
    143        {
    144             Color MyColor ;
    145             int i = itemIndex ;
    146            switch (i) 
    147             {
    148                  case 0 :
    149                   MyColor = Color.Green;
    150                   return MyColor;
    151                  case 1 :
    152                   MyColor = Color.Red;
    153                    return MyColor;
    154                  case 2:
    155                   MyColor = Color.Yellow;
    156                   return MyColor;
    157                  case 3 :
    158                   MyColor = Color.Blue;
    159                   return MyColor;
    160                  case 4 :
    161                   MyColor = Color.Orange;
    162                   return MyColor;
    163                 case 5 :
    164                   MyColor = Color.Aqua;
    165                   return MyColor;
    166                  case 6:
    167                   MyColor = Color.SkyBlue;
    168                   return MyColor;
    169                  case 7:
    170                   MyColor = Color.DeepPink;
    171                   return MyColor;
    172                  case 8:
    173                   MyColor = Color.Azure;
    174                   return MyColor;
    175                  case 9:
    176                   MyColor = Color.Brown;
    177                   return MyColor;
    178                  case 10:
    179                   MyColor = Color.Pink;
    180                   return MyColor;
    181                  case 11:
    182                   MyColor = Color.BurlyWood;
    183                   return MyColor;
    184                  case 12:
    185                   MyColor = Color.Chartreuse;
    186                   return MyColor;
    187                  default:
    188                   MyColor = Color.Pink;
    189                   return MyColor;
    190            }

    191        }

    192
    193    }

    194}

    195

     

    曲线图实现

    <%@ Import Namespace="System" %> 
    <%@ Import Namespace="System.Drawing" %> 
    <%@ Import Namespace="System.Drawing.Drawing2D" %> 
    <%@ Import Namespace="System.Drawing.Imaging" %> 

    <script language="C#" runat="server"> 

       class LineChart 
    {; 
    //Sample ASPX C# LineChart Class, Steve Hall, 2002 
    public Bitmap b; 
    public string Title="Default Title"; 
    public ArrayList chartvalues = new ArrayList(); 
    public float Xorigin=0, Yorigin=0; 
    public float ScaleX, ScaleY; 
    public float Xdivs=2, Ydivs=2; 

    private int Width, Height; 
    private Graphics g; 
    private Page p; 

    struct datapoint {; 
    public float x; 
    public float y; 
    public bool valid; 
    }; 

    //initialize 
    public LineChart(int myWidth, int myHeight, Page myPage) {; 
    Width = myWidth; Height = myHeight; 
    ScaleX = myWidth; ScaleY = myHeight; 
    b = new Bitmap(myWidth, myHeight); 
    g = Graphics.FromImage(b); 
    p = myPage; 
    }; 

    public void Addvalue(int x, int y) {; 
    datapoint myPoint; 
    myPoint.x=x; 
    myPoint.y=y; 
    myPoint.valid=true; 
    chartvalues.Add(myPoint); 
    }; 

    public void Draw() {; 
    int i; 
    float x, y, x0, y0; 
    string myLabel; 
    Pen blackPen = new Pen(Color.Black,1); 
    Brush blackBrush = new SolidBrush(Color.Black); 
    Font axesFont = new Font("arial",10); 

    //first establish working area 
    p.Response.ContentType="image/jpeg"; 
    g.FillRectangle(new 
    SolidBrush(Color.LightYellow),0,0,Width,Height); 
    int ChartInset = 50; 
    int ChartWidth = Width-(2*ChartInset); 
    int ChartHeight = Height-(2*ChartInset); 
    g.DrawRectangle(new 
    Pen(Color.Black,1),ChartInset,ChartInset,ChartWidth,ChartHeight); 

    //must draw all text items before doing the rotate below 
    g.DrawString(Title, new Font("arial",14), blackBrush, 
    Width/3, 10); 
    //draw X axis labels 
    for(i=0; i<=Xdivs; i++) {; 
    x=ChartInset+(i*ChartWidth)/Xdivs; 
    y=ChartHeight+ChartInset; 
    myLabel = (Xorigin + (ScaleX*i/Xdivs)).ToString(); 
    g.DrawString(myLabel, axesFont, blackBrush, x-4, 
    y+10); 
    g.DrawLine(blackPen, x, y+2, x, y-2); 
    }; 
    //draw Y axis labels 
    for(i=0; i<=Ydivs; i++) {; 
    x=ChartInset; 
    y=ChartHeight+ChartInset-(i*ChartHeight/Ydivs); 
    myLabel = (Yorigin + (ScaleY*i/Ydivs)).ToString(); 
    g.DrawString(myLabel, axesFont, blackBrush, 5, y-6); 
    g.DrawLine(blackPen, x+2, y, x-2, y); 
    }; 

    //transFORM drawing coords to lower-left (0,0) 
    g.RotateTransFORM(180); 
    g.TranslateTransFORM(0,-Height); 
    g.TranslateTransFORM(-ChartInset,ChartInset); 
    g.ScaleTransFORM(-1, 1); 

    //draw chart data 
    datapoint prevPoint = new datapoint(); 
    prevPoint.valid=false; 
    foreach(datapoint myPoint in chartvalues) {; 
    if(prevPoint.valid==true) {; 
    x0=ChartWidth*(prevPoint.x-Xorigin)/ScaleX; 
    y0=ChartHeight*(prevPoint.y-Yorigin)/ScaleY; 
    x=ChartWidth*(myPoint.x-Xorigin)/ScaleX; 
    y=ChartHeight*(myPoint.y-Yorigin)/ScaleY; 
    g.DrawLine(blackPen,x0,y0,x,y); 
    g.FillEllipse(blackBrush,x0-2,y0-2,4,4); 
    g.FillEllipse(blackBrush,x-2,y-2,4,4); 
    }; 
    prevPoint = myPoint; 
    }; 

    //finally send graphics to browser 
    b.Save(p.Response.OutputStream, ImageFORMat.Jpeg); 
    }; 

    ~LineChart() {; 
    g.Dispose(); 
    b.Dispose(); 
    }; 
    }; 


       void Page_Load(Object sender, EventArgs e) {; 
    LineChart c = new LineChart(640, 480, Page); 
    c.Title="My Line Chart"; 
    c.Xorigin=0; c.ScaleX=500; c.Xdivs=5; 
    c.Yorigin=0; c.ScaleY=1000; c.Ydivs=5; 
    c.Addvalue(50,50); 
    c.Addvalue(100,100); 
    c.Addvalue(200,150); 
    c.Addvalue(450,450); 
    c.Draw(); 
    }; 

    </script> 
    <%@ Import Namespace="System" %> 
    <%@ Import Namespace="System.Drawing" %> 
    <%@ Import Namespace="System.Drawing.Drawing2D" %> 
    <%@ Import Namespace="System.Drawing.Imaging" %> 

    <script language="C#" runat="server"> 

       class LineChart 
    {; 
    //Sample ASPX C# LineChart Class, Steve Hall, 2002 
    public Bitmap b; 
    public string Title="Default Title"; 
    public ArrayList chartvalues = new ArrayList(); 
    public float Xorigin=0, Yorigin=0; 
    public float ScaleX, ScaleY; 
    public float Xdivs=2, Ydivs=2; 

    private int Width, Height; 
    private Graphics g; 
    private Page p; 

    struct datapoint {; 
    public float x; 
    public float y; 
    public bool valid; 
    }; 

    //initialize 
    public LineChart(int myWidth, int myHeight, Page myPage) {; 
    Width = myWidth; Height = myHeight; 
    ScaleX = myWidth; ScaleY = myHeight; 
    b = new Bitmap(myWidth, myHeight); 
    g = Graphics.FromImage(b); 
    p = myPage; 
    }; 

    public void Addvalue(int x, int y) {; 
    datapoint myPoint; 
    myPoint.x=x; 
    myPoint.y=y; 
    myPoint.valid=true; 
    chartvalues.Add(myPoint); 
    }; 

    public void Draw() {; 
    int i; 
    float x, y, x0, y0; 
    string myLabel; 
    Pen blackPen = new Pen(Color.Black,1); 
    Brush blackBrush = new SolidBrush(Color.Black); 
    Font axesFont = new Font("arial",10); 

    //first establish working area 
    p.Response.ContentType="image/jpeg"; 
    g.FillRectangle(new 
    SolidBrush(Color.LightYellow),0,0,Width,Height); 
    int ChartInset = 50; 
    int ChartWidth = Width-(2*ChartInset); 
    int ChartHeight = Height-(2*ChartInset); 
    g.DrawRectangle(new 
    Pen(Color.Black,1),ChartInset,ChartInset,ChartWidth,ChartHeight); 

    //must draw all text items before doing the rotate below 
    g.DrawString(Title, new Font("arial",14), blackBrush, 
    Width/3, 10); 
    //draw X axis labels 
    for(i=0; i<=Xdivs; i++) {; 
    x=ChartInset+(i*ChartWidth)/Xdivs; 
    y=ChartHeight+ChartInset; 
    myLabel = (Xorigin + (ScaleX*i/Xdivs)).ToString(); 
    g.DrawString(myLabel, axesFont, blackBrush, x-4, 
    y+10); 
    g.DrawLine(blackPen, x, y+2, x, y-2); 
    }; 
    //draw Y axis labels 
    for(i=0; i<=Ydivs; i++) {; 
    x=ChartInset; 
    y=ChartHeight+ChartInset-(i*ChartHeight/Ydivs); 
    myLabel = (Yorigin + (ScaleY*i/Ydivs)).ToString(); 
    g.DrawString(myLabel, axesFont, blackBrush, 5, y-6); 
    g.DrawLine(blackPen, x+2, y, x-2, y); 
    }; 

    //transFORM drawing coords to lower-left (0,0) 
    g.RotateTransFORM(180); 
    g.TranslateTransFORM(0,-Height); 
    g.TranslateTransFORM(-ChartInset,ChartInset); 
    g.ScaleTransFORM(-1, 1); 

    //draw chart data 
    datapoint prevPoint = new datapoint(); 
    prevPoint.valid=false; 
    foreach(datapoint myPoint in chartvalues) {; 
    if(prevPoint.valid==true) {; 
    x0=ChartWidth*(prevPoint.x-Xorigin)/ScaleX; 
    y0=ChartHeight*(prevPoint.y-Yorigin)/ScaleY; 
    x=ChartWidth*(myPoint.x-Xorigin)/ScaleX; 
    y=ChartHeight*(myPoint.y-Yorigin)/ScaleY; 
    g.DrawLine(blackPen,x0,y0,x,y); 
    g.FillEllipse(blackBrush,x0-2,y0-2,4,4); 
    g.FillEllipse(blackBrush,x-2,y-2,4,4); 
    }; 
    prevPoint = myPoint; 
    }; 

    //finally send graphics to browser 
    b.Save(p.Response.OutputStream, ImageFORMat.Jpeg); 
    }; 

    ~LineChart() {; 
    g.Dispose(); 
    b.Dispose(); 
    }; 
    }; 


       void Page_Load(Object sender, EventArgs e) {; 
    LineChart c = new LineChart(640, 480, Page); 
    c.Title="My Line Chart"; 
    c.Xorigin=0; c.ScaleX=500; c.Xdivs=5; 
    c.Yorigin=0; c.ScaleY=1000; c.Ydivs=5; 
    c.Addvalue(50,50); 
    c.Addvalue(100,100); 
    c.Addvalue(200,150); 
    c.Addvalue(450,450); 
    c.Draw(); 
    }; 

    </script> 


    Microsoft Office Web Components

    Microsoft Office Web Components 包含在 Microsoft Office 2000 中。它们是用于向 Web 页添加电子表格、图表和数据处理功能的 ActiveX 控件的集合。可以直接在浏览器中处理数据,并以图表的形式显示数据。由于其基于Office的强大功能,以及与Office相同的用户界面,无疑是ASP.NET中图表生成的明智选择。
    本章主要包括以下几个方面内容:
    ● 基于GDI+的图表生成。
    ● 基于Office Web Components的图表生成。
    ● 基于Office Web Components的报表生成。
    经过本章的学习,将掌握ASP.NET中统计图表的实现,利用图表将网站的数据完美呈现给用户。
    方案设计
    本节分别介绍GDI+与Office Web Components的具体使用,为后面的章节打下基础。
    使用GDI+
    GDI+ 是 GDI(Windows XP之前版本提供的图形设备接口)的后续版本。GDI+ 是一种应用程序编程接口 (API),负责在屏幕和打印机上显示信息。
    在ASP.NET中,利用GDI+可以创建简单的柱状图和饼图。
    ASP.NET页面GDI+图像使用
    在完整的生成柱状图和饼图之前,先从简单的ASP.NET页面图像使用开始。
    在System.Draw命名空间中包含了创建、编辑图像的所有类。创建图像时,主要使用Bitmap类和Graphics类。为了便于理解,可以把Bitmap类想象成画板,Graphics类想象成画笔。Bitmap类主要用于创建画板以及在完成后图像的保存。Graphics类主要用来绘制图像、图形和线条。
    首先使用下面的代码创建画板。(本小节所有代码需要添加System.Drawing命名空间与System.Drawing.Image命名空间)
    Bitmap myPalette = new Bitmap(600, 400); //创建600*400的画板
    有了画板,还需要创建Graphics类的实例来创建画笔,指定画板。代码如下
    Graphics myGraphics = Graphics.FromImage(myPalette);
    有了画笔和画板,只要使用Graphics类中的各种方法在画板上绘制图像、图形和线条就可以了。
    Graphics类中的方法分为两类:绘制方法与填充方法。例如,DrawRectangle方法与FillRectangle方法。绘制方法仅仅绘制出图形的轮廓,而填充方法绘制出图形的轮廓同时填充图形的内部。
    下面的代码绘制了简单的图形:
    int width=150,height=50;
    // 创建黑色背景椭圆
    myGraphics.FillEllipse(new SolidBrush(Color.Black), 300, 150, width, height);
    // 创建蓝色背景椭圆
    myGraphics.FillEllipse(new SolidBrush(Color.LightBlue), 300, 150, width - 10, height - 10);
    // 创建输出文本
    string textOut = "ASP.NET";
    //指定字体
    Font fontOut = new Font("Times New Roman", 16, FontStyle.Bold|FontStyle.Italic);
    //指定文本居中
    StringFormat stringFormat = new StringFormat();
    stringFormat.Alignment = StringAlignment.Center;
    stringFormat.LineAlignment = StringAlignment.Center;
    // 绘制文本
    myGraphics.DrawString(textOut,fontOut,new SolidBrush(Color.Black),new Rectangle(0,0,width,height),stringFormat);
    图已经画好了,只剩下将图保存下来。要将保存的图在网页中显示,可以在下面两种方式中任选其一:
    ● 将图像保存在服务器的文件系统中,使用HTML的<img>标记来显示。
    ● 直接将图像的二进制流输出到Response对象的输出流。
    两种方式各有千秋。第一种方式适合于创建不需要变动的图片(例如网站广告图片),能够创建一次,满足今后的所有要求。但会在服务器端保留下临时文件。第二种方式适用于动态的创建图片供页面显示,不能满足今后的需要,却也不会留下临时文件。
    下面分别写出这两种方式的代码:
    ● 保存文件方式代码:
    保存文件方式首先需要在Aspx文件中添加<Img>标记
    <!-- 指定显示文件为tmpFile.jpg -->
    <img src = “tmpFile.jpg”>
    然后在代码中保存文件即可:
    //将文件保存为当前页面所在目录下的tmpFile.jpg
    myPalette.Save(Server.MapPath("")+@"/tmpFile.jpg",ImageFormat.Jpeg);
    ● 直接输出方式代码:
    //直接将图片以二进制流的方式输出到Response对象的输出流。
    myPalette.Save(Response.OutputStream, ImageFormat.Jpeg);
    将代码加入页面的PageLoad事件中即可得到如图18-1效果。
          
           图18-1 GDI+图像使用效果
    创建柱状图
    在知道了如何使用GDI+创建简单图像并显示到页面后,创建复杂一些的柱状图就非常自然了。
    使用简单的FillRectangle,DrawRectangle,DrawString方法,即可实现基本的柱状图。代码如下:
    //初始化Bitmap类实例与Graphics类实例准备画图
    const int width = 600, height = 400;
    Bitmap myPalette = new Bitmap(width,height);
    Graphics myGraphics = Graphics.FromImage(myPalette);
    // 绘制白色背景
    myGraphics.FillRectangle(new SolidBrush(Color.White), 0, 0, width, height);
    // 设定显示数据
    string [] DataName = {"Jan","Feb","Mar","Apr","May","Jun"};
    int [] Data = {100,20,50,60,240,20};
    //设定显示颜色
    Color [] myColors = {
    Color.Blue,
    Color.Red,
    Color.Yellow,
    Color.Purple,
    Color.Orange,
    Color.Brown
    };
    //绘制柱图
    for(int i = 0;i<DataName.Length;i++)
    {
    //填充柱图
    myGraphics.FillRectangle(new SolidBrush(myColors[i]),(i*40)+30,300 - Data[i],20,Data[i]+5);
    //绘制柱图边界
    myGraphics.DrawRectangle(new Pen(Color.Black),(i*40)+30,300 - Data[i],20,Data[i]+5);
    //绘制柱图上方数据
    myGraphics.DrawString(Data[i].ToString(), new Font("宋体", 9), Brushes.Black, new PointF((i*40)+30,300-Data[i]-20));
    //绘制柱图下标
    myGraphics.DrawString(DataName[i], new Font("宋体", 9), Brushes.Black, new PointF((i*40)+30,320));
    }
    //输出图像
    myPalette.Save(Response.OutputStream, ImageFormat.Jpeg);
    // 清除所用绘图对象
    myGraphics.Dispose();
    myPalette.Dispose();
    将上述代码写入页面CodeBehind文件的PageLoad事件中即可看到如图18-2效果:
           
              图18-2 GDI+柱状图效果
    使用Office Web Components
    Office Web Components是用于向 Web 页添加电子表格、图表和数据处理功能的 ActiveX控件的集合。
    利用Office Web Components可以方便的来绘制简单的柱状图与饼图。不必像在GDI+中需要考虑画图的细节。
    使用Office Web Components要求
    使用Office Web Components需要系统中装有Office2000以上版本。在工程的引用中添加Office Web Components即可。
    具体步骤如下:
    在解决方案资源管理器的引用文件夹上单击鼠标右键选择添加引用,在出现的添加引用对话框中选择COM标签,选择Microsoft Office Web Components,双击选中,点击确定即可。图18-3、18-4显示了该过程。
           
                图18-3 添加引用           图18-4 添加Office Web Components引用

    使用Office Web Components绘制柱状图
    使用Office Web Components绘制图表不同于直接使用GDI+,主要的工作从绘图的细节转移到对于图表的设置。步骤如下:
    ● Step1 创建ChartSpace对象来放置图表
    ChartSpace是用来放置图表的类,图表完成后用它来输出。
    OWC.ChartSpace objCSpace = new OWC.ChartSpaceClass ();
    ● Step2 使用ChartSpace对象的Add方法创建图表
    ChartSpace的Add方法创建图表,参数表示所创建图表的索引。
    OWC.WCChart objChart = objCSpace.Charts.Add (0);
    ● Step3 指定图表的类型
    通过设定Chart类对象的Type属性来指定图表的类型。
    objChart.Type = OWC.ChartChartTypeEnum.chChartTypeColumnClustered;
    本例创建柱状图,选择了chChartTypeColunmClustered类型。
    其他的类型包括:chChartTypeArea 面积图、chChartTypeBarClustered 条形图、chChartTypePie 饼图、chChartType RadarLine 雷达线图、chChartTypeSmoothLine 平滑曲线图、chChartTypeDoughnut 环形图等等。
    图18-5至18-10显示了部分图表的简单实例。
           
             图18-5 曲线图          图18-6 条形图          图18-7 面积图
           
             图18-8 环形图           图18-9 饼图          图18-10 雷达图
    ● Step4 设定图示说明
    图示说明主要包括图例(用颜色表示数据类型)、图题(图表的标题)、XY轴的数据说明(一般用来说明各轴上的数据单位)。设定代码如下:
    //指定图表是否需要图例
    objChart.HasLegend = true;

    //给定标题
    objChart.HasTitle = true;
    objChart.Title.Caption= "上半年月收入图";

    //给定x,y轴的图示说明
    objChart.Axes[0].HasTitle = true;
    objChart.Axes[0].Title.Caption = "万元";
    objChart.Axes[1].HasTitle = true;
    objChart.Axes[1].Title.Caption = "月份";
    ● Step5 添加数据
    添加数据主要设定Chart类对象的SeriesCollection属性。首先使用SeriesCollection的Add方法创建一组数据。然后使用SetData方法具体添加数据。代码如下:
    (注意:数据的格式是以'/t'间隔的字符串)
    //添加一组图表数据
    objChart.SeriesCollection.Add(0);
    //给定该组数据的名字
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimSeriesNames,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,”上半年收入”);
    //给定数据分类
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimCategories,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,
    "Jan"+'/t'+"Feb"+'/t'+"Mar"+'/t'+"Apr"+'/t'+"May"+'/t'+"Jun"+'/t' );
    //给定数据值
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimValues,
    (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,
    "100"+'/t'+"20"+'/t'+"50"+'/t'+"60"+'/t'+"240"+'/t'+"20"+'/t');
    ● Step6 显示数据
    显示数据是使用Chart类对象的ExportPicture方法将生成的图表创建为图片,然后显示的。代码如下:
    //输出成GIF文件,参数为文件名、格式、图片大小
    objCSpace.ExportPicture(Server.MapPath("")+@"/tmpFile.gif", "GIF", 400, 300);
    //从生成的图片创建Bitmap对象,输出到Response输出流
    Bitmap myPalette = new Bitmap(Server.MapPath("")+@"/tmpFile.gif",true);
    myPalette.Save(Response.OutputStream,System.Drawing.Imaging.ImageFormat.Gif);
    经过了以上的步骤,将代码输入页面的PageLoad事件代码段中,运行程序就可以得到如图18-11效果。
            
            图18-11 Office Web Components柱状图示例
    使用Office Web Components绘制饼图
    绘制饼图与绘制柱状图的区别不是很大,需要注意的是饼图没有XY轴,所以不能设置XY轴的图示说明。在绘制柱状图的代码上去掉关于XY轴图示说明的代码即可。
    完整代码如下:
    //初始化图表数据
    string [] DataName = {"Jan","Feb","Mar","Apr","May","Jun"};
    int [] Data = {100,20,50,60,240,20};
    //声明存储数据分类和数据值的字符串
    string strDataName = "";
    string strData = "";
    //循环按格式生成存储数据分类与数据值的字符串
    for(int i=0;i< Data.Length;i++)
    {
    strCategory += DataName[i]+'/t';
    strValue += Data[i].ToString()+'/t';
    }
    //创建ChartSpace对象来放置图表
    OWC.ChartSpace objCSpace = new OWC.ChartSpaceClass ();

    //在ChartSpace对象中添加图表,Add方法返回chart对象
    OWC.WCChart objChart = objCSpace.Charts.Add (0);

    //指定图表的类型为饼图
    objChart.Type = OWC.ChartChartTypeEnum.chChartTypePie;
    //指定图表是否需要图例
    objChart.HasLegend = true;
    //给定标题
    objChart.HasTitle = true;
    objChart.Title.Caption= "上半年月收入图";

    //添加一个series
    objChart.SeriesCollection.Add(0);

    //给定数据分类
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimCategories,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,strDataName);

    //给定数据值
    objChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimValues,
    (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral,strData);
    //输出成GIF文件.
    objCSpace.ExportPicture(Server.MapPath("")+@"/tmpFile.gif", "GIF", 400, 300);
    Bitmap myPalette = new Bitmap(Server.MapPath("")+@"/tmpFile.gif",true);
    myPalette.Save(Response.OutputStream,System.Drawing.Imaging.ImageFormat.Gif);
    将上述代码写入页面文件的PageLoad事件处理代码中,运行得到如图18-12效果。
             
            图18-12 Office Web Components饼图示例
    公司盈利状况统计
    前面介绍了Office Web Components的情况,本节将通过公司盈利状况统计来介绍Office Web Components柱状图在具体实例中的使用。
    数据库设计
    为了实现公司盈利状况统计。首先,需要设计相关的数据库表。在实际情况中,公司的盈利就是收入的总和与支出的总和之差。而每笔收入与支出都是在一次交易中完成的。基于以上考虑,同时为了实现简单。设计数据库表单如下:
    表名 T_Deal 别名 交易表
    表项      说明   类型     是否可空
    DealTime   交易时间  DateTime     否
    DealIncome  交易金额  int       否
    DealContent  交易内容  Varchar(50)   否
    DealObject  交易对象  Varchar(20)   是
    Comment    备注    Varchar(50)   是
    注意:为了简单起见,用交易金额统一表示收入与支出。用正数的交易金额表示收入,负数的交易金额表示支出。这样计算盈利时只需将交易金额求和即可。
    按照上表的格式在SqlServer中创建表。添加样例数据供程序使用。
    然后创建下面的存储过程来实现公司盈利状况的统计。
    CREATE PROCEDURE sp_SelectIncome
    @year int
    AS

    Select sum(DealCount),Datepart(mm,DealTime) From T_Deal
    where DATEPART(yy,DealTime)=@year
    Group By Datepart(mm,DealTime)
    GO
    该存储过程选择交易时间的年份与输入参数@year相等的数据,并将选择得到的数据按交易时间的月份分组。返回每组交易金额的总和以及该组的交易月份。
    界面设计
    新建Web工程WebChart。将WebForm1.aspx改名为OWCChart.aspx。同时,将其代码文件中的类名改为OWCChart。
    界面如图18-13所示:
          
              图18-13 公司盈利统计界面
    该界面主要包括两部分:一个PlaceHolder控件用来放置生成的图表构成显示图表部分。一个用来选择统计年份的DropDownList控件,一个用来确定生成图表的Button控件,一个用来显示错误信息的Label控件构成了图表的生成部分。
    同样为了界面整洁使用Table将所用控件放在表格中。按照图18-13安排好界面后就可以为控件设置属性了,主要包括以下几个方面的设置:
    ● PlaceHolder控件的设置
    PlaceHolder控件在本程序中用于放置生成的图表,只需设置其Id属性为ChartPlaceHolder即可。
    ● DropDownList控件的设置
    DropDownList控件在本程序中用于选择统计年份,设置其Id属性为ddlYear。并为其添加ListItem 2000,2001,2002,2003。
    <asp:ListItem Value="2000">2000</asp:ListItem>
    <asp:ListItem Value="2001">2001</asp:ListItem>
    <asp:ListItem Value="2002">2002</asp:ListItem>
    <asp:ListItem Value="2003">2003</asp:ListItem>
    ● Button控件的设置
    Button控件设置Id属性为btnSumbit,Text属性为“确定”即可。
    ● Label控件的设置
    Label控件设置Id属性为Info即可。
    代码实现
    在完成了上面的界面设计后,就要进入后台代码的编写了。下面就将分模块介绍各部分功能的代码实现。
    数据读入
    为了显示公司盈利状况统计,首先需要将统计的结果从数据库中读入。读入数据的代码包括以下两部分。
    ● 创建数据库联接
    为了方便程序的配置,将数据库联接字段保存在Web.Config文件中。如此一来,在需要修改数据库联接字段时只需要修改Web.Config文件即可,不需要修改程序代码,重新编译。
    在Web.Config文件中的<configuration>字段中加入如下代码:
    <appSettings>
    <add key="ConnectStr"
    value="server=localhost;uid=yourid;pwd=yourpas;database=Info;"/>
    </appSettings>
    其中localhost要改为自己的数据库服务器名,uid,pwd分别为数据库用户id和密码,database为数据库名。
    设置好联接字段后就可在代码中对其进行引用了。
    主要使用AppSettingReader对象的GetValue方法获取”ConnectStr”字段信息,该方法需要两个参数,第一个指定要引用的字段,第二个参数指定需要的类型。返回一个Object类型的变量。需要使用Convert的ToString方法将其转换为字符串类型
    引用代码如下:
    //全局数据库联接
    System.Data.SqlClient.SqlConnection MyConnection;
    private void Page_Load(object sender, System.EventArgs e)
    {
    // 在此处放置用户代码以初始化页面
    if(Page.IsPostBack==false) // 页面首次加载时
    {

    //创建Web.Config文件应用程序设置字段读取对象
    System.Configuration.AppSettingsReader ConnectionString = new System.Configuration.AppSettingsReader();
    //创建数据库联接
    MyConnection = new System.Data.SqlClient.SqlConnection();
    //设置数据库联接的连接字段
    MyConnection.ConnectionString = Convert.ToString(ConnectionString.GetValue("ConnectStr",System.Type.GetType("System.String")));
    }
    }
    ● 利用数据库联接读取数据
    有了前面创建的数据库联接就可以从数据库中读取数据了。
    读取数据代码如下:
    //读取数据函数,参数为需要统计的年份,返回DataSet
    DataSet ReadData(string Year)
    {
    //创建DataSet
    DataSet dsIncome = new DataSet();
    //设置存储过程名
    string SpName = "sp_SelectIncome";
    //创建Sql命令
    SqlCommand IncomeCmd = new SqlCommand(SpName,MyConnection);
    //设定数据库命令类型为存储过程
    IncomeCmd.CommandType = CommandType.StoredProcedure;
    //打开数据库联接
    MyConnection.Open();
    //创建并设定存储过程参数
    SqlParameter IncomeYear = new SqlParameter("@year",SqlDbType.Int,4);
    IncomeYear.Value=Convert.ToInt16(Year);
    //为Sql命令添加参数
    IncomeCmd.Parameters.Add(IncomeYear);
    //创建Sql数据桥接器
    SqlDataAdapter adapter = new SqlDataAdapter(SpName,MyConnection);
    //指定桥接器Sql命令
    adapter.SelectCommand = IncomeCmd;
    //填充DataSet
    adapter.Fill(dsIncome,"Income");
    //关闭数据库联接
    MyConnection.Close();
    }
    数据显示
    使用ReadData方法读出数据,接下来就是显示数据了。显示数据同样需要两个步骤。
    ● 处理数据库读出的数据
    由于从数据库读出的数据不能完全满足显示的要求,有可能某个月份没有交易,那么返回的DataSet中就不会包含该月的数据。但显示时需要所有月份的数据。所以直接显示数据之前先要对数据进行加工。代码如下:
    //创建存储数据的数组,MyMonthIncome存放每月数据,MyMonthName存放月份缩写
    int[] MyMonthIncome = new int[12];
    string[] MyMonthName = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};

    //声明存放显示用字符串的变量,strMonthName存放月份信息,strMonthIncome存放数据
    string strMonthName = "";
    string strMonthIncome = "";
    //对存在数据的月份将数据保存在MyMonthName
    for(int i=0;i< dsIncome.Tables["Income"].Rows.Count;i++)
    {
    MyMonthIncome[Convert.ToInt16(dsIncome.Tables["Income"].Rows[i][1])-1] = Convert.ToInt16(dsIncome.Tables["Income"].Rows[i][0]);
    }
    //用已有的数据来生成图表显示所需的字符串
    for(int i=0;i< 12;i++)
    {
    strMonthName += MyMonthName[i]+'/t';
    strMonthIncome += MyMonthIncome[i].ToString()+'/t';
    }
    ● 使用Office Web Components显示数据
    经过上一步骤,图表显示所需的字符串已经放入了strMonthName和strMonthIncome中,下面使用18.2节中关于Office Web Components的知识就可以大功告成了。需要注意的是在生成图片后使用了PlaceHolder的.Controls属性的Add方法将动态生成的<img>标签放入页面。为了方便后面的使用,将显示数据的代码写为函数。代码如下:
    private void MakeLineChart(string Year)
    {
    //使用ReadData函数读出数据
    DataSet dsIncome = ReadData(Year);
    //以下插入处理数据库读出的数据部分的代码,不再重复
    //….上一步骤中处理数据库读出数据代码

    //创建ChartSpace对象来放置图表
    OWC.ChartSpace mySpace = new OWC.ChartSpaceClass ();
    //在ChartSpace对象中添加图表,Add方法返回chart对象
    OWC.WCChart myChart = mySpace.Charts.Add (0);

    //指定图表的类型为线性图
    myChart.Type = OWC.ChartChartTypeEnum.chChartTypeLine;
    //指定图表是否需要图例
    myChart.HasLegend = true;
    //给定标题
    myChart.HasTitle = true;
    myChart.Title.Caption= ddlYear.SelectedItem.Text + "月收入图";
    //给定x,y轴的图示说明
    myChart.Axes[0].HasTitle = true;
    myChart.Axes[0].Title.Caption = "万元";
    myChart.Axes[1].HasTitle = true;
    myChart.Axes[1].Title.Caption = "月份";
    //添加一个series
    myChart.SeriesCollection.Add(0);
    //给定series的名字
    myChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimSeriesNames,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strSeriesName);
    //给定分类
    myChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimCategories,
    + (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strCategory);
    //给定值
    myChart.SeriesCollection[0].SetData (OWC.ChartDimensionsEnum.chDimValues,
    (int)OWC.ChartSpecialDataSourcesEnum.chDataLiteral, strValue);
    //输出成GIF文件.
    string strAbsolutePath = (Server.MapPath(".")) + @"/images/tempFile.gif";
    mySpace.ExportPicture(strAbsolutePath, "GIF", 700, 350);
    //创建GIF文件的相对路径.
    string strRelativePath = "./images/tempFile.gif”
    //生成显示图片的<img>标签
    string strImageTag = "<IMG SRC='" + strRelativePath + "'/>";
    //把图片添加到placeholder.
    ChartPlaceHolder.Controls.Add(new LiteralControl(strImageTag));
    18.3.3.3 按钮点击事件
    有了前面的MakeLineChart函数,在aspx页面的设计模式下双击btnSumbit创建按钮点击事件。修改代码如下:
    private void btnSubmit_Click(object sender, System.EventArgs e)
    {
    MakeLineChart(ddlYear.SelectedItem.Text);
    }
    至此,公司盈利状况统计功能完全实现,运行结果如图18-16:
            
             图18-16 公司盈利状况统计效果
    公司收入分块图
    上一节介绍了Office Web Components的柱状图的使用,实现了对公司盈利状况统计。本节将通过公司收入分块图的实现来介绍Office Web Components中饼装图的使用。
    数据库设计
    为了实现公司收入分块图,为T_Deal表增添交易类别字段。扩充后的T_Deal表如下:
    表名 T_Deal 别名 交易表
    表项      说明   类型     是否可空
    DealTime   交易时间  DateTime     否
    DealIncome  交易金额  int       否
    DealContent  交易内容  Varchar(50)   否
    DealObject  交易对象  Varchar(20)   是
    DealCategory 交易类别  Varchar(20)   否
    Comment     备注   Varchar(50)   是
    按照新表的格式重新在SqlServer中创建表。添加样例数据供程序使用。并且创建如下存储过程实现公司收入分块统计。
    CREATE PROCEDURE sp_SelectCategory
    @year int
    AS

    Select sum(DealCount),DealCategory From T_Deal
    where DATEPART(yy,DealTime)=@year
    Group By DealCategory
    GO
    该存储过程选择交易时间的年份与输入参数@year相等的数据,并将选择得到的数据按交易类别分组。返回每组交易金额的总和以及该组的交易类别。
    界面设计
    为了简便同时利用已有成果,在现有的基础上修改无疑是最好的选择。因此,本节的程序直接在上一节的程序上修改。在原有界面上添加一个DropDownList来选择不同的图表内容。新的界面如图18-17:
          
             图18-17 公司收入分布界面
    新增的DropDownList属性设置为Id=ddlChartType,并为其添加Item
    <asp:ListItem Value="Income">公司盈利状况</asp:ListItem>
    <asp:ListItem Value="Category">公司收入分块图</asp:ListItem>
    代码实现
    在完成了上面的界面设计后,就要进入后台代码的编写了。由于是在上一节的基础上,所以只需增加新功能。
    数据读入
    由于已经有了创建数据库联接部分,下面只需要读出数据即可。数据读入部分代码与上一节的代码相似,不同之处只是所调用的存储过程不同,为了简化代码,修改ReadData函数,为其增加参数SpName 指定调用的存储过程。将原有程序中声明SpName的语句删除即可。
    //读取数据函数,参数Yesr为需要统计的年份SpName为调用存储过程名,返回DataSet
    DataSet ReadData(string Year,string SpName)
    {
    //创建DataSet
    DataSet dsIncome = new DataSet();
    //设置存储过程名,通过新增参数完成,将此句去除
    //string SpName = "sp_SelectIncome";
    //以下部分不做修改,不再重复

    }
    注意:修改ReadData函数后,在上一节MakeLineChart函数中调用ReadData的代码需要为其增加参数。
    private void MakeLineChart(string Year)
    {
    //使用ReadData函数读出数据
    DataSet dsIncome = ReadData(Year,“sp_SelectIncome”);
    //以下部分不做修改

    }
    数据显示
    使用ReadData方法读出数据,接下来就是显示数据了。显示数据的代码也只需对上一节代码做部分修改即可。声明绘制分类收入的函数,将MakeLineChart函数内容复制并修改如下:
    private void MakePieChart(string Year)
    {
    //使用ReadData函数读出数据
    DataSet dsCategory = ReadData(Year);
    //创建存储数据的数组,MyCategory存放类别数据,MyMonthName存放类别名称
    int[] MyCategory = new int[dsIncome.Tables["Income"].Rows.Count];
    string[] MyCategoryName = new string[dsIncome.Tables["Income"].Rows.Count];

    //声明存放显示用字符串的变量,strMonthName存放月份信息,strMonthIncome存放数据
    string strCategoryName = "";
    string strCategory = "";
    //声明总收入,用来计算各分类收入百分比
    int IncomeSum = 0;
    //将数据放入数组,同时计算总收入
    for(int i=0;i< dsIncome.Tables["Income"].Rows.Count;i++)
    {
    MyCategory[i] = Convert.ToInt16(dsIncome.Tables["Income"].Rows[i][0]);
    MyCategoryName[i] = Convert.ToString(dsIncome.Tables["Income"].Rows[i][1]);
    IncomeSum += MyCategory[i];
    }
    //用已有的数据来生成图表显示所需的字符串
    for(int i=0;i< dsIncome.Tables["Income"].Rows.Count;i++)
    {
    //计算出各分类所占百分比
    int PercentCategory= 100*MyCategory[i]/IncomeSum;
    strCategory += MyCategoryName[i]+" "+PercentCategory.ToString()+ "%"+'/t';
    strValue += MyCategory[i].ToString()+'/t';
    }
    //下面代码与上一节基本相同不再重复
    //仅给出需要修改的部分

    //指定图表的类型为线性图 改为饼图
    myChart.Type = OWC.ChartChartTypeEnum.chChartTypePie;
    //指定图表是否需要图例
    myChart.HasLegend = true;
    //给定标题
    myChart.HasTitle = true;
    myChart.Title.Caption= ddlYear.SelectedItem.Text + "收入图";
    //给定x,y轴的图示说明 ,去掉XY轴图示说明部分
    /*
    myChart.Axes[0].HasTitle = true;
    myChart.Axes[0].Title.Caption = "万元";
    myChart.Axes[1].HasTitle = true;
    myChart.Axes[1].Title.Caption = "月份";
    */

    }
    18.3.3.3 按钮点击事件
    由于增加了新功能,按钮点击的代码修改如下:
    private void btnSubmit_Click(object sender, System.EventArgs e)
    {
    //根据ddlChartType的选项判断执行的内容
    if(ddlChartType.SelectedItem.Value=="Income")
    MakeLineChart(ddlYear.SelectedItem.Text); //显示公司盈利统计
    else if(ddlChartType.SelectedItem.Value=="Category")
    MakePieChart(ddlYear.SelectedItem.Text);//显示收入分布
    }
    至此,公司盈利状况统计功能完全实现,运行后选择收入分布点击确定按钮。结果如图18-18:
           
            图18-18 公司收入分块图效果
    报表产出
    前面的几个小节完成了对数据的统计并以图表的形式呈现给用户,使用户能够一目了然的获取所需信息。这一节将把统计结果以Excel报表的形式输出,以免用户提交报表时手工输入的麻烦,提高工作效率。
    报表产出主要使用了Office Web Components的Spreadsheet控件。利用该控件创建并编辑数据表格,并将最终结果输出到Excel报表。步骤如下:
    ● Step1创建SpreadsheetClass对象,用来放置数据表格
    类似于Chart控件中的ChartSpace,Spread控件中也需要创建一个放置SpreadsheetClass的对象作为单个表的容器。
    SpreadsheetClass exl = new SpreadsheetClass();
    ● Step2利用SpreadsheetClass的ActiveSheet获得当前处于活动状态的表格
    一个SpreadsheetClass对象就相当于一个运行中的Excel,通过其ActiveSheet属性能够得到当前处于活动状态的表格。一个Worksheet对象就相当于Excel中的一张表格。将SpreadsheetClass对象的ActiveSheet属性赋值给Worksheet对象。就可以在后面的代码中对表格进行操作了。
    OWC.Worksheet ws = exl.ActiveSheet;
    ● Step3 编辑表格
    编辑表格使用的是Worksheet对象的Cells属性。Cells属性就代表着表格中的每个单元格。使用Cells[row,col]的格式引用,row表示行号,col表示列号。需要注意的是行号和列号都是从1开始的,而不是像C#的数组是从0开始。例如Cells[2,2]就表示表格的第二行,第二列的单元格。下面是产生盈利状况统计报表的编辑表格代码(该段代码添加在MakePieChart函数末尾,其中的变量延用之前的声明):
    //为表格设定标题
    ws.Cells[1, 1] = "收入(万元)";
    ws.Cells[1,2] = "类别";
    ws.Cells[1,3] = "所占比重";
    //将数据写入表格
    for(int i=0;i<dsIncome.Tables[0].Rows.Count;i++)
    {
    ws.Cells[i+2,1] = MyCategory[i].ToString();
    ws.Cells[i+2,2] = MyCategoryName[i];
    int Percent = MyMonthIncome[i]*100/IncomeSum;
    ws.Cells[i+2,3] = Percent.ToString() + "%";
    }
    //将总收入写入表格
    ws.Cells[dsIncome.Tables[0].Rows.Count + 2,1] = IncomeSum.ToString();
    ws.Cells[dsIncome.Tables[0].Rows.Count + 2,2] = "总和";
    ws.Cells[dsIncome.Tables[0].Rows.Count + 2,3] = "100%";
    Step4 导出表格
    导出表格使用Worksheet对象的Export方法,将表格导出为Excel文件即可。考虑到可能出现异常,使用了try,catch来捕获可能出现的异常,输出错误信息。
    try
    {
    //输出Excel报表到服务器文件系统
    ws.Export(Server.MapPath(" ") + @"/Excel/report.xls", OWC.SheetExportActionEnum.ssExportActionNone);
    }
    catch
    {
    //错误时输出错误提示
    Info.Text = "保存报表错误,请与管理员联系";
    }
    将上述代码添加到MakePieChart函数的末尾,重新运行,在工程所在文件夹下的子Excel目录中就会有report.xls文件。其结果如图18-19。
           
            图18-19 生成报表结果图
    小结
    这一章先对ASP.NET中生成统计图表进行了介绍,然后对GDI+与Office Web Components的使用进行了详细说明,为后面做好了知识储备。随后利用公司盈利状况统计和公司收入分块图两个实例详细的介绍了如何利用Office Web Components与数据库结合绘制统计图表以及生成报表。
    通过本章的学习,读者对于.NET中统计报表的生成有了深刻的理解,相信精美、清晰的报表一定会为成为Web程序的亮点。

    原文:http://www.cnblogs.com/sgsoft/articles/68025.html

    展开全文
  • 在ASP.Net中两种利用CSS实现多界面的方法通过使页面动态加载不同CSS实现多界面方法一: public void page_load(Object obj,EventArgs e) { //创建服务器端控件. //指定的标记"LINK"初始化此类的新实例....

     

    在ASP.Net中两种利用CSS实现多界面的方法

    通过使页面动态加载不同CSS实现多界面

    方法一:

    <%@page language="C#"%>
    <%@import namespace="System.Data"%>
    <script language="c#" runat="server">
    public void page_load(Object obj,EventArgs e)
    {
    //创建服务器端控件.
    //指定的标记"LINK"初始化此类的新实例.
    HtmlGenericControl objLink=new HtmlGenericControl("LINK");
    objLink.ID=ID;
    objLink.Attributes["rel"]="stylesheet";
    objLink.Attributes["type"]="text/css";
    objLink.Attributes["href"]="portal.css";

    //此控件不产生任何可见输出,仅作为其他控件的容器,可在其中添加,插入或移除控件.
    MyCSS.Controls.Add(objLink);
    }
    </script>
    <html>
    <head>
    <title>c#</title>
    <asp:placeholder id="MyCSS" runat="server"></asp:placeholder>
    </head>
    <body bgColor="#ffcc66" style="FONT:9pt">
    <form runat="server">

    </form>
    </body>
    </html>


    通过动态设置页面所有同类型控件的样式来该变界面:

    方法二:

    可以通过改变WEB控件的CssClass属性,可方便地设置和修改控件的样式。
    但在实际开发过程中,一个个地设置控件的CssClass属性,非常繁琐,所以此思路应用不广.
    但下面的代码段演示了一次性改变页面所有同类型控件的样式的方法,可以实现简单的SKIN等功能。

    代码如下:

    public void page_load(Object obj,EventArgs e)
    {
    if(!Page.IsPostBack){
    //为页面的所有控件设置样式.
    SetCSS(Page.Controls);
    }
    }

    private void SetCSS(System.Web.UI.ControlCollection vControls)
    {
    for(int i=0;i<vControls.Count;i++)
    {
    System.Web.UI.Control vControl=vControls[i];

    //得到控件的类型
    //可增加控件类型及相应处理方法
    string PType=vControl.GetType().Name;
    switch (PType)
    {
    case "TextBox":
    TextBox_CSS ((TextBox) vControl);
    break;
    case "Button":
    //Button_CSS ((Button) vControl);
    break;
    case "DataGrid":
    //DataGrid_CSS ((DataGrid) vControl);
    break;
    }
    if(vControl.Controls.Count>0)
    SetCSS(vControl.Controls);
    }
    }


    private void TextBox_CSS(TextBox tb){
    tb.CssClass="TextBox_show";
    }

    <form runat="server">
    <asp:textbox id="Search1" runat="server"/>
    <asp:textbox id="Search2" CssClass="INPUT" runat="server"/>
    </form>
    运行后,查看页面源码.可发现文本框的样式已统一修改为"TextBox_show".

    转换函数大全

    1、DateTime 数字型
    System.DateTime currentTime=new System.DateTime();;
    1.1 取当前年月日时分秒
    currentTime=System.DateTime.Now;;
    1.2 取当前年
    int 年=currentTime.Year;;
    1.3 取当前月
    int 月=currentTime.Month;;
    1.4 取当前日
    int 日=currentTime.Day;;
    1.5 取当前时
    int 时=currentTime.Hour;;
    1.6 取当前分
    int 分=currentTime.Minute;;
    1.7 取当前秒
    int 秒=currentTime.Second;;
    1.8 取当前毫秒
    int 毫秒=currentTime.Millisecond;;
    (变量可用中文)

    2、Int32.Parse(变量) Int32.Parse("常量")
    字符型转换 转为32位数字型

    3、 变量.ToString()
    字符型转换 转为字符串
    12345.ToString("n");; //生成 12,345.00
    12345.ToString("C");; //生成 ¥12,345.00
    12345.ToString("e");; //生成 1.234500e+004
    12345.ToString("f4");; //生成 12345.0000
    12345.ToString("x");; //生成 3039 (16进制)
    12345.ToString("p");; //生成 1,234,500.00%


    4、变量.Length 数字型
    取字串长度:
    如: string str="中国";;
    int Len = str.Length ;; //Len是自定义变量, str是求测的字串的变量名

    5、System.Text.Encoding.Default.GetBytes(变量)
    字码转换 转为比特码
    如:byte[] bytStr = System.Text.Encoding.Default.GetBytes(str);;
    然后可得到比特长度:
    len = bytStr.Length;;

    6、System.Text.StringBuilder("")
    字符串相加,(+号是不是也一样?)
    如:System.Text.StringBuilder sb = new System.Text.StringBuilder("");;
    sb.Append("中华");;
    sb.Append("人民");;
    sb.Append("共和国");;

    7、变量.Substring(参数1,参数2);;
    截取字串的一部分,参数1为左起始位数,参数2为截取几位。
    如:string s1 = str.Substring(0,2);;

    8、String user_IP=Request.ServerVariables["REMOTE_ADDR"].ToString();;
    取远程用户IP地址

    9、穿过代理服务器取远程用户真实IP地址:
    if(Request.ServerVariables["HTTP_VIA"]!=null){
    string user_IP=Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();;
    }else{
    string user_IP=Request.ServerVariables["REMOTE_ADDR"].ToString();;
    }

    10、 Session["变量"];;
    存取Session值;
    如,赋值: Session["username"]="小布什";;

    取值: Object objName=Session["username"];;
    String strName=objName.ToString();;
    清空: Session.RemoveAll();;

    11、String str=Request.QueryString["变量"];;
    用超链接传送变量。
    如在任一页中建超链接:〈a href=Edit.aspx?fbid=23〉点击〈/a〉
    在Edit.aspx页中取值:String str=Request.QueryString["fdid"];;

    12、DOC对象.CreateElement("新建节点名");;
    创建XML文档新节点

    13、父节点.AppendChild(子节点);
    将新建的子节点加到XML文档父节点下

    14、 父节点.RemoveChild(节点);;
    删除节点

    15、Response
    Response.Write("字串");
    Response.Write(变量);
    向页面输出。

    Response.Redirect("URL地址");
    跳转到URL指定的页面

    16、char.IsWhiteSpce(字串变量,位数)——逻辑型
    查指定位置是否空字符;
    如:
    string str="中国 人民";;
    Response.Write(char.IsWhiteSpace(str,2));; //结果为:True, 第一个字符是0位,2是第三个字符。

    17、char.IsPunctuation('字符') --逻辑型
    查字符是否是标点符号
    如:Response.Write(char.IsPunctuation('A'));; //返回:False

    18、(int)'字符'
    把字符转为数字,查代码点,注意是单引号。
    如:
    Response.Write((int)'中');; //结果为中字的代码:20013

    19、(char)代码
    把数字转为字符,查代码代表的字符。
    如:
    Response.Write((char)22269);; //返回;国”字。

    20、 Trim()
    清除字串前后空格

    21 、字串变量.Replace("子字串","替换为")
    字串替换
    如:
    string str="中国";;
    str=str.Replace("国","央");; //将国字换为央字
    Response.Write(str);; //输出结果为;中央”

    再如:(这个非常实用)

    string str="这是〈script〉脚本";;
    str=str.Replace("〈","〈font〉〈〈/font〉");; //将左尖括号替换为〈font〉 与 〈 与 〈/font〉 (或换为〈,但估计经XML存诸后,再提出仍会还原)
    Response.Write(str);; //显示为:;这是〈script〉脚本”

    如果不替换,〈script〉将不显示,如果是一段脚本,将运行;而替换后,脚本将不运行。
    这段代码的价值在于:你可以让一个文本中的所有HTML标签失效,全部显示出来,保护你的具有交互性的站点。
    具体实现:将你的表单提交按钮脚本加上下面代码:
    string strSubmit=label1.Text;; //label1是你让用户提交数据的控件ID。
    strSubmit=strSubmit.Replace("〈","〈font〉〈〈/font〉");;
    然后保存或输出strSubmit。
    用此方法还可以简单实现UBB代码。

    22、Math.Max(i,j)
    取i与j中的最大值
    如 int x=Math.Max(5,10);; // x将取值 10

    23、字串对比一般都用: if(str1==str2){ } , 但还有别的方法:

    (1)、
    string str1;; str2
    //语法: str1.EndsWith(str2);; __检测字串str1是否以字串str2结尾,返回布尔值.如:
    if(str1.EndsWith(str2)){ Response.Write("字串str1是以"+str2+"结束的");; }

    (2)、
    //语法:str1.Equals(str2);; __检测字串str1是否与字串str2相等,返回布尔值,用法同上.

    (3)、
    //语法 Equals(str1,str2);; __检测字串str1是否与字串str2相等,返回布尔值,用法同上.

    24、IndexOf() 、LastIndexOf()
    查找字串中指定字符或字串首次(最后一次)出现的位置,返回索引值,如:
    str1.IndexOf("字"); //查找;字”在str1中的索引值(位置)
    str1.IndexOf("字串");//查找;字串”的第一个字符在str1中的索引值(位置)
    str1.IndexOf("字串",3,2);//从str1第4个字符起,查找2个字符,查找;字串”的第一个字符在str1中的索引值(位置)

    25、Insert()
    在字串中指定索引位插入指定字符。如:
    str1.Insert(1,"字");;在str1的第二个字符处插入;字”,如果str1="中国",插入后为;中字国”;

    26、PadLeft()、PadRight()
    在字串左(或右)加空格或指定char字符,使字串达到指定长度,如:
    〈%
    string str1="中国人";;
    str1=str1.PadLeft(10,'1');; //无第二参数为加空格
    Response.Write(str1);; //结果为;1111111中国人” , 字串长为10
    %〉

    27、Remove()
    从指定位置开始删除指定数的字符
    字串对比一般都用: if(str1==str2){ } , 但还有别的方法:

    1、
    string str1;; str2
    //语法: str1.EndsWith(str2);; __检测字串str1是否以字串str2结尾,返回布尔值.如:
    if(str1.EndsWith(str2)){ Response.Write("字串str1是以"+str2+"结束的");; }

    2、
    //语法:str1.Equals(str2);; __检测字串str1是否与字串str2相等,返回布尔值,用法同上.

    3、
    //语法 Equals(str1,str2);; __检测字串str1是否与字串str2相等,返回布尔值,用法同上.

    IndexOf()
    查找字串中指定字符或字串首次出现的位置,返首索引值,如:
    str1.IndexOf("字"); //查找;字”在str1中的索引值(位置)
    str1.IndexOf("字串");//查找;字串”的第一个字符在str1中的索引值(位置)
    str1.IndexOf("字串",3,2);//从str1第4个字符起,查找2个字符,查找;字串”的第一个字符在str1中的索引值(位置)

    1.9 取中文日期显示——年月日时分
    string strY=currentTime.ToString("f");; //不显示秒

    1.10 取中文日期显示_年月
    string strYM=currentTime.ToString("y");;

    1.11 取中文日期显示_月日
    string strMD=currentTime.ToString("m");;

    1.12 取当前年月日,格式为:2003-9-23
    string strYMD=currentTime.ToString("d");;

    1.13 取当前时分,格式为:14:24
    string strT=currentTime.ToString("t");;
    2007/7/6

    转载(正则表达式)

    正则表达式用于字符串处理,表单验证等场合,实用高效,但用到时总是不太把握,以致往往要上网查一番。我将一些常用的表达式收藏在这里,作备忘之用。本贴随时会更新。

    匹配中文字符的正则表达式: [/u4e00-/u9fa5]

    匹配双字节字符(包括汉字在内):[^/x00-/xff]

    应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

    String.prototype.len=function(){return this.replace([^/x00-/xff]/g,"aa").length;}

    匹配空行的正则表达式:/n[/s| ]*/r

    匹配HTML标记的正则表达式:/<(.*)>.*<///1>|<(.*) //>/

    匹配首尾空格的正则表达式:(^/s*)|(/s*$)

     

    String.prototype.trim = function()
    {
        return this.replace(/(^/s*)|(/s*$)/g, "");
    }

    利用正则表达式分解和转换IP地址:

    下面是利用正则表达式匹配IP地址,并将IP地址转换成对应数值的Javascript程序:

    function IP2V(ip)
    {
     re=/(/d+)/.(/d+)/.(/d+)/.(/d+)/g  //匹配IP地址的正则表达式
    if(re.test(ip))
    {
    return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1
    }
    else
    {
     throw new Error("Not a valid IP address!")
    }
    }

    不过上面的程序如果不用正则表达式,而直接用split函数来分解可能更简单,程序如下:

    var ip="10.100.20.168"
    ip=ip.split(".")
    alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))

    匹配Email地址的正则表达式:/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*

    匹配网址URL的正则表达式:http://([/w-]+/.)+[/w-]+(/[/w- ./?%&=]*)?

    利用正则表达式去除字串中重复的字符的算法程序:[注:此程序不正确,原因见本贴回复]

    var s="abacabefgeeii"
    var s1=s.replace(/(.).*/1/g,"$1")
    var re=new RegExp("["+s1+"]","g")
    var s2=s.replace(re,"")
    alert(s1+s2)  //结果为:abcefgi

    我原来在CSDN上发贴寻求一个表达式来实现去除重复字符的方法,最终没有找到,这是我能想到的最简单的实现方法。思路是使用后向引用取出包括重复的字符,再以重复的字符建立第二个表达式,取到不重复的字符,两者串连。这个方法对于字符顺序有要求的字符串可能不适用。

    得用正则表达式从URL地址中提取文件名的javascript程序,如下结果为page1

    s="http://www.9499.net/page1.htm"
    s=s.replace(/(.*//){0,}([^/.]+).*/ig,"$2")
    alert(s)

    利用正则表达式限制网页表单里的文本框输入内容:

    正则表达式限制只能输入中文:οnkeyup="value=value.replace(/[^/u4E00-/u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^/u4E00-/u9FA5]/g,''))"

    正则表达式限制只能输入全角字符: οnkeyup="value=value.replace(/[^/uFF00-/uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^/uFF00-/uFFFF]/g,''))"

    正则表达式限制只能输入数字:οnkeyup="value=value.replace(/[^/d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^/d]/g,''))"

    正则表达式限制只能输入数字和英文:οnkeyup="value=value.replace(/[/W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^/d]/g,''))"

     

    正则表达式,相关链接
    http://blog.csdn.net/laily/category/19548.aspx
    http://blog.csdn.net/laily/archive/2004/06/30/30525.aspx 微软的正则表达式教程(五):选择/编组和后向引用

    http://blog.csdn.net/laily/archive/2004/06/30/30522.aspx 微软的正则表达式教程(四):限定符和定位符

    http://blog.csdn.net/laily/archive/2004/06/30/30517.aspx 微软的正则表达式教程(三):字符匹配

    http://blog.csdn.net/laily/archive/2004/06/30/30514.aspx 微软的正则表达式教程(二):正则表达式语法和优先权顺序

    http://blog.csdn.net/laily/archive/2004/06/30/30511.aspx 微软的正则表达式教程(一):正则表达式简介

    http://blog.csdn.net/laily/archive/2004/06/30/30360.aspx 小程序大作为:高级查找/替换、正则表达式练习器、Javascript脚本程序调试器

    http://blog.csdn.net/laily/archive/2004/06/24/25872.aspx 经典正则表达式

    正则表达式,正规表达式,正则表达式匹配,正则表达式语法,模式匹配,正规表达式匹配 javascript正则表达式 ASP正则表达式 ASP.NET正则表达式 C#正则表达式 JSP正则表达式 PHP正则表达式 VB.NET正则表达式 VBSCript正则表达式编程 delphi正则表达式 jscript

     

    正则表达式 regular expression
    正则表达式 RegExp
    模式 pattern
    匹配 Match
    .NET命名空间: System.Text.RegularExpression

     

    补充:
    ^/d+$  //匹配非负整数(正整数 + 0)
    ^[0-9]*[1-9][0-9]*$  //匹配正整数
    ^((-/d+)|(0+))$  //匹配非正整数(负整数 + 0)
    ^-[0-9]*[1-9][0-9]*$  //匹配负整数
    ^-?/d+$    //匹配整数
    ^/d+(/./d+)?$  //匹配非负浮点数(正浮点数 + 0)
    ^(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*))$  //匹配正浮点数
    ^((-/d+(/./d+)?)|(0+(/.0+)?))$  //匹配非正浮点数(负浮点数 + 0)
    ^(-(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*)))$  //匹配负浮点数
    ^(-?/d+)(/./d+)?$  //匹配浮点数
    ^[A-Za-z]+$  //匹配由26个英文字母组成的字符串
    ^[A-Z]+$  //匹配由26个英文字母的大写组成的字符串
    ^[a-z]+$  //匹配由26个英文字母的小写组成的字符串
    ^[A-Za-z0-9]+$  //匹配由数字和26个英文字母组成的字符串
    ^/w+$  //匹配由数字、26个英文字母或者下划线组成的字符串
    ^[/w-]+(/.[/w-]+)*@[/w-]+(/.[/w-]+)+$    //匹配email地址
    ^[a-zA-z]+://匹配(/w+(-/w+)*)(/.(/w+(-/w+)*))*(/?/S*)?$  //匹配url

     

    利用正则表达式去除字串中重复的字符的算法程序:

    var s="abacabefgeeii"
    var s1=s.replace(/(.).*/1/g,"$1")
    var re=new RegExp("["+s1+"]","g")
    var s2=s.replace(re,"")
    alert(s1+s2) //结果为:abcefgi
    ===============================
    如果var s = "abacabefggeeii"
    结果就不对了,结果为:abeicfgg
    正则表达式的能力有限

     

    1.确认有效电子邮件格式
    下面的代码示例使用静态 Regex.IsMatch 方法验证一个字符串是否为有效电子邮件格式。如果字符串包含一个有效的电子邮件地址,则 IsValidEmail 方法返回 true,否则返回 false,但不采取其他任何操作。您可以使用 IsValidEmail,在应用程序将地址存储在数据库中或显示在 ASP.NET 页中之前,筛选出包含无效字符的电子邮件地址。

    [Visual Basic]
    Function IsValidEmail(strIn As String) As Boolean
    ' Return true if strIn is in valid e-mail format.
    Return Regex.IsMatch(strIn, ("^([/w-/.]+)@((/[[0-9]{1,3}/.[0-9]{1,3}/.[0-9]{1,3}/.)|(([/w-]+/.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(/]?)$")
    End Function
    [C#]
    bool IsValidEmail(string strIn)
    {
    // Return true if strIn is in valid e-mail format.
    return Regex.IsMatch(strIn, @"^([/w-/.]+)@((/[[0-9]{1,3}/.[0-9]{1,3}/.[0-9]{1,3}/.)|(([/w-]+/.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(/]?)$");
    }


    2.清理输入字符串
    下面的代码示例使用静态 Regex.Replace 方法从字符串中抽出无效字符。您可以使用这里定义的 CleanInput 方法,清除掉在接受用户输入的窗体的文本字段中输入的可能有害的字符。CleanInput 在清除掉除 @、-(连字符)和 .(句点)以外的所有非字母数字字符后返回一个字符串。

    [Visual Basic]
    Function CleanInput(strIn As String) As String
    ' Replace invalid characters with empty strings.
    Return Regex.Replace(strIn, "[^/w/.@-]", "")
    End Function
    [C#]
    String CleanInput(string strIn)
    {
    // Replace invalid characters with empty strings.
    return Regex.Replace(strIn, @"[^/w/.@-]", "");
    }


    3.更改日期格式
    以下代码示例使用 Regex.Replace 方法来用 dd-mm-yy 的日期形式代替 mm/dd/yy 的日期形式。

    [Visual Basic]
    Function MDYToDMY(input As String) As String
    Return Regex.Replace(input, _
    "/b(?<month>/d{1,2})/(?<day>/d{1,2})/(?<year>/d{2,4})/b", _
    "${day}-${month}-${year}")
    End Function
    [C#]
    String MDYToDMY(String input)
    {
    return Regex.Replace(input,
    "//b(?<month>//d{1,2})/(?<day>//d{1,2})/(?<year>//d{2,4})//b",
    "${day}-${month}-${year}");
    }
    Regex 替换模式
    本示例说明如何在 Regex.Replace 的替换模式中使用命名的反向引用。其中,替换表达式 ${day} 插入由 (?<day>...) 组捕获的子字符串。

    有几种静态函数使您可以在使用正则表达式操作时无需创建显式正则表达式对象,而 Regex.Replace 函数正是其中之一。如果您不想保留编译的正则表达式,这将给您带来方便


    4.提取 URL 信息
    以下代码示例使用 Match.Result 来从 URL 提取协议和端口号。例如,“http://www.contoso.com:8080/letters/readme.html”将返回“http:8080”。

    [Visual Basic]
    Function Extension(url As String) As String
    Dim r As New Regex("^(?<proto>/w+)://[^/]+?(?<port>:/d+)?/", _
    RegexOptions.Compiled)
    Return r.Match(url).Result("${proto}${port}")
    End Function
    [C#]
    String Extension(String url)
    {
    Regex r = new Regex(@"^(?<proto>/w+)://[^/]+?(?<port>:/d+)?/",
    RegexOptions.Compiled);
    return r.Match(url).Result("${proto}${port}");
    }

     

      一、正则表达式基础知识
      我们先从简单的开始。假设你要搜索一个包含字符“cat”的字符串,搜索用的正则表达式就是“cat”。如果搜索对大小写不敏感,单词“catalog”、“Catherine”、“sophisticated”都可以匹配。也就是说:


      1.1句点符号
      假设你在玩英文拼字游戏,想要找出三个字母的单词,而且这些单词必须以“t”字母开头,以“n”字母结束。另外,假设有一本英文字典,你可以用正则表达式搜索它的全部内容。要构造出这个正则表达式,你可以使用一个通配符??句点符号“.”。这样,完整的表达式就是“t.n”,它匹配“tan”、“ten”、“tin”和“ton”,还匹配 “t#n”、“tpn”甚至“tn”,还有其他许多无意义的组合。这是因为句点符号匹配所有字符,包括空格、Tab字符甚至换行符:

      1.2方括号符号
      为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号(“[]”)里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是说,正则表达式“t[aeio]n”只匹配“tan”、“Ten”、“tin”和“ton”。但“Toon”不匹配,因为在方括号之内你只能匹配单个字符:

      1.4表示匹配次数的符号
      表一显示了表示匹配次数的符号,这些符号用来确定紧靠该符号左边的符号出现的次数:

      假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如图一所示。在正则表达式中,连字符(“-”)有着特殊的意义,它表示一个范围,比如从0到9。因此,匹配社会安全号码中的连字符号时,它的前面要加上一个转义字符“/”。

      图一:匹配所有123-12-1234形式的社会安全号码
      假设进行搜索的时候,你希望连字符号可以出现,也可以不出现??即,999-99-9999和999999999都属于正确的格式。这时,你可以在连字符号后面加上“?”数量限定符号,如图二所示:

      图二:匹配所有123-12-1234和123121234形式的社会安全号码
      下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分“[0-9]{ 4}”,再加上字母部分“[A-Z]{ 2}”。图三显示了完整的正则表达式

      图三:匹配典型的美国汽车牌照号码,如8836KV
      1.5“否”符号
      “^”符号称为“否”符号。如果用在方括号内,“^”表示不想要匹配的字符。例如,图四的正则表达式匹配所有单词,但以“X”字母开头的单词除外。

      图四:匹配所有单词,但“X”开头的除外
      1.6圆括号和空白符号
      假设要从格式为“June26,1951”的生日日期中提取出月份部分,用来匹配该日期的正则表达式可以如图五所示:

      图五:匹配所有MothDD,YYYY格式的日期
      新出现的“/s”符号是空白符号,匹配所有的空白字符,包括Tab字符。如果字符串正确匹配,接下来如何提取出月份部分呢?只需在月份周围加上一个圆括号创建一个组,然后用OROAPI(本文后面详细讨论)提取出它的值。修改后的正则表达式如图六所示:

      图六:匹配所有MonthDD,YYYY格式的日期,定义月份值为第一个组
      1.7其它符号
      为简便起见,你可以使用一些为常见正则表达式创建的快捷符号。如表二所示:
      表二:常用符号

      例如,在前面社会安全号码的例子中,所有出现“[0-9]”的地方我们都可以使用“/d”。修改后的正则表达式如图七所示:

     


    /*------------------------
    功能:替换任何空白字符
    -------------------------*/
    function TrimString (strVal)
    {
    strTmp = strVal + "";
    if (strTmp.length == 0)
    return (strTmp);
    reVal = /^/s*/;
    strTmp = strTmp.replace (reVal, '');
    reVal = //s*$/;
    return (strTmp.replace (reVal, ''));
    }

    /*------------------------
    功能:检测是否是有效数字
    -------------------------*/
    function Check_Num( num )
    {
    num = ( TrimString( num ) );
    if (num.length == 0)
    return (false);
    return ( Number( num ) );
    }

    /*------------------------
    功能:检测是否是有效日期
    -------------------------*/
    function Check_Date (strDate)
    {
    strDate = (TrimString (strDate));
    if (strDate.length == 0)
    return (false);
    reVal = /^([1-2]/d{3})[//|/-](0?[1-9]|10|11|12)[//|/-]([1-2]?[0-9]|0[1-9]|30|31)$/;
    return (reVal.test (strDate));
    }

    /*------------------------
    功能:检测是否是有效Email
    -------------------------*/
    function Check_Email (strEmail)
    {
    strEmail = (TrimString (strEmail));
    if (strEmail.length == 0)
    return (false);

    reVal = /^[/-!#/$%&'/*/+///.//0-9=/?A-Z/^_`a-z{|}~]+@[/-!#/$%&'/*/+///.//0-9=/?A-Z/^_`a-z{|}~]+(/.[/-!#/$%&'/*/+///.//0-9=/?A-Z/^_`a-z{|}~]+)+$/;
    return (reVal.test (strEmail));
    }

    /*------------------------
    功能:检测是否是有效时间
    -------------------------*/
    function Check_Time (strTime)
    {
    strTime = (TrimString (strTime));
    if (strTime.length == 0)
    return (false);

    reVal = /^(([0-9]|[01][0-9]|2[0-3])(:([0-9]|[0-5][0-9])){0,2}|(0?[0-9]|1[0-1])(:([0-9]|[0-5][0-9])){0,2}/s?[aApP][mM])?$/;
    return (reVal.test (strTime));
    }

    /*------------------------
    功能:检测是否是有效日期特定格式
    -------------------------*/
    function Check_Date_1 (strDate)
    {
    strDate = (TrimString (strDate));
    if (strDate.length == 0)
    return (false);
    reVal = /^([1-2]/d{3})[//](0?[1-9]|10|11|12)[//]([1-2]?[0-9]|0[1-9]|30|31)$/;
    return (reVal.test (strDate));
    }

    /*------------------------
    功能:检测是否是有效日期特定格式
    -------------------------*/
    function Check_Date_2 (strDate)
    {
    strDate = (TrimString (strDate));
    if (strDate.length == 0)
    return (false);
    reVal = /^([1-2]/d{3})[/-](0[1-9]|10|11|12)[/-]([1-2][0-9]|0[1-9]|30|31)$/;
    return (reVal.test (strDate));
    }

    /*--------------------------------------
    功能:换行定行
    ---------------------------------------*/
    function enter( form, temp )
    {
    if ( window.event.keyCode == 13 )
    {
    eval( form + temp + ".focus()" );
    eval( form + temp + ".select()" );
    }
    else
    return (false);
    }

    /*--------------------------------------
    功能:检查字符串长度
    ---------------------------------------*/
    function ByteString (strVal)
    {
    nLen = 0;

    for (i = 0; i < strVal.length; i ++)
    {
    if (strVal.charCodeAt (i) > 255)
    nLen += 2;
    else
    nLen ++;
    };
    return (nLen);
    }

    /*--------------------------------------
    功能:按要求截取字符串长度
    ---------------------------------------*/
    function SubString(strVal,nStrLen)
    {
    nLen = 0;
    nTemp = 0;
    for (i = 0; i < strVal.length; i ++)
    {
    if (strVal.charCodeAt (i) > 255)
    nLen += 2;
    else
    nLen ++;
    if(nLen <= nStrLen)
    nTemp = i;
    else
    break;
    };
    return(strVal.substr(0,nTemp+1));
    }

    /*------------------------
    功能:检测密码,密码只能由英文字母、数字、减号、下划线、$、#、*、(和)构成,且首位必须是英文字母
    -------------------------*/
    function Check_Pass( strPass )
    {
    strPass = ( TrimString( strPass ) );
    if (strPass.length == 0)
    return (false);
    reVal = /^[a-zA-Z]{1}[a-zA-Z0-9-_$#*()]{0,29}$/;
    return ( reVal.test (strPass) );
    }

    这是所有的,不过是PHP的,你自己转换一下吧~~

    # re: 正则表达式 2005-02-28 00:59 yongsheng

    ^(((19)|(20))/d{2})(((((-|/)0?)|0)[1-9])|((-|/)?1[0-2]))((((((-|/)0?)|0)[1-9])|((-|/)?[1-2][0-9]))|((-|/)?3[0-1]))$


    2004-1-1格式

    # re: 正则表达式 2005-03-07 14:33 yongsheng

    一、验证类
    1、数字验证内
    1.1 整数
    1.2 大于0的整数 (用于传来的ID的验证)
    1.3 负整数的验证
    1.4 整数不能大于iMax
    1.5 整数不能小于iMin
    2、时间类
    2.1 短时间,形如 (13:04:06)
    2.2 短日期,形如 (2003-12-05)
    2.3 长时间,形如 (2003-12-05 13:04:06)
    2.4 只有年和月。形如(2003-05,或者2003-5)
    2.5 只有小时和分钟,形如(12:03)
    3、表单类
    3.1 所有的表单的值都不能为空
    3.2 多行文本框的值不能为空。
    3.3 多行文本框的值不能超过sMaxStrleng
    3.4 多行文本框的值不能少于sMixStrleng
    3.5 判断单选框是否选择。
    3.6 判断复选框是否选择.
    3.7 复选框的全选,多选,全不选,反选
    3.8 文件上传过程中判断文件类型
    4、字符类
    4.1 判断字符全部由a-Z或者是A-Z的字字母组成
    4.2 判断字符由字母和数字组成。
    4.3 判断字符由字母和数字,下划线,点号组成.且开头的只能是下划线和字母
    4.4 字符串替换函数.Replace();
    5、浏览器类
    5.1 判断浏览器的类型
    5.2 判断ie的版本
    5.3 判断客户端的分辨率

    6、结合类
    6.1 email的判断。
    6.2 手机号码的验证
    6.3 身份证的验证


    二、功能类

    1、时间与相关控件类
    1.1 日历
    1.2 时间控件
    1.3 万年历
    1.4 显示动态显示时钟效果(文本,如OA中时间)
    1.5 显示动态显示时钟效果 (图像,像手表)
    2、表单类
    2.1 自动生成表单
    2.2 动态添加,修改,删除下拉框中的元素
    2.3 可以输入内容的下拉框
    2.4 多行文本框中只能输入iMax文字。如果多输入了,自动减少到iMax个文字(多用于短信发送)

    3、打印类
    3.1 打印控件
    4、事件类
    4.1 屏蔽右键
    4.2 屏蔽所有功能键
    4.3 --> 和<-- F5 F11,F9,F1
    4.4 屏蔽组合键ctrl+N
    5、网页设计类
    5.1 连续滚动的文字,图片(注意是连续的,两段文字和图片中没有空白出现)
    5.2 html编辑控件类
    5.3 颜色选取框控件
    5.4 下拉菜单
    5.5 两层或多层次的下拉菜单
    5.6 仿IE菜单的按钮。(效果如rongshuxa.com的导航栏目)
    5.7 状态栏,title栏的动态效果(例子很多,可以研究一下)
    5.8 双击后,网页自动滚屏
    6、树型结构。
    6.1 asp+SQL版
    6.2 asp+xml+sql版
    6.3 java+sql或者java+sql+xml
    7、无边框效果的制作
    8、连动下拉框技术
    9、文本排序


    一、验证类
    1、数字验证内
    1.1 整数
    /^(-|/+)?/d+$/.test(str)
    1.2 大于0的整数 (用于传来的ID的验证)
    /^/d+$/.test(str)
    1.3 负整数的验证
    /^-/d+$/.test(str)
    2、时间类
    2.1 短时间,形如 (13:04:06)
    function isTime(str)
    {
    var a = str.match(/^(/d{1,2})(:)?(/d{1,2})/2(/d{1,2})$/);
    if (a == null) {alert('输入的参数不是时间格式'); return false;}
    if (a[1]>24 || a[3]>60 || a[4]>60)
    {
    alert("时间格式不对");
    return false
    }
    return true;
    }
    2.2 短日期,形如 (2003-12-05)
    function strDateTime(str)
    {
    var r = str.match(/^(/d{1,4})(-|//)(/d{1,2})/2(/d{1,2})$/);
    if(r==null)return false;
    var d= new Date(r[1], r[3]-1, r[4]);
    return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[3]&&d.getDate()==r[4]);
    }
    2.3 长时间,形如 (2003-12-05 13:04:06)
    function strDateTime(str)
    {
    var reg = /^(/d{1,4})(-|//)(/d{1,2})/2(/d{1,2}) (/d{1,2}):(/d{1,2}):(/d{1,2})$/;
    var r = str.match(reg);
    if(r==null)return false;
    var d= new Date(r[1], r[3]-1,r[4],r[5],r[6],r[7]);
    return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[3]&&d.getDate()==r[4]&&d.getHours()==r[5]&&d.getMinutes()==r[6]&&d.getSeconds()==r[7]);
    }
    2.4 只有年和月。形如(2003-05,或者2003-5)
    2.5 只有小时和分钟,形如(12:03)
    3、表单类
    3.1 所有的表单的值都不能为空
    <input οnblur="if(this.value.replace(/^/s+|/s+$/g,'')=='')alert('不能为空!')">
    3.2 多行文本框的值不能为空。
    3.3 多行文本框的值不能超过sMaxStrleng
    3.4 多行文本框的值不能少于sMixStrleng
    3.5 判断单选框是否选择。
    3.6 判断复选框是否选择.
    3.7 复选框的全选,多选,全不选,反选
    3.8 文件上传过程中判断文件类型
    4、字符类
    4.1 判断字符全部由a-Z或者是A-Z的字字母组成
    <input οnblur="if(/[^a-zA-Z]/g.test(this.value))alert('有错')">
    4.2 判断字符由字母和数字组成。
    <input οnblur="if(/[^0-9a-zA-Z]/g.test(this.value))alert('有错')">
    4.3 判断字符由字母和数字,下划线,点号组成.且开头的只能是下划线和字母
    /^([a-zA-z_]{1})([/w]*)$/g.test(str)
    4.4 字符串替换函数.Replace();
    5、浏览器类
    5.1 判断浏览器的类型
    window.navigator.appName
    5.2 判断ie的版本
    window.navigator.appVersion
    5.3 判断客户端的分辨率
    window.screen.height; window.screen.width;

    6、结合类
    6.1 email的判断。
    function ismail(mail)
    {
    return(new RegExp(/^/w+((-/w+)|(/./w+))*/@[A-Za-z0-9]+((/.|-)[A-Za-z0-9]+)*/.[A-Za-z0-9]+$/).test(mail));
    }
    6.2 手机号码的验证
    6.3 身份证的验证
    function isIdCardNo(num)
    {
    if (isNaN(num)) {alert("输入的不是数字!"); return false;}
    var len = num.length, re;
    if (len == 15)
    re = new RegExp(/^(/d{6})()?(/d{2})(/d{2})(/d{2})(/d{3})$/);
    else if (len == 18)
    re = new RegExp(/^(/d{6})()?(/d{4})(/d{2})(/d{2})(/d{3})(/d)$/);
    else {alert("输入的数字位数不对!"); return false;}
    var a = num.match(re);
    if (a != null)
    {
    if (len==15)
    {
    var D = new Date("19"+a[3]+"/"+a[4]+"/"+a[5]);
    var B = D.getYear()==a[3]&&(D.getMonth()+1)==a[4]&&D.getDate()==a[5];
    }
    else
    {
    var D = new Date(a[3]+"/"+a[4]+"/"+a[5]);
    var B = D.getFullYear()==a[3]&&(D.getMonth()+1)==a[4]&&D.getDate()==a[5];
    }
    if (!B) {alert("输入的身份证号 "+ a[0] +" 里出生日期不对!"); return false;}
    }
    return true;
    }

    3.7 复选框的全选,多选,全不选,反选
    <form name=hrong>
    <input type=checkbox name=All οnclick="checkAll('mm')">全选<br/>
    <input type=checkbox name=mm οnclick="checkItem('All')"><br/>
    <input type=checkbox name=mm οnclick="checkItem('All')"><br/>
    <input type=checkbox name=mm οnclick="checkItem('All')"><br/>
    <input type=checkbox name=mm οnclick="checkItem('All')"><br/>
    <input type=checkbox name=mm οnclick="checkItem('All')"><br/><br/>


    <input type=checkbox name=All2 οnclick="checkAll('mm2')">全选<br/>
    <input type=checkbox name=mm2 οnclick="checkItem('All2')"><br/>
    <input type=checkbox name=mm2 οnclick="checkItem('All2')"><br/>
    <input type=checkbox name=mm2 οnclick="checkItem('All2')"><br/>
    <input type=checkbox name=mm2 οnclick="checkItem('All2')"><br/>
    <input type=checkbox name=mm2 οnclick="checkItem('All2')"><br/>

    </form>

    <SCRIPT LANGUAGE="JavaScript">
    function checkAll(str)
    {
    var a = document.getElementsByName(str);
    var n = a.length;
    for (var i=0; i<n; i++)
    a[i].checked = window.event.srcElement.checked;
    }
    function checkItem(str)
    {
    var e = window.event.srcElement;
    var all = eval("document.hrong."+ str);
    if (e.checked)
    {
    var a = document.getElementsByName(e.name);
    all.checked = true;
    for (var i=0; i<a.length; i++)
    {
    if (!a[i].checked){ all.checked = false; break;}
    }
    }
    else all.checked = false;
    }
    </SCRIPT>

    3.8 文件上传过程中判断文件类型
    <input type=file οnchange="alert(this.value.match(/^(.*)(/.)(.{1,8})$/)[3])">

    画图:
    <OBJECT
    id=S
    style="LEFT: 0px; WIDTH: 392px; TOP: 0px; HEIGHT: 240px"
    height=240
    width=392
    classid="clsid:369303C2-D7AC-11D0-89D5-00A0C90833E6">
    </OBJECT>
    <SCRIPT>
    S.DrawingSurface.ArcDegrees(0,0,0,30,50,60);
    S.DrawingSurface.ArcRadians(30,0,0,30,50,60);
    S.DrawingSurface.Line(10,10,100,100);
    </SCRIPT>

    写注册表:
    <SCRIPT>
    var WshShell = WScript.CreateObject("WScript.Shell");
    WshShell.RegWrite ("HKCU//Software//ACME//FortuneTeller//", 1, "REG_BINARY");
    WshShell.RegWrite ("HKCU//Software//ACME//FortuneTeller//MindReader", "Goocher!", "REG_SZ");
    var bKey = WshShell.RegRead ("HKCU//Software//ACME//FortuneTeller//");
    WScript.Echo (WshShell.RegRead ("HKCU//Software//ACME//FortuneTeller//MindReader"));
    WshShell.RegDelete ("HKCU//Software//ACME//FortuneTeller//MindReader");
    WshShell.RegDelete ("HKCU//Software//ACME//FortuneTeller//");
    WshShell.RegDelete ("HKCU//Software//ACME//");
    </SCRIPT>

    TABLAE相关(客户端动态增加行列)
    <HTML>
    <SCRIPT LANGUAGE="JScript">
    function numberCells() {
    var count=0;
    for (i=0; i < document.all.mytable.rows.length; i++) {
    for (j=0; j < document.all.mytable.rows(i).cells.length; j++) {
    document.all.mytable.rows(i).cells(j).innerText = count;
    count++;
    }
    }
    }
    </SCRIPT>
    <BODY οnlοad="numberCells()">
    <TABLE id=mytable border=1>
    <TR><TH>&nbsp;</TH><TH>&nbsp;</TH><TH>&nbsp;</TH><TH>&nbsp;</TH></TR>
    <TR><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD></TR>
    <TR><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD></TR>
    </TABLE>
    </BODY>
    </HTML>

    1.身份证严格验证:

    <script>
    var aCity={11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙江 ",31:"上海",32:"江苏",33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山东",41:"河南",42:"湖北 ",43:"湖南",44:"广东",45:"广西",46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏 ",61:"陕西",62:"甘肃",63:"青海",64:"宁夏",65:"新疆",71:"台湾",81:"香港",82:"澳门",91:"国外 "}

    function cidInfo(sId){
    var iSum=0
    var info=""
    if(!/^/d{17}(/d|x)$/i.test(sId))return false;
    sId=sId.replace(/x$/i,"a");
    if(aCity[parseInt(sId.substr(0,2))]==null)return "Error:非法地区";
    sBirthday=sId.substr(6,4)+"-"+Number(sId.substr(10,2))+"-"+Number(sId.substr(12,2));
    var d=new Date(sBirthday.replace(/-/g,"/"))
    if(sBirthday!=(d.getFullYear()+"-"+ (d.getMonth()+1) + "-" + d.getDate()))return "Error:非法生日";
    for(var i = 17;i>=0;i --) iSum += (Math.pow(2,i) % 11) * parseInt(sId.charAt(17 - i),11)
    if(iSum%11!=1)return "Error:非法证号";
    return aCity[parseInt(sId.substr(0,2))]+","+sBirthday+","+(sId.substr(16,1)%2?"男":"女")
    }

    document.write(cidInfo("380524198002300016"),"<br/>");
    document.write(cidInfo("340524198002300019"),"<br/>")
    document.write(cidInfo("340524197711111111"),"<br/>")
    document.write(cidInfo("34052419800101001x"),"<br/>");
    </script>

    2.验证IP地址
    <SCRIPT LANGUAGE="JavaScript">
    function isip(s){
    var check=function(v){try{return (v<=255 && v>=0)}catch(x){return false}};
    var re=s.split(".")
    return (re.length==4)?(check(re[0]) && check(re[1]) && check(re[2]) && check(re[3])):false
    }

    var s="202.197.78.129";
    alert(isip(s))
    </SCRIPT>



    3.加sp1后还能用的无边框窗口!!
    <HTML XMLNS:IE>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    <IE:Download ID="include" STYLE="behavior:url(#default#download)" />
    <title>Chromeless Window</title>

    <SCRIPT LANGUAGE="JScript">
    /*--- Special Thanks For andot ---*/

    /*
    This following code are designed and writen by Windy_sk <seasonx@163.net>
    You can use it freely, but u must held all the copyright items!
    */

    /*--- Thanks For andot Again ---*/

    var CW_width = 400;
    var CW_height = 300;
    var CW_top = 100;
    var CW_left = 100;
    var CW_url = "/";
    var New_CW = window.createPopup();
    var CW_Body = New_CW.document.body;
    var content = "";
    var CSStext = "margin:1px;color:black; border:2px outset;border-style:expression(οnmοuseοut=οnmοuseup=function(){this.style.borderStyle='outset'}, οnmοusedοwn=function(){if(event.button!=2)this.style.borderStyle='inset'});background-color:buttonface;width:16px;height:14px;font-size:12px;line-height:11px;cursor:Default;";

    //Build Window
    include.startDownload(CW_url, function(source){content=source});

    function insert_content(){
    var temp = "";
    CW_Body.style.overflow = "hidden";
    CW_Body.style.backgroundColor = "white";
    CW_Body.style.border = "solid black 1px";
    content = content.replace(/<a ([^>]*)>/g,"<a οnclick='parent.open(this.href);return false' $1>");
    temp += "<table width=100% height=100% cellpadding=0 cellspacing=0 border=0>";
    temp += "<tr style=';font-size:12px;background:#0099CC;height:20;cursor:default' οndblclick=/"Max.innerText=Max.innerText=='1'?'2':'1';parent.if_max=!parent.if_max;parent.show_CW();/" οnmοuseup='parent.drag_up(event)' οnmοusemοve='parent.drag_move(event)' οnmοusedοwn='parent.drag_down(event)' onselectstart='return false' οncοntextmenu='return false'>";
    temp += "<td style='color:#ffffff;padding-left:5px'>Chromeless Window For IE6 SP1</td>";
    temp += "<td style='color:#ffffff;padding-right:5px;' align=right>";
    temp += "<span id=Help οnclick=/"alert('Chromeless Window For IE6 SP1 - Ver 1.0//n//nCode By Windy_sk//n//nSpecial Thanks For andot')/" style=/""+CSStext+"font-family:System;padding-right:2px;/">?</span>";
    temp += "<span id=Min οnclick='parent.New_CW.hide();parent.blur()' style=/""+CSStext+"font-family:Webdings;/" title='Minimum'>0</span>";
    temp += "<span id=Max οnclick=/"this.innerText=this.innerText=='1'?'2':'1';parent.if_max=!parent.if_max;parent.show_CW();/" style=/""+CSStext+"font-family:Webdings;/" title='Maximum'>1</span>";
    temp += "<span id=Close οnclick='parent.opener=null;parent.close()' style=/""+CSStext+"font-family:System;padding-right:2px;/" title='Close'>x</span>";
    temp += "</td></tr><tr><td colspan=2>";
    temp += "<div id=include style='overflow:scroll;overflow-x:hidden;overflow-y:auto; HEIGHT: 100%; width:"+CW_width+"'>";
    temp += content;
    temp += "</div>";
    temp += "</td></tr></table>";
    CW_Body.innerHTML = temp;
    }

    setTimeout("insert_content()",1000);

    var if_max = true;
    function show_CW(){
    window.moveTo(10000, 10000);
    if(if_max){
    New_CW.show(CW_top, CW_left, CW_width, CW_height);
    if(typeof(New_CW.document.all.include)!="undefined"){
    New_CW.document.all.include.style.width = CW_width;
    New_CW.document.all.Max.innerText = "1";
    }

    }else{
    New_CW.show(0, 0, screen.width, screen.height);
    New_CW.document.all.include.style.width = screen.width;
    }
    }

    window.onfocus = show_CW;
    window.onresize = show_CW;

    // Move Window
    var drag_x,drag_y,draging=false

    function drag_move(e){
    if (draging){
    New_CW.show(e.screenX-drag_x, e.screenY-drag_y, CW_width, CW_height);
    return false;
    }
    }

    function drag_down(e){
    if(e.button==2)return;
    if(New_CW.document.body.offsetWidth==screen.width && New_CW.document.body.offsetHeight==screen.height)return;
    drag_x=e.clientX;
    drag_y=e.clientY;
    draging=true;
    e.srcElement.setCapture();
    }

    function drag_up(e){
    draging=false;
    e.srcElement.releaseCapture();
    if(New_CW.document.body.offsetWidth==screen.width && New_CW.document.body.offsetHeight==screen.height) return;
    CW_top = e.screenX-drag_x;
    CW_left = e.screenY-drag_y;
    }

    </SCRIPT>
    </HTML>

    电话号码的验证

    要求:
      (1)电话号码由数字、"("、")"和"-"构成
      (2)电话号码为3到8位
      (3)如果电话号码中包含有区号,那么区号为三位或四位
      (4)区号用"("、")"或"-"和其他部分隔开
      (5)移动电话号码为11或12位,如果为12位,那么第一位为0
      (6)11位移动电话号码的第一位和第二位为"13"
      (7)12位移动电话号码的第二位和第三位为"13"
      根据这几条规则,可以与出以下正则表达式
      (^[0-9]{3,4}/-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^/([0-9]{3,4}/)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)


    <script language="javascript">
    function PhoneCheck(s) {
    var str=s;
    var reg=/(^[0-9]{3,4}/-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^/([0-9]{3,4}/)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)/
    alert(reg.test(str));
    }
    </script>
    <input type=text name="iphone">
    <input type=button οnclick="PhoneCheck(document.all.iphone.value)" value="Check">

    具有在输入非数字字符不回显的效果,即对非数字字符的输入不作反应。
    function numbersonly(field,event){
    var key,keychar;
    if(window.event){
    key = window.event.keyCode;
    }
    else if (event){
    key = event.which;
    }
    else{
    return true
    }
    keychar = String.fromCharCode(key);
    if((key == null)||(key == 0)||(key == 8)||(key == 9)||(key == 13)||(key == 27)){
    return true;
    }
    else if(("0123456789.").indexOf(keychar)>-1){
    window.status = "";
    return true;
    }
    else {
    window.status = "Field excepts numbers only";
    return false;
    }
    }

    验证ip

    str=document.RegExpDemo.txtIP.value;
    if(/^(/d{1,3})/.(/d{1,3})/.(/d{1,3})/.(/d{1,3})$/.test(str)==false)
    {
    window.alert('错误的IP地址格式');
    document.RegExpDemo.txtIP.select();
    document.RegExpDemo.txtIP.focus();
    return;
    }
    if(RegExp.$1<1 || RegExp.$1>254||RegExp.$2<0||RegExp.$2>254||RegExp.$3<0||RegExp.$3>254||RegExp.$4<1||RegExp.$4>254)
    {
    window.alert('错误的IP地址');
    document.RegExpDemo.txtIP.select();
    document.RegExpDemo.txtIP.focus();
    return;
    }
    //剔除 如 010.020.020.03 前面 的0
    var str=str.replace(/0(/d)/g,"$1");
    str=str.replace(/0(/d)/g,"$1");
    window.alert(str);


    //一下是取数据的类
    //Obj参数指定数据的来源(限定Table),默认第一行为字段名称行
    //GetTableData类提供MoveNext方法,参数是表的行向上或向下移动的位数,正数向下移动,负数向上.
    //GetFieldData方法获得指定的列名的数据
    //Sort_desc方法对指定的列按降序排列
    //Sort_asc方法对指定的列按升序排列
    //GetData方法返回字段值为特定值的数据数组,提供数据,可以在外部进行其他处理
    //Delete方法删除当前记录,数组减少一行
    //初始化,Obj:table的名字,Leftlen:左面多余数据长度,Rightlen:右面多余数据长度,
    function GetTableData(Obj,LeftLen,RightLen){
    var MyObj=document.all(Obj);
    var iRow=MyObj.rows.length;
    var iLen=MyObj.rows[0].cells.length;
    var i,j;

    TableData=new Array();
    for (i=0;i< iRow;i++){
    TableData[i]=new Array();
    for (j=0;j<iLen;j++){
    TableStr=MyObj.rows(i).cells(j).innerText;
    TableStr=TableStr.substring(LeftLen, TableStr.length-RightLen).Trim();
    TableStr=TableStr.replace(/ /gi,"").replace(//r/n/ig,"");
    TableData[i][j]=TableStr;
    }
    }

    this.TableData=TableData;
    this.cols=this.TableData[0].length;
    this.rows=this.TableData.length;
    this.rowindex=0;
    }


    function movenext(Step){
    if (this.rowindex>=this.rows){
    return
    }

    if (Step=="" || typeof(Step)=="undefined") {
    if (this.rowindex<this.rows-1)
    this.rowindex++;
    return;

    }
    else{
    if (this.rowindex + Step<=this.rows-1 && this.rowindex + Step>=0 ){
    this.rowindex=this.rowindex + Step;
    }
    else
    {
    if (this.rowindex + Step<0){
    this.rowindex= 0;
    return;
    }
    if (this.rowindex + Step>this.rows-1){
    this.rowindex= this.rows-1;
    return;
    }
    }
    }
    }


    function getfielddata(Field){
    var colindex=-1;
    var i=0;
    if (typeof(Field) == "number"){
    colindex=Field;
    }
    else
    {
    for (i=0;i<this.cols && this.rowindex<this.rows ;i++){
    if (this.TableData[0][i]==Field){
    colindex=i;
    break;
    }
    }
    }
    if (colindex!=-1) {
    return this.TableData[this.rowindex][colindex];
    }

    }



    function sort_desc(){//降序
    var colindex=-1;
    var highindex=-1;
    desc_array=new Array();
    var i,j;
    for (n=0; n<arguments.length; n++){
    Field=arguments[arguments.length-1-n];
    for (i=0;i<this.cols;i++){
    if (this.TableData[0][i]==Field){
    colindex=i;
    break;
    }
    }
    if ( colindex==-1 )
    return;
    else
    {
    desc_array[0]=this.TableData[0];
    for(i=1;i<this.rows;i++){
    desc_array[i]=this.TableData[1];
    highindex=1;
    for(j=1;j<this.TableData.length;j++){
    if (desc_array[i][colindex]<this.TableData[j][colindex]){
    desc_array[i]=this.TableData[j];
    highindex=j;
    }

    }
    if (highindex!=-1)
    this.TableData=this.TableData.slice(0,highindex).concat(this.TableData.slice(highindex+1,this.TableData.length));
    }
    }


    this.TableData=desc_array;
    }
    return;
    }



    function sort_asc(){//升序
    var colindex=-1;
    var highindex=-1;
    var i,j;
    for (n=0; n<arguments.length; n++){
    asc_array=new Array();
    Field=arguments[arguments.length-1-n];
    for (i=0;i<this.cols;i++){
    if (this.TableData[0][i]==Field){
    colindex=i;
    break;
    }
    }
    if ( colindex==-1 )
    return;
    else
    {
    asc_array[0]=this.TableData[0];
    for(i=1;i<this.rows;i++){
    asc_array[i]=this.TableData[1];
    highindex=1;
    for(j=1;j<this.TableData.length;j++){//找出最小的列值
    if (asc_array[i][colindex]>this.TableData[j][colindex]){
    asc_array[i]=this.TableData[j];
    highindex=j;

    }

    }
    if (highindex!=-1)
    this.TableData=this.TableData.slice(0,highindex).concat(this.TableData.slice(highindex+1,this.TableData.length));

    }
    }


    this.TableData=asc_array;
    }
    return;
    }



    function getData(Field,FieldValue){
    var colindex=-1;
    var i,j;

    GetData=new Array();
    if (typeof(Field)=="undefined" || typeof(FieldValue)=="undefined" ){
    return this.TableData;
    }

    for(j=0;j<this.cols;j++){
    if (this.TableData[0][j]==Field){
    colindex=j;
    }
    }
    if (colindex!=-1){

    for(i=1;i<this.rows;i++){
    if (this.TableData[i][colindex]==FieldValue){
    GetData[i]=new Array();
    GetData[i]=this.TableData[i];
    }
    }
    }
    return GetData;
    }
    function DeletE(){
    this.TableData=this.TableData.slice(0,this.rowindex).concat(this.TableData.slice(this.rowindex+1,this.TableData.length));
    this.rows=this.TableData.length;
    return;
    }
    function updateField(Field,FieldValue){
    var colindex=-1;
    var i=0;
    if (typeof(Field) == "number"){
    colindex=Field;
    }
    else
    {
    for (i=0;i<this.cols && this.rowindex<this.rows ;i++){
    if (this.TableData[0][i]==Field){
    colindex=i;
    break;
    }
    }
    }
    if (colindex!=-1) {
    this.TableData[this.rowindex][colindex]=FieldValue;
    }


    }
    function movefirst(){
    this.rowindex=0;
    }
    function movelast(){
    this.rowindex=this.rows-1;
    }
    function String.prototype.Trim() {return this.replace(/(^/s*)|(/s*$)/g,"");}
    GetTableData.prototype.MoveNext = movenext;
    GetTableData.prototype.GetFieldData = getfielddata;
    GetTableData.prototype.Sort_asc = sort_asc;
    GetTableData.prototype.Sort_desc = sort_desc;
    GetTableData.prototype.GetData = getData;
    GetTableData.prototype.Delete = DeletE;
    GetTableData.prototype.UpdateField = updateField;
    GetTableData.prototype.MoveFirst = movefirst;

    具体的例子:http://202.119.73.208/NetEAn/com/test/jsprint.htm

    在每个文本框的onblur事件中调用校验代码,并且每个文本框中onKeyDown事件中写一个enter转tab函数

    //回车键换为tab
    function enterToTab()
    {
    if(event.srcElement.type != 'button' && event.srcElement.type != 'textarea'
    && event.keyCode == 13)
    {
    event.keyCode = 9;
    }

    2007/7/5

    SQL的自动生成卡号和密码

    declare @i bigint,@j int,@str nvarchar(160) ,@int_temp int,@str_temp nvarchar(10),@Card_NO nvarchar(10)
    ;
    set @i = 10200001;
    while (@i<=10250000)
    begin
    set @j = 0;
    set @str='';
    while (@j<=16)
    begin
    set @int_temp=rand()*9;
    set @str_temp=str(@int_temp);
    set @str=@str+@str_temp;
    set @j=@j+1;
    end
    set @Card_NO=str(@i);
    set @str=replace(@str,' ','');
    insert into IN_Card (Card_No,[Password],[Value])values(@Card_NO,@str,100);
    set @i=@i+1;
    2007/3/17

    Asp.Net防止刷新重复提交数据

      最近在用Asp.Net编写点东西时遇到个问题:即用户在提交表单后按刷新就会重复提交数据,即所谓的“刷新重复提交”的问题。在网上搜 一下,可以找到很多关于这方面的资料,其中有一篇是来自MSDN上的一种解决方法: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/BedrockASPNET.asp 它是通过重新定义 System.Web.UI.Page 类来实现加载页面时,是“刷新”、“后退”请求,还是正常请求,其他的页面则继承了自定义的这 个Page类。感觉他这个方法比较独特,有例子可以下载,有兴趣的可以研究研究。
    网上最多的解决此类问题的方法就是不保存缓存,即提交后表单上的数据不会被浏览器的缓存保存,如果此时再遇到刷新或者后退请求时, 就会显示“网页已过期”,数据也就不会重复提交了,这就起到了阻止刷新重复提交的效果。
    下面以简单的提交一篇帖子为例,介绍禁用缓存防止刷新重复提交的方法,表单数据包括“标题”和“正文”两个部分。
    以下是该方法的代码(post.aspx):

    CODE:
    //页面加载
    protected void Page_Load(object sender, EventArgs e)
    {
       //可以在页面加载时设置页面的缓存为“SetNoStore()”,即无缓存
       Response.Cache.SetNoStore();
       //Session中存储的变量“IsSubmit”是标记是否提交成功的
       if ((bool)Session["IsSubmit"])
       {
         //如果表单数据提交成功,就设“Session["IsSubmit"]”为false
         Session["IsSubmit"] = false;
         //显示提交成功信息
         ShowMsg.Text = " * 提交成功!";
       }
       else
         //否则的话(没有提交,或者是页面刷新),不显示任何信息
         ShowMsg.Text = "";
    }
    //提交按钮(btnOK)单击事件
    protected void btnOK_Click(object sender, EventArgs e)
    {
       if (txtTitle.Text.ToString().Trim() == "")
         //ShowMsg是用来显示提示信息的
         ShowMsg.Text = " * 标题不能为空!";
      else if (txtText.Text.ToString().Trim() == "")
         ShowMsg.Text = " * 内容不能为空!";
      else
       {
         //这里是将数据提交到数据库中,省略
         /*
         string sql = "insert into tab...values(...)";
         MyConn.ExecQuery(sql);
         */
         //提交成功后,设“Session["IsSubmit"]”为true
         Session["IsSubmit"] = true;
         //强制转换页面(不可少,否则刷新仍会重复提交,仍转到本页),
         通过页面的转换将缓存中的提交的数据都释放了,即提交的标单数据不会被保存到缓存里,
         如果后退的话,将会出现该页无法显示
         Response.Redirect("post.aspx");
      }
    }

    上面这个方法非常简单也很实用,推荐大家使用。
    下面是我自己研究出来的另一种方法,该方法不同于“不保存缓存的方法”,它是让浏览器保存所有页面缓存的。该方法通过随机码的方式 来判断是正常提交还是“刷新”或“后退”的。
    首先(提交页面是post.aspx)在 Session 中 增加变量 Rnd 用来存放随机码,同时在提交表单数据时不做处理,而是让页面转到 post.aspx?r=x,这里“x”等于Session["Rnd"],这个时候在页面加载时,通过判断r的值和Session["Rnd"]的值是否相同,如果相同就处理提 交的数据,否则即可认为是“刷新”或者是“后退”操作了,最后再次付给Session["Rnd"]一个随机码。
    以下是该方法代码(post.aspx):
     
    CODE:
    //获取随机码
    public class MyRnd
    {
       public static string Rnd()
       {
         //随机码是由 0-9 a-z A-Z 之间的数字或字母组成的
         //下面是生成的20位随机码
         //0..9 A..Z a..z
         //48-57 65-90 97-122
         string rst = "";
         Random rr = new Random();
         for (int i = 0; i < 20; i++)
         {
           int ir = 0;
           do
           {
             ir = rr.Next(123);
             if((ir >= 48) && (ir <= 57)) break;
             else if((ir >= 65) && (ir <= 90)) break;
             else if ((ir >= 97) && (ir <= 122)) break;
           }
           while (true);
           rst += ((char)ir).ToString();
           }
         return rst;
       }
    }
    //页面加载
    protected void Page_Load(object sender, EventArgs e)
    {
       //获取URL中请求的“r”值,如果“r”不存在则 r=""
       string r = "";
       if(Request.QueryString["r"] != null)
         r = Request.QueryString["r"].ToString().Trim();
       string t;
       //获取 “Session” 中的 “Rnd” 值,用于和“r”比较
       t = Session["Rnd"].ToString().Trim();
       //如果“r=t”则为提交操作,即可对表单的数据进行处理
      if(r == t)
      {
         if (txtTitle.Text.ToString().Trim() == "")
           ShowMsg.Text = " * 标题不能为空!";
         else if (txtText.Text.ToString().Trim() == "")
           ShowMsg.Text = " * 内容不能为空!";
         else      {
           //这里是将数据提交到数据库中,省略
           /*
           string sql = "insert into tab...values(...)";
           MyConn.ExecQuery(sql);
           */
           //提交成功后清空表单数据
           txtTitle.Text = "";
           txtText.Text = "";
           //显示提交成功信息
           ShowMsg.Text = " * 提交成功!";
         }
      }
       //否则可以认为是“刷新”或者“后退”操作
       else
       {
           txtTitle.Text = "";
           txtText.Text = "";
      }
      //最后要重新获得“Session["Rnd"]”的值,并将“btnOK.PostBackUrl”设为“Session["Rnd"]”的值
      Session["Rnd"] = MyRnd.Rnd();
      btnOK.PostBackUrl ="post.aspx?r=" + Session["Rnd"].ToString().Trim();
    }
    //这里提交按钮(btnOK)单击事件就不需要写任何代码了

    通过这种方法,每次加载页面时“Session["Rnd"]”都将得到一个新的值,而在刷新或后退时就不会得到相同的“r”和“t”值,数据也就 不会被重复提交,只有通过“btnOK”来提交的操作才会得到“r==t”,数据才会被提交处理的,通过判断随机码的方式来阻止刷新重复提交就 可以实现了。
    2007/2/8

    提高SQL Server性能

    有时,为了让应用程序运行得更快,所做的全部工作就是在这里或那里做一些很小调整。但关键在于确定如何进行调整!迟早您会遇到这种情况:应用程序中的 SQL 查询不能按照您想要的方式进行响应。它要么不返回数据,要么耗费的时间长得出奇。如果它降低了企业应用程序的速度,用户必须等待很长时间。用户希望应用程序响应迅速,他们的报告能够在瞬间之内返回分析数据。就我自己而言,如果在Web上冲浪时某个页面要耗费十多秒才能加载,我也会很不耐烦。

      为了解决这些问题,重要的是找到问题的根源。那么,从哪里开始呢?根本原因通常在于数据库设计和访问它的查询。我将讲述四项技术,这些技术可用于提高基于SQL Server的应用程序的性能或改善其可伸缩性。我将仔细说明 LEFT JOIN、CROSS JOIN 的使用以及IDENTITY 值的检索。请记住,根本没有神奇的解决方案。调整您的数据库及其查询需要占用时间、进行分析,还需要大量的测试。这些技术都已被证明行之有效,但对您的应用程序而言,可能其中一些技术比另一些技术更适用。

      从 INSERT 返回 IDENTITY

      我决定从遇到许多问题的内容入手:如何在执行SQL INSERT后检索IDENTITY值。通常,问题不在于如何编写检索值的查询,而在于在哪里以及何时进行检索。在SQL Server中,下面的语句可用于检索由最新在活动数据库连接上运行的 SQL 语句所创建的 IDENTITY 值:

      SELECT @@IDENTITY

      这个 SQL 语句并不复杂,但需要记住的一点是:如果这个最新的 SQL 语句不是 INSERT,或者您针对非 INSERT SQL 的其他连接运行了此 SQL,则不会获得期望的值。您必须运行下列代码才能检索紧跟在 INSERT SQL 之后且位于同一连接上的 IDENTITY,如下所示:

      INSERT INTO Products (ProductName) VALUES ('Chalk')

      SELECT @@IDENTITY

      在一个连接上针对 Northwind 数据库运行这些查询将返回一个名称为 Chalk 的新产品的 IDENTITY 值。所以,在使用ADOVisual Basic应用程序中,可以运行以下语句:

      Set oRs = oCn.Execute("SET NOCOUNT ON;INSERT INTO Products _

      (ProductName) VALUES ('Chalk');SELECT @@IDENTITY")

      lProductID = oRs(0) 

      此代码告诉 SQL Server 不要返回查询的行计数,然后执行 INSERT 语句,并返回刚刚为这个新行创建的 IDENTITY 值。SET NOCOUNT ON 语句表示返回的记录集有一行和一列,其中包含了这个新的 IDENTITY 值。如果没有此语句,则会首先返回一个空的记录集(因为 INSERT 语句不返回任何数据),然后会返回第二个记录集,第二个记录集中包含 IDENTITY 值。这可能有些令人困惑,尤其是因为您从来就没有希望过 INSERT 会返回记录集。之所以会发生此情况,是因为 SQL Server 看到了这个行计数(即一行受到影响)并将其解释为表示一个记录集。因此,真正的数据被推回到了第二个记录集。当然您可以使用 ADO 中的 NextRecordset 方法获取此第二个记录集,但如果总能够首先返回该记录集且只返回该记录集,则会更方便,也更有效率。

      此方法虽然有效,但需要在 SQL 语句中额外添加一些代码。获得相同结果的另一方法是在 INSERT 之前使用 SET NOCOUNT ON 语句,并将 SELECT @@IDENTITY 语句放在表中的 FOR INSERT 触发器中,如下面的代码片段所示。这样,任何进入该表的 INSERT 语句都将自动返回 IDENTITY 值。

      CREATE TRIGGER trProducts_Insert ON Products FOR INSERT AS

      SELECT @@IDENTITY

      GO

      触发器只在 Products 表上发生 INSERT 时启动,所以它总是会在成功 INSERT 之后返回一个 IDENTITY。使用此技术,您可以始终以相同的方式在应用程序中检索 IDENTITY 值。

    内嵌视图与临时表

      某些时候,查询需要将数据与其他一些可能只能通过执行 GROUP BY 然后执行标准查询才能收集的数据进行联接。例如,如果要查询最新五个定单的有关信息,您首先需要知道是哪些定单。这可以使用返回定单 ID 的 SQL 查询来检索。此数据就会存储在临时表(这是一个常用技术)中,然后与 Products 表进行联接,以返回这些定单售出的产品数量:

      CREATE TABLE #Temp1 (OrderID INT NOT NULL, _

      OrderDate DATETIME NOT NULL)

      INSERT INTO #Temp1 (OrderID, OrderDate)

      SELECT TOP 5 o.OrderID, o.OrderDate

      FROM Orders o ORDER BY o.OrderDate DESC

      SELECT p.ProductName, SUM(od.Quantity) AS ProductQuantity

      FROM #Temp1 t

      INNER JOIN [Order Details] od ON t.OrderID = od.OrderID

      INNER JOIN Products p ON od.ProductID = p.ProductID

      GROUP BY p.ProductName

      ORDER BY p.ProductName

      DROP TABLE #Temp1

      这些 SQL 语句会创建一个临时表,将数据插入该表中,将其他数据与该表进行联接,然后除去该临时表。这会导致此查询进行大量 I/O 操作,因此,可以重新编写查询,使用内嵌视图取代临时表。内嵌视图只是一个可以联接到 FROM 子句中的查询。所以,您不用在 tempdb 中的临时表上耗费大量 I/O 和磁盘访问,而可以使用内嵌视图得到同样的结果:

      SELECT p.ProductName,

      SUM(od.Quantity) AS ProductQuantity

      FROM (

      SELECT TOP 5 o.OrderID, o.OrderDate

      FROM Orders o

      ORDER BY o.OrderDate DESC

      ) t

      INNER JOIN [Order Details] od ON t.OrderID = od.OrderID

      INNER JOIN Products p ON od.ProductID = p.ProductID

      GROUP BY

      p.ProductName

      ORDER BY

      p.ProductName

      此查询不仅比前面的查询效率更高,而且长度更短。临时表会消耗大量资源。如果只需要将数据联接到其他查询,则可以试试使用内嵌视图,以节省资源。

      避免 LEFT JOIN 和 NULL

      当然,有很多时候您需要执行 LEFT JOIN 和使用 NULL 值。但是,它们并不适用于所有情况。改变 SQL 查询的构建方式可能会产生将一个花几分钟运行的报告缩短到只花几秒钟这样的天壤之别的效果。有时,必须在查询中调整数据的形态,使之适应应用程序所要求的显示方式。虽然 TABLE 数据类型会减少大量占用资源的情况,但在查询中还有许多区域可以进行优化。SQL 的一个有价值的常用功能是 LEFT JOIN。它可以用于检索第一个表中的所有行、第二个表中所有匹配的行、以及第二个表中与第一个表不匹配的所有行。例如,如果希望返回每个客户及其定单,使用 LEFT JOIN 则可以显示有定单和没有定单的客户。

      此工具可能会被过度使用。LEFT JOIN 消耗的资源非常之多,因为它们包含与 NULL(不存在)数据匹配的数据。在某些情况下,这是不可避免的,但是代价可能非常高。LEFT JOIN 比 INNER JOIN 消耗资源更多,所以如果您可以重新编写查询以使得该查询不使用任何 LEFT JOIN,则会得到非常可观的回报。

      加快使用 LEFT JOIN 的查询速度的一项技术涉及创建一个 TABLE 数据类型,插入第一个表(LEFT JOIN 左侧的表)中的所有行,然后使用第二个表中的值更新 TABLE 数据类型。此技术是一个两步的过程,但与标准的 LEFT JOIN 相比,可以节省大量时间。一个很好的规则是尝试各种不同的技术并记录每种技术所需的时间,直到获得用于您的应用程序的执行性能最佳的查询。

      测试查询的速度时,有必要多次运行此查询,然后取一个平均值。因为查询(或存储过程)可能会存储在 SQL Server 内存中的过程缓存中,因此第一次尝试耗费的时间好像稍长一些,而所有后续尝试耗费的时间都较短。另外,运行您的查询时,可能正在针对相同的表运行其他查询。当其他查询锁定和解锁这些表时,可能会导致您的查询要排队等待。例如,如果您进行查询时某人正在更新此表中的数据,则在更新提交时您的查询可能需要耗费更长时间来执行。

      避免使用 LEFT JOIN 时速度降低的最简单方法是尽可能多地围绕它们设计数据库。例如,假设某一产品可能具有类别也可能没有类别。如果 Products 表存储了其类别的 ID,而没有用于某个特定产品的类别,则您可以在字段中存储 NULL 值。然后您必须执行 LEFT JOIN 来获取所有产品及其类别。您可以创建一个值为“No Category”的类别,从而指定外键关系不允许 NULL 值。通过执行上述操作,现在您就可以使用 INNER JOIN 检索所有产品及其类别了。虽然这看起来好像是一个带有多余数据的变通方法,但可能是一个很有价值的技术,因为它可以消除 SQL 批处理语句中消耗资源较多的 LEFT JOIN。在数据库中全部使用此概念可以为您节省大量的处理时间。请记住,对于您的用户而言,即使几秒钟的时间也非常重要,因为当您有许多用户正在访问同一个联机数据库应用程序时,这几秒钟实际上的意义会非常重大。

    灵活使用笛卡尔乘积

      对于此技巧,我将进行非常详细的介绍,并提倡在某些情况下使用笛卡尔乘积。出于某些原因,笛卡尔乘积 (CROSS JOIN) 遭到了很多谴责,开发人员通常会被警告根本就不要使用它们。在许多情况下,它们消耗的资源太多,从而无法高效使用。但是像 SQL 中的任何工具一样,如果正确使用,它们也会很有价值。例如,如果您想运行一个返回每月数据(即使某一特定月份客户没有定单也要返回)的查询,您就可以很方便地使用笛卡尔乘积。

      虽然这看起来好像没什么神奇的,但是请考虑一下,如果您从客户到定单(这些定单按月份进行分组并对销售额进行小计)进行了标准的 INNER JOIN,则只会获得客户有定单的月份。因此,对于客户未订购任何产品的月份,您不会获得 0 值。如果您想为每个客户都绘制一个图,以显示每个月和该月销售额,则可能希望此图包括月销售额为 0 的月份,以便直观标识出这些月份。如果使用 Figure 2(最后一页) 中的 SQL,数据则会跳过销售额为 0 美元的月份,因为在定单表中对于零销售额不会包含任何行(假设您只存储发生的事件)。

      Figure 3(最后一页)中的代码虽然较长,但是可以达到获取所有销售数据(甚至包括没有销售额的月份)的目标。首先,它会提取去年所有月份的列表,然后将它们放入第一个 TABLE 数据类型表 (@tblMonths) 中。下一步,此代码会获取在该时间段内有销售额的所有客户公司的名称列表,然后将它们放入另一个 TABLE 数据类型表 (@tblCus-tomers) 中。这两个表存储了创建结果集所必需的所有基本数据,但实际销售数量除外。 第一个表中列出了所有月份(12 行),第二个表中列出了这个时间段内有销售额的所有客户(对于我是 81 个)。并非每个客户在过去 12 个月中的每个月都购买了产品,所以,执行 INNER JOIN 或 LEFT JOIN 不会返回每个月的每个客户。这些操作只会返回购买产品的客户和月份。

      笛卡尔乘积则可以返回所有月份的所有客户。笛卡尔乘积基本上是将第一个表与第二个表相乘,生成一个行集合,其中包含第一个表中的行数与第二个表中的行数相乘的结果。因此,笛卡尔乘积会向表 @tblFinal 返回 972 行。最后的步骤是使用此日期范围内每个客户的月销售额总计更新 @tblFinal 表,以及选择最终的行集。

      如果由于笛卡尔乘积占用的资源可能会很多,而不需要真正的笛卡尔乘积,则可以谨慎地使用 CROSS JOIN。例如,如果对产品和类别执行了 CROSS JOIN,然后使用 WHERE 子句、DISTINCT 或 GROUP BY 来筛选出大多数行,那么使用 INNER JOIN 会获得同样的结果,而且效率高得多。如果需要为所有的可能性都返回数据(例如在您希望使用每月销售日期填充一个图表时),则笛卡尔乘积可能会非常有帮助。但是,您不应该将它们用于其他用途,因为在大多数方案中 INNER JOIN 的效率要高得多。

      拾遗补零

      这里介绍其他一些可帮助提高 SQL 查询效率的常用技术。假设您将按区域对所有销售人员进行分组并将他们的销售额进行小计,但是您只想要那些数据库中标记为处于活动状态的销售人员。您可以按区域对销售人员分组,并使用 HAVING 子句消除那些未处于活动状态的销售人员,也可以在 WHERE 子句中执行此操作。在 WHERE 子句中执行此操作会减少需要分组的行数,所以比在 HAVING 子句中执行此操作效率更高。HAVING 子句中基于行的条件的筛选会强制查询对那些在 WHERE 子句中会被去除的数据进行分组。

      另一个提高效率的技巧是使用 DISTINCT 关键字查找数据行的单独报表,来代替使用 GROUP BY 子句。在这种情况下,使用 DISTINCT 关键字的 SQL 效率更高。请在需要计算聚合函数(SUM、COUNT、MAX 等)的情况下再使用 GROUP BY。另外,如果您的查询总是自己返回一个唯一的行,则不要使用 DISTINCT 关键字。在这种情况下,DISTINCT 关键字只会增加系统开销。

      您已经看到了,有大量技术都可用于优化查询和实现特定的业务规则,技巧就是进行一些尝试,然后比较它们的性能。最重要的是要测试、测试、再测试。

    Figure 2 Returning All Customers and Their Sales

    set nocount on

    DECLARE @dtStartDate DATETIME,

    @dtEndDate DATETIME,

    @dtDate DATETIME

    SET @dtEndDate = '5/5/1997'

    SET @dtEndDate = DATEADD(DD, -1, CAST(CAST((MONTH(@dtEndDate) + 1)

    AS VARCHAR(2)) + '/01/' + CAST(YEAR(@dtEndDate) AS VARCHAR(4)) + '

    23:59:59' AS DATETIME))

    SET @dtStartDate = DATEADD(MM, -1 * 12, @dtEndDate)

    SELECT CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +

    CASE

    WHEN MONTH(o.OrderDate) < 10

    THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))

    ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))

    END AS sMonth,

    c.CustomerID,

    c.CompanyName,

    c.ContactName,

    SUM(od.Quantity * od.UnitPrice) AS mSales

    FROM Customers c

    INNER JOIN Orders o ON c.CustomerID = o.CustomerID

    INNER JOIN [Order Details] od ON o.OrderID = od.OrderID

    WHERE o.OrderDate BETWEEN @dtStartDate AND @dtEndDate

    GROUP BY

    CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +

    CASE

    WHEN MONTH(o.OrderDate) < 10

    THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))

    ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))

    END,

    c.CustomerID,

    c.CompanyName,

    c.ContactName

    ORDER BY

    c.CompanyName,

    sMonth-------------------------------------------------------------------------------------------------------------------------------------

    Figure 3 Cartesian Product at Work

    DECLARE @tblMonths TABLE (sMonth VARCHAR(7))

    DECLARE @tblCustomers TABLE ( CustomerID CHAR(10),

    CompanyName VARCHAR(50),

    ContactName VARCHAR(50))

    DECLARE @tblFinal TABLE ( sMonth VARCHAR(7),

    CustomerID CHAR(10),

    CompanyName VARCHAR(50),

    ContactName VARCHAR(50),

    mSales MONEY)

    DECLARE @dtStartDate DATETIME,

    @dtEndDate DATETIME,

    @dtDate DATETIME,

    @i INTEGER

    SET @dtEndDate = '5/5/1997'

    SET @dtEndDate = DATEADD(DD, -1, CAST(CAST((MONTH(@dtEndDate) + 1) AS

    VARCHAR(2)) + '/01/' + CAST(YEAR(@dtEndDate) AS VARCHAR(4)) + '

    23:59:59' AS DATETIME))

    SET @dtStartDate = DATEADD(MM, -1 * 12, @dtEndDate)

    — Get all months into the first table

    SET @i = 0

    WHILE (@i < 12)

    BEGIN

    SET @dtDate = DATEADD(mm, -1 * @i, @dtEndDate)

    INSERT INTO @tblMonths SELECT CAST(YEAR(@dtDate) AS VARCHAR(4)) + '-' +

    CASE

    WHEN MONTH(@dtDate) < 10

    THEN '0' + CAST(MONTH(@dtDate) AS VARCHAR(2))

    ELSE CAST(MONTH(@dtDate) AS VARCHAR(2))

    END AS sMonth

    SET @i = @i + 1

    END

    — Get all clients who had sales during that period into the "y" table

    INSERT INTO @tblCustomers

    SELECT DISTINCT

    c.CustomerID,

    c.CompanyName,

    c.ContactName

    FROM Customers c

    INNER JOIN Orders o ON c.CustomerID = o.CustomerID

    WHERE o.OrderDate BETWEEN @dtStartDate AND @dtEndDate

    INSERT INTO @tblFinal

    SELECT m.sMonth,

    c.CustomerID,

    c.CompanyName,

    c.ContactName,

    0

    FROM @tblMonths m CROSS JOIN @tblCustomers c

     

    UPDATE @tblFinal SET

    mSales = mydata.mSales

    FROM @tblFinal f INNER JOIN

    (

    SELECT c.CustomerID,

    CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +

    CASE WHEN MONTH(o.OrderDate) < 10

    THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))

    ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))

    END AS sMonth,

    SUM(od.Quantity * od.UnitPrice) AS mSales

    FROM Customers c

    INNER JOIN Orders o ON c.CustomerID = o.CustomerID

    INNER JOIN [Order Details] od ON o.OrderID = od.OrderID

    WHERE o.OrderDate BETWEEN @dtStartDate AND @dtEndDate

    GROUP BY

    c.CustomerID,

    CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +

    CASE WHEN MONTH(o.OrderDate) < 10

    THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))

    ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))

    END

    ) mydata on f.CustomerID = mydata.CustomerID AND f.sMonth =

    mydata.sMonth

    SELECT f.sMonth,

    f.CustomerID,

    f.CompanyName,

    f.ContactName,

    f.mSales

    FROM @tblFinal f

    ORDER BY

    f.CompanyName,

    f.sMonth

    SQL Server存储过程

    首先介绍一下什么是存储过程:存储过程就是将常用的或很复杂的工作,预先用SQL语句写好并用一个指定的名称存储起来,并且这样的语句是放在数据库中的,还可以根据条件执行不同SQL语句,那么以后要叫数据库提供与已定义好的存储过程的功能相同的服务时,只需调用execute,即可自动完成命令。

      请大家来了解一下存储过程的语法。

      CREATE PROC [ EDURE ] procedure_name [ ; number ]
    [ { @parameter data_type }
    [ VARYING ] [ = default ] [ OUTPUT ]
    ] [ ,...n ]

      [ WITH
    { RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ]

      [ FOR REPLICATION ]

      AS sql_statement [ ...n ]

      参数:

      procedure_name

      新存储过程的名称。过程名必须符合标识符规则,且对于数据库及其所有者必须唯一。

      要创建局部临时过程,可以在 procedure_name 前面加一个编号符 (#procedure_name),要创建全局临时过程,可以在 procedure_name 前面加两个编号符 (##procedure_name)。完整的名称(包括 # 或 ##)不能超过 128 个字符。指定过程所有者的名称是可选的。

      ;number

      是可选的整数,用来对同名的过程分组,以便用一条 DROP PROCEDURE 语句即可将同组的过程一起除去。例如,名为 orders 的应用程序使用的过程可以命名为 orderproc;1、orderproc;2 等。DROP PROCEDURE orderproc 语句将除去整个组。如果名称中包含定界标识符,则数字不应包含在标识符中,只应在 procedure_name 前后使用适当的定界符。

      @parameter

      过程中的参数。在 CREATE PROCEDURE 语句中可以声明一个或多个参数。用户必须在执行过程时提供每个所声明参数的值(除非定义了该参数的默认值)。存储过程最多可以有 2100 个参数。

      使用@符号作为第一个字符来指定参数名称。参数名称必须符合标识符的规则。每个过程的参数仅用于该过程本身;相同的参数名称可以用在其它过程中。默认情况下,参数只能代替常量,而不能用于代替表名、列名或其它数据库对象的名称。

      data_type

      参数的数据类型。所有数据类型(包括 text、ntext 和 image)均可以用作存储过程的参数。不过,cursor 数据类型只能用于 OUTPUT 参数。如果指定的数据类型为 cursor,也必须同时指定 VARYING 和 OUTPUT 关键字。

      说明:对于可以是cursor 数据类型的输出参数,没有最大数目的限制。

    VARYING

      指定作为输出参数支持的结果集(由存储过程动态构造,内容可以变化)。仅适用于游标参数。

      default

      参数的默认值。如果定义了默认值,不必指定该参数的值即可执行过程。默认值必须是常量或 NULL。如果过程将对该参数使用 LIKE 关键字,那么默认值中可以包含通配符(%、_、[] 和 [^])。

      OUTPUT

      表明参数是返回参数。该选项的值可以返回给 EXEC[UTE]。使用 OUTPUT 参数可将信息返回给调用过程。Text、ntext 和 image 参数可用作 OUTPUT 参数。使用 OUTPUT 关键字的输出参数可以是游标占位符。

      n

      表示最多可以指定 2100 个参数的占位符。

      {RECOMPILE | ENCRYPTION | RECOMPILE, ENCRYPTION}
    RECOMPILE 表明 SQL Server 不会缓存该过程的计划,该过程将在运行时重新编译。在使用非典型值或临时值而不希望覆盖缓存在内存中的执行计划时,请使用 RECOMPILE 选项。

      ENCRYPTION 表示 SQL Server 加密 syscomments 表中包含 CREATE PROCEDURE 语句文本的条目。使用 ENCRYPTION 可防止将过程作为 SQL Server 复制的一部分发布。

      说明:在升级过程中,SQL Server 利用存储在 syscomments 中的加密注释来重新创建加密过程。

      FOR REPLICATION

      指定不能在订阅服务器上执行为复制创建的存储过程。.使用 FOR REPLICATION 选项创建的存储过程可用作存储过程筛选,且只能在复制过程中执行。本选项不能和 WITH RECOMPILE 选项一起使用。

      AS

      指定过程要执行的操作。

      sql_statement

      过程中要包含的任意数目和类型的 Transact-SQL 语句。但有一些限制。

      n

      是表示此过程可以包含多条 Transact-SQL 语句的占位符。

      注释

      存储过程的最大大小为 128 MB。

    存储过程的优点都有哪些呢?

      1.存储过程只在创造时进行编译即可,以后每次执行存储过程都不需再重新编译,而我们通常使用的SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。

      2.经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作。当对数据库进行复杂操作时(如对多个表进行Update, Insert,Query,Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。可以极大的提高数据库的使用效率,减少程序的执行时间,这一点在较大数据量的数据库的操作中是非常重要的。在代码上看,SQL语句和程序代码语句的分离,可以提高程序代码的可读性。

      3.存储过程可以设置参数,可以根据传入参数的不同重复使用同一个存储过程,从而高效的提高代码的优化率和可读性。

      4.安全性高,可设定只有某此用户才具有对指定存储过程的使用权存储过程的种类:

      (1)系统存储过程:以sp_开头,用来进行系统的各项设定.取得信息.相关管理工作,如 sp_help就是取得指定对象的相关信息。

      (2)扩展存储过程 以XP_开头,用来调用操作系统提供的功能
    exec master..xp_cmdshell 'ping 10.8.16.1'

      (3)用户自定义的存储过程,这是我们所指的存储过程常用格式

      模版:Create procedure procedue_name [@parameter data_type][output]
    [with]{recompile|encryption} as sql_statement

      解释:output:表示此参数是可传回的

      with {recompile|encryption} recompile:表示每次执行此存储过程时都重新编译一次;encryption:所创建的存储过程的内容会被加密。

    实例1:只返回单一记录集的存储过程。

      表银行存款表(bankMoney)的内容如下

    Id

    userID

    Sex

    Money

    001

    Zhangsan

    30

    002

    Wangwu

    50

    003

    Zhangsan

    40

    要求1:查询表bankMoney的内容的存储过程

    create procedure sp_query_bankMoney
    as
    select * from bankMoney
    go
    exec sp_query_bankMoney

    注* 在使用过程中只需要把中的SQL语句替换为存储过程名,就可以了很方便吧!

      实例2(向存储过程中传递参数):

    加入一笔记录到表bankMoney,并查询此表中userID= Zhangsan的所有存款的总金额。

    Create proc insert_bank @param1 char(10),@param2 varchar(20),@param3 varchar(20),@param4 int,@param5 int output
    with encryption ---------加密
    as
    insert bankMoney (id,userID,sex,Money)
    Values(@param1,@param2,@param3, @param4)
    select @param5=sum(Money) from bankMoney where userID='Zhangsan'
    go
    在SQL Server查询分析器中执行该存储过程的方法是:
    declare @total_price int
    exec insert_bank '004','Zhangsan','男',100,@total_price output
    print '总余额为'+convert(varchar,@total_price)
    go

    在这里再啰嗦一下存储过程的3种传回值(方便正在看这个例子的朋友不用再去查看语法内容):

    1.以Return传回整数
    2.以output格式传回参数
    3.Recordset

    传回值的区别:

    output和return都可在批次程式中用变量接收,而recordset则传回到执行批次的客户端中。

    实例3:使用带有复杂 SELECT 语句的简单过程

      下面的存储过程从四个表的联接中返回所有作者(提供了姓名)、出版的书籍以及出版社。该存储过程不使用任何参数。

      USE pubs
    IF EXISTS (SELECT name FROM sysobjects
    WHERE name = 'au_info_all' AND type = 'P')
    DROP PROCEDURE au_info_all
    GO
    CREATE PROCEDURE au_info_all
    AS
    SELECT au_lname, au_fname, title, pub_name
    FROM authors a INNER JOIN titleauthor ta
    ON a.au_id = ta.au_id INNER JOIN titles t
    ON t.title_id = ta.title_id INNER JOIN publishers p
    ON t.pub_id = p.pub_id
    GO

      au_info_all 存储过程可以通过以下方法执行:

      EXECUTE au_info_all
    -- Or
    EXEC au_info_all

      如果该过程是批处理中的第一条语句,则可使用:

      au_info_all

      实例4:使用带有参数的简单过程

      CREATE PROCEDURE au_info
    @lastname varchar(40),
    @firstname varchar(20)
    AS
    SELECT au_lname, au_fname, title, pub_name
    FROM authors a INNER JOIN titleauthor ta
    ON a.au_id = ta.au_id INNER JOIN titles t
    ON t.title_id = ta.title_id INNER JOIN publishers p
    ON t.pub_id = p.pub_id
    WHERE au_fname = @firstname
    AND au_lname = @lastname
    GO

      au_info 存储过程可以通过以下方法执行:

      EXECUTE au_info 'Dull', 'Ann'
    -- Or
    EXECUTE au_info @lastname = 'Dull', @firstname = 'Ann'
    -- Or
    EXECUTE au_info @firstname = 'Ann', @lastname = 'Dull'
    -- Or
    EXEC au_info 'Dull', 'Ann'
    -- Or
    EXEC au_info @lastname = 'Dull', @firstname = 'Ann'
    -- Or
    EXEC au_info @firstname = 'Ann', @lastname = 'Dull'

      如果该过程是批处理中的第一条语句,则可使用:

      au_info 'Dull', 'Ann'
    -- Or
    au_info @lastname = 'Dull', @firstname = 'Ann'
    -- Or
    au_info @firstname = 'Ann', @lastname = 'Dull'

    实例5:使用带有通配符参数的简单过程

    CREATE PROCEDURE au_info2
    @lastname varchar(30) = 'D%',
    @firstname varchar(18) = '%'
    AS
    SELECT au_lname, au_fname, title, pub_name
    FROM authors a INNER JOIN titleauthor ta
    ON a.au_id = ta.au_id INNER JOIN titles t
    ON t.title_id = ta.title_id INNER JOIN publishers p
    ON t.pub_id = p.pub_id
    WHERE au_fname LIKE @firstname
    AND au_lname LIKE @lastname
    GO

      au_info2 存储过程可以用多种组合执行。下面只列出了部分组合:

      EXECUTE au_info2
    -- Or
    EXECUTE au_info2 'Wh%'
    -- Or
    EXECUTE au_info2 @firstname = 'A%'
    -- Or
    EXECUTE au_info2 '[CK]ars[OE]n'
    -- Or
    EXECUTE au_info2 'Hunter', 'Sheryl'
    -- Or
    EXECUTE au_info2 'H%', 'S%'

      = 'proc2'

    2007/1/4

    Ajax Validate

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="login.aspx.cs" Inherits="AnsonWebShop.Web.login" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
        <link href="App_Themes/AnsonWebShop/test.css" type="text/css" rel="stylesheet" />
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:Label ID="Label1" runat="server" Text="User:"></asp:Label>
            <input id="un" type="text" style="width: 150px" runat="server" οnblur="checkEmailAddress(this.value, true);" /><div id="divE"></div><br />
            <asp:Label ID="Label2" runat="server" Text="Pass:"></asp:Label>
            <input id="pw" style="width: 150px" type="password" runat="server" /><br />
            <input id="Button1" style="width: 184px" runat="server" οnclick="loginin()" value="OK" />&nbsp;&nbsp;
            &nbsp;&nbsp;&nbsp;
            <br />
             <input type="button" name="btNext" id="btNext" οnclick="return checkEmailBorad();" value="Next" class="joinbtn" />
            <br />
          <script language="javascript" type="text/javascript">
        function checkEmailAddress(strValue, isCheck)
    {
        var str = strValue.trim();
        var uu = document.getElementById("un");
        var d = document.getElementById("divEmail");
        if(str.length < 1)
     {
      d.innerHTML = "<div class=/"check/">电子邮件地址不能为空</div>";
      return false;
     }
     else
     {
         var reg = /^/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*$/;
         if(checkReg(reg, str))
         {
             if(isCheck)
             {
                 var url = "CEE.aspx";
              var pars = "EMail=" + StrCode(strValue);
              var acheck = new Ajaxcheck.check({success: "divE"}, url, {method: "post", parameters: pars, onLoading: function(){$("divE").innerHTML = "<div class=/"loading/">检测中,请稍后……</div>";}});
          }
          return true;
         }
         else
         {
             d.innerHTML = "<div class=/"checkerror/">电子邮件地址不合法</div>";
          return false;
         }
     }
    }
    function checkEmailBorad()
    {
        if(checkEmailAddress("un", false))
        {
            
        }
        else
        {
            return false;
        }
    }
          </script>
             </form>
    </body>
    </html>
    2007/1/3

    Ajax Tree

    1.建立一个aspx页面
    html代码

    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head id="Head1" runat="server">
    <title>Ajax Tree</title>
    <link type="text/css" href="../../Styles/tree_css/tree.css" rel="stylesheet">
    </head>
    <body>
    <form id="Form1" runat="server">
    <div class="TreeMenu" id="CategoryTree" style="width: 100%; height: 489px">
    </div>
    <script language="javascript" type="text/javascript">
    function el(id)
    {
    return document.getElementById(id);
    }
    function ExpandSubCategory(iCategoryID)
    {
    var li_father = el("li_" + iCategoryID);
    if (li_father.getElementsByTagName("li").length > 0) //分类已下载
    {
    ChangeStatus(iCategoryID);
    return;
    }

    li_father.className = "Opened";

    switchNote(iCategoryID, true);
    AjaxMethod.GetSubCategory(iCategoryID, GetSubCategory_callback);
    }

    function GetSubCategory_callback(response)
    {
    var dt = response.value.Tables[0];
    if (dt.Rows.length > 0)
    {
    var iCategoryID = dt.Rows[0].FatherID;
    }
    var li_father = el("li_" + iCategoryID);
    var ul = document.createElement("ul");
    for (var i = 0;i < dt.Rows.length;i++)
    {
    if (dt.Rows[i].IsChild == 1) //叶子节点
    {
    var li = document.createElement("li");
    li.className = "Child";
    li.id = "li_" + dt.Rows[i].CategoryID;

    var img = document.createElement("img");
    img.id = dt.Rows[i].CategoryID;
    img.className = "s";
    img.src = "../../Styles/tree_css/s.gif";

    var a = document.createElement("a");
    var id = dt.Rows[i].CategoryID;
    a.onmouseover = function()
    {
    PreviewImage(id);
    };
    a.href = "javascript:OpenDocument('" + dt.Rows[i].CategoryID + "');";
    a.innerHTML = dt.Rows[i].CategoryName;
    }
    else
    {
    var li = document.createElement("li");
    li.className = "Closed";
    li.id = "li_" + dt.Rows[i].CategoryID;

    var img = document.createElement("img");
    img.id = dt.Rows[i].CategoryID;
    img.className = "s";
    img.src = "../../Styles/tree_css/s.gif";
    img.onclick = function () {
    ExpandSubCategory(this.id);
    };
    img.alt = "展开/折叠";

    var a = document.createElement("a");
    a.href = "javascript:ExpandSubCategory(" +
    dt.Rows[i].CategoryID + ");";
    a.innerHTML = dt.Rows[i].CategoryName;
    }
    li.appendChild(img);
    li.appendChild(a);
    ul.appendChild(li);
    }
    li_father.appendChild(ul);

    switchNote(iCategoryID, false);
    }

    // 叶子节点的单击响应函数
    function OpenDocument(iCategoryID)
    {
    // 预加载信息
    PreloadFormUrl(iCategoryID);
    }

    function PreviewImage(iCategoryID)
    {

    }

    function ChangeStatus(iCategoryID)
    {
    var li_father = el("li_" + iCategoryID);
    if (li_father.className == "Closed")
    {
    li_father.className = "Opened";
    }
    else
    {
    li_father.className = "Closed";
    }
    }

    function switchNote(iCategoryID, show)
    {
    var li_father = el("li_" + iCategoryID);
    if (show)
    {
    var ul = document.createElement("ul");
    ul.id = "ul_note_" + iCategoryID;

    var note = document.createElement("li");
    note.className = "Child";

    var img = document.createElement("img");
    img.className = "s";
    img.src = "../../Styles/tree_css/s.gif";

    var a = document.createElement("a");
    a.href = "javascript:void(0);";
    a.innerHTML = "请稍候";

    note.appendChild(img);
    note.appendChild(a);
    ul.appendChild(note);
    li_father.appendChild(ul);
    }
    else
    {
    var ul = el("ul_note_" + iCategoryID);
    if (ul)
    {
    li_father.removeChild(ul);
    }
    }
    }

    // 加载根节点
    var tree = el("CategoryTree");
    var root = document.createElement("li");
    root.id = "li_0";
    tree.appendChild(root);

    // 加载页面时显示第一级分类
    ExpandSubCategory(0);

    function PreloadFormUrl(iCategoryID)
    {
    // 采用同步调用的方式获取图片的信息
    var ds = AjaxMethod.GetFormsList(iCategoryID).value;
    // 如果返回了结果
    if (ds)
    {
    // 判断数据表是否不为空
    if (ds.Tables[0].Rows.length > 0)
    {
    // 返回的信息数据表
    dt = ds.Tables[0];
    el("furl").src = dt.Rows[0].FormUrl;
    }
    else // 分类下没有
    {
    }
    }
    }
    </script>
    </form>
    </body>
    </html>



    2.cs代码

    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using AjaxPro;

    public partial class Pages_Home_HomePage : System.Web.UI.Page
    {
    protected void Page_Load(object sender, EventArgs e)
    {
    AjaxPro.Utility.RegisterTypeForAjax(typeof(AjaxMethod));
    }
    }


    3.建立一个tree.css的css样式

    a
    {
    text-decoration:none;
    }
    a,a:visited
    {
    color:#000;
    background:inherit;
    }
    body
    {
    margin:0;
    padding:20px;
    font:12px tahoma,宋体,sans-serif;
    }
    dt
    {
    font-size:22px;
    font-weight:bold;
    margin:0 0 0 15px;
    }
    dd
    {
    margin:0 0 0 15px;
    }
    h4
    {
    margin:0;
    padding:0;
    font-size:18px;
    text-align:center;
    }
    p
    {
    margin:0;
    padding:0 0 0 18px;
    }
    p a,p a:visited
    {
    color:#00f;
    background:inherit;
    }

    .TreeMenu img.s
    {
    cursor:hand;
    vertical-align:middle;
    }
    .TreeMenu ul
    {
    padding:0;
    }
    .TreeMenu li
    {
    list-style:none;
    padding:0;
    }
    .Closed ul
    {
    display:none;
    }
    .Child img.s
    {
    background:none;
    cursor:default;
    }

    #CategoryTree ul
    {
    margin:0 0 0 17px;
    }
    #CategoryTree img.s
    {
    width:34px;
    height:18px;
    }
    #CategoryTree .Opened img.s
    {
    background:url(skin3/opened.gif) no-repeat 0 1px;
    }
    #CategoryTree .Closed img.s
    {
    background:url(skin3/closed.gif) no-repeat 0 1px;
    }
    #CategoryTree .Child img.s
    {
    background:url(skin3/child.gif) no-repeat 13px 2px;
    }

    #CategoryTree
    {
    float:left;
    width:249px;
    border:1px solid #99BEEF;
    background:#D2E4FC;
    color:inherit;
    margin:3px;
    padding:3px;
    height:600px;
    }


    4.建立一个类AjaxMethod

    using System;
    using System.Data;
    using System.Data.SqlClient;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using AjaxPro;

    /** <summary>
    /// Summary description for AjaxMethod
    /// </summary>
    public class AjaxMethod
    {
    public AjaxMethod()
    {
    //
    // TODO: Add constructor logic here
    //
    }
    [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
    public static DataSet GetSubCategory(int iCategoryID)
    {
    string sql = string.Format("SELECT CategoryID, CategoryName, FatherID, dbo.IsLeaf(CategoryID) as IsChild FROM Category WHERE FatherID = {0}", iCategoryID);
    return GetDataSet(sql);
    }

    [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
    public static DataSet GetFormsList(int iCategoryID)
    {
    string sql = string.Format("SELECT * FROM forms WHERE form_category_id = {0}", iCategoryID);
    return GetDataSet(sql);
    }
    public static string ConnectionString = ConfigurationSettings.AppSettings["ConnectionString"].ToString();

    public static DataSet GetDataSet(string sql)
    {
    SqlDataAdapter sda = new SqlDataAdapter(sql, ConnectionString);
    DataSet ds = new DataSet();
    sda.Fill(ds);
    if (ds != null)
    return ds;
    else
    return null;
    }
    }


    5.sql脚本

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Category]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
    drop table [dbo].[Category]
    GO

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Forms]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
    drop table [dbo].[Forms]
    GO

    CREATE TABLE [dbo].[Category] (
    [CategoryID] [int] IDENTITY (1, 1) NOT NULL ,
    [CategoryName] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
    [FatherID] [int] NULL
    ) ON [PRIMARY]
    GO

    CREATE TABLE [dbo].[Forms] (
    [FormID] [int] IDENTITY (1, 1) NOT NULL ,
    [FormName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
    [FormUrl] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
    [Form_category_id] [int] NULL ,
    [target] [char] (10) COLLATE Chinese_PRC_CI_AS NULL
    ) ON [PRIMARY]
    GO
    CREATE FUNCTION IsLeaf (@cat_id int)
    RETURNS int AS
    BEGIN

    declare @count int
    select @count = (select count(*) from Category where FatherID=@cat_id)
    if (@count=0)
    return 1
    return 0

    END
    2006/12/26

    Ajax DataGrid

    Ajax 实现DataGrid邦定

    1. 在引用中添加引用Ajax.dll
     
    2.在web.config中建立HttpHandler(这个当然是在system.web串里的)
     
    <httpHandlers>
    <add verb="POST,GET" path="ajax/*.ashx" type="Ajax.PageHandlerFactory, Ajax" />
    </httpHandlers>
     
    3.在Global的Application_Start里加上个设置
     
    protected void Application_Start(Object sender, EventArgs e)
    {
     Ajax.Utility.HandlerPath = "ajax";
    }
     
    4.新建一个类DemoMethods,这个类里面提供了更新数据库和输出列表的方法。其实主要思想就是获得控件运行后生成的html,然后输出
     
    [Ajax.AjaxMethod]
    public int AddAjaxTable(string name)
    {
      //输入一个字符串,然后更新
      SqlConnection conn = new SqlConnection( System.Configuration.ConfigurationSettings.AppSettings["connectionString"] );
      SqlCommand cmd = new SqlCommand("insert into ajaxTable(name) values(’"+name+"’)", conn);
      cmd.Connection.Open();
      int result = cmd.ExecuteNonQuery();
      conn.Dispose();
      cmd.Dispose();
      return result;
     }

     [Ajax.AjaxMethod]
     public string GetAjaxTable()
     {
      //这个方法就是拿到datagrid生成出来的html
      SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationSettings.AppSettings["connectionString"]);
      SqlCommand cmd = new SqlCommand("select * from ajaxTable order by id", conn);
      SqlDataAdapter ap = new SqlDataAdapter( cmd );
      DataSet ds = new DataSet();
      ap.SelectCommand.Connection.Open();
      ap.Fill( ds, "db" );

      conn.Dispose();
      cmd.Dispose();

      //实例化一个datagird类并设置好数据源
      DataGrid dg = new DataGrid();
      dg.DataSource = ds.Tables["db"];1 
        dg.DataBind();

      //实例化一个HtmlTextWriter的类
      System.Text.StringBuilder strb = new System.Text.StringBuilder();
      System.IO.StringWriter sw = new System.IO.StringWriter( strb );
      System.Web.UI.HtmlTextWriter htw = new HtmlTextWriter( sw );

      //执行控件的render并输出到HtmlTextWriter里
      dg.RenderControl( htw );

      string s = strb.ToString();

      return s;//最后就是返回这个html啦
     }
     
    5.然后再建一个default.js文件,用作存放 js方法
     
    function AddAjax(name)
    {
     DemoMethods.AddAjaxTable(name);
     LoadGrid();
    }
    function LoadGrid()
    {
     var cc=document.getElementById("UCtd");
     cc.innerHTML=DemoMethods.GetAjaxTable().value;
    }
      
    6.建一个default.aspx,在pageload事件里面加个注册的东西
     
    private void Page_Load(object sender, System.EventArgs e)
    {
     Ajax.Utility.RegisterTypeForAjax(typeof(AjaxTestPrjLib.DemoMethods));
    }
      
    7.最后就是default.aspx的html和js了。
     
    <%@ Page language="c#" Codebehind="default.aspx.cs" AutoEventWireup="false" Inherits="AjaxTextPrjWeb._default" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
    <HTML>
    <HEAD>
     <title>default</title>
     <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
     <meta name="CODE_LANGUAGE" Content="C#">
     <meta name="vs_defaultClientScript" content="JavaScript">
     <meta name="vs_targetSchema" content="
    http://schemas.microsoft.com/intellisense/ie5">
    <script language="javascript" src="default.js"></script>
    </HEAD>
    <body οnlοad="LoadGrid()">
    <form id="Form1" method="post" runat="server">
     <INPUT type="text" id="AddTextBox" maxlength="10"><INPUT type="button" value="添加" οnclick="javascript:AddAjax(form.AddTextBox.value);">
     <table>
      <tr>
       <td id="UCtd"></td>
      </tr>
     </table>
    </form>
    </body>
    </HTML>

    ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页

    ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页
     
    ASP.Net中的DataGrid有内置分页功能, 但是它的默认的分页方式效率是很低的,特别是在数据量很大的时候,用它内置的分页功能几乎是不可能的事,因为它会把所有的数据从数据库读出来再进行分页, 这种只选取了一小部分而丢掉大部分的方法是不可去取的.
    在最进的一个项目中因为一个管理页面要管理的数据量非常大,所以必须分页显示,并且不能用DataGrid的内置分页功能,于是自己实现分页. 下面介绍一下我在项目中用到的分页方法.
    当然显示控件还是用DataGrid的, 因为数据绑定很方便^_^.
    要保证不传输冗余的数据,那么必须在数据库中数据读取时实现分页, 数据库的分页操作可以放在存储过程中. 看了CSDN的一篇Blog中讲了一个百万级数据分页的存储过程的实现(http://blog.csdn.net/wellknow/posts/55167.aspx,他的这个方法可以根据不同情况进行适当的优化), 根据他的方法,这里实现一个简单的SQL语句来实现这里分页需要的存储过程。
    create procedure ListProduct
    (
           @PageIndex int, -- 分页后需要页的序号
           @PageSize int, -- 一页的大小
           @ConditionSQL – 查询条件的SQL语句
    )
     AS … 具体代码就不写了(可以参考上面的链接).
     
    具体的SQL语句如下:
    SELECT TOP 100 * FROM (select * from product where productid<200000) T WHERE T.productid NOT IN
    (SELECT TOP 900 productid FROM (select productid from product where productid<200000) T1 ORDER BY T1.productid asc) ORDER BY productid asc
    这条语句的 从总的商品(30万)中取出productid<200000(共20万),再按每页100的大小分页,然后取出第10页.
     
    Public DataTable ListProduct(int pageIndex, int pageSize)
    {
           //ADO.net从数据库中取出数据的代码就略过^_^.
    }
     
     
    用上面的存储过程读出的数据在DataGrid里面分页, 必须把DataGrid的AllowPaging和AllowCustomPaging设置为true
    protected System.Web.UI.WebControls.DataGrid ProductGrid;
    ProductGrid.AllowPaging = true;
    ProductGrid.AllowCustomPaging = true;
     
    然后在设置要显示的一页的大小
    ProductGrid.PageSize = 100; // 在显示的时候依据实际的数据显示。
    设置一页大小后,如果要让DataGrid实际分出页数来,还必须设置
    ProductGrid.VirtualItemCount = GetProductCount() ; // GetProductCount() 的功能是获取满足条件的产品数目, 这里的条件就是productid<200000. 设置这项属性后,那么这个DataGrid的页数就是
    VirtualItemCount/PageSize, 也就是PageCount的值. 不能对PageCount直接赋值,因为他是只读的属性.
    这些属性设置好后再绑定数据:
    ProductGrid.DataSource = ListProduct(1, ProductGrid.PageSize); // 在Page_Load里面 pageIndex为1,记住判断IsPostBack,在IsPostBack为false时执行这些代码
    ProductGrid.DataBind();
     
    这样数据绑定后就可以看到具有分页模样的页面了.但是还不能真正的分页.要实现真正的分页,还必须实现下面的功能.
     
    处理DataGrid的PageIndexChanged事件(处理用户新选中某页时的事件)
    private void ProductGrid_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
    {
         // 如果在存储过程分页功能中用1表示第一页的序号的话那么这里必须用e.NewPageIndex+1作为pageIndex(如果选择了DataGrid上页号为3的页,那么e.NewPageIndex就为2), 否则的话直接用e.NewPageIndex就可以了
         ProductGrid.DataSource = ListProduct(e.NewPageIndex+1, ProductGrid.PageSize); // 从数据库中读取新的数据
         ProductGrid.DataBind();
         // 设置当前的Page序号值, 如果不设置的话它是不会变得, 这样会给用户造成误解,以为所有页的数据相同。
         ProductGrid.CurrentPageIndex =e.NewPageIndex;
    }
     
    如果你处理了DataGrid的ItemCommand的事件的话,必须在ItemCommand事件处理代码前面加上这些代码:
    if (e.Item.ItemType == ListItemType.Pager)
    {
         return;
    }
    因为当PageIndexChanged事件激发,也就是用户选则了另外一页时会先激发ItemCommand事件,如果不这样处理的话,可能会遇到一些意想不到的情况(如果你确实需要的话也可以上面这段代码,不过最好实际测试一下)。
     
    整个过程完成后,再次浏览页面,觉得速度真是快多了。ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页
     
    运行环境:
    WinXP Pro SP1, SQLServer 2000, .Net Framework 1.1

    Ajax Login Sample

    一、介绍一下Ajax在Asp.Net中的基本使用
        1、在工程中引入Ajax.dll文件。
      Ajax.dll实现XmlHttpRequest请求服务器的实现细节。.net项目中,添加上对其的引用,就可以进
    行相应封装操作了。
        2、在web.config中设置HttpHandle
        <httpHandlers>
          <add verb="POST,GET" path="ajax/*.ashx" type="Ajax.PageHandlerFactory, Ajax"/>
        </httpHandlers>
        3、在 <HEAD>与</HEAD>间加入一些引用如下:
        <script src=js/Xml.js></script>
        <link href="css/myStyle.css" type="text/css" rel="stylesheet">
        <script src="/HttpForAjax/ajax/common.ashx" type="text/javascript"></script>
        <script src="/HttpForAjax/ajax/Ttyu.AjaxData,HttpForAjax.ashx" type="text/javascript"></script>
        二、介绍正题-用户登录验证
        1、前台Html:
    <form id="Form1" method="post" runat="server" action="" οnsubmit="login.GetLogin();return false;">  
        <TABLE id="Table1"  cellSpacing="1" cellPadding="1" width="300" border="1">
         <TR>
          <TD></TD>
          <TD><INPUT type="text"  id="txtUsername">usename</TD>
         </TR>
         <TR>
          <TD></TD>
          <TD><INPUT type="password"  id="txtPassword">pwd</TD>
         </TR>
         <TR>
          <TD></TD>
          <TD><INPUT type="submit" value="登陆"></TD>
         </TR>
        </TABLE>
      </form>
        2、引用Js文件
    <SCRIPT language="javascript" src="login.js" type="text/javascript"></SCRIPT>
      <script language="javascript">
      window.onload = function()
        {
           login=new Login(testAjax);
          }
      </script>
       login.Js文件
    // 提取控件值
    function getValueById(pObjID){
     var obj=document.getElementById(pObjID);
     try{
      return obj.value;
     }catch(e){
      alert("控件:"+pObjID+" 不存在,或没有value属性");
     }
    }
    function Login(obj)
    {
     this.OBJ = obj;
     this.GetLogin=function()
     {
      var returnValue;
      var username=getValueById('txtUsername');
      var password=getValueById('txtPassword');
      if(!username||!password)
      {
       alert('请输入用户名与密码!');
       return;
      } 
      try
      {
       returnValue=this.OBJ.Login(username,password).value;
      }catch(e)
      {
       alert('登录出错,请稍后再试或与管理员联系');
      }
      switch(returnValue)
      {
      
       case 1:
        alert('对不起,您输入的用户名或密码不正确或者不是管理员!');
        break;  
       case 0:
        alert('管理员登录成功!');
        window.document.location.href('../Error.aspx');
        break;  
       default:
        alert('登录失败,请稍后再试或与管理员联系'+returnValue);
        break;
      }
     }
    }
    3、.cs文件
    private void Page_Load(object sender, System.EventArgs e)
      {
       Ajax.Utility.RegisterTypeForAjax(typeof(testAjax));
      }
      [Ajax.AjaxMethod()]
      public int Login(string username,string password)
      {  
       // 管理员登陆入口
       Action.Common.CDB cdb = new Action.Common.CDB();
       if("admin"==cdb.ExeScalar("select upower from users where
    uname='"+username+"' and upwd='"+password+"'"))
        return 0;
       else
        return 1;
      }
     

    Ajax Shopping Cart(2)

    [CS]
     
    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using AW.Components;
    using AjaxPro;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Text;
    using AW.Components.Helpers;
    public partial class _Default : System.Web.UI.Page {
        protected string Key = "ORDERDETAIL_" + CContext.Current.SiteOwnerUserID.ToString();
        protected void Page_Load(object sender, EventArgs e) {
            Utility.RegisterTypeForAjax(typeof(_Default));
            string action = Request["Act"];
            int id;
            if (string.IsNullOrEmpty(action))
                action = "list";
            if (int.TryParse(Request["ID"], out id)) {
                if (action == "add") {
                    CProduct prodcut = CProducts.GetProduct(id, CContext.Current.SiteOwnerUserID);
                    if (prodcut == null) {
                        CJS.AlertAndGoUrl("此商品已经被删除!", Request.Url.AbsolutePath);
                        return;
                    }
                    AddProductToOrder(id, 1);
                    Response.Redirect(Request.Url.AbsolutePath, true);
                    return;
                }
            }
            rptView.DataSource = GetOrders();
            rptView.DataBind();
            MultiView1.ActiveViewIndex = 0;
        }
        public List<ORDERDETAIL> GetOrders() {
            HttpCookie cookie;
            cookie = Request.Cookies[Key] == null ? new HttpCookie(Key) : Request.Cookies[Key];
            NameValueCollection nvc = CHttpHelper.Base64Decode(cookie.Value);
            List<ORDERDETAIL> orders = new List<ORDERDETAIL>();
            int totalNum = 0;
            double totalMoney = 0.00;
            double totalVipMoney = 0.00;
            for (int i = 0; i < nvc.Count; i++) {
                ORDERDETAIL ord = new ORDERDETAIL(int.Parse(nvc.Keys[i]), int.Parse(nvc[i]));
                orders.Add(ord);
                totalNum += int.Parse(nvc[i]);
                totalMoney += (ord.Number * (ord.Product==null?0:ord.Product.Price));
                totalVipMoney += (ord.Number * (ord.Product==null?0:ord.Product.VipPrice));
            }
            lbTotalNum.Text = totalNum.ToString();
            lbTotalMoney.Text = totalVipMoney.ToString("0.00");
            lbDiscount.Text = (totalMoney - totalVipMoney).ToString("0.00");
            return orders;
        }
        public void AddProductToOrder(int pID, int num) {
            HttpCookie cookie;
            cookie = Request.Cookies[Key] == null ? new HttpCookie(Key) : Request.Cookies[Key];
            cookie.Path = Request.ApplicationPath;
            cookie.Domain = "." + Request.Url.Host;
            NameValueCollection nvc = CHttpHelper.Base64Decode(cookie.Value);
            if (nvc[pID.ToString()] != null)
                nvc[pID.ToString()] = (int.Parse(nvc[pID.ToString()]) + num).ToString();
            else
                nvc.Add(pID.ToString(), num.ToString());
            cookie.Value = CHttpHelper.Base64Encode(nvc);
            Response.AppendCookie(cookie);
        }
        [AjaxMethod]
        public RESUTLINFO ModifyProductNumber(int pID, int num, string cookieStr) {
            NameValueCollection nvc = CHttpHelper.Base64Decode(cookieStr);
            nvc[pID.ToString()] = num.ToString();
            return new RESUTLINFO(pID, int.Parse(nvc[pID.ToString()]),CHttpHelper.Base64Encode(nvc));
        }
        [AjaxMethod]
        public RESUTLINFO RemoveProductFromOrder(int pID, string cookieStr) {
            NameValueCollection nvc = CHttpHelper.Base64Decode(cookieStr);
            nvc.Remove(pID.ToString());
            return new RESUTLINFO(pID, CHttpHelper.Base64Encode(nvc));
        }
    }
     
    CS文件代码
     
    [CHttpHeler]
     
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Collections.Specialized;
    using System.Web;
    namespace AW.Components.Helpers {
        public class CHttpHelper {
            private CHttpHelper() { }
            GetString#region GetString
            public static string GetString(NameValueCollection nvc) {
                string rtn = string.Empty;
                for (int i = 0; i < nvc.Count; i++) {
                    rtn += nvc.Keys[i] + "=" + nvc[i];
                    if (i < nvc.Count - 1) rtn += "&";
                }
                return rtn;
            }
            public static string GetString(string base64String) {
                byte[] bytes = Convert.FromBase64String(base64String);
                return Encoding.Default.GetString(bytes);
            }
            #endregion
            public static string Base64Encode(NameValueCollection nvc) {
                return Convert.ToBase64String(Encoding.Default.GetBytes(GetString(nvc)), Base64FormattingOptions.None);
            }
            public static NameValueCollection Base64Decode(string base64String) {
                if (string.IsNullOrEmpty(base64String))
                    return new NameValueCollection();
                return HttpUtility.ParseQueryString(GetString(HttpUtility.UrlDecode(base64String)));
            }
        }
        public struct ORDERDETAIL {
            public ORDERDETAIL(int pID, int num) {
                Product = CProducts.GetProduct(pID, CContext.Current.SiteOwnerUserID);
                Number = num;
            }
            public CProduct Product;
            public int Number;
            public void ParseFromString(string str) {
            }
            public int ProudctID {
                get {
                    return Product == null ? 0 : Product.ID;
                }
            }
            public override string ToString() {
                return ProudctID + ":" + Number.ToString();
            }
        }
        public struct RESUTLINFO {
            public string NVC;
            public int PID;
            public int TOTAL;
            public RESUTLINFO(int pID, string nvc) {
                PID = pID;
                NVC = nvc;
                TOTAL = 0;
            }
            public RESUTLINFO(int pID, int total, string nvc) {
                PID = pID;
                NVC = nvc;
                TOTAL = total;
            }
        }
    }
    一个Helper 类

    Ajax Shopping Cart(1)

    [ASPX]
     
    <%@ Page Language="C#" MasterPageFile="~/Scripts/ShopCart/ShopCart.master" AutoEventWireup="true"
        CodeFile="Default.aspx.cs" Inherits="_Default" Title="购物车" %>
      
       <%@ Import Namespace="AW.Components.Helpers" %> 
    <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
        <asp:MultiView ID="MultiView1" runat="server">
            <asp:View ID="View1" runat="server">
                <script language="javascript" type="text/javascript" src='<%= this.ResolveUrl("~/Utility/Functions.js") %>'></script>
                <script language="javascript" type="text/javascript">
            var key = '<%= Key %>';
            function remove(pID){
                var v = getCookie(key)==null?"":getCookie(key);
                _Default.RemoveProductFromOrder(pID,v,remove_Callback);
            }
            function remove_Callback(res){
                if(res.error!=null)alert(res.error);
                else{
                   var tr = document.getElementById("tr_" + res.value.PID.toString());
                   tr.style.display = "none";        
                   deleteCookie(key,"/","." + location.host);
                   setCookie(key,res.value.NVC,null,"/","."+location.host);
                   calcMoney();
                }
            }
            function modify(pID,num){
                var v = getCookie(key)==null?"":getCookie(key);
                _Default.ModifyProductNumber(pID,num,v,modify_Callback);
            }
            function modify_Callback(res){
                deleteCookie(key,"/","." + location.host);
                setCookie(key,res.value.NVC,null,"/","."+location.host);   
                var total = document.getElementById("txtSubTotal_" + res.value.PID.toString());
                var price = document.getElementById("txtVipPrice_" + res.value.PID.toString());
                total.value = Round(parseFloat(parseInt(res.value.TOTAL) * parseFloat(price.value)),2);
                calcMoney();
            }
            function modifyAll(){
          
            }
            function clearCart(){
                if (!confirm('确定要清空购物车吗?')) return;
                var tb = document.getElementById("tbOrder");
                   for(var i=1;i<tb.rows.length;i++){
                        var tr = tb.rows.item(i);
                        if(tr.id.indexOf("_")!=-1 && tr.style.display!="none"){
                            tr.style.display = 'none';
                         }
                    } 
                 deleteCookie(key,"/","." + location.host);
                var ctlTotalNum = document.getElementById("<%=lbTotalNum.ClientID %>");
                var ctlTotalMoney = document.getElementById("<%=lbTotalMoney.ClientID %>");
                var ctlDiscount = document.getElementById("<%=lbDiscount.ClientID %>");    
                ctlTotalNum.innerHTML = "0";           
                ctlTotalMoney.innerHTML = "0";
                ctlDiscount.innerHTML = "0";
            }
           
            function calcMoney(){
                var ctlNums = document.getElementsByName("txtNumber");
                var ctlPrices = document.getElementsByName("txtPrice");
                var ctlVipPrices = document.getElementsByName("txtVipPrice");
                var ctlSubTotal = document.getElementsByName("txtSubTotal");
                var ctlTotalNum = document.getElementById("<%=lbTotalNum.ClientID %>");
                var ctlTotalMoney = document.getElementById("<%=lbTotalMoney.ClientID %>");
                var ctlDiscount = document.getElementById("<%=lbDiscount.ClientID %>");    
                var totalNum = 0;
                var subTotal = 0;
                var subTotalVip = 0;
                var totalMoney = 0; 
                var totalVipMoney = 0;
               
                for(var i=0;i<ctlNums.length;i++){
                    totalNum += parseInt(ctlNums[i].value);
                    subTotal  = parseFloat(totalNum * parseFloat(ctlPrices[i].value));
                    subTotalVip =  parseFloat(totalNum * parseFloat(ctlVipPrices[i].value));
                    totalMoney +=  subTotal;
                    totalVipMoney += subTotalVip;
                   ctlSubTotal.value = subTotalVip.toString();
                }
                ctlTotalNum.innerHTML = Round(totalNum,2);
                ctlTotalMoney.innerHTML = Round(totalVipMoney,2);
                ctlDiscount.innerHTML = Round((totalMoney - totalVipMoney),2);
            }
            function Round(a_Num , a_Bit){
                return (Math.round(a_Num * Math.pow (10 , a_Bit)) / Math.pow(10 , a_Bit)).toString()  ;
            }
            </script>
                <div id="shopcart">
                    <table width="778" border="0" align="center" cellpadding="0" cellspacing="0" background="../../Icon/ShopCart/shopC_syp_5.gif">
                        <tbody>
                            <tr>
                                <td width="12">
                                    <img height="72" src="../../Icon/ShopCart/shopC_syp_1.gif" width="12" /></td>
                                <td>
                                    <img height="72" src="../../Icon/ShopCart/shopC_6.gif" width="176" /></td>
                                <td valign="bottom" align="right">
                                    <img height="29" src="../../Icon/ShopCart/shopC_4.gif" width="324" /></td>
                                <td width="10" align="right" valign="bottom">
                                    <img height="72" src="../../Icon/ShopCart/shopC_syp_3.gif" width="10" /></td>
                            </tr>
                        </tbody>
                    </table>
                    <table class="meun_bg" cellspacing="0" cellpadding="0" width="540" align="center"
                        border="0">
                        <tbody>
                            <tr>
                                <td align="right">
                                    <img height="28" src="../../Icon/ShopCart/shopC_syx_01.gif" width="93" border="0" /></td>
                                <td>
                                    <img height="32" src="../../Icon/ShopCart/shopC_sy_8.gif" width="55" /></td>
                                <td>
                                    <img height="28" src="../../Icon/ShopCart/shopC_syx_02.gif" width="112" border="0" /></td>
                                <td>
                                    <img height="32" src="../../Icon/ShopCart/shopC_sy_8.gif" width="55" /></td>
                                <td>
                                    <img height="22" src="../../Icon/ShopCart/shopC_syx_03.gif" width="109" border="0" /></td>
                            </tr>
                        </tbody>
                    </table>
                    <table cellspacing="0" cellpadding="0" width="778" align="center" bgcolor="#fafafa"
                        border="0">
                        <tbody>
                            <tr>
                                <td>
                                    <img height="41" hspace="8" src="../../Icon/ShopCart/shopc_z1.gif" width="143" /></td>
                            </tr>
                            <tr>
                                <td>
                                    <table cellspacing="0" cellpadding="0" width="96%" align="center" border="0">
                                        <tbody>
                                            <tr align="right" bgcolor="#fafafa">
                                                <td>
                                                    <img height="15" src="../../Icon/ShopCart/shopc_syx_j.gif" width="771" /></td>
                                            </tr>
                                            <tr align="right" bgcolor="#fafafa">
                                                <td class="boder_center_bg">
                                                    <table cellspacing="1" width="95%" align="center" border="0" id="tbOrder">
                                                        <tbody>
                                                            <tr class="boder_topbg" align="center">
                                                                <td>
                                                                    商品名称</td>
                                                                <td>
                                                                    单 位</td>
                                                                <td>
                                                                    数 量</td>
                                                                <td>
                                                                    市场价(元)</td>
                                                                <td>
                                                                    会员价(元)</td>
                                                                <td>
                                                                    小 计(元)</td>
                                                                <td width="8%">
                                                                    操作</td>
                                                            </tr>
                                                            <asp:Repeater ID="rptView" runat="server">
                                                                <ItemTemplate>
                                                                    <tr align="center" bgcolor="#f9f9f9" id="tr_<%# ((ORDERDETAIL)Container.DataItem).Product.ID %>">
                                                                        <td align="left">
                                                                            <asp:HyperLink Target="_blank" NavigateUrl='<%# "~/" + ((ORDERDETAIL)Container.DataItem).Product.ChannelID.ToString() + "_" + ((ORDERDETAIL)Container.DataItem).Product.ID.ToString() + ".aspx" %>'
                                                                                Text='<%# ((ORDERDETAIL)Container.DataItem).Product.Name %>' runat="server" /></td>
                                                                        <td>
                                                                            <%# String.IsNullOrEmpty(((ORDERDETAIL)Container.DataItem).Product.Unit) ? "个" : ((ORDERDETAIL)Container.DataItem).Product.Unit %>
                                                                        </td>
                                                                        <td>
                                                                            <input style="text-align: right;" onbeforepaste="clipboarddata.setdata('text',clipboarddata.getdata('text').replace(/[^/d]/g,''))"
                                                                                id="txtNum_<%# ((ORDERDETAIL)Container.DataItem).Product.ID %>" οnkeyup="value=value.replace(/[^/d]/g,'');"
                                                                                οnblur="if(this.value.length==0)this.value=0;modify(<%# ((ORDERDETAIL)Container.DataItem).Product.ID %>,value);"
                                                                                maxlength="2" size="4" value="<%# ((ORDERDETAIL)Container.DataItem).Number %>"
                                                                                name="txtNumber" /></td>
                                                                        <td style="padding-left: 20px" align="right">
                                                                            <del>
                                                                                <%# ((ORDERDETAIL)Container.DataItem).Product.Price %>
                                                                            </del>
                                                                            <input name='txtPrice' id="txtPrice_<%# ((ORDERDETAIL)Container.DataItem).Product.ID %>"
                                                                                type="hidden" value='<%# ((ORDERDETAIL)Container.DataItem).Product.Price %>' />
                                                                        </td>
                                                                        <td style="padding-left: 20px" align="right">
                                                                            <input style="text-align: right;" name='txtVipPrice' id="txtVipPrice_<%# ((ORDERDETAIL)Container.DataItem).Product.ID %>"
                                                                                type="hidden" value='<%# ((ORDERDETAIL)Container.DataItem).Product.VipPrice %>' />
                                                                            <%# ((ORDERDETAIL)Container.DataItem).Product.VipPrice %>
                                                                        </td>
                                                                        <td style="padding-left: 20px" align="right">
                                                                            <input style="text-align: right;border: none 0px white; background-color: White;" size="4" name='txtSubTotal' id="txtSubTotal_<%# ((ORDERDETAIL)Container.DataItem).Product.ID %>"
                                                                                type="text" readonly="readonly" value='<%# ((ORDERDETAIL)Container.DataItem).Product.VipPrice * ((ORDERDETAIL)Container.DataItem).Number %>' /></td>
                                                                        <td>
                                                                            <a href="javascript:remove(<%# ((ORDERDETAIL)Container.DataItem).Product.ID %>);"><font
                                                                                color="#ff0000">删除</font></a></td>
                                                                    </tr>
                                                                </ItemTemplate>
                                                            </asp:Repeater>
                                                            <tr align="right" bgcolor="#f9f9f9">
                                                                <td colspan="7">
                                                                    购物车中共有
                                                                    <asp:Label ID="lbTotalNum" ForeColor="red" runat="server" />
                                                                    件商品,
    共计 <font class="font_red">¥<asp:Label ID="lbTotalMoney" runat="server" />
                                                                        元</font>(不包括邮费) &nbsp;您节省了<font class="font_red">¥<asp:Label ID="lbDiscount" runat="server" /></font>
                                                                </td>
                                                            </tr>
                                                            <tr align="left" bgcolor="#f9f9f9">
                                                                <td colspan="7">
                                                                    <img style="width: 104px; height: 27px; cursor: pointer;" οnclick="modifyAll();"
                                                                        height="23" alt="单击这里保存您所修改的商品数量" width="85" src="../../Icon/ShopCart/shopc_13_02.gif"
                                                                        border="0" />
                                                                    &nbsp;
                                                                    <img style="cursor: pointer" οnclick="clearCart();" height="27" alt="单击这里清空所有购买的商品"
                                                                        src="../../Icon/ShopCart/shopc_13_03.gif" width="104" />&nbsp;</td>
                                                            </tr>
                                                        </tbody>
                                                    </table>
                                                </td>
                                            </tr>
                                            <tr align="right" bgcolor="#fafafa">
                                                <td>
                                                    <img height="15" src="../../Icon/ShopCart/shopc_20.gif" width="771" /></td>
                                            </tr>
                                        </tbody>
                                    </table>
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    <img style="cursor: hand" οnclick="javascript:window.close();" height="42" alt="点击继续购买您喜欢的其它商品"
                                        src="../../Icon/ShopCart/shopc_13_01.gif" width="143" vspace="10" />&nbsp; &nbsp;
                                    &nbsp;
                                    <img style="cursor: hand" οnclick="location.href='./ClientInfo.aspx';" height="42"
                                        alt="点击去收银台结帐" hspace="10" src="../../Icon/ShopCart/shopc_13.gif" width="143"
                                        vspace="10" id="IMG1" /></td>
                            </tr>
                            <tr>
                                <td class="style2" align="center">
                                </td>
                            </tr>
                        </tbody>
                        <tr>
                            <td>
                            </td>
                        </tr>
                    </table>
                </div>
            </asp:View>
        </asp:MultiView>
        <br />
        <br />
    </asp:Content>
     
    HTML代码 

    ASP.NET Cache

    ASP.NET 数据库缓存依赖

    By Peter A. Bromberg, Ph.D.
    在ASP.NET中,Cache类最酷的特点是它能根据各种依赖来良好的控制自己的行为。以文件为基础的依赖是最有用的,文件依赖项是通过使用 Cache.Insert 并提供引用文件的 CacheDependency 对象添加的
     
    Cache.Insert("MyData", Source, new CacheDependency(Server.MapPath("authors.xml")));
     
    但是当我们想让缓存根据数据库中表的变化而失效并重建该缓存的时候,应该怎么做呢 – 这种情景在很多应用程序中都存在。Asp.net没有为监视数据库表的变化提供内在的直接缓存支持。利用SQL Server的不常用的系统存储过程sp_makewebtask ,是可以达到这个目的的,这个存储过程本来是用作从查询中生成web页面的,但是我们只要稍作修改- 在触发器中使用它,我们就可以取得一个合理有效的途径,当数据库某张表的记录被更新,删除或者修改时来修改某个特定的文件, 这样会使在CacheDependency实例中的文件监视进程侦测到文件的变化,从而使缓存失效。事实上,因为CacheDependency 类工作在UNC文件协议上,我们可以在整个Web Farm上部署这个解决方案,Web Farm上每台机器上的应用程序副本都会通过UNC文件路径来监视WebFarm中某台单个机器上的同一个文件
    废话少说,让我们创建一个简单的web应用程序,来演示它是如果工作的。首先,我们将会使用我们SQL Server中都信赖的Northwind范例数据库。创建一个简单的DataGrid来显示Employees表中的记录. 我们要做的第一件事情就是创建触发器。
    CREATE TRIGGER WriteCacheDepFile ON [dbo].[Employees]
    FOR INSERT, UPDATE, DELETE
    AS
    EXEC sp_makewebtask '//peter/C$/Cache/mycache.txt', 'SELECT top 1 FirstName FROM employees'
     
    以上存储过程就是简单的告诉SQL Server,如果Employee表发生任何变动,就根据一个简单的查询来更新”mycache.txt”文件,有这个简单的查询语句其实足够了,只要它是一个有效的T-SQL语句,SQL Server会很乐意的去更新那个文件。
    接下来,我们需要创建一个目录,并设为共享。你可能要更新该文件的访问权限,以使它可以被写入,注意,我这里使用的是管理员共享”C$”.另外,你还需要创建一个空的文本文件,"mycache.txt".
    好,现在可以创建我们的应用程序了。首先,在web.config文件中输入依赖文件名称,这样做可以使我们在修改依赖文件的时候不需要重新部署应用程序。
    在web.config文件的根部,添加appSettings配置节:
    </system.web>
    <appSettings>
    <!—缓存依赖文件路径 -->
    <add key="dependencyFile" value="//peter/Cache/mycache.txt" />
    </appSettings>
    </configuration>
     
    现在,让我们在Global类中建立缓存机制,这样我们不需要在任何页面中编写特定的代码

    [C#]
    public class Global : System.Web.HttpApplication
    {
    Cache _cache =null;
    public static bool blnReflash = false;
    public const string ConnStr = "server=localhost;database=Northwind;uid=sa;pwd=";
    public const string strSQL = "SELECT EmployeeID, lastname, firstname FROM Employees";
     
    protected void Application_Start(Object sender, EventArgs e)
    {
    _cache = Context.Cache;
    RefreshCahe(null,null,0);
    }
     
    protected void Session_Start(Object sender, EventArgs e)
    {
    if(HttpContext.Current.Cache["Employees"]==null)
    RefreshCache(null,null,0);
    }
     
    static void RefreshCache(string key,object item,CacheItemRemoveReason reason)
    {
    SqlDataAdapter adapter = new SqlDataAdapter(strSQL,ConnStr);
    DataSet ds = new DataSet();
    adapter.Fill(ds,"Employees");
    CacheItemRemovedCallback onRemove = new CacheItemRemovedCallback(RefreshCache);
     
    string depFile= ConfigurationSettings.AppSettings["dependencyFile"].ToString();
    HttpContext.Current.Cache.Insert("Employees",ds,new CacheDependency(depFile),
    Cache.NoAbsoluteExpiration,Cache.NoSlidingExpiration,
    CacheItemPriority.High,onRemove);
     
    blnReflash = true;
    }
     
    就像上面看到的一样,我们定义了一个Cache类型的_cache对象,在Application_Start方法中,我们把当前的Cache实例赋给它,然后调用RefreshCache方法去填充该对象。RefreshCache实际上是一个静态的委托回调方法,它所做的就是简单的从Empoyees表中取得一个DataSet,然后创建CacheItemRemovedCallback类型的委托OnRemove,使其指向RefreshCache方法,这样当被监控的文件变化时,也就是缓存失效时,就会调用该委托,刷新缓存中的数据。
    最后我们把DataSet连同OnRemove委托一起插入到缓存中,在Session_Start中,为了“保险“,我另外添加了一个判断来调用RefreshCache方法填充缓存。
    到这里,我们应用程序就创建好了,在任何页面中都可以访问到缓存的DataSet。在WebForm1aspx中,我演示了如何使用它。
    [C#]
    private void Page_Load(object sender, System.EventArgs e)
    {
    //保证缓存非空,如果为空,则填充它
    if(Cache["Employees"] == null)
    Global.RefreshCache(null,null, 0);
    cacheStatus.Text = "Cache Refreshed at "+ DateTime.Now.ToLongTimeString();
    else
    cacheStatus.Text = " DataSet from Cache ";
     
    DataSet ds = (DataSet)Cache["Employees"];
    DataGrid1.DataSource= ds.Tables[0];
    DataGrid1.DataBind();
    }
     
    现在,如果你请求这个页面,它将会每次成功的显示从从Cache中取得

    ASP.NET 2.0 SQL Cache

    Stephen Walther
      
      Microsoft Corporation
      
      适用于:
      
      Microsoft ASP.NET 2.0
      
      Microsoft ASP.NET Framework
      
      Microsoft SQL Server
      
      Microsoft Visual Studio .NET
      
      摘要:本文中,Stephen Walther 将重点介绍 ASP.NET 2.0 中新增的缓存功能,以及如何使用这些新功能改进 ASP.NET 应用程序的性能和可扩展性。(本文包含一些指向英文站点的链接。)
      
      
      
      本页内容
       更轻松的数据缓存
       使用 SQL Cache Invalidation
       使用 Post-Cache Substitution
       结论
      
      对于由数据库驱动的 Web 应用程序来说,要改进其性能,最好的方法就是使用缓存。从数据库中检索数据可能是您在 Web 站点上执行的最慢的操作之一。如果能够将数据库中的数据缓存到内存中,就无需在请求每个页面时都访问数据库,从而可以大大提高应用程序的性能。
      
      缓存有一个且只有一个缺点,那就是数据过期的问题。如果将数据库表的内容缓存到内存中,当基础数据库表中的记录发生更改时,您的 Web 应用程序将显示过期的、不准确的数据。对于某些类型的数据,即便显示的数据稍微有些过期,影响也不会太大;但对于诸如股票价格和竞拍出价之类的数据,即使显示的数据稍微有些过期也是不可接受的。
      
      Microsoft ASP.NET 1.0 Framework 没有针对此问题提供一个完善的解决方案。使用 ASP.NET 1.0 Framework 时,您不得不在性能和数据过期之间作出权衡。幸运的是,Microsoft ASP.NET 2.0 Framework 提供了一项新功能,称为 SQL Cache Invalidation,可以解决这一棘手的问题。
      
      在本文中,您将进一步了解 ASP.NET 2.0 Framework 中许多新的缓存改进功能。首先,您将了解到如何在新增的 DataSource 控件中集成缓存支持。然后,您将了解到如何配置和使用 SQL Cache Invalidation。最后,您将了解到随 ASP.NET 2.0 Framework 引入的一个新控件:Substitution 控件,使用该控件可以向已缓存的页面中插入动态内容。
      
      更轻松的数据缓存
      在 ASP.NET 2.0 Framework 中,最大的变化之一就是在 ASP.NET 页面上访问数据库数据的方式发生了变化。ASP.NET 2.0 Framework 包含一组新的控件,统称为 DataSource 控件。您可以使用这些控件来表示数据源,例如数据库或 XML 文件。
      
      在 ASP.NET 1.0 Framework 中,是通过将控件绑定到 DataSet 或 DataReader,使用控件来显示数据库数据的。而在 ASP.NET 2.0 Framework 中,通常是将控件绑定到 DataSource 控件。通过 DataSource 控件,您可以创建显示数据库数据的 ASP.NET 页面,而不用为访问数据库编写任何代码。
      
      在处理数据库数据时,通常使用下列三个 DataSource 控件中的一个控件:
      
      • SqlDataSource — 表示 SQL 数据源,例如 Microsoft SQL Server 或 Oracle 数据库。
      
      • AccessDataSource — 一个专用的 SqlDataSource 控件,用于 Microsoft Access 数据库。
      
      • ObjectDataSource — 表示充当数据源的自定义业务对象。
      
      
      例如,假设您要在 DropDownList 控件中显示从数据库中检索到的书目列表(参见图 1)。列表 1 中的页面说明了如何将 DropDownList 控件绑定到 SqlDataSource 控件。
      
      图 1:使用 SqlDataSource 控件检索数据
      
      
      列表 1:DisplayTitles.aspx
      
      <html>
      <head runat ="server">
      <title>Display Titles</title>
      </head>
      <body>
      <form id="form1" runat ="server">
      
      <asp:DropDownList
      ID="DropDownList1"
      DataSourceId="SqlDataSource1"
      DataTextField="Title"
      Runat="server" />
      
      <asp:SqlDataSource
      ID="SqlDataSource1"
      ConnectionString="Server=localhost;database=Pubs"
      SelectCommand="SELECT Title FROM Titles"
      Runat="server" />
      
      </form>
      </body>
      </html>
      
      请注意,列表 1 中的 SqlDataSource 控件用于提供连接字符串,SQL SELECT 命令用于从数据库中检索记录。DropDownList 控件通过其 DataSourceID 属性绑定到 SqlDataSource 控件。
      
      使用 DataSource 控件缓存数据
      使用 DataSource 控件,不仅可以更轻松地连接数据库,还使缓存数据库数据变得更容易。只需在 SqlDataSource 控件上设置一两个属性,就可以自动在内存中缓存由 DataSource 控件表示的数据。
      
      例如,如果要将 Titles 数据库表在内存中缓存至少 10 分钟,可以按照以下方式声明 SqlDataSource 控件。
      
       <asp:SqlDataSource
      ID="SqlDataSource1"
      EnableCaching="true"
      CacheDuration="600"
      ConnectionString="Server=localhost;database=Pubs"
      SelectCommand="SELECT Title FROM Titles"
      Runat="server" />
      
      如果 EnableCaching 属性的值为 true,SqlDataSource 将自动缓存通过 SelectCommand 检索到的数据。使用 CacheDuration 属性,可以指定从数据库中刷新数据之前缓存数据的时间(以秒为单位)。
      
      默认情况下,SqlDataSource 使用绝对过期策略来缓存数据,即每隔指定的秒数就从数据库中刷新一次。此外,您还可以选择使用可变过期策略。如果将 SqlDataSource 配置为使用可变过期策略,那么只要持续访问数据,数据就不会过期。如果需要缓存大量项目,使用可变过期策略将非常有用,因为这种过期策略将只在内存中保留访问最频繁的项目。
      
      例如,下面的 SqlDataSourceControl 被配置为使用可变过期策略,过期时间为 10 分钟。
      
      <asp:SqlDataSource
      ID="SqlDataSource1"
      EnableCaching="true"
      CacheExpirationPolicy="Sliding"
      CacheDuration="600"
      ConnectionString="Server=localhost;database=Pubs"
      SelectCommand="SELECT Title FROM Titles"
      Runat="server" />
      
      由于 CacheExpirationPolicy 属性的值被设置为 Sliding,CacheDuration 属性的值被设置为 600,因此,只要在 10 分钟内持续访问,此 SqlDataSource 表示的数据就会一直保留在内存中。
      
      返回页首
      使用 SQL Cache Invalidation
      SQL Cache Invalidation 是 ASP.NET 2.0 Framework 最值得期待的新增功能之一。使用 SQL Cache Invalidation 可以获得缓存的全部性能优势,而不用担心数据过期的问题。SQL Cache Invalidation 使您可以在基础数据库中的数据发生更改时自动更新缓存中的数据。
      
      SQL Cache Invalidation 通过在后台不断轮询数据库来检查数据更改。每隔一定的时间(毫秒),ASP.NET Framework 就会检查数据库中是否存在更新。如果 ASP.NET Framework 检测到任何更改,将从缓存中删除从数据库中添加的、依赖于数据库的任何项目(即,这些项目将过期)。
      
      注意:Microsoft SQL Server 2005 支持一种截然不同的 SQL Cache Invalidation 方法。您可以配置 SQL Server 2005,使其在数据库、数据库表或数据库行发生变化时通知 ASP.NET 应用程序。这样,ASP.NET Framework 就不需要通过不断轮询 SQL Server 2005 数据库来检查数据更改了。
      
      需要注意的是,SQL Cache Invalidation 只能用于 Microsoft SQL Server 7 及更高版本,不能用于其他数据库,例如 Microsoft Access 或 Oracle。
      
      在缓存整个页面的输出、使用 DataSource控件或直接使用 Cache 对象时,都可以使用 SQL Cache Invalidation。下面将分别介绍这三种情况。
      
      配置 SQL Cache Invalidation
      在 Web 应用程序中使用 SQL Cache Invalidation 之前,首先必须执行一些配置步骤。必须将 Microsoft SQL Server 配置为支持 SQL Cache Invalidation,还必须在应用程序的 Web 配置文件中添加必要的配置信息。
      
      可以按照以下两种方法配置 SQL Server:使用 aspnet_regsql 命令行工具,或者使用 SqlCacheDependencyAdmin 类。
      
      使用 ASPNET_REQSQL 启用 SQL Cache Invalidation
      使用 aspnet_regsql 工具,您可以通过命令行来配置 SQL Cache Invalidation。aspnet_regsql 工具位于 Windows/Microsoft.NET/Framework/[版本] 文件夹中。要使用此工具,必须打开命令提示符窗口并浏览到此文件夹。
      
      要在使用 Pubs 数据库时支持 SQL Cache Invalidation,需要执行以下命令。
      
      aspnet_regsql -E -d Pubs -ed
      
      -E 选项使 aspnet_regsql 工具在连接到数据库服务器时使用集成的安全设置。-d 选项用于选择 Pubs 数据库。最后,-ed 选项用于为数据库启用 SQL Cache Invalidation。
      
      执行此命令时,将在数据库中添加一个名为 AspNet_SqlCacheTablesForChangeNotification 的新数据库表。此表包含启用了 SQL Cache Invalidation 的所有数据库表的列表。此命令还将在数据库中添加一组存储过程。
      
      为数据库启用 SQL Cache Invalidation 后,必须从数据库中选择要启用 SQL Cache Invalidation 的特定表。以下命令将为 Titles 数据库表启用 SQL Cache Invalidation。
      
      aspnet_regsql -E -d Pubs -t Titles -et
      
      -t 选项用于选择数据库表。-et 选项为数据库表启用 SQL Cache Invalidation。当然,您可以通过对每个数据库表重复执行此命令,为多个表启用 SQL Cache Invalidation。
      
      执行此命令时,将在数据库表中添加一个触发器。只要您对表进行了修改,此触发器就将触发并更新 AspNet_SqlCacheTablesForChangeNotification 表。
      
      最后,要获取某个特定数据库中当前启用了 SQL Cache Invalidation 的表的列表,可以使用以下命令。
      
      aspnet_regsql -E -d Pubs -lt
      
      此方法将从 AspNet_SqlCacheTablesForChangeNotification 中选择表的列表。此外,您也可以通过直接在该数据库表中执行查询来检索此信息。
      
      使用 SqlCacheDependencyAdmin 类
      aspnet_regsql 工具在后台使用 SqlCacheDependencyAdmin 类的方法来配置 Microsoft SQL Server。如果您愿意,可以直接从 ASP.NET 页面中使用此类的方法。
      
      SqlCacheDependencyAdmin 类具有五个重要的方法:
      
      • DisableNotifications — 为特定数据库禁用 SQL Cache Invalidation。
      
      • DisableTableForNotifications — 为数据库中的特定表禁用 SQL Cache Invalidation。
      
      • EnableNotifications — 为特定数据库启用 SQL Cache Invalidation。
      
      • EnableTableForNotifications — 为数据库中的特定表启用 SQL Cache Invalidation。
      
      • GetTablesEnabledForNotifications — 返回启用了 SQL Cache Invalidation 的所有表的列表。
      
      
      例如,使用列表 2 中的 ASP.NET 页面,您可以为 Pubs 数据库中的任何表配置 SQL Cache Invalidation(参见图 2)。
      
      图 2:从 ASP.NET 页面中启用 SQL Cache Invalidation
      
      
      列表 2:EnableSCI.aspx (C#)
      
      <%@ Page Language="c#" %>
      <%@ Import Namespace="System.Web.Caching" %>
      <script runat ="server">
      
      const string connectionString = "Server=localhost;Database=Pubs";
      
      void Page_Load()
       {
      if (!IsPostBack)
       {
      SqlCacheDependencyAdmin.EnableNotifications(
      connectionString);
      SqlDataSource1.SelectParameters.Add("connectionString",
      connectionString);
       }
       }
      
      void EnableTable(Object s, EventArgs e)
       {
      try
       {
      SqlCacheDependencyAdmin.EnableTableForNotifications(
      connectionString, txtTableName.Text);
       }
      catch (Exception ex)
       {
      lblErrorMessage.Text = ex.Message;
       }
      txtTableName.Text = "";
       }
      
      </script>
      
      <html>
      <head runat ="server">
      <title>Enable SQL Cache Invalidation</title>
      </head>
      <body>
      <form id="form1" runat ="server">
      
      <h1>SQL Cache Invalidation</h1>
      
      以下表格已启用 SQL Cache Invalidation:
      
      <p>
      <asp:GridView id="grdTables"
      DataSourceID="SqlDataSource1" CellPadding="10"
      ShowHeader="false" Runat="Server" />
      </p>
      
      <asp:ObjectDataSource
      ID="SqlDataSource1"
      TypeName="System.Web.Caching.SqlCacheDependencyAdmin"
      SelectMethod="GetTablesEnabledForNotifications"
      Runat="Server" />
      <p>
      <asp:Label ID="lblErrorMessage" EnableViewState="false"
      ForeColor="red" Runat="Server" />
      </p>
      
      <asp:TextBox ID="txtTableName" Runat="Server" />
      <asp:Button Text="Enable Table" OnClick="EnableTable"
      Runat="Server" />
      
      </form>
      </body>
      </html>
      
      列表 2:EnableSCI.aspx (Visual Basic .NET)
      
      <%@ Page Language="vb" %>
      <%@ Import Namespace="System.Web.Caching" %>
      <script runat ="server">
      
      Const connectionString As String = "Server=localhost;Database=Pubs"
      
      Sub Page_Load()
      
      If Not IsPostBack Then
      SqlCacheDependencyAdmin.EnableNotifications( _
      connectionString)
      SqlDataSource1.SelectParameters.Add("connectionString", _
      connectionString)
      End If
      End Sub
      
      Sub EnableTable(ByVal s As Object, ByVal e As EventArgs)
      
      Try
      
      SqlCacheDependencyAdmin.EnableTableForNotifications( _
      connectionString, txtTableName.Text)
      Catch ex As Exception
      lblErrorMessage.Text = ex.Message
      End Try
      txtTableName.Text = ""
      End Sub
      
      </script>
      
      <html>
      <head id="Head1" runat ="server">
      <title>ConfigureSCI</title>
      </head>
      <body>
      <form id="form1" runat ="server">
      
      <h1>SQL Cache Invalidation</h1>
      
      以下表格已启用 SQL Cache Invalidation:
      
      <p>
      <asp:GridView id="grdTables" DataSourceID="SqlDataSource1"
      CellPadding="10" ShowHeader="false" Runat="Server" />
      </p>
      
      <asp:ObjectDataSource
      ID="SqlDataSource1"
      TypeName="System.Web.Caching.SqlCacheDependencyAdmin"
      SelectMethod="GetTablesEnabledForNotifications"
      Runat="Server" />
      <p>
      <asp:Label ID="lblErrorMessage" EnableViewState="false"
      ForeColor="red" Runat="Server" />
      </p>
      
      <asp:TextBox ID="txtTableName" Runat="Server" />
      <asp:Button ID="Button1" Text="Enable Table"
      OnClick="EnableTable" Runat="Server" />
      
      </form>
      </body>
      </html>
      
      在列表 2 中,connectionString 常量用于选择启用了 SQL Cache Invalidation 的数据库(如果要为 Pubs 数据库以外的数据库启用 SQL Cache Invalidation,可以更改此常量的值)。在 Page_Load 方法中,调用 SqlCacheDependencyAdmin 类上的 EnableNotifications 方法,为由 connectionString 常量指定的数据库启用 SQL Cache Invalidation。
      
      列表 2 中的 GridView 显示了当前启用了 SQL Cache Invalidation 的所有数据库表。GridView 被绑定到 ObjectDataSource 控件上,该控件为其 SelectMethod 调用 GetTablesneabledForNotifications 方法。
      
      最后,您可以使用列表 2 中的页面为其他表启用 SQL Cache Invalidation。在文本框中输入表的名称并单击“Enable Table”按钮时,将调用 EnableTableForNotifications 方法。
      
      SQL Cache Invalidation 的 Web 配置设置
      在 ASP.NET 应用程序中使用 SQL Cache Invalidation 之前,下一步要做的是更新您的 Web 配置文件。您需要配置 ASP.NET Framework,以便轮询启用了 SQL Cache Invalidation 的数据库。
      
      列表 3 中的 Web 配置文件包含轮询 Pubs 数据库所必需的配置信息。
      
      列表 3:Web.Config
      
      <configuration>
      
      <connectionStrings>
      <add name="mySqlServer"
      connectionString="Server=localhost;Database=Pubs" />
      </connectionStrings>
      
      <system.web>
      
      <caching>
      <sqlCacheDependency enabled="true">
      <databases>
      <add
      name="Pubs"
      connectionStringName="mySqlServer"
      pollTime="60000" />
      </databases>
      </sqlCacheDependency>
      </caching>
      </system.web>
      </configuration>
      
      列表 3 中的 Web 配置文件包含两部分。<connectionStrings> 部分用于创建数据库连接字符串,以连接到名为 mySqlServer 的 Pubs 数据库。
      
      caching 部分用于配置 SQL Cache Invalidation 轮询。在 <databases> 子部分中,您可以列出要对其进行轮询以检查数据更改的一个或多个数据库。在列表 3 中,mySqlServer 表示的数据库每分钟(每 60000 毫秒)轮询一次。
      
      您可以为不同的数据库指定不同的轮询间隔。每次轮询数据库以检查数据更改时,服务器都必须执行一些操作。如果您认为数据库中的数据不会频繁地更改,可以增加轮询间隔。
      
      在页面输出缓存中使用 SQL Cache Invalidation
      现在,我们已经完成了 SQL Cache Invalidation 的所有配置步骤,可以在 ASP.NET 页面中使用它了。一种方法是在页面输出缓存中使用 SQL Cache Invalidation。页面输出缓存允许您在内存中缓存页面所显示的所有内容。通过使用 SQL Cache Invalidation,您可以在(且只在)数据库表发生更改时自动更新缓存的页面。
      
      例如,列表 4 中的页面在 GridView 控件中显示了 Titles 数据库表的内容。在该页面的顶部,OutputCache 指令用于在内存中缓存页面内容。如果 Titles 数据库表发生更改,SqlDependency 属性将使页面更新。
      
      列表 4:OutputCacheTitles.aspx
      
      <%@ OutputCache SqlDependency="Pubs:Titles"
      Duration="6000" VaryByParam="none" %>
      <html>
      <head runat ="server">
      <title>Output Cache Titles</title>
      </head>
      <body>
      <form id="form1" runat ="server">
      
      <%= DateTime.Now %>
      
      <asp:GridView
      ID="grdTitles"
      DataSourceID="SqlDataSource1"
      Runat="Server" />
      
      <asp:SqlDataSource
      ID="SqlDataSource1"
      SelectCommand="Select * FROM Titles"
      ConnectionString="<%$ ConnectionStrings:mySqlServer %>"
      Runat="Server" />
      
      </form>
      </body>
      </html>
      
      请注意,SqlDependency 属性引用了 Web 配置文件中定义的数据库的名称。由于我们指定了每分钟轮询一次 Pubs 数据库以检查数据更改,因此如果对该数据库进行了更改,列表 4 中的页面将在一分钟之内进行更新。
      
      您可以为 SqlDependency 属性值列出多个数据库和/或多个数据库表。要创建多个依赖关系,只需用分号分隔每个依赖关系即可。
      
      在 DataSource 控件中使用 SQL Cache Invalidation
      除了在页面输出缓存中使用 SQL Cache Invalidation 之外,还可以直接在 DataSource 控件中使用 SQL Cache Invalidation。如果要在多个页面中使用相同的数据库数据,请考虑在 DataSource 控件中使用 SQL Cache Invalidation。SqlDataSource、AccessDataSource 和 ObjectDataSource 控件都支持 SqlCacheDependency 属性。
      
      例如,列表 5 中的页面在 SqlDataSource 控件中使用了 SQL Cache Invalidation。
      
      列表 5:SqlDataSourceCaching.aspx
      
      <html>
      <head id="Head1" runat ="server">
      <title>SqlDataSource Caching</title>
      </head>
      <body>
      <form id="form1" runat ="server">
      
      <%= DateTime.Now %>
      
      <asp:GridView
      ID="grdTitles"
      DataSourceId="SqlDataSource1"
      Runat="server" />
      
      <asp:SqlDataSource
      ID="SqlDataSource1"
      EnableCaching="true"
      SqlCacheDependency="Pubs:Titles"
      SelectCommand="select * from titles"
      ConnectionString="<%$ ConnectionStrings:mySqlServer %>"
      Runat="server" />
      
      </form>
      </body>
      </html>
      
      在列表 5 中,SqlDataSource 控件是使用 EnableCaching 和 SqlCacheDependency 这两个属性声明的。SqlCacheDependency 属性使用的语法与 OutputCache 指令的 SqlDependency 属性相同。您需要列出数据库的名称,后跟数据库表的名称。
      
      在 Cache 对象中使用 SQL Cache Invalidation
      最后,您还可以在 Cache 对象中使用 SQL Cache Invalidation。此选项使您可以最大程度地对 SQL Cache Invalidation 进行编程控制。
      
      要在 Cache 对象中使用 SQL Cache Invalidation,您需要创建一个 SqlCacheDependency 对象实例。使用 Insert 方法在 Cache 中插入新对象时,可以使用 SqlCacheDependency 对象。
      
      例如,列表 6 中的页面显示了 Titles 数据库表中的记录数。计数是基于对基础数据库表的依赖关系进行缓存的。
      
      列表 6:DisplayTitleCount.aspx (C#)
      
      <%@ Page Language="c#" %>
      <%@ Import Namespace="System.Data.SqlClient" %>
      <script runat ="server">
      
      void Page_Load()
       {
      int count = 0;
      
      if (Cache["TitleCount"] != null)
       {
      count = (int)Cache["TitleCount"];
       }
      else
       {
      string connectionString =
      ConfigurationSettings.ConnectionStrings[
      "mySqlServer"].ConnectionString;
      SqlConnection con = new SqlConnection(connectionString);
      SqlCommand cmd = new
      SqlCommand("SELECT Count(*) FROM Titles", con);
      con.Open();
      count = (int)cmd.ExecuteScalar();
      con.Close();
      Cache.Insert("TitleCount", count,
      new SqlCacheDependency("Pubs", "Titles"));
       }
      lblTitleCount.Text = count.ToString();
       }
      
      </script>
      
      <html>
      <head runat ="server">
      <title>Display Title Count</title>
      </head>
      <body>
      <form id="form1" runat ="server">
      
      <asp:Label ID="lblTitleCount" Runat="Server" />
      
      </form>
      </body>
      </html>
      
      列表 6:DisplayTitleCount.aspx (Visual Basic .NET)
      
      <%@ Page Language="vb" %>
      <%@ Import Namespace="System.Data.SqlClient" %>
      <script runat ="server">
      
      Sub Page_Load()
      
      Dim count As Integer = 0
      
      If Not Cache("TitleCount") Is Nothing Then
      count = Convert.ToInt32(Cache("TitleCount"))
      Else
      Dim connectionString As String = _
      ConfigurationSettings.ConnectionStrings( _
      "mySqlServer").ConnectionString
      Dim con As New SqlConnection(connectionString)
      Dim cmd As New _
      SqlCommand("SELECT Count(*) FROM Titles", con)
      con.Open()
      count = Convert.ToInt32(cmd.ExecuteScalar())
      con.Close()
      Cache.Insert("TitleCount", count, _
      new SqlCacheDependency("Pubs", "Titles"))
      End If
      
      lblTitleCount.Text = count.ToString()
      End Sub
      
      </script>
      
      <html>
      <head id="Head1" runat ="server">
      <title>Display Titles Count</title>
      </head>
      <body>
      <form id="form1" runat ="server">
      
      <asp:Label ID="lblTitleCount" Runat="Server" />
      
      </form>
      </body>
      </html>
      
      返回页首
      使用 Post-Cache Substitution
      在许多情况下,您需要缓存页面的一部分,而不是整个页面。例如,在您的 Web 站点主页上,您可能希望同时显示随机的标题广告和数据库表中的记录。如果缓存整个页面,每个用户都将在每次请求的页面上看到同一个标题广告。
      
      要处理这种同时混有动态内容和缓存内容的问题,一种方法是使用 Web 用户控件。因为可以为 Web 用户控件添加 OutputCache 指令,所以即使不缓存包含页面的内容,也可以缓存 Web 用户控件的内容。
      
      但有时候可能会事与愿违。虽然您可以使用 Web 用户控件在动态页面上添加缓存的内容,但很多情况下,您实际上是想在缓存的页面中添加动态内容。例如,假设您要缓存整个页面的内容,只留一小块区域用于显示当前用户的用户名。这种情况下最好使用 Post-Cache Substitution。
      
      ASP.NET 2.0 Framework 引入了一种新控件,称为 Substitution 控件。您可以使用 Substitution 控件在缓存的页面中插入动态内容。列表 7 中的页面使用 Substitution 控件将用户名插入到缓存的内容中(参见图 3)。
      
      图 3:使用 Substitution 控件显示用户名
      
      
      列表 7:PostCacheSubstitution.aspx (C#)
      
      <%@ Page Language="C#" %>
      <%@ OutputCache Duration="6000" VaryByParam="none" %>
      
      <script runat ="server">
      
      static string DisplayUsername(HttpContext context)
       {
      if (!context.Request.IsAuthenticated)
      return "Anonymous";
      else
      return context.User.Identity.Name;
       }
      
      </script>
      
      <html>
      <head runat ="server">
      <title>Post Cache Substitution</title>
      </head>
      <body>
      <form id="form1" runat ="server">
      
      Welcome <asp:Substitution
      MethodName="DisplayUsername" Runat="Server" />!
      
      <p>
      此页已缓存, 因为时间
      <%= DateTime.Now.ToString("t") %> 并无改变。
      </p>
      
      </form>
      </body>
      </html>
      
      列表 7:PostCacheSubstitution.aspx (Visual Basic .NET)
      
      <%@ Page Language="vb" %>
      <%@ OutputCache Duration="6000" VaryByParam="none" %>
      
      <script runat ="server">
      
      Shared Function DisplayUsername(ByVal context As HttpContext) _
      As String
      If Not context.Request.IsAuthenticated Then
      Return "Anonymous"
      Else
      Return context.User.Identity.Name
      End If
      End Function
      
      </script>
      
      <html>
      <head id="Head1" runat ="server">
      <title>Post Cache Substitution</title>
      </head>
      <body>
      <form id="form1" runat ="server">
      
      Welcome <asp:Substitution
      ID="Substitution1"
      MethodName="DisplayUsername"
      Runat="Server" />!
      
      <p>
      此页已缓存, 因为时间
      <%= DateTime.Now.ToString("t") %> 并无改变。
      </p>
      
      </form>
      </body>
      </html>
      
      Substitution 控件有一个非常重要的属性:即 MethodName 属性。MethodName 属性用于表示为返回动态内容而调用的方法。由 Substitution 控件调用的方法必须是静态方法(在 Visual Basic .NET 中共享的方法)。此外,该方法还必须具有一个表示当前 HttpContext 的参数。
      
      在 ASP.NET 2.0 Framework 中,已对 AdRotator 控件进行了修改以支持 Post-Cache Substitution。如果在使用 OutputCache 指令的页面中添加 AdRotator 控件,AdRotator 控件将自动从其包含页面的缓存策略中排除出去。
      
      返回页首
      结论
      缓存对由数据库驱动的 Web 应用程序的性能具有非常大的影响。幸运的是,ASP.NET 2.0 Framework 提供了许多新的重要增强功能,使您可以在应用程序中更轻松地使用缓存功能。
      
      新增的 DataSource 控件中包含的属性使得在内存中缓存数据库数据变得非常容易。通过使用 DataSource 控件,您可以检索并缓存数据库数据,而无需编写任何代码。
      
      新增的 SQL Cache Invalidation 支持使您可以在基础数据库中的数据发生更改时自动在缓存中重新加载数据库数据。此功能为您提供了缓存的所有性能优势,而不用担心数据过期的问题。
      
      最后,使用新增的 Substitution 控件,您可以更轻松地在缓存的页面中混合动态内容。Substitution 控件为您在缓存的页面中插入动态内容提供了一个独立的空间。
      
      作者简介
      
      Stephen Walther 编写了有关 ASP.NET 的畅销书 ASP.NET Unleashed。此外,他还是 ASP.NET Community Starter Kit(Microsoft 开发的 ASP.NET 示例应用程序)的体系结构设计师和主要开发人员。他还通过自己的公司 Superexpert (http://www.superexpert.com/) 为美国的公司(包括 NASA 和 Microsoft)提供 ASP.NET 培训。
    2006/12/11

    CSS

     一.使用css缩写
    使用缩写可以帮助减少你CSS文件的大小,更加容易阅读。css缩写的主要规则请参看《常用css缩写语法总结》,这里就不展开描述。
     
    二.明确定义单位,除非值为0
    忘记定义尺寸的单位是CSS新手普遍的错误。在HTML中你可以只写width=100,但是在CSS中,你必须给一个准确的单位,比如:width: 100px width:100em。只有两个例外情况可以不定义单位:行高和0值。除此以外,其他值都必须紧跟单位,注意,不要在数值和单位之间加空格。
     
    三.区分大小写
    当在XHTML中使用CSS,CSS里定义的元素名称是区分大小写的。为了避免这种错误,我建议所有的定义名称都采用小写。
    class和id的值在HTML和XHTML中也是区分大小写的,如果你一定要大小写混合写,请仔细确认你在CSS的定义和XHTML里的标签是一致的。
     
    四.取消class和id前的元素限定
    当你写给一个元素定义class或者id,你可以省略前面的元素限定,因为ID在一个页面里是唯一的,鴆las s可以在页面中多次使用。你限定某个元素毫无意义。例如:
    div#content { /* declarations */ }
    fieldset.details { /* declarations */ }
    可以写成
    #content { /* declarations */ }
    .details { /* declarations */ }
    这样可以节省一些字节。
     
    五.默认值
    通常padding的默认值为0,background-color的默认值是transparent。但是在不同的浏览器默认值可能不同。如果怕有冲突,可以在样式表一开始就先定义所有元素的margin和padding值都为0,象这样:
    * {
    margin:0;
    padding:0;
    }
     
    六.不需要重复定义可继承的值
    CSS中,子元素自动继承父元素的属性值,象颜色、字体等,已经在父元素中定义过的,在子元素中可以直接继承,不需要重复定义。但是要注意,浏览器可能用一些默认值覆盖你的定义。
     
    七.最近优先原则
    如果对同一个元素的定义有多种,以最接近(最小一级)的定义为最优先,例如有这么一段代码
    Update: Lorem ipsum dolor set
    在CSS文件中,你已经定义了元素p,又定义了一个classupdate
    p {
    margin:1em 0;
    font-size:1em;
    color:#333;
    }
    .update {
    font-weight:bold;
    color:#600;
    }
    这两个定义中,class=update将被使用,因为class比p更近。你可以查阅W3C的《 Calculating a selector’s specificity》 了解更多。

    八.多重class定义
    一个标签可以同时定义多个class。例如:我们先定义两个样式,第一个样式背景为#666;第二个样式有10 px的边框。
    .one{width:200px;background:#666;}
    .two{border:10px solid #F00;}
    在页面代码中,我们可以这样调用
    <div class=one two></div>
    这样最终的显示效果是这个div既有#666的背景,也有10px的边框。是的,这样做是可以的,你可以尝试一下。

    九.使用子选择器(descendant selectors)
    CSS初学者不知道使用子选择器是影响他们效率的原因之一。子选择器可以帮助你节约大量的class定义。我们来看下面这段代码:
    <div id=subnav>
    <ul>
    <li class=subnavitem> <a href=# class=subnavitem>Item 1</a></li>>
    <li class=subnavitemselected> <a href=# class=subnavitemselected> Item 1</a> </li>
    <li class=subnavitem> <a href=# class=subnavitem> Item 1</a> </li>
    </ul>
    </div>
    这段代码的CSS定义是:
    div#subnav ul { /* Some styling */ }
    div#subnav ul li.subnavitem { /* Some styling */ }
    div#subnav ul li.subnavitem a.subnavitem { /* Some styling */ }
    div#subnav ul li.subnavitemselected { /* Some styling */ }
    div#subnav ul li.subnavitemselected a.subnavitemselected { /* Some styling */ }
    你可以用下面的方法替代上面的代码
    <ul id=subnav>
    <li> <a href=#> Item 1</a> </li>
    <li class=sel> <a href=#> Item 1</a> </li>
    <li> <a href=#> Item 1</a> </li>
    </ul>
    样式定义是:
    #subnav { /* Some styling */ }
    #subnav li { /* Some styling */ }
    #subnav a { /* Some styling */ }
    #subnav .sel { /* Some styling */ }
    #subnav .sel a { /* Some styling */ }
    用子选择器可以使你的代码和CSS更加简洁、更加容易阅读。
     
    十.不需要给背景图片路径加引号
    为了节省字节,我建议不要给背景图片路径加引号,因为引号不是必须的。例如:
    background:url(images/***.gif) #333;
    可以写为
    background:url(images/***.gif) #333;
    如果你加了引号,反而会引起一些浏览器的错误。
     
    十一.组选择器(Group selectors)
    当一些元素类型、class或者id都有共同的一些属性,你就可以使用组选择器来避免多次的重复定义。这可以节省不少字节。
    例如:定义所有标题的字体、颜色和margin,你可以这样写:
    h1,h2,h3,h4,h5,h6 {
    font-family:Lucida Grande,Lucida,Arial,Helvetica,sans-serif;
    color:#333;
    margin:1em 0;
    }
    如果在使用时,有个别元素需要定义独立样式,你可以再加上新的定义,可以覆盖老的定义,例如:
    h1 { font-size:2em; }
    h2 { font-size:1.6em; }
     
    十二.用正确的顺序指定链接的样式
    当你用CSS来定义链接的多个状态样式时,要注意它们书写的顺序,正确的顺序是::link :visited :hover :active。抽取第一个字母是LVHA,你可以记忆成LoVe HAte(喜欢讨厌)。为什么这么定义,可以参考Eric Meyer的《Link Specificity》。
    如果你的用户需要用键盘来控制,需要知道当前链接的焦点,你还可以定义:focus属性。:focus属性的效果也取决与你书写的位置,如果你希望聚焦元素显示:hover效果,你就把:focus写在:hover前面;如果你希望聚焦效果替代:hover效果,你就把:focus放在:hover后面。
     
    十三.清除浮动
    一个非常常见的CSS问题,定位使用浮动的时候,下面的层被浮动的层所覆盖,或者层里嵌套的子层超出了外层的范围。
    通常的解决办法是在浮动层后面添加一个额外元素,例如一个div或者一个br,并且定义它的样式为clear: both。这个办法有一点牵强,幸运的是还有一个好办法可以解决,参看这篇文章《How To Clear Floats Without Structural Markup》(注:本站将尽快翻译此文)。
    上面2种方法可以很好解决浮动超出的问题,但是如果当你真的需要对层或者层里的对象进行clear的时候怎么办?一种简单的方法就是用overflow属性,这个方法最初的发表在《Simple Clearing of Floats》,又在《Clearance》和《Super simple clearing floats》中被广泛讨论。
    上面那一种clear方法更适合你,要看具体的情况,这里不再展开论述。另外关于float的应用,一些优秀的文章已经说得很清楚,推荐你阅读:《Floatutorial》、《Containing Floats》和《Float Layouts》
     
    十四.横向居中(centering)
    这是一个简单的技巧,但是值得再说一遍,因为我看见太多的新手问题都是问这个:CSS如何横向居中?你需要定义元素的宽,并且定义横向的margin,如果你的布局包含在一个层(容器)中,就象这样:
    <!-- 你的布局这里开始 -->
    你可以这样定义使它横向居中:
    #wrap {
    width:760px; /* 修改为你的层的宽度 */
    margin:0 auto;
    }
    但是IE5/Win不能正确显示这个定义,我们采用一个非常有用的技巧来解决:用text-align属性。就象这样:
    body {
    text-align:center;
    }
    #wrap {
    width:760px; /* 修改为你的层的宽度 */
    margin:0 auto;
    text-align:left;
    }
    第一个body的text-align:center; 规则定义IE5/Win中body的所有元素居中(其他浏览器只是将文字居中) ,第二个text-align:left;是将#warp中的文字居左。
     
    十五.导入(Import)和隐藏CSS
    因为老版本浏览器不支持CSS,一个通常的做法是使用@import技巧来把CSS隐藏起来。例如:
    @import url(main.css);
    然而,这个方法对IE4不起作用,这让我很是头疼了一阵子。后来我用这样的写法:
    @import main.css;
    这样就可以在IE4中也隐藏CSS了,呵呵,还节省了5个字节呢。想了解@import语法的详细说明,可以看这里《centricle’s css filter chart》
     
    十六.针对IE的优化
    有些时候,你需要对IE浏览器的bug定义一些特别的规则,这里有太多的CSS技巧(hacks),我只使用其中的两种方法,不管微软在即将发布的IE7 beta版里是否更好的支持CSS,这两种方法都是最安全的。
    * 1.注释的方法
    o (a)在IE中隐藏一个CSS定义,你可以使用子选择器(child selector):
    html>body p {
    /* 定义内容 */
    }
    o (b)下面这个写法只有IE浏览器可以理解(对其他浏览器都隐藏)
    * html p {
    /* declarations */
    }
    o (c)还有些时候,你希望IE/Win有效而IE/Mac隐藏,你可以使用反斜线技巧:
    /* */
    * html p {
    declarations
    }
    /* */
    * 2.条件注释(conditional comments)的方法
    另外一种方法,我认为比CSS Hacks更加经得起考验就是采用微软的私有属性条件注释(conditional comments)。用这个方法你可以给IE单独定义一些样式,而不影响主样式表的定义。就象这样:
    <!--[if IE]>
    <link rel=stylesheet type=text/css href=ie.css />
    <![endif]-->
     
    十七.调试技巧:层有多大?
    当调试CSS发生错误,你就要象排版工人,逐行分析CSS代码。我通常在出问题的层上定义一个背景颜色,这样就能很明显看到层占据多大空间。有些人建议用 border,一般情况也是可以的,但问题是,有时候border 会增加元素的尺寸,border-top和boeder-bottom会破坏纵向margin的值,所以使用background更加安全些。
    另外一个经常出问题的属性是outline。outline看起来象boeder,但不会影响元素的尺寸或者位置。只有少数浏览器支持outline属性,我所知道的只有Safari、OmniWeb、和Opera。
     
    十八.CSS代码书写样式
    在写CSS代码的时候,对于缩进、断行、空格,每个人有每个人的书写习惯。在经过不断实践后,我决定采用下面这样的书写样式:
    selector1,
    selector2 {
    property:value;
    }
    当使用联合定义时,我通常将每个选择器单独写一行,这样方便在CSS文件中找到它们。在最后一个选择器和大括号{之间加一个空格,每个定义也单独写一行,分号直接在属性值后,不要加空格。
    我习惯在每个属性值后面都加分号,虽然规则上允许最后一个属性值后面可以不写分号,但是如果你要加新样式时容易忘记补上分号而产生错误,所以还是都加比较好。
    最后,关闭的大括号}单独写一行。
    空格和换行有助与阅读。

    longhorn server Key

     
    2. Click Invitations
     
    3. Input your E-mail address  and  Password for the Sign in
     
    4. Input the Invitaion ID : TE06-KVM4-3RM9  to GO
     
    5. Click Product Keys
     
    6. Click Request New Product Key
     
     
    Key :  49HMJ-F2KY4-K984X-62FFP-V9X84
     
    this key only for Longhorn Server , not Windows Vista.
    2006/12/6

    Windows Server 2003 IIS6 PHP

     第一步:相关软件准备(以下软件全部是截止到2006年7月7日的)
    PHP: 推荐PHP-4.4.0-Win32的ZIP解压版本
       4.4.0版本下载:http://cn.php.net/get/php-4.4.0-Win32.zip/from/a/mirror
       5.1.2版本下载:http://cn.php.net/get/php-5.1.2-Win32.zip/from/a/mirror
       5.1.4版本下载:http://download.discuz.net/env/php-5.1.4-Win32.zip
    MySQL:配合PHP4推荐MySQL5.0.22的WIN系统安装版本
       5.0.22版本下载:http://download.discuz.net/env/mysql-essential-5.0.22-win32.msi
       官方下载地址:http://dev.mysql.com/downloads/mysql/5.0.html
    ZendOptimizer:版本越新越好啊(目前最新是2.6.2)
       官方下载地址:https://www.zend.com/store/free_download.php?pid=13
       (虽然下载是免费的,但是要注册用户,才可以下载,为了方便大家的使用,公开我注册好的用户名:ideacmblog密码:chm.ideacm.cn,方便大家使用,希望大家在使用这个帐号的时候不要修改密码和用于其它非正当途径)
    phpMyAdmin:这个当然也是越新越好啊
       官方下载地址:http://www.phpmyadmin.net/home_page/downloads.php
       国内下载地址:http://www.crsky.com/soft/4190.html
                                   http://www.skycn.com/soft/10687.html
    好了,软件下载好了,现在就开始安装了;
    假设你的系统在C://,如果你的系统不是C://那么下面请自己对应修改。同时,为了避免C://因为重装系统等等各种原因,对C盘进行操作,和在系统盘下备份、转移也很不方便,所以不建议将PHP相关软件安装在C://,这里我把它安装在D://php目录下(这个目录你也可以自己设定,如果你要安装到不同墓立涉及到路径修改的请修改下面对应的路径即可)
    第二步:安装PHP(我取PHP安装路径取为D://php//php4//(为避混淆,PHP5.1.x版本安装路径取为D://php//php5//)
       (1)、下载得到的 php-4.4.0-Win32.zip ,解压至D://php目录,将得到二级目录php-4.4.0-Win32,改名为 php4,也即得到PHP文件存放目录D://php//php4//[如果是PHP5.1.2,得到的文件是php-5.1.2-Win32.zip,直接全部接压至D://php//php5目录即可得PHP文件存放目录D://php//php5//];
       (2)、再将D://php//php4目录和D://php//php4//dlls目录[PHP5为D://php//php5//]下的所有dll文件拷到c://Windows//system32(win2000系统为 c:/winnt/system32/)下,如果目录下有这些dll文件就覆盖已有的dll文件;
       (3)、将D://php//php4//php.ini-dist用记事本打开,利用记事本的查找功能(Ctrl+F)搜索并修改:
       register_globals = Off
       把 Off 改成 On ,即得到 register_globals = On
       注:这个对应PHP的全局变量功能,考虑有很多PHP程序需要全局变量功能故打开,打开后请注意-PHP程序的严谨性,如果不需要推荐不修改保持默认Off状态
    再搜索
       extension_dir =
    ,并将其路径指到你的 PHP 目录下的 extensions 目录,比如:修改extension_dir = "./"为extension_dir = "D:/php/php4/extensions/" ;
    PHP扩展功能目录[PHP5对应修改为extension_dir = "D:/php/php5/ext/"]
    在D://php下建立文件夹并命名为tmp
    查找
       ;upload_tmp_dir =
    将;upload_tmp_dir该行的注释符,即前面的分号“;”去掉,使该行在php.ini文档中起作用。upload_tmp_dir是用来定义上传文件存放的临时路径,在这里你还可以修改并给其定义一个绝对路径,这里设置的目录必须有读写权限。
    这里我设置为upload_tmp_dir = D:/php/tmp  (即前面建立的这个文件夹呵)
    搜索找到
       ;Windows Extensions
    将下面一些常用的项前面的;去掉
       ;extension=php_mbstring.dll
       ;extension=php_curl.dll
       ;extension=php_dbase.dll
       ;extension=php_gd2.dll
    这个是用来支持GD库的,一般需要,必选
       ;extension=php_ldap.dll
       extension=php_zip.dll
    去掉前面的";"
    对于PHP5的版本还需要查找
       ;extension=php_mysql.dll
    并同样去掉前面的";"
    这个是用来支持MYSQL的,由于PHP5将MySQL作为一个独立的模块来加载运行的,故要支持MYSQL必选
    查找
       ;session.save_path =
    去掉前面;号,本文这里将其设置置为
    session.save_path = D:/php/tmp
    其他的你可以选择需要的去掉前面的;然后将该文件另存为为php.ini到C://Windows ( Windows 2000 下为 C://WINNT)目录下,注意更改文件后缀名为ini,得到C://Windows//php.ini ( Windows 2000 下为 C://WINNT//php.ini)
    若路径等和本文相同可直接保存到C://Windows ( Windows 2000 下为 C://WINNT)目录下使用若路径等和本文相同可直接保存到C://Windows ( Windows 2000 下为 C://WINNT)目录下使用
    一些朋友经常反映无法上传较大的文件或者运行某些程序经常超时,那么可以找到C://Windows ( Windows 2000 下为 C://WINNT)目录下的PHP.INI以下内容修改:
    max_execution_time = 30     ; 这个是每个脚本运行的最长时间,可以自己修改加长,单位秒
    max_input_time = 60        ; 这是每个脚本可以消耗的时间,单位也是秒
    memory_limit = 8M      ; 这个是脚本运行最大消耗的内存,也可以自己加大
    upload_max_filesize = 2M ; 上载文件的最大许可大小 ,自己改吧,一些图片论坛需要这个更大的值
    第四步:配置IIS使其支持PHP
       IIS如何安装,那就不用说了吧!
       PHP 支持 CGI 和 ISAPI 两种安装模式,CGI 更消耗资源,容易因为超时而没有反映,但是实际上比较安全,负载能力强,节省资源,但是安全性略差于CGI,本人推荐使用 ISAPI 模式。故这里只解介绍 ISAPI 模式安装方法:
       在“控制面板”的“管理工具”中选择“Internet 服务管理器”,打开 IIS 后停止服务,对于Win2003系统展开”Internet 服务管理器“的下级树一般为你的”计算机名“选择”网站“并单击右键选择“属性”,在弹出的属性窗口上选择“ISAPI 筛选器”选项卡找到并点击“添加”按钮,在弹出的“筛选器属性”窗口中的“筛选器名称”栏中输入:PHP ,再将浏览可执行文件使路径指向 php4isapi.dll 所在路径,如本文中为:D://php//php4//sapi//php4isapi.dll[PHP5对应路径为D://php//php5//php5isapi.dll]。
    打开“站点属性”窗口的“主目录”选项卡,找到并点击“配置”按钮
    在弹出的“应用程序配置”窗口中的”应用程序映射“选项卡找到并点击“添加”按钮新增一个扩展名映射,在弹出的窗口中单击“浏览”将可执行文件指向 php4isapi.dll 所在路径,如本文中为:D://php//php4//sapi//php4isapi.dll[PHP5对应路径为D://php//php5//php5isapi.dll],扩展名为 .php ,动作限于”GET,HEAD,POST,TRACE“,将“脚本引擎”“确认文件是否存在”选中,然后一路确定即可。如果还想支持诸如 .php3 ,.phtml 等扩展名的 PHP 文件,可以重复“添加”步骤,对应扩展名设置为需要的即可如.PHPX。
    此步操作将使你服务器IIS下的所有站点都支持你所添加的PHP扩展文件,当然如果你只需要部分站点支持PHP,只需要在“你需要支持PHP的Web站点”比如“默认Web站点”上单击右键选择“属性”,在打开的“ Web 站点属性”“主目录”选项卡,编辑或者添加PHP的扩展名映射即可或者将你步需要支持PHP的站点中的PHP扩展映射删除即可
    再打开“站点属性”窗口的“文档”选项卡,找到并点击“添加”按钮,向默认的 Web 站点启动文档列表中添加 index.php 项。您可以将 index.php 升到最高优先级,这样,访问站点时就会首先自动寻找并打开 index.php 文档。
    确定 Web 目录的应用程序设置和执行许可中选择为纯脚本,然后关闭 Internet 信息服务管理器
    对于2003系统还需要在“Internet 服务管理器”左边的“WEB服务扩展”中设置ISAPI 扩展允许,Active Server Pages 允许
    完成所有操作后,重新启动IIS服务。
    在CMD命令提示符中执行如下命令:
    net stop w3svc
    net stop iisadmin
    net start w3svc
    到此,PHP的基本安装已经完成,我们已经使网站支持PHP脚本。
    检查方法是,在 IIS 根目录下新建一个文本文件存为 php.php ,内容如下:
    phpinfo();
    ?>
    打开浏览器,输入:http://localhost/php.php,将显示当前服务器所支持 PHP 的全部信息,可以看到 Server API的模式为:ISAPI 。
    或者利用PHP探针检测,到http://depoch.net/download.htm下载后解压到你的站点根目录下并访问即可
    第三步:安装MySQL
       对于MySQL4.0.26下载得到的是mysql-4.0.26-win32.zip,解压到mysql-4.0.26-win32目录双击执行 Setup.exe 一路Next下一步,选择安装目录为D://php//MySQL和安装方式为Custom自定义安装,再一路Next下一步即可。
       安装完毕后,在CMD命令行中输入并运行:
       D://php//MySQL//bin//mysqld-nt -install
       如果返回Service successfully installed.则说明系统服务成功安装
    新建一文本文件存为MY.INI,编辑配置MY.INI,这里给出一个参考的配置
      
    [mysqld]
    basedir=D:/php/MySQL
    #MySQL所在目录
    datadir=D:/php/MySQL/data
    #MySQL数据库所在目录,可以更改为其他你存放数据库的目录
    #language=D:/php/MySQL/share/your language directory
    #port=3306
    set-variable    = max_connections=800
    skip-locking
    set-variable        = key_buffer=512M
    set-variable        = max_allowed_packet=4M
    set-variable        = table_cache=1024
    set-variable        = sort_buffer=2M
    set-variable        = thread_cache=64
    set-variable        = join_buffer_size=32M
    set-variable        = record_buffer=32M
    set-variable        = thread_concurrency=8
    set-variable        = myisam_sort_buffer_size=64M
    set-variable        = connect_timeout=10
    set-variable        = wait_timeout=10
    server-id        = 1
    [isamchk]
    set-variable        = key_buffer=128M
    set-variable        = sort_buffer=128M
    set-variable        = read_buffer=2M
    set-variable        = write_buffer=2M
    [myisamchk]
    set-variable        = key_buffer=128M
    set-variable        = sort_buffer=128M
    set-variable        = read_buffer=2M
    set-variable        = write_buffer=2M
    [WinMySQLadmin]
    Server=D:/php/MySQL/bin/mysqld-nt.exe
    保存后复制此MY.INI文件到C://Windows ( Windows 2000 下为 C://WINNT)目录下
    回到CMD命令行中输入并运行:
    net start mysql
    MySQL 服务正在启动 .
    MySQL 服务已经启动成功。
    将启动 MySQL 服务;
    DOS下修改ROOT密码:当然后面安装PHPMYADMIN后修改密码也可以通过PHPMYADMIN修改
    格式:mysqladmin -u用户名 -p旧密码 password 新密码
    例:给root加个密码ideacmblog
    首先在进入CMD命令行,转到MYSQL目录下的bin目录,然后键入以下命令
    mysqladmin -uroot password ideacmblog
    注:因为开始时root没有密码,所以-p旧密码一项就可以省略了。
    D://php//MySQL//bin>mysqladmin -uroot password ideacmblog回车后ROOT密码就设置为ideacmblog了
    如果你下载的是 MySQL5.x或者MySQL4.1.x,例mysql-5.0.18-win32:解压后双击执行 Setup.exe ,Next下一步后选择Custom自定义安装,再Next下一步选择安装路径这里我们选择D://php//MySQL,继续Next下一步跳过Sign UP完成安装。
    安装完成后会提示你是不是立即进行配置,选择是即可进行配置。当然一般安装后菜单里面也有配置向导MySQL Server Instance Config Wizar,运行后按下面步骤配置并设置ROOT密码即可
    Next下一步后选择Standard Configuration
    Next下一步,钩选Include .. PATH
    Next下一步,设置ROOT密码,建议社设置复杂点,确保服务器安全!
    Apply完成后将在D://php//MySQL目录下生成MY.INI配置文件,添加并启动MySQL服务

    第四步:安装 Zend Optimizer
       下载后得到 ZendOptimizer-2.6.2-Windows-i386.exe ,直接双击安装即可,安装过程要你选择 Web Server 时,选择 IIS ,然后提示你是否 Restart Web Server,选择是,完成安装之前提示是否备份 php.ini ,点确定后安装完成。我这里安装到D://php//Zend
    以下两步的目录根据你自己的默认WEB站点目录来选,当然也可以选择到D://php//Zend目录
       Zend Optimizer 的安装向导会自动根据你的选择来修改 php.ini 帮助你启动这个引擎。下面简单介绍一下 Zend Optimizer 的配置选项。以下为本人安装完成后 php.ini 里的默认配置代码(分号后面的内容为注释):
    zend_extension_ts="D://php//Zend//lib//ZendExtensionManager.dll"
    ;Zend Optimizer 模块在硬盘上的安装路径。
    zend_extension_manager.optimizer_ts="D://php//Zend//lib//Optimizer-2.6.2"
    ;优化器所在目录,默认无须修改。
    zend_optimizer.optimization_level=1023
    ;优化程度,这里定义启动多少个优化过程,默认值是 15 ,表示同时开启 10 个优化过程中的 1-4 ,我们可以将这个值改为 1023 ,表示开启全部10个优化过程。
    调用phpinfo()函数后显示:
    Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies with Zend Extension Manager v1.0.9, Copyright (c) 2003-2006, by Zend Technologies with Zend Optimizer v2.6.2, Copyright (c) 1998-2006, by Zend Technologies 则表示安装成功。
    第五步:安装GD库
       这一步在前面PHP.INI配置中去掉“;extension=php_gd2.dll”前面的;实际上已经安装好了~
    [在php.ini里找到"extension=php_gd2.dll"这一行,并且去掉前面的分号,gd库安装完成,用echophpinfo();测试是否成功! ]
    第六步:安装phpMyAdmin
       下载得到 phpMyAdmin-2.8.2.zip ,将其解压到D://php//或者 IIS 根目录,改名phpMyAdmin-2.8.2为phpMyAdmin,并在IIS中建立新站点或者虚拟目录指向该目录以便通过WEB地址访问,这里建立默认站点的phpMyAdmin虚拟目录指向D://php//phpMyAdmin目录通过http://localhost/phpmyadmin/访问
    找到并打开D://php//phpMyAdmin//libraries(phpMyAdmin2.7.0和以前的版本在D://php//phpMyAdmin//目录下)目录下的 config.default.php ,做以下修改:
    查找
    $cfg[/'PmaAbsoluteUri/']
    设置你的phpmyadmin的WEB访问URL,如本文中:$cfg[/'PmaAbsoluteUri/'] = /'http://localhost/phpmyadmin//'; 注意这里假设phpmyadmin在默认站点的根目录下
    搜索
    $cfg[/'blowfish_secret/'] =
    设置COOKIES加密密匙,如ideacmblog则设置为$cfg[/'blowfish_secret/'] = /'ideacmblog/';
    搜索$cfg[/'Servers/'][$i][/'auth_type/'],默认为config,是不安全的,不推荐,推荐使用cookie,将其设置为$cfg[/'Servers/'][$i][/'auth_type/']     = /'cookie/';
    注意这里如果设置为config请在下面设置用户名和密码!例如:
    $cfg[/'Servers/'][$i][/'user/']          = /'root/';      // MySQL user-----MySQL连接用户
    $cfg[/'Servers/'][$i][/'password/']      = /'ideacmblog/';  
    搜索$cfg[/'DefaultLang/'] ,将其设置为 zh-gb2312 ;
    搜索$cfg[/'DefaultCharset/'] ,将其设置为 gb2312 ;
    打开浏览器,输入:http://localhost/phpMyAdmin/ ,若 IIS 和 MySQL 均已启动,输入用户ROOT密码ideacmblog(如没有设置密码则密码留空)即可进入phpMyAdmin数据库管理。
    在进http://localhost/phpmyadmin/输入用户名和密码后,如果出现 Client does not support authentication protocol requested by server; consider upgrading MySQL client 错误提示,
    这是由于MySQL 4.1 及其后版本验证协议使用的密码哈希算法与老的客户端不兼容,因此需要在MySQL Command Line Client里面用命令同步兼容密码:
    进入MySQL Command Line Client后MYSQL的提示符是:mysql>
    然后执行:
    SET PASSWORD FOR /'root/'@/'localhost/' = OLD_PASSWORD(/'你的ROOT管理密码/');
    再可以进入phpmyadmin管理,每新建一个用户的时候都要这样执行命令一次,注意把root替换成你新建的用户名和对应的密码。
    首先点击权限进入用户管理,删除除ROOT和主机不为localhost的用户并重新读取用户权限表,这里同样可以修改和设置ROOT的密码,添加其他用户等。
    phpMyAdmin 的具体功能,请慢慢熟悉,这里就不赘述。
    至此所有安装完毕。
    第七步:目录结构以及NTFS格式下安全的目录权限设置:
       当前目录结构为
                                                D://php
                                                     |
                    +—————+——————+———————+———————+
                php4(php5)    tmp             MySQL                     Zend         phpMyAdmin
       D://php设置为管理员和SYSTEM完全权限即可,其他用户均无权限
       对于其下的二级目录
       php4(或者php5)、 tmp 给EVERYONE完全权限
       MySQL 、Zend 管理员和SYSTEM完全权限
       phpMyAdminWEB匿名用户读取运行权限
    发表于 2007-08-14 08:37 网络金领 阅读(1008) 评论(0)  编辑 收藏 网摘
    展开全文
  • sql server

    千次阅读 2012-03-23 01:14:56
    sql server 作者:Sanle 来源:博客园 发布时间:2006-04-27 13:06 阅读:3402 次 原文链接 [收藏]  ...1.清空日志:DUMP TRANSACTION 库名 WITH NO_LOG  ...2.截断事务日志:BACKUP LOG 数据库名 WITH NO_...

    sql server

    作者:Sanle  来源:博客园  发布时间:2006-04-27 13:06  阅读:3402 次  原文链接   [收藏]  

    1.清空日志:DUMP TRANSACTION 库名 WITH NO_LOG 
    2.截断事务日志:BACKUP LOG 数据库名 WITH NO_LOG 
    3.收缩数据库文件(如果不压缩,数据库的文件不会减小)  
      --收缩数据库 DBCC SHRINKDATABASE(database_name) 
      --收缩指定数据文件,1是文件号,可以通过这个语句查询到:
        select * from sysfiles DBCC SHRINKFILE(1) 
    4.为了最大化的缩小日志文件(如果是sql 7.0,这步只能在查询分析器中进行) 
      a.分离数据库 
      b.在我的电脑中删除LOG文件 
      c.附加数据库.此法将生成新的LOG,大小只有500多K 
        (用代码:下面的示例分离 pubs,然后将 pubs 中的一个文件附加到当前服务器。 
         a.分离 EXEC sp_detach_db @dbname = 'pubs' 
         b.删除日志文件 
         c.再附加 EXEC sp_attach_single_file_db 
                  @dbname = 'pubs', 
           @physname = 'c:\Program Files\Microsoft SQL Server\MSSQL\Data\pubs.mdf') 
    5.为了以后能自动收缩,设置:企业管理器--服务器--右键数据库--属性--选项--选择"自动收缩" 
      --SQL语句设置方式: EXEC sp_dboption '数据库名', 'autoshrink', 'TRUE'
    6.如果想以后不让它日志增长得太大:企业管理器--服务器--右键数据库--属性--事务日志 --将文      件增长限制为xM(x是你允许的最大数据文件大小) 
      --SQL语句的设置方式: alter database 数据库名 modify file(name=逻辑文件名,maxsize=20)


    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=654569

    数据库日志文件的误删或别的原因引起数据库日志的损坏 
      方法一

      1.新建一个同名的数据库

      2.再停掉sql server(注意不要分离数据库)

      3.用原数据库的数据文件覆盖掉这个新建的数据库

      4.再重启sql server

      5.此时打开企业管理器时会出现置疑,先不管,执行下面的语句(注意修改其中的数据库名)

      6.完成后一般就可以访问数据库中的数据了,这时,数据库本身一般还要问题,解决办法是,利用

      数据库的脚本创建一个新的数据库,并将数据导进去就行了.

      USE MASTER

      GO

      SP_CONFIGURE 'ALLOW UPDATES',1 RECONFIGURE WITH OVERRIDE

      GO

      UPDATE SYSDATABASES SET STATUS =32768 WHERE NAME='置疑的数据库名'

      Go

      sp_dboption '置疑的数据库名', 'single user', 'true'

      Go

      DBCC CHECKDB('置疑的数据库名')

      Go

      update sysdatabases set status =28 where name='置疑的数据库名'

      Go

      sp_configure 'allow updates', 0 reconfigure with override

      Go

      sp_dboption '置疑的数据库名', 'single user', 'false'

      Go

      方法二

      事情的起因

      昨天,系统管理员告诉我,我们一个内部应用数据库所在的磁盘空间不足了。我注意到数据库事件日志文件XXX_Data.ldf文件已经增长到了3GB,于是我决意缩小这个日志文件。经过收缩数据库等操作未果后,我犯了一个自进入行业以来的最大最愚蠢的错误:竟然误删除了这个日志文件!后来我看到所有论及数据库恢复的文章上都说道:“无论如何都要保证数据库日志文件存在,它至关重要”,甚至微软甚至有一篇KB文章讲如何只靠日志文件恢复数据库的。我真是不知道我那时候是怎么想的?!

      这下子坏了!这个数据库连不上了,企业管理器在它的旁边写着“(置疑)”。而且最要命的,这个数据库从来没有备份了。我唯一找得到的是迁移半年前的另外一个数据库服务器,应用倒是能用了,但是少了许多记录、表和存储过程。真希望这只是一场噩梦!

      没有效果的恢复步骤

      附加数据库

      _Rambo讲过被删除日志文件中不存在活动日志时,可以这么做来恢复:

      1,分离被置疑的数据库,可以使用sp_detach_db

      2,附加数据库,可以使用sp_attach_single_file_db

      但是,很遗憾,执行之后,SQL Server质疑数据文件和日志文件不符,所以无法附加数据库数据文件。

      DTS数据导出

      不行,无法读取XXX数据库,DTS Wizard报告说“初始化上下文发生错误”。

      紧急模式

      怡红公子讲过没有日志用于恢复时,可以这么做:

      1,把数据库设置为emergency mode

      2,重新建立一个log文件

      3,把SQL Server 重新启动一下

      4,把应用数据库设置成单用户模式

      5,做DBCC CHECKDB

      6,如果没有什么大问题就可以把数据库状态改回去了,记得别忘了把系统表的修改选项关掉

      我实践了一下,把应用数据库的数据文件移走,重新建立一个同名的数据库XXX,然后停掉SQL服务,把原来的数据文件再覆盖回来。之后,按照怡红公子的步骤走。

      但是,也很遗憾,除了第2步之外,其他步骤执行非常成功。可惜,重启SQL Server之后,这个应用数据库仍然是置疑!

      不过,让我欣慰的是,这么做之后,倒是能够Select数据了,让我大出一口气。只不过,组件使用数据库时,报告说:“发生错误:-2147467259,未能在数据库 'XXX' 中运行 BEGIN TRANSACTION,因为该数据库处于回避恢复模式。”

      最终成功恢复的全部步骤

      设置数据库为紧急模式

      停掉SQL Server服务;

      把应用数据库的数据文件XXX_Data.mdf移走;

      重新建立一个同名的数据库XXX;

      停掉SQL服务;

      把原来的数据文件再覆盖回来;

      运行以下语句,把该数据库设置为紧急模式;

      运行“Use Master

      Go

      sp_configure 'allow updates', 1

      reconfigure with override

      Go”

      执行结果:

      DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

      已将配置选项 'allow updates' 从 0 改为 1。请运行 RECONFIGURE 语句以安装。

      接着运行“update sysdatabases set status = 32768 where name = 'XXX'”

      执行结果:

      (所影响的行数为 1 行)

      重启SQL Server服务;

      运行以下语句,把应用数据库设置为Single User模式;

      运行“sp_dboption 'XXX', 'single user', 'true'”

      执行结果:

      命令已成功完成。

      ü 做DBCC CHECKDB;

      运行“DBCC CHECKDB('XXX')”

      执行结果:

      'XXX' 的 DBCC 结果。

      'sysobjects' 的 DBCC 结果。

      对象 'sysobjects' 有 273 行,这些行位于 5 页中。

      'sysindexes' 的 DBCC 结果。

      对象 'sysindexes' 有 202 行,这些行位于 7 页中。

      'syscolumns' 的 DBCC 结果。

      ………

      ü 运行以下语句把系统表的修改选项关掉;

      运行“sp_resetstatus "XXX"

      go

      sp_configure 'allow updates', 0

      reconfigure with override

      Go”

      执行结果:

      在 sysdatabases 中更新数据库 'XXX' 的条目之前,模式 = 0,状态 = 28(状态 suspect_bit = 0),

      没有更新 sysdatabases 中的任何行,因为已正确地重置了模式和状态。没有错误,未进行任何更改。

      DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

      已将配置选项 'allow updates' 从 1 改为 0。请运行 RECONFIGURE 语句以安装。

      重新建立另外一个数据库XXX.Lost;

      DTS导出向导

      运行DTS导出向导;

      复制源选择EmergencyMode的数据库XXX,导入到XXX.Lost;

      选择“在SQL Server数据库之间复制对象和数据”,试了多次,好像不行,只是复制过来了所有表结构,但是没有数据,也没有视图和存储过程,而且DTS向导最后报告复制失败;

      所以最后选择“从源数据库复制表和视图”,但是后来发现,这样总是只能复制一部分表记录;

      于是选择“用一条查询指定要传输的数据”,缺哪个表记录,就导哪个;

      视图和存储过程是执行SQL语句添加的。

      维护Sql Server中表的索引

      在使用和创建数据库索引中经常会碰到一些问题,在这里可以采用一些另类的方法解决…

      --第一步:查看是否需要维护,查看扫描密度/Scan Density是否为100%

      declare @table_id int

      set @table_id=object_id('表名')

      dbcc showcontig(@table_id)

      --第二步:重构表索引

      dbcc dbreindex('表名',pk_索引名,100)

      --重做第一步,如发现扫描密度/Scan Density还是小于100%则重构表的所有索引

      --并不一定能达100%。

      dbcc dbreindex('表名','',100)

     


    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=654300
    SQL语句的优化是将性能低下的SQL语句转换成目的相同的性能优异的SQL语句。

      人工智能自动SQL优化就是使用人工智能技术,自动对SQL语句进行重写,从而找到性能最好的等效SQL语句。

      数据库性能的优化

     
      一个数据库系统的生命周期可以分成:设计、开发和成品三个阶段。在设计阶段进行数据库性能优化的成本最低,收益最大。在成品阶段进行数据库性能优化的成本最高,收益最小。

      数据库的优化通常可以通过对网络、硬件、操作系统、数据库参数和应用程序的优化来进行。最常见的优化手段就是对硬件的升级。根据统计,对网络、硬件、操作系统、数据库参数进行优化所获得的性能提升,全部加起来只占数据库系统性能提升的40%左右,其余的60%系统性能提升来自对应用程序的优化。许多优化专家认为,对应用程序的优化可以得到80%的系统性能的提升。

      应用程序的优化

      应用程序的优化通常可分为两个方面:源代码和SQL语句。由于涉及到对程序逻辑的改变,源代码的优化在时间成本和风险上代价很高,而对数据库系统性能的提升收效有限。

      为什么要优化SQL语句

      . SQL语句是对数据库进行操作的惟一途径,对数据库系统的性能起着决定性的作用。

      . SQL语句消耗了70%至90%的数据库资源。

      . SQL语句独立于程序设计逻辑,对SQL语句进行优化不会影响程序逻辑。

      . SQL语句有不同的写法,在性能上的差异非常大。

      . SQL语句易学,但难精通。

      优化SQL语句的传统方法是通过手工重写来对SQL语句进行优化。DBA或资深程序员通过对SQL语句执行计划的分析,依靠经验,尝试重写SQL语句,然后对结果和性能进行比较,以试图找到性能较佳的SQL语句。这种传统上的作法无法找出SQL语句的所有可能写法,且依赖于人的经验,非常耗费时间。

      SQL优化技术的发展历程

      第一代SQL优化工具是执行计划分析工具。这类工具针对输入的SQL语句,从数据库提取执行计划,并解释执行计划中关键字的含义。

      第二代SQL优化工具只能提供增加索引的建议,它通过对输入的SQL语句的执行计划的分析,来产生是否要增加索引的建议。

      第三代SQL优化工具不仅分析输入SQL语句的执行计划,还对输入的SQL语句本身进行语法分析,经过分析产生写法上的改进建议。

      人工智能自动SQL优化


    图1 人工智能自动SQL优化示意图

      人工智能自动SQL优化出现在90年代末。目前在商用数据库领域,LECCO Technology Limited(灵高科研有限公司)拥有该技术,并提供使用该技术的自动优化产品LECCO SQL Expert,它支持Oracle、Sybase、MS SQL Server和IBM DB2数据库平台。该产品针对数据库应用的开发和维护阶段提供的模块有:SQL语法优化器、PL/SQL集成化开发调试环境(IDE)、扫描器、数据库监视器等。其核心模块SQL 语法优化器的工作原理为:①输入一条源SQL语句;②“人工智能反馈式搜索引擎”对输入的SQL语句,结合检测到的数据库结构和索引进行重写,产生N条等效的SQL语句输出;③产生的N条等效SQL语句再送入“人工智能反馈式搜索引擎”进行重写,直至无法产生新的输出或搜索限额满;④对输出的SQL语句进行过滤,选出具有不同执行计划的SQL语句;⑤对得到的SQL语句进行批量测试,找出性能最好的SQL语句。

      LECCO SQL Expert自动优化实例

      假设我们从源代码中抽取出这条SQL语句(也可以通过内带的扫描器或监视器获得SQL语句):

      SELECT COUNT(*)

       FROM EMPLOYEE

      swheresEXISTS (SELECT 'X'

       FROM DEPARTMENT

      swheresEMP_DEPT=DPT_ID

       AND DPT_NAME LIKE 'AC%')

      AND EMP_ID IN (SELECT SAL_EMP_ID

       FROM EMP_SAL_HIST B

      swheresSAL_SALARY > 70000)

      按下“优化”按钮后,经过10几秒,SQL Expert就完成了优化的过程,并在这10几秒的时间里重写产生了2267 条等价的SQL语句,其中136条SQL语句有不同的执行计划。

      接下来,我们可以对自动重写产生的136条SQL语句进行批运行测试,以选出性能最佳的等效SQL语句。按下“批运行” 按钮,在“终止条件” 页选择“最佳运行时间SQL语句”,按“确定”。

      经过几分钟的测试运行后,我们可以发现SQL124的运行时间和反应时间最短。运行速度约有22.75倍的提升(源SQL语句运行时间为2.73秒,SQL124运行时间为0.12秒)。现在我们就可以把SQL124放入源代码中,结束一条SQL语句的优化工作了。

      “边做边学式训练”提升SQL开发水平

      LECCO SQL Expert不仅能够找到最佳的SQL语句,它所提供的“边做边学式训练”还能够教开发人员和数据库管理员如何写出性能最好的SQL语句。LECCO SQL Expert的“SQL比较器”可以标明源SQL和待选SQL间的不同之处。

      以上面优化的结果为例,为了查看源SQL语句和SQL124在写法上有什么不同,我们可以按下“比较器” 按钮,对SQL124和源SQL语句进行比较。“SQL 比较器”将SQL124相对于源SQL语句的不同之处以蓝颜色表示了出来。如果选择“双向比较”复选框,“SQL 比较器”可以将两条SQL语句的不同之处以蓝色表示。当然,我们也可以从源语句和重写后的SQL 语句中任选两条进行比较。

      从比较的结果可以看到,重写后的SQL124把第一个Exists改写成了In;在字段DPT_ID上进行了合并空字符串的操作,以诱导数据库先执行子查询中的

      (SELECT DPT_ID||''

      FROM DEPARTMENT

      WHERE DPT_NAME LIKE 'AC%')

      在子查询完成后,再与EMPLOYEE表进行嵌套循环连接(Nested Loop Join)。

      如果觉得对写法的改变难以理解,还可以点中“执行计划”复选框,通过比较两条SQL语句的执行计划的不同,来了解其中的差异。在查看执行计划过程中,如果有什么不明白的地方,可以点中“SQL信息按钮”,再点击执行计划看不明白的地方,LECCO SQL Expert的上下文敏感帮助系统将提供执行计划该处的解释。

      在“SQL比较器”中,选中“统计信息”复选框后,可得到详细的两条SQL语句运行时的统计信息比较,这对于学习不同的SQL写法对数据库资源的消耗很有帮助。

      LECCO SQL Expert优化模块的特点

      LECCO SQL Expert优化模块的特点主要表现为:自动优化SQL语句;以独家的人工智能知识库“反馈式搜索引擎”来重写性能优异的SQL语句;找出所有等效的SQL语句及可能的执行计划;保证产生相同的结果;先进的SQL语法分析器能处理最复杂的SQL语句;可以重写SELECT、SELECT INTO、UPDATE、INSERT和DELETE语句;通过测试运行,为应用程序和数据库自动找到性能最好的SQL语句;提供微秒级的计时,能够优化Web应用程序和有大量用户的在线事务处理中运行时间很短的SQL语句;为开发人员提供“边做边学式训练”,迅速提高开发人员的SQL编程技能;提供上下文敏感的执行计划帮助系统和SQL运行状态帮助;不是猜测或建议,而是独一无二的SQL重写解决方案。

      写出专家级的SQL语句

      LECCO SQL Expert的出现,使SQL的优化变得极其简单,只要能够写出SQL语句,它就能帮用户找到最好性能的写法。LECCO SQL Expert不仅能在很短的时间内找到所有可能的优化方案,而且能够通过实际测试,确定最有效的优化方案。同以往的数据库优化手段相比较,LECCO SQL Expert将数据库优化技术带到了一个崭新的技术高度,依赖人的经验、耗费大量时间、受人的思维束缚的数据库优化手段已经被高效、省时且准确的自动优化软件所取代了。通过内建的“LECCO小助手”的帮助,即使是SQL的开发新手,也能快速且简单地写出专家级的SQL语句。

     


    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=652551
    EmsNo        CopGNo         ExgVersion      

    E57705000004 DSHC0741           60                                  
    E57705000003 DSHC0741           50  
    E57705000002 DSHC0741           36 
    E57705000001 DSHC0742           65                                         
    E57705000000 DSHC0742           75   
    需要的结果:
    EmsNo        CopGNo         ExgVersion       
     
    E57705000004 DSHC0741           60                                   
    E57705000000 DSHC0742           75   
    既 CopGNO中每个产品的最大ExgVersion给取出来。

    SELECT T.EMSNO,E.COPGNO,E.EXGVERSION ,T.begindate,t.enddate
    FROM emsexgversion T ,(SELECT copgno,MAX(ExgVersion) as exgversion from emsexgversion group by copgno) E 
    WHERE T.COPGNO=E.COPGNO AND T.EXGVERSION=E.EXGVERSION
    ORDER BY E.COPGNO

    select a.* from emsexgversion a 
    where not exists(select 1 from emsexgversion where CopGNo=a.CopGNo and ExgVersion>a.ExgVersion)

    select 1 from ...
    通常存在于exists中.
    也可以写做
    select 2 from ...
    或者任何常数.

    因为exists只是判断为不为null来返回true或者false
    通常的写法还有
    select count(1) from ...
    其实等同于
    select count(*) from ...
    或者
    select count(主键) from ...
    这样的SQL

    根据主键及索引的建立方式,速度上有细小的差别.

    而-1 = -1这样的表达式是永远返回true的.
    就像 1 = 2是永远返回false一样.

    我们通常copy表结构就经常用
    create table newtable as
    select * from oldtable where 1 = 2;

    -1 = -1一般是写在条件不确定的用字符串拼出来的动态SQL中.
    比方说:
    我的where后面可能有5个条件,也可能一个也没有.
    这时我会这样写
    ".... where 1 = 1"+str1+str2+...; -- 其中的str1,str2等有可能是空字符串.
    *******************Transact_SQL********************

    --语 句                                功 能
    --数据操作
    SELECT      --从数据库表中检索数据行和列
    INSERT      --向数据库表添加新数据行
    DELETE      --从数据库表中删除数据行
    UPDATE      --更新数据库表中的数据
    --数据定义
    CREATE TABLE    --创建一个数据库表
    DROP TABLE     --从数据库中删除表
    ALTER TABLE     --修改数据库表结构
    CREATE VIEW     --创建一个视图
    DROP VIEW     --从数据库中删除视图
    CREATE INDEX    --为数据库表创建一个索引
    DROP INDEX     --从数据库中删除索引
    CREATE PROCEDURE   --创建一个存储过程
    DROP PROCEDURE    --从数据库中删除存储过程
    CREATE TRIGGER    --创建一个触发器
    DROP TRIGGER    --从数据库中删除触发器
    CREATE SCHEMA    --向数据库添加一个新模式
    DROP SCHEMA     --从数据库中删除一个模式
    CREATE DOMAIN    --创建一个数据值域
    ALTER DOMAIN    --改变域定义
    DROP DOMAIN     --从数据库中删除一个域
    --数据控制
    GRANT      --授予用户访问权限
    DENY      --拒绝用户访问
    REVOKE      --解除用户访问权限
    --事务控制
    COMMIT      --结束当前事务
    ROLLBACK     --中止当前事务
    SET TRANSACTION    --定义当前事务数据访问特征
    --程序化SQL
    DECLARE      --为查询设定游标
    EXPLAN      --为查询描述数据访问计划
    OPEN      --检索查询结果打开一个游标
    FETCH      --检索一行查询结果
    CLOSE      --关闭游标
    PREPARE      --为动态执行准备SQL 语句
    EXECUTE      --动态地执行SQL 语句
    DESCRIBE     --描述准备好的查询

    ---局部变量
    declare @id char(10)
    --set @id = '10010001'
    select @id = '10010001'

    ---全局变量
    ---必须以@@开头

    --IF ELSE
    declare @x int @y int @z int
    select @x = 1 @y = 2 @z=3
    if @x > @y
     print 'x > y' --打印字符串'x > y'
    else if @y > @z
     print 'y > z'
    else print 'z > y'

    --CASE
    use pangu
    update employee
    set e_wage =
     case
      when job_level = ’1’ then e_wage*1.08
      when job_level = ’2’ then e_wage*1.07
      when job_level = ’3’ then e_wage*1.06
      else e_wage*1.05
     end

    --WHILE CONTINUE BREAK
    declare @x int @y int @c int
    select @x = 1 @y=1
    while @x < 3
     begin
      print @x --打印变量x 的值
      while @y < 3
       begin
        select @c = 100*@x + @y
        print @c --打印变量c 的值
        select @y = @y + 1
       end
      select @x = @x + 1
      select @y = 1
     end

    --WAITFOR
    --例 等待1 小时2 分零3 秒后才执行SELECT 语句
    waitfor delay ’01:02:03’
    select * from employee
    --例 等到晚上11 点零8 分后才执行SELECT 语句
    waitfor time ’23:08:00’
    select * from employee

     

    ***SELECT***

       select *(列名) from table_name(表名) where column_name operator value
       ex:(宿主)
      select * from stock_information where stockid   = str(nid)
         stockname = 'str_name' 
         stockname like '% find this %' 
         stockname like '[a-zA-Z]%' --------- ([]指定值的范围)
         stockname like '[^F-M]%'   --------- (^排除指定范围)
         --------- 只能在使用like关键字的where子句中使用通配符)
         or stockpath = 'stock_path'
         or stocknumber < 1000
         and stockindex = 24
         not stocksex = 'man'
         stocknumber between 20 and 100
         stocknumber in(10,20,30)
         order by stockid desc(asc) --------- 排序,desc-降序,asc-升序
         order by 1,2 --------- by列号
         stockname = (select stockname from stock_information  where stockid  = 4)
         --------- 子查询
         --------- 除非能确保内层select只返回一个行的值,
         --------- 否则应在外层where子句中用一个in限定符
      select distinct column_name form table_name --------- distinct指定检索独有的列值,不重复
      select stocknumber ,"stocknumber + 10" = stocknumber + 10 from table_name
      select stockname , "stocknumber" = count(*) from table_name group by stockname
                                          --------- group by 将表按行分组,指定列中有相同的值
              having count(*) = 2  ---------  having选定指定的组
            
      select * 
      from table1, table2                  
      where table1.id *= table2.id -------- 左外部连接,table1中有的而table2中没有得以null表示
         table1.id =* table2.id -------- 右外部连接

      select stockname from table1
      union [all]  -----  union合并查询结果集,all-保留重复行
      select stockname from table2

    ***insert***

      insert into table_name (Stock_name,Stock_number) value ("xxx","xxxx")
                  value (select Stockname , Stocknumber from Stock_table2)---value为select语句

    ***update***

      update table_name set Stockname = "xxx" [where Stockid = 3]
             Stockname = default
             Stockname = null
             Stocknumber = Stockname + 4

    ***delete***

      delete from table_name where Stockid = 3
      truncate table_name ----------- 删除表中所有行,仍保持表的完整性
      drop table table_name --------------- 完全删除表

    ***alter table*** --- 修改数据库表结构

      alter table database.owner.table_name add column_name char(2) null .....
      sp_help table_name ---- 显示表已有特征
      create table table_name (name char(20), age smallint, lname varchar(30))
      insert into table_name select ......... ----- 实现删除列的方法(创建新表)
      alter table table_name drop constraint Stockname_default ---- 删除Stockname的default约束
        
    ***function(/*常用函数*/)***

    ----统计函数----
    AVG    --求平均值
    COUNT   --统计数目
    MAX    --求最大值
    MIN    --求最小值
    SUM    --求和

    --AVG
    use pangu
    select avg(e_wage) as dept_avgWage
    from employee
    group by dept_id

    --MAX
    --求工资最高的员工姓名
    use pangu
    select e_name
    from employee
    where e_wage =
     (select max(e_wage)
      from employee)

    --STDEV()
    --STDEV()函数返回表达式中所有数据的标准差

    --STDEVP()
    --STDEVP()函数返回总体标准差

    --VAR()
    --VAR()函数返回表达式中所有值的统计变异数

    --VARP()
    --VARP()函数返回总体变异数

    ----算术函数----

    /***三角函数***/
    SIN(float_expression) --返回以弧度表示的角的正弦
    COS(float_expression) --返回以弧度表示的角的余弦
    TAN(float_expression) --返回以弧度表示的角的正切
    COT(float_expression) --返回以弧度表示的角的余切
    /***反三角函数***/
    ASIN(float_expression) --返回正弦是FLOAT 值的以弧度表示的角
    ACOS(float_expression) --返回余弦是FLOAT 值的以弧度表示的角
    ATAN(float_expression) --返回正切是FLOAT 值的以弧度表示的角
    ATAN2(float_expression1,float_expression2) 
            --返回正切是float_expression1 /float_expres-sion2的以弧度表示的角
    DEGREES(numeric_expression)
                           --把弧度转换为角度返回与表达式相同的数据类型可为
            --INTEGER/MONEY/REAL/FLOAT 类型
    RADIANS(numeric_expression) --把角度转换为弧度返回与表达式相同的数据类型可为
            --INTEGER/MONEY/REAL/FLOAT 类型
    EXP(float_expression)  --返回表达式的指数值
    LOG(float_expression)  --返回表达式的自然对数值
    LOG10(float_expression)--返回表达式的以10 为底的对数值
    SQRT(float_expression) --返回表达式的平方根
    /***取近似值函数***/
    CEILING(numeric_expression)  --返回>=表达式的最小整数返回的数据类型与表达式相同可为
            --INTEGER/MONEY/REAL/FLOAT 类型
    FLOOR(numeric_expression)    --返回<=表达式的最小整数返回的数据类型与表达式相同可为
            --INTEGER/MONEY/REAL/FLOAT 类型
    ROUND(numeric_expression)    --返回以integer_expression 为精度的四舍五入值返回的数据
            --类型与表达式相同可为INTEGER/MONEY/REAL/FLOAT 类型
    ABS(numeric_expression)      --返回表达式的绝对值返回的数据类型与表达式相同可为
            --INTEGER/MONEY/REAL/FLOAT 类型
    SIGN(numeric_expression)     --测试参数的正负号返回0 零值1 正数或-1 负数返回的数据类型
            --与表达式相同可为INTEGER/MONEY/REAL/FLOAT 类型
    PI()       --返回值为π 即3.1415926535897936
    RAND([integer_expression])   --用任选的[integer_expression]做种子值得出0-1 间的随机浮点数


    ----字符串函数----
    ASCII()         --函数返回字符表达式最左端字符的ASCII 码值
    CHAR()   --函数用于将ASCII 码转换为字符
        --如果没有输入0 ~ 255 之间的ASCII 码值CHAR 函数会返回一个NULL 值
    LOWER()   --函数把字符串全部转换为小写
    UPPER()   --函数把字符串全部转换为大写
    STR()   --函数把数值型数据转换为字符型数据
    LTRIM()   --函数把字符串头部的空格去掉
    RTRIM()   --函数把字符串尾部的空格去掉
    LEFT(),RIGHT(),SUBSTRING()  --函数返回部分字符串
    CHARINDEX(),PATINDEX()  --函数返回字符串中某个指定的子串出现的开始位置
    SOUNDEX()  --函数返回一个四位字符码 
        --SOUNDEX函数可用来查找声音相似的字符串但SOUNDEX函数对数字和汉字均只返回0 值     
    DIFFERENCE()    --函数返回由SOUNDEX 函数返回的两个字符表达式的值的差异
        --0 两个SOUNDEX 函数返回值的第一个字符不同
        --1 两个SOUNDEX 函数返回值的第一个字符相同
        --2 两个SOUNDEX 函数返回值的第一二个字符相同
        --3 两个SOUNDEX 函数返回值的第一二三个字符相同
        --4 两个SOUNDEX 函数返回值完全相同
                                          

    QUOTENAME()  --函数返回被特定字符括起来的字符串
    /*select quotename('abc', '{') quotename('abc')
    运行结果如下
    ----------------------------------{
    {abc} [abc]*/

    REPLICATE()     --函数返回一个重复character_expression 指定次数的字符串
    /*select replicate('abc', 3) replicate( 'abc', -2)
    运行结果如下
    ----------- -----------
    abcabcabc NULL*/

    REVERSE()       --函数将指定的字符串的字符排列顺序颠倒
    REPLACE()       --函数返回被替换了指定子串的字符串
    /*select replace('abc123g', '123', 'def')
    运行结果如下
    ----------- -----------
    abcdefg*/

    SPACE()   --函数返回一个有指定长度的空白字符串
    STUFF()   --函数用另一子串替换字符串指定位置长度的子串


    ----数据类型转换函数----
    CAST() 函数语法如下
    CAST() (<expression> AS <data_ type>[ length ])
    CONVERT() 函数语法如下
    CONVERT() (<data_ type>[ length ], <expression> [, style])

    select cast(100+99 as char) convert(varchar(12), getdate())
    运行结果如下
    ------------------------------ ------------
    199   Jan 15 2000

    ----日期函数----
    DAY()   --函数返回date_expression 中的日期值
    MONTH()   --函数返回date_expression 中的月份值
    YEAR()   --函数返回date_expression 中的年份值
    DATEADD(<datepart> ,<number> ,<date>) 
        --函数返回指定日期date 加上指定的额外日期间隔number 产生的新日期
    DATEDIFF(<datepart> ,<number> ,<date>)
        --函数返回两个指定日期在datepart 方面的不同之处
    DATENAME(<datepart> , <date>)  --函数以字符串的形式返回日期的指定部分
    DATEPART(<datepart> , <date>)  --函数以整数值的形式返回日期的指定部分
    GETDATE()  --函数以DATETIME 的缺省格式返回系统当前的日期和时间

    ----系统函数----
    APP_NAME()      --函数返回当前执行的应用程序的名称
    COALESCE()  --函数返回众多表达式中第一个非NULL 表达式的值
    COL_LENGTH(<'table_name'>, <'column_name'>) --函数返回表中指定字段的长度值
    COL_NAME(<table_id>, <column_id>)   --函数返回表中指定字段的名称即列名
    DATALENGTH() --函数返回数据表达式的数据的实际长度
    DB_ID(['database_name']) --函数返回数据库的编号
    DB_NAME(database_id)  --函数返回数据库的名称
    HOST_ID()     --函数返回服务器端计算机的名称
    HOST_NAME()     --函数返回服务器端计算机的名称
    IDENTITY(<data_type>[, seed increment]) [AS column_name])
     --IDENTITY() 函数只在SELECT INTO 语句中使用用于插入一个identity column列到新表中
    /*select identity(int, 1, 1) as column_name
     into newtable
     from oldtable*/
    ISDATE()  --函数判断所给定的表达式是否为合理日期
    ISNULL(<check_expression>, <replacement_value>) --函数将表达式中的NULL 值用指定值替换
    ISNUMERIC()  --函数判断所给定的表达式是否为合理的数值
    NEWID()   --函数返回一个UNIQUEIDENTIFIER 类型的数值
    NULLIF(<expression1>, <expression2>)
     --NULLIF 函数在expression1 与expression2 相等时返回NULL 值若不相等时则返回expression1 的值

     


    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=642227
    Transact SQL  语 句 功 能 
    ========================================================================

      --数据操作

       SELECT --从数据库表中检索数据行和列 
          INSERT --向数据库表添加新数据行 
          DELETE --从数据库表中删除数据行 
          UPDATE --更新数据库表中的数据

      --数据定义

       CREATE TABLE --创建一个数据库表 
          DROP TABLE --从数据库中删除表 
          ALTER TABLE --修改数据库表结构 
          CREATE VIEW --创建一个视图 
          DROP VIEW --从数据库中删除视图 
          CREATE INDEX --为数据库表创建一个索引 
          DROP INDEX --从数据库中删除索引 
          CREATE PROCEDURE --创建一个存储过程 
          DROP PROCEDURE --从数据库中删除存储过程 
          CREATE TRIGGER --创建一个触发器 
          DROP TRIGGER --从数据库中删除触发器 
          CREATE SCHEMA --向数据库添加一个新模式 
          DROP SCHEMA --从数据库中删除一个模式 
          CREATE DOMAIN --创建一个数据值域 
          ALTER DOMAIN --改变域定义 
          DROP DOMAIN --从数据库中删除一个域

      --数据控制

       GRANT --授予用户访问权限 
          DENY --拒绝用户访问 
          REVOKE --解除用户访问权限

      --事务控制

       COMMIT --结束当前事务 
          ROLLBACK --中止当前事务 
          SET TRANSACTION --定义当前事务数据访问特征

      --程序化SQL

       DECLARE --为查询设定游标 
          EXPLAN --为查询描述数据访问计划 
          OPEN --检索查询结果打开一个游标 
          FETCH --检索一行查询结果 
          CLOSE --关闭游标 
          PREPARE --为动态执行准备SQL 语句 
          EXECUTE --动态地执行SQL 语句 
          DESCRIBE --描述准备好的查询  

      ---局部变量

       declare @id char(10) 
          --set @id = '10010001' 
          select @id = '10010001'  

      ---全局变量

      ---必须以@@开头  

      --IF ELSE

      declare @x int @y int @z int 
          select @x = 1 @y = 2 @z=3 
          if @x > @y 
           print 'x > y' --打印字符串'x > y' 
          else if @y > @z 
           print 'y > z' 
          else print 'z > y' 
          --CASE 
          use pangu 
          update employee 
          set e_wage = 
           case 
           when job_level = ’1’ then e_wage*1.08 
           when job_level = ’2’ then e_wage*1.07 
           when job_level = ’3’ then e_wage*1.06 
           else e_wage*1.05 
           end 
          --WHILE CONTINUE BREAK 
          declare @x int @y int @c int 
          select @x = 1 @y=1 
          while @x < 3 
           begin 
           print @x --打印变量x 的值 
           while @y < 3 
           begin 
           select @c = 100*@x + @y 
           print @c --打印变量c 的值 
           select @y = @y + 1 
           end 
           select @x = @x + 1 
           select @y = 1 
           end 
          --WAITFOR

      --例 等待1 小时2 分零3 秒后才执行SELECT 语句

      waitfor delay ’01:02:03’ 
          select * from employee

        --例 等到晚上11 点零8 分后才执行SELECT 语句

        waitfor time ’23:08:00’


    SELECT  

       select *(列名) from table_name(表名) where column_name operator value ex宿主) 
         select * from stock_information where stockid = str(nid) 
         stockname = 'str_name' 
         stockname like '% find this %' 
         stockname like '[a-zA-Z]%' --------- ([]指定值的范围) 
         stockname like '[^F-M]%' --------- (^排除指定范围) 
         --------- 只能在使用like关键字的where子句中使用通配符) 
         or stockpath = 'stock_path' 
         or stocknumber < 1000 
         and stockindex = 24 
         not stocksex = 'man' 
         stocknumber between 20 and 100 
         stocknumber in(10,20,30) 
         order by stockid desc(asc) --------- 排序,desc-降序,asc-升序 
         order by 1,2 --------- by列号 
         stockname = (select stockname from stock_information where stockid = 4) 
         --------- 子查询 
         --------- 除非能确保内层select只返回一个行的值 
         --------- 否则应在外层where子句中用一个in限定符 
         select distinct column_name form table_name 
       --------- distinct指定检索独有的列值,不重复 
         select stocknumber ,"stocknumber + 10" = stocknumber + 10 from table_name 
         select stockname , "stocknumber" = count(*) from table_name group by stockname 
         --------- group by 将表按行分组,指定列中有相同的值 
         having count(*) = 2 --------- having选定指定的组

       select * 
         from table1, table2 
    where table1.id *= table2.id -------- 左外部连接,table1中有的而table2中没有得以null表示 
         table1.id =* table2.id -------- 右外部连接 
         select stockname from table1 
         union [all] -------- union合并查询结果集,all-保留重复行 
         select stockname from table2 

       insert 

       insert into table_name (Stock_name,Stock_number) value ("xxx","xxxx" 
       value (select Stockname , Stocknumber from Stock_table2) 
       -------value为select语句  

       update  

       update table_name set Stockname = "xxx" [where Stockid = 3] 
       Stockname = default 
       Stockname = null 
       Stocknumber = Stockname + 4  

       delete  

       delete from table_name where Stockid = 3 
       truncate table_name --------- 删除表中所有行,仍保持表的完整性 
       drop table table_name --------- 完全删除表 

       alter table -------- 修改数据库表结构  

       alter table database.owner.table_name add column_name char(2) null .. 
       sp_help table_name -------- 显示表已有特征 
       create table table_name (name char(20), age smallint, lname varchar(30)) 
       insert into table_name select -------- 实现删除列的方法(创建新表) 
       alter table table_name drop constraint Stockname_default 
       --------- 删除Stockname的default约束

     


    常用函数(function)  

        转换函数

        convert(数据类型,值,格式)

      统计函数

      AVG --求平均值 
      COUNT --统计数目 
      MAX --求最大值 
      MIN --求最小值 
      SUM --求和 

      AVG

      use pangu 
      select avg(e_wage) as dept_avgWage 
      from employee 
      group by dept_id  

      MAX

      --求工资最高的员工姓名 
      use pangu 
      select e_name 
      from employee 
      where e_wage = 
       (select max(e_wage) 
       from employee)  

      STDEV()

      --STDEV()函数返回表达式中所有数据的标准差 
      --STDEVP() 
      --STDEVP()函数返回总体标准差  

      VAR()

      --VAR()函数返回表达式中所有值的统计变异数  

      VARP()

      --VARP()函数返回总体变异数  

      算术函数  

      三角函数

      SIN(float_expression) --返回以弧度表示的角的正弦 
      COS(float_expression) --返回以弧度表示的角的余弦 
      TAN(float_expression) --返回以弧度表示的角的正切 
      COT(float_expression) --返回以弧度表示的角的余切

      反三角函数

      ASIN(float_expression) --返回正弦是FLOAT 值的以弧度表示的角 
      ACOS(float_expression) --返回余弦是FLOAT 值的以弧度表示的角 
      ATAN(float_expression) --返回正切是FLOAT 值的以弧度表示的角 
      ATAN2(float_expression1,float_expression2) 
       ------返回正切是float_expression1 /float_expres-sion2的以弧度表示的角 
      DEGREES(numeric_expression) 
       ------把弧度转换为角度返回与表达式相同的数据类型可为 
       ------INTEGER/MONEY/REAL/FLOAT 类型 
      RADIANS(numeric_expression) 
    ------把角度转换为弧度返回与表达式相同的数据类型可为

       ------INTEGER/MONEY/REAL/FLOAT 类型 
      EXP(float_expression) --返回表达式的指数值 
      LOG(float_expression) --返回表达式的自然对数值 
      LOG10(float_expression)--返回表达式的以10 为底的对数值 
      SQRT(float_expression) --返回表达式的平方根

      取近似值函数

      CEILING(numeric_expression) 
    -------返回>=表达式的最小整数返回的数据类型与表达式相同可为 
       -------INTEGER/MONEY/REAL/FLOAT 类型 
      FLOOR(numeric_expression) 
    -------返回<=表达式的最小整数返回的数据类型与表达式相同可为 
       -------INTEGER/MONEY/REAL/FLOAT 类型 
      ROUND(numeric_expression) 
    -------返回以integer_expression 为精度的四舍五入值返回的数据 
       -------类型与表达式相同可为INTEGER/MONEY/REAL/FLOAT 类型 
      ABS(numeric_expression) 
    -------返回表达式的绝对值返回的数据类型与表达式相同可为 
       -------INTEGER/MONEY/REAL/FLOAT 类型 
      SIGN(numeric_expression) 
    -------测试参数的正负号返回0 零值1 正数或-1 负数返回的数据类型 
       -------与表达式相同可为INTEGER/MONEY/REAL/FLOAT 类型 
      PI() -------返回值为π 即3.1415926535897936 
      RAND([integer_expression]) 
    -------用任选的[integer_expression]做种子值得出0-1 间的随机浮点数


    字符串函数

      ASCII() ------函数返回字符表达式最左端字符的ASCII 码值 
      CHAR() ------函数用于将ASCII 码转换为字符 
       ------如果没有输入0 ~ 255 之间的ASCII 码值CHAR 函数会返回一个NULL 值 
      LOWER() ------函数把字符串全部转换为小写 
      UPPER() ------函数把字符串全部转换为大写 
      STR() ------函数把数值型数据转换为字符型数据 
      LTRIM() ------函数把字符串头部的空格去掉 
      RTRIM() ------函数把字符串尾部的空格去掉 
      LEFT(),RIGHT(),SUBSTRING() --函数返回部分字符串 
      CHARINDEX(),PATINDEX() --函数返回字符串中某个指定的子串出现的开始位置 
      SOUNDEX() ------函数返回一个四位字符码 
       ------SOUNDEX函数可用来查找声音相似的字符串但SOUNDEX函数对数字和汉字均只返回0 值 
      DIFFERENCE() ------函数返回由SOUNDEX 函数返回的两个字符表达式的值的差异 
       ------0 两个SOUNDEX 函数返回值的第一个字符不同 
       ------1 两个SOUNDEX 函数返回值的第一个字符相同 
       ------2 两个SOUNDEX 函数返回值的第一二个字符相同 
       ------3 两个SOUNDEX 函数返回值的第一二三个字符相同 
       ------4 两个SOUNDEX 函数返回值完全相同同 
      QUOTENAME() ------函数返回被特定字符括起来的字符串

      /**//*select quotename('abc', '{') quotename('abc') 
      运行结果如下

      { 
      {abc} [abc]*/ 
      REPLICATE() ------函数返回一个重复character_expression 指定次数的字符串 
      /**//*select replicate('abc', 3) replicate( 'abc', -2)

      运行结果如下

      abcabcabc NULL*/ 
      REVERSE() ------函数将指定的字符串的字符排列顺序颠倒 
      REPLACE() ------函数返回被替换了指定子串的字符串 
      /**//*select replace('abc123g', '123', 'def')

      运行结果如下 
       
      abcdefg*/  

      SPACE() ------函数返回一个有指定长度的空白字符串 
      STUFF() ------函数用另一子串替换字符串指定位置长度的子串  

      数据类型转换函数

      CAST() 函数语法如下 
      CAST() ( AS [ length ]) 
      CONVERT() 函数语法如下 
      CONVERT() ([ length ], [, style]) 
      select cast(100+99 as char) convert(varchar(12), getdate())

      运行结果如下 
      199 Jan 15 2000 

      日期函数

      DAY() ------函数返回date_expression 中的日期值 
      MONTH() ------函数返回date_expression 中的月份值 
      YEAR() ------函数返回date_expression 中的年份值 
      DATEADD( , ,) 
       -----函数返回指定日期date 加上指定的额外日期间隔number 产生的新日期 
      DATEDIFF( , ,) 
       -----函数返回两个指定日期在datepart 方面的不同之处

      DATENAME( ,  ------函数以字符串的形式返回日期的指定部分 
      DATEPART( ,  ------函数以整数值的形式返回日期的指定部分 
      GETDATE() ------函数以DATETIME 的缺省格式返回系统当前的日期和时间  

      系统函数

      APP_NAME() ------函数返回当前执行的应用程序的名称 
      COALESCE() -----函数返回众多表达式中第一个非NULL 表达式的值 
      COL_LENGTH(<'table_name'>, <'column_name'> ----函数返回表中指定字段的长度值 
      COL_NAME(,  ----函数返回表中指定字段的名称即列名 
      DATALENGTH() -----函数返回数据表达式的数据的实际长度 
      DB_ID(['database_name']) ------函数返回数据库的编号 
      DB_NAME(database_id) ------函数返回数据库的名称 
      HOST_ID() -----函数返回服务器端计算机的名称 
      HOST_NAME() -----函数返回服务器端计算机的名称 
      IDENTITY([, seed increment]) [AS column_name]) 
       --IDENTITY() 函数只在SELECT INTO 语句中使用用于插入一个identity column列到新表中 
      /**//*select identity(int, 1, 1) as column_name 
       into newtable 
       from oldtable*/

      ISDATE() ----函数判断所给定的表达式是否为合理日期 
      ISNULL(,  --函数将表达式中的NULL 值用指定值替换 
      ISNUMERIC() ----函数判断所给定的表达式是否为合理的数值 
      NEWID() ----函数返回一个UNIQUEIDENTIFIER 类型的数值 
      NULLIF(,  
       ----NULLIF 函数在expression1 与expression2 相等时返回NULL 值若不相等时则返回xpression1 的值

    SQL2000下将数据库直接备份到网络上其他计算机硬盘的方法!      

    1.两台机器(数据库所在的机器和存放备份文件的机器)都需要建一个同名同密码的用户,方便起见,最好将这两个用户都直接归到管理员组下;

    2.将数据库的启动帐户设置成刚才所建立的那个帐户,并重新开启SQL服务;

    3.假设远程机器的IP是192.168.61.234,共享为默认共享f$,先用查询分析器登陆到本地的SQL服务器(用sa和信任模式都可以),在master下执行xp_cmdshell 'dir \\192.168.61.234\f$'看有没有结果,还是有报错的,如有报错,请根据错误提示检查;

    4.执行以下备份语句可将数据库备份到远程硬盘上,以crm2k为例:

    backup database crm2k to disk='\\192.168.61.234\f$\crm2k0722_2.dmp'

    5.同时注意,一定要用“\\机器名或IP”不能用映射的盘符。

    不过我觉得直接备份到远程硬盘并不是个好主意,一则速度慢,二则网络传输过程中可能出现意外。还是直接备份到本地,再拷到远程硬盘的好,用SQL的脚本可以调用master..cmdshell 'copy...'实现。
     
    更正 
    不好意思,帖中有一处笔识,现更正:
    最后:“调用master..cmdshell 'copy...'实现。”
    应该是:“调用master..xp_cmdshell 'copy...'实现。”

    另外,xp_cmdshell是个十分有用的扩展存储过程,可以在SQL中执行WINDOWS的命令行命令,大家有空可以自己研究一下,对我们平时使用SQL过程中,很有帮助的。

    本机的备份和还原数据库的Transact-SQL实现

    backup database 数据库名称  to disk = 'C:\DATA1'(具体选择实际的路径名称)
    restore database 数据库名称 from disk = 'C:\yuhua.bak'(具体选择实际的路径名称)

     


    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=636935

    体现了SQL Server中的四个知识点: 
    1.   获取SQL Server服务器上的默认目录

    2.   备份SQL语句的使用

    3.   恢复SQL语句的使用,同时考虑了强制恢复时关闭其他用户进程的处理

    4.   作业创建SQL语句的使用

     

    /*1.--得到数据库的文件目录
     
     @dbname 指定要取得目录的数据库名
       如果指定的数据不存在,返回安装SQL时设置的默认数据目录
       如果指定NULL,则返回默认的SQL备份目录名
    ----*/

    /*--调用示例
     select 数据库文件目录=dbo.f_getdbpath('tempdb')
      ,[默认SQL SERVER数据目录]=dbo.f_getdbpath('')
      ,[默认SQL SERVER备份目录]=dbo.f_getdbpath(null)
    --*/
    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_getdbpath]') and xtype in (N'FN', N'IF', N'TF'))
    drop function [dbo].[f_getdbpath]
    GO

    create function f_getdbpath(@dbname sysname)
    returns nvarchar(260)
    as 
    begin
     declare @re nvarchar(260)
     if @dbname is null or db_id(@dbname) is null
      select @re=rtrim(reverse(filename)) from master..sysdatabases where name='master'
     else
      select @re=rtrim(reverse(filename)) from master..sysdatabases where name=@dbname

     if @dbname is null
      set @re=reverse(substring(@re,charindex('\',@re)+5,260))+'BACKUP'
     else
      set @re=reverse(substring(@re,charindex('\',@re),260))
     return(@re)
    end
    go

     

    /*2.--备份数据库--*/

    /*--调用示例

    --备份当前数据库
    exec p_backupdb @bkpath='c:\',@bkfname='db_\DATE\_db.bak'

    --差异备份当前数据库
    exec p_backupdb @bkpath='c:\',@bkfname='db_\DATE\_df.bak',@bktype='DF'

    --备份当前数据库日志
    exec p_backupdb @bkpath='c:\',@bkfname='db_\DATE\_log.bak',@bktype='LOG'

    --*/

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_backupdb]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
    drop procedure [dbo].[p_backupdb]
    GO

    create proc p_backupdb
    @dbname sysname='',   --要备份的数据库名称,不指定则备份当前数据库
    @bkpath nvarchar(260)='', --备份文件的存放目录,不指定则使用SQL默认的备份目录
    @bkfname nvarchar(260)='', --备份文件名,文件名中可以用\DBNAME\代表数据库名,\DATE\代表日期,\TIME\代表时间
    @bktype nvarchar(10)='DB', --备份类型:'DB'备份数据库,'DF' 差异备份,'LOG' 日志备份
    @appendfile bit=1   --追加/覆盖备份文件
    as
     declare @sql varchar(8000)
     if isnull(@dbname,'')='' set @dbname=db_name()
     if isnull(@bkpath,'')='' set @bkpath=dbo.f_getdbpath(null)
     if isnull(@bkfname,'')='' set @bkfname='\DBNAME\_\DATE\_\TIME\.BAK'
     set @bkfname=replace(replace(replace(@bkfname,'\DBNAME\',@dbname)
      ,'\DATE\',convert(varchar,getdate(),112))
      ,'\TIME\',replace(convert(varchar,getdate(),108),':',''))
     set @sql='backup '+case @bktype when 'LOG' then 'log ' else 'database ' end +@dbname
      +' to disk='''+@bkpath+@bkfname
      +''' with '+case @bktype when 'DF' then 'DIFFERENTIAL,' else '' end
      +case @appendfile when 1 then 'NOINIT' else 'INIT' end
     print @sql
     exec(@sql)
    go

     

    /*3.--恢复数据库--*/

    /*--调用示例
    --完整恢复数据库
    exec p_RestoreDb @bkfile='c:\db_20031015_db.bak',@dbname='db'

    --差异备份恢复
    exec p_RestoreDb @bkfile='c:\db_20031015_db.bak',@dbname='db',@retype='DBNOR'
    exec p_backupdb @bkfile='c:\db_20031015_df.bak',@dbname='db',@retype='DF'

    --日志备份恢复
    exec p_RestoreDb @bkfile='c:\db_20031015_db.bak',@dbname='db',@retype='DBNOR'
    exec p_backupdb @bkfile='c:\db_20031015_log.bak',@dbname='db',@retype='LOG'

    --*/

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_RestoreDb]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
    drop procedure [dbo].[p_RestoreDb]
    GO

    create proc p_RestoreDb
    @bkfile nvarchar(1000),  --定义要恢复的备份文件名
    @dbname sysname='',      --定义恢复后的数据库名,默认为备份的文件名
    @dbpath nvarchar(260)='', --恢复后的数据库存放目录,不指定则为SQL的默认数据目录
    @retype nvarchar(10)='DB', --恢复类型:'DB'完事恢复数据库,'DBNOR' 为差异恢复,日志恢复进行完整恢复,'DF' 差异备份的恢复,'LOG' 日志恢复
    @filenumber int=1,   --恢复的文件号
    @overexist bit=1,        --是否覆盖已经存在的数据库,仅@retype为
    @killuser bit=1       --是否关闭用户使用进程,仅@overexist=1时有效
    as
    declare @sql varchar(8000)

    --得到恢复后的数据库名
    if isnull(@dbname,'')=''
     select @sql=reverse(@bkfile)
      ,@sql=case when charindex('.',@sql)=0 then @sql
       else substring(@sql,charindex('.',@sql)+1,1000) end
      ,@sql=case when charindex('\',@sql)=0 then @sql
       else left(@sql,charindex('\',@sql)-1) end
      ,@dbname=reverse(@sql)

    --得到恢复后的数据库存放目录
    if isnull(@dbpath,'')='' set @dbpath=dbo.f_getdbpath('')

    --生成数据库恢复语句
    set @sql='restore '+case @retype when 'LOG' then 'log ' else 'database ' end+@dbname
     +' from disk='''+@bkfile+''''
     +' with file='+cast(@filenumber as varchar)
     +case when @overexist=1 and @retype in('DB','DBNOR') then ',replace' else '' end
     +case @retype when 'DBNOR' then ',NORECOVERY' else ',RECOVERY' end
    print @sql
    --添加移动逻辑文件的处理
    if @retype='DB' or @retype='DBNOR'
    begin
     --从备份文件中获取逻辑文件名
     declare @lfn nvarchar(128),@tp char(1),@i int

     --创建临时表,保存获取的信息
     create table #tb(ln nvarchar(128),pn nvarchar(260),tp char(1),fgn nvarchar(128),sz numeric(20,0),Msz numeric(20,0))
     --从备份文件中获取信息
     insert into #tb exec('restore filelistonly from disk='''+@bkfile+'''')
     declare #f cursor for select ln,tp from #tb
     open #f
     fetch next from #f into @lfn,@tp
     set @i=0
     while @@fetch_status=0
     begin
      select @sql=@sql+',move '''+@lfn+''' to '''+@dbpath+@dbname+cast(@i as varchar)
       +case @tp when 'D' then '.mdf''' else '.ldf''' end
       ,@i=@i+1
      fetch next from #f into @lfn,@tp
     end
     close #f
     deallocate #f
    end

    --关闭用户进程处理
    if @overexist=1 and @killuser=1
    begin
     declare @spid varchar(20)
     declare #spid cursor for
      select spid=cast(spid as varchar(20)) from master..sysprocesses where dbid=db_id(@dbname)
     open #spid
     fetch next from #spid into @spid
     while @@fetch_status=0
     begin  
      exec('kill '+@spid)
      fetch next from #spid into @spid
     end  
     close #spid
     deallocate #spid
    end

    --恢复数据库
    exec(@sql)

    go

    /*4.--创建作业--*/

    /*--调用示例

    --每月执行的作业
    exec p_createjob @jobname='mm',@sql='select * from syscolumns',@freqtype='month'

    --每周执行的作业
    exec p_createjob @jobname='ww',@sql='select * from syscolumns',@freqtype='week'

    --每日执行的作业
    exec p_createjob @jobname='a',@sql='select * from syscolumns'

    --每日执行的作业,每天隔4小时重复的作业
    exec p_createjob @jobname='b',@sql='select * from syscolumns',@fsinterval=4

    --*/
    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_createjob]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
    drop procedure [dbo].[p_createjob]
    GO

    create proc p_createjob
    @jobname varchar(100),  --作业名称
    @sql varchar(8000),   --要执行的命令
    @dbname sysname='',   --默认为当前的数据库名
    @freqtype varchar(6)='day', --时间周期,month 月,week 周,day 日
    @fsinterval int=1,   --相对于每日的重复次数
    @time int=170000   --开始执行时间,对于重复执行的作业,将从0点到23:59分
    as
    if isnull(@dbname,'')='' set @dbname=db_name()

    --创建作业
    exec msdb..sp_add_job @job_name=@jobname

    --创建作业步骤
    exec msdb..sp_add_jobstep @job_name=@jobname,
     @step_name = '数据处理',
     @subsystem = 'TSQL',
     @database_name=@dbname,
     @command = @sql,
     @retry_attempts = 5, --重试次数
     @retry_interval = 5  --重试间隔

    --创建调度
    declare @ftype int,@fstype int,@ffactor int
    select @ftype=case @freqtype when 'day' then 4
         when 'week' then 8
         when 'month' then 16 end
     ,@fstype=case @fsinterval when 1 then 0 else 8 end
    if @fsinterval<>1 set @time=0
    set @ffactor=case @freqtype when 'day' then 0 else 1 end

    EXEC msdb..sp_add_jobschedule @job_name=@jobname, 
     @name = '时间安排',
     @freq_type=@ftype ,      --每天,8 每周,16 每月
     @freq_interval=1,     --重复执行次数
     @freq_subday_type=@fstype,   --是否重复执行
     @freq_subday_interval=@fsinterval,  --重复周期
     @freq_recurrence_factor=@ffactor,
     @active_start_time=@time     --下午17:00:00分执行

    go


    /*--应用案例--备份方案:
    完整备份(每个星期天一次)+差异备份(每天备份一次)+日志备份(每2小时备份一次)

    调用上面的存储过程来实现
    --*/

    declare @sql varchar(8000)
    --完整备份(每个星期天一次)
    set @sql='exec p_backupdb @dbname=''要备份的数据库名'''
    exec p_createjob @jobname='每周备份',@sql,@freqtype='week'

    --差异备份(每天备份一次)
    set @sql='exec p_backupdb @dbname=''要备份的数据库名'',@bktype='DF''
    exec p_createjob @jobname='每天差异备份',@sql,@freqtype='day'

    --日志备份(每2小时备份一次)
    set @sql='exec p_backupdb @dbname=''要备份的数据库名'',@bktype='LOG''
    exec p_createjob @jobname='每2小时日志备份',@sql,@freqtype='day',@fsinterval=2

    *--应用案例2

    生产数据核心库:PRODUCE

    备份方案如下:
     1.设置三个作业,分别对PRODUCE库进行每日备份,每周备份,每月备份
     2.新建三个新库,分别命名为:每日备份,每周备份,每月备份
     3.建立三个作业,分别把三个备份库还原到以上的三个新库。

    目的:当用户在produce库中有任何的数据丢失时,均可以从上面的三个备份库中导入相应的TABLE数据。
    --*/

    declare @sql varchar(8000)

    --1.建立每月备份和生成月备份数据库的作业,每月每1天下午16:40分进行:
    set @sql='
    declare @path nvarchar(260),@fname nvarchar(100)
    set @fname=''PRODUCE_''+convert(varchar(10),getdate(),112)+''_m.bak''
    set @path=dbo.f_getdbpath(null)+@fname

    --备份
    exec p_backupdb @dbname=''PRODUCE'',@bkfname=@fname

    --根据备份生成每月新库
    exec p_RestoreDb @bkfile=@path,@dbname=''PRODUCE_月''

    --为周数据库恢复准备基础数据库
    exec p_RestoreDb @bkfile=@path,@dbname=''PRODUCE_周'',@retype=''DBNOR''

    --为日数据库恢复准备基础数据库
    exec p_RestoreDb @bkfile=@path,@dbname=''PRODUCE_日'',@retype=''DBNOR''
    '
    exec p_createjob @jobname='每月备份',@sql,@freqtype='month',@time=164000

    --2.建立每周差异备份和生成周备份数据库的作业,每周日下午17:00分进行:
    set @sql='
    declare @path nvarchar(260),@fname nvarchar(100)
    set @fname=''PRODUCE_''+convert(varchar(10),getdate(),112)+''_w.bak''
    set @path=dbo.f_getdbpath(null)+@fname

    --差异备份
    exec p_backupdb @dbname=''PRODUCE'',@bkfname=@fname,@bktype=''DF''

    --差异恢复周数据库
    exec p_backupdb @bkfile=@path,@dbname=''PRODUCE_周'',@retype=''DF''
    '
    exec p_createjob @jobname='每周差异备份',@sql,@freqtype='week',@time=170000

    --3.建立每日日志备份和生成日备份数据库的作业,每周日下午17:15分进行:
    set @sql='
    declare @path nvarchar(260),@fname nvarchar(100)
    set @fname=''PRODUCE_''+convert(varchar(10),getdate(),112)+''_l.bak''
    set @path=dbo.f_getdbpath(null)+@fname

    --日志备份
    exec p_backupdb @dbname=''PRODUCE'',@bkfname=@fname,@bktype=''LOG''

    --日志恢复日数据库
    exec p_backupdb @bkfile=@path,@dbname=''PRODUCE_日'',@retype=''LOG''
    '
    exec p_createjob @jobname='每周差异备份',@sql,@freqtype='day',@time=171500


     
        >>是update 吗

          >>又alter 跟update 有何不同呢

     


            update 是否耗时和数据结构的组成有密切关系,最有效率的是那种

    每笔纪录都有固定栏数栏宽的资料表结构,那么 update 和 new

    的速度差不多,new 是直接摆在资料表最尾端,update 则是算出

    该笔纪录在档案的位置,把资料置换过来。

     

        但如果数据结构是那种分隔符式的纯文字资料表,由于他每笔纪录

    不一定同栏数,每栏宽度也不固定,也就是每笔纪录的长度不一,你要

    换算某笔资料在档案的位置就要麻烦了,况且你要 update 的那笔资料

    不见得宽度刚好适合摆得下。


     

        所以每笔纪录固定长度的资料表,update 只需更改一笔纪录,但对

    分隔符式资料表而言,update 却必须把整个资料表所有纪录从头到

    尾重排一遍。

     

            > ALTER 指的是修改已建立 table 的结构 (schema)

                alter 必须重排整个资料表纪录。

             > UPDATE 指的是更新 table 中已建立的资料

            要补充说的是 delete 和 insert 的动作,delete 在资料表

    处理的合理作法上,并不是真把该纪录删去,然后把所有后面的纪录

    往前移,因为你不知道该纪录后面是否有成千上万笔纪录要一一前挪的。

    它只是把该纪录前面做个删除注记,系统读到他就知道是个已删除的纪录

    ,而不处理。

     


        至于 insert ,严格说来数据库根本不会做这种插入动作,因为每插

    一笔,整个后面纪录就要重挪一遍。如果你的数据库软件可以给你

    insert 纪录,那只不过是结合 new 和 resort 之后的障眼法而已。


     

        从这里就可看出,一个资料表经过一段时间的 update,delete,new,

    insert 之后,一定排序前后颠到,废纪录注记一堆,效率也愈来愈差,

    这时就要整理重建资料表。这没什么大学问,就是先把原资料表 sort

    一遍,然后按 sort 过后的次序,一笔笔纪录 copy 到新的资料表,

    并丢弃那些有废除注记的纪录,完毕后,再把那新资料 recover 回

    来,盖掉旧资料表。

     


        所以什么最花 cpu 时间?当然是资料表纪录重整,其次是纪录排序及搜寻,

    最简单的就是只改一笔,并且能用加减乘除的数学运算找出该笔数据得位置。
    sysaltfiles 主数据库 保存数据库的文件
    syscharsets 主数据库 字符集与排序顺序
    sysconfigures 主数据库 配置选项
    syscurconfigs 主数据库 当前配置选项
    sysdatabases 主数据库 服务器中的数据库
    syslanguages 主数据库 语言
    syslogins 主数据库 登陆帐号信息
    sysoledbusers 主数据库 链接服务器登陆信息
    sysprocesses 主数据库 进程
    sysremotelogins主数据库 远程登录帐号
    syscolumns 每个数据库 列
    sysconstrains 每个数据库 限制
    sysfilegroups 每个数据库 文件组
    sysfiles 每个数据库 文件
    sysforeignkeys 每个数据库 外部关键字
    sysindexs 每个数据库 索引
    sysmenbers 每个数据库 角色成员
    sysobjects 每个数据库 所有数据库对象
    syspermissions 每个数据库 权限
    systypes 每个数据库 用户定义数据类型
    sysusers 每个数据库 用户

    收藏几段SQL  Server语句和存储过程

     

    -- ======================================================

    --列出SQL SERVER 所有表,字段名,主键,类型,长度,小数位数等信息

    --在查询分析器里运行即可,可以生成一个表,导出到EXCEL中

    -- ======================================================

    SELECT

           (case when a.colorder=1 then d.name else '' end)表名,

           a.colorder 字段序号,

           a.name 字段名,

           (case when COLUMNPROPERTY( a.id,a.name,'IsIdentity')=1 then '√'else '' end) 标识,

           (case when (SELECT count(*)

           FROM sysobjects

           WHERE (name in

                     (SELECT name

                    FROM sysindexes

                    WHERE (id = a.id) AND (indid in

                              (SELECT indid

                             FROM sysindexkeys

                             WHERE (id = a.id) AND (colid in

                                       (SELECT colid

                                      FROM syscolumns

                                      WHERE (id = a.id) AND (name = a.name))))))) AND

                  (xtype = 'PK'))>0 then '√' else '' end) 主键,

           b.name 类型,

           a.length 占用字节数,

           COLUMNPROPERTY(a.id,a.name,'PRECISION') as 长度,

           isnull(COLUMNPROPERTY(a.id,a.name,'Scale'),0) as 小数位数,

           (case when a.isnullable=1 then '√'else '' end) 允许空,

           isnull(e.text,'') 默认值,

           isnull(g.[value],'') AS 字段说明   

     

    FROM  syscolumns  a left join systypes b

    on  a.xtype=b.xusertype

    inner join sysobjects d

    on a.id=d.id  and  d.xtype='U' and  d.name<>'dtproperties'

    left join syscomments e

    on a.cdefault=e.id

    left join sysproperties g

    on a.id=g.id AND a.colid = g.smallid 

    order by a.id,a.colorder

    一、 只复制一个表结构,不复制数据

     

    select top 0 * into [t1] from [t2]

    二、 获取数据库中某个对象的创建脚本

    1、 先用下面的脚本创建一个函数


    if exists(select 1 from sysobjects where id=object_id('fgetscript') and objectproperty(id,'IsInlineFunction')=0)
     drop function fgetscript
    go

    create function fgetscript(
     @servername varchar(50)     --服务器名
     ,@userid varchar(50)='sa'    --用户名,如果为nt验证方式,则为空
     ,@password varchar(50)=''    --密码
     ,@databasename varchar(50)    --数据库名称
     ,@objectname varchar(250)    --对象名

    ) returns varchar(8000)
    as
    begin
     declare @re varchar(8000)        --返回脚本
     declare @srvid int,@dbsid int       --定义服务器、数据库集id
     declare @dbid int,@tbid int        --数据库、表id
     declare @err int,@src varchar(255), @desc varchar(255) --错误处理变量

    --创建sqldmo对象
     exec @err=sp_oacreate 'sqldmo.sqlserver',@srvid output
     if @err<>0 goto lberr

    --连接服务器
     if isnull(@userid,'')='' --如果是 Nt验证方式
     begin
      exec @err=sp_oasetproperty @srvid,'loginsecure',1
      if @err<>0 goto lberr

      exec @err=sp_oamethod @srvid,'connect',null,@servername
     end
     else
      exec @err=sp_oamethod @srvid,'connect',null,@servername,@userid,@password

     if @err<>0 goto lberr

    --获取数据库集
     exec @err=sp_oagetproperty @srvid,'databases',@dbsid output
     if @err<>0 goto lberr

    --获取要取得脚本的数据库id
     exec @err=sp_oamethod @dbsid,'item',@dbid output,@databasename
     if @err<>0 goto lberr

    --获取要取得脚本的对象id
     exec @err=sp_oamethod @dbid,'getobjectbyname',@tbid output,@objectname
     if @err<>0 goto lberr

    --取得脚本
     exec @err=sp_oamethod @tbid,'script',@re output
     if @err<>0 goto lberr

     --print @re
     return(@re)

    lberr:
     exec sp_oageterrorinfo NULL, @src out, @desc out 
     declare @errb varbinary(4)
     set @errb=cast(@err as varbinary(4))
     exec master..xp_varbintohexstr @errb,@re out
     set @re='错误号: '+@re
       +char(13)+'错误源: '+@src
       +char(13)+'错误描述: '+@desc
     return(@re)
    end
    go


    2、 用法如下
    用法如下,

    print dbo.fgetscript('服务器名','用户名','密码','数据库名','表名或其它对象名')

    3、 如果要获取库里所有对象的脚本,如如下方式


    declare @name varchar(250)
    declare #aa cursor for
     select name from sysobjects where xtype not in('S','PK','D','X','L')
    open #aa
    fetch next from #aa into @name
    while @@fetch_status=0
    begin
     print dbo.fgetscript('onlytiancai','sa','sa','database',@name)
     fetch next from #aa into @name
    end
    close #aa
    deallocate #aa

    4、 声明,此函数是csdn邹建邹老大提供的
    三、 分隔字符串
    如果有一个用逗号分割开的字符串,比如说"a,b,c,d,1,2,3,4",如何用t-sql获取这个字符串有几个元素,获取第几个元素的值是多少呢?因为t-sql里没有split函数,也没有数组的概念,所以只能自己写几个函数了。
    1、 获取元素个数的函数


    create function getstrarrlength (@str varchar(8000))
    returns int
    as
    begin
      declare @int_return int
      declare @start int
      declare @next int
      declare @location int
      select @str =','+ @str +','
      select @str=replace(@str,',,',',')
      select @start =1
      select @next =1 
      select @location = charindex(',',@str,@start)
      while (@location <>0)
      begin
        select @start = @location +1
        select @location = charindex(',',@str,@start)
        select @next =@next +1
      end
     select @int_return = @next-2
     return @int_return
    end

    2、 获取指定索引的值的函数


    create function getstrofindex (@str varchar(8000),@index i