经典SQL语句

获取GUID: SELECT NEWID()
说明:复制表(只复制结构,源表名:a 新表名:b)
SQL: 
select * into b from a where 1<>1
说明:拷贝表(拷贝数据,源表名:a 目标表名:b)
insert into b(a, b, c) select d,e,f from b;
把所有姓名相同的只取出一个
select a.name from table_name a where a.id in 
 (
select b.id from table_name b where a.id<>b.id)
同理删除荣誉数据
delete from table_name  where table_name.id in 
 (
select b.id from table_name b where table_name.id<>b.id)

select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b

随机取出10条数据
select top 10 * from tablename order by newid()

Microsoft SQL Server是如何加密口令的?未公开的加密函数? 
        
如果对MSSQL的用户信息有兴趣的,可能会发现master.dbo.sysxlogins里面存放着用户的口令,可是呢,password字段如果不是null就是一堆看不懂的binary,这个口令是怎么加密的呢?


其实只要仔细看看master.dbo.sp_addlogin就知道了,MSSQL的sp都可以看到代码,真是不错。
让我们来看看它是怎么做的,注意这一行select 
@passwd = pwdencrypt(@passwd),这个时后@passwd就被加密了,让我们也来试一下
DECLARE @ClearPWD varchar(255
DECLARE @EncryptedPWD varbinary(255)
SELECT @ClearPWD = 'test'
SELECT @EncryptedPWD = CONVERT(varbinary(255), pwdencrypt(@ClearPWD))
SELECT @EncryptedPWD
看上去不错,确实被加密了,可是我怎么还原呢? 

呵呵,这就没戏了,口令加密都是单向的,用加密后的密文来比较就可以了。
继续看看其它用户相关的sp,可以发现master.dbo.sp_password里面有口令比较的内容。
pwdcompare(
@old, password, (CASE WHEN xstatus&2048 = 2048 THEN 1 ELSE 0 END))
不用去理会xstatus,这是一个状态掩码,一般我们用的时候就直接用0就可以了
DECLARE @ClearPWD varchar(255
DECLARE @EncryptedPWD varbinary(255)
SELECT @ClearPWD = 'test'
SELECT @EncryptedPWD = CONVERT(varbinary(255), pwdencrypt(@ClearPWD))
SELECT pwdcompare(@ClearPWD@EncryptedPWD0)
SELECT pwdcompare('ErrorPassword'@EncryptedPWD0)
这样我们就可以使用这两个函数来加密自己的密码了,怎么样,还不错吧?


1.如果 T 表还有一字段 F0 数据类型为自动增量整型(唯一,不会重复),
  而且 T 表中含有除 F0 字段外,请删除其它字段完全相同的重复多余的脏记录数据:
delete from t  where f0 in(select max(f0) from t group by f1,f2,f3,f4,f5,f6,f7 having count(f0)>1)

上面这个sql有问题
正确的如下

DELETE Legal_Dispute_Lawyer WHERE Lawyer_Record_No IN(SELECT Lawyer_Record_No FROM Legal_Dispute_Lawyer LDL WHERE Lawyer_Record_No(SELECT TOP 1 Lawyer_Record_No FROM Legal_Dispute_Lawyer WHERE LD=LDL.LD AND Name=LDL.Name AND Email=LDL.Email AND Phone_No=LDL.Phone_No AND Fax_No=LDL.Fax_No))

消除Legal_Dispute_Lawyer 表中除Lawyer_Record_No(自增字段)外其余数据完全相同的记录.
表结构如下
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Legal_Dispute_Lawyer]'and OBJECTPROPERTY(id, N'IsUserTable'= 1)
drop table [dbo].[Legal_Dispute_Lawyer]
GO

CREATE TABLE [dbo].[Legal_Dispute_Lawyer] (
 
[Lawyer_Record_No] [int] IDENTITY (11NOT NULL ,
 
[LD] [int] NOT NULL ,
 
[Name] [int] NOT NULL ,
 
[Phone_No] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,
 
[Fax_No] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,
 
[Email] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL 
ON [PRIMARY]
GO


分页语句
select top 100 * from 表名 where id not in (select top page_no*100 * from 表名)
page_no是程序中的变量

从数据库中去一年的各单位电话费统计(电话费定额贺电化肥清单两个表来源)

SELECT a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy'AS telyear,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '01', a.factration)) AS JAN,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '02', a.factration)) AS FRI,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '03', a.factration)) AS MAR,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '04', a.factration)) AS APR,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '05', a.factration)) AS MAY,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '06', a.factration)) AS JUE,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '07', a.factration)) AS JUL,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '08', a.factration)) AS AGU,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '09', a.factration)) AS SEP,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '10', a.factration)) AS OCT,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '11', a.factration)) AS NOV,
      
SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '12', a.factration)) AS DEC
FROM (SELECT a.userper, a.tel, a.standfee, b.telfeedate, b.factration
        
FROM TELFEESTAND a, TELFEE b
        
WHERE a.tel = b.telfax) a
GROUP BY a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy')

个人认为,偶写了这么久的SQL,只说语法很无聊,语句的涵义与灵活的组合很重要,下面这个是写的一个药品管理的存储过程的一句,很经典:
 
UPDATE 药房库存 SET 库存数量=库存数量-B.用量 FROM [药房库存] A ,
 ( 
Select sum(用量) as 用量,药品价码 FROM 处方项 
    
WHERE 处方号=@RecipeNo AND 处方序号=@RecipeXNo 
  
GROUP BY 药品价码
 ) B  
WHERE A.药品价码=B.药品价码 AND A.库房名称=@DepotName

这是一个参照B表将A表中库存一一修改,而B表中存在一个求和,A表也与B表关联,同时要满足A表条件。

两台SQL服务器上的一个数据表同步!

drop procedure dbSync
GO

/*     数据同步                      */
CREATE PROCEDURE dbSync 
       
@sTabelName  varchar(255),    --要同步的表名
       @sKeyField   varchar(255),    --关键字段
       @sServer     varchar(255),    --服务器名称或IP
       @sUserName   varchar(255),    --登录到服务器的用户名,一般为sa
       @sPassWord   varchar(32)      --用户登录到服务器的密码 
AS


   
/*删除临时表*/
  
if exists (select * from dbo.sysobjects where id = object_id(N'tempTbl'and OBJECTPROPERTY(id, N'IsUserTable'= 1)
  
drop table tempTbl
  
                
  
declare @sql VARCHAR(2000

  
/*把表@sTabelName[远程]的数据拷贝到临时表*/
   
  
set @sql='select * into tempTbl from '
  
set @sql=@sql + ' OPENDATASOURCE( '
  
set @sql=@sql + '''SQLOLEDB.1'','
  
set @sql=@sql + '''Persist Security Info=True;User ID=' + @sUserName
  
set @sql=@sql + ';Password=' + @sPassWord
  
set @sql=@sql + ';Initial Catalog=toys;Data Source=' + @sServer
  
set @sql=@sql + ''').toys.dbo.'+@sTabelName

  
EXEC(@sql)  

  
  
/* 把@sTabelName[本地]中的@sTabelName[远程]表中没有的数据插入到临时表中*/

  
set @sql='insert into tempTbl select * from '+@sTabelName+' where ['+@sKeyField+'] not in (select ['+@sKeyField+'] from tempTbl)'

  
EXEC(@sql)
  

  
/*清空表@sTabelName[本地]*/
  
set @sql='truncate table '+@sTabelName

  
EXEC(@sql)

  
  
--取得列名
  declare @MySql VARCHAR(2000)
  
set @MySql=''
  
declare @title varchar(20)

  
DECLARE titles_cursor CURSOR FOR 

  
SELECT name from syscolumns where id=object_id(@sTabelName)

  
OPEN titles_cursor

  
FETCH NEXT FROM titles_cursor INTO @title

  
WHILE @@FETCH_STATUS = 0
  
BEGIN
    
if @title<>'id' 
    
begin
      
if @MySql = ''
        
set @MySql = @MySql + @title
      
else
        
set @MySql = @MySql + ',' + @title
    
end
    
FETCH NEXT FROM titles_cursor INTO @title
  
END

  
CLOSE titles_cursor

  
DEALLOCATE titles_cursor
  
--取列名结束


  
/*把临时表的内容插入到表@sTabelName[本地]*/
  
set @sql='insert into '+@sTabelName+' select '+@MySql+' from tempTbl'

  
EXEC(@sql


  
/*删除临时表*/
  
if exists (select * from dbo.sysobjects where id = object_id(N'tempTbl'and OBJECTPROPERTY(id, N'IsUserTable'= 1)
  
drop table tempTbl

GO

select a,b,c from a where a IN (select d from b )
这是一个可以优化的sql语句,给a表中的a和b表中的d使用索引,然后改为
select a,b,c from a where exists (select * from b where b.d=a.a)

总结说一点:
1、要合理使用索引
索引是数据库一个重要的构成部分,很多人都会忽略它,其实索引的根本目的就是
为了提高查询效率。
使用原则如下: 
在经常进行连接,但是没有指定为外键的列上建立索引,而不经常连接的字段则
由优化器自动生成索引。 

在频繁进行排序或分组(即进行group by或order by操作)的列上建立索引。 

在条件表达式中经常用到的不同值较多的列上建立检索,在不同值少的列上不要
建立索引。比如在雇员表的“性别”列上只有“男”与“女”两个不同值,因此就
无必要建立索引。如果建立索引不但不会提高查询效率,反而会严重降低更新速度
。 
如果待排序的列有多个,可以在这些列上建立复合索引(compound 
index)。 

在写sql语句时就必须注意有些写法是会使得数据库无法使用索引的,比如IS 
NULL
IS NOT NULLIN ,NOT IN 等。。。

2.避免或简化排序 
应当简化或避免对大型表进行重复的排序。当能够利用索引自动以适当的次序产生
输出时,优化器就避免了排序的步骤。以下是一些影响因素: 
●索引中不包括一个或几个待排序的列; 
group by或order by子句中列的次序与索引的次序不一样; 
●排序的列来自不同的表。 
为了避免不必要的排序,就要正确地增建索引,合理地合并数据库表(尽管有时可
能影响表的规范化,但相对于效率的提高是值得的)。如果排序不可避免,那么应
当试图简化它,如缩小排序的列的范围等。 
3.消除对大型表行数据的顺序存取 
在嵌套查询中,对表的顺序存取对查询效率可能产生致命的影响。比如采用顺序存
取策略,一个嵌套3层的查询,如果每层都查询1000行,那么这个查询就要查询10
亿行数据。避免这种情况的主要方法就是对连接的列进行索引。例如,两个表:学
生表(学号、姓名、年龄……)和选课表(学号、课程号、成绩)。如果两个表要
做连接,就要在“学号”这个连接字段上建立索引。 
还可以使用并集来避免顺序存取。尽管在所有的检查列上都有索引,但某些形式的
where子句强迫优化器使用顺序存取。下面的查询将强迫对orders表执行顺序操作
: 
SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001OR 
order_num
=1008 
虽然在customer_num和order_num上建有索引,但是在上面的语句中优化器还是使
用顺序存取路径扫描整个表。因为这个语句要检索的是分离的行的集合,所以应该
改为如下语句: 
SELECT * FROM orders WHERE customer_num=104 AND order_num>1001 
UNION 
SELECT * FROM orders WHERE order_num=1008 
这样就能利用索引路径处理查询。 
4.避免相关子查询 
一个列的标签同时在主查询和where子句中的查询中出现,那么很可能当主查询中
的列值改变之后,子查询必须重新查询一次。查询嵌套层次越多,效率越低,因此
应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的
行。 
5.避免困难的正规表达式 
MATCHES和LIKE关键字支持通配符匹配,技术上叫正规表达式。但这种匹配特别耗
费时间。例如:
SELECT * FROM customer WHERE zipcode LIKE “98_ _ _” 
即使在zipcode字段上建立了索引,在这种情况下也还是采用顺序扫描的方式。如
果把语句改为SELECT * 
FROM customer WHERE zipcode >98000”,在执行查询
时就会利用索引来查询,显然会大大提高速度。 
另外,还要避免非开始的子串。例如语句:
SELECT * FROM customer WHERE 
zipcode
[2,3] >80”,在where子句中采用了非开始子串,因而这个语句也不会
使用索引。 
6.使用临时表加速查询 
把表的一个子集进行排序并创建临时表,有时能加速查询。它有助于避免多重排序
操作,而且在其他方面还能简化优化器的工作。例如: 
SELECT cust.name,rcvbles.balance,……other columns 
FROM cust,rcvbles 
WHERE cust.customer_id = rcvlbes.customer_id 
AND rcvblls.balance>0 
AND cust.postcode>98000” 
ORDER BY cust.name 
如果这个查询要被执行多次而不止一次,可以把所有未付款的客户找出来放在一个
临时文件中,并按客户的名字进行排序: 
SELECT cust.name,rcvbles.balance,……other columns 
FROM cust,rcvbles 
WHERE cust.customer_id = rcvlbes.customer_id 
AND rcvblls.balance>0 
ORDER BY cust.name 
INTO TEMP cust_with_balance 
然后以下面的方式在临时表中查询: 
SELECT * FROM cust_with_balance 
WHERE postcode>98000” 
临时表中的行要比主表中的行少,而且物理顺序就是所要求的顺序,减少了磁盘
I
/O,所以查询工作量可以得到大幅减少。 
注意:临时表创建后不会反映主表的修改。在主表中数据频繁修改的情况下,注意
不要丢失数据。 
7.用排序来取代非顺序存取 
非顺序磁盘存取是最慢的操作,表现在磁盘存取臂的来回移动。SQL语句隐藏了这
一情况,使得我们在写应用程序时很容易写出要求存取大量非顺序页的查询。 
有些时候,用数据库的排序能力来替代非顺序的存取能改进查询。 

posted on 2006-11-21 23:19  IMustDo  阅读(779)  评论(1编辑  收藏  举报