1 只复制一个表结构,不复制数据
select top 0 * into [t1] from [t2]
2 获取数据库中某个对象的创建脚本
(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
3 分隔字符串
如果有一个用逗号分割开的字符串,比如说"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
)
4 一条语句执行跨越若干个数据库
我要在一条语句里操作不同的服务器上的不同的数据库里的不同的表,怎么办呢?
方法一:

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
5 获取一个表中所有的字段信息
先创建一个视图

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

6 时间格式转换问题
因为新开发的软件需要用一些旧软件生成的一些数据,在时间格式上不统一,只能手工转换,研究了一下午写了三条语句,以前没怎么用过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 ' )
7 分区视图
分区视图是提高查询性能的一个很好的办法

-- 看下面的示例


-- 示例表
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 行)
==*/
8 树型的实现


-- 参考


-- 树形数据查询示例

-- 作者: 邹建


-- 示例数据
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


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

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
10 一条语句删除一批记录
首先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 )
11 获取子表内的一列数据的组合字符串
下面这个函数获取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
12 让0变成1,1变成0

declare @a int
set @a = 0 -- 初始为0
select @a
set @a = @a ^ 1 -- 把0变成1
select @a
set @a = @a ^ 1 -- 把1变成0
select @a
13 四种方法取表里n到m条纪录
(1) 第一种

如果tablename里没有其他identity列,那么:

select top m * into 临时表(或表变量) from tablename order by columnname -- 将top m笔插入
set rowcount n
select * from 表变量 order by columnname desc 
(2) 第二种

select top n * from ( select top m * from tablename order by columnname) a order by columnname desc
(3) 第三种

select identity(int) id0,* into #temp from tablename
取n到m条的语句为:

select * from #temp where id0 >=n and id0 <= m
如果你在执行 select identity(int) id0,* into #temp from tablename这条语句的时候报错,那是因为你的DB中间的select into/bulkcopy属性没有打开要先执行:


exec sp_dboption 你的DB名字,'select into/bulkcopy',true

如果表里有identity属性,那么简单:


select * from tablename where identitycol between n and m


select rows from sysindexes where id = object_id ( ' test ' ) and indid in ( 0 , 1 )
15 提取数据库内所有表的字段详细说明的SQL语句

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 ' 字段说明 '
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
获取表结构 [ 把 'sysobjects' 替换 成 'tablename' 即可 ]
SELECT CASE IsNull (I.name, '' )
When '' Then ''
Else ' * '
End as IsPK,
Object_Name (A.id) as t_name,
A.name as c_name,
IsNull ( SubString (M. text , 1 , 254 ), '' ) as pbc_init,
T.name as F_DataType,
CASE IsNull ( TYPEPROPERTY (T.name, ' Scale ' ), '' )
WHEN '' Then Cast (A.prec as varchar )
ELSE Cast (A.prec as varchar ) + ' , ' + Cast (A.scale as varchar )
END as F_Scale,
A.isnullable as F_isNullAble
FROM Syscolumns as A
JOIN Systypes as T
ON (A.xType = T.xUserType AND A.Id = Object_id ( ' sysobjects ' ) )
LEFT JOIN ( SysIndexes as I
JOIN Syscolumns as A1
ON ( I.id = A1.id and A1.id = object_id ( ' sysobjects ' ) and (I.status & 0x800 ) = 0x800 AND A1.colid <= I.keycnt) )
ON ( A.id = I.id AND A.name = index_col ( ' sysobjects ' , I.indid, A1.colid) )
LEFT JOIN SysComments as M
ON ( M.id = A.cdefault and ObjectProperty (A.cdefault, ' IsConstraint ' ) = 1 )
ORDER BY A.Colid ASC


16 SQL Server中删除重复数据的几个方法



(1) 方法一

declare @max integer , @id integer
declare cur_rows cursor local for select 主字段, count ( * ) from 表名 group by 主字段 having count ( * ) > 1
open cur_rows
fetch cur_rows into @id , @max
while @@fetch_status = 0
begin
select @max = @max - 1
set rowcount @max
delete from 表名 where 主字段 = @id
fetch cur_rows into @id , @max
end
close cur_rows
set rowcount 0

(2) 方法二

有两个意义上的重复记录,一是完全重复的记录,也即所有字段均重复的记录,二是部分关键字段重复的记录,比如Name字段重复,而其他字段不一定重复或都重复可以忽略。

〈1〉 对于第一种重复,比较容易解决,使用


就可以得到无重复记录的结果集。

如果该表需要删除重复的记录(重复记录保留1条),可以按以下方法删除

select distinct * into #Tmp from tableName
drop table tableName
select * into tableName from #Tmp
drop table #Tmp

发生这种重复的原因是表设计不周产生的,增加唯一索引列即可解决。

〈2〉 这类重复问题通常要求保留重复记录中的第一条记录,操作方法如下

假设有重复的字段为Name, Address,要求得到这两个字段唯一的结果集

select identity ( int , 1 , 1 ) as autoID, * into #Tmp from tableName
select min (autoID) as autoID into #Tmp2 from #Tmp group by Name,autoID
select * from #Tmp where autoID in ( select autoID from #tmp2)

最后一个select即得到了Name,Address不重复的结果集(但多了一个autoID字段,实际写时可以写在select子句中省去此列)

17 查询分析器不能单步调试的的原因

具体步骤如下:

1、将服务器【身份验证】属性设置成【混合模式】(window与sql身份验证)

2、在【控制面板】中打开【服务】将【MSSQLSERVER】服务打开【属性】,选择【登录】页面,将登录身份设置成服务器本地帐号和该帐号密码,如administrator,密码123;

3、重新启动sqlserver服务,此时的服务指的是【SQL服务管理器】中的SQL SERVER服务;假设【帐号】设置为administrator

此时达到的效果是:服务器本地帐号administrator与客户端上的administrator(并且该帐号的密码要与服务器密码相同)可以通过【查询分析器】进行调试;

如果想让【其他帐号】也能够调试,那么还需要如下设置:

1、在【服务器】上运行dcomcnfg.exe;

2、在【默认安全机制】中【默认访问权限】右边点击【编辑默认值】选择允许调试的帐号类型,如users用户类型,sample帐号有包含users组;

3、重新启动sqlserver服务;

3、在客户端上创建与服务帐号密码一样的用户,如sample;

做到这步就可以通过查询分析器的调试功能进行单步调试了。

注:第二步更改“启动服务帐户”,在第一次登录之前,必须更改用户密码。

不然,event log:

以当前密码登录的尝试因下列错误而宣告失败:

在第一次登录之前,必须更改用户密码。
















