最近看到一个SQL Server的小例子,发现完全可以作为SQL server的一道入门面试题。题目如下: 例:有一合同表Contract Id Name Total buget 1 合同名称 100 102,22 2 合同名称2 300 ,102,22, 3 合同名称3 200 103,23, 要求:用SQL语句更新表的buget字段,如果前后没有","要加上","(即一个英文逗号)。(10分) 创建表数据: View Code
1 |
<ol class="dp-sql"><li class="alt"><span><span>use Testdb2 </span></span></li><li><span>go </span></li><li class="alt"><span>IF </span><span class="op"><font color="#808080">NOT</font></span><span> OBJECT_ID(</span><span class="string"><font color="#0000ff">'[Contract]'</font></span><span>) </span><span class="keyword"><strong><font color="#006699">IS</font></strong></span><span> </span><span class="op"><font color="#808080">NULL</font></span><span> </span></li><li><span class="keyword"><strong><font color="#006699">DROP</font></strong></span><span> </span><span class="keyword"><strong><font color="#006699">TABLE</font></strong></span><span> [Contract] </span></li><li class="alt"><span>GO </span></li><li><span class="keyword"><strong><font color="#006699">Create</font></strong></span><span> </span><span class="keyword"><strong><font color="#006699">table</font></strong></span><span> [Contract] </span></li><li class="alt"><span>(ID </span><span class="keyword"><strong><font color="#006699">int</font></strong></span><span> </span><span class="keyword"><strong><font color="#006699">primary</font></strong></span><span> </span><span class="keyword"><strong><font color="#006699">key</font></strong></span><span> identity(1,1) </span></li><li><span>,[</span><span class="keyword"><strong><font color="#006699">Name</font></strong></span><span>] nvarchar(50) </span><span class="op"><font color="#808080">null</font></span><span> </span></li><li class="alt"><span>,Total </span><span class="keyword"><strong><font color="#006699">float</font></strong></span><span> </span><span class="op"><font color="#808080">null</font></span><span> </span></li><li><span>,buget Nvarchar(500) </span><span class="op"><font color="#808080">null</font></span><span> ) </span></li><li class="alt"><span>go </span></li><li><span class="keyword"><strong><font color="#006699">insert</font></strong></span><span> </span><span class="keyword"><strong><font color="#006699">into</font></strong></span><span> [Contract] </span></li><li class="alt"><span class="keyword"><strong><font color="#006699">select</font></strong></span><span> </span><span class="string"><font color="#0000ff">'合同名称'</font></span><span>, 100,</span><span class="string"><font color="#0000ff">'102,22'</font></span><span> </span></li><li><span class="keyword"><strong><font color="#006699">union</font></strong></span><span> </span><span class="op"><font color="#808080">all</font></span><span> </span></li><li class="alt"><span class="keyword"><strong><font color="#006699">select</font></strong></span><span> </span><span class="string"><font color="#0000ff">'合同名称2'</font></span><span>, 300,</span><span class="string"><font color="#0000ff">',102,22,'</font></span><span> </span></li><li><span class="keyword"><strong><font color="#006699">union</font></strong></span><span> </span><span class="op"><font color="#808080">all</font></span><span> </span></li><li class="alt"><span class="keyword"><strong><font color="#006699">select</font></strong></span><span> </span><span class="string"><font color="#0000ff">'合同名称3'</font></span><span>, 300,</span><span class="string"><font color="#0000ff">'101,23,'</font></span><span> </span></li></ol> |
分析:这道题乍看很简单,由于肯定用到Replace,所以很自然的结合left,right,从而得到以下语句 方法一:
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword"><strong><font color="#006699">update</font></strong></span><span> [Contract] </span><span class="keyword"><strong><font color="#006699">set</font></strong></span><span> buget=</span><span class="string"><font color="#0000ff">','</font></span><span>+buget </span><span class="keyword"><strong><font color="#006699">where</font></strong></span><span> </span><span class="func"><font color="#ff1493">left</font></span><span>(buget,1)=</span><span class="string"><font color="#0000ff">','</font></span><span> </span></span></li><li><span class="keyword"><strong><font color="#006699">update</font></strong></span><span> [Contract] </span><span class="keyword"><strong><font color="#006699">set</font></strong></span><span> buget=buget+</span><span class="string"><font color="#0000ff">','</font></span><span> </span><span class="keyword"><strong><font color="#006699">where</font></strong></span><span> </span><span class="func"><font color="#ff1493">right</font></span><span>(buget,1)=</span><span class="string"><font color="#0000ff">','</font></span><span> </span></li></ol> |
如果能写成一个 SQL语句,可以加1分。
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword"><strong><font color="#006699">update</font></strong></span><span> [Contract] </span></span></li><li><span class="keyword"><strong><font color="#006699">set</font></strong></span><span> buget=(</span><span class="func"><font color="#ff1493">case</font></span><span> </span><span class="keyword"><strong><font color="#006699">when</font></strong></span><span> (</span><span class="func"><font color="#ff1493">left</font></span><span>(buget,1)!=</span><span class="string"><font color="#0000ff">','</font></span><span> </span><span class="op"><font color="#808080">and</font></span><span> </span><span class="func"><font color="#ff1493">right</font></span><span> (buget,1)!=</span><span class="string"><font color="#0000ff">','</font></span><span>) </span><span class="keyword"><strong><font color="#006699">then</font></strong></span><span> </span><span class="string"><font color="#0000ff">','</font></span><span>+buget+</span><span class="string"><font color="#0000ff">','</font></span><span> </span></li><li class="alt"><span class="keyword"><strong><font color="#006699">when</font></strong></span><span> </span><span class="func"><font color="#ff1493">left</font></span><span>(buget,1)!=</span><span class="string"><font color="#0000ff">','</font></span><span> </span><span class="keyword"><strong><font color="#006699">then</font></strong></span><span> </span><span class="string"><font color="#0000ff">','</font></span><span>+buget </span></li><li><span class="keyword"><strong><font color="#006699">when</font></strong></span><span> </span><span class="func"><font color="#ff1493">right</font></span><span>(buget,1)!=</span><span class="string"><font color="#0000ff">','</font></span><span> </span><span class="keyword"><strong><font color="#006699">then</font></strong></span><span> buget+</span><span class="string"><font color="#0000ff">','</font></span><span> </span></li><li class="alt"><span class="keyword"><strong><font color="#006699">else</font></strong></span><span> buget </span></li><li><span class="keyword"><strong><font color="#006699">end</font></strong></span><span>) </span></li></ol> |
如果能从字符串的开关和结尾这个思路出发,结合Reverse,可以提到如下方法: 方法二:
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword"><strong><font color="#006699">update</font></strong></span><span> [Contract] </span><span class="keyword"><strong><font color="#006699">set</font></strong></span><span> buget=</span><span class="string"><font color="#0000ff">','</font></span><span>+buget </span><span class="keyword"><strong><font color="#006699">where</font></strong></span><span> charindex(</span><span class="string"><font color="#0000ff">','</font></span><span>,buget)<>1 </span></span></li><li><span class="keyword"><strong><font color="#006699">update</font></strong></span><span> [Contract] </span><span class="keyword"><strong><font color="#006699">set</font></strong></span><span> buget=buget+</span><span class="string"><font color="#0000ff">','</font></span><span> </span><span class="keyword"><strong><font color="#006699">where</font></strong></span><span> charindex(</span><span class="string"><font color="#0000ff">','</font></span><span>,reverse(buget))<>1 </span></li></ol> |
该方法,主要涉及charindex函数和reverse函数。 说实话,我当时就这两种思路,这也是SQL中常见的基本用法。但出人意料的第三种方法出现了。 方法三:
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword"><strong><font color="#006699">UPDATE</font></strong></span><span> [contract] </span><span class="keyword"><strong><font color="#006699">SET</font></strong></span><span> Buget = </span><span class="string"><font color="#0000ff">','</font></span><span>+Buget+</span><span class="string"><font color="#0000ff">','</font></span><span> </span></span></li><li><span class="keyword"><strong><font color="#006699">UPDATE</font></strong></span><span> [contract] </span><span class="keyword"><strong><font color="#006699">SET</font></strong></span><span> Buget = </span><span class="func"><font color="#ff1493">REPLACE</font></span><span>(Buget,</span><span class="string"><font color="#0000ff">',,'</font></span><span>,</span><span class="string"><font color="#0000ff">','</font></span><span>) </span></li></ol> |
解析:该方法最主要的亮点不在于语法的精妙,而在于其思路的异于常规。先给两边补上逗号,再替换双逗号为单逗号。这在实际编程中确实难能可贵。换句话说,如果没有事先思考过的话,这反映了解题者反应敏捷,思路开放。因此,至少可以再加3分。 当然,此语句其实还是有bug,比如如果原bug字段中间有两个逗号,那么在Replace时就会更新掉不应该更新的内容。不过,稍加修正,限定replace的范围即可, 受此思路启发,可以引申得到以下类似方法: 方法四:
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword"><strong><font color="#006699">UPDATE</font></strong></span><span> [contract] </span><span class="keyword"><strong><font color="#006699">SET</font></strong></span><span> Buget = </span><span class="func"><font color="#ff1493">substring</font></span><span>(BuGet,2,len(BuGet)-1) wherecharindex(</span><span class="string"><font color="#0000ff">','</font></span><span>,buget)=1 </span></span></li><li><span class="keyword"><strong><font color="#006699">UPDATE</font></strong></span><span> [contract] </span><span class="keyword"><strong><font color="#006699">SET</font></strong></span><span> Buget = </span><span class="func"><font color="#ff1493">substring</font></span><span>(BuGet,1,len(BuGet)-1) wherecharindex(</span><span class="string"><font color="#0000ff">','</font></span><span>,reverse(buget))=1 </span></li><li class="alt"><span class="keyword"><strong><font color="#006699">UPDATE</font></strong></span><span> [contract] </span><span class="keyword"><strong><font color="#006699">SET</font></strong></span><span> BuGet = </span><span class="string"><font color="#0000ff">','</font></span><span>+BuGet+</span><span class="string"><font color="#0000ff">','</font></span><span> </span></li></ol> |
该方法是先去掉两边的逗号,再给每条记录加上逗号,比起方法三来,稍显繁琐,这也反衬了方法三的巧妙。 当然,也可以结合前面的思路稍作修正,这里就不再赘述,请读者自己思考。 感悟:释迦牟尼说过“人生需要经过六项修炼:布施、持戒、忍辱、精进、禅定、智慧。”,SQL编程,或C#、Java,甚至Javascrip的某个领域也是如此。技术是死的,思路是鲜活的,有时候,思路能轻易地突破技术很难实现的死角。到了一定程度时,会发现潜意识里已经被惯性思维塞满,而无法接受新鲜思维方式或思路,如果一段时间内持续如此,那么,我们应该警醒,把自己的头脑放空,把自己置于一个初学者的地位,重新开始“精进”的修炼! 原文链接:http://www.cnblogs.com/downmoon/archive/2011/03/02/1968615.html
View Details1、 首先要搞明白什么叫执行计划? 执行计划是数据库根据SQL语句和相关表的统计信息作出的一个查询方案,这个方案是由查询优化器自动分析产生的,比如一条SQL语句如果用来从一个10万条记录的表中查1条记录,那查询优化器会选择“索引查找”方式,如果该表进行了归档,当前只剩下5000条记录了,那查询优化器就会改变方案,采用“全表扫描”方式。 可见,执行计划并不是固定的,它是“个性化的”。产生一个正确的“执行计划”有两点很重要: (1) SQL语句是否清晰地告诉查询优化器它想干什么? (2) 查询优化器得到的数据库统计信息是否是最新的、正确的? 2、 统一SQL语句的写法 对于以下两句SQL语句,程序员认为是相同的,数据库查询优化器认为是不同的。
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword"><strong><font color="#006699">select</font></strong></span><span> * </span><span class="keyword"><strong><font color="#006699">from</font></strong></span><span> dual </span></span></li><li><span class="keyword"><strong><font color="#006699">select</font></strong></span><span> * </span><span class="keyword"><strong><font color="#006699">From</font></strong></span><span> dual </span></li></ol> |
其实就是大小写不同,查询分析器就认为是两句不同的SQL语句,必须进行两次解析。生成2个执行计划。所以作为程序员,应该保证相同的查询语句在任何地方都一致,多一个空格都不行! 3、 不要把SQL语句写得太复杂 我经常看到,从数据库中捕捉到的一条SQL语句打印出来有2张A4纸这么长。一般来说这么复杂的语句通常都是有问题的。我拿着这2页长的SQL语句去请教原作者,结果他说时间太长,他一时也看不懂了。可想而知,连原作者都有可能看糊涂的SQL语句,数据库也一样会看糊涂。 一般,将一个Select语句的结果作为子集,然后从该子集中再进行查询,这种一层嵌套语句还是比较常见的,但是根据经验,超过3层嵌套,查询优化器就很容易给出错误的执行计划。因为它被绕晕了。像这种类似人工智能的东西,终究比人的分辨力要差些,如果人都看晕了,我可以保证数据库也会晕的。 另外,执行计划是可以被重用的,越简单的SQL语句被重用的可能性越高。而复杂的SQL语句只要有一个字符发生变化就必须重新解析,然后再把这一大堆垃圾塞在内存里。可想而知,数据库的效率会何等低下。 4、 使用“临时表”暂存中间结果 简化SQL语句的重要方法就是采用临时表暂存中间结果,但是,临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查询就在tempdb中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。 5、 OLTP系统SQL语句必须采用绑定变量
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword"><strong><font color="#006699">select</font></strong></span><span> * </span><span class="keyword"><strong><font color="#006699">from</font></strong></span><span> orderheader </span><span class="keyword"><strong><font color="#006699">where</font></strong></span><span> changetime > ‘2010-10-20 00:00:01’ </span></span></li><li><span class="keyword"><strong><font color="#006699">select</font></strong></span><span> * </span><span class="keyword"><strong><font color="#006699">from</font></strong></span><span> orderheader </span><span class="keyword"><strong><font color="#006699">where</font></strong></span><span> changetime > ‘2010-09-22 00:00:01’ </span></li></ol> |
以上两句语句,查询优化器认为是不同的SQL语句,需要解析两次。如果采用绑定变量
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword"><strong><font color="#006699">select</font></strong></span><span> * </span><span class="keyword"><strong><font color="#006699">from</font></strong></span><span> orderheader </span><span class="keyword"><strong><font color="#006699">where</font></strong></span><span> changetime > @chgtime </span></span></li></ol> |
@chgtime变量可以传入任何值,这样大量的类似查询可以重用该执行计划了,这可以大大降低数据库解析SQL语句的负担。一次解析,多次重用,是提高数据库效率的原则。 6、 绑定变量窥测 事物都存在两面性,绑定变量对大多数OLTP处理是适用的,但是也有例外。比如在where条件中的字段是“倾斜字段”的时候。 “倾斜字段”指该列中的绝大多数的值都是相同的,比如一张人口调查表,其中“民族”这列,90%以上都是汉族。那么如果一个SQL语句要查询30岁的汉族人口有多少,那“民族”这列必然要被放在where条件中。这个时候如果采用绑定变量@nation会存在很大问题。 试想如果@nation传入的第一个值是“汉族”,那整个执行计划必然会选择表扫描。然后,第二个值传入的是“布依族”,按理说“布依族”占的比例可能只有万分之一,应该采用索引查找。但是,由于重用了第一次解析的“汉族”的那个执行计划,那么第二次也将采用表扫描方式。这个问题就是著名的“绑定变量窥测”,建议对于“倾斜字段”不要采用绑定变量。 7、 只在必要的情况下才使用begin tran SQL Server中一句SQL语句默认就是一个事务,在该语句执行完成后也是默认commit的。其实,这就是begin tran的一个最小化的形式,好比在每句语句开头隐含了一个begin tran,结束时隐含了一个commit。 有些情况下,我们需要显式声明begin tran,比如做“插、删、改”操作需要同时修改几个表,要求要么几个表都修改成功,要么都不成功。begin tran 可以起到这样的作用,它可以把若干SQL语句套在一起执行,最后再一起commit。好处是保证了数据的一致性,但任何事情都不是完美无缺的。Begin tran付出的代价是在提交之前,所有SQL语句锁住的资源都不能释放,直到commit掉。 可见,如果Begin tran套住的SQL语句太多,那数据库的性能就糟糕了。在该大事务提交之前,必然会阻塞别的语句,造成block很多。 Begin tran使用的原则是,在保证数据一致性的前提下,begin tran 套住的SQL语句越少越好!有些情况下可以采用触发器同步数据,不一定要用begin tran。 8、 一些SQL查询语句应加上nolock 在SQL语句中加nolock是提高SQL Server并发性能的重要手段,在oracle中并不需要这样做,因为oracle的结构更为合理,有undo表空间保存“数据前影”,该数据如果在修改中还未commit,那么你读到的是它修改之前的副本,该副本放在undo表空间中。这样,oracle的读、写可以做到互不影响,这也是oracle广受称赞的地方。SQL Server 的读、写是会相互阻塞的,为了提高并发性能,对于一些查询,可以加上nolock,这样读的时候可以允许写,但缺点是可能读到未提交的脏数据。使用nolock有3条原则。 (1) 查询的结果用于“插、删、改”的不能加nolock ! (2) 查询的表属于频繁发生页分裂的,慎用nolock ! (3) 使用临时表一样可以保存“数据前影”,起到类似oracle的undo表空间的功能, 能采用临时表提高并发性能的,不要用nolock 。 9、 聚集索引没有建在表的顺序字段上,该表容易发生页分裂 比如订单表,有订单编号orderid,也有客户编号contactid,那么聚集索引应该加在哪个字段上呢?对于该表,订单编号是顺序添加的,如果在orderid上加聚集索引,新增的行都是添加在末尾,这样不容易经常产生页分裂。然而,由于大多数查询都是根据客户编号来查的,因此,将聚集索引加在contactid上才有意义。而contactid对于订单表而言,并非顺序字段。 比如“张三”的“contactid”是001,那么“张三”的订单信息必须都放在这张表的第一个数据页上,如果今天“张三”新下了一个订单,那该订单信息不能放在表的最后一页,而是第一页!如果第一页放满了呢?很抱歉,该表所有数据都要往后移动为这条记录腾地方。 SQL Server的索引和Oracle的索引是不同的,SQL Server的聚集索引实际上是对表按照聚集索引字段的顺序进行了排序,相当于oracle的索引组织表。SQL Server的聚集索引就是表本身的一种组织形式,所以它的效率是非常高的。也正因为此,插入一条记录,它的位置不是随便放的,而是要按照顺序放在该放的数据页,如果那个数据页没有空间了,就引起了页分裂。所以很显然,聚集索引没有建在表的顺序字段上,该表容易发生页分裂。 曾经碰到过一个情况,一位哥们的某张表重建索引后,插入的效率大幅下降了。估计情况大概是这样的。该表的聚集索引可能没有建在表的顺序字段上,该表经常被归档,所以该表的数据是以一种稀疏状态存在的。比如张三下过20张订单,而最近3个月的订单只有5张,归档策略是保留3个月数据,那么张三过去的15张订单已经被归档,留下15个空位,可以在insert发生时重新被利用。在这种情况下由于有空位可以利用,就不会发生页分裂。但是查询性能会比较低,因为查询时必须扫描那些没有数据的空位。 重建聚集索引后情况改变了,因为重建聚集索引就是把表中的数据重新排列一遍,原来的空位没有了,而页的填充率又很高,插入数据经常要发生页分裂,所以性能大幅下降。 对于聚集索引没有建在顺序字段上的表,是否要给与比较低的页填充率?是否要避免重建聚集索引?是一个值得考虑的问题! 10、加nolock后查询经常发生页分裂的表,容易产生跳读或重复读 加nolock后可以在“插、删、改”的同时进行查询,但是由于同时发生“插、删、改”,在某些情况下,一旦该数据页满了,那么页分裂不可避免,而此时nolock的查询正在发生,比如在第100页已经读过的记录,可能会因为页分裂而分到第101页,这有可能使得nolock查询在读101页时重复读到该条数据,产生“重复读”。同理,如果在100页上的数据还没被读到就分到99页去了,那nolock查询有可能会漏过该记录,产生“跳读”。 上面提到的哥们,在加了nolock后一些操作出现报错,估计有可能因为nolock查询产生了重复读,2条相同的记录去插入别的表,当然会发生主键冲突。 11、使用like进行模糊查询时应注意 有的时候会需要进行一些模糊查询比如
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword"><strong><font color="#006699">select</font></strong></span><span> * </span><span class="keyword"><strong><font color="#006699">from</font></strong></span><span> contact </span><span class="keyword"><strong><font color="#006699">where</font></strong></span><span> username </span><span class="op"><font color="#808080">like</font></span><span> ‘%yue%’ </span></span></li></ol> |
关键词%yue%,由于yue前面用到了“%”,因此该查询必然走全表扫描,除非必要,否则不要在关键词前加%, 12、数据类型的隐式转换对查询效率的影响 sql server2000的数据库,我们的程序在提交sql语句的时候,没有使用强类型提交这个字段的值,由sql […]
View DetailsCase具有两种格式。简单Case函数和Case搜索函数。 —简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END --Case搜索函数 CASE WHEN sex = '1' THEN '男' WHEN sex = '2' THEN '女' ELSE '其他' END 这两种方式,可以实现相同的功能。简单Case函数的写法相对比较简洁,但是和Case搜索函数相比,功能方面会有些限制,比如写判断式。 还有一个需要注意的问题,Case函数只返回第一个符合条件的值,剩下的Case部分将会被自动忽略。 —比如说,下面这段SQL,你永远无法得到“第二类”这个结果 CASE WHEN col_1 IN ( 'a', 'b') THEN '第一类' WHEN col_1 IN ('a') THEN '第二类' ELSE'其他' END 下面我们来看一下,使用Case函数都能做些什么事情。 一,已知数据按照另外一种方式进行分组,分析。 有如下数据:(为了看得更清楚,我并没有使用国家代码,而是直接用国家名作为Primary Key) 国家(country)人口(population) 中国600 美国100 加拿大100 英国200 法国300 日本250 德国200 墨西哥50 印度250 根据这个国家人口数据,统计亚洲和北美洲的人口数量。应该得到下面这个结果。 洲人口 亚洲1100 北美洲250 其他700 想要解决这个问题,你会怎么做?生成一个带有洲Code的View,是一个解决方法,但是这样很难动态的改变统计的方式。 如果使用Case函数,SQL代码如下: SELECT SUM(population), CASE […]
View Detailsusing System;using System.Data;using System.Xml; //***************************************// 作者: yangtang_newton//其实用DataSet操作XML,归根到底就是对DataSet里的表格,行,列等进行操作,//然后用DataSet里的东西重新写到XML中,从而实现编辑XML的目的。如果再配合上.xsd文件的话,那效果更佳。//xsd生成方法:xsd file.xml [/outputdir:directory] [/parameters:file.xml] //*************************************** namespace USTC{/// <summary>/// OperateXmlByDataSet 的摘要说明。/// </summary>public class XmlDataSet{private string strXmlPath;//这个是相对路径public XmlDataSet(string strXmlPath){ // // TODO: 在此处添加构造函数逻辑 // this.strXmlPath=strXmlPath;} #region GetDataSetByXml/// <summary>/// 读取xml直接返回DataSet/// </summary>/// <param name="strXmlPath">xml文件相对路径</param>/// <returns></returns>public DataSet GetDataSetByXml(){ try { DataSet ds = new DataSet(); ds.ReadXml(GetXmlFullPath(strXmlPath)); if(ds.Tables.Count > 0) { return ds; } return null; } catch(Exception) { return null; }}#endregion /* * 以下代码读取到一个没有排序和筛选的DataSet。 USTC.XmlDataSet XML=new XmlDataSet(@"XML/PortalCfg.xml");DataGrid1.DataSource = XML.GetDataSetByXml();DataGrid1.DataBind();//以下代码读到的数据是经过筛选和排序的:DataGrid1.DataSource =XML.GetDataViewByXml("name = 'Asp.net’", //条件:name列值为Asp.net"peopleNum desc"); //按peopleNum列降序排列DataGrid1.DataBind(); */ #region GetDataViewByXml/// <summary>/// 读取Xml返回一个经排序或筛选后的DataView/// </summary>/// <param name="strXmlPath"></param>/// <param name="strWhere">筛选条件,如:"name = […]
View DetailsDataSet和XML文件互操作的例子 //读取XML文件到DataSetDataSet ds = new DataSet();MyXmlPath = "C:\\Message.xml";FileStream fs = new FileStream(MyXmlPath, FileMode.Open);ds.ReadXml(fs, XmlReadMode.ReadSchema);fs.Close();//筛选行存入DataSetDataRow[] FoundRows;string Expression = "AREA IN ('" + Area + "',")";string SortOrder = "DAY DESC";FoundRows = ds.Tables[0].Select(Expression, SortOrder);DataTable Mydt = new DataTable();Mydt.Columns.Add("FKEY");Mydt.Columns.Add("IIIII");Mydt.Columns.Add("NAME");Mydt.Columns.Add("AREA");Mydt.Columns.Add("X");Mydt.Columns.Add("Y");Mydt.Columns.Add("BKIND");Mydt.Columns.Add("SKIND");Mydt.Columns.Add("DAY");Mydt.Columns.Add("ETIME");Mydt.Columns.Add("TYPE");Mydt.Columns.Add("MAIN");Mydt.Columns.Add("TTIME");foreach (DataRow dr in FoundRows){Mydt.Rows.Add(dr.ItemArray);}DataSet Myds = new DataSet();Myds.Tables.Add(Mydt);//保存到XML文件Myds.WriteXml(MyXmlPath, XmlWriteMode.WriteSchema); //ListView的一个例子XmlDocument doc = new XmlDocument();XmlDeclaration Declaration = doc.CreateXmlDeclaration("1.0","GB2312","");doc.AppendChild(Declaration);XmlElement xe = doc.CreateElement("Infos");doc.AppendChild(xe);for(int i = 0;i < listview.Items.Count;i++){XmlNode parent = doc.CreateElement("Info" + i.ToString());ListViewItem temp = listview.Items[i];for(int j = 0;j < temp.SubItems.Count;j++){string s = temp.SubItems[j].Text;XmlNode node = doc.CreateElement(s);node.InnerText = s;parent.AppendChild(node);}doc.AppendChild(parent);}doc.Save(FilePath);
View Details以前在使用VB来实现多线程的时候,发现有一定的难度。虽然也有这样那样的方法,但都不尽人意,但在C#中,要编写多线程应用程序却相当的简单。这篇文章将作简要的介绍,以起到抛砖引玉的作用! .NET将关于多线程的功能定义在System.Threading名字空间中。因此,要使用多线程,必须先声明引用此名字空间(using System.Threading;)。 即使你没有编写多线程应用程序的经验,也可能听说过“启动线程”“杀死线程”这些词,其实除了这两个外,涉及多线程方面的还有诸如“暂停线程”“优先级”“挂起线程”“恢复线程”等等。下面将一个一个的解释。 1.启动线程 顾名思义,“启动线程”就是新建并启动一个线程的意思,如下代码可实现: Thread thread1 = new Thread(new ThreadStart( Count)); 其中的 Count 是将要被新线程执行的函数。 2.杀死线程 “杀死线程”就是将一线程斩草除根,为了不白费力气,在杀死一个线程前最好先判断它是否还活着(通过 IsAlive 属性),然后就可以调用 Abort 方法来杀死此线程。 3.暂停线程 它的意思就是让一个正在运行的线程休眠一段时间。如 thread.Sleep(1000); 就是让线程休眠1秒钟。 4.优先级 这个用不着解释了。Thread类中有一个ThreadPriority属性,它用来设置优先级,但不能保证操作系统会接受该优先级。一个线程的优先级可分为5种:Normal, AboveNormal, BelowNormal, Highest, Lowest。具体实现例子如下: thread.Priority = ThreadPriority.Highest; 5.挂起线程 Thread类的Suspend方法用来挂起线程,直到调用Resume,此线程才可以继续执行。如果线程已经挂起,那就不会起作用。 if (thread.ThreadState = ThreadState.Running) { thread.Suspend(); } 6.恢复线程 用来恢复已经挂起的线程,以让它继续执行,如果线程没挂起,也不会起作用。 if (thread.ThreadState = ThreadState.Suspended) { thread.Resume(); } 下面将列出一个例子,以说明简单的线程处理功能。此例子来自于帮助文档。 using System; using System.Threading; // Simple threading scenario: Start a static method running // on a second thread. public class ThreadExample { // The ThreadProc method is called when the thread starts. // It […]
View Details我现在正在使用vs2010英文版,平常也很少看那些有的没的文字,而且在写程序的时候很”明智”的异常捕获并且写进日志里去,所以没有出现那个可爱的调试状态下出现异常的那个小框框. 我在上网查了一会儿,有人说直接设置控件的CheckForIllegalCrossThreadCalls属性为false,但是因为可能的不安全因素所以还是不用的好.当然还有写一个委托来同步调用.但是我觉得它有点麻烦,就放弃用委托同步了. 后来我搞了好多种写法,都摆脱不了这个怨念,最终也摆脱了异常捕获并抛出了这个小框框. 框框上明确的说道:”线程间操作无效: 从不是创建控件 [控件名称] 的线程访问它。”但是在框框的Suggestion列表中显示出了一条项目,大意是:”如何:对 Windows 窗体控件进行线程安全调用.”,我点开它,并且跳进了MSDN. 原来在MSDN上就有教咱如果夸线程操作控件啊.亏我还Google半天呢. MSDN上的办法就是使用委托来同步调用控件的.具体方法我也就不卖关子了.因为MSDN上的代码比较繁多,所以我稍微改进了一下. //首先声明一个委托. delegate void SetValueDelegate(int val); //模仿程序中的跨线程调用 public void Progress() { Thread t = new Thread(() => { //跨线程由此开始 SetValue(100); }); t.Start(); } //关键部分在这里 public void SetValue(int val) { //InvokeRequired属性当非创建本控件线程操作的时候 //它返回true,此时使用窗体(该控件的创建者)的Invoke方法创建同步调用. //妙哉,妙哉! if (ProgressBar1.InvokeRequired) { var svd = new SetValueDelegate(SetValue); this.Invoke(svd, val); } else { ProgressBar1.Value = val; } } 好了,就是这样,非讨论文章就越精炼越好.希望能帮到你. 最后附上MSDN的地址:这里
View Details在ecshop2.7.0开始,底部版权Powered by ecshop如果删除了之后,就会发现Powered by ecshop到处乱跑,如何彻底删除Powered by ecshop版权呢。首先,需要打开js/common.js删除以下js函数. onload = function(){ var link_arr = document.getElementsByTagName(String.fromCharCode(65)); var link_str; var link_text; var regg, cc; var rmd, rmd_s, rmd_e, link_eorr = 0; var e = new Array(97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 ); try { for(var i = 0; i < link_arr.length; i++) { link_str = link_arr[i].href; if (link_str.indexOf(String.fromCharCode(e[22], 119, 119, 46, e[4], 99, e[18], e[7], e[14], e[15], […]
View Details
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Collections; namespace DBUtility { /// <summary> /// 数据库操作类 /// </summary> public abstract class SqlHelper { // 数据库连接 public static readonly string ConnectionStringLocalTransaction = ConfigurationManager.ConnectionStrings["SQLConnString1"].ConnectionString; // 用哈希表缓存参数 private static readonly Hashtable ParmCache = Hashtable.Synchronized(new Hashtable()); /// <summary> /// 执行一个SQL语句(连接字符串) /// </summary> /// <param name="connectionString">连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回命令影响的行数</returns> public static int ExecuteNonQuery(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); using (var conn = new SqlConnection(connectionString)) { PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters); var val = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); return val; } } /// <summary> /// 执行一个SQL语句(连接对象) /// </summary> /// <param name="connection">一个已经存在的连接对象</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回命令影响的行数</returns> public static int ExecuteNonQuery(SqlConnection connection, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters); var val = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); return val; } /// <summary> /// 执行一个SQL语句(事务) /// </summary> /// <param name="trans">一个已经存在的事务</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>an int representing the number of rows affected by the command</returns> public static int ExecuteNonQuery(SqlTransaction trans, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, commandParameters); var val = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); return val; } /// <summary> /// 执行一个返回DataReader的SQL语句 /// </summary> /// <param name="connectionString">一个有效的连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回一个DataReader对象</returns> public static SqlDataReader ExecuteReader(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); var conn = new SqlConnection(connectionString); // we use a try/catch here because if the method throws an exception we want to // close the connection throw code, because no datareader will exist, hence the // commandBehaviour.CloseConnection will not work try { PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters); var rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection); cmd.Parameters.Clear(); return rdr; } catch { conn.Close(); throw; } } /// <summary> /// 返回DataSet /// </summary> /// <param name="connectionString"></param> /// <param name="cmdText"></param> /// <param name="cmdParms"></param> /// <returns></returns> public static DataSet ExecuteDataSet(string connectionString, string cmdText, params SqlParameter[] cmdParms) { using (var connection = new SqlConnection(connectionString)) { var cmd = new SqlCommand(); PrepareCommand(cmd,connection,null,CommandType.Text,cmdText,cmdParms); using (var da = new SqlDataAdapter(cmd)) { var ds = new DataSet(); try { da.Fill(ds, "ds"); cmd.Parameters.Clear(); } catch (SqlException ex) { throw new Exception(ex.Message); } return ds; } } } /// <summary> /// 根据SQL语句返回DataSet /// </summary> /// <param name="cmdText"></param> /// <param name="cmdParms"></param> /// <returns></returns> public static DataSet Query(string cmdText, params SqlParameter[] cmdParms) { using (var connection = new SqlConnection(ConnectionStringLocalTransaction)) { var cmd = new SqlCommand(); PrepareCommand(cmd, connection, null, CommandType.Text, cmdText, cmdParms); using (var da = new SqlDataAdapter(cmd)) { var ds = new DataSet(); try { da.Fill(ds, "ds"); cmd.Parameters.Clear(); } catch (SqlException ex) { throw new Exception(ex.Message); } return ds; } } } /// <summary> /// 执行返回一个对象的SQL语句(连接字符串) /// </summary> /// <param name="connectionString">连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回一个object对象,对象中只包含一列。</returns> public static object ExecuteScalar(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); using (var connection = new SqlConnection(connectionString)) { PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters); var val = cmd.ExecuteScalar(); cmd.Parameters.Clear(); return val; } } /// <summary> /// 执行返回一个对象的SQL语句(连接对象) /// </summary> /// <param name="connection">一个已经存在的连接对象</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回一个object对象,对象中只包含一列。</returns> public static object ExecuteScalar(SqlConnection connection, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters); var val = cmd.ExecuteScalar(); cmd.Parameters.Clear(); return val; } /// <summary> /// 添加参数集到缓存 /// </summary> /// <param name="cacheKey">缓存的名称</param> /// <param name="commandParameters">要缓存的参数集</param> public static void CacheParameters(string cacheKey, params SqlParameter[] commandParameters) { ParmCache[cacheKey] = commandParameters; } /// <summary> /// 从缓存中获取参数集 /// </summary> /// <param name="cacheKey">key used to lookup parameters</param> /// <returns>Cached SqlParamters array</returns> public static SqlParameter[] GetCachedParameters(string cacheKey) { var cachedParms = (SqlParameter[])ParmCache[cacheKey]; if (cachedParms == null) return null; var clonedParms = new SqlParameter[cachedParms.Length]; var j = cachedParms.Length; for (var i = 0; i < j; i++) clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone(); return clonedParms; } /// <summary> /// 为执行准备命令对象 /// </summary> /// <param name="cmd">command 对象</param> /// <param name="conn">连接对象</param> /// <param name="trans">事务对象</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="cmdParms">参数集</param> private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans, CommandType cmdType, string cmdText, IEnumerable<SqlParameter> cmdParms) { if (conn.State != ConnectionState.Open) conn.Open(); cmd.Connection = conn; cmd.CommandText = cmdText; if (trans != null) cmd.Transaction = trans; cmd.CommandType = cmdType; if (cmdParms == null) return; foreach (var parm in cmdParms) cmd.Parameters.Add(parm); } /// <summary> /// 是否存在记录 /// </summary> /// <param name="strSql"></param> /// <returns></returns> public static bool Exists(string strSql) { var obj = ExecuteScalar(ConnectionStringLocalTransaction, CommandType.Text, strSql); int cmdresult; if ((Equals(obj, null)) || (Equals(obj, DBNull.Value))) { cmdresult = 0; } else { cmdresult = int.Parse(obj.ToString()); } return cmdresult != 0; } /// <summary> /// 是否存在记录 /// </summary> /// <param name="strSql"></param> /// <param name="cmdParms"></param> /// <returns></returns> public static bool Exists(string strSql, params SqlParameter[] cmdParms) { var obj = ExecuteScalar(ConnectionStringLocalTransaction,CommandType.Text,strSql, cmdParms); int cmdresult; if ((Equals(obj, null)) || (Equals(obj, DBNull.Value))) { cmdresult = 0; } else { cmdresult = int.Parse(obj.ToString()); } return cmdresult != 0; } } } |
View Details
数据库是电子商务、金融以及ERP系统的基础,通常都保存着重要的商业伙伴和客户信息。大多数企业、组织以及政府部门的电子数据都保存在各种数据库中,他们用这些数据库保存一些个人资料,比如员工薪水、个人资料等等。数据库服务器还掌握着敏感的金融数据。包括交易记录、商业事务和帐号数据,战略上的或者专业的信息,比如专利和工程数据,甚至市场计划等等应该保护起来防止竞争者和其他非法者获取的资料。数据完整性和合法存取会受到很多方面的安全威胁,包括密码策略、系统后门、数据库操作以及本身的安全方案。但是数据库通常没有象操作系统和网络这样在安全性上受到重视。 微软的SQL Server是一种广泛使用的数据库,很多电子商务网站、企业内部信息化平台等都是基于SQL Server上的,但是数据库的安全性还没有被人们更系统的安全性等同起来,多数管理员认为只要把网络和操作系统的安全搞好了,那么所有的应用程序也就安全了。大多数系统管理员对数据库不熟悉而数据库管理员有对安全问题关心太少,而且一些安全公司也忽略数据库安全,这就使数据库的安全问题更加严峻了。数据库系统中存在的安全漏洞和不当的配置通常会造成严重的后果,而且都难以发现。数据库应用程序通常同操作系统的最高管理员密切相关。广泛SQL Server数据库又是属于“端口”型的数据库,这就表示任何人都能够用分析工具试图连接到数据库上,从而绕过操作系统的安全机制,进而闯入系统、破坏和窃取数据资料,甚至破坏整个系统。 这里,我们主要谈论有关SQL Server2000数据库的安全配置以及一些相关的安全和使用上的问题。 在进行SQL Server 2000数据库的安全配置之前,首先你必须对操作系统进行安全配置,保证你的操作系统处于安全状态。然后对你要使用的操作数据库软件(程序)进行必要的安全审核,比如对ASP、PHP等脚本,这是很多基于数据库的WEB应用常出现的安全隐患,对于脚本主要是一个过滤问题,需要过滤一些类似 , ‘ ; @ / 等字符,防止破坏者构造恶意的SQL语句。接着,安装SQL Server2000后请打上补丁sp1以及最新的sp2。 在做完上面三步基础之后,我们再来讨论SQL Server的安全配置。 1、使用安全的密码策略 我们把密码策略摆在所有安全配置的第一步,请注意,很多数据库帐号的密码过于简单,这跟系统密码过于简单是一个道理。对于sa更应该注意,同时不要让sa帐号的密码写于应用程序或者脚本中。健壮的密码是安全的第一步! SQL Server2000安装的时候,如果是使用混合模式,那么就需要输入sa的密码,除非你确认必须使用空密码。这比以前的版本有所改进。 同时养成定期修改密码的好习惯。数据库管理员应该定期查看是否有不符合密码要求的帐号。比如使用下面的SQL语句: Use master Select name,Password from syslogins where password is null 2、使用安全的帐号策略。 由于SQL Server不能更改sa用户名称,也不能删除这个超级用户,所以,我们必须对这个帐号进行最强的保护,当然,包括使用一个非常强壮的密码,最好不要在数据库应用中使用sa帐号,只有当没有其它方法登录到 SQL Server 实例(例如,当其它系统管理员不可用或忘记了密码)时才使用 sa。建议数据库管理员新建立一个拥有与sa一样权限的超级用户来管理数据库。安全的帐号策略还包括不要让管理员权限的帐号泛滥。 SQL Server的认证模式有Windows身份认证和混合身份认证两种。如果数据库管理员不希望操作系统管理员来通过操作系统登陆来接触数据库的话,可以在帐号管理中把系统帐号“BUILTINAdministrators”删除。不过这样做的结果是一旦sa帐号忘记密码的话,就没有办法来恢复了。 很多主机使用数据库应用只是用来做查询、修改等简单功能的,请根据实际需要分配帐号,并赋予仅仅能够满足应用要求和需要的权限。比如,只要查询功能的,那么就使用一个简单的public帐号能够select就可以了。 3、加强数据库日志的记录。 审核数据库登录事件的“失败和成功”,在实例属性中选择“安全性”,将其中的审核级别选定为全部,这样在数据库系统和操作系统日志里面,就详细记录了所有帐号的登录事件。 请定期查看SQL Server日志检查是否有可疑的登录事件发生,或者使用DOS命令。 findstr /C:"登录" d:Microsoft SQL ServerMSSQLLOG*.* 4、管理扩展存储过程 对存储过程进行大手术,并且对帐号调用扩展存储过程的权限要慎重。其实在多数应用中根本用不到多少系统的存储过程,而SQL Server的这么多系统存储过程只是用来适应广大用户需求的,所以请删除不必要的存储过程,因为有些系统的存储过程能很容易地被人利用起来提升权限或进行破坏。 如果你不需要扩展存储过程xp_cmdshell请把它去掉。使用这个SQL语句: use master sp_dropextendedproc 'xp_cmdshell' xp_cmdshell是进入操作系统的最佳捷径,是数据库留给操作系统的一个大后门。如果你需要这个存储过程,请用这个语句也可以恢复过来。 sp_addextendedproc 'xp_cmdshell', 'xpsql70.dll' […]
View Details