﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-梦幻白桦林-文章分类-SqlServer</title><link>http://www.cppblog.com/colys/category/4145.html</link><description>LIFE AS CODE</description><language>zh-cn</language><lastBuildDate>Thu, 22 May 2008 13:41:45 GMT</lastBuildDate><pubDate>Thu, 22 May 2008 13:41:45 GMT</pubDate><ttl>60</ttl><item><title>分散数据库压力,分表处理设计思想和实现</title><link>http://www.cppblog.com/colys/articles/32397.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Tue, 18 Sep 2007 01:51:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/32397.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/32397.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/32397.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/32397.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/32397.html</trackback:ping><description><![CDATA[<div><strong> 一、概述</strong> </div>
<div>&nbsp;</div>
<div>分表是个目前算是比较炒的比较流行的概念，特别是在大负载的情况下，分表是一个良好分散数据库压力的好方法。</div>
<div>&nbsp;</div>
<div>首先要了解为什么要分表，分表的好处是什么。我们先来大概了解以下一个数据库执行SQL的过程：</div>
<div>接收到SQL --&gt; 放入SQL执行队列 --&gt; 使用分析器分解SQL --&gt; 按照分析结果进行数据的提取或者修改 --&gt; 返回处理结果</div>
<div>&nbsp;</div>
<div>当然，这个流程图不一定正确，这只是我自己主观意识上这么我认为。那么这个处理过程当中，最容易出现问题的是什么？就是说，如果前一个SQL没
有执行完毕的话，后面的SQL是不会执行的，因为为了保证数据的完整性，必须对数据表文件进行锁定，包括共享锁和独享锁两种锁定。共享锁是在锁定的期间，
其它线程也可以访问这个数据文件，但是不允许修改操作，相应的，独享锁就是整个文件就是归一个线程所有，其它线程无法访问这个数据文件。一般MySQL中
最快的存储引擎MyISAM，它是基于表锁定的，就是说如果一锁定的话，那么整个数据文件外部都无法访问，必须等前一个操作完成后，才能接收下一个操作，
那么在这个前一个操作没有执行完成，后一个操作等待在队列里无法执行的情况叫做阻塞，一般我们通俗意义上叫做&#8220;锁表&#8221;。</div>
<div>&nbsp;</div>
<div>锁表直接导致的后果是什么？就是大量的SQL无法立即执行，必须等队列前面的SQL全部执行完毕才能继续执行。这个无法执行的SQL就会导致没有结果，或者延迟严重，影响用户体验。</div>
<div>&nbsp;</div>
<div>特别是对于一些使用比较频繁的表，比如SNS系统中的用户信息表、论坛系统中的帖子表等等，都是访问量大很大的表，为了保证数据的快速提取返回给用户，必须使用一些处理方式来解决这个问题，这个就是我今天要聊到的分表技术。</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>分表技术顾名思义，就是把若干个存储相同类型数据的表分成几个表分表存储，在提取数据的时候，不同的用户访问不同的表，互不冲突，减少锁表的几
率。比如，目前保存用户分表有两个表，一个是user_1表，还有一个是 user_2 表，两个表保存了不同的用户信息，user_1
保存了前10万的用户信息，user_2保存了后10万名用户的信息，现在如果同时查询用户 heiyeluren1 和 heiyeluren2
这个两个用户，那么就是分表从不同的表提取出来，减少锁表的可能。</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>我下面要讲述的两种分表方法我自己都没有实验过，不保证准确能用，只是提供一个设计思路。下面关于分表的例子我假设是在一个贴吧系统的基础上来进行处理和构建的。（如果没有用过贴吧的用户赶紧Google一下）</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div><strong> 二、基于基础表的分表处理</strong> </div>
<div>&nbsp;</div>
<div>这个基于基础表的分表处理方式大致的思想就是：一个主要表，保存了所有的基本信息，如果某个项目需要找到它所存储的表，那么必须从这个基础表中
查找出对应的表名等项目，好直接访问这个表。如果觉得这个基础表速度不够快，可以完全把整个基础表保存在缓存或者内存中，方便有效的查询。</div>
<div>&nbsp;</div>
<div>我们基于贴吧的情况，构建假设如下的3张表：</div>
<div>&nbsp;</div>
<div>1. 贴吧版块表: 保存贴吧中版块的信息</div>
<div>2. 贴吧主题表：保存贴吧中版块中的主题信息，用于浏览</div>
<div>3. 贴吧回复表：保存主题的原始内容和回复内容</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&#8220;贴吧版块表&#8221;包含如下字段：</div>
<div>版块ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; board_id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int(10)</div>
<div>版块名称&nbsp;&nbsp;&nbsp; board_name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char(50)</div>
<div>子表ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; table_id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; smallint(5)</div>
<div>产生时间&nbsp;&nbsp;&nbsp; created&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; datetime</div>
<div>&nbsp;</div>
<div>&#8220;贴吧主题表&#8221;包含如下字段：</div>
<div>主题ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; topic_id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int(10)</div>
<div>主题名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; topic_name&nbsp;&nbsp;&nbsp;&nbsp; char(255)</div>
<div>版块ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; board_id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int(10)</div>
<div>创建时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; created&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; datetime</div>
<div>&nbsp;</div>
<div>&#8220;贴吧回复表&#8221;的字段如下：</div>
<div>回复ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reply_id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int(10)</div>
<div>回复内容&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reply_text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; text</div>
<div>主题ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; topic_id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int(10)</div>
<div>版块ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; board_id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int(10)</div>
<div>创建时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; created&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; datetime</div>
<div>&nbsp;</div>
<div>那么上面保存了我们整个贴吧中的表结构信息，三个表对应的关系是：</div>
<div>&nbsp;</div>
<div>版块 --&gt; 多个主题</div>
<div>主题 --&gt; 多个回复</div>
<div>&nbsp;</div>
<div>那么就是说，表文件大小的关系是：</div>
<div>版块表文件 &lt; 主题表文件 &lt; 回复表文件</div>
<div>&nbsp;</div>
<div>所以基本可以确定需要对主题表和回复表进行分表，已增加我们数据检索查询更改时候的速度和性能。</div>
<div>&nbsp;</div>
<div>看了上面的表结构，会明显发现，在&#8220;版块表&#8221;中保存了一个"table_id"字段，这个字段就是用于保存一个版块对应的主题和回复都是分表保存在什么表里的。</div>
<div>&nbsp;</div>
<div>比如我们有一个叫做&#8220;PHP&#8221;的贴吧，board_id是1，子表ID也是1，那么这条记录就是：</div>
<div>&nbsp;</div>
<div>board_id | board_name | table_id | created</div>
<div>1 | PHP | 1 | 2007-01-19 00:30:12</div>
<div>&nbsp;</div>
<div>相应的，如果我需要提取&#8220;PHP&#8221;吧里的所有主题，那么就必须按照表里保存的table_id来组合一个存储了主题的表名称，比如我们主题表的前缀是&#8220;topic_&#8221;，那么组合出来&#8220;PHP&#8221;吧对应的主题表应该是：&#8220;topic_1&#8221;，那么我们执行：</div>
<div>&nbsp;</div>
<div>Select * FROM topic_1 Where board_id = 1 orDER BY topic_id DESC LIMIT 10</div>
<div>&nbsp;</div>
<div>这样就能够获取这个主题下面回复列表，方便我们进行查看，如果需要查看某个主题下面的回复，我们可以继续使用版块表中保存的&#8220;table_id&#8221;来进行查询。比如我们回复表的前缀是&#8220;reply_&#8221;，那么就可以组合出&#8220;PHP&#8221;吧的ID为1的主题的回复：</div>
<div>&nbsp;</div>
<div>Select * FROM reply_1 Where topic_id = 1 orDER BY reply_id DESC LIMIT 10</div>
<div>&nbsp;</div>
<div>这里，我们能够清晰的看到，其实我们这里使用了基础表，基础表就是我们的版块表。那么相应的，肯定会说：基础表的数据量大了以后如何保证它的速度和效率？</div>
<div>&nbsp;</div>
<div>当然，我们就必须使得这个基础表保持最好的速度和性能，比如，可以采用MySQL的内存表来存储，或者保存在内存当中，比如Memcache之类的内存缓存等等，可以按照实际情况来进行调整。</div>
<div>&nbsp;</div>
<div>一般基于基础表的分表机制在SNS、交友、论坛等Web2.0网站中是个比较不错的解决方案，在这些网站中，完全可以单独使用一个表来来保存基本标识和目标表之间的关系。使用表保存对应关系的好处是以后扩展非常方便，只需要增加一个表记录。</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>【<strong> 优势</strong> 】增加删除节点非常方便，为后期升级维护带来很大便利</div>
<div>【<strong> 劣势</strong> 】需要增加表或者对某一个表进行操作，还是无法离开数据库，会产生瓶颈</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div><strong> 三、基于</strong> <strong> Hash</strong> <strong> 算法的分表处理</strong> </div>
<div>&nbsp;</div>
<div>我们知道Hash表就是通过某个特殊的Hash算法计算出的一个值，这个值必须是惟一的，并且能够使用这个计算出来的值查找到需要的值，这个叫做哈希表。</div>
<div>&nbsp;</div>
<div>我们在分表里的hash算法跟这个思想类似：通过一个原始目标的ID或者名称通过一定的hash算法计算出数据存储表的表名，然后访问相应的表。</div>
<div>&nbsp;</div>
<div>继续拿上面的贴吧来说，每个贴吧有版块名称和版块ID，那么这两项值是固定的，并且是惟一的，那么我们就可以考虑通过对这两项值中的一项进行一些运算得出一个目标表的名称。</div>
<div>&nbsp;</div>
<div>现在假如我们针对我们这个贴吧系统，假设系统最大允许1亿条数据，考虑每个表保存100万条记录，那么整个系统就不超过100个表就能够容纳。按照这个标准，我们假设在贴吧的版块ID上进行hash，获得一个key值，这个值就是我们的表名，然后访问相应的表。</div>
<div>&nbsp;</div>
<div>我们构造一个简单的hash算法：</div>
<div>&nbsp;</div>
<div>function get_hash($id){</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp; $str = bin2hex($id);</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp; $hash = substr($str, 0, 4);</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp; if (strlen($hash)&lt;4){</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $hash = str_pad($hash, 4, "0");</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp; }</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp; return $hash;</div>
<div>}</div>
<div>&nbsp;</div>
<div>算法大致就是传入一个版块ID值，然后函数返回一个4位的字符串，如果字符串长度不够，使用0进行补全。</div>
<div>&nbsp;</div>
<div>比如：get_hash(1)，输出的结果是&#8220;3100&#8221;，输入：get_hash(23819)，得到的结果是：3233，那么我们经过简单的跟表前缀组合，就能够访问这个表了。那么我们需要访问ID为1的内容时候哦，组合的表将是：topic_3100、reply_3100，那么就可以直接对目标表进行访问了。</div>
<div>&nbsp;</div>
<div>当然，使用hash算法后，有部分数据是可能在同一个表的，这一点跟hash表不同，hash表是尽量解决冲突，我们这里不需要，当然同样需要预测和分析表数据可能保存的表名。</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>如果需要存储的数据更多，同样的，可以对版块的名字进行hash操作，比如也是上面的二进制转换成十六进制，因为汉字比数字和字母要多很多，那么重复几率更小，但是可能组合成的表就更多了，相应就必须考虑一些其它的问题。</div>
<div>&nbsp;</div>
<div>归根结底，使用hash方式的话必须选择一个好的hash算法，才能生成更多的表，然数据查询的更迅速。</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>【<strong> 优点hash算法直接得出目标表名称，效率很高</strong> 】通过</div>
<div>【<strong> 劣势</strong> 】扩展性比较差，选择了一个hash算法，定义了多少数据量，以后只能在这个数据量上跑，不能超过过这个数据量，可扩展性稍差</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div><strong> 四、其它问题</strong> </div>
<div>&nbsp;</div>
<div><strong> 1. </strong> <strong> 搜索问题</strong> </div>
<div>现在我们已经进行分表了，那么就无法直接对表进行搜索，因为你无法对可能系统中已经存在的几十或者几百个表进行检索，所以搜索必须借助第三方的组件来进行，比如Lucene作为站内搜索引擎是个不错的选择。</div>
<div>&nbsp;</div>
<div><strong> 2. </strong> <strong> 表文件问题</strong> </div>
<div>我们知道MySQL的MyISAM引擎每个表都会生成三个文件，*.frm、*.MYD、*.MYI
三个文件，分表用来保存表结构、表数据和表索引。Linux下面每个目录下的文件数量最好不要超过1000个，不然检索数据将更慢，那么每个表都会生成三
个文件，相应的如果分表超过300个表，那么将检索非常慢，所以这时候就必须再进行分，比如在进行数据库的分离。</div>
<div>&nbsp;</div>
<div>使用基础表，我们可以新增加一个字段，用来保存这个表保存在什么数据。使用Hash的方式，我们必须截取hash值中第几位来作为数据库的名字。这样，完好的解决这个问题。</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div><strong> 五、总结</strong> </div>
<div>&nbsp;</div>
<div>在大负载应用当中，数据库一直是个很重要的瓶颈，必须要突破，本文讲解了两种分表的方式，希望对很多人能够有启发的作用。当然，本文代码和设想没有经过任何代码测试，所以无法保证设计的完全准确实用，具体还是需要读者在使用过程当中认真分析实施。</div>
<div>&nbsp;</div>
<br><img src ="http://www.cppblog.com/colys/aggbug/32397.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-09-18 09:51 <a href="http://www.cppblog.com/colys/articles/32397.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL语句导入导出大全[收集] </title><link>http://www.cppblog.com/colys/articles/22813.html</link><dc:creator>colys</dc:creator><author>colys</author><pubDate>Wed, 25 Apr 2007 10:07:00 GMT</pubDate><guid>http://www.cppblog.com/colys/articles/22813.html</guid><wfw:comment>http://www.cppblog.com/colys/comments/22813.html</wfw:comment><comments>http://www.cppblog.com/colys/articles/22813.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colys/comments/commentRss/22813.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colys/services/trackbacks/22813.html</trackback:ping><description><![CDATA[/******* 导出到excel<br>EXEC master..xp_cmdshell 'bcp SettleDB.dbo.shanghu out c:\temp1.xls -c -q -S"GNETDATA/GNETDATA" -U"sa" -P""'<br><br>/*********** 导入Excel<br>SELECT * <br>FROM OpenDataSource( 'Microsoft.Jet.OLEDB.4.0',<br>'Data Source="c:\test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0')...xactions<br><br>/*动态文件名<br>declare @fn varchar(20),@s varchar(1000)<br>set @fn = 'c:\test.xls'<br>set @s ='''Microsoft.Jet.OLEDB.4.0'',<br>''Data Source="'+@fn+'";User ID=Admin;Password=;Extended properties=Excel 5.0'''<br>set @s = 'SELECT * FROM OpenDataSource ('+@s+')...sheet1$'<br>exec(@s)<br>*/<br><br>SELECT cast(cast(科目编号 as numeric(10,2)) as nvarchar(255))+'　' 转换后的别名<br>FROM OpenDataSource( 'Microsoft.Jet.OLEDB.4.0',<br>'Data Source="c:\test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0')...xactions<br><br>/********************** EXCEL导到远程SQL<br>insert OPENDATASOURCE(<br>'SQLOLEDB',<br>'Data Source=远程ip;User ID=sa;Password=密码'<br>).库名.dbo.表名 (列名1,列名2)<br>SELECT 列名1,列名2<br>FROM OpenDataSource( 'Microsoft.Jet.OLEDB.4.0',<br>'Data Source="c:\test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0')...xactions<br><br><br>/** 导入文本文件<br>EXEC master..xp_cmdshell 'bcp dbname..tablename in c:\DT.txt -c -Sservername -Usa -Ppassword'<br><br>/** 导出文本文件<br>EXEC master..xp_cmdshell 'bcp dbname..tablename out c:\DT.txt -c -Sservername -Usa -Ppassword'<br>或<br>EXEC master..xp_cmdshell 'bcp "Select * from dbname..tablename" queryout c:\DT.txt -c -Sservername -Usa -Ppassword'<br><br>导出到TXT文本，用逗号分开<br>exec master..xp_cmdshell 'bcp "库名..表名" out "d:\tt.txt" -c -t ,-U sa -P password'<br><br><br>BULK INSERT 库名..表名<br>FROM 'c:\test.txt'<br>WITH (<br>FIELDTERMINATOR = ';',<br>ROWTERMINATOR = '\n'<br>)<br><br><br>--/* dBase IV文件<br>select * from <br>OPENROWSET('MICROSOFT.JET.OLEDB.4.0'<br>,'dBase IV;HDR=NO;IMEX=2;DATABASE=C:\','select * from [客户资料4.dbf]')<br>--*/<br><br>--/* dBase III文件<br>select * from <br>OPENROWSET('MICROSOFT.JET.OLEDB.4.0'<br>,'dBase III;HDR=NO;IMEX=2;DATABASE=C:\','select * from [客户资料3.dbf]')<br>--*/<br><br>--/* FoxPro 数据库<br>select * from openrowset('MSDASQL',<br>'Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:\',<br>'select * from [aa.DBF]')<br>--*/<br><br>/**************导入DBF文件****************/<br>select * from openrowset('MSDASQL',<br>'Driver=Microsoft Visual FoxPro Driver;<br>SourceDB=e:\VFP98\data;<br>SourceType=DBF',<br>'select * from customer where country != "USA" order by country')<br>go<br>/***************** 导出到DBF ***************/<br>如果要导出数据到已经生成结构(即现存的)FOXPRO表中,可以直接用下面的SQL语句<br><br>insert into openrowset('MSDASQL',<br>'Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:\',<br>'select * from [aa.DBF]')<br>select * from 表<br><br>说明:<br>SourceDB=c:\ 指定foxpro表所在的文件夹<br>aa.DBF 指定foxpro表的文件名.<br><br><br><br><br>/*************导出到Access********************/<br>insert into openrowset('Microsoft.Jet.OLEDB.4.0', <br>'x:\A.mdb';'admin';'',A表) select * from 数据库名..B表<br><br>/*************导入Access********************/<br>insert into B表 selet * from openrowset('Microsoft.Jet.OLEDB.4.0', <br>'x:\A.mdb';'admin';'',A表)<br><br>文件名为参数<br>declare @fname varchar(20)<br>set @fname = 'd:\test.mdb'<br>exec('SELECT a.* FROM opendatasource(''Microsoft.Jet.OLEDB.4.0'',<br>'''+@fname+''';''admin'';'''', topics) as a ')<br><br>SELECT * <br>FROM OpenDataSource( 'Microsoft.Jet.OLEDB.4.0',<br>'Data Source="f:\northwind.mdb";Jet OLEDB:Database Password=123;User ID=Admin;Password=;')...产品<br><br>********************* 导入 xml　文件<br><br>DECLARE @idoc int<br>DECLARE @doc varchar(1000)<br>--sample XML document<br>SET @doc ='<br><root /><br><customer city="Issaquah" name="Janine" cid="C1" /><br><order amount="3.5" date="1/20/1996" oid="O1" /><br><order amount="13.4" date="4/30/1997" oid="O2" />Customer was very satisfied<br></order /><br></customer /><br><customer city="Oelde" name="Ursula" cid="C2" /><br><order amount="100" date="7/14/1999" oid="O3" note="Wrap it blue <br/>
&#13;&#10;&#13;&#10;white red" /><br><urgency />Important</urgency /><br>Happy Customer.<br></order /><br><order amount="10000" date="1/20/1996" oid="O4" /><br></customer /><br></root /><br>'<br>-- Create an internal representation of the XML document.<br>EXEC sp_xml_preparedocument @idoc OUTPUT, @doc<br><br>-- Execute a SELECT statement using OPENXML rowset provider.<br>SELECT *<br>FROM OPENXML (@idoc, '/root/Customer/Order', 1)<br>WITH (oid char(5), <br>amount float, <br>comment ntext 'text()')<br>EXEC sp_xml_removedocument @idoc<br><br><br><br>???????<br><br>/**********************Excel导到Txt****************************************/<br>想用<br>select * into opendatasource(...) from opendatasource(...)<br>实现将一个Excel文件内容导入到一个文本文件<br><br>假设Excel中有两列，第一列为姓名，第二列为很行帐号(16位)<br>且银行帐号导出到文本文件后分两部分，前8位和后8位分开。<br><br><br>邹健：<br>如果要用你上面的语句插入的话,文本文件必须存在,而且有一行:姓名,银行账号1,银行账号2<br>然后就可以用下面的语句进行插入<br>注意文件名和目录根据你的实际情况进行修改.<br><br>insert into<br>opendatasource('MICROSOFT.JET.OLEDB.4.0'<br>,'Text;HDR=Yes;DATABASE=C:\'<br>)...[aa#txt]<br>--,aa#txt)<br>--*/<br>select 姓名,银行账号1=left(银行账号,8),银行账号2=right(银行账号,8) <br>from <br>opendatasource('MICROSOFT.JET.OLEDB.4.0'<br>,'Excel 5.0;HDR=YES;IMEX=2;DATABASE=c:\a.xls'<br>--,Sheet1$)<br>)...[Sheet1$]<br><br><br><br>如果你想直接插入并生成文本文件,就要用bcp<br><br>declare @sql varchar(8000),@tbname varchar(50)<br><br>--首先将excel表内容导入到一个全局临时表<br>select @tbname='[##temp'+cast(newid() as varchar(40))+']'<br>,@sql='select 姓名,银行账号1=left(银行账号,8),银行账号2=right(银行账号,8) <br>into '+@tbname+' from <br>opendatasource(''MICROSOFT.JET.OLEDB.4.0''<br>,''Excel 5.0;HDR=YES;IMEX=2;DATABASE=c:\a.xls''<br>)...[Sheet1$]'<br>exec(@sql)<br><br>--然后用bcp从全局临时表导出到文本文件<br>set @sql='bcp "'+@tbname+'" out "c:\aa.txt" /S"(local)" /P"" /c'<br>exec master..xp_cmdshell @sql<br><br>--删除临时表<br>exec('drop table '+@tbname)<br><br><br>/********************导整个数据库*********************************************/<br><br>用bcp实现的存储过程<br><br><br>/*<br>实现数据导入/导出的存储过程<br>根据不同的参数,可以实现导入/导出整个数据库/单个表<br>调用示例:<br>--导出调用示例<br>----导出单个表<br>exec file2table 'zj','','','xzkh_sa..地区资料','c:\zj.txt',1<br>----导出整个数据库<br>exec file2table 'zj','','','xzkh_sa','C:\docman',1<br><br>--导入调用示例<br>----导入单个表<br>exec file2table 'zj','','','xzkh_sa..地区资料','c:\zj.txt',0<br>----导入整个数据库<br>exec file2table 'zj','','','xzkh_sa','C:\docman',0<br><br>*/<br>if exists(select 1 from sysobjects where name='File2Table' and objectproperty(id,'IsProcedure')=1)<br>drop procedure File2Table<br>go<br>create procedure File2Table<br>@servername varchar(200) --服务器名<br>,@username varchar(200) --用户名,如果用NT验证方式,则为空''<br>,@password varchar(200) --密码<br>,@tbname varchar(500) --数据库.dbo.表名,如果不指定:.dbo.表名,则导出数据库的所有用户表<br>,@filename varchar(1000) --导入/导出路径/文件名,如果@tbname参数指明是导出整个数据库,则这个参数是文件存放路径,文件名自动用表名.txt<br>,@isout bit --1为导出,0为导入<br>as<br>declare @sql varchar(8000)<br><br>if @tbname like '%.%.%' --如果指定了表名,则直接导出单个表<br>begin<br>set @sql='bcp '+@tbname<br>+case when @isout=1 then ' out ' else ' in ' end<br>+' "'+@filename+'" /w'<br>+' /S '+@servername<br>+case when isnull(@username,'')='' then '' else ' /U '+@username end<br>+' /P '+isnull(@password,'')<br>exec master..xp_cmdshell @sql<br>end<br>else<br>begin --导出整个数据库,定义游标,取出所有的用户表<br>declare @m_tbname varchar(250)<br>if right(@filename,1)&lt;&gt;'\' set @filename=@filename+'\'<br><br>set @m_tbname='declare #tb cursor for select name from '+@tbname+'..sysobjects where xtype=''U'''<br>exec(@m_tbname)<br>open #tb<br>fetch next from #tb into @m_tbname<br>while @@fetch_status=0<br>begin<br>set @sql='bcp '+@tbname+'..'+@m_tbname<br>+case when @isout=1 then ' out ' else ' in ' end<br>+' "'+@filename+@m_tbname+'.txt " /w'<br>+' /S '+@servername<br>+case when isnull(@username,'')='' then '' else ' /U '+@username end<br>+' /P '+isnull(@password,'')<br>exec master..xp_cmdshell @sql<br>fetch next from #tb into @m_tbname<br>end<br>close #tb<br>deallocate #tb <br>end<br>go<br><br><br>/************* Oracle **************/<br>EXEC sp_addlinkedserver 'OracleSvr', <br>'Oracle 7.3', <br>'MSDAORA', <br>'ORCLDB'<br>GO<br><br>delete from openquery(mailser,'select * from yulin')<br><br>select * from openquery(mailser,'select * from yulin')<br><br>update openquery(mailser,'select * from yulin where id=15')set disorder=555,catago=888<br><br>insert into openquery(mailser,'select disorder,catago from yulin')values(333,777)<img src ="http://www.cppblog.com/colys/aggbug/22813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colys/" target="_blank">colys</a> 2007-04-25 18:07 <a href="http://www.cppblog.com/colys/articles/22813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>