T-SQL技巧

 

一、 只复制一个表结构,不复制数据

 

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   int   = 0 )
returns   varchar ( 8000 )
as
begin
  
declare   @str_return   varchar ( 8000 )
  
declare   @start   int
  
declare   @next   int
  
declare   @location   int
  
select   @start   = 1
  
select   @next   = 1   -- 如果习惯从0开始则select @next =0
   select   @location   =   charindex ( ' , ' , @str , @start )
  
while  ( @location   <> 0   and   @index   >   @next  )
  
begin
    
select   @start   =   @location   + 1
    
select   @location   =   charindex ( ' , ' , @str , @start )
    
select   @next   = @next   + 1
  
end
  
if   @location   = 0   select   @location   = len ( @str ) + 1   -- 如果是因为没有逗号退出,则认为逗号在字符串后
   select   @str_return   =   substring ( @str , @start , @location   - @start -- @start肯定是逗号之后的位置或者就是初始值1
   if  ( @index   <>   @next  )  select   @str_return   =   ''   -- 如果二者不相等,则是因为逗号太少,或者@index小于@next的初始值1。
   return   @str_return
end

3、 测试

SELECT   [ dbo ] . [ getstrarrlength ] ( ' 1,2,3,4,a,b,c,d ' )
SELECT   [ dbo ] . [ getstrofindex ] ( ' 1,2,3,4,a,b,c,d ' , 5 )

四、 一条语句执行跨越若干个数据库
我要在一条语句里操作不同的服务器上的不同的数据库里的不同的表,怎么办呢?
第一种方法:

select   *   from   OPENDATASOURCE ( ' SQLOLEDB ' , ' Data Source=远程ip;User ID=sa;Password=密码 ' ).库名.dbo.表名

第二种方法:
先使用联结服务器:

EXEC  sp_addlinkedserver  ' 别名 ' , '' , ' MSDASQL ' , NULL , NULL , ' DRIVER={SQL Server};SERVER=远程名;UID=用户;PWD=密码; '
exec  sp_addlinkedsrvlogin   @rmtsrvname = ' 别名 ' , @useself = ' false ' , @locallogin = ' sa ' , @rmtuser = ' sa ' , @rmtpassword = ' 密码 '
GO

然后你就可以如下:

select   *   from  别名.库名.dbo.表名
insert  库名.dbo.表名  select   *   from  别名.库名.dbo.表名
select   *   into  库名.dbo.新表名  from  别名.库名.dbo.表名
go

五、 怎样获取一个表中所有的字段信息
蛙蛙推荐:怎样获取一个表中所有字段的信息
先创建一个视图

Create   view  fielddesc    
as
select  o.name  as  table_name,c.name  as  field_name,t.name  as  type,c.length  as  

length,c.isnullable 
as  isnullable, convert ( varchar ( 30 ),p.value)  as  desp 
from  syscolumns c  
join  systypes t  on  c.xtype  =  t.xusertype
join  sysobjects o  on  o.id = c.id 
left   join     sysproperties p  on  p.smallid = c.colid  and  p.id = o.id    
where  o.xtype = ' U '

查询时:

Select   *   from  fielddesc  where  table_name  =   ' 你的表名 '

 

还有个更强的语句,是邹建写的,也写出来吧

SELECT  
 (
case   when  a.colorder = 1   then  d.name  else   ''   end ) N ' 表名 ' ,
 a.colorder N
' 字段序号 ' ,
 a.name N
' 字段名 ' ,
 (
case   when   COLUMNPROPERTY ( a.id,a.name, ' IsIdentity ' ) = 1   then   ' ' else   ''   end ) N ' 标识 ' ,
 (
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 ) N ' 主键 ' ,
 b.name N
' 类型 ' ,
 a.length N
' 占用字节数 ' ,
 
COLUMNPROPERTY (a.id,a.name, ' PRECISION ' as  N ' 长度 ' ,
 
isnull ( COLUMNPROPERTY (a.id,a.name, ' Scale ' ), 0 as  N ' 小数位数 ' ,
 (
case   when  a.isnullable = 1   then   ' ' else   ''   end ) N ' 允许空 ' ,
 
isnull (e. text , '' ) N ' 默认值 ' ,
 
isnull (g. [ value ] , '' AS  N ' 字段说明 '
-- into ##tx

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   object_name (a.id),a.colorder

六、 时间格式转换问题
因为新开发的软件需要用一些旧软件生成的一些数据,在时间格式上不统一,只能手工转换,研究了一下午写了三条语句,以前没怎么用过convert函数和case语句,还有"+"操作符在不同上下文环境也会起到不同的作用,把我搞晕了要,不过现在看来是差不多弄好了。

1、把所有"70.07.06"这样的值变成"1970-07-06"

UPDATE  lvshi
SET  shengri  =   ' 19 '   +   REPLACE (shengri,  ' . ' ' - ' )
WHERE  (zhiyezheng  =   ' 139770070153 ' )

 

2、在"1970-07-06"里提取"70","07","06"

SELECT   SUBSTRING (shengri,  3 2 AS   year SUBSTRING (shengri,  6 2 AS   month
      
SUBSTRING (shengri,  9 2 AS   day
FROM  lvshi
WHERE  (zhiyezheng  =   ' 139770070153 ' )

3、把一个时间类型字段转换成"1970-07-06"

UPDATE  lvshi
SET  shenling  =   CONVERT ( varchar ( 4 ),  YEAR (shenling)) 
      
+   ' - '   +   CASE   WHEN   LEN ( MONTH (shenling))  =   1   THEN   ' 0 '   +   CONVERT ( varchar ( 2 ), 
      
month (shenling))  ELSE   CONVERT ( varchar ( 2 ),  month (shenling)) 
      
END   +   ' - '   +   CASE   WHEN   LEN ( day (shenling))  =   1   THEN   ' 0 '   +   CONVERT ( char ( 2 ), 
      
day (shenling))  ELSE   CONVERT ( varchar ( 2 ),  day (shenling))  END
WHERE  (zhiyezheng  =   ' 139770070153 ' )

七、 分区视图
分区视图是提高查询性能的一个很好的办法

-- 看下面的示例

-- 示例表
create   table  tempdb.dbo.t_10(
id 
int   primary   key   check (id  between   1   and   10 ),name  varchar ( 10 ))

create   table  pubs.dbo.t_20(
id 
int   primary   key   check (id  between   11   and   20 ),name  varchar ( 10 ))

create   table  northwind.dbo.t_30(
id 
int   primary   key   check (id  between   21   and   30 ),name  varchar ( 10 ))
go

-- 分区视图
create   view  v_t
as
select   *   from  tempdb.dbo.t_10
union   all
select   *   from  pubs.dbo.t_20
union   all
select   *   from  northwind.dbo.t_30
go

-- 插入数据
insert  v_t  select   1  , ' aa '
union    all   select   2  , ' bb '
union    all   select   11 , ' cc '
union    all   select   12 , ' dd '
union    all   select   21 , ' ee '
union    all   select   22 , ' ff '

-- 更新数据
update  v_t  set  name = name + ' _更新 '   where   right (id, 1 ) = 1

-- 删除测试
delete   from  v_t  where   right (id, 1 ) = 2

-- 显示结果
select   *   from  v_t
go

-- 删除测试
drop   table  northwind.dbo.t_30,pubs.dbo.t_20,tempdb.dbo.t_10
drop   view  v_t

/*--测试结果

id          name       
----------- ---------- 
1           aa_更新
11          cc_更新
21          ee_更新

(所影响的行数为 3 行)
==
*/


八、 树型的实现

-- 参考

-- 树形数据查询示例
--
作者: 邹建

-- 示例数据
create   table   [ tb ] ( [ id ]   int   identity ( 1 , 1 ), [ pid ]   int ,name  varchar ( 20 ))
insert   [ tb ]   select   0 , ' 中国 '
union    all    select   0 , ' 美国 '
union    all    select   0 , ' 加拿大 '
union    all    select   1 , ' 北京 '
union    all    select   1 , ' 上海 '
union    all    select   1 , ' 江苏 '
union    all    select   6 , ' 苏州 '
union    all    select   7 , ' 常熟 '
union    all    select   6 , ' 南京 '
union    all    select   6 , ' 无锡 '
union    all    select   2 , ' 纽约 '
union    all    select   2 , ' 旧金山 '
go

-- 查询指定id的所有子
create   function  f_cid(
@id   int
)
returns   @re   table ( [ id ]   int , [ level ]   int )
as
begin
 
declare   @l   int
 
set   @l = 0
 
insert   @re   select   @id , @l
 
while   @@rowcount > 0
 
begin
  
set   @l = @l + 1
  
insert   @re   select  a. [ id ] , @l
  
from   [ tb ]  a, @re  b
  
where  a. [ pid ] = b. [ id ]   and  b. [ level ] = @l - 1
 
end
/**/ /*--如果只显示最明细的子(下面没有子),则加上这个删除
 delete a from @re a
 where exists(
  select 1 from [tb] where [pid]=a.[id])
--
*/

 
return
end
go

-- 调用(查询所有的子)
select  a. * ,层次 = b. [ level ]   from   [ tb ]  a,f_cid( 2 )b  where  a. [ id ] = b. [ id ]
go

-- 删除测试
drop   table   [ tb ]
drop   function  f_cid
go

 

九、 排序问题

CREATE   TABLE   [ t ]  (
 
[ id ]   [ int ]   IDENTITY  ( 1 1 NOT   NULL  ,
 
[ GUID ]   [ uniqueidentifier ]   NULL  
ON   [ PRIMARY ]
GO


下面这句执行5次

insert  t  values  ( newid ())


查看执行结果

select   *   from  t


1、 第一种

select   *   from  t
 
order   by   case  id  when   4   then   1
                  
when   5   then   2
                  
when   1   then   3
                  
when   2   then   4
                  
when   3   then   5   end


2、 第二种

select   *   from  t  order   by  (id + 2 ) % 6


3、 第三种

select   *   from  t  order   by   charindex ( cast (id  as   varchar ), ' 45123 ' )


4、 第四种

select   *   from  t
WHERE  id  between   0   and   5
order   by   charindex ( cast (id  as   varchar ), ' 45123 ' )


5、 第五种

select   *   from  t  order   by   case   when  id  > 3   then  id - 5   else  id  end


6、 第六种

select   *   from  t  order   by  id  /   4   desc ,id  asc

 

十、 一条语句删除一批记录
首先id列是int标识类类型,然后删除ID值为5,6,8,9,10,11的列,这里的cast函数不能用convert函数代替,而且转换的类型必须是varchar,而不能是char,否则就会执行出你不希望的结果,这里的"5,6,8,9,10,11"可以是你在页面上获取的一个chkboxlist构建成的值,然后用下面的一句就全部删
除了,比循环用多条语句高效吧应该。

delete   from   [ fujian ]   where   charindex ( ' , ' + cast ( [ id ]   as   varchar ) + ' , ' , ' , ' + ' 5,6,8,9,10,11, ' + ' , ' ) > 0


还有一种就是

delete   from  table1  where  id  in ( 1 , 2 , 3 , 4  )


十一、获取子表内的一列数据的组合字符串
下面这个函数获取05年已经注册了的某个所的律师,唯一一个参数就是事务所的名称,然后返回zhuce字段里包含05字样的所有律师。

CREATE     FUNCTION  fn_Get05LvshiNameBySuo  ( @p_suo   Nvarchar ( 50 ))
RETURNS   Nvarchar ( 2000 )
AS
BEGIN   
 
DECLARE   @LvshiNames   varchar ( 2000 ),  @name   varchar ( 50 )
 
select   @LvshiNames = ''
 
DECLARE  lvshi_cursor  CURSOR   FOR


数据库里有1,2,3,4,5 共5条记录,要用一条sql语句让其排序,使它排列成4,5,1,2,3,怎么写?

 

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值