X的家
编程,软件,技术交流
日历
网志文件夹
· [所有网志]
· [未分类]
· 程序人生
· 技术文章
· 心情随笔
最新的评论
站内搜索
友情链接
· [RedFoxOnline]
· [IT从业者社区]
· 管理我的Blog

订阅 RSS

0017528

歪酷博客

X @ 2007-12-06 10:21

我搬家了:)http://www.ccworker.com



 
X @ 2005-02-03 16:39

使用 .NET 和后台智能传输服务 API 来编写自动更新应用程序
http://www.microsoft.com/china/MSDN/library/netFramework/netframework/AutoUpdApp.mspx


 
X @ 2005-01-27 17:36

"蜘蛛"(Spider)是Internet上一种很有用的程序,搜索引擎利用蜘蛛程序将Web页面收集到数据库,企业利用蜘蛛程序监视竞争对手的网站并跟踪变动,个人用户用蜘蛛程序下载Web页面以便脱机使用,开发者利用蜘蛛程序扫描自己的Web检查无效的链接……对于不同的用户,蜘蛛程序有不同的用途。那么,蜘蛛程序到底是怎样工作的呢?

  蜘蛛是一种半自动的程序,就象现实当中的蜘蛛在它的Web(蜘蛛网)上旅行一样,蜘蛛程序也按照类似的方式在Web链接织成的网上旅行。蜘蛛程序之所以是半自动的,是因为它总是需要一个初始链接(出发点),但此后的运行情况就要由它自己决定了,蜘蛛程序会扫描起始页面包含的链接,然后访问这些链接指向的页面,再分析和追踪那些页面包含的链接。从理论上看,最终蜘蛛程序会访问到Internet上的每一个页面,因为Internet上几乎每一个页面总是被其他或多或少的页面引用。

  本文介绍如何用C#语言构造一个蜘蛛程序,它能够把整个网站的内容下载到某个指定的目录,程序的运行界面如图一。你可以方便地利用本文提供的几个核心类构造出自己的蜘蛛程序。



图1


  C#特别适合于构造蜘蛛程序,这是因为它已经内置了HTTP访问和多线程的能力,而这两种能力对于蜘蛛程序来说都是非常关键的。下面是构造一个蜘蛛程序要解决的关键问题:

  ⑴ HTML分析:需要某种HTML解析器来分析蜘蛛程序遇到的每一个页面。

  ⑵ 页面处理:需要处理每一个下载得到的页面。下载得到的内容可能要保存到磁盘,或者进一步分析处理。

  ⑶ 多线程:只有拥有多线程能力,蜘蛛程序才能真正做到高效。

  ⑷ 确定何时完成:不要小看这个问题,确定任务是否已经完成并不简单,尤其是在多线程环境下。

  一、HTML解析

  C#语言本身不包含解析HTML的能力,但支持XML解析;不过,XML有着严格的语法,为XML设计的解析器对HTML来说根本没用,因为HTML的语法要宽松得多。为此,我们需要自己设计一个HTML解析器。本文提供的解析器是高度独立的,你可以方便地将它用于其它用C#处理HTML的场合。

  本文提供的HTML解析器由ParseHTML类实现,使用非常方便:首先创建该类的一个实例,然后将它的Source属性设置为要解析的HTML文档:

ParseHTML parse = new ParseHTML();
parse.Source = "<p>Hello World</p>";
  接下来就可以利用循环来检查HTML文档包含的所有文本和标记。通常,检查过程可以从一个测试Eof方法的while循环开始:

while(!parse.Eof())
{
char ch = parse.Parse();
  Parse方法将返回HTML文档包含的字符--它返回的内容只包含那些非HTML标记的字符,如果遇到了HTML标记,Parse方法将返回0值,表示现在遇到了一个HTML标记。遇到一个标记之后,我们可以用GetTag()方法来处理它。

if(ch==0)
{
HTMLTag tag = parse.GetTag();
}
  一般地,蜘蛛程序最重要的任务之一就是找出各个HREF属性,这可以借助C#的索引功能完成。例如,下面的代码将提取出HREF属性的值(如果存在的话)。

Attribute href = tag["HREF"];
string link = href.Value;

  获得Attribute对象之后,通过Attribute.Value可以得到该属性的值。

二、处理HTML页面

  下面来看看如何处理HTML页面。首先要做的当然是下载HTML页面,这可以通过C#提供的HttpWebRequest类实现:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(m_uri);
response = request.GetResponse();
stream = response.GetResponseStream();

  接下来我们就从request创建一个stream流。在执行其他处理之前,我们要先确定该文件是二进制文件还是文本文件,不同的文件类型处理方式也不同。下面的代码确定该文件是否为二进制文件。

if( !response.ContentType.ToLower().StartsWith("text/") )
{
SaveBinaryFile(response);
return null;
}
string buffer = "",line;

  如果该文件不是文本文件,我们将它作为二进制文件读入。如果是文本文件,首先从stream创建一个StreamReader,然后将文本文件的内容一行一行加入缓冲区。

reader = new StreamReader(stream);
while( (line = reader.ReadLine())!=null )
{
buffer+=line+"\r\n";
}

  装入整个文件之后,接着就要把它保存为文本文件。

SaveTextFile(buffer);

  下面来看看这两类不同文件的存储方式。

  二进制文件的内容类型声明不以"text/"开头,蜘蛛程序直接把二进制文件保存到磁盘,不必进行额外的处理,这是因为二进制文件不包含HTML,因此也不会再有需要蜘蛛程序处理的HTML链接。下面是写入二进制文件的步骤。

  首先准备一个缓冲区临时地保存二进制文件的内容。 byte []buffer = new byte[1024];

  接下来要确定文件保存到本地的路径和名称。如果要把一个myhost.com网站的内容下载到本地的c:\test文件夹,二进制文件的网上路径和名称是http://myhost.com/images/logo.gif,则本地路径和名称应当是c:\test\images\logo.gif。与此同时,我们还要确保c:\test目录下已经创建了images子目录。这部分任务由convertFilename方法完成。

string filename = convertFilename( response.ResponseUri );
  convertFilename方法分离HTTP地址,创建相应的目录结构。确定了输出文件的名字和路径之后就可以打开读取Web页面的输入流、写入本地文件的输出流。

Stream outStream = File.Create( filename );
Stream inStream = response.GetResponseStream();
  接下来就可以读取Web文件的内容并写入到本地文件,这可以通过一个循环方便地完成。

int l;
do
{
l = inStream.Read(buffer,0,
buffer.Length);
if(l>0)
outStream.Write(buffer,0,l);
} while(l>0);

  写入整个文件之后,关闭输入流、输出流。

outStream.Close();
inStream.Close();

  比较而言,下载文本文件更容易一些。文本文件的内容类型总是以"text/"开头。假设文件已被下载并保存到了一个字符串,这个字符串可以用来分析网页包含的链接,当然也可以保存为磁盘上的文件。下面代码的任务就是保存文本文件。

string filename = convertFilename( m_uri );
StreamWriter outStream = new StreamWriter( filename );
outStream.Write(buffer);
outStream.Close();

  在这里,我们首先打开一个文件输出流,然后将缓冲区的内容写入流,最后关闭文件。

  三、多线程

  多线程使得计算机看起来就象能够同时执行一个以上的操作,不过,除非计算机包含多个处理器,否则,所谓的同时执行多个操作仅仅是一种模拟出来的效果--靠计算机在多个线程之间快速切换达到"同时"执行多个操作的效果。一般而言,只有在两种情况下多线程才能事实上提高程序运行的速度。第一种情况是计算机拥有多个处理器,第二种情况是程序经常要等待某个外部事件。
对于蜘蛛程序来说,第二种情况正是它的典型特征之一,它每发出一个URL请求,总是要等待文件下载完毕,然后再请求下一个URL。如果蜘蛛程序能够同时请求多个URL,显然能够有效地减少总下载时间。

  为此,我们用DocumentWorker类封装所有下载一个URL的操作。每当一个DocumentWorker的实例被创建,它就进入循环,等待下一个要处理的URL。下面是DocumentWorker的主循环:

while(!m_spider.Quit )
{
m_uri = m_spider.ObtainWork();

m_spider.SpiderDone.WorkerBegin();
string page = GetPage();
if(page!=null)
ProcessPage(page);
m_spider.SpiderDone.WorkerEnd();
}
  这个循环将一直运行,直至Quit标记被设置成了true(当用户点击"Cancel"按钮时,Quit标记就被设置成true)。在循环之内,我们调用ObtainWork获取一个URL。ObtainWork将一直等待,直到有一个URL可用--这要由其他线程解析文档并寻找链接才能获得。Done类利用WorkerBegin和WorkerEnd方法来确定何时整个下载操作已经完成。

  从图一可以看出,蜘蛛程序允许用户自己确定要使用的线程数量。在实践中,线程的最佳数量受许多因素影响。如果你的机器性能较高,或者有两个处理器,可以设置较多的线程数量;反之,如果网络带宽、机器性能有限,设置太多的线程数量其实不一定能够提高性能。

  四、任务完成了吗?

  利用多个线程同时下载文件有效地提高了性能,但也带来了线程管理方面的问题。其中最复杂的一个问题是:蜘蛛程序何时才算完成了工作?在这里我们要借助一个专用的类Done来判断。

  首先有必要说明一下"完成工作"的具体含义。只有当系统中不存在等待下载的URL,而且所有工作线程都已经结束其处理工作时,蜘蛛程序的工作才算完成。也就是说,完成工作意味着已经没有等待下载和正在下载的URL。

  Done类提供了一个WaitDone方法,它的功能是一直等待,直到Done对象检测到蜘蛛程序已完成工作。下面是WaitDone方法的代码。

public void WaitDone()
{
Monitor.Enter(this);
while ( m_activeThreads>0 )
{
Monitor.Wait(this);
}
Monitor.Exit(this);
}
  WaitDone方法将一直等待,直到不再有活动的线程。但必须注意的是,下载开始的最初阶段也没有任何活动的线程,所以很容易造成蜘蛛程序一开始就立即停止的现象。为解决这个问题,我们还需要另一个方法WaitBegin来等待蜘蛛程序进入"正式的"工作阶段。一般的调用次序是:先调用WaitBegin,再接着调用WaitDone,WaitDone将等待蜘蛛程序完成工作。下面是WaitBegin的代码:

public void WaitBegin()
{
Monitor.Enter(this);
while ( !m_started )
{
Monitor.Wait(this);
}
Monitor.Exit(this);
}
  WaitBegin方法将一直等待,直到m_started标记被设置。m_started标记是由WorkerBegin方法设置的。工作线程在开始处理各个URL之时,会调用WorkerBegin;处理结束时调用WorkerEnd。WorkerBegin和WorkerEnd这两个方法帮助Done对象确定当前的工作状态。下面是WorkerBegin方法的代码:

public void WorkerBegin()
{
Monitor.Enter(this);
m_activeThreads++;
m_started = true;
Monitor.Pulse(this);
Monitor.Exit(this);
}
  WorkerBegin方法首先增加当前活动线程的数量,接着设置m_started标记,最后调用Pulse方法以通知(可能存在的)等待工作线程启动的线程。如前所述,可能等待Done对象的方法是WaitBegin方法。每处理完一个URL,WorkerEnd方法会被调用:

public void WorkerEnd()
{
Monitor.Enter(this);
m_activeThreads--;
Monitor.Pulse(this);
Monitor.Exit(this);
}
  WorkerEnd方法减小m_activeThreads活动线程计数器,调用Pulse释放可能在等待Done对象的线程--如前所述,可能在等待Done对象的方法是WaitDone方法。

  结束语:本文介绍了开发Internet蜘蛛程序的基础知识,下面提供的源代码将帮助你进一步深入理解本文的主题。这里提供的代码非常灵活,你可以方便地将它用于自己的程序。

下载本文的代码:webFindercode.rar


 
X @ 2005-01-27 17:23

作者Blog:http://blog.csdn.net/lovewangshu/

快速排序的基本思想是基于分治策略的。对于输入的子序列ap..ar,如果规模足够小则直接进行排序,否则分三步处理:

分解(Divide):将输入的序列ap..ar划分成两个非空子序列ap..aq和aq+1..ar,使ap..aq中任一元素的值不大于aq+1..ar中任一元素的值。  
递归求解(Conquer):通过递归对p..aq和aq+1..ar进行排序。  
合并(Merge):由于对分解出的两个子序列的排序是就地进行的,所以在ap..aq和aq+1..ar都排好序后不需要执行任何计算ap..ar就已排好序。  
这个解决流程是符合分治法的基本步骤的。因此,快速排序法是分治法的经典应用实例之一。

using System;

namespace VcQuickSort
{
/// <summary>
/// ClassQuickSort 快速排序。
/// 范维肖
/// </summary>
public class QuickSort
{
 public QuickSort()
 {
 }

 private void Swap(ref int i,ref int j)
 //swap two integer
 {
  int t;
  t=i;
  i=j;
  j=t;
 }
  
 public void Sort(int [] list,int low,int high)
 {
  if(high<=low)
  {
   //only one element in array list
   //so it do not need sort
   return;
  }
  else if (high==low+1)
  {
   //means two elements in array list
   //so we just compare them
   if(list[low]>list[high])
   {
    //exchange them
    Swap(ref list[low],ref list[high]);
    return;
   }
  }
  //more than 3 elements in the arrary list
  //begin QuickSort
  myQuickSort(list,low,high);
 }

 public void myQuickSort(int [] list,int low,int high)
 {
  if(low<high)
  {
   int pivot=Partition(list,low,high);
   myQuickSort(list,low,pivot-1);
   myQuickSort(list,pivot+1,high);
  }
 }

 private int Partition(int [] list,int low,int high)
 {
  //get the pivot of the arrary list
  int pivot;
  pivot=list[low];
  while(low<high)
  {
   while(low<high && list[high]>=pivot)
   {
    high--;
   }
   if(low!=high)
   {
    Swap(ref list[low],ref list[high]);
    low++;
   }
   while(low<high && list[low]<=pivot)
   {
    low++;
   }
   if(low!=high)
   {
    Swap(ref list[low],ref list[high]);  
    high--;
   }
  }
  return low;
 }

}
}


 
X @ 2005-01-25 10:47

/*******  导出到excel
EXEC master..xp_cmdshell ’bcp SettleDB.dbo.shanghu out c:\temp1.xls -c -q -S"GNETDATA/GNETDATA" -U"sa" -P""’

/***********  导入Excel
SELECT *
FROM OpenDataSource( ’Microsoft.Jet.OLEDB.4.0’,
 ’Data Source="c:\test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0’)...xactions


SELECT cast(cast(科目编号 as numeric(10,2)) as nvarchar(255))+’ ’ 转换后的别名
FROM OpenDataSource( ’Microsoft.Jet.OLEDB.4.0’,
 ’Data Source="c:\test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0’)...xactions

/** 导入文本文件
EXEC master..xp_cmdshell ’bcp "dbname..tablename" in c:\DT.txt -c -Sservername -Usa -Ppassword’

/** 导出文本文件
EXEC master..xp_cmdshell ’bcp "dbname..tablename" out c:\DT.txt -c -Sservername -Usa -Ppassword’

EXEC master..xp_cmdshell ’bcp "Select * from dbname..tablename" queryout c:\DT.txt -c -Sservername -Usa -Ppassword’

导出到TXT文本,用逗号分开
exec master..xp_cmdshell ’bcp "库名..表名" out "d:\tt.txt" -c -t ,-U sa -P password’


BULK INSERT 库名..表名
FROM ’c:\test.txt’
WITH (
   FIELDTERMINATOR = ’;’,
   ROWTERMINATOR = ’\n’
)


--/* dBase IV文件
select * from
OPENROWSET(’MICROSOFT.JET.OLEDB.4.0’
,’dBase IV;HDR=NO;IMEX=2;DATABASE=C:\’,’select * from [客户资料4.dbf]’)
--*/

--/* dBase III文件
select * from
OPENROWSET(’MICROSOFT.JET.OLEDB.4.0’
,’dBase III;HDR=NO;IMEX=2;DATABASE=C:\’,’select * from [客户资料3.dbf]’)
--*/

--/* FoxPro 数据库
select * from openrowset(’MSDASQL’,
’Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:\’,
’select * from [aa.DBF]’)
--*/

/**************导入DBF文件****************/
select * from openrowset(’MSDASQL’,
’Driver=Microsoft Visual FoxPro Driver;
SourceDB=e:\VFP98\data;
SourceType=DBF’,
’select * from customer where country != "USA" order by country’)
go
/***************** 导出到DBF ***************/
如果要导出数据到已经生成结构(即现存的)FOXPRO表中,可以直接用下面的SQL语句

insert into openrowset(’MSDASQL’,
’Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:\’,
’select * from [aa.DBF]’)
select * from 表

说明:
SourceDB=c:\  指定foxpro表所在的文件夹
aa.DBF        指定foxpro表的文件名.




/*************导出到Access********************/
insert into openrowset(’Microsoft.Jet.OLEDB.4.0’,
  ’x:\A.mdb’;’admin’;’’,A表) select * from 数据库名..B表

/*************导入Access********************/
insert into B表 selet * from openrowset(’Microsoft.Jet.OLEDB.4.0’,
  ’x:\A.mdb’;’admin’;’’,A表)

*********************  导入 xml 文件

DECLARE @idoc int
DECLARE @doc varchar(1000)
--sample XML document
SET @doc =’
<root>
 <Customer cid= "C1" name="Janine" city="Issaquah">
     <Order oid="O1" date="1/20/1996" amount="3.5" />
     <Order oid="O2" date="4/30/1997" amount="13.4">Customer was very satisfied
     </Order>
  </Customer>
  <Customer cid="C2" name="Ursula" city="Oelde" >
     <Order oid="O3" date="7/14/1999" amount="100" note="Wrap it blue
            white red">
           <Urgency>Important</Urgency>
           Happy Customer.
     </Order>
     <Order oid="O4" date="1/20/1996" amount="10000"/>
  </Customer>
</root>

-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc

-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, ’/root/Customer/Order’, 1)
     WITH (oid     char(5),
           amount  float,
           comment ntext ’text()’)
EXEC sp_xml_removedocument @idoc


/********************导整个数据库*********************************************/

用bcp实现的存储过程


/*
实现数据导入/导出的存储过程
        根据不同的参数,可以实现导入/导出整个数据库/单个表
调用示例:
--导出调用示例
----导出单个表
exec file2table ’zj’,’’,’’,’xzkh_sa..地区资料’,’c:\zj.txt’,1
----导出整个数据库
exec file2table ’zj’,’’,’’,’xzkh_sa’,’C:\docman’,1

--导入调用示例
----导入单个表
exec file2table ’zj’,’’,’’,’xzkh_sa..地区资料’,’c:\zj.txt’,0
----导入整个数据库
exec file2table ’zj’,’’,’’,’xzkh_sa’,’C:\docman’,0

*/
if exists(select 1 from sysobjects where name=’File2Table’ and objectproperty(id,’IsProcedure’)=1)
drop procedure File2Table
go
create procedure File2Table
@servername varchar(200)  --服务器名
,@username varchar(200)   --用户名,如果用NT验证方式,则为空’’
,@password varchar(200)   --密码
,@tbname varchar(500)   --数据库.dbo.表名,如果不指定:.dbo.表名,则导出数据库的所有用户表
,@filename varchar(1000)  --导入/导出路径/文件名,如果@tbname参数指明是导出整个数据库,则这个参数是文件存放路径,文件名自动用表名.txt
,@isout bit      --1为导出,0为导入
as
declare @sql varchar(8000)

if @tbname like ’%.%.%’ --如果指定了表名,则直接导出单个表
begin
set @sql=’bcp ’+@tbname
 +case when @isout=1 then ’ out ’ else ’ in ’ end
 +’ "’+@filename+’" /w’
 +’ /S ’+@servername
 +case when isnull(@username,’’)=’’ then ’’ else ’ /U ’+@username end
 +’ /P ’+isnull(@password,’’)
exec master..xp_cmdshell @sql
end
else
begin --导出整个数据库,定义游标,取出所有的用户表
declare @m_tbname varchar(250)
if right(@filename,1)<>’\’ set @filename=@filename+’\’

set @m_tbname=’declare #tb cursor for select name from ’+@tbname+’..sysobjects where xtype=’’U’’’
exec(@m_tbname)
open #tb
fetch next from #tb into @m_tbname
while @@fetch_status=0
begin
 set @sql=’bcp ’+@tbname+’..’+@m_tbname
  +case when @isout=1 then ’ out ’ else ’ in ’ end
  +’ "’+@filename+@m_tbname+’.txt " /w’
  +’ /S ’+@servername
  +case when isnull(@username,’’)=’’ then ’’ else ’ /U ’+@username end
  +’ /P ’+isnull(@password,’’)
 exec master..xp_cmdshell @sql
 fetch next from #tb into @m_tbname
end
close #tb
deallocate #tb  
end
go


/**********************Excel导到Txt****************************************/
想用
select * into opendatasource(...) from opendatasource(...)
实现将一个Excel文件内容导入到一个文本文件

假设Excel中有两列,第一列为姓名,第二列为很行帐号(16位)
且银行帐号导出到文本文件后分两部分,前8位和后8位分开。


如果要用你上面的语句插入的话,文本文件必须存在,而且有一行:姓名,银行账号1,银行账号2
然后就可以用下面的语句进行插入
注意文件名和目录根据你的实际情况进行修改.

insert into
opendatasource(’MICROSOFT.JET.OLEDB.4.0’
,’Text;HDR=Yes;DATABASE=C:\’
)...[aa#txt]
--,aa#txt)
--*/
select 姓名,银行账号1=left(银行账号,8),银行账号2=right(银行账号,8)
from
opendatasource(’MICROSOFT.JET.OLEDB.4.0’
,’Excel 5.0;HDR=YES;IMEX=2;DATABASE=c:\a.xls’
--,Sheet1$)
)...[Sheet1$]

如果你想直接插入并生成文本文件,就要用bcp

declare @sql varchar(8000),@tbname varchar(50)

--首先将excel表内容导入到一个全局临时表
select @tbname=’[##temp’+cast(newid() as varchar(40))+’]’
,@sql=’select 姓名,银行账号1=left(银行账号,8),银行账号2=right(银行账号,8)
into ’+@tbname+’ from
opendatasource(’’MICROSOFT.JET.OLEDB.4.0’’
,’’Excel 5.0;HDR=YES;IMEX=2;DATABASE=c:\a.xls’’
)...[Sheet1$]’
exec(@sql)

--然后用bcp从全局临时表导出到文本文件
set @sql=’bcp "’+@tbname+’" out "c:\aa.txt" /S"(local)" /P"" /c’
exec master..xp_cmdshell @sql

--删除临时表
exec(’drop table ’+@tbname)


用bcp将文件导入导出到数据库的存储过程:


/*--bcp-二进制文件的导入导出

支持image,text,ntext字段的导入/导出
image适合于二进制文件;text,ntext适合于文本数据文件

注意:导入时,将覆盖满足条件的所有行
 导出时,将把所有满足条件的行也出到指定文件中

此存储过程仅用bcp实现
邹建 2003.08-----------------*/

/*--调用示例
--数据导出
exec p_binaryIO ’zj’,’’,’’,’acc_演示数据..tb’,’img’,’c:\zj1.dat’

--数据导出
exec p_binaryIO ’zj’,’’,’’,’acc_演示数据..tb’,’img’,’c:\zj1.dat’,’’,0
--*/
if exists (select * from dbo.sysobjects where id = object_id(N’[dbo].[p_binaryIO]’) and OBJECTPROPERTY(id, N’IsProcedure’) = 1)
drop procedure [dbo].[p_binaryIO]
GO

Create proc p_binaryIO
@servename varchar (30),--服务器名称
@username varchar (30), --用户名
@password varchar (30), --密码
@tbname varchar (500),  --数据库..表名
@fdname varchar (30),  --字段名
@fname varchar (1000), --目录+文件名,处理过程中要使用/覆盖:@filename+.bak
@tj varchar (1000)=’’,  --处理条件.对于数据导入,如果条件中包含@fdname,请指定表名前缀
@isout bit=1   --1导出((默认),0导入
AS
declare @fname_in varchar(1000) --bcp处理应答文件名
,@fsize varchar(20)   --要处理的文件的大小
,@m_tbname varchar(50)  --临时表名
,@sql varchar(8000)

--则取得导入文件的大小
if @isout=1
set @fsize=’0’
else
begin
create table #tb(可选名 varchar(20),大小 int
 ,创建日期 varchar(10),创建时间 varchar(20)
 ,上次写操作日期 varchar(10),上次写操作时间 varchar(20)
 ,上次访问日期 varchar(10),上次访问时间 varchar(20),特性 int)
insert into #tb
exec master..xp_getfiledetails @fname
select @fsize=大小 from #tb
drop table #tb
if @fsize is null
begin
 print ’文件未找到’
 return
end

end

--生成数据处理应答文件
set @m_tbname=’[##temp’+cast(newid() as varchar(40))+’]’
set @sql=’select * into ’+@m_tbname+’ from(
select null as 类型
union all select 0 as 前缀
union all select ’+@fsize+’ as 长度
union all select null as 结束
union all select null as 格式
) a’
exec(@sql)
select @fname_in=@fname+’_temp’
,@sql=’bcp "’+@m_tbname+’" out "’+@fname_in
+’" /S"’+@servename
+case when isnull(@username,’’)=’’ then ’’
 else ’" /U"’+@username end
+’" /P"’+isnull(@password,’’)+’" /c’
exec master..xp_cmdshell @sql
--删除临时表
set @sql=’drop table ’+@m_tbname
exec(@sql)

if @isout=1
begin
set @sql=’bcp "select top 1 ’+@fdname+’ from ’
 +@tbname+case isnull(@tj,’’) when ’’ then ’’
  else ’ where ’+@tj end
 +’" queryout "’+@fname
 +’" /S"’+@servename
 +case when isnull(@username,’’)=’’ then ’’
  else ’" /U"’+@username end
 +’" /P"’+isnull(@password,’’)
 +’" /i"’+@fname_in+’"’
exec master..xp_cmdshell @sql
end
else
begin
--为数据导入准备临时表
set @sql=’select top 0 ’+@fdname+’ into ’
 +@m_tbname+’ from ’ +@tbname
exec(@sql)

--将数据导入到临时表
set @sql=’bcp "’+@m_tbname+’" in "’+@fname
 +’" /S"’+@servename
 +case when isnull(@username,’’)=’’ then ’’
  else ’" /U"’+@username end
 +’" /P"’+isnull(@password,’’)
 +’" /i"’+@fname_in+’"’
exec master..xp_cmdshell @sql
 
--将数据导入到正式表中
set @sql=’update ’+@tbname
 +’ set ’+@fdname+’=b.’+@fdname
 +’ from ’+@tbname+’ a,’
 +@m_tbname+’ b’
 +case isnull(@tj,’’) when ’’ then ’’
  else ’ where ’+@tj end
exec(@sql)

--删除数据处理临时表
set @sql=’drop table ’+@m_tbname
end

--删除数据处理应答文件
set @sql=’del ’+@fname_in
exec master..xp_cmdshell @sql

go


/** 导入文本文件
EXEC master..xp_cmdshell ’bcp "dbname..tablename" in c:\DT.txt -c -Sservername -Usa -Ppassword’

改为如下,不需引号
EXEC master..xp_cmdshell ’bcp dbname..tablename in c:\DT.txt -c -Sservername -Usa -Ppassword’

/** 导出文本文件
EXEC master..xp_cmdshell ’bcp "dbname..tablename" out c:\DT.txt -c -Sservername -Usa -Ppassword’
此句需加引号




 
X @ 2005-01-25 10:45

DB2 提供了关连式资料库的查询语言 SQL (Structured Query Language),是一种非常口语化、既易学又易懂的语法。此一语言几乎是每个资料库系统都必须提供的,用以表示关连式的*作,包含了资料的定义(DDL)以及资料的处理(DML)。SQL原来拼成SEQUEL,这语言的原型以“系统 R“的名字在 IBM 圣荷西实验室完成,经过IBM内部及其他的许多使用性及效率测试,其结果相当令人满意,并决定在系统R 的技术基础发展出来 IBM 的产品。而且美国国家标准学会(ANSI)及国际标准化组织(ISO)在1987遵循一个几乎是以 IBM SQL 为基础的标准关连式资料语言定义。

一、资料定义 DDL(Data Definition Language)
资料定语言是指对资料的格式和形态下定义的语言,他是每个资料库要建立时候时首先要面对的,举凡资料分哪些表格关系、表格内的有什麽栏位主键、表格和表格之间互相参考的关系等等,都是在开始的时候所必须规划好的。

1、建表格:
CREATE TABLE table_name(
column1 DATATYPE [NOT NULL] [NOT NULL PRIMARY KEY],
column2 DATATYPE [NOT NULL],
...)
说明: 
DATATYPE --是资料的格式,详见表。
NUT NULL --可不可以允许资料有空的(尚未有资料填入)。
PRIMARY KEY --是本表的主键。

2、更改表格 
ALTER TABLE table_name
ADD COLUMN column_name DATATYPE
说明:增加一个栏位(没有删除某个栏位的语法。
ALTER TABLE table_name
ADD PRIMARY KEY (column_name)
说明:更改表得的定义把某个栏位设为主键。
ALTER TABLE table_name
DROP PRIMARY KEY (column_name)
说明:把主键的定义删除。

3、建立索引 
CREATE INDEX index_name ON table_name (column_name)
说明:对某个表格的栏位建立索引以增加查询时的速度。

4、删除 
DROP table_name
DROP index_name

二、的资料形态 DATATYPEs
smallint
16 位元的整数。
interger
32 位元的整数。
decimal(p,s)
p 精确值和 s 大小的十进位整数,精确值p是指全部有几个数(digits)大小值,s是指小数
点後有几位数。如果没有特别指定,则系统会设为 p=5; s=0 。
float
32位元的实数。
double
64位元的实数。
char(n)
n 长度的字串,n不能超过 254。
varchar(n)
长度不固定且其最大长度为 n 的字串,n不能超过 4000。
graphic(n)
和 char(n) 一样,不过其单位是两个字元 double-bytes, n不能超过127。这个形态是为
了支援两个字元长度的字体,例如中文字。
vargraphic(n)
可变长度且其最大长度为 n 的双字元字串,n不能超过 2000。
date
包含了 年份、月份、日期。
time
包含了 小时、分钟、秒。
timestamp
包含了 年、月、日、时、分、秒、千分之一秒。

三、资料*作 DML (Data Manipulation Language)
资料定义好之後接下来的就是资料的*作。资料的*作不外乎增加资料(insert)、查询资料(query)、更改资料(update) 、删除资料(delete)四种模式,以下分 别介绍他们的语法:

1、增加资料:
INSERT INTO table_name (column1,column2,...)
valueS ( value1,value2, ...)
说明:
1.若没有指定column 系统则会按表格内的栏位顺序填入资料。
2.栏位的资料形态和所填入的资料必须吻合。
3.table_name 也可以是景观 view_name。

INSERT INTO table_name (column1,column2,...)
SELECT columnx,columny,... FROM another_table
说明:也可以经过一个子查询(subquery)把别的表格的资料填入。

2、查询资料:
基本查询
SELECT column1,columns2,...
FROM table_name
说明:把table_name 的特定栏位资料全部列出来
SELECT *
FROM table_name
WHERE column1 = xxx
[AND column2 > yyy] [OR column3 <> zzz]
说明:
1.’*’表示全部的栏位都列出来。
2.WHERE 之後是接条件式,把符合条件的资料列出来。

SELECT column1,column2
FROM table_name
ORDER BY column2 [DESC]
说明:ORDER BY 是指定以某个栏位做排序,[DESC]是指从大到小排列,若没有指明,则是从小到大
排列

组合查询
组合查询是指所查询得资料来源并不只有单一的表格,而是联合一个以上的
表格才能够得到结果的。
SELECT *
FROM table1,table2
WHERE table1.colum1=table2.column1
说明:
1.查询两个表格中其中 column1 值相同的资料。
2.当然两个表格相互比较的栏位,其资料形态必须相同。
3.一个复杂的查询其动用到的表格可能会很多个。

整合性的查询:
SELECT COUNT (*)
FROM table_name
WHERE column_name = xxx
说明:
查询符合条件的资料共有几笔。
SELECT SUM(column1)
FROM table_name
说明:
1.计算出总和,所选的栏位必须是可数的数字形态。
2.除此以外还有 AVG() 是计算平均、MAX()、MIN()计算最大最小值的整合性查询。
SELECT column1,AVG(column2)
FROM table_name
GROUP BY column1
HAVING AVG(column2) > xxx
说明:
1.GROUP BY: 以column1 为一组计算 column2 的平均值必须和 AVG、SUM等整合性查询的关键字
一起使用。
2.HAVING : 必须和 GROUP BY 一起使用作为整合性的限制。

复合性的查询
SELECT *
FROM table_name1
WHERE EXISTS (
SELECT *
FROM table_name2
WHERE conditions )
说明:
1.WHERE 的 conditions 可以是另外一个的 query。
2.EXISTS 在此是指存在与否。
SELECT *
FROM table_name1
WHERE column1 IN (
SELECT column1
FROM table_name2
WHERE conditions )
说明: 
1. IN 後面接的是一个集合,表示column1 存在集合里面。
2. SELECT 出来的资料形态必须符合 column1。

其他查询
SELECT *
FROM table_name1
WHERE column1 LIKE ’x%’
说明:LIKE 必须和後面的’x%’ 相呼应表示以 x为开头的字串。
SELECT *
FROM table_name1
WHERE column1 IN (’xxx’,’yyy’,..)
说明:IN 後面接的是一个集合,表示column1 存在集合里面。
SELECT *
FROM table_name1
WHERE column1 BETWEEN xx AND yy
说明:BETWEEN 表示 column1 的值介於 xx 和 yy 之间。

3、更改资料:
UPDATE table_name
SET column1=’xxx’
WHERE conditoins
说明:
1.更改某个栏位设定其值为’xxx’。
2.conditions 是所要符合的条件、若没有 WHERE 则整个 table 的那个栏位都会全部被更改。

4、删除资料:
DELETE FROM table_name
WHERE conditions
说明:删除符合条件的资料。

说明:关于WHERE条件后面如果包含有日期的比较,不同数据库有不同的表达式。具体如下:
(1)如果是ACCESS数据库,则为:WHERE mydate>#2000-01-01#
(2)如果是ORACLE数据库,则为:WHERE mydate>cast(’2000-01-01’ as date)
或:WHERE mydate>to_date(’2000-01-01’,’yyyy-mm-dd’)
在Delphi中写成:
thedate=’2000-01-01’;
query1.SQL.add(’select * from abc where mydate>cast(’+’’’’+thedate+’’’’+’ as date)’);

如果比较日期时间型,则为:
WHERE mydatetime>to_date(’2000-01-01 10:00:01’,’yyyy-mm-dd hh24:mi:ss’)