Microsoft SQL Server 数据库维护
2.6.1数据库联机与脱机
--联机:该状态为数据库正常状态,也就是我们常看到的数据库的状态,该状态下的数据库处于可操作状态,可以对数据库进行任何权限内的操作。
ALTER DATABASE MyDataBase
SET ONLINE
--脱机:我们可以在Microsoft SQL Server Management中看到该数据库,但该数据库名称旁边有"脱机"的字样,说明该数据库现在虽然存在于数据库引擎实例中,但是不可以执行任何有效的数据操作,比如新增,修改,删除等,这就是脱机状态。
EXEC sp_dboption 'MyDataBase', 'offline', 'TRUE'
ALTER DATABASE MyDataBase
SET OFFLINE
--可疑:和"脱机"状态一样,我们可以在Microsoft SQL Server Management中看到该数据库,但该数据库名称旁边有"可疑"的字样,这说明至少主文件组可疑或可能已损坏。
如果需要暂时关闭某个数据库的服务或复制正在使用的原数据库,用户可以通过选择脱机方式来实现,脱机后在需要的时候可以暂时关闭数据库。
2.6.2数据库的收缩
--1.使用AUTO_SHRINK数据库选项设置自动收缩数据库
ALTER DATABASE MyDataBase SET AUTO_SHRINK ON
--2.DBCC SHRINKDATABASE(数据库名,百分比)百分比:即“收缩后文件中的最大可用空间”,取值范围“大于等于0, 小于100%”,实际使用中设为0即可。
DBCC SHRINKDATABASE(MyDataBase,target_percent)
--3.DBCC ShrinkFile
DBCC ShrinkFile(file_name,targetsize); /* 收缩数据库文件 */
DBCC ShrinkFile(file_log_name,targetsize); /* 收缩日志文件 */
--Targetsize:单位为兆,必须为整数,DBCC SHRINKFILE 尝试将文件收缩到指定大小。
--DBCC SHRINKFILE 不会将文件收缩到小于“实际使用的空间”大小,例如“分配空间”为10M,“实际使用空间”为6M,当制定targetsize为1时,则将该文件收缩到6M,不会将文件收缩到1M。
2.6.3分离数据库
/*
可以将数据库从实例中删除,同时确保数据库在其数据文件和事务日志文件中保持不变。
除了系统数据库外,其余的数据库都可以从服务器的管理中分离出来。
分离数据库不是删除数据库,只是从服务器中分离出来,保证了数据库的数据文件和日志文件完整无损。
分离注意事项:
数据库存在数据库快照时不能分离,在分离前,必须删除所有快照。
数据库正在被镜像时,不能被分离
分离数据库列表中各选项功能:
删除链接:表示是否断开与指定数据库的连接。
更新统计信息:表示在分离数据库之前是否更新过时的优化信息。
保留全文目录:表示是否与数据库相关联的所有全文目录,以用于全文索引。
*/
EXEC sp_detach_db MyDataBase
分离数据库: sp_detach_db;
2.6.4附加数据库
--附加数据库是指将当前数据库以外的数据库附加到当前数据库实例中
--将分离的数据库重新附加服务器中,但在附加数据库时必须指定主数据文件(MDF)的名称和物理位置。
use master
go
create database database_name
on
(filename='E:\AllMyWork\SqlServer\database_name.mdf')
for attach
附加数据库:sp_attach_db 后接表明,附加需要完整的路径名
2.6.5数据库快照
/*
数据库快照是一个只读、静态数据库视图,它是数据库恢复到特定时间点的有效途径。
一个数据库可能多个数据库快照。数据库快照一直保持和源数据库快照被创建的时刻一致。
所以首先,通过快照数据库恢复到创建快照时刻,比其他方法速度快,占用系统资源少。
其次,快照可作为用户保留一份可供读取的历史数据,如历年的客户订单信息。因为是只读的,可替代源数据库实现某些只需查询而
不需写入服务。快照命名时,建议名称中含有数据库名及快照创建时间。
*/
CREATE DATABASE databasename_datetime
ON
(name=database_name,
filename='E:\db\databasename_datetime.mdf'
)
as snapshot of database_name
Go
--恢复数据库快照
create database test_2011820
on
(name='test',
filename='e:\test\test_2011820.mdf'),
(name='sale2009',
filename='e:\test\sale2009_2011820.ndf'),
(name='sale2010',
filename='e:\test\sale2010_2011820.ndf'),
(name='sale2011',
filename='e:\test\sale2011_2011820.mdf'),
(name='sale2012',
filename='e:\test\sale2012_2011820.ndf'),
(name='sale2012_2',
filename='e:\test\sale2012_2_2011820.ndf'),
(name='sale2013',
filename='e:\test\sale2013_2011820.ndf')
as snapshot of test
restore database test
from database_snapshot='test_2011820'
--删除快照
Drop database 快照名
2.6.6数据库的备份
--使用T-SQL语句对数据库进行一次完全数据库备份。备份设备为:Pubs_bk。
USE Sales
GO
EXEC sp_addumpdevice ‘disk’,’pubs_bk’,’c:\sales.bak’
GO
BACKUP DATABASE Sales TO pubs_bk
2.6.7数据库还原恢复
--数据库文件若损坏了,就有必要进行还原该数据库的操作
USE master
RESTORE DATABASE Sales FROM pubs_bk
2.6.8数据库文件的导入导出
--可以使用BULK INSERT 语句按照用户指定的格式把大量数据插入到数据库的表中,这是批量加载数据的一种方式。
--FIELDTERMINATOR用于指定字段之间的分隔符,ROWTERMINATOR用于指定行之间的分隔符。
bulk insert test.dbo.tb1
from 'D:\SQLServer\tb1.txt'
with(fieldterminator=',',rowterminator='\n')
go
2.6.9数据库报表的配置及设计
5.1SELECT
--打卡记录输入到临时表
SELECT * INTO #CardRecord FROM(
SELECT
REPLACE(p.PersonnelID,char(9)+char(13)+char(10),'') 员工编号,
REPLACE(cast(p.PName as varchar(20)),char(9)+char(13)+char(10),'') 员工姓名,
REPLACE(cast(d.DeptName as varchar(20)),char(9)+char(13)+char(10),'') 员工部门,
CONVERT(varchar(50),DATEADD(DAY,-2,DATEADD(s,0,Work.RepotDate)),23) 打卡日期,
CAST(right(datename(weekday,convert(varchar(50),DATEADD(DAY,-2,DATEADD(s,0,Work.RepotDate)),120)),1) as varchar(10)) 星期,
case when Work.indate_1 in('-1','-2',NULL) or len(Work.indate_1)<=2 then '' when len(left(Work.indate_1,LEN(Work.indate_1)-2)+':'+right(Work.indate_1,2))=4 then '0'+left(Work.indate_1,LEN(Work.indate_1)-2)+':'+right(Work.indate_1,2) else left(Work.indate_1,LEN(Work.indate_1)-2)+':'+right(Work.indate_1,2) end 上午上班,
case when Work.OutDate_1 in('-1','-2',NULL) or len(Work.OutDate_1)<=2 then '' when len(left(Work.OutDate_1,LEN(Work.OutDate_1)-2)+':'+right(Work.OutDate_1,2))=4 then '0'+left(Work.OutDate_1,LEN(Work.OutDate_1)-2)+':'+right(Work.OutDate_1,2) else left(Work.OutDate_1,LEN(Work.OutDate_1)-2)+':'+right(Work.OutDate_1,2) end 上午下班,
case when Work.indate_2 in('-1','-2',NULL) or len(Work.indate_2)<=2 then '' when len(left(Work.indate_2,LEN(Work.indate_2)-2)+':'+right(Work.indate_2,2))=4 then '0'+left(Work.indate_2,LEN(Work.indate_2)-2)+':'+right(Work.indate_2,2) else left(Work.indate_2,LEN(Work.indate_2)-2)+':'+right(Work.indate_2,2) end 下午上班,
case when Work.OutDate_2 in('-1','-2',NULL) or len(Work.OutDate_2)<=2 then '' when len(left(Work.OutDate_2,LEN(Work.OutDate_2)-2)+':'+right(Work.OutDate_2,2))=4 then '0'+left(Work.OutDate_2,LEN(Work.OutDate_2)-2)+':'+right(Work.OutDate_2,2) else left(Work.OutDate_2,LEN(Work.OutDate_2)-2)+':'+right(Work.OutDate_2,2) end 下午下班,
case when Work.indate_3 in('-1','-2',NULL) or len(Work.indate_3)<=2 then '' when len(left(Work.indate_3,LEN(Work.indate_3)-2)+':'+right(Work.indate_3,2))=4 then '0'+left(Work.indate_3,LEN(Work.indate_3)-2)+':'+right(Work.indate_3,2) else left(Work.indate_3,LEN(Work.indate_3)-2)+':'+right(Work.indate_3,2) end 晚上上班,
case when Work.OutDate_3 in('-1','-2',NULL) or len(Work.OutDate_3)<=2 then '' when len(left(Work.OutDate_3,LEN(Work.OutDate_3)-2)+':'+right(Work.OutDate_3,2))=4 then '0'+left(Work.OutDate_3,LEN(Work.OutDate_3)-2)+':'+right(Work.OutDate_3,2) else left(Work.OutDate_3,LEN(Work.OutDate_3)-2)+':'+right(Work.OutDate_3,2) end 晚上下班,
case when Work.indate_4 in('-1','-2',NULL) or len(Work.indate_4)<=2 then '' when len(left(Work.indate_4,LEN(Work.indate_4)-2)+':'+right(Work.indate_4,2))=4 then '0'+left(Work.indate_4,LEN(Work.indate_4)-2)+':'+right(Work.indate_4,2) else left(Work.indate_4,LEN(Work.indate_4)-2)+':'+right(Work.indate_4,2) end 午夜上班,
case when Work.OutDate_4 in('-1','-2',NULL) or len(Work.OutDate_4)<=2 then '' when len(left(Work.OutDate_4,LEN(Work.indate_4)-2)+':'+right(Work.OutDate_4,2))=4 then '0'+left(Work.OutDate_4,LEN(Work.OutDate_4)-2)+':'+right(Work.OutDate_4,2) else left(Work.OutDate_4,LEN(Work.OutDate_4)-2)+':'+right(Work.OutDate_4,2) end 午夜下班,
case when Work.Earlyminute=0 then '' when Work.Earlyminute!=0 then cast(Work.Earlyminute as varchar(50)) end 早退分钟,
case when Work.Lateminute=0 then '' when Work.Lateminute!=0 then cast(Work.Lateminute as varchar(50)) end 迟到分钟,
case when p.Sex=0 then '男' when p.Sex=1 then '女' end 性别,
CONVERT(varchar(50),DATEADD(s,0,p.Birthday),23) 生日日期,
REPLACE(cast(w.WorkName as varchar(20)),char(9)+char(13)+char(10),'') 员工班次
FROM OPENDATASOURCE(
'SQLOLEDB',
'Data Source=192.168.1.41;User ID=sa;Password=123lhm..'
).onecard.dbo.WorkDayRecord Work
LEFT JOIN OPENDATASOURCE(
'SQLOLEDB',
'Data Source=192.168.1.41;User ID=sa;Password=123lhm..'
).onecard.dbo.Personnel p ON Work.PersonnelID=p.PersonnelID
LEFT JOIN OPENDATASOURCE(
'SQLOLEDB',
'Data Source=192.168.1.41;User ID=sa;Password=123lhm..'
).onecard.dbo.Department d ON p.DepartmentID=d.DeptID
LEFT JOIN OPENDATASOURCE(
'SQLOLEDB',
'Data Source=192.168.1.41;User ID=sa;Password=123lhm..'
).onecard.dbo.Worktimegroup w ON Work.WorkTimeGroupID=w.WorkTimeGroupID
) CardRecord
where CONVERT(varchar(50),DATEADD(DAY,0,DATEADD(s,0,打卡日期)),23) between '2018-07-01' and '2018-07-30'
--查询本月打卡记录
SELECT * FROM #CardRecord WHERE 员工姓名='张雷' and 打卡日期 between dateadd(dd,-day(getdate()),getdate()) and dateadd(dd,-day(dateadd(month,1,getdate())),dateadd(month,1,getdate()))
--删除临时表
if object_id('tempdb..#CardRecord') is not null
Begin
drop table #CardRecord
End
2、收缩数据库--重建索引
DBCC REINDEXDBCC INDEXDEFRAG--收缩数据和日志DBCC SHRINKDBDBCC SHRINKFILE3、压缩数据库dbcc shrinkdatabase(dbname)
4、转移数据库给新用户以已存在用户权限exec sp_change_users_login 'update_one','newname','oldname'
go5、检查备份集RESTORE VERIFYONLY from disk='E:\dvbbs.bak'
6、修复数据库ALTER DATABASE [dvbbs] SET SINGLE_USER
GODBCC CHECKDB('dvbbs',repair_allow_data_loss) WITH TABLOCKGOALTER DATABASE [dvbbs] SET MULTI_USERGO7、日志清除SET NOCOUNT ON
DECLARE @LogicalFileName sysname, @MaxMinutes INT, @NewSize INT USE tablename -- 要操作的数据库名SELECT @LogicalFileName = 'tablename_log', -- 日志文件名@MaxMinutes = 10, -- Limit on time allowed to wrap log. @NewSize = 1 -- 你想设定的日志文件的大小(M)Setup / initialize
DECLARE @OriginalSize intSELECT @OriginalSize = size FROM sysfiles WHERE name = @LogicalFileNameSELECT 'Original Size of ' + db_name() + ' LOG is ' + CONVERT(VARCHAR(30),@OriginalSize) + ' 8K pages or ' + CONVERT(VARCHAR(30),(@OriginalSize*8/1024)) + 'MB' FROM sysfiles WHERE name = @LogicalFileNameCREATE TABLE DummyTrans (DummyColumn char (8000) not null) DECLARE @Counter INT, @StartTime DATETIME, @TruncLog VARCHAR(255)SELECT @StartTime = GETDATE(), @TruncLog = 'BACKUP LOG ' + db_name() + ' WITH TRUNCATE_ONLY'DBCC SHRINKFILE (@LogicalFileName, @NewSize)
EXEC (@TruncLog)-- Wrap the log if necessary.WHILE @MaxMinutes > DATEDIFF (mi, @StartTime, GETDATE()) -- time has not expired AND @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName) AND (@OriginalSize * 8 /1024) > @NewSize BEGIN -- Outer loop.SELECT @Counter = 0 WHILE ((@Counter < @OriginalSize / 16) AND (@Counter < 50000)) BEGIN -- update INSERT DummyTrans VALUES ('Fill Log') DELETE DummyTrans SELECT @Counter = @Counter + 1 END EXEC (@TruncLog) ENDSELECT 'Final Size of ' + db_name() + ' LOG is ' + CONVERT(VARCHAR(30),size) + ' 8K pages or ' + CONVERT(VARCHAR(30),(size*8/1024)) + 'MB' FROM sysfiles WHERE name = @LogicalFileNameDROP TABLE DummyTransSET NOCOUNT OFF8、说明:更改某个表exec sp_changeobjectowner 'tablename','dbo'
9、存储更改全部表
CREATE PROCEDURE dbo.User_ChangeObjectOwnerBatch
@OldOwner as NVARCHAR(128),@NewOwner as NVARCHAR(128)ASDECLARE @Name as NVARCHAR(128)
DECLARE @Owner as NVARCHAR(128)DECLARE @OwnerName as NVARCHAR(128)DECLARE curObject CURSOR FOR
select 'Name' = name, 'Owner' = user_name(uid)from sysobjectswhere user_name(uid)=@OldOwnerorder by nameOPEN curObject
FETCH NEXT FROM curObject INTO @Name, @OwnerWHILE(@@FETCH_STATUS=0)BEGIN if @Owner=@OldOwner begin set @OwnerName = @OldOwner + '.' + rtrim(@Name) exec sp_changeobjectowner @OwnerName, @NewOwnerend-- select @name,@NewOwner,@OldOwnerFETCH NEXT FROM curObject INTO @Name, @Owner
ENDclose curObject
deallocate curObjectGO 10、SQL SERVER中直接循环写入数据declare @i intset @i=1while @i<30begin insert into test (userid) values(@i) set @i=@i+1end案例:有如下表,要求就裱中所有沒有及格的成績,在每次增長0.1的基礎上,使他們剛好及格:Name score
Zhangshan 80
Lishi 59
Wangwu 50
Songquan 69
while((select min(score) from tb_table)<60)
begin
update tb_table set score =score*1.01
where score<60
if (select min(score) from tb_table)>60
break
else
continue
end
数据开发-经典
1.按姓氏笔画排序: Select * From TableName Order By CustomerName Collate Chinese_PRC_Stroke_ci_as //从少到多2.数据库加密:select encrypt('原始密码')
select pwdencrypt('原始密码')select pwdcompare('原始密码','加密后密码') = 1--相同;否则不相同 encrypt('原始密码')select pwdencrypt('原始密码')select pwdcompare('原始密码','加密后密码') = 1--相同;否则不相同3.取回表中字段:declare @list varchar(1000),
@sql nvarchar(1000) select @list=@list+','+b.name from sysobjects a,syscolumns b where a.id=b.id and a.name='表A'set @sql='select '+right(@list,len(@list)-1)+' from 表A' exec (@sql)4.查看硬盘分区:EXEC master..xp_fixeddrives
5.比较A,B表是否相等:if (select checksum_agg(binary_checksum(*)) from A)
= (select checksum_agg(binary_checksum(*)) from B)print '相等'elseprint '不相等'6.杀掉所有的事件探察器进程:DECLARE hcforeach CURSOR GLOBAL FOR SELECT 'kill '+RTRIM(spid) FROM master.dbo.sysprocesses
WHERE program_name IN('SQL profiler',N'SQL 事件探查器')EXEC sp_msforeach_worker '?'7.记录搜索:开头到N条记录Select Top N * From 表
-------------------------------N到M条记录(要有主索引ID)Select Top M-N * From 表 Where ID in (Select Top M ID From 表) Order by ID Desc----------------------------------N到结尾记录Select Top N * From 表 Order by ID Desc案例例如1:一张表有一万多条记录,表的第一个字段 RecID 是自增长字段,写一个SQL语句,找出表的第31到第40个记录。select top 10 recid from A where recid not in(select top 30 recid from A)
分析:如果这样写会产生某些问题,如果recid在表中存在逻辑索引。
select top 10 recid from A where……是从索引中查找,而后面的select top 30 recid from A则在数据表中查找,这样由于索引中的顺序有可能和数据表中的不一致,这样就导致查询到的不是本来的欲得到的数据。
解决方案
1, 用order by select top 30 recid from A order by ricid 如果该字段不是自增长,就会出现问题
2, 在那个子查询中也加条件:select top 30 recid from A where recid>-1
例2:查询表中的最后以条记录,并不知道这个表共有多少数据,以及表结构。set @s = 'select top 1 * from T where pid not in (select top ' + str(@count-1) + ' pid from T)'
print @s exec sp_executesql @s
9:获取当前数据库中的所有用户表
select Name from sysobjects where xtype='u' and status>=010:获取某一个表的所有字段select name from syscolumns where id=object_id('表名')
select name from syscolumns where id in (select id from sysobjects where type = 'u' and name = '表名')
两种方式的效果相同
11:查看与某一个表相关的视图、存储过程、函数select a.* from sysobjects a, syscomments b where a.id = b.id and b.text like '%表名%'
12:查看当前数据库中所有存储过程select name as 存储过程名称 from sysobjects where xtype='P'
13:查询用户创建的所有数据库
select * from master..sysdatabases D where sid not in(select sid from master..syslogins where name='sa')或者select dbid, name AS DB_NAME from master..sysdatabases where sid <> 0x0114:查询某一个表的字段和数据类型select column_name,data_type from information_schema.columns
where table_name = '表名'15:不同服务器数据库之间的数据操作
--创建链接服务器
exec sp_addlinkedserver 'ITSV ', ' ', 'SQLOLEDB ', '远程服务器名或ip地址 '
exec sp_addlinkedsrvlogin 'ITSV ', 'false ',null, '用户名 ', '密码 '
--查询示例
select * from ITSV.数据库名.dbo.表名
--导入示例
select * into 表 from ITSV.数据库名.dbo.表名
--以后不再使用时删除链接服务器
exec sp_dropserver 'ITSV ', 'droplogins '
--连接远程/局域网数据(openrowset/openquery/opendatasource)
--1、openrowset
--查询示例
select * from openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)
--生成本地表
select * into 表 from openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)
--把本地表导入远程表
insert openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)
select *from 本地表
--更新本地表
update b
set b.列A=a.列A
from openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)as a inner join 本地表 b
on a.column1=b.column1
--openquery用法需要创建一个连接
--首先创建一个连接创建链接服务器
exec sp_addlinkedserver 'ITSV ', ' ', 'SQLOLEDB ', '远程服务器名或ip地址 '
--查询
select *
FROM openquery(ITSV, 'SELECT * FROM 数据库.dbo.表名 ')
--把本地表导入远程表
insert openquery(ITSV, 'SELECT * FROM 数据库.dbo.表名 ')
select * from 本地表
--更新本地表
update b
set b.列B=a.列B
FROM openquery(ITSV, 'SELECT * FROM 数据库.dbo.表名 ') as a
inner join 本地表 b on a.列A=b.列A
--3、opendatasource/openrowset
SELECT *
FROM opendatasource( 'SQLOLEDB ', 'Data Source=ip/ServerName;User ID=登陆名;Password=密码 ' ).test.dbo.roy_ta
--把本地表导入远程表
insert opendatasource( 'SQLOLEDB ', 'Data Source=ip/ServerName;User ID=登陆名;Password=密码 ').数据库.dbo.表名
select * from 本地表
SQL Server基本函数
SQL Server基本函数
1.字符串函数 长度与分析用
1,datalength(Char_expr) 返回字符串包含字符数,但不包含后面的空格
2,substring(expression,start,length) 取子串,字符串的下标是从“1”,start为起始位置,length为字符串长度,实际应用中以len(expression)取得其长度3,right(char_expr,int_expr) 返回字符串右边第int_expr个字符,还用left于之相反4,isnull( check_expression , replacement_value )如果check_expression為空,則返回replacement_value的值,不為空,就返回check_expression字符操作类5,Sp_addtype 自定義數據類型
例如:EXEC sp_addtype birthday, datetime, 'NULL'
6,set nocount {on|off}
使返回的结果中不包含有关受 Transact-SQL 语句影响的行数的信息。如果存储过程中包含的一些语句并不返回许多实际的数据,则该设置由于大量减少了网络流量,因此可显著提高性能。SET NOCOUNT 设置是在执行或运行时设置,而不是在分析时设置。
SET NOCOUNT 为 ON 时,不返回计数(表示受 Transact-SQL 语句影响的行数)。 SET NOCOUNT 为 OFF 时,返回计数
常识
在SQL查询中:from后最多可以跟多少张表或视图:256
在SQL语句中出现 Order by,查询时,先排序,后取
在SQL中,一个字段的最大容量是8000,而对于nvarchar(4000),由于nvarchar是Unicode码。