清空数据库中所有表数据的方法

其实删除数据库中数据的方法并不复杂,为什么我还要多此一举呢,一是我这里介绍的是删除数据库的所有数据,因为数据之间可能形成相互约束关系,删除操作可能陷入死循环,二是这里使用了微软未正式公开的sp_MSForEachTable存储过程。

也许很多读者朋友都经历过这样的事情:要在开发数据库基础上清理一个空库,但由于对数据库结构缺乏整体了解,在删除一个表的记录时,删除不了,因为可能有外键约束,一个常见的数据库结构是一个主表,一个子表,这种情况下一般都得先删除子表记录,再删除主表记录。

说道删除数据记录,往往马上会想到的是delete和truncate语句,但在遇到在两个或多个表之间存在约束的话,这两个语句可能都会失效,而且最要命的是这两个命令都只能一次操作一个表。那么真正遇到要删除SQL Server数据库中所有记录时,该怎么办呢?有两个选择:

1.按照先后顺序逐个删除,这个方法在表非常多的情况下显得很不现实,即便是表数量不多,但约束比较多时,你还是要花费大量的时间和精力去研究其间的约束关系,然后找出先删哪个表,再删哪个表,最后又删哪个表。

2.禁用所有约束,删除所有数据,最后再启用约束,这样就不用花时间和精力去研究什么约束了,只需要编写一个简单的存储过程就可以自动完成这个任务。

从这两个选择中不难看出第二个选择是最简单有效的了,那么在使用第二个选择时,具体该怎么实施呢?

首先得编写代码循环检查所有的表,这里我推荐一个存储过程sp_MSForEachTable,因为在微软的官方文档中没有对这个存储过程有描述,很多开发人员也许都还未曾听说,所以你在互联网上搜索得到的解决办法大多很复杂,也许有的人会认为,既然没有官方文档,这个存储过程可能会不稳定,打心理上会排斥它,但事实并非如此。下面来先看一个完整的脚本:

CREATE PROCEDURE sp_DeleteAllData

AS

EXEC sp_MSForEachTable ‘ALTER TABLE ? NOCHECK CONSTRAINT ALL’

EXEC sp_MSForEachTable ‘ALTER TABLE ? DISABLE TRIGGER ALL’

EXEC sp_MSForEachTable ‘DELETE FROM ?’

EXEC sp_MSForEachTable ‘TRUNCATE TABLE ?’ — 截断表,比较快

EXEC sp_MSForEachTable ‘ALTER TABLE ? CHECK CONSTRAINT ALL’

EXEC sp_MSForEachTable ‘ALTER TABLE ? ENABLE TRIGGER ALL’

EXEC sp_MSForEachTable ‘SELECT * FROM ?’

GO

这个脚本创建了一个命名为sp_DeleteAllData的存储过程,前面两行语句分别禁用约束和触发器,第三条语句才是真正地删除所有数据,接下里的语句分别还原约束和触发器,最后一条语句是显示每个表中的记录,当然这条语句也可以不要,我只是想确认一下是否清空了所有表而已。

你可以在任何数据库上运行这个存储过程,当然不要在生成数据库上运行,可别怪我没告诉你!不管怎样,还是先备份一下数据库,使用备份数据库还原,然后再运行该存储过程,呵呵,即使是一个大型数据库,也要不多长时间,你的数据库就成一个空库了。

删除数据库快照

删除数据库快照将删除 SQL Server 中的数据库快照,并删除快照使用的稀疏文件.删除数据库快照时,将终止所有到此快照的用户连接.

具有 DROP DATABASE 权限的任何用户都可以删除数据库快照.

删除数据库快照

  1. 标识要删除的数据库快照.
  1. 执行 DROP DATABASE 语句,并指定要删除的数据库快照的名称.

此示例将删除名为 SalesSnapshot0600 的数据库快照,而不影响源数据库.

DROP DATABASE SalesSnapshot0600

 SalesSnapshot0600 的所有用户连接都被终止,并删除快照使用的所有 NTFS 文件系统稀疏文件

XML文件导入SQL Server

使用有道词典的童鞋们注意啦.

想问一下大家使用词典的生词本功能时有没有以下的困扰:

1.字体很丑;

2.打印出来格式很乱,设置成自己想要的格式太麻烦;

3.不能复制出来,每次查看都要在电脑上;

 

那么请看下面几步,轻松搞定.

1.选择生词本

 

2.选择导出选项

 

3.导出到某一路径下,:”D:/3.xml”

 

4.打开SQL Server,并执行以下脚本

— 创建保存但成本的数据库

CREATE DATABASE YouDaoWordList

GO

— 创建保存单词本的表

USE YouDaoWordList

GO

CREATE TABLE WordList

(word                VARCHAR(50),

 trans                VARCHAR(50) ,

 phonetic        NVARCHAR(50),

 tags                VARCHAR(50)

)

— 将XML文件导入到SQL Server中

DECLARE @h  int                — 定义xml句柄

DECLARE @doc  xml        — 定义xml对象

SELECT @doc = BulkColumn FROM OPENROWSET (BULK ‘C:/3.xml’, SINGLE_BLOB) AS xmlData        — 获得xml对象

EXECUTE sp_xml_preparedocument @h OUTPUT, @doc        — 获得xml句柄

— 插入表中

INSERT INTO WordList SELECT * FROM OPENXML(@h, ‘/wordbook/item’, 2) with WordList

EXECUTE sp_xml_removedocument @h        — 删除xml句柄

 

5.查询结果,如图所示

— 查询结果

SELECT word, phonetic, trans

FROM WordList

ORDER BY word

GO

 

6.现在就可以复制出来到Word或者Excel,编辑成自己喜欢的格式,打印出来随时翻阅了.

使用TOP限制删除的行

可以使用 TOP 子句限制 DELETE 语句中删除的行数. TOP (n子句与 DELETE 一起使用时,将针对随机选择的第 n 执行删除操作.

例如,下面的语句从 PurchaseOrderDetail 表中删除了其到期日期早于 2002  7  1 日的 20 个随机行.

USE AdventureWorks2008R2;

GO

DELETE TOP (20)

FROM Purchasing.PurchaseOrderDetail

WHERE DueDate < ‘20020701’;

GO

如果需要使用 TOP 来删除按有意义的时间顺序排列的行,您必须同时使用 TOP  ORDER BY 子句.下面的查询从PurchaseOrderDetail 表中删除了其到期日期最早的 10 .为了确保仅删除 10 ,嵌套 Select 语句(PurchaseOrderID) 中指定的列将成为表的主键.如果指定列包含重复的值,则在嵌套 Select 语句中使用非键列可能会导致删除的行超过 10 .

USE AdventureWorks2008R2;

GO

DELETE FROM Purchasing.PurchaseOrderDetail

WHERE PurchaseOrderDetailID IN

(SELECT TOP 10 PurchaseOrderDetailID

FROM Purchasing.PurchaseOrderDetail

ORDER BY DueDate ASC);

GO

如何更改对象所属的架构

如何在架构之间传输安全对象?

语法:ALTER SCHEMA schema_name TRANSFER securable_name

参数

1.schema_name:当前数据库中的架构名称,安全对象将移入其中。其数据类型不能为 SYS INFORMATION_SCHEMA

2.securable_name:要移入架构中的架构包含安全对象的一部分或两部分名称

备注

用户与架构完全分离。有关详细信息,请参阅用户架构分离。

ALTER SCHEMA 仅可用于在同一数据库中的架构之间移动安全对象。若要更改或删除架构中的安全对象,请使用特定于该安全对象的 ALTER 或 DROP 语句。

如果对 securable_name 使用了由一部分组成的名称,则将使用当前生效的名称解析规则查找该安全对象。

将安全对象移入新架构时,将删除与该安全对象关联的全部权限。如果已显式设置安全对象的所有者,则该所有者保持不变。如果安全对象的所有者已设置为 SCHEMA OWNER,则该所有者将保持为 SCHEMA OWNER;但移动之后,SCHEMA OWNER 将解析为新架构的所有者。新所有者的 principal_id 将为 NULL。

注意:从 SQL Server 2005 开始,架构的行为发生了更改。因此,假设架构与数据库用户等价的代码不再返回正确的结果。包含 sysobjects 的旧目录视图不应在曾经使用任何下列 DDL 语句的数据库中使用:CREATE SCHEMA、ALTER SCHEMA、DROP SCHEMA、CREATE USER、ALTER USER、DROP USER、CREATE ROLE、ALTER ROLE、DROP ROLE、CREATE APPROLE、ALTER APPROLE、DROP APPROLE、ALTER AUTHORIZATION。在这类数据库中,必须改用新目录视图。新的目录视图将采用在 SQL Server 2005 中引入的使主体和架构分离的方法

权限

若要从另一个架构中传输安全对象,当前用户必须拥有对该安全对象(非架构)的 CONTROL 权限,并拥有对目标架构的 ALTER 权限。

如果已为安全对象指定 EXECUTE AS OWNER,且所有者已设置为 SCHEMA OWNER,则用户还必须拥有对目标架构所有者的 IMPERSONATION 权限。

在移动安全对象后,将删除与所传输的安全对象相关联的所有权限。

示例

以下示例通过将表 Address 从架构 Person 传输到 HumanResources 架构来修改该架构。

USE AdventureWorks;
GO
ALTER SCHEMA HumanResources TRANSFER Person.Address;
GO

SPARSE列的使用

稀疏列是对 Null 值采用优化的存储方式的普通列.稀疏列减少了 Null 值的空间需求,但代价是检索非 Null 值的开销增加.当至少能够节省 20%  40% 的空间时,才应考虑使用稀疏列.稀疏列和列集是通过使用 CREATE TABLE ALTER TABLE 语句定义的.

稀疏列可以与列集和筛选索引一起使用

1.列集:INSERTUPDATE  DELETE 语句可以通过名称来引用稀疏列.但是,您也可以查看并处理表中组合为一个 XML 列的所有稀疏列.此列称为列集.

2.筛选索引:因为稀疏列有许多 Null 值行,所以尤其适用于筛选索引.稀疏列的筛选索引可以仅仅对已填充值的行编制索引.这会创建一个更小、更有效的索引.

稀疏列和筛选索引使应用程序( Windows SharePoint Services)可以通过 SQL Server 2008 有效地存储和访问大量的用户定义属性.

注意:

下面的数据类型不能指定为 SPARSE

geography

text

geometry

timestamp

image

user-defined data types

ntext

 

创建存储过程时的WITH RECOMPILE 选项

RECOMPILE:

指示数据库引擎不缓存该过程的计划,该过程在运行时编译.如果指定了 FOR REPLICATION,则不能使用此选项.对于CLR 存储过程,不能指定 RECOMPILE.

若要指示数据库引擎放弃存储过程内单个查询的计划,请使用 RECOMPILE 查询提示.如果非典型值或临时值仅用于属于存储过程的查询子集,则使用 RECOMPILE 查询提示.

 

查询提示:

查询提示指定应在整个查询中使用指示的提示.查询提示影响到语句中的所有运算符.如果主查询中涉及 UNION,则只有涉及 UNION 运算符的最后一个查询才能有 OPTION 子句.查询提示作为 OPTION 子句的一部分指定.如果一个或多个查询提示导致查询优化器不能生成有效计划,则引发 8622 错误.

注意:由于 SQL Server 查询优化器通常会为查询选择最佳执行计划,因此我们建议资深开发人员和数据库管理员只有在不得已时才可使用提示.

SCOPE_IDENTITY 函数使用

返回插入到同一作用域中的标识列内的最后一个标识值.一个范围是一个模块:存储过程、触发器、函数或批处理.因此,如果两个语句处于同一个存储过程、函数或批处理中,则它们位于相同的作用域中.

语法:SCOPE_IDENTITY()

返回类型:numeric(38,0)


SCOPE_IDENTITYIDENT_CURRENT  @@IDENTITY 是相似的函数,因为它们都返回插入到标识列中的值.

IDENT_CURRENT 不受作用域和会话的限制,而受限于指定的表.IDENT_CURRENT 返回为任何会话和作用域中的特定表所生成的值.

SCOPE_IDENTITY  @@IDENTITY 返回在当前会话中的任何表内所生成的最后一个标识值.但是,SCOPE_IDENTITY 只返回插入到当前作用域中的值;@@IDENTITY 不受限于特定的作用域.

例如,有两个表 T1  T2,并且在 T1 上定义了 INSERT 触发器.当将某行插入 T1 ,触发器被激发,并在 T2 中插入一行.该方案演示了两个作用域:在 T1 上的插入,以及在 T2 通过触发器的插入.

假设 T1  T2 都有标识列,@@IDENTITY  SCOPE_IDENTITY 将在 T1 上的 INSERT 语句的最后返回不同的值.@@IDENTITY 将返回在当前会话中的任何作用域内插入的最后一个标识列的值.这是在 T2 中插入的值.SCOPE_IDENTITY() 将返回在 T1 中插入的 IDENTITY .这是在同一个作用域内发生的最后的插入.如果在任何 INSERT 语句作用于作用域中的标识列之前调用 SCOPE_IDENTITY() 函数,则该函数将返回 Null.

如果语句和事务失败,它们会更改表的当前标识,从而使标识列中的值出现不连贯现象.即使未提交试图向表中插入值的事务,也永远无法回滚标识值.例如,如果因 IGNORE_DUP_KEY 冲突而导致 INSERT 语句失败,表的当前标识值仍然会增加.

 

示例

A.  @@IDENTITY  SCOPE_IDENTITY 用于触发器

下面的示例创建两个表,TZ  TY,并对 TZ 创建一个 INSERT 触发器.当将某行插入表 TZ 中时,触发器 (Ztrig)将激发并在 TY 中插入一行.

USE tempdb

GO

CREATE TABLE TZ (

Z_id int IDENTITY(1,1)PRIMARY KEY,

Z_name varchar(20) NOT NULL)

 

INSERT TZ

VALUES (‘Lisa’)

INSERT TZ

VALUES (‘Mike’)

INSERT TZ

VALUES (‘Carla’)

 

SELECT * FROM TZ

 

–Result set: This is how table TZ looks.

 

Z_id Z_name

————-

1 Lisa

2 Mike

3 Carla

 

CREATE TABLE TY (

Y_id int IDENTITY(100,5)PRIMARY KEY,

Y_name varchar(20) NULL)

 

INSERT TY (Y_name)

VALUES (‘boathouse’)

INSERT TY (Y_name)

VALUES (‘rocks’)

INSERT TY (Y_name)

VALUES (‘elevator’)

 

SELECT * FROM TY

–Result set: This is how TY looks:

 

Y_id Y_name

—————

100 boathouse

105 rocks

110 elevator

 

/*Create the trigger that inserts a row in table TY

when a row is inserted in table TZ.*/

CREATE TRIGGER Ztrig

ON TZ

FOR INSERT AS

BEGIN

INSERT TY VALUES (”)

END

 

/*FIRE the trigger and determine what identity values you obtain

with the @@IDENTITY and SCOPE_IDENTITY functions.*/

INSERT TZ VALUES (‘Rosalie’)

 

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]

GO

SELECT @@IDENTITY AS [@@IDENTITY]

GO

 

下面是结果集:

SCOPE_IDENTITY

4

/*SCOPE_IDENTITY 返回同一个作用域中的最后一个标识值.这对于表 TZ 是插入操作.*/

@@IDENTITY

115

/*@@IDENTITY 返回由触发器插入到 TY 的最后一个标识值.之所以激发,是因为以前对 TZ 执行了插入.*/

B.  @@IDENTITY  SCOPE_IDENTITY() 用于复制

下面的示例说明如何针对为合并复制发布的数据库中的插入内容使用 @@IDENTITY  SCOPE_IDENTITY().示例中的两个表都在 AdventureWorks2008R2 示例数据库中,其中 Person.ContactType 未发布,Sales.Customer已发布.合并复制将把触发器添加到已发布的表中.因此,@@IDENTITY 可以从复制系统表中的插入内容而非用户表中的插入内容返回值.

Person.ContactType 表的最大标识值为 20.如果在该表中插入一行,@@IDENTITY  SCOPE_IDENTITY() 将返回相同的值.

USE AdventureWorks2008R2;

GO

INSERT INTO Person.ContactType ([Name]) VALUES (‘Assistant to the Manager’);

GO

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];

GO

SELECT @@IDENTITY AS [@@IDENTITY];

GO

 

下面是结果集:

SCOPE_IDENTITY

21

@@IDENTITY

21

Sales.Customer 表的最大标识值为 29483.如果在此表中插入一行,@@IDENTITY  SCOPE_IDENTITY() 将返回不同值.SCOPE_IDENTITY() 从用户表的插入内容返回值, @@IDENTITY 从复制系统表中的插入内容返回值.请对需要访问插入的标识值的应用程序使用 SCOPE_IDENTITY().

INSERT INTO Sales.Customer ([TerritoryID],[PersonID]) VALUES (8,NULL);

GO

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];

GO

SELECT @@IDENTITY AS [@@IDENTITY];

GO

 

下面是结果集:

SCOPE_IDENTITY

29484

@@IDENTITY

89

SqlServer中日期和时间数据类型及函数

日期和时间数据类型

下表列出了 Transact-SQL 的日期和时间数据类型.

数据类型

格式

范围

精确度

存储大小(以字节为单位)

用户定义的秒的小数精度

时区偏移量

time

hh:mm:ss[.nnnnnnn]

00:00:00.0000000 23:59:59.9999999

100 纳秒

5

date

YYYY-MM-DD

0001-01-01  9999-12-31

3

smalldatetime

YYYY-MM-DD hh:mm:ss

1900-01-01  2079-06-06

分钟

4

datetime

YYYY-MM-DD hh:mm:ss[.nnn]

1753-01-01  9999-12-31

0.00333

8

datetime2

YYYY-MM-DD hh:mm:ss[.nnnnnnn]

0001-01-01 00:00:00.0000000 9999-12-31 23:59:59.9999999

100 纳秒

8

datetimeoffset

YYYY-MM-DD hh:mm:ss[.nnnnnnn] [+|-]hh:mm

0001-01-01 00:00:00.0000000 9999-12-31 23:59:59.9999999(以UTC 时间表示)

100 纳秒

10

 

注意:Transact-SQL rowversion 数据类型不是日期或时间数据类型.timestamp  rowversion 的同义词,但不推荐使用.

 

日期和时间函数

用来获取系统日期和时间值的函数

所有系统日期和时间值均得自运行 SQL Server 实例的计算机的操作系统.
精度较高的系统日期和时间函数

SQL Server 2008 使用 GetSystemTimeAsFileTime() Windows API 来获取日期和时间值.精确程度取决于运行 SQL Server 实例的计算机硬件和 Windows 版本. API 的精度固定为 100 纳秒.可通过使用 GetSystemTimeAdjustment() Windows API 来确定该精确度.

函数

语法

返回值

返回数据类型

确定性

SYSDATETIME

SYSDATETIME ()

返回包含计算机的日期和时间的 datetime2(7),SQL Server 的实例正在该计算机上运行.时区偏移量未包含在内.

datetime2(7)

不具有确定性

SYSDATETIMEOFFSET

SYSDATETIMEOFFSET ( )

返回包含计算机的日期和时间的datetimeoffset(7),SQL Server 的实例正在该计算机上运行.时区偏移量包含在内.

datetimeoffset(7)

不具有确定性

SYSUTCDATETIME

SYSUTCDATETIME ( )

返回包含计算机的日期和时间的 datetime2(7),SQL Server 的实例正在该计算机上运行.日期和时间作为 UTC 时间(通用协调时间)返回.

datetime2(7)

不具有确定性


精度较低的系统日期和时间函数

函数

语法

返回值

返回数据类型

确定性

CURRENT_TIMESTAMP

CURRENT_TIMESTAMP

返回包含计算机的日期和时间的datetime2(7) ,SQL Server的实例正在该计算机上运行.时区偏移量未包含在内.

datetime

不具有确定性

GETDATE

GETDATE ( )

返回包含计算机的日期和时间的datetime2(7) ,SQL Server的实例正在该计算机上运行.时区偏移量未包含在内.

datetime

不具有确定性

GETUTCDATE

GETUTCDATE ( )

返回包含计算机的日期和时间的datetime2(7) ,SQL Server的实例正在该计算机上运行.日期和时间作为 UTC 时间(通用协调时间)返回.

datetime

不具有确定性

用来获取日期和时间部分的函数

函数

语法

返回值

返回数据类型

确定性

DATENAME

DATENAME ( datepartdate )

返回表示指定日期的指定datepart 的字符串.

nvarchar

不具有确定性

DATEPART

DATEPART ( datepartdate )

返回表示指定 date 的指定datepart 的整数.

int

不具有确定性

DAY

DAY ( date )

返回表示指定 date 部分的整数.

int

具有确定性

MONTH

MONTH ( date )

返回表示指定 date 部分的整数.

int

具有确定性

YEAR

YEAR ( date )

返回表示指定 date 部分的整数.

int

具有确定性

用来获取日期和时间差的函数

函数

语法

返回值

返回数据类型

确定性

DATEDIFF

DATEDIFF ( datepart ,startdate , enddate )

返回两个指定日期之间所跨的日期或时间 datepart 边界的数目.

int

具有确定性

用来修改日期和时间值的函数

函数

语法

返回值

返回数据类型

确定性

DATEADD

DATEADD (datepartnumber date )

通过将一个时间间隔与指定date 的指定 datepart相加,返回一个新的datetime .

date 参数的数据类型.

具有确定性

SWITCHOFFSET

SWITCHOFFSET(DATETIMEOFFSET ,time_zone)

SWITCH OFFSET 更改DATETIMEOFFSET 值的时区偏移量并保留 UTC .

具有DATETIMEOFFSET的小数精度的datetimeoffset

具有确定性

TODATETIMEOFFSET

TODATETIMEOFFSET (expression ,time_zone)

TODATETIMEOFFSET datetime2 值转换为datetimeoffset.datetime2 值被解释为指定 time_zone 的本地时间.

具有 datetime 参数的小数精度的datetimeoffset

具有确定性

用来设置或获取会话格式的函数

函数

语法

返回值

返回数据类型

确定性

@@DATEFIRST

@@DATEFIRST

返回对会话进行 SET DATEFIRST操作所得结果的当前值.

tinyint

不具有确定性

SET DATEFIRST

SET DATEFIRST {number |@number_var }

将一周的第一天设置为从 1  7 的一个数字.

不适用

不适用

SET DATEFORMAT

SET DATEFORMAT {format |@format_var }

设置用于输入 datetime smalldatetime 数据的日期各部分(月//年)的顺序.

不适用

不适用

@@LANGUAGE

@@LANGUAGE

返回当前使用的语言的名称.@@LANGUAGE 不是日期或时间函数.但是,语言设置会影响日期函数的输出.

不适用

不适用

SET LANGUAGE

SET LANGUAGE { [ N ] language |@language_var }

设置会话和系统消息的语言环境.SET LANGUAGE 不是日期或时间函数.但是,语言设置会影响日期函数的输出.

不适用

不适用

sp_helplanguage

sp_helplanguage [ [@language = ]language ]

返回有关所有支持语言日期格式的信息.sp_helplanguage 不是日期或时间存储过程.但是,语言设置会影响日期函数的输出.

不适用

不适用

用来验证日期和时间值的函数

函数

语法

返回值

返回数据类型

确定性

ISDATE

ISDATE (expression )

确定 datetime smalldatetime 输入表达式是否为有效的日期或时间值.

int

只有与 CONVERT 函数一起使用,同时指定了 CONVERT 样式参数且样式不等于 0,100,9  109,ISDATE 才是确定的.

 

日期和时间相关主题

主题

说明

使用日期和时间数据

提供通用于日期和时间数据类型及函数的信息和示例.

CAST  CONVERT (Transact-SQL)

提供有关在日期和时间值与字符串文字及其他日期和时间格式之间进行相互转换的信息.

编写国际化 Transact-SQL 语句

提供使用 Transact-SQL 语句的数据库和数据库应用程序在不同语言之间的可移植性准则,或支持多种语言的数据库和数据库应用程序的可移植性准则.

ODBC 标量函数(Transact-SQL)

提供有关可在 Transact-SQL 语句中使用的 ODBC 标量函数的信息.这包括ODBC 日期和时间函数.

分布式查询的数据类型映射

提供有关以下方面的信息:日期和时间数据类型对具有不同版本的 SQL Server 或不同访问接口的服务器之间的分布式查询有何影响.

Common Table Expression (CTE)

指定临时命名的结果集,这些结果集称为公用表表达式 (CTE).该表达式源自简单查询,并且在单条SELECT,INSERT,UPDATE,MERGE  DELETE 语句的执行范围内定义.该子句也可用在 CREATE VIEW 语句中,作为该语句的 SELECT 定义语句的一部分.公用表表达式可以包括对自身的引用.这种表达式称为递归公用表表达式.

 

语法

[ WITH <common_table_expression> [ ,…] ]

 

<common_table_expression>::=

        expression_name [ ( column_name [ ,…] ) ]

    AS

        ( CTE_query_definition )

参数

expression_name

公用表表达式的有效标识符. expression_name 必须与在同一 WITH <common_table_expression> 子句中定义的任何其他公用表表达式的名称不同, expression_name 可以与基表或基视图的名称相同.在查询中对 expression_name 的任何引用都会使用公用表表达式,而不使用基对象.

column_name

在公用表表达式中指定列名.在一个 CTE 定义中不允许出现重复的名称.指定的列名数必须与CTE_query_definition 结果集中列数匹配.只有在查询定义中为所有结果列都提供了不同的名称时,列名称列表才是可选的.

CTE_query_definition

指定一个其结果集填充公用表表达式的 SELECT 语句.除了 CTE 不能定义另一个 CTE 以外,CTE_query_definition  SELECT 语句必须满足与创建视图时相同的要求.

如果定义了多个 CTE_query_definition,则这些查询定义必须用下列一个集合运算符联接起来:UNION ALL,UNION,EXCEPT  INTERSECT.

注释

创建和使用公用表表达式的准则

下面的准则适用于非递归公用表表达式.

  • CTE 之后必须跟随引用部分或全部 CTE 列的单条 SELECT,INSERT,UPDATE,MERGE  DELETE 语句.也可以在 CREATE VIEW 语句中将 CTE 指定为视图中 SELECT 定义语句的一部分.
  • 可以在非递归 CTE 中定义多个 CTE 查询定义.定义必须与以下集合运算符之一结合使用:UNION ALL,UNION,INTERSECT  EXCEPT.
  • CTE 可以引用自身,也可以引用在同一 WITH 子句中预先定义的 CTE.不允许前向引用.
  • 不允许在一个 CTE 中指定多个 WITH 子句.例如,如果 CTE_query_definition 包含一个子查询,则该子查询不能包括定义另一个 CTE 的嵌套的 WITH 子句.
  • 不能在 CTE_query_definition 中使用以下子句:
    • COMPUTE  COMPUTE BY
    • ORDER BY(除非指定了 TOP 子句)
    • INTO
    • 带有查询提示的 OPTION 子句
    • FOR XML
    • FOR BROWSE
  • 如果将 CTE 用在属于批处理的一部分的语句中,那么在它之前的语句必须以分号结尾.
  • 可以使用引用 CTE 的查询来定义游标.
  • 可以在 CTE 中引用远程服务器中的表.
  • 在执行 CTE ,任何引用 CTE 的提示都可能与该 CTE 访问其基础表时发现的其他提示相冲突,这种冲突与引用查询中的视图的提示所发生的冲突相同.发生这种情况时,查询将返回错误.
  •  CTE  UPDATE 语句的目标时,在该语句中对 CTE 的所有引用都必须匹配.例如,如果在 FROM 子句中向 CTE 分配了一个别名,则该别名必须用于对 CTE 的所有其他引用.不明确的 CTE 引用可能会产生意外的联接行为和意外的查询结果.

 

定义和使用递归公用表表达式的准则

下面的准则适用于定义递归公用表表达式:

  • 递归 CTE 定义至少必须包含两个 CTE 查询定义,一个定位点成员和一个递归成员.可以定义多个定位点成员和递归成员;但必须将所有定位点成员查询定义置于第一个递归成员定义之前.所有 CTE 查询定义都是定位点成员,但它们引用 CTE 本身时除外.
  • 定位点成员必须与以下集合运算符之一结合使用:UNION ALL,UNION,INTERSECT  EXCEPT.在最后一个定位点成员和第一个递归成员之间,以及组合多个递归成员时,只能使用 UNION ALL 集合运算符.
  • 定位点成员和递归成员中的列数必须一致.
  • 递归成员中列的数据类型必须与定位点成员中相应列的数据类型一致.
  • 递归成员的 FROM 子句只能引用一次 CTE expression_name.
  • 在递归成员的 CTE_query_definition 中不允许出现下列项:
    • SELECT DISTINCT
    • GROUP BY
    • HAVING
    • 标量聚合
    • TOP
    • LEFT,RIGHT,OUTER JOIN(允许出现 INNER JOIN)
    • 子查询
    • 应用于对 CTE_query_definition 中的 CTE 的递归引用的提示.

 

下面的准则适用于使用递归公用表表达式:

  • 无论参与的 SELECT 语句返回的列的为 Null 性如何,递归 CTE 返回的全部列都可以为空.
  • 如果递归 CTE 组合不正确,可能会导致无限循环.例如,如果递归成员查询定义对父列和子列返回相同的值,则会造成无限循环.可以使用 MAXRECURSION 提示以及在 INSERT,UPDATE,MERGE,DELETE SELECT 语句的 OPTION 子句中的一个 0  32,767 之间的值,来限制特定语句所允许的递归级数,以防止出现无限循环.这样就能够在解决产生循环的代码问题之前控制语句的执行.服务器范围的默认值为100.如果指定 0,则没有限制.每一个语句只能指定一个 MAXRECURSION .
  • 不能使用包含递归公用表表达式的视图来更新数据.
  • 可以使用 CTE 在查询上定义游标.CTE 是定义游标结果集的 select_statement 参数.递归 CTE 只允许使用快速只进游标和静态(快照)游标.如果在递归 CTE 中指定了其他游标类型,则该类型将转换为静态游标类型.
  • 可以在 CTE 中引用远程服务器中的表.如果在 CTE 的递归成员中引用了远程服务器,那么将为每个远程表创建一个假脱机,这样就可以在本地反复访问这些表.如果为 CTE 查询,Index Spool/Lazy Spool 则显示在查询计划中,并具有额外的 WITH STACK 谓词.这是一种确认正确递归的方法.
  • SQL Server 2008 不允许在 CTE 的递归部分中使用分析和聚合函数.

 

 

示例

A. 创建一个简单公用表表达式

以下示例显示直接向 Adventure Works Cycles 的每个经理报告的雇员的数目.

USE AdventureWorks2008R2;
GO

WITH Sales_CTE (SalesPersonID, NumberOfOrders)
AS
(
SELECT SalesPersonID, COUNT(*)
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID
)

SELECT SalesPersonID, NumberOfOrders
FROM Sales_CTE
ORDER BY SalesPersonID;
GO

B. 使用公用表表达式来限制次数和报告平均数

以下示例显示向经理报告的雇员的平均数.

WITH Sales_CTE (SalesPersonID, NumberOfOrders)
AS
(
SELECT SalesPersonID, COUNT(*)
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID
)
SELECT AVG(NumberOfOrders) AS “Average Sales Per Person”
FROM Sales_CTE;
GO

C. 多次引用同一个公用表表达式

以下示例显示 SalesOrderHeader 表中每个销售人员的销售订单的总数和最近的销售订单的日期.CTE 在运行的语句中被引用两次:一次返回为销售人员所选的列,另一次检索销售经理的类似详细信息.销售人员和销售经理的数据都返回在一行中.

USE AdventureWorks2008R2;
GO
— Define the CTE expression name and column list.
WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear)
AS
— Define the CTE query.
(
SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
)
— Define the outer query referencing the CTE name.
SELECT SalesPersonID, COUNT(SalesOrderID) AS TotalSales, SalesYear
FROM Sales_CTE
GROUP BY SalesYear, SalesPersonID
ORDER BY SalesPersonID, SalesYear;
GO

使用递归公用表表达式显示递归的多个级别.

以下示例显示经理以及向经理报告的雇员的层次列表.

USE AdventureWorks2008R2;
GO
WITH DirectReports(ManagerID, EmployeeID, Title, EmployeeLevel) AS
(
SELECT ManagerID, EmployeeID, Title, 0 AS EmployeeLevel
FROM dbo.MyEmployees
WHERE ManagerID IS NULL
UNION ALL
SELECT e.ManagerID, e.EmployeeID, e.Title, EmployeeLevel + 1
FROM dbo.MyEmployees AS e
INNER JOIN DirectReports AS d
ON e.ManagerID = d.EmployeeID
)
SELECT ManagerID, EmployeeID, Title, EmployeeLevel
FROM DirectReports
ORDER BY ManagerID;
GO

E. 使用递归公用表表达式显示递归的两个级别.

以下示例显示经理以及向经理报告的雇员.将返回的级别数目被限制为两个.

USE AdventureWorks2008R2;
GO
WITH DirectReports(ManagerID, EmployeeID, Title, EmployeeLevel) AS
(
SELECT ManagerID, EmployeeID, Title, 0 AS EmployeeLevel
FROM dbo.MyEmployees
WHERE ManagerID IS NULL
UNION ALL
SELECT e.ManagerID, e.EmployeeID, e.Title, EmployeeLevel + 1
FROM dbo.MyEmployees AS e
INNER JOIN DirectReports AS d
ON e.ManagerID = d.EmployeeID
)
SELECT ManagerID, EmployeeID, Title, EmployeeLevel
FROM DirectReports
WHERE EmployeeLevel <= 2 ;
GO

F. 使用递归公用表表达式显示层次列表

以下示例在示例 C 的基础上添加经理和雇员的名称,以及他们各自的头衔.通过缩进各个级别,突出显示经理和雇员的层次结构.

USE AdventureWorks2008R2;
GO
WITH DirectReports(Name, Title, EmployeeID, EmployeeLevel, Sort)
AS (SELECT CONVERT(varchar(255), e.FirstName + ‘ ‘ + e.LastName),
e.Title,
e.EmployeeID,
1,
CONVERT(varchar(255), e.FirstName + ‘ ‘ + e.LastName)
FROM dbo.MyEmployees AS e
WHERE e.ManagerID IS NULL
UNION ALL
SELECT CONVERT(varchar(255), REPLICATE (‘|    ‘ , EmployeeLevel) +
e.FirstName + ‘ ‘ + e.LastName),
e.Title,
e.EmployeeID,
EmployeeLevel + 1,
CONVERT (varchar(255), RTRIM(Sort) + ‘|    ‘ + FirstName + ‘ ‘ +
LastName)
FROM dbo.MyEmployees AS e
JOIN DirectReports AS d ON e.ManagerID = d.EmployeeID
)
SELECT EmployeeID, Name, Title, EmployeeLevel
FROM DirectReports
ORDER BY Sort;
GO

G. 使用 MAXRECURSION 取消一条语句

可以使用 MAXRECURSION 来防止不合理的递归 CTE 进入无限循环.以下示例特意创建了一个无限循环,然后使用MAXRECURSION 提示将递归级别限制为两级.

USE AdventureWorks2008R2;
GO
–Creates an infinite loop
WITH cte (EmployeeID, ManagerID, Title) as
(
SELECT EmployeeID, ManagerID, Title
FROM dbo.MyEmployees
WHERE ManagerID IS NOT NULL
UNION ALL
SELECT cte.EmployeeID, cte.ManagerID, cte.Title
FROM cte
JOIN  dbo.MyEmployees AS e
ON cte.ManagerID = e.EmployeeID
)
–Uses MAXRECURSION to limit the recursive levels to 2
SELECT EmployeeID, ManagerID, Title
FROM cte
OPTION (MAXRECURSION 2);
GO

 

在更正代码错误之后,就不再需要 MAXRECURSION.以下示例显示了更正后的代码.

USE AdventureWorks2008R2;
GO
WITH cte (EmployeeID, ManagerID, Title)
AS
(
SELECT EmployeeID, ManagerID, Title
FROM dbo.MyEmployees
WHERE ManagerID IS NOT NULL
UNION ALL
SELECT  e.EmployeeID, e.ManagerID, e.Title
FROM dbo.MyEmployees AS e
JOIN cte ON e.ManagerID = cte.EmployeeID
)
SELECT EmployeeID, ManagerID, Title
FROM cte;
GO

 

H. 使用公用表表达式来有选择地执行 SELECT 语句中的递归操作

以下示例显示了为 ProductAssemblyID = 800 生产自行车所需的产品装配和部件层次结构.

USE AdventureWorks2008R2;
GO
WITH Parts(AssemblyID, ComponentID, PerAssemblyQty, EndDate, ComponentLevel) AS
(
SELECT b.ProductAssemblyID, b.ComponentID, b.PerAssemblyQty,
b.EndDate, 0 AS ComponentLevel
FROM Production.BillOfMaterials AS b
WHERE b.ProductAssemblyID = 800
AND b.EndDate IS NULL
UNION ALL
SELECT bom.ProductAssemblyID, bom.ComponentID, p.PerAssemblyQty,
bom.EndDate, ComponentLevel + 1
FROM Production.BillOfMaterials AS bom
INNER JOIN Parts AS p
ON bom.ProductAssemblyID = p.ComponentID
AND bom.EndDate IS NULL
)
SELECT AssemblyID, ComponentID, Name, PerAssemblyQty, EndDate,
ComponentLevel
FROM Parts AS p
INNER JOIN Production.Product AS pr
ON p.ComponentID = pr.ProductID
ORDER BY ComponentLevel, AssemblyID, ComponentID;
GO

I.  UPDATE 语句中使用递归 CTE

以下示例为直接或间接用于创建 ProductAssemblyID 800 的所有部件和组件更新 PerAssemnblyQty .公用表表达式将返回用于直接生成 ProductAssemblyID 800 的部件和用于生成这些组件的部件等的列表.只修改公用表表达式所返回的行.

USE AdventureWorks2008R2;
GO
WITH Parts(AssemblyID, ComponentID, PerAssemblyQty, EndDate, ComponentLevel) AS
(
SELECT b.ProductAssemblyID, b.ComponentID, b.PerAssemblyQty,
b.EndDate, 0 AS ComponentLevel
FROM Production.BillOfMaterials AS b
WHERE b.ProductAssemblyID = 800
AND b.EndDate IS NULL
UNION ALL
SELECT bom.ProductAssemblyID, bom.ComponentID, p.PerAssemblyQty,
bom.EndDate, ComponentLevel + 1
FROM Production.BillOfMaterials AS bom
INNER JOIN Parts AS p
ON bom.ProductAssemblyID = p.ComponentID
AND bom.EndDate IS NULL
)
UPDATE Production.BillOfMaterials
SET PerAssemblyQty = c.PerAssemblyQty * 2
FROM Production.BillOfMaterials AS c
JOIN Parts AS d ON c.ProductAssemblyID = d.AssemblyID
WHERE d.ComponentLevel = 0;

使用多个定位点和递归成员

以下示例使用多个定位点和递归成员来返回指定的人的所有祖先.创建了一个表,并在表中插入值,以建立由递归 CTE 返回的宗谱.

— Genealogy table
IF OBJECT_ID(‘dbo.Person’,’U’) IS NOT NULL DROP TABLE dbo.Person;
GO
CREATE TABLE dbo.Person(ID int, Name varchar(30), Mother int, Father int);
GO
INSERT dbo.Person
VALUES(1, ‘Sue’, NULL, NULL)
,(2, ‘Ed’, NULL, NULL)
,(3, ‘Emma’, 1, 2)
,(4, ‘Jack’, 1, 2)
,(5, ‘Jane’, NULL, NULL)
,(6, ‘Bonnie’, 5, 4)
,(7, ‘Bill’, 5, 4);
GO
— Create the recursive CTE to find all of Bonnie’s ancestors.
WITH Generation (ID) AS
(
— First anchor member returns Bonnie’s mother.
SELECT Mother
FROM dbo.Person
WHERE Name = ‘Bonnie’
UNION
— Second anchor member returns Bonnie’s father.
SELECT Father
FROM dbo.Person
WHERE Name = ‘Bonnie’
UNION ALL
— First recursive member returns male ancestors of the previous generation.
SELECT Person.Father
FROM Generation, Person
WHERE Generation.ID=Person.ID
UNION ALL
— Second recursive member returns female ancestors of the previous generation.
SELECT Person.Mother
FROM Generation, dbo.Person
WHERE Generation.ID=Person.ID
)
SELECT Person.ID, Person.Name, Person.Mother, Person.Father
FROM Generation, dbo.Person
WHERE Generation.ID = Person.ID;
GO

UPDATE SET FROM 语句

有这样一个需求:两个表ab,想使b中的memo字段值等于a表中对应id的name值  

a:

id

name  

1

Kobe

2

Jordon

3

Yao

b:

id

memo

1

 

2

 

3

 

T-SQL语句:UPDATE b SET b.memo = a.name FROM a, b WHERE a.id = b.id

 

UPDATE SET FROM 语句格式

WHERESET都需要关联一个表进行查询时,整个UPDATE执行时,就需要对被关联的表进行两次扫描,显然效率比较低.

对于这种情况Sybase和SQL SERVER的解决办法是使用UPDATE…SET…FROM…WHERE…的语法,实际上就是从源表获取更新数据.

T-SQL中,表连接(LEFT JOIN, RIGHT JOIN, INNER JOIN)等常常用于SELECT语句,其实在T-SQL语法中,这些连接也是可以用于UPDATEDELETE语句的,在这些语句中使用JOIN还常常得到事半功倍的效果.

UPDATE b SET b.memo = a.name FROM b LEFT JOIN a ON a.id = b.id

如果需要更新多个字段的话使用:

UPDATE A  SET A1 = B1, A2 = B2, A3 = B3  FROM A LEFT JOIN B ON A.ID = B.ID

或者:

UPDATE A SET A1 = B1, A2 = B2, A3 = B3 FROM A, B WHERE A.ID = B.ID

防止表被删除的触发器

问题:如何防止数据库中表被删除,除了控制权限(登录账户没有删除表的权限)之外还可以通过创建触发器实现

创建触发器方法:

1.创建一个数据库级别的触发器,防止表被误删除

 

2.当删除表时会有如下图提示:

 

如何保存数据库级别修改的记录

前几天在论坛上发了一个帖子”SQL Server 2008如何查看表结构修改记录“,很感谢马上有人热心回复并给出建议,现在我把问题的原因和到最后的解决办法与大家分享,希望对大家有帮助.

问题:上午一上班就有用户打电话说系统出了问题,第一反应是马上去看系统是否有BUG,经过测试之后发现系统是完全没有问题的,但是原来能使用此页面的用户竟然都没有了权限,再次DEBUG系统时,发现从数据库的权限表里拿到的数据都是乱码,推测应该是有人修改了表的”排序规则”,使得中文部分都变成了问号,最郁闷的是查看日志之后也不知道是谁修改的,赶紧先把数据库恢复,之后分析原因主要有以下几点:

1.对数据库权限粒度划分不明确;

2.对数据库修改的日志没有记录;

解决办法:

1.创建数据库修改日志表(如何害怕不小心被删除,可以参考防止表被删除的触发器)

  1. USE [QSBN]
  2. GO
  3. SET ANSI_NULLS ON
  4. GO
  5. SET QUOTED_IDENTIFIER ON
  6. GO
  7. — 创建数据库修改日志表
  8. CREATE TABLE dbo.[DatabaseModifiedLog](
  9.          [ID] INT           IDENTITY(1,1) NOT NULL,
  10.          [EventType]        NVARCHAR(500) NULL,
  11.          [PostTime]         DATETIME NULL,
  12.          [ClientUser]       NVARCHAR(10) NULL,
  13.          [ServerName]       NVARCHAR(250) NULL,
  14.          [LoginName]        NVARCHAR(250) NULL,
  15.          [UserName]         NVARCHAR(250) NULL,
  16.          [DatabaseName]     NVARCHAR(250) NULL,
  17.          [SchemaName]       NVARCHAR(250) NULL,
  18.          [ObjectName]       NVARCHAR(250) NULL,
  19.          [ObjectType]       NVARCHAR(250) NULL,
  20.          [CommandText]      NVARCHAR(MAX) NULL,
  21.          [EventData]        XML NULL,
  22. PRIMARY KEY CLUSTERED
  23. ([ID] ASC)
  24. WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  25. )ON [PRIMARY]
  26. GO

2.创建数据库级别的触发器

  1. — 创建数据库级别的触发器
  2. CREATE TRIGGER [DataBase_DDL_TRIGGER]
  3. ON DATABASE
  4. FOR DDL_DATABASE_LEVEL_EVENTS
  5. AS
  6.   DECLARE @EventData        XML
  7.   DECLARE @EventType        NVARCHAR(250)
  8.   DECLARE @PostTime         DATETIME
  9.   DECLARE @SPID             NVARCHAR(6)
  10.   DECLARE @ClientUser       NVARCHAR(50)
  11.   DECLARE @ServerName       NVARCHAR(250)
  12.   DECLARE @LoginName        NVARCHAR(250)
  13.   DECLARE @UserName         NVARCHAR(250)
  14.   DECLARE @DatabaseName     NVARCHAR(250)
  15.   DECLARE @SchemaName       NVARCHAR(250)
  16.   DECLARE @ObjectName       NVARCHAR(250)
  17.   DECLARE @ObjectType       NVARCHAR(250)
  18.   DECLARE @CommandText      NVARCHAR(MAX)
  19.   SET @EventData = EVENTDATA();
  20.   SET @EventType = @EventData.value(‘(/EVENT_INSTANCE[1]/EventType[1])’, ‘NVARCHAR(250)’)
  21.   SET @PostTime = @EventData.value(‘(/EVENT_INSTANCE[1]/PostTime[1])’, ‘DATETIME’)
  22.   SET @SPID = @EventData.value(‘(/EVENT_INSTANCE[1]/SPID[1])’, ‘NVARCHAR(6)’)
  23.   SELECT @ClientUser = hostname FROM master..sysprocesses WHERE spid = @SPID
  24.   SET @ServerName = @EventData.value(‘(/EVENT_INSTANCE[1]/ServerName[1])’, ‘NVARCHAR(250)’)
  25.   SET @LoginName = @EventData.value(‘(/EVENT_INSTANCE[1]/LoginName[1])’, ‘NVARCHAR(250)’)
  26.   SET @UserName = @EventData.value(‘(/EVENT_INSTANCE[1]/UserName[1])’, ‘NVARCHAR(250)’)
  27.   SET @DatabaseName = @EventData.value(‘(/EVENT_INSTANCE[1]/DatabaseName[1])’, ‘NVARCHAR(250)’)
  28.   SET @SchemaName  = @EventData.value(‘(/EVENT_INSTANCE[1]/SchemaName[1])’, ‘NVARCHAR(250)’)
  29.   SET @ObjectName = @EventData.value(‘(/EVENT_INSTANCE[1]/ObjectName[1])’, ‘NVARCHAR(250)’)
  30.   SET @ObjectType = @EventData.value(‘(/EVENT_INSTANCE[1]/ObjectType[1])’, ‘NVARCHAR(250)’)
  31.   SET @CommandText = @EventData.value(‘(/EVENT_INSTANCE[1]/TSQLCommand[1]/CommandText[1])’, ‘NVARCHAR(MAX)’)
  32. — 将记录插入到数据库
  33. INSERT INTO [dbo].[DatabaseModifiedLog]
  34.            ([EventType]
  35.            ,[PostTime]
  36.            ,[ClientUser]
  37.            ,[ServerName]
  38.            ,[LoginName]
  39.            ,[UserName]
  40.            ,[DatabaseName]
  41.            ,[SchemaName]
  42.            ,[ObjectName]
  43.            ,[ObjectType]
  44.            ,[CommandText]
  45.            ,[EventData])
  46.      VALUES
  47.            (@EventType
  48.            ,@PostTime
  49.            ,@ClientUser
  50.            ,@ServerName
  51.            ,@LoginName
  52.            ,@UserName
  53.            ,@DatabaseName
  54.            ,@SchemaName
  55.            ,@ObjectName
  56.            ,@ObjectType
  57.            ,@CommandText
  58.            ,@EventData)
  59. GO
  60. SET ANSI_NULLS OFF
  61. GO
  62. SET QUOTED_IDENTIFIER OFF
  63. GO
  64. DISABLE TRIGGER [DataBase_DDL_TRIGGER] ON DATABASE
  65. GO
  66. ENABLE TRIGGER [DataBase_DDL_TRIGGER] ON DATABASE
  67. GO

3.执行DDL语句之后,查看日志表中数据,如图:

SQLServer2008阻止保存要求重新创建表的更改

问题:当用户在在SQL Server 2008企业管理器中更改表结构时,必须要先删除原来的表,然后重新创建新表,才能完成表的更改,如果强行更改会出现以下提示:不允许保存更改.您所做的更改要求删除并重新创建以下表.您对无法重新创建的标进行了更改或者启用了”阻止保存要求重新创建表的更改”选项,如图:

解决办法:

1.打开SQL Server 2008选择”工具”菜单,选择”选项”,如图:

 

2.选择”Desgners(设计器)”菜单中的”表设计器和数据库设计器”选项,看到”表选项”中的”组织保存要求重新创建表的更改”选项是选中状态,如图:

 

3.勾选掉此选项,点击确定即可.如图:

SqlServer数据库访问Oracle数据库

最近要实现一段业务,把Sqlserver数据库中表的数据作为条件在Oracle核心库中查询到相应的数据,然后再在SqlServer数据库中做统计信息.所以要实现Sqlserver数据库到Oracle的DBlink把数据从Oracle数据库中拉出来.
 

准备工作:

1.必须安装SqlServer数据库;
2.要有Oracle的客户端,客户端版本不低于Oracle数据库的版本;
3.配置tnsnames.ora文件(路径:$ORACLE_HOME$\db_1\NETWORK\ADMIN\tnsnames.ora)
OrclDBLink =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.2)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = ORCL.SNDA.COM)
    )
  )
4.测试tns配置是否成功,使用sqlplus命名在命令行窗口登录,如果能够登录成功说明tnsname.ora配置正确.
  
 
创建连接服务器
1.在常规页面配置,如图:
  
2.在安全性页面配置,如图:
  
 
测试访问Oracle数据库
1.SELECT * FROM DBLINK..HR.EMPLOYEES; 此查询对象要用大写,如果查询某个字段也要使用大写,连接服务器后面是两点[..]
2.SELECT * FROM 
openquery(DBLINK, ‘SELECT * FROM HR.EMPLOYEES’);此方法比上一种方法快50%,此方法跟直接连Oracle的速度相当.

单独还原个别文件操作

创建数据库与多个文件组,在各个文件组中放置不同的数据表,故意损坏其中一个文件后,

通过设置,可以让改数据库内其它完好的文件组继续提供访问,并经过还原备份数据,可以单独回复该数据文件与文件组

 

1.创建NWind测试数据库,并添加3个文件组

  

 

 

2.在不同的FileGroup中分别放置一个数据表

3.查看各个数据表所属的FileGroup

4.分析各个数据文件的属性

 

 

5.向数据库中插入数据

  

6.分析各个表中的数据

  

 

 

7.备份NWind数据库

 

 

8.暂停MSSQLSERVER服务,并删掉NWind_B.ndf文件模拟数据库损坏

 

 

9.出现错误

 

 

10.检查NWind数据库处于RECOVERY_PENDING状态

 

11.设置文件NWind_B为OFFLINE,并设置NWind数据库状态为ONLINE

 

12.分析各个数据文件的在线状态

 

 

13.分析各个表的数据,查询TbB时候出错

 

14.向数据库中插入数据,TbB中插入数据时出错

 

15.备份日志文件

NO_TRUNCATE 指定不截断日志,并使数据库引擎尝试执行备份,而不考虑数据库的状态.

因此,使用 NO_TRUNCATE 执行的备份可能具有不完整的元数据.该选项允许在数据库损坏时备份日志.

BACKUP LOG 的 NO_TRUNCATE 选项相当于同时指定 COPY_ONLY 和 CONTINUE_AFTER_ERROR.

如果不使用 NO_TRUNCATE 选项,则数据库必须联机.

 

16.查询备份文件的头信息

 

17.查询备份文件的文件信息

 

18.还原损坏的数据库

 

19.分析各个数据文件的属性,Nwind_B处于RESTORING状态

20.还原NWind的日志文件

21.分析各个数据文件的属性

 

22.分析各个表中的数据

Database Mirroring

试验目标:创建Database Mirroring

准备工作:

1.准备3台数据库实例

  • WIN-9JFNLS74727为主服务器
  • WIN-9JFNLS74727/SQLSERVER_R2_S01为镜像服务器
  • WIN-9JFNLS74727/SQLSERVER_R2_S02为见证服务器

         

2.在主服务器上创建DB_Mirror示例数据库,并设置示例数据库的RECOVERY MODEL为FULL

3.备份主服务器上的DB_Mirror示例数据库

  

4.将DB_Mirror示例数据库的备份文件以WITH NORECOVERY模式还原至镜像服务器,以承接后续的事务数据

 

实验步骤

1.创建端点:

  • SQL Server Management Studio主服务器的DB_Mirror数据库中,单击右键选择属性选项,然后在数据库属性对话框中选择镜像页签,如图:

  • 在单击配置安全性按钮,弹出设置数据库镜像安全向导对话框,包括见证服务器窗口中选择如图所示:

  • 分别设置主体,镜像和见证服务器,首先是主体服务器的端点名称侦听器端口(默认5022)”,如图:

  • 设置镜像服务器的端点名称侦听器端口(默认5023)”,如图:

  • 设置见证服务器的端点名称侦听器端口(默认5024)”,如图:

  • 显示配置信息

  • 显示配置成功

2.创建镜像连接

  • 创建成功后向导会询问是否要启动镜像,可以立即启动或者事后再启动

  • 服务器网络地址:显示了3个服务器(主体,镜像,见证)端点路径及通信端口
  • 运行模式:
    • 高性能模式:不需要见证服务器,采用异步操作,有数据遗失的风险
    • 高保护模式:不需要见证服务器,采用同步操作,没有数据遗失的风险,但是主体发生异常时必须手动转移至镜像服务器
    • 高可用模式:需要有见证服务器,采用同步操作,没有数据遗失的风险,如果主体发生异常可以自动转移至镜像服务器
  • 镜像机制开始运行

3.验证数据库镜像

  • 在主体服务器上创建表及数据

  • 点击故障转移“,如图

  • 验证镜像服务器中数据

master数据库的备份与恢复

master数据库内保存了SQL Server最重要的信息,主要包括:

1.服务器系统配置

2.用户登录账户

3.用户数据库的配置及文件位置

 

master数据库备份的原则是:只要SQL Server系统配置有任何更改或者执行各项数据库管理工作,都要备份master数据库

1.创建或者删除数据库

2.新建或者移除文件和文件组

3.新建SQL Server登录账户或变更安全性设置

4.更改SQL Server服务器级别设置,或者数据库配置选项

5.创建或者移除备份设备

6.配置SQL Server分布式查询与远程调用(RPC)功能

 

master数据库还原步骤

1.执行setup.exe重建master数据库

2.以’单一用户模式’启动SQL Server实例

3.利用最近一次的备份数据还原master数据库

4.重新启动SQL Server实例

 

在SQL Server 2008中,如果需要重新创建master数据库,必须利用SQL Server的安装程序从命令行执行setup.exe,语法为:

setup.exe /QUIET /INSTANCENAME=MSSQLSERVER /ACTION=REBUILDDATABASE /SQLSYSADMINACCOUNTS=Administrator /SAPWD=…

/QUIET:setup.exe工具程序不呈现互动画面,直接完成指令所要求的工作

/INSTANCENAME:目标实例名称,如果是默认实例则为MSSQLSERVER

/ACTION:要setup.exe执行的工作,此处REBUILDDATABASE选项代表要创建系统数据库

/SQLSYSADMINACCOUNTS:管理SQL Server实例的Windows账户

/SAPWD:若SQL Server的验证采用混合验证模式,则通过这个参数给定sa账户的密码,要满足复杂度

SQL Server 2008后setup.exe工具程序在路径 C:/Program Files/Microsoft SQL Server/100/Setup Bootstrap/Release 下

 

执行sqlservr.exe 加上-m选项,以单用户模式启动SQL Server,如:sqlservr.exe -m

sqlservr.exe在路径C:/Program Files/Microsoft SQL Server/MSSQL10.MSSQLSERVER/MSSQL/Binn下

利用单用户模式启动SQL Server实例后,应先停用SQL Server相关服务,包括:

1.SQL Server Agent

2.SQL Server Analysis Services

3.SQL Server Fulltext Search

4.SQL Server Integration Services

5.SQL Server Reporting Services

 

执行RESTORE DATABASE语句还原master数据库

[c-sharp] view plaincopy

  1. USE MSDB
  2. GO
  3. RESTORE DATABASE master
  4. FROM DISK = N’物理路径’

 

 

详细步骤:

1.创建master的备份设备

 

[c-sharp] view plaincopy

  1. EXEC sp_addumpdevice N’DISK’, N’Master_BackupDevice’, N’D:/master.bak’

 

 

2.设置master数据库的恢复模式为完整

 

[c-sharp] view plaincopy

  1. ALTER DATABASE master SET RECOVERY FULL
  2. — 或者用修改数据库选项方式:
  3. EXEC sp_dboption master, N’trunc. log on chkpt.’, FALSE
  4. EXEC sp_dboption master, N’select into/bulkcopy’, FALSE

 

 

3.备份master数据库到Master_BackupDevice备份设备中

 

[c-sharp] view plaincopy

  1. BACKUP DATABASE master
  2. TO Master_BackupDevice
  3. WITH NAME = N’master 完全备份’, COMPRESSION, INIT

 

 

4.备份master数据库后创建,测试还原master之后的结果

 

[c-sharp] view plaincopy

  1. CREATE DATABASE AfterMaster

 

 

5.停掉SQL Server所有服务,并在路径C:/Program Files/Microsoft SQL Server/MSSQL10.MSSQLSERVER/MSSQL/DATA下删除master数据库文件(master.mdf)和mastlog.ldf文件,以模拟master数据库的损坏

 

6.重建master数据库,进入命令行界面执行 cd C:/Program Files/Microsoft SQL Server/100/Setup Bootstrap/Release进入此路径,然后执行 setup.exe /QUIET /INSTANCENAME=MSSQLSERVER /ACTION=REBUILDDATABASE /SQLSYSADMINACCOUNTS=CA0043416 /SAPWD=1q2w3e.!! 命令,如下图,此时C:/Program Files/Microsoft SQL Server/MSSQL10.MSSQLSERVER/MSSQL/DATA路径下出现了master.mdf和mastlog.ldf文件

 

 

7.单用户模式启动SQL Server实例,进入命令行界面执行 cd C:/Program Files/Microsoft SQL Server/MSSQL10.MSSQLSERVER/MSSQL/Binn进入此路径,然后执行命令sqlservr.exe -m,如下图所示:

 

8.还原master数据库,再打开一个命令行界面,执行sqlcmd命令,利用sqlcmd工具程序登陆SQL Server

 

[c-sharp] view plaincopy

  1. — 执行RESTORE DATABASE语句还原master数据库
  2. USE msdb
  3. GO
  4. RESTORE DATABASE master
  5. FROM DISK = N’D:/master.bak’
  6. WITH REPLACE
  7. GO

 

 

9.还原成功 执行NET START MSSQLSERVER命令,重新启动SQL Server实例

 

 

10.如预期所想,启动SQL Server实例后没有AfterMaster数据库,则附加数据库到SQL Server

 

[c-sharp] view plaincopy

  1. USE [master]
  2. GO
  3. CREATE DATABASE [AfterMaster] ON
  4. ( FILENAME = N’C:/Program Files/Microsoft SQL Server/MSSQL10.MSSQLSERVER/MSSQL/DATA/AfterMaster.mdf’ ),
  5. ( FILENAME = N’C:/Program Files/Microsoft SQL Server/MSSQL10.MSSQLSERVER/MSSQL/DATA/AfterMaster_log.LDF’ )
  6. FOR ATTACH
  7. GO

 

更多0