如何安装 SQL Server 2000

这一组"如何"主题中包括了安装 Microsoft® SQL Server™ 2000 时常用的过程。


如何安装 SQL Server 2000（安装程序）

安装 SQL Server 2000

  1. 将 Microsoft® SQL Server™ 2000 光盘插入 CD-ROM 驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"。

    如果运行的是 Microsoft Windows® 95，则单击"SQL Server 2000 必要条件"，然后单击"安装公用控件库更新"。

  3. 选择"安装数据库服务器"，安装程序于是准备 SQL Server 安装向导。在"欢迎"屏幕中单击"下一步"按钮。

  4. 在"计算机名"对话框中，"本地计算机"是默认选项，并且本地计算机名出现在编辑框中。单击"下一步"按钮。

    对于远程安装，请单击"远程计算机"选项。然后可以键入计算机名或者单击"浏览"按钮以找到远程计算机。

    如果检测到群集，则"虚拟服务器"是默认选项。

  5. 在"安装选项"对话框中，单击"创建 SQL Server 新实例或安装客户端工具"选项，然后单击"下一步"按钮。

  6. 按照"用户信息"、"软件许可协议"和相关屏幕上的指导进行操作。

  7. 在"安装定义"对话框中，单击"服务器和客户端工具"选项，然后单击"下一步"按钮。

  8. 在"实例名称"对话框中，如果"默认"复选框可用，就可以安装默认实例或命名实例。如果"默认"复选框不可用，则表示已经安装了默认实例，且只能安装命名实例。
    • 若要安装默认实例，请选择"默认"复选框，然后单击"下一步"按钮。

    • 若要安装命名实例，请清除"默认"复选框，并在"实例名称"编辑框中键入一个新的命名实例。单击"下一步"按钮。
  9. 在"安装类型"对话框中单击"典型"或"最小"，然后单击"下一步"按钮。

    如果要选择组件和子组件，则更改字符集、网络库或其它设置，并单击"自定义"按钮，然后单击"下一步"按钮。

  10. 在"服务帐户"对话框中，接受默认设置，输入域密码，然后单击"下一步"按钮。

    有关服务帐户选项的信息，请参阅服务帐户。

  11. 在"身份验证模式"对话框中，接受默认设置，然后单击"下一步"按钮。

    若要使用"混合模式"，请参阅身份验证模式。

  12. 在完成选项的指定后，请在"开始复制文件"对话框中单击"下一步"按钮。

  13. 在"选择授权模式"对话框中，按照许可协议进行选择，然后单击"继续"按钮开始安装。

    有关授权的信息，请单击"帮助"按钮或向系统管理员进行咨询。

  14. 在"安装完成"对话框中单击"是，我想现在重新启动计算机"选项，然后单击"完成"按钮。

请参见

如何向 SQL Server 2000 实例中添加组件（安装程序）

如何创建区分大小写的 SQL Server 实例（安装程序）

如何安装 SQL Server 命名实例（安装程序）


如何只安装客户端工具（安装程序）

可以使用任意 SQL Server 光盘，在受支持的任何操作系统上仅安装客户端工具。有关更多信息，请参阅如何从任意光盘仅安装工具。

为 SQL Server 2000 只安装客户端工具

  1. 将 Microsoft® SQL Server™ 2000 光盘插入 CD-ROM 驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"，选择"安装数据库服务器"，然后在 SQL Server 安装向导的"欢迎"屏幕上单击"下一步"按钮。

  3. 在"计算机名"对话框中，"本地计算机"是默认选项，本地计算机名显示在编辑框中。单击"下一步"按钮。

  4. 在"安装选项"对话框中，单击"创建 SQL Server 新实例或安装客户端工具"选项，然后单击"下一步"按钮。

  5. 按照"用户信息"、"软件许可协议"和相关屏幕上的指导进行操作。

  6. 在"安装定义"对话框中单击"仅客户端工具"选项，然后单击"下一步"按钮。

  7. 在"选择组件"对话框中，接受默认设置或选择需要的组件，然后单击"下一步"按钮。

    可以在"组件"列表中选择一项（如"管理工具"选项），然后从相关的"子组件"列表中选择项目，比如"企业管理器"选项。单击以选择希望安装的项目；清除不希望安装的项目的复选框。

    有关各个组件的信息，请选择该组件项，然后查看"描述"框。

  8. 在"开始复制文件"对话框中，单击"下一步"按钮以完成客户端工具的安装。


如何从任意光盘仅安装工具（安装程序）

说明 在此过程中，可以在安装有 SQL Server 2000 支持的任意操作系统的计算机上使用任何 SQL Server 2000 版本的安装光盘。

从任意光盘仅安装工具

  1. 将 Microsoft® SQL Server™ 2000 光盘插入 CD-ROM 驱动器。该光盘可以是任何 SQL Server 2000 版本的安装光盘（无论操作系统是否支持）。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"，选择"安装数据库服务器"，然后在 SQL Server 安装向导的"欢迎"屏幕上单击"下一步"按钮。

  3. 在"计算机名"对话框中，"本地计算机"是默认选项，本地计算机名显示在编辑框中。单击"下一步"按钮。

  4. 按照"用户信息"、"软件许可协议"和相关屏幕上的指导进行操作。

  5. 在"选择组件"对话框中，接受默认设置或选择需要的组件，然后单击"下一步"按钮。

    可以在"组件"列表中选择一项，比如"管理工具"选项，然后从相关的"子组件"列表中选择项目，比如"企业管理器"选项。单击以选择希望安装的项目；清除不希望安装的项目的复选框。

    有关各个组件的信息，请选择该组件项，然后查看"描述"框。

  6. 在"开始复制文件"对话框中，单击"下一步"按钮以完成客户端工具的安装。


如何只安装连接（安装程序）

使用"仅连接"选项可以安装网络库和 MDAC（Microsoft® 数据访问组件）。

为 SQL Server 2000 只安装连接

  1. 将 Microsoft SQL Server™ 2000 光盘插入 CD-ROM 驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"。

    如果运行的是 Microsoft Windows® 95，请单击"安装公用控件库更新"。

  3. 选择"安装数据库服务器"，安装程序于是准备 SQL Server 安装向导。在"欢迎"屏幕中单击"下一步"按钮。

  4. 在"计算机名"对话框中，"本地计算机"是默认选项，本地计算机名显示在编辑框中。单击"下一步"按钮。

  5. 在"安装选项"对话框中单击"创建 SQL Server 新实例或安装客户端工具"，然后单击"下一步"按钮。

  6. 按照"用户信息"、"软件许可协议"和相关屏幕上的指导进行操作。

  7. 在"安装定义"对话框中单击"仅连接"选项，然后单击"下一步"按钮。

  8. 在"开始复制文件"对话框中单击"下一步"按钮以完成安装。


如何安装 SQL Server 2000 命名实例（安装程序）

Microsoft® SQL Server™ 2000 命名实例可以在第一次运行 SQL Server 安装程序时安装，也可以在安装了默认实例之后安装。对于其它每个要安装的命名实例，都请按照此过程进行操作。

说明 如果计算机上已有 SQL Server 7.0 安装，则该安装会在安装 SQL Server 2000 命名实例的过程中保持原封不动。默认的 SQL Server 2000 实例将重写 SQL Server 7.0 安装（作为以前的默认安装），但命名实例不会重写 SQL Server 7.0。

安装 SQL Server 2000 的命名实例

  1. 将 SQL Server 2000 光盘插入 CD-ROM 驱动器中。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"。

    如果运行的是 Microsoft Windows® 95，请选择"安装公用控件库更新"。

  3. 选择"安装数据库服务器"，安装程序于是准备 SQL Server 安装向导。在"欢迎"屏幕中单击"下一步"按钮。在"计算机名"对话框中，"本地计算机"是默认选项，本地计算机名显示在编辑框中。单击"下一步"按钮。

  4. 在"安装选项"对话框中，单击"创建 SQL Server 新实例或安装客户端工具"，然后单击"下一步"按钮。
    • 如果这是首次在计算机上安装 SQL Server 2000，则请按照"用户信息"、"软件许可协议"和相关屏幕上的指导进行操作。

    • 如果计算机上已经装有 SQL Server 2000，就不会出现这些屏幕。
  5. 在"安装定义"对话框中，单击"服务器和客户端工具"选项，然后单击"下一步"按钮。

  6. 在"实例名称"对话框中清除"默认"复选框并键入新命名实例的名称，然后单击"下一步"按钮。

    说明 如果已有默认安装（SQL Server 7.0 或 2000），则"默认"复选框不可用。

    如果已键入一个实例名称，则在安装程序完成前可以返回"实例名称"对话框更改该名称。然而，需要一个工作区来编辑实例名称框，单击"上一步"按钮回到该对话框后实例名称框将不可用。选择"默认"复选框，然后立即将其清除，这样就可以编辑实例名称了。

    有关实例名称的更多信息，请单击"帮助"按钮。

  7. 在"安装类型"对话框中选择"典型"、"最小"或"自定义"选项，然后单击"下一步"按钮。

    如果要选择子组件或更改字符集、网络库或其它设置，请单击"自定义"按钮。

  8. 在"服务帐户"对话框中，接受默认设置，输入域密码，然后单击"下一步"按钮。

    有关服务帐户的信息，请参阅服务帐户。

  9. 在"身份验证模式"对话框中，接受默认设置，然后单击"下一步"按钮。

    若要使用"混合模式"身份验证，请参阅身份验证模式。

  10. 在完成选项的指定后，请在"开始复制文件"对话框中单击"下一步"按钮。

  11. 在"选择授权模式"对话框中，按照许可协议进行选择，然后单击"继续"按钮开始安装。

    有关授权的信息，请单击"帮助"按钮或向系统管理员进行咨询。

  12. 在"安装完成"对话框中单击"是，我想现在重新启动计算机"选项，然后单击"完成"按钮。

请参见

处理 SQL Server 2000 的命名实例和多实例

与 SQL Server 2000 命名实例一起运行 SQL Server 7.0


如何将 SQL Server 7.0 安装升级到 SQL Server 2000（安装程序）

注意 此版本升级过程将重写 Microsoft® SQL Server™ 7.0 安装；因此计算机上不再存在此安装。另外，还删除以前的注册表设置。例如，在升级后需要重新注册服务器。

若要还原 SQL Server 7.0 安装，必须首先卸载 SQL Server 2000 并执行完全重新安装 SQL Server 7.0 文件，然后还原所备份的 SQL Server 7.0 数据库。

将 SQL Server 7.0 升级到 SQL Server 2000

  1. 将要升级到的版本的 Microsoft SQL Server 2000 光盘插入光盘驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

    说明 如果购买的 SQL Server 版本所具有的功能比当前的 SQL Server 7.0 安装多，则升级过程将同时执行版次和功能版本的升级。

  2. 选择"SQL Server 2000 组件"，选择"安装数据库服务器"，安装程序于是准备 SQL Server 安装向导。在"欢迎"屏幕中单击"下一步"按钮。

  3. 在"计算机名"对话框中，"本地计算机"是默认选项，本地计算机名显示在编辑框中。单击"下一步"按钮。

  4. 在"安装选项"对话框中，单击"升级、删除或将组件添加到 SQL Server 现有实例中"，然后单击"下一步"按钮。

  5. 在"实例名称"对话框中，"默认"是被选定的。单击"下一步"按钮。

    说明 在升级时，SQL Server 7.0 会自动变为 SQL Server 2000 的默认实例。

  6. 在"现有安装"对话框中，单击"升级现有安装"选项，然后单击"下一步"按钮。

  7. 在"升级"对话框中，会得到是否希望继续进行所请求的升级的提示。单击"是，升级我的<针对升级的文本>"开始升级过程，然后单击"下一步"按钮。升级进程一直运行直到结束。

  8. 在"连接到服务器"对话框中选择身份验证模式，然后单击"下一步"按钮。

    如果不确定采用哪种模式，请接受默认值："我登录到计算机上所使用的 Windows 帐户信息 (Windows)"。

  9. 在"开始复制文件"对话框中单击"下一步"按钮。

  10. 在"安装完成"对话框中，单击"是，我想现在重新启动计算机"选项，然后单击"完成"按钮。

请参见

身份验证模式

如何在 SQL Server 2000 内进行版本升级（安装程序）


如何使用复制数据库向导联机升级数据库（企业管理器）

将 SQL Server 7.0 数据库升级到 SQL Server 2000 数据库

  1. 展开服务器组，然后展开服务器。

  2. 右击该服务器，指向"所有任务"选项，然后单击"复制数据库向导"命令。

  3. 完成向导中的步骤。

重要 升级 SQL Server 7.0 数据库后，对目的服务器上的数据库运行 sp_updatestats（更新统计），以确保复制的数据库具有最佳性能。

请参见

复制数据库向导帮助

升级 SQL Server 7.0 数据库（复制数据库向导）


如何在 SQL Server 2000 内进行版本升级（安装程序）

将某个 SQL Server 2000 安装升级到其它版本的 SQL Server 2000

  1. 将想要安装的版本的 Microsoft® SQL Server 2000™ 光盘插入光盘驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"，选择"安装数据库服务器"，安装程序于是准备 SQL Server 安装向导。在"欢迎"屏幕中单击"下一步"按钮。

  3. 在"计算机名"对话框中选择"本地计算机"或"远程计算机"。

  4. 在"安装选项"对话框中，单击"升级、删除或将组件添加到 SQL Server 现有实例中"选项，然后单击"下一步"按钮。

  5. 在"实例名称"对话框中，单击"下一步"按钮。

  6. 在"现有安装"对话框中，单击"升级现有安装"选项，然后单击"下一步"按钮。

  7. 如果安装程序检测到正在进行版本升级，就会出现"升级"对话框。单击"是，升级我的<针对升级的文本>"以升级当前安装的功能集，然后单击"下一步"按钮。

  8. 在升级完成后，会得到是否要安装别的组件的提示。如果单击"是"按钮，就会出现"选择组件"对话框。接受默认值或选择其它希望安装的组件，然后单击"下一步"按钮。

    可以在"组件"列表中选择一项，然后从相关的"子组件"列表中选择各个项目。单击以选择希望安装的项目；清除不希望安装的项目的复选框。

  9. 在完成选项的指定后，请在"开始复制文件"对话框中单击"下一步"按钮。

  10. 在"安装完成"对话框中单击"是，我想现在重新启动计算机"选项，然后单击"完成"按钮以完成版本升级。

请参见

升级现有的 SQL Server 安装


如何卸载 SQL Server 的现有安装（安装程序）

卸载 SQL Server 7.0 或 SQL Server 2000 现有安装（默认或命名实例）

  1. 将 Microsoft® SQL Server™ 2000 光盘插入 CD-ROM 驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"，选择"安装数据库服务器"，安装程序于是准备 SQL Server 安装向导。在"欢迎"屏幕中单击"下一步"按钮。

  3. 在"计算机名"对话框中，选择"本地计算机"或"远程计算机"。

  4. 在"安装选项"对话框中，单击"升级、删除或将组件添加到 SQL Server 现有实例中"选项，然后单击"下一步"按钮。

  5. 如果安装了默认实例，则在"实例名称"对话框中，"默认"选项是被选定的。如果要卸载命名实例，请从"实例名称"列表框中选择该实例，然后单击"下一步"按钮。

  6. 在"现有安装"对话框中，单击"卸载现有安装"选项，然后单击"下一步"按钮。

  7. 安装程序于是删除选定的安装。在"卸载"对话框中单击"下一步"按钮，然后在"安装完成"对话框中单击"完成"按钮。


如何测试 SQL Server 2000 的安装（命令提示符）

测试安装

  1. 启动 Microsoft® SQL Server™ 2000 的方法是在命令提示符下输入下列命令：

    对于默认实例，请使用：

    net start mssqlserver

    对于命名实例，请输入实例名称，例如：

    net start MSSQL$Instance1
  2. 采用输入方法连接到 SQL Server：

    对于默认实例，请使用：

    osql /Usa /P <administrator password>

    对于命名实例，请输入服务器名称和实例名称，例如：

    osql /Usa /P /S Machine1\Instance1

    当连接 osql 时，即出现 osql 提示符：

    1>

    如果未能连接 osql，则返回 ODBC 错误。

  3. 输入一个简单查询，例如：
    SELECT @@SERVERNAME
GO

    osql 实用工具返回服务器名称：

    1> SELECT @@SERVERNAME
2> GO
-------------------------------
WOLFHOUND

(1 row affected)
1>
  4. 验证是否已选中了 SQL Server 2000 服务器，方法是输入：
    SELECT @@VERSION
GO

    osql 实用工具返回版本信息。

  5. 退出 osql 实用工具，方法是输入：
    Exit


如何更改 SQL Server 服务登录帐户信息 (Windows NT)

更改 SQL Server 服务登录帐户信息 (Windows NT)

  1. 在"开始"菜单中指向"设置"子菜单，然后单击"控制面板"命令。

  2. 双击"服务"按钮。

  3. 在"服务"对话框中，双击"服务"列表中的"MSSQLSERVER"。

    说明 对于命名实例，实例名称也包含在内。例如，若要修改 Instance1 的用户帐户，请双击"MSSQL$Instance1"。

  4. 在"服务"对话框中的"登录身份"下选择"本帐户"，然后输入更改后的帐户信息。

  5. 对于 SQL Server 代理重复上述步骤 3 和 4。在"服务"对话框中，双击"SQLSERVERAGENT"（对于命名实例则是"SQLAgent$Instance1"），然后在"服务"对话框中输入更改后的帐户信息。

  6. 启动 SQL Server 企业管理器，同样为 SQL Server 和 SQL Server 代理程序更改其中的用户帐户信息。有关更多信息，请参阅如何更改 SQL Server 服务登录帐户信息（企业管理器）。


如何更改 SQL Server 服务登录帐户信息 (Windows)

更改 SQL Server 服务登录帐户信息 (Windows 2000)

  1. 在"开始"菜单上，指向"程序"，进而指向"管理工具"，然后单击"服务"命令。

  2. 右击"MSSQLServer"，然后单击"属性"命令。

  3. 在"登录"选项卡中，输入并确认新的密码，然后使用 SQL Server 服务管理器重新启动服务。

  4. 对于 SQLServerAgent 及其它服务重复该密码重置。

  5. 启动 SQL Server 企业管理器，同样为 SQL Server 和 SQL Server 代理更改其中的用户帐户信息。有关更多信息，请参阅如何更改 SQL Server 服务登录帐户信息（企业管理器）。


如何更改 SQL Server 服务登录帐户信息（企业管理器）

说明 如果正在运行 Microsoft® Windows® 2000 且想要使用 Windows 2000 加密文件系统加密任何 Microsoft SQL Server™ 文件，则必须不加密这些文件才能更改 SQL Server 服务帐户。如果加密了这些文件然后重置 SQL Server 服务帐户，则无法不加密这些文件。

更改 MSSQLServer 服务登录（企业管理器）

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 在"SQL Server 属性"对话框中，单击"安全"选项卡。

  4. 在"启动服务帐户"框中，"此帐户"一项已选中，表明 SQL Server 服务帐户是一个 Windows 域帐户。输入所需帐户和密码更改。

更改 SQLServerAgent 服务登录（企业管理器）

说明 可将 SQLServerAgent 服务帐户更改为非 Microsoft Windows NT® 4.0 管理员帐户。但是，Windows NT 4.0 帐户必须是 sysadmin 固定服务器角色的成员以运行 SQL Server 代理程序。

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，然后单击"属性"。

  4. 在"SQL Server 代理程序属性"对话框中，单击"常规"选项卡。

  5. 在"服务启动帐户"框中输入适当的帐户和密码。

请参见

创建 SQL Server 服务用户帐户

更改密码和用户帐户


如何重建注册表（安装程序）

重建注册表

  1. 将 Microsoft® SQL Server™ 2000 光盘插入 CD-ROM 驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"，选择"安装数据库服务器"，然后在 SQL Server 安装向导的"欢迎"屏幕上单击"下一步"按钮。

  3. 在"计算机名"对话框中单击"下一步"按钮。

  4. 在"安装选项"对话框中，单击"高级选项"按钮，然后在"高级选项"对话框中单击"注册表重建"选项。单击"下一步"按钮。

  5. 此时出现一条消息，告知您安装程序基于您在后续屏幕中所提供的信息重建注册表。

    注意 所输入的安装选项必须与您在初始安装时所输入的选项相同。如果您不知道或不确定此信息，请不要使用这种注册表重建进程。如果使用注册表重建进程，则必须卸载并重新安装 SQL Server 以还原注册表。

  6. 若要准备注册表重建，请输入与 SQL Server 初始安装过程中在安装程序屏幕出现时所输入的内容相同的信息。完成后，将会进行注册表重建。

  7. 说明 重建注册表包括重新复制外部组件如 MDAC 和 MS DTC。


如何重建 master 数据库（重建 Master 实用工具）

重建 master 数据库

  1. 关闭 Microsoft® SQL Server™ 2000，然后运行 Rebuildm.exe。该程序位于 Program Files\Microsoft SQL Server\80\Tools\Binn 目录中。

  2. 在"重建 Master"对话框中单击"浏览"按钮。

  3. 在"浏览文件夹"对话框中，选择 SQL Server 2000 光盘上或用于安装 SQL Server 2000 的共享网络目录中的 \Data 文件夹，然后单击"确定"按钮。

  4. 单击"设置"按钮。在"排序规则设置"对话框中，验证或更改用于 Master 数据库或其它数据库的设置。

    最初，显示的是默认排序规则设置，但这些设置有可能与安装期间选择的排序规则不匹配。可以选择与安装期间使用的排序规则相同的设置，也可以选择新的排序规则设置。完成后单击"确定"按钮。

  5. 在"重建 Master"对话框中单击"重建"按钮以启动进程。

    重建 Master 实用工具重新安装 master 数据库。

    说明 若要继续，则可能需要终止正在运行的服务器。

请参见

安装程序中的排序规则设置


如何进行远程 SQL Server 2000 安装（安装程序）

进行远程安装

  1. 将 Microsoft® SQL Server™ 2000 光盘插入 CD-ROM 驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"，选择"安装数据库服务器"，然后在 SQL Server 安装向导的"欢迎"屏幕上单击"下一步"按钮。

  3. 在"计算机名"框中单击"远程计算机"按钮。然后可以键入计算机名或者单击"浏览"按钮以找到远程计算机。

  4. 在"安装选项"对话框中，单击"创建 SQL Server 新实例"或"安装客户端工具"。

  5. 按照"用户信息"、"软件许可协议"和相关屏幕上的指导进行操作。

  6. 在"远程安装信息"对话框中输入密码和其它信息。有关更多信息，请参阅远程安装信息。完成定义各选项之后，单击"下一步"按钮。

  7. 在"安装定义"、"实例名称"、"安装类型"和随后出现的安装屏幕中，选择所需的远程安装的选项。

    SQL Server 安装程序用指定的选项在本地系统文件夹中创建 Setup.iss 文件。

  8. 在安装程序创建 Setup.iss 之后，就会出现"安装完成"对话框。单击"完成"按钮以启动远程安装进程。

  9. 完成该进程后，在出现的消息框中单击"确定"按钮。在运行远程实例之前，重新引导远程计算机。


如何记录无值守安装文件（安装程序）

"记录无值守"安装程序选项使您得以模拟安装并创建一个 .iss 文件，该文件可在将来用于 Microsoft® SQL Server™ 2000 的无值守安装。SQL Server 文件并不在这一进程中安装。

创建用于无值守安装的文件

  1. 将 Microsoft SQL Server 2000 光盘插入 CD-ROM 驱动器中。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"，选择"安装数据库服务器"，然后在 SQL Server 安装向导的"欢迎"屏幕上单击"下一步"按钮。

  3. 在"计算机名"对话框中，选择需要的选项，然后单击"下一步"按钮。

  4. 在"安装选项"对话框中单击"高级选项"命令，然后在"高级选项"对话框中单击"记录无值守 .ISS 文件"。单击"下一步"按钮。

  5. 在后续的安装程序屏幕中，为无值守安装选择所需的选项。完成各项选择之后，在"安装信息"屏幕中单击"下一步"按钮。

  6. 在"安装完成"屏幕中，单击"完成"按钮。

    此时出现下列消息："安装程序收集到创建无值守安装文件 (.iss) 所需的信息，以便使用较新的 SQL Server 无值守安装。"

    然后 SQL Server 安装程序用指定的选项在 %windir% 位置创建 Setup.iss 文件。

    若要运行该文件，请参阅如何运行无值守 SQL Server 2000 安装（命令提示符）。

请参见

执行无值守安装


如何运行无值守 SQL Server 2000 安装（命令提示符）

可以通过包含在 Microsoft® SQL Server™ 2000 光盘中的示例批处理文件和安装程序初始化文件运行无值守安装。或者可以直接从要安装的 SQL Server 版本相应目录中的命令提示符下，根据需要使用参数来运行安装程序。

使用已做好的批处理文件运行无值守安装

  1. 在 SQL Server 2000 光盘的根目录中查找 .bat 文件和 .iss 文件。

  2. 查看 .bat 文件及相关的 .iss 文件，如有必要可作修改。有关更多信息，请参见手动创建安装文件。

  3. 从命令提示符运行适当的批处理文件及安装程序文件：
    • 对于标准无值守安装，运行 Sqlins.bat。

    • 对于仅客户端无值守安装，运行 Sqlcli.bat。

    • 对于自定义无值守安装，运行 Sqlcst.bat。

从命令提示符直接运行无值守安装

  1. 在适当的构架目录中从安装目录运行 Setupsql.exe 文件。

  2. 根据需要使用参数：
-f1 <initialization file path>
选择一个无值守安装程序初始化文件。
start/wait 命令（带有 -SMS 选项）
只有在 SQL Server 安装程序完成之后才返回对命令提示符的控制。
-s 标志
导致安装程序在无用户界面的静默模式下运行。

有关命令提示符选项和参数的示例，请参阅 SQL Server 2000 光盘上的 .bat 示例文件。

请参见

执行无值守安装

如何记录无值守安装文件（安装程序）


如何向 SQL Server 2000 实例中添加组件（安装程序）

说明 不能通过清除"选择组件"对话框中的复选框来删除组件。如果需要删除 SQL Server 实例中的组件，必须卸载该实例。

向 SQL Server 2000 实例（默认或命名）中添加组件

  1. 运行 SQL Server 安装程序，选择"SQL Server 2000 组件"，然后单击 SQL Server 安装向导"欢迎"屏幕上的"下一步"按钮。

  2. 在"计算机名"对话框中，"本地计算机"是默认选项，本地计算机名显示在编辑框中。单击"下一步"按钮。

  3. 在"安装选项"对话框中，单击"升级、删除或将组件添加到 SQL Server 现有实例中"选项，然后单击"下一步"按钮。

  4. 如果已经安装了默认实例，则在"实例名称"对话框中，"默认"选项是被选定的。如果要向命名实例中添加组件，请从"实例名称"列表中选择该组件，然后单击"下一步"按钮。

  5. 在"现有安装"对话框中，单击"向现有安装中添加组件"选项，然后单击"下一步"按钮。

  6. 在"选择组件"对话框中，从"组件"列表中选择一个组件，然后从相关的"子组件"列表中选择各项。单击以选择要添加的项目，然后单击"下一步"按钮。

    有关各个组件的信息，请选择该组件项，然后查看"描述"框。

  7. 在完成选项的指定后，请在"开始复制文件"对话框中单击"下一步"按钮，向所选 SQL Server 实例中添加组件。

请参见

如何卸载 SQL Server 的现有安装（安装程序）


如何访问 SQL Server 7.0 的 SQL Server 联机丛书

如果 Microsoft® SQL Server™ 7.0 正作为默认实例运行（而且 SQL Server 2000 作为命名实例），则 SQL Server 7.0 的 SQL Server 联机丛书在计算机上保持完好无损。可以从"开始"菜单访问 SQL Server 联机丛书，或者在桌面上创建联机丛书的快捷方式。

从开始菜单访问 SQL Server 7.0 的 SQL Server 联机丛书

  • 在"开始"菜单上，指向"程序"菜单的"Microsoft SQL Server 7.0"子菜单，然后单击"联机丛书"命令。

创建 SQL Server 7.0 的 SQL Server 联机丛书的快捷方式

  1. 在计算机上找到 Sqlbol.chm 文件。（默认位置是 C:\Mssql7\Books。）

  2. 右击 Sqlbol.chm 文件，然后单击"创建快捷方式"命令。

  3. 将该快捷方式复制到桌面，从桌面上使用它访问 SQL Server 联机丛书。

首次安装 SQL Server 7.0 的 SQL Server 联机丛书或重新安装时，必须从 SQL Server 7.0 光盘或 SQL Server Web 站点安装。

从 SQL Server 7.0 光盘重新安装 SQL Server 联机丛书

  1. 将 Microsoft SQL Server 7.0 光盘插入 CD-ROM 驱动器中。

  2. 在光盘中找到 Sqlbol.chm 文件，并将其复制到计算机上的某个位置。

  3. 在桌面上创建 SQL Server 7.0 的 SQL Server 联机丛书的快捷方式。

从 SQL Server Web 站点下载 SQL Server 7.0 的 SQL Server 联机丛书

  1. 转到 Microsoft SQL Server Web 站点，网址为 Microsoft Web 站点。

  2. 在 SQL Server"欢迎"页上单击"支持"。

  3. 在"支持"页上单击"文档"并按照指令访问 SQL Server 7.0 联机丛书。


如何安装 English Query（安装程序）

安装 English Query

  1. 将 Microsoft® SQL Server™ 2000 光盘插入 CD-ROM 驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"。

  3. 在"安装组件"屏幕上，选择"安装 English Query"。

    不必再选择其它内容。SQL Server 安装程序将 English Query 安装到计算机上。


如何安装 Analysis Services（安装程序）

下列过程是安装 Analysis Services 的简化步骤。有关更完整的安装过程和相关信息，请参阅运行安装程序。

安装 Analysis Services

  1. 将 Microsoft® SQL Server™ 2000 光盘插入 CD-ROM 驱动器。如果该光盘不自动运行，请双击该光盘根目录中的 Autorun.exe 文件。

  2. 选择"SQL Server 2000 组件"。

  3. 在"安装组件"屏幕上选择"安装 Analysis Services"。

  4. 在 Microsoft SQL Server Analysis Services 的"欢迎"屏幕上单击"下一步"按钮。

  5. 按照"用户信息"、"软件许可协议"和相关屏幕上的指导进行操作。

  6. 在"选择组件"对话框中根据需要选择或清除组件，然后单击"下一步"按钮。

    如果要更改 Analysis Services 程序文件的默认位置，请单击"目的文件夹"上的"浏览"按钮，然后选择一个文件夹位置。

  7. 在"数据文件夹位置"对话框中接受或更改数据文件的默认位置，然后单击"下一步"按钮。

  8. 在"选择程序文件夹"中接受或更改默认设置，然后单击"下一步"按钮。

SQL Server 安装程序将 Analysis Services 安装到计算机上。


如何创建区分大小写的 SQL Server 2000 实例（安装程序）

创建区分大小写的 SQL Server 2000 实例

  1. 运行 SQL Server 安装程序来安装"SQL Server 2000 组件"，并选择"安装数据库服务器"，然后在 SQL Server 安装向导的"欢迎"屏幕上单击"下一步"按钮。

  2. 在"计算机名"对话框中，"本地计算机"是默认选项，本地计算机名显示在编辑框中。单击"下一步"按钮。

  3. 在"安装选项"对话框中单击"创建 SQL Server 新实例或安装客户端工具"，然后单击"下一步"按钮。

  4. 按照"用户信息"和相关屏幕上的指导进行操作。

  5. 在"安装定义"对话框中，单击"服务器和客户端工具"选项，然后单击"下一步"按钮。

  6. 在"实例名称"对话框中：
    • 若要创建区分大小写的默认实例，请接受"默认"复选框并单击"下一步"按钮。

    • 若要创建区分大小写的命名实例，请清除"默认"复选框并键入实例名称。
  7. 在"安装类型"对话框中单击"自定义"选项，然后单击"下一步"按钮。

  8. 在"选择组件"、"服务帐户"和"身份验证模式"对话框中，更改或接受默认设置，然后单击"下一步"按钮。

  9. 在"排列规则设置"对话框中有两个选项：
    • 若要使 Windows 区域设置排序规则区分大小写，请选择"排列规则指示器"，然后从列表中选择正确的排序规则指示器。清除"二进制"复选框，然后选择"区分大小写"复选框。

    • 若要使 SQL 排序规则区分大小写，请选择"SQL 排序规则"，然后键入正确的排序规则名称。

    有关排序规则选项的更多信息，请单击"帮助"按钮。完成选项的设置后，请单击"下一步"按钮。

  10. 在随后出现的各对话框中，更改或接受默认设置，然后单击"下一步"按钮。

  11. 在完成选项的指定后，请在"开始复制文件"对话框中单击"下一步"按钮。

  12. 在"选择授权模式"对话框中，按照许可协议进行选择，然后单击"继续"按钮开始安装。

  13. 有关授权的信息，请单击"帮助"按钮或向系统管理员进行咨询。

请参见

选择 SQL 排序规则


如何设置客户端代码页

在 Windows NT、Windows 2000 或 Windows 98 操作系统中设置客户端代码页

  • 使用在 Microsoft® Windows NT®、Microsoft Windows® 98 或 Microsoft Windows 2000 文档中所描述的"控制面板"中的"区域设置"应用程序。


如何从 SQL Server 6.5 切换到 SQL Server 2000（命令提示符）

从 SQL Server 6.5 切换到 SQL Server 2000

  • 运行 Vswitch.exe。
-SwitchTo <65|80>
确定要激活的 Microsoft® SQL Server™ 2000 的版本。
-Silent <0|1>
指定是否显示任何用户界面或消息。如果指定为 1，则不会显示任何用户界面或消息。默认值为 0。
示例
c:\...\vswitch -SwitchTo 80 -Silent 1


如何从 SQL Server 6.5 切换到 SQL Server 2000 (Windows)

从 SQL Server 6.5 切换到 SQL Server 2000

  • 在"开始"菜单上，指向"程序"的"Microsoft SQL Server — 版本切换"子菜单，然后单击"Microsoft SQL Server 2000"命令。

    SQL Server 安装程序会从 Microsoft® SQL Server™ 6.5 版切换到 SQL Server 2000。


如何删除 SQL Server 2000 (Windows)

可以使用"控制面板"来删除 Microsoft® SQL Server™ 2000 实例。每个命名实例都需要单独删除。在升级或维护实例时，可使用安装程序中的"卸载"选项来删除 SQL Server。有关更多信息，请参阅如何卸载现有安装（安装程序）。

不能在安装了选定的 SQL Server 2000 组件后删除该组件。若要删除组件，必须删除整个实例。

删除 SQL Server 2000 的命名实例

  1. 在"控制面板"中单击"添加/删除程序"。

  2. 选择一个 SQL Server 2000 实例名称，然后单击"删除"按钮。

删除所有 SQL Server 2000 实例

  1. 在"控制面板"中单击"添加/删除程序"。

  2. 对已安装的 SQL Server 2000 的每个实例，重复此删除过程。

虽然 SQL Server 2000 已经卸载，但有些文件可能还保留着。如有任何与 SQL Server 2000 相关的文件仍然存在，应手动删除相应目录。

请参见

定位目录和文件


如何从 SQL Server 6.5 升级

本部分中的"如何"主题专门针对使用 SQL Server 升级向导将数据从 Microsoft® SQL Server™ 6.5 转换到 Microsoft SQL Server 2000 的过程。

说明 若要运行 SQL Server 升级向导，计算机上必须已经安装有 Microsoft SQL Server 2000 实例。

从 SQL Server 6.5 升级时的注意事项：
  • 在升级过程中，SQL Server 6.5 服务器将停止并启动，同时将对象编为脚本并析取数据。数据传输开始后，只有 SQL Server 2000 在运行，无法访问 SQL Server 6.5。

  • 如果将现有的 SQL Server 6.5 服务器升级到运行 SQL Server 2000 的另一台计算机，则这两台计算机都应配置为对 MSSQLServer 服务使用域用户名和密码。

  • 在该升级过程中，在 SQL Server 6.5 中使用 sp_addmessage 创建的用户定义消息不转换到 SQL Server 2000。若要保留这些自定义消息，请将在 SQL Server 6.5 中添加的消息手工复制到 SQL Server 2000 安装。

请参见

SQL Server 升级向导疑难解答

完成 SQL Server 升级向导

升级日志文件

升级到 SQL Server 2000 常见问题解答


如何更改 SQL Server 6.5 中 tempdb 的大小 (ISQL/w)

更改 SQL Server 6.5 中 tempdb 的大小

  1. 在"开始"菜单上指向"程序"菜单，单击"Microsoft SQL Server 6.5"子菜单，然后单击"ISQL/w"命令。

  2. 输入 sa 密码；然后单击"连接"按钮。

  3. 执行 DISK INIT 命令以将 tempdb 设备的大小增加到至少 25 MB。

  4. 执行 ALTER DATABASE 命令以将 tempdb 数据库的大小增加到至少 25 MB。
示例
--Increase the size of the tempdb device
DISK INIT name = 'tempdb1',physname = 'c:\mssql\data\tempdb1.DAT',vdevno = 100, size = 12800
GO
--Increase the size of tempdb
ALTER DATABASE tempdb ON tempdb1 = 25


如何更改为 SQL Server 6.5 master 数据库中当前的服务器名称 (ISQL/w)

更改为 SQL Server 6.5 master 数据库中当前服务器名

  1. 以最小配置模式启动 Microsoft® SQL Server™。在命令提示符窗口中，从 \Mssql\Binn 目录运行：
    sqlservr -f
  2. 在"开始"菜单上，指向"程序"菜单，单击"Microsoft SQL Server 6.5"子菜单，然后单击"ISQL/w"命令。

  3. 输入 sa 密码；然后单击"连接"按钮。

  4. 执行 SELECT @@SERVERNAME 检索以前的服务器名称。

  5. 执行 sp_dropserver 除去以前的服务器。

  6. 执行 sp_addserver 添加当前服务器。

  7. 终止 SQL Server。在命令提示符窗口中同时按下 Ctrl 键和 C 键。

  8. 重新启动 SQL Server。

  9. 执行 SELECT @@SERVERNAME 以验证当前服务器名称。
示例
--Start SQL Server in minimal configuration mode.
--Retrieve the former server name.
SELECT @@SERVERNAME
--Drop the server returned from the previous select.
sp_dropserver 'SERVER6X'
--Add the current server.
sp_addserver 'SERVER70', local
--Stop SQL Server.
--Restart SQL Server in minimal configuration mode.
--Verify the current server name.
SELECT @@SERVERNAME


如何更新 SQL Server 6.5 master 数据库中的设备文件位置 (ISQL/w)

更新 SQL Server 6.5 master 数据库中的设备文件位置

  1. 在"开始"菜单上，指向"程序"菜单，单击"Microsoft SQL Server 6.5"子菜单，然后单击"ISQL/w"命令。

  2. 输入 sa 密码；然后单击"连接"按钮。

  3. 从 master 数据库里的 sysdevices 中进行选择以查看原来的设备文件位置。

  4. 执行 sp_configure 以允许对系统表进行更新，然后用 RECONFIGURE WITH OVERRIDE 语句强制实施该配置。

  5. 更新已更改的设备文件位置。

  6. 执行 sp_configure 以禁止对系统表进行更新，然后用 RECONFIGURE WITH OVERRIDE 语句强制实施该配置。
示例
--View the old device file locations
SELECT phyname FROM sysdevices

--Allow updates to the system tables
sp_configure 'allow updates',1
GO
RECONFIGURE WITH OVERRIDE
GO
--Update device file locations that have changed
UPDATE sysdevices
SET phyname = "E:\Data\HR\HR1.dat"
WHERE name = "HumanResources1"
GO
UPDATE sysdevices
SET phyname = "E:\Data\HR\HR1Log.dat"
WHERE name = "HumanResources1Log"
GO
--Disallow updates to the system tables
sp_configure 'allow updates',0
GO
RECONFIGURE WITH OVERRIDE
GO


如何估计从 SQL Server 6.5 升级到 SQL Server 2000 所需要的磁盘空间（SQL Server 升级向导）

说明 若要运行 SQL Server 升级向导，计算机上必须安装有 Microsoft® SQL Server™ 2000 实例。

估计升级所需的磁盘空间

  1. 在"开始"菜单中指向"程序"菜单，单击"Microsoft SQL Server — 版本切换"子菜单，再单击"SQL Server 升级向导"命令，然后单击"下一步"按钮。

  2. 选择"命名管道"，然后单击"下一步"按钮。

  3. 在"导出服务器 (6.5)"中的"服务器名称"框内，输入装有 SQL Server 6.5 的本地计算机或远程计算机的名称。

  4. 在"管理员密码 ('sa')"框中输入 SQL Server 6.5 的 sa 密码，然后单击"下一步"按钮。

    如果不加以更改，SQL Server 2000 的系统管理员密码应是空的。

  5. 将要升级的数据库包括进来。将所有不纳入磁盘空间估算的数据库都移动到"排除"列表中，然后单击"下一步"按钮。

  6. 选择"使用默认配置"或编辑默认值，然后单击"编辑"按钮。

    出现 SQL Server 升级向导版式实用工具，显示推荐使用的 SQL Server 2000 数据文件版式。

  7. 单击"高级"。

  8. 单击"建议的数据库布局"框中的一个对象，以便在"对象详细信息"框中查看详细信息。

  9. "驱动器摘要"框显示所有 SQL Server 2000 数据文件的估计大小和所有本地固定磁盘上剩余的可用磁盘空间。在"选项"菜单上选择"可用空间包括 SQL Server 6.5 文件"以查看若删除 SQL Server 6.5 数据文件后将剩余的可用空间。

  10. 单击"接受"按钮以返回到"数据库创建"对话框。

  11. 单击"取消"以退出 SQL Server 升级向导。


如何编辑默认数据库配置（SQL Server 升级向导）

说明 若要运行 SQL Server 升级向导，计算机上必须安装有 Microsoft® SQL Server™ 2000 实例。

编辑默认数据库配置

  1. 在 SQL Server 升级向导的"数据库创建"对话框中单击"编辑"按钮。

  2. 单击"高级"按钮以查看对象详细信息和驱动器摘要。

  3. 在"建议的数据库布局"框中双击一个数据库文件。

  4. 更改任意数据库文件特性，然后单击"确定"按钮。

  5. 查看对驱动器摘要所做的更改。

  6. 完成所有要做的更改后，单击"接受"按钮以保存数据库配置。

请参见

建议的数据库布局


如何使用直接管道将 SQL Server 6.5 版升级到 SQL Server 2000（SQL Server 升级向导）

说明 若要运行 SQL Server 升级向导，计算机上必须安装有 Microsoft® SQL Server™ 2000 实例。

通过命名管道将 SQL Server 6.5 版升级到 SQL Server 2000

  1. 在"开始"菜单中指向"程序"菜单，单击"Microsoft SQL Server — 版本切换"子菜单，单击"SQL Server 升级向导"命令，然后单击"下一步"按钮。

  2. 在"数据和对象传输"屏幕上接受默认选定内容，包括"命名管道"，然后单击"下一步"按钮。建议使用验证选项，但不是必须如此。有关信息，请单击"帮助"按钮。

  3. 在"登录"屏幕上的"导出服务器 (6.5)"组框内的"服务器名称"框中，输入安装 Microsoft SQL Server 6.5 版的本地计算机或远程计算机的名称。

    在"管理员密码 ('sa')"框中输入 SQL Server 6.5 的 sa 密码，然后单击"下一步"按钮。如果不加以更改，SQL Server 2000 的系统管理员密码应是空的。

    对于"导入服务器 (2000)"组框，服务器名称已经提供。如果需要，请输入可选启动参数。有关信息，请单击"帮助"按钮。完成选项的设置后，请单击"下一步"按钮。

  4. 如果已做好升级的准备，请在询问是否要继续的消息框内单击"是"按钮。SQL Server 升级向导关闭 SQL Server 6.5 并启动 SQL Server 2000。

  5. 在"代码页选择"屏幕中接受或更改默认设置，然后单击"下一步"按钮。

  6. 在"数据库选择"屏幕中，将要升级的数据库包括进来。将所有这次不升级的数据库都移动到"排除"列表中，然后单击"下一步"按钮。

    建议转换所有数据库。

  7. 在"数据库创建"对话框中，选择"使用默认配置或编辑默认值"选项，然后单击"下一步"按钮。

    单击"编辑"按钮以进行检查，并在版式实用工具内更改推荐的磁盘配置。在"建议的数据库布局"框中，根据需要进行改动。单击"高级"以查看"对象详细信息"和"驱动器摘要"框。完成后，单击"接受"按钮以返回到 SQL Server 升级向导。

  8. 在"系统配置"屏幕上的"要传输的系统对象"中，选择要从 SQL Server 6.5 传输到 SQL Server 2000 的对象类型：
    • 服务器配置

      与 SQL Server 2000 相关的登录注册和远程登录注册、服务器配置选项均作为版本升级的一部分进行传输。

    • 复制设置

      所有项目，每个已选数据库的订阅和发布，以及分发数据库（如果有的话）均进行传输和升级。

    • SQL Executive 设置

      所有由 SQL Executive 调度的任务均进行传输与升级，以便 SQL Server 2000 可以在 SQL Server 代理中调度和运行这些任务。

  9. 在"系统配置"屏幕上的"高级设置"中，对于"ANSI Nulls"请选择下列选项之一：
    • "Off"（创建存储过程时不应使用 ANSI Null）。这是默认设置。

    • "On"（创建存储过程时应使用 ANSI Null）。
  10. 在"被引用的标识符"中选择下列选项之一，然后单击"下一步"按钮：
    • "混合型（或未知）"（一些对象是用设为 ON 的 QUOTED_IDENTIFIER 创建的，而其余对象是用设为 OFF 的 QUOTED_IDENTIFIER 创建的，或者无法确定它们是如何创建的）。

    • "Off"（所有对象都应该用设为 OFF 的 QUOTED_IDENTIFIER 编译）。

    • "On"（所有对象都应该用设为 ON 的 QUOTED_IDENTIFIER 编译）。
  11. 在"完成 SQL Server 向导"屏幕中，查看所作选择的摘要。单击"在记事本中查看警告和选择"按钮以打开升级脚本的文本版。如果所有的选项都正确，请单击"完成"按钮。

此时出现"SQL Server 升级脚本解释器"屏幕，并附有升级进度信息。

请参见

使用直接管道或磁带驱动器进行升级的次序


如何使用磁带驱动器将 SQL Server 6.5 版升级到 SQL Server 2000（SQL Server 升级向导）

说明 若要运行 SQL Server 升级向导，计算机上必须安装有 Microsoft® SQL Server™ 2000 实例。

使用磁带驱动器将 SQL Server 6.5 版升级到 SQL Server 2000

  1. 在"开始"菜单中指向"程序"菜单，单击"Microsoft SQL Server — 版本切换"子菜单，再单击"SQL Server 升级向导"命令，然后单击"下一步"按钮。

  2. 在"数据和对象传输"屏幕上单击"磁带"选项，然后单击"下一步"按钮。建议使用验证选项，但不是必须如此。有关信息，请单击"帮助"按钮。

  3. 在"登录"屏幕上"导出服务器 (6.5)"组框内的"服务器名称"框中，输入已安装了 Microsoft SQL Server 6.5 版的计算机名称。

    在"管理员密码 ('sa')"框中输入 SQL Server 6.5 的 sa 密码，然后单击"下一步"按钮。

    如果不加以更改，SQL Server 2000 的系统管理员密码应是空的。

    对于"导入服务器 (2000)"组框，服务器名称已经提供。如果需要，请输入可选启动参数。有关信息，请单击"帮助"按钮。完成选项的设置后，请单击"下一步"按钮。

  4. 如果已做好升级的准备，请在询问是否要继续的消息框内单击"是"按钮。SQL Server 升级向导切换到 SQL Server 2000 服务器。

  5. 在"代码页选择"屏幕中接受或更改默认设置，然后单击"下一步"按钮。

  6. 在"数据库选择"屏幕中，把欲升级的数据库包括进来。将所有这次不升级的数据库都移动到"排除"列表中，然后单击"下一步"按钮。

  7. 在"数据传输设备"框中指定磁带驱动器的位置。

  8. 如果尚未备份数据库，请在"6.5 设备备份选项"中选择"导出数据前先备份 6.5 设备"。

    在创建 SQL Server 2000 数据库前，SQL Server 升级向导要么提示备份 SQL Server 6.5 设备，要么自动为您复制这些设备。

  9. 如果磁盘空间不足，必要时可选择"在导入数据之前删除 6.5 设备"选项，然后单击"下一步"按钮。

    在导出对象和数据之后，在 SQL Server 2000 中创建数据库之前，SQL Server 升级向导会删除 SQL Server 6.5 设备以收回磁盘空间。

  10. 选择"使用默认配置"选项或编辑默认值，然后单击"下一步"按钮。

    单击"编辑"按钮以进行检查，并在版式实用工具内更改推荐的磁盘配置。在"建议的数据库布局"框中，根据需要进行改动。单击"高级"以查看"对象详细信息"和"驱动器摘要"框。完成后，单击"接受"按钮以返回到 SQL Server 升级向导。

  11. 在"要传输的系统对象"屏幕中选择要从 SQL Server 6.5 传输到 SQL Server 2000 的对象类型：
    • 服务器配置

      与 SQL Server 2000 相关的登录注册和远程登录注册、服务器配置选项均作为版本升级的一部分进行传输。

    • 复制设置

      所有项目，每个已选数据库的订阅和发布，以及分发数据库（如果有的话）均进行传输和升级。

    • SQL Executive 设置

      所有由 SQL Executive 调度的任务均进行传输与升级，以便 SQL Server 2000 可以在 SQL Server 代理中调度和运行这些任务。

  12. 在"ANSI Nulls"中选择下列选项之一：
    • "Off"（创建存储过程时不应使用 ANSI Null）。这是默认设置。

    • "On"（创建存储过程时应使用 ANSI Null）。
  13. 在"引用的标识符"中选择下列选项之一，然后单击"下一步"按钮：
    • "混合型（或未知）"（一些对象是用设为 ON 的 QUOTED_IDENTIFIER 创建的，而其余对象是用设为 OFF 的 QUOTED_IDENTIFIER 创建的，或者无法确定它们是如何创建的）。

    • "Off"（所有对象都应该用设为 OFF 的 QUOTED_IDENTIFIER 编译）。

    • "On"（所有对象都应该用设为 ON 的 QUOTED_IDENTIFIER 编译）。
  14. 在"完成 SQL Server 向导"屏幕中查看所作选择的摘要。单击"在记事本中查看警告和选择"按钮以打开升级脚本的文本版。如果所有的选项都正确，请单击"完成"按钮。

    此时出现"SQL Server 升级脚本解释器"屏幕，并附有升级进度信息。

请参见

使用直接管道或磁带驱动器进行升级的次序


SQL Server 企业管理器

Microsoft® 管理控制台 (MMC) 是一个工具，它可呈现一个公共界面，用以管理 Microsoft Windows® 网络中的不同服务器应用程序。服务器应用程序提供一个称为 MMC 管理单元的组件，用以向 MMC 用户呈现一个用户界面来管理服务器应用程序。SQL Server 企业管理器是 Microsoft SQL Server™ MMC 的管理单元。

SQL Server 企业管理器是 SQL Server 的主要管理工具，它提供了一个遵从 MMC 标准的用户界面，使用户得以：

  • 定义 SQL Server 实例组。

  • 将个别服务器注册到组中。

  • 为每个已注册的服务器配置所有 SQL Server 选项。

  • 在每个已注册的服务器中创建并管理所有 SQL Server 数据库、对象、登录、用户和权限。

  • 在每个已注册的服务器上定义并执行所有 SQL Server 管理任务。

  • 通过唤醒调用 SQL 查询分析器，交互地设计并测试 SQL 语句、批处理和脚本。

  • 唤醒调用为 SQL Server 定义的各种向导。


管理 SQL Server

Microsoft® SQL Server™ 2000 管理应用程序及其随附的服务旨在协助系统管理员完成所有与维护和监视服务器性能和活动有关的管理任务。

主题 | 描述
启动、暂停和停止 SQL Server | 解释如何启动 SQL Server 实例，以及登录前后和登录过程中需要执行的操作。
故障转移群集 | 描述如何安装和使用 SQL Server 2000 故障转移群集。
导入和导出数据 | 描述如何从外部源检索数据并将数据传送到其它应用程序。
备份和还原数据库 | 针对各种潜在的系统问题，说明保护和还原数据的方法。
使用复制数据库向导 | 描述如何在服务器之间复制或移动数据库，以及如何将数据库从 SQL Server 7.0 版升级到 SQL Server 2000。
管理服务器 | 描述如何注册和配置远程及链接服务器，如何添加或删除服务器以及如何修改服务器设置。
管理客户端 | 描述如何配置客户端与服务器组件的连接，以及如何更改默认网络协议以符合站点的需要。
自动化管理任务 | 说明如何建立定期发生的管理责任、如何定义作业和警报以及如何运行 SQL Server 代理。
安全管理 | 说明如何通过限制权限来保护数据库，使得只有经过授权的用户才可以访问它。
监视服务器性能和活动 | 说明如何开发一个策略以保证服务器和活动性能的水平可以接受。
使用 Web 助手向导 | 解释如何使用该向导创建 Web 页。


如何自动启动 SQL Server 实例（企业管理器）

自动启动 SQL Server 实例

  1. 右击一个服务器，再单击"属性"。

  2. 单击"常规"选项卡。

  3. 在"在操作系统启动时自动启动策略"下选择"自动启动 SQL Server"复选框。

请参见

自动启动 SQL Server

如何关闭 SQL Server 的自动启动（企业管理器）


如何关闭 SQL Server 的自动启动（企业管理器）

关闭 SQL Server 的自动启动

  1. 右击一个服务器，再单击"属性"。

  2. 单击"常规"选项卡。

  3. 在"在操作系统启动时自动启动策略"下清除"自动启动 SQL Server"复选框。

请参见

自动启动 SQL Server

如何自动启动 SQL Server


如何启动 SQL Server（企业管理器）

启动 SQL Server

  • 右击一个服务器，再单击"启动"。

    在服务器名称旁边的图标上会出现绿色箭头，表示服务器已成功启动。

请参见

手工启动 SQL Server

停止 SQL Server

暂停和继续运行 SQL Server


如何停止 SQL Server 或 SQL Server 代理（企业管理器）

说明 在停止 Microsoft® SQL Server™ 实例之前，应当暂停 SQL Server 并停止 SQL Server 代理程序，从而保证最为有序的关闭。也可用 SQL Server 服务管理器停止 SQL Server 和 SQL Server 代理。

停止 SQL Server 或 SQL Server 代理（企业管理器）

  1. 右击一个服务器，再单击"暂停"。

  2. 可选地，发送一个消息，通知已连接用户服务器即将关闭。适当时间间隔后，继续第 3 步。

  3. 右击"SQL Server 代理程序"，然后单击"停止"。

  4. 右击该服务器，然后单击"停止"按钮。

说明 使用 SQL Server 企业管理器或 net stop mssqlserver 命令停止 SQL Server 实例将导致 SQL Server 在所有数据库中执行检查点。然后执行 SHUTDOWN WITH NOWAIT，从数据高速缓存中刷新所有提交的数据并立即停止服务器。

停止 SQL Server 或 SQL Server 代理（服务管理器）

  1. 如果该服务是远程服务，则在"服务器"框中输入远程服务器的名称。如果是本地服务器，"服务器"框将是已填好的。

    这样可将您连接到远程服务器，并将在远程计算机上注册的 SQL Server 服务的名称填充到"服务"框中。

  2. 在"服务"对话框中单击"SQL Server"或"SQL Server 代理"选项。

  3. 单击"暂停"按钮。

如果正在停止 SQL Server 代理程序，则继续第 4 步。否则，发送一条消息，通知连接的用户服务器将关机。适当时间间隔后，继续第 4 步。

  4. 单击"停止"按钮。

请参见

停止 SQL Server


如何启动 SQL Server 的默认实例（服务管理器）

启动 SQL Server 的默认实例

  1. 在"服务"框中，单击"SQL Server"。

    如果该服务是远程服务，则在"服务器"框中输入远程服务器的名称。

  2. 单击"开始/继续"按钮。

请参见

手工启动 SQL Server


如何启动 SQL Server 的聚集实例（服务管理器）

启动 SQL Server 的聚集实例

  1. 在"服务器"框中输入虚拟 SQL Server 的名称。如果它是默认实例，只需指定虚拟服务器名称。如果它是命名实例，则必须输入 VIRTUALSERVER\Instance。

  2. 在"服务"框中，单击"SQL Server"。

  3. 单击"开始/继续"按钮。

请参见

手工启动 SQL Server


如何启动 SQL Server 的命名实例（服务管理器）

启动 SQL Server 的命名实例

  1. 在"服务器"框中，选择服务器的名称及 Microsoft® SQL Server™ 2000 的命名实例，或输入远程服务器的名称。

  2. 在"服务"框中，单击 SQL Server，单击"开始"按钮，然后再单击"继续"按钮。


如何启动 SQL Server 的默认实例 (Windows)

启动 SQL Server 的默认实例

  1. 在"控制面板"中双击"服务"。

  2. 在"服务"对话框中，单击"MSSQLSERVER"，然后单击"开始"。


如何启动 SQL Server 的命名实例 (Windows)

启动 SQL Server 的命名实例

  1. 在"控制面板"中双击"服务"。

  2. 在"服务"对话框中，单击要启动的 Microsoft® SQL Server™ 2000 的命名实例，然后单击"启动"。


如何启动 SQL Server 的默认实例（命令提示符）

从命令提示符启动 SQL Server 的默认实例

  • 从命令提示符输入：

    sqlservr.exe -c

    说明 在启动 sqlservr.exe 之前，必须在命令窗口中切换到适当的目录（要启动的 Microsoft® SQL Server™ 实例所在的目录）。

请参见

手工启动 SQL Server


如何启动 SQL Server 的命名实例（命令提示符）

从命令提示符启动 SQL Server 的命名实例

  • 从命令提示符输入以下命令：

sqlservr.exe -c -s {instancename}

说明 在启动 sqlservr.exe 之前，必须在命令窗口中切换到适当的目录（要启动的 Microsoft® SQL Server™ 2000 实例所在的目录）。例如，如果实例 1 使用 \mssql$Instance1 存储它的二进制文件，则必须在 \mssql$Instance1\binn 目录中启动 sqlservr.exe。


如何在单用户模式下启动 SQL Server 的默认实例（命令提示符）

在单用户模式下从命令提示符启动 SQL Server 的默认实例

  • 从命令提示符输入：

    sqlservr.exe -c -m

    说明 在启动 sqlservr.exe 之前，必须在命令窗口中切换到适当的目录（要启动的 Microsoft® SQL Server™ 实例所在的目录）。

请参见

在单用户模式下启动 SQL Server

使用启动选项


如何在单用户模式下启动 SQL Server 的命名实例（命令提示符）

在单用户模式下从命令提示符启动 SQL Server 的命名实例

  • 从命令提示符输入：

    sqlservr.exe -c - m -s {instancename}

    说明 在启动 sqlservr.exe 之前，必须在命令窗口中切换到适当的目录（要启动的 Microsoft® SQL Server™ 2000 实例所在的目录）。


如何以最小配置启动 SQL Server 的默认实例（命令提示符）

以最小配置启动 SQL Server 的默认实例

  • 从命令提示符输入以下命令，以启动 Microsoft® SQL Server™ 的默认实例作为服务：

    sqlservr -c -f

    说明 在启动 sqlservr.exe 之前，您必须在命令窗口中转换到适当的目录（要启动的 SQL Server 实例所在的目录）。

请参见

手工启动 SQL Server


如何以最小配置启动 SQL Server 的命名实例（命令提示符）

以最小配置启动 SQL Server 的命名实例

  • 从命令提示符输入以下命令，以启动 Microsoft® SQL Server™ 2000 的命名实例作为服务：

    sqlservr -c -f -s {instancename}

    说明 在启动 sqlservr.exe 之前，您必须在命令窗口中转换到适当的目录（要启动的 SQL Server 实例所在的目录）。


如何暂停和继续执行 SQL Server 的默认实例（服务管理器）

暂停和继续执行 SQL Server 的默认实例

  1. 在"服务"框中，单击"SQL Server"。

    如果该服务是远程服务，则键入远程服务器的名称。

  2. 单击"暂停"，单击"开始/继续"按钮。

请参见

暂停和继续运行 SQL Server


如何停止 SQL Server 聚集实例（服务管理器)

停止 SQL Server 的聚集实例

  1. 在"服务器"框中，输入虚拟 Microsoft® SQL Server™ 的名称。如果它是默认实例，只需指定虚拟服务器名称。如果它是命名实例，则必须输入 VIRTUALSERVER\Instance。

  2. 在"服务"框中，单击"SQL Server"。

  3. 单击"停止"按钮。这会暂停群集资源，然后停止 SQL Server 服务，但不会导致 SQL Server 的故障转移。

请参见

停止 SQL Server


如何暂停和继续执行 SQL Server 的命名实例（服务管理器）

暂停或继续执行 SQL Server 的命名实例

  1. 在"服务器"框中，选择服务器的名称及 Microsoft® SQL Server™ 2000 的命名实例，或输入远程服务器的名称。

  2. 在"服务"框中，单击"SQL Server"。

  3. 单击"暂停"，单击"开始/继续"按钮。


如何暂停和继续执行 SQL Server 的默认实例 (Windows)

暂停和继续执行 SQL Server 的默认实例

  1. 在"控制面板"中双击"服务"。

  2. 在"服务"对话框中，单击"MSSQLSERVER"。

  3. 单击"暂停"或"继续"。


如何暂停和继续执行 SQL Server 的命名实例 (Windows)

暂停或继续执行 SQL Server 的命名实例

  1. 在"控制面板"中双击"服务"。

  2. 在"服务"对话框中，单击要暂停的 Microsoft® SQL Server™ 2000 的命名实例。

  3. 单击"暂停"或"继续"。


如何暂停和继续执行 SQL Server 的默认实例（命令提示符）

暂停和继续执行 SQL Server 的默认实例

  • 从命令提示符输入：

    net pause mssqlserver

    -或-

    net continue mssqlserver

    Microsoft® SQL Server™ 的实例只有在作为 Microsoft Windows NT® 4.0 或 Windows® 2000 服务启动时才可以暂停或继续执行。

请参见

暂停和继续运行 SQL Server


如何暂停或继续执行 SQL Server 的命名实例（命令提示符）

暂停或继续执行 SQL Server 的命名实例

  • 从命令提示符输入：

    net pause mssql$instancename

    -或-

    net continue mssql$instancename


如何广播关机消息（命令提示符）

广播关机消息

  • 从命令提示符输入：

    net send /users "message"

    例如：

    net send /users "SQL Server is going down in 20 minutes.
Disconnect within 15 minutes."

    说明 只有当 Microsoft® SQL Server™ 的实例在 Microsoft Windows NT® 4.0 或 Windows® 2000 上运行时，才会广播关机消息。users 选项指定该消息应该发送给所有连接到服务器上的用户。有关其它"网络发送"选项的信息，请参阅 Windows NT 4.0 和 Windows 2000 文档。

请参见

停止 SQL Server


如何停止 SQL Server 的默认实例 (Windows)

停止 SQL Server 的默认实例

  1. 在"控制面板"中双击"服务"。

  2. 在"服务"对话框中单击"MSSQLSERVER"，然后单击"停止"。


如何停止 SQL Server 命名实例 (Windows)

停止 SQL Server 的命名实例

  1. 在"控制面板"中双击"服务"。

  2. 在"服务"对话框中，单击要停止的 Microsoft® SQL Server™ 2000 命名实例，然后单击"停止"。


如何停止 SQL Server 的默认实例（命令提示符）

停止 SQL Server 的默认实例

  • 从命令提示符输入：

    net stop mssqlserver

说明 使用 SQL Server 企业管理器或 net stop mssqlserver 命令停止 Microsoft® SQL Server™ 的默认实例将导致 SQL Server 在所有数据库中执行检查点。然后执行 SHUTDOWN WITH NOWAIT，从数据高速缓存中刷新所有提交的数据并立即停止服务器。只有在运行 Microsoft Windows NT® 4.0 或 Windows® 2000 时，从命令提示符停止 SQL Server 的默认实例才能起作用。

请参见

停止 SQL Server


如何停止 SQL Server 的命名实例（命令提示符）

停止 SQL Server 的命名实例

  • 从命令提示符输入：

    net stop mssql$instancename

说明 使用 SQL Server 企业管理器或 net stop mssql$instancename 命令停止 Microsoft® SQL Server™ 2000 的命名实例将导致 SQL Server 在所有数据库中执行检查点。然后执行 SHUTDOWN WITH NOWAIT，从数据高速缓存中刷新所有提交的数据并立即停止服务器。只有在运行 Microsoft Windows NT® 4.0 或 Windows® 2000 时，从命令提示符停止 SQL Server 2000 的命名实例才能起作用。


如何登录到 SQL Server 的默认实例（命令提示符）

登录到 SQL Server 的默认实例

  • 从命令提示符输入：

    osql /U [login_id] /P [password] /S [servername]

    -或-

    isql/U [login_id]/P [password] /S [servername]

请参见

osql 实用工具


如何登录到 SQL Server 的命名实例（命令提示符）

登录到 SQL Server 的命名实例

  • 从命令提示符输入：

    osql / U login_id /P password /S servername\instancename

    -或-

    isql/U login_id/P password /S servername\instancename


如何更改默认服务（服务管理器）

更改默认服务

  1. 右击"SQL Server 服务管理器"，然后单击"选项"。

  2. 在"默认服务"框中，选择要通过 SQL Server 服务管理器查看的新默认服务。重新启动计算机时，显示的服务是新的默认服务。例如，如果将默认服务更改为 SQLServerAgent 服务，然后关闭计算机，在下次启动时，SQLServerAgent 服务将显示在服务控制管理器中。您只可以改变本地计算机的默认服务。


如何创建新的故障转移群集（SQL Server 安装程序）

重要 在创建 Microsoft® SQL Server™ 2000 故障转移群集之前，必须配置 Microsoft 群集服务 (MSCS) 并使用 Microsoft Windows NT® 4.0 或 Windows® 2000 中的群集管理员创建至少一个群集磁盘资源。在运行 SQL Server 安装程序之前，在群集管理员中记下群集驱动器的位置，因为创建新的故障转移群集需要该信息。

创建新的故障转移群集

  1. 在"Microsoft SQL Server 安装向导"的"欢迎"屏幕中，单击"下一步"按钮。

  2. 在"计算机名称"屏幕上，单击"虚拟服务器"并输入虚拟服务器名称。如果安装程序检测到 MSCS 正在运行，则将默认为"虚拟服务器"。单击"下一步"按钮。

  3. 在"用户信息"屏幕上，输入用户名和公司名。单击"下一步"按钮。

  4. 在"软件许可协议"屏幕上，单击"是"按钮。

  5. 在"故障转移群集"屏幕上，输入为客户端访问配置的每个网络的一个 IP 地址。也就是为每个虚拟服务器可由公共（或混合）网络上的客户端使用的网络输入一个 IP 地址。选择要输入 IP 地址的网络，然后输入 IP 地址。单击"添加"按钮。

    显示 IP 地址和子网。子网由 MSCS 提供。继续为每个已安装的网络输入 IP 地址，直到所有需要的网络都填充了 IP 地址。单击"下一步"按钮。

  6. 在"群集磁盘选择"屏幕中，选择在默认情况下用于放置数据文件的群集磁盘组。单击"下一步"按钮。

  7. 在"群集管理"屏幕中，查看 SQL Server 2000 所提供的群集定义。默认情况下，选定所有可用节点。删除不属于正创建的虚拟服务器群集定义的任何节点。单击"下一步"按钮。

  8. 在"远程信息"屏幕中，输入远程群集节点的登录凭据。该登录凭据必须在群集的远程节点上有管理员特权。单击"下一步"按钮。

  9. 在"实例名称"屏幕中，选择默认实例或指定命名实例。若要指定命名实例，请先清除"默认"复选框，然后输入命名实例的名称。单击"下一步"按钮。

    重要 不能将实例命名为 DEFAULT 或 MSSQLSERVER。有关 SQL Server 2000 命名实例的更多信息，请参阅使用 SQL Server 2000 的命名实例和多实例。名称必须遵从 SQL Server 标识符规则。有关标识符命名规则的更多信息，请参阅使用标识符。

  10. 在"安装类型"屏幕中选择要安装的安装类型。安装程序自动默认为来自先前所选的组中的第一个可用群集磁盘资源。不过，如果需要指定另一个群集驱动器资源，可在"数据文件"下单击"浏览"按钮，然后指定群集驱动器资源的路径。安装程序将要求选择群集驱动器资源，该资源为正在运行安装程序的节点所拥有。该驱动器也必须是先前所选的群集组成员。单击"下一步"按钮。

  11. 在"服务帐户"屏幕上，选择要在故障转移群集中运行的服务帐户。单击"下一步"按钮。

  12. 在"身份验证模式"对话框中，选择要使用的身份验证模式。如果将选择内容从"Windows 身份验证模式"变为"混合模式（Windows 身份验证和 SQL Server 身份验证）"，则需要输入并确认 sa 登录密码。

  13. 在"开始复制文件"屏幕上，单击"下一步"按钮。

  14. 在"安装完成"屏幕上，单击"完成"按钮。

    如果安装程序指示重新启动计算机，则立即这样做。完成安装后，阅读来自安装程序的消息是很重要的。未能重新启动任何指定的节点可能导致将来在故障转移群集中的任何节点上运行安装程序失败。


如何安装单节点故障转移群集（SQL Server 安装程序）

  1. 在"Microsoft SQL Server 安装向导"的"欢迎"屏幕中，单击"下一步"按钮。

  2. 在"计算机名称"屏幕上，单击"虚拟服务器"并输入虚拟服务器名称。如果 SQL Server 安装程序检测到 Microsoft® 群集服务 (MSCS) 正在运行，则将默认为"虚拟服务器"。单击"下一步"按钮。

  3. 在"用户信息"屏幕上，输入用户名和公司。单击"下一步"按钮。

  4. 在"软件许可协议"屏幕上，单击"是"按钮。

  5. 在"故障转移群集"屏幕中，输入虚拟服务器的每个已安装网络的 IP 地址。选择要输入 IP 地址的网络，然后输入 IP 地址。单击"添加"按钮。该 IP 地址及子网将在下面显示出来。该子网由 MSCS 提供。继续为每个已安装的网络输入 IP 地址，直到所有需要的网络都填充了 IP 地址。单击"下一步"按钮。

  6. 在"群集磁盘选择"屏幕中，选择将在默认情况下放置数据文件的群集磁盘组。单击"下一步"按钮。

  7. 在"群集管理"屏幕上，查看 Microsoft SQL Server™ 2000 所提供的故障转移群集定义。默认情况下，选定所有可用的节点。删除任何不属于正在创建的虚拟服务器群集定义的节点。单击"下一步"按钮。

  8. 在"远程信息"屏幕中，输入在群集的远程节点上有管理员特权的登录凭据。单击"下一步"按钮。

  9. 在"实例名称"屏幕中，选择默认实例或指定命名实例。若要指定命名实例，请先清除"默认"复选框，然后键入实例名称。单击"下一步"按钮。

    重要 不能将实例命名为 DEFAULT 或 MSSQLSERVER。其名称必须遵守有关 SQL Server 标识符的规则。有关标识符命名规则的更多信息，请参阅使用标识符。

  10. 在"安装类型"屏幕中，选择要安装的安装类型。安装程序默认自动选择来自先前所选择的组中的第一个可用的群集磁盘资源。不过，如果需要指定另一个群集驱动器资源，则在"数据文件"下单击"浏览"按钮，然后指定群集驱动器资源的路径。您必须选择一个由正在其上运行安装程序的节点所拥有的群集驱动器资源。该驱动器也必须是先前所选的群集组中的成员。单击"下一步"按钮。

  11. 在"服务帐户"屏幕上，选择要在故障转移群集中运行的服务帐户。单击"下一步"按钮。

  12. 在"身份验证模式"对话框中，选择要使用的身份验证模式。如果将选择内容从"Windows 身份验证模式"变为"混合模式（Windows 身份验证和 SQL Server 身份验证）"，则必须输入并确认 sa 登录密码。

  13. 在"开始复制文件"屏幕上单击"下一步"按钮。

  14. 在"安装完成"屏幕上单击"完成"按钮。如果安装程序指示重新启动计算机，则立即进行此操作。完成安装后，阅读来自安装程序的消息是很重要的。未能重新启动任何指定的节点可能导致将来在群集中的任何节点上运行安装程序时失败。


如何将节点添加到现有的虚拟服务器（SQL Server 安装程序）

  1. 在"Microsoft SQL Server 安装向导"的"欢迎"屏幕中，单击"下一步"按钮。

  2. 在"计算机名称"屏幕中，单击"虚拟服务器"选项，并指定要向其添加节点的虚拟服务器。单击"下一步"按钮。

  3. 在"安装选择"屏幕上，单击"高级选项"按钮。单击"下一步"按钮。

  4. 在"高级选项"屏幕上，单击"维护故障转移群集的虚拟服务器"。单击"下一步"按钮。

  5. 在"故障转移群集"屏幕上，单击"下一步"按钮。

    不需要输入 IP 地址。

  6. 在"群集管理"屏幕上，选择节点并单击"添加"按钮。

    如果列出的节点不可用，则必须修改虚拟服务器的群集组中的磁盘资源，以便要添加到 Microsoft® SQL Server™ 配置中的节点可以使用该磁盘。单击"下一步"按钮。

  7. 在"远程信息"屏幕中，为在该群集的远程节点上具有管理员特权的远程群集节点输入登录凭据。单击"下一步"按钮。

  8. 在"安装完成"屏幕中，单击"完成"按钮。


如何从现有的故障转移群集中删除节点（SQL Server 安装程序）

  1. 在"Microsoft SQL Server 安装向导"的"欢迎"屏幕中，单击"下一步"按钮。

  2. 在"计算机名称"屏幕中，选择"虚拟服务器"选项并指定要从中删除节点的服务器名称。单击"下一步"按钮。

  3. 可能会看到一条错误信息，指示 Microsoft Windows® NT 4.0 或 Windows 2000® 群集的一个（或多个）节点不可用。这可能是因为正试图删除的节点已损坏。但仍然可以删除该节点。单击"确定"按钮。

  4. 在"安装选择"屏幕上，单击"高级选项"。单击"下一步"按钮。

  5. 在"高级选项"屏幕上，单击"维护故障转移群集的虚拟服务器"。单击"下一步"按钮。

  6. 在"故障转移群集"屏幕上，单击"下一步"按钮。

    不需要修改任何 IP 地址。

  7. 在"群集管理"屏幕上，选择节点并单击"删除"。单击"下一步"按钮。

  8. 在"远程信息"屏幕中，为在该群集的远程节点上具有管理员特权的远程群集节点输入登录凭据。单击"下一步"按钮。

  9. 在"安装完成"屏幕中，单击"完成"按钮。

    如果得到重新启动计算机的指示，请立即进行此操作。完成安装后，阅读 SQL Server 安装程序中的信息是很重要的。重新启动任何指定的节点失败都可能导致将来在故障转移群集中任何节点上运行安装程序失败。


如何删除群集实例（SQL Server 安装程序）

  1. 在"Microsoft SQL Server 安装向导"的"欢迎"屏幕中，单击"下一步"按钮。

  2. 在"计算机名称"屏幕中，选择"虚拟服务器"并指定要从中删除群集实例的服务器名。单击"下一步"按钮。

  3. 在"安装选择"屏幕中，单击"对现有 SQL Server 实例进行升级、删除或添加组件"。

  4. 在"实例名称"屏幕上，对于默认实例，单击"默认"按钮。对于命名实例，指定要删除的实例名。单击"下一步"按钮。

  5. 在"现有安装"屏幕上，单击"卸载现有安装"按钮。单击"下一步"按钮。

  6. 在"远程信息"屏幕中，指定对此群集所有节点都有效的管理员密码。单击"下一步"按钮。

  7. 出现"安装"信息的"成功卸载实例 . . . "后，单击"确定"按钮。

  8. 在"安装完成"屏幕中，单击"完成"按钮。

    如果安装程序指示重新启动计算机，则立即进行此操作。完成安装后，阅读来自 SQL Server 安装程序的消息是很重要的。未能重新启动任何指定的节点可能导致将来在故障转移群集中的任何节点上运行安装程序失败。


如何从第一种情况的故障转移群集失败中恢复

在此情况中，失败是由两个节点的群集中节点 1 的硬件故障造成的。例如，该硬件故障可能是由小型计算机系统接口 (SCSI) 卡的故障或操作系统的故障引起的。

  1. 节点 1 失败后，Microsoft® SQL Server™ 2000 故障转移群集将故障转移到节点 2。

  2. 运行 SQL Server 安装程序并删除节点 1。有关更多信息，请参阅维护故障转移群集。

  3. 从 Microsoft 群集服务 (MSCS) 中排除节点 1。若要从 MSCS 中排除节点，可在节点 2 中右击要删除的节点，然后单击"排除节点"命令。

  4. 安装新的硬件，以替换节点 1 中发生故障的硬件。

  5. 安装操作系统。有关安装哪种操作系统以及具体的安装方法的更多信息，请参阅安装故障转移群集前的准备工作。

  6. 安装 MSCS 并联接现有群集。有关更多信息，请参阅安装故障转移群集前的准备工作。

  7. 在节点 2 上运行安装程序，并将节点 1 添加回故障转移群集。


如何从第二种情况的故障转移群集失败中恢复

第二种情况，失败由节点 1 关闭或脱机引起，但不是无法挽回的损坏。例如，这可能是由操作系统故障造成的。

  1. 节点 1 失败后，Microsoft® SQL Server™ 2000 故障转移群集将故障转移到节点 2。

  2. 运行 SQL Server 安装程序并删除节点 1。有关更多信息，请参阅维护故障转移群集。

  3. 解决节点 1 的问题。

  4. 确保Microsoft 群集服务 (MSCS) 群集正在工作且所有节点均处于联机状态。

  5. 在节点 2 上运行安装程序，并将节点 1 添加回故障转移群集。


如何从 SQL Server 6.5 主动/被动故障转移群集升级（SQL Server 安装程序）

从 SQL Server 6.5 主动/被动故障转移群集升级

  1. 取消群集 Microsoft® SQL Server™ 6.5版。

  2. 安装 SQL Server 2000 默认实例。

    必须将二进制文件安装到某个本地驱动器并对数据使用群集磁盘。该本地驱动器是路径，它是在群集的所有节点上都有效的非群集磁盘。在群集的所有节点上，该驱动器必须至少有 300 MB 的可用空间。

  3. 运行 SQL Server 升级向导以将数据迁移到 SQL Server 2000 中。

  4. 卸载 SQL Server 6.5。

  5. 运行 SQL Server 安装程序以将 SQL Server 2000 默认实例升级到 SQL Server 2000 故障转移群集。

    有关更多信息，请参阅如何从默认实例升级到 SQL Server 2000 的默认群集实例（SQL Server 安装程序）。

请参见

如何用直接管道将 SQL Server 6.5 版升级到 SQL Server 2000（SQL Server 升级向导）

如何用磁带驱动器将 SQL Server 6.5 版升级到 SQL Server 2000（SQL Server 升级向导）


如何从 SQL Server 6.5 主动/主动故障转移群集升级（SQL Server 安装程序）

说明 若要从 Microsoft® SQL Server™ 6.5 主动/主动故障转移群集（或 SQL Server 存在于第二个节点上的任何配置）升级，必须先将故障转移群集的一端转换为 SQL Server 2000 命名实例。

从 SQL Server 6.5 主动/主动故障转移群集升级

  1. 在节点 1 上，取消群集 SQL Server 6.5。在节点 2 上，取消群集 SQL Server 6.5。

  2. 在节点 1 上，安装 SQL Server 2000 默认（非群集）实例。

    必须将二进制文件安装到某个本地驱动器并对数据使用群集磁盘。该本地驱动器是路径，它是在群集的所有节点上都有效的非群集磁盘。在群集的所有节点上，该驱动器必须有至少 300 MB 的可用空间。

  3. 在节点 1 上运行 SQL Server 2000 升级向导以将数据迁移到 SQL Server 2000 中。

  4. 卸载 SQL Server 6.5 实例。

  5. 安装 SQL Server 2000 的命名群集实例。

  6. 运行复制数据库向导 (CDW.exe) 以将 SQL Server 数据（最初来自 SQL Server 6.5）迁移到 SQL Server 2000 故障转移群集中的命名实例。有关复制数据库向导的更多信息，请参阅使用复制数据库向导或如何使用复制数据库向导联机升级数据库（企业管理器）。

  7. 在节点 1 上卸载 SQL Server 2000 默认实例。

  8. 在节点 2 上安装 SQL Server 2000 默认实例。

  9. 运行 SQL Server 2000 升级向导以将数据迁移到 SQL Server 2000 中。

    必须将二进制文件安装到某个本地驱动器并对数据使用群集磁盘。该本地驱动器是路径，它是在群集的所有节点上都有效的非群集磁盘。在群集的所有节点上，该驱动器必须有至少 300 MB 的可用空间。

  10. 卸载 SQL Server 6.5 实例。

  11. 在节点 2 上，将 SQL Server 默认实例升级为群集实例。

    有关更多信息，请参阅如何从默认实例升级到 SQL Server 2000 的默认群集实例（SQL Server 安装程序）。


如何从 SQL Server 7.0 主动/主动故障转移群集升级（SQL Server 安装程序）

说明 若要从 Microsoft® SQL Server™ 7.0 版主动/主动故障转移群集（或 SQL Server 存在于第二个节点上的任何配置）升级，必须先将故障转移群集的一端转换为 SQL Server 2000 命名实例。

从 SQL Server 7.0 主动/主动故障转移群集升级

  1. 在节点 1 上，取消群集 SQL Server 7.0 版。

  2. 在节点 2 上，取消群集 SQL Server 7.0。

  3. 在节点 1 上，将 SQL Server 2000 的群集命名实例作为虚拟服务器安装。这不是升级过程，而是并行安装 SQL Server 7.0 和 SQL Server 2000。

  4. 在节点 1 上，运行复制数据库向导 (CDW.exe) 以将所有数据库及相关信息从 SQL Server 7.0 安装移动到 SQL Server 2000 的群集命名实例中。有关复制数据库向导的更多信息，请参阅使用复制数据库向导或如何使用复制数据库向导联机升级数据库（企业管理器）。

  5. 在节点 1 上，卸载 SQL Server 7.0。

  6. 在节点 2 上，将 SQL Server 7.0 作为默认实例升级到 SQL Server 2000。

    必须将二进制文件安装到某个本地驱动器并对数据使用群集磁盘。该本地驱动器是路径，它是在群集的所有节点上都有效的非群集磁盘。在群集的所有节点上，该驱动器必须有至少 300 MB 的可用空间。

  7. 在节点 2 上，将 SQL Server 2000 默认实例升级为群集实例。

    有关更多信息，请参阅如何从默认实例升级到 SQL Server 2000 的默认群集实例（SQL Server 安装程序）。

说明 或者，可以创建两个 SQL Server 2000 命名实例，并使用复制数据库向导将这两个 SQL Server 7.0 安装都升级到 SQL Server 2000 的群集命名实例。这将提供更好的一致性，因为对 SQL Server 2000 群集安装的所有引用都将是 VirtualServer\Instance 形式，而不是有时仅为 servername 形式，有时为 servername 和 instancename 形式。


如何从 SQL Server 7.0 主动/被动故障转移群集升级（SQL Server 安装程序）

从 SQL Server 7.0 主动/被动故障转移群集升级

  1. 在节点 1 上，取消群集 Microsoft® SQL Server™ 7.0 版。

  2. 在节点 1 上，将 SQL Server 7.0 作为默认实例升级到 SQL Server 2000。

    必须将二进制文件安装到某个本地驱动器并对数据使用群集磁盘。该本地驱动器是路径，它是在群集的所有节点上都有效的非群集磁盘。在群集的所有节点上，该驱动器必须有至少 300 MB 的可用空间。

  3. 在节点 1 上，将 SQL Server 2000 默认实例作为 SQL Server 2000 群集实例升级。

    有关更多信息，请参阅如何从默认实例升级到 SQL Server 2000 的默认群集实例（SQL Server 安装程序）。


如何从默认实例升级到 SQL Server 2000 的默认群集实例（SQL Server 安装程序）

说明 该升级是从默认实例（数据在本地磁盘上的本地安装）升级到 Microsoft® SQL Server™ 2000 的群集实例。如果希望有默认虚拟服务器，则使用该升级。

从默认实例升级到 SQL Server 2000 的默认群集实例

  1. 在"Microsoft SQL Server 安装向导"的"欢迎"屏幕中，单击"下一步"按钮。

  2. 在"计算机名称"屏幕上，单击"本地计算机"按钮。此时应显示您希望从默认实例改变为群集实例的计算机。必须是在本地计算机上才能将默认实例升级为群集实例。单击"下一步"按钮。

  3. 在"安装选择"屏幕中，单击"对现有 SQL Server 实例进行升级、删除或添加组件"。单击"下一步"按钮。

  4. 在"现有安装"屏幕上，单击"升级现有安装为群集安装"。单击"下一步"按钮。

  5. 在"虚拟服务器名称"屏幕中，输入虚拟服务器的名称。单击"下一步"按钮。

  6. 在"故障转移群集"屏幕上，输入为客户端访问配置的每个网络的一个 IP 地址。也就是为每个虚拟服务器可由公共（或混合）网络上的客户端使用的网络输入一个 IP 地址。选择要输入 IP 地址的网络，然后输入 IP 地址。单击"添加"按钮。

    显示 IP 地址和子网。子网由 Microsoft 群集服务 (MSCS) 提供。继续为每个已安装的网络输入 IP 地址，直到所有需要的网络都填充了 IP 地址。单击"下一步"按钮。

  7. 在"群集管理"屏幕上，查看 SQL Server 2000 所提供的故障转移群集定义。默认情况下，选定所有可用节点。删除不属于正在创建的虚拟服务器群集定义的任何节点。单击"下一步"按钮。

  8. 在"远程信息"屏幕中，输入远程群集节点的登录凭据。该登录凭据必须在群集的远程节点上有管理员特权。单击"下一步"按钮。

  9. 在"服务帐户"屏幕中，为将在其下运行故障转移群集的 SQL Server 服务选择服务帐户。单击"下一步"按钮。

  10. 在"安装完成"屏幕中单击"完成"按钮。如果需要重新启动故障转移群集中的远程节点，则安装程序将在"安装完成"屏幕中提供相应的指示。


如何从本地默认实例升级到 SQL Server 2000 命名群集实例（SQL Server 安装程序）

从本地默认实例升级到 SQL Server 2000 的命名群集实例

  1. 安装 Microsoft® SQL Server™ 2000 的群集命名实例。

  2. 运行复制数据库向导 (CDW.exe) 以将所有数据库及相关信息移动到 SQL Server 2000 的群集命名实例中。有关复制数据库向导的更多信息，请参阅使用复制数据库向导或如何使用复制数据库向导联机升级数据库（企业管理器）。

  3. 或者，可以卸载 SQL Server 2000 的默认实例。


备份和还原数据库

Microsoft® SQL Server™ 的备份和还原组件为保护存储在 SQL Server 数据库中的关键数据提供了非常重要的安全措施。理解如何创建和还原数据库、差异数据库、事务日志，以及文件和文件组备份有助于实施这一重要的维护手段。


如何创建逻辑磁盘备份设备（企业管理器）

创建逻辑磁盘备份设备

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹，右击"备份"，然后单击"新建备份设备"命令。

  3. 在"名称"框中输入该命名备份设备的名称。

  4. 单击"文件名"，然后执行下列操作之一：
    • 输入磁盘备份设备所使用的文件名。

    • 单击浏览（"..."）按钮显示"备份设备位置"对话框，再选择磁盘备份设备所使用的本地计算机上的物理文件。

请参见

备份设备


如何创建逻辑磁带备份设备（企业管理器）

创建逻辑磁带备份设备

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹，右击"备份"，然后单击"新建备份设备"命令。

  3. 在"名称"框中输入该命名备份设备的名称。

  4. 单击"磁带驱动器名"，然后单击要用作磁带备份设备的磁带设备。

说明 如果没有列出磁带设备，则在本地计算机上将无法检测到磁带设备。有关如何设置磁带设备的更多信息，请参阅 Microsoft® Windows NT® 4.0 和 Windows® 2000 文档。

请参见

备份设备


如何删除逻辑备份设备（企业管理器）

删除逻辑备份设备

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹，然后单击"备份"。

  3. 在详细信息窗格中，右击要删除的命名备份设备。

  4. 单击"删除"命令并确认删除。

请参见

备份设备

sp_dropdevice


如何创建数据库备份（企业管理器）

创建数据库备份

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"备份数据库"命令。

  3. 在"名称"框内，输入备份集名称。在"描述"框中输入对备份集的描述。（可选）

  4. 在"备份"选项下单击"数据库 — 完全"。

  5. 在"目的"选项下，单击"磁带"或"磁盘"，然后指定备份目的地。

    如果没出现备份目的地，则单击"添加"以添加现有的目的地或创建新目的地。

  6. 在"重写"选项下，执行下列操作之一：
    • 单击"追加到媒体"，将备份追加到备份设备上任何现有的备份中。

    • 单击"重写现有媒体"，将重写备份设备中任何现有的备份。
  7. 选择"调度"复选框调度备份操作在以后执行或定期执行。（可选）

  8. 单击"选项"选项卡并执行下列一项或多项操作：（可选）
    • 选择"完成后验证备份"复选框，在备份时对备份进行验证。

    • 选择"备份后弹出磁带"复选框，在备份操作完成后弹出磁带。该选项只适用于磁带设备。

    • 选择"检查媒体集名称和备份集到期时间"，检查备份媒体以防意外重写。在"媒体集名称"框中，输入将用于备份操作的媒体的名称。如果仅指定备份集到期时间，则将其保留为空。
  9. 如果是第一次使用备份媒体，或者要更改现有的媒体标签，则在"媒体集标签"框下选择"初始化并标识媒体"复选框，然后输入媒体集名称和媒体集描述。只有在重写媒体时才能对其进行初始化和标识设置。

请参见

追加备份集

备份 master 数据库

备份 model、msdb 和 distribution 数据库

复制数据库

事务日志备份

数据库备份

差异数据库备份

删除数据库

重写备份媒体

减少恢复时间

初始化备份媒体

验证备份


如何启动创建数据库备份向导（企业管理器）

启动创建数据库备份向导

  1. 展开服务器组，然后展开服务器。

  2. 在"工具"菜单上单击"向导"命令。

  3. 在"选择向导"对话框中，展开"管理"。

  4. 双击"备份向导"。

  5. 完成向导中的步骤。

请参见

数据库备份


如何还原数据库备份（企业管理器）

说明 如果要还原数据库备份，而在 msdb 数据库中存储的备份历史记录中没有列出此数据库备份的任何备份集信息，例如在另一台服务器上创建的数据库备份，请参阅如何从备份设备还原备份。

还原数据库备份

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"还原数据库"命令。

  3. 在"还原为数据库"框中，如果要还原的数据库名称与显示的默认数据库名称不同，请在其中进行输入或选择。若要用新名称还原数据库，请输入新的数据库名称。

  4. 单击"数据库"。

  5. 在"要还原的第一个备份"列表中，选择要还原的备份集。

  6. 在"还原"列表中，单击要还原的数据库备份。

  7. 单击"选项"选项卡并执行下列操作：（可选）
    • 在"还原为"中输入组成数据库备份的各数据库文件的新名称或新位置。

      说明 为数据库指定新名称将自动为从数据库备份中还原的数据库文件指定新名称。

    • 单击"使数据库可以继续运行，但无法还原其它事务日志"，如果没有其它要应用的事务日志或差异数据库备份。

    • 如果要应用另一个事务日志或差异数据库备份，则单击"使数据库不再运行，但能还原其它事务日志"。

请参见

事务日志备份

数据库备份

差异数据库备份

标识要还原的备份集

重建 master 数据库

将数据库还原到前一个状态

从当前备份还原 master 数据库

还原 model、msdb 和 distribution 数据库

减少恢复时间


如何从备份设备还原备份（企业管理器）

从备份设备还原备份

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"还原数据库"命令。

  3. 在"还原为数据库"框中，如果要还原的数据库名称与显示的默认数据库名称不同，请在其中进行输入或选择。若要用新名称还原数据库，请输入新的数据库名称。

    说明 为数据库指定新名称将自动为从数据库备份中还原的数据库文件指定新名称。

  4. 单击"从设备"，然后单击"选择设备"。

  5. 在"还原自"下，单击"磁带"或"磁盘"，然后选择还原设备。

    如果没有出现设备，则单击"添加"以添加现有的备份设备或创建新的备份设备。在"还原数据库"对话框内，单击"查看内容"并选择要还原的备份集。

    说明 此选项将扫描备份集以获得备份内容信息，该操作可能需要花费较长时间，特别是在使用磁带设备时。如果已经知道要还原的备份集，则在"备份号"中输入备份集编号。

  6. 在"还原备份集"下执行下列操作之一：
    • 单击"数据库 — 完全"还原数据库备份。

    • 单击"数据库 — 差异"还原差异数据库备份。

    • 单击"事务日志"应用事务日志备份。

    • 单击"文件或文件组"还原文件或文件组备份。指定文件或文件组的名称。
  7. 单击"选项"选项卡，然后执行下列操作之一：（可选）
    • 单击"使数据库可以继续运行，但无法还原其它事务日志"，如果没有其它要应用的事务日志备份。

    • 单击"使数据库不再运行，但能还原其它事务日志"，如果要应用其它事务日志备份。

请参见

事务日志备份

数据库备份

差异数据库备份

标识要还原的备份集

重建 master 数据库

将数据库还原到前一个状态

从当前备份还原 master 数据库

还原 model、msdb 和 distribution 数据库

减少恢复时间


如何创建事务日志备份（企业管理器）

创建事务日志备份

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，再单击"备份数据库"命令。

  3. 在"名称"框中输入备份集名称。在"描述"框中输入对备份集的描述。（可选）

  4. 在"备份"下，单击"事务日志"。

    说明 如果"事务日志"选项不可用，需确保恢复模型设置为"完全"或"大容量日志记录"。有关更多信息，请参阅使用恢复模型。

  5. 在"目的"下，单击"磁带"或"磁盘"，然后指定备份目的地。

    如果没有出现目的地，单击"添加"以添加现有的备份设备或创建新的备份设备。

  6. 在"重写"下执行下列操作之一：
    • 单击"追加到媒体"，将备份追到备份设备上任何现有的备份中。

    • 单击"重写现有媒体"，将重写备份设备中任何现有的备份。
  7. 选择"调度"复选框调度备份操作以后执行或定期执行。（可选）

  8. 单击"选项"选项卡，然后执行下列操作之一：（可选）
    • 选择"完成后验证备份"复选框，在备份时验证备份。

    • 选择"备份后弹出磁带"复选框，在备份操作完成后弹出磁带。该选项只适用于磁带设备。

    • 选择"删除事务日志中不活动的条目"复选框，截断事务日志中的不活动部分，从而允许使用 Microsoft® SQL Server™。

    • 重新使用此截断的未用空间。

    • 选择"检查媒体集名称和备份集到期时间"，检查备份媒体以防意外重写。在"媒体集名称"框中，输入将用于备份操作的媒体的名称。如果仅指定备份集到期时间，则将其保留为空。
  9. 如果是第一次使用备份媒体，或者要更改现有的媒体标签，则在"媒体集标签"框下选择"初始化并标识媒体"复选框，然后输入媒体集名称和媒体集描述。只能在重写媒体时对其进行初始化和标识设置。

请参见

事务日志备份

使用文件备份

将数据库还原到前一个状态

减少恢复时间


如何应用事务日志备份（企业管理器）

说明 如果要还原事务日志备份，而在 msdb 数据库中存储的备份历史记录中没有列出此事务日志备份的任何备份集信息，例如在另一台服务器上创建的事务日志备份，请参阅如何从备份设备还原备份。

应用事务日志备份

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"还原数据库"命令。

  3. 在"还原为数据库"框中，如果要还原的数据库名称与显示的默认数据库名称不同，请在其中进行输入或选择。

  4. 单击"数据库"。

  5. 在"要还原的第一个备份"列表中，选择要还原的备份集。

  6. 在"还原"列表中，单击要还原的事务日志备份。

  7. 单击"选项"选项卡，然后执行下列操作之一：（可选）
    • 单击"使数据库可以继续运行，但无法还原其它事务日志"，如果没有其它要应用的事务日志或差异数据库备份。

    • 单击"使数据库不再运行，但能还原其它事务日志"，如果要应用其它事务日志或差异数据库备份。

请参见

事务日志备份

使用文件备份

减少恢复时间


如何创建差异数据库备份（企业管理器）

创建差异数据库备份

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，再单击"备份数据库"命令。

  3. 在"名称"框内，输入备份集名称。在"描述"框中输入备份集的描述（可选）。

  4. 在"备份"框下选择"数据库 — 差异"。

  5. 在"目的"下，单击"磁带"或"磁盘"，然后指定备份目的地。

    如果没有出现目的地，单击"添加"以添加现有的备份设备或创建新的备份设备。

  6. 在"重写"下执行下列操作之一：
    • 单击"追加到媒体"，将备份追加到备份设备上任何现有的备份中。

    • 单击"重写现有媒体"，将重写备份设备中任何现有的备份。
  7. 选择"调度"复选框调度备份操作以后执行或定期执行。（可选）

  8. 单击"选项"选项卡，然后执行下列一项或多项操作：（可选）
    • 选择"完成后验证备份"复选框，在备份时验证备份。

    • 选择"备份后弹出磁带"复选框，在备份操作完成后弹出磁带。该选项只适用于磁带设备。

    • 选择"检查媒体集名称和备份集到期时间"复选框，检查备份媒体以防意外重写。在"媒体集名称"框中，输入将用于备份操作的媒体的名称。如果仅指定备份集到期时间，则将其保留为空。
  9. 如果是第一次使用备份媒体，或者要更改现有的媒体标签，则在"媒体集标签"框下选择"初始化并标识媒体"复选框，然后输入媒体集名称和媒体集描述。只有在重写媒体时才能对其进行初始化和标识设置。

请参见

差异数据库备份

减少恢复时间


如何还原差异数据库备份（企业管理器）

说明 如果要还原差异数据库备份，而在 msdb 数据库中存储的备份历史记录中没有列出此差异数据库备份的任何备份集信息，例如在另一台服务器上创建的差异数据库备份，请参阅如何从备份设备还原备份。

还原差异数据库备份

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"还原数据库"命令。

  3. 在"还原为数据库"框中，如果要还原的数据库名称与显示的默认数据库名称不同，请在其中进行输入或选择。

  4. 单击"数据库"。

  5. 在"要还原的第一个备份"列表中，选择要还原的备份集。

  6. 在"还原"列表中，单击要还原的差异备份。

  7. 单击"选项"选项卡，然后执行下列操作之一：（可选）
    • 单击"使数据库可以继续运行，但无法还原其它事务日志"，如果没有其它要应用的事务日志备份。

    • 单击"使数据库不再运行，但能还原其它事务日志"，如果要应用其它事务日志备份。

请参见

差异数据库备份

减少恢复时间


如何设置、维护备用服务器并使备用服务器联机（企业管理器）

设置备用服务器通常包括在主服务器上创建数据库备份和周期性事务日志备份，然后按次序将这些备份应用到备用服务器上。在还原操作之间，备用服务器保持为只读状态。当需要使用备用服务器时，任何来自主服务器的未完成的事务日志备份，包括活动事务日志备份，都将应用到备用服务器中，同时还要恢复数据库。

在主服务器上创建备份

如何创建数据库备份

如何创建事务日志备份

设置和维护备份（备用）服务器

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"还原数据库"命令。

  3. 在"还原为数据库"框中，如果要还原的数据库名称与显示的默认数据库名称不同，请在其中进行输入或选择。若要用新名称还原数据库，可输入新名称。

  4. 在"还原"下，单击"从设备"，然后单击"选择设备"。

  5. 在"还原自"下，单击"磁带"或"磁盘"，然后选择还原设备。

    如果没有出现设备，则单击"添加"以添加现有的备份设备或创建新的备份设备。备份设备必须引用在主服务器上创建的备份设备文件。

  6. 在"还原数据库"对话框中单击"查看内容"按钮。选择要还原的备份集。

    说明 此选项将扫描备份集以获得备份内容信息，该操作可能需要花费较长时间，特别是在使用磁带设备时。如果已经知道要还原的备份集，可在"备份号"中输入备份集编号。

  7. 在"还原备份集"下，执行下列操作之一：
    • 单击"数据库 — 完全"，通过它可还原在主服务器上创建的初始数据库备份。必须先还原初始数据库备份，然后才能应用事务日志备份。

    • 单击"事务日志"，通过它可应用在主服务器上创建的事务日志备份。
  8. 在"选项"选项卡上，单击"使数据库为只读，但能还原其它事务日志"，然后在"撤消文件"框内输入撤消文件的名称，该文件包含在影响数据页的未提交事务回滚之前这些数据页的内容。

  9. 对于每个应用于备用服务器的事务日志备份重复此过程。

使备用服务器联机（主服务器发生故障）

  1. 如果可能，备份主服务器上的活动事务日志。

    有关更多信息，请参阅如何创建当前活动事务日志的备份。

  2. 应用所有尚未应用到备用服务器上的事务日志备份，包括步骤 1 中创建的活动事务日志备份。

    有关更多信息，请参阅如何应用事务日志备份。

  3. 恢复数据库。

    有关更多信息，请参阅如何恢复数据库但不还原。

请参见

使用备用服务器


如何还原到某个即时点（企业管理器）

还原到某个即时点

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"还原数据库"命令。

  3. 在"还原为数据库"框中，如果要还原的数据库名称与显示的默认数据库名称不同，请在其中进行输入或选择。

  4. 单击"数据库"。

  5. 在"要还原的第一个备份"列表中，选择要还原的备份集。

  6. 在"还原"列表中选择要还原的数据库备份和一个或多个事务日志。

  7. 选择"时点恢复"，然后输入"日期"和"时间"值。

  8. 单击"选项"选项卡，然后单击"使数据库可以继续运行"。但无法还原其它事务日志"。

请参见

将数据库还原到前一个状态


如何查看备份集内的数据和日志文件（企业管理器）

查看备份集内的数据和日志文件

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"还原数据库"命令。

  3. 单击"从设备"，然后单击"选择设备"。

  4. 在"还原自"下，单击"磁带"或"磁盘"，然后选择还原设备。

    如果没有出现备份目的地，单击"添加"以添加现有的备份设备或创建新的备份设备。备份设备必须引用在主服务器上创建的备份设备文件。

  5. 在"还原数据库"对话框中单击"查看内容"按钮。

请参见

验证备份

查看有关备份的信息


如何查看备份和媒体的标题信息（企业管理器）

查看备份和媒体的标题信息

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹，然后单击"备份"。

  3. 在详细信息窗格中右击要查看的命名备份设备，然后单击"属性"命令。

  4. 单击"查看内容"命令。

请参见

验证备份

查看有关备份的信息


如何备份文件和文件组（企业管理器）

备份文件和文件组

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"备份数据库"命令。

  3. 在"名称"框内，输入备份集名称。在"描述"框中输入对备份集的描述。（可选）

  4. 在"备份"下，单击"文件和文件组"，然后单击浏览（"..."）按钮。

  5. 在"指定文件组和文件"对话框中，为要备份的每个文件组和文件选择"备份"。

    通过选定文件组名，可自动选择该文件组中的所有文件。

  6. 在"目的"选项下，单击"磁带"或"磁盘"，然后指定备份目的地。

    如果没有出现备份目的地，单击"添加"以添加现有的目的地或创建新的目的地。

  7. 在"重写"下，执行下列操作之一：
    • 单击"追加到媒体"，将备份追加到备份设备上任何现有的备份中。

    • 单击"重写现有媒体"，将重写备份设备中任何现有的备份。
  8. 选择"调度"复选框调度备份操作以后执行或定期执行。（可选）

  9. 单击"选项"选项卡，然后执行下列一项或多项操作：（可选）
    • 选择"完成后验证备份"复选框，在备份时对备份进行验证。

    • 选择"备份后弹出磁带"复选框，在备份操作完成后弹出磁带。该选项只适用于磁带设备。

    • 选择"检查媒体集名称和备份集到期时间"，检查备份媒体以防意外重写。在"媒体集名称"框中，输入将用于备份操作的媒体的名称。如果仅指定备份集到期时间，则将其保留为空。
  10. 如果是第一次使用备份媒体，或者要更改现有的媒体标签，则在"媒体集标签"框下选择"初始化并标识媒体"复选框，然后输入媒体集名称和媒体集描述。只有在重写媒体时才能对其进行初始化和标识设置。

请参见

使用文件备份


如何还原文件和文件组（企业管理器）

说明 如果要还原文件或文件组备份，而在 msdb 数据库中存储的备份历史记录中没有列出此文件或文件组备份的任何备份集信息，例如在另一台服务器上创建的文件或文件组备份，请参阅如何从备份设备还原备份。

还原文件和文件组

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"还原数据库"命令。

  3. 在"还原为数据库"框中，如果要还原的数据库名称与显示的默认数据库名称不同，请在其中进行输入或选择。

  4. 单击"文件组或文件"。

  5. 在"还原"列表中，选择每个要还原的文件和文件组。

  6. 单击"选项"选项卡，然后执行下列操作之一：
    • 单击"使数据库可以继续运行，但无法还原其它事务日志"，如果没有其它要应用的事务日志备份。

    • 单击"使数据库不再运行，但能还原其它事务日志"，如果要应用其它事务日志备份。

重要 如果在创建文件备份后修改了文件，则必须应用在文件备份后创建的事务日志备份。

请参见

使用文件备份


如何在现有文件上还原文件和文件组（企业管理器）

在现有文件上还原文件和文件组

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，指向"所有任务"子菜单，然后单击"还原数据库"命令。

  3. 在"还原为数据库"框中，如果要还原的数据库名称与显示的默认数据库名称不同，请在其中进行输入或选择。

  4. 单击"从设备"，然后单击"选择设备"。

  5. 在"还原自"下，单击"磁带"或"磁盘"，然后选择还原设备。

    如果没有出现目的地，单击"添加"以添加现有的备份设备或创建新的备份设备。备份设备必须引用在主服务器上创建的备份设备文件。

  6. 在"还原数据库"对话框中单击"查看内容"按钮。选择要还原的备份集。

    说明 此选项将扫描备份集以获得备份内容信息，该操作可能需要花费较长时间，特别是在使用磁带设备时。如果已经知道要还原的备份集，可在"备份号"中输入备份集编号。

  7. 在"还原备份集"下，单击"文件或文件组"，然后输入要还原的文件名。

  8. 单击"选项"选项卡，然后单击"在现有数据库上强制还原"。

  9. 在"恢复完成状态"下，执行下列操作之一：
    • 单击"使数据库可以继续运行，但无法还原其它事务日志"，如果没有其它要应用的事务日志备份。

    • 单击"使数据库不再运行，但能还原其它事务日志"，如果要应用其它事务日志备份。

请参见

复制数据库


如何为数据库设置恢复模型（企业管理器）

为数据库设置恢复模型

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击数据库，然后单击"属性"命令。

  3. 单击"选项"选项卡。

  4. 在"模型"列表中，单击一种恢复模型。

请参见

使用恢复模型


管理服务器

Microsoft® SQL Server™ 服务器管理由多种管理任务组成，其中包括：

  • 注册服务器和指派密码。

  • 重新配置网络连接。

  • 配置链接服务器，从而使您得以对整个企业内的 OLE DB 数据源执行分布式查询和分布式事务。

  • 配置远程服务器，使您得以使用某个 SQL Server 实例执行驻留在另一 SQL Server 实例上的存储过程。

  • 配置备用服务器。

  • 设置服务器配置选项。

  • 管理 SQL Server 消息。

  • 设置轮询间隔。

在大多数情况下，您无须重新配置服务器。SQL Server 安装程序在运行时会按照默认设置对服务器组件进行配置，使您得以在 SQL Server 安装结束后立即运行 SQL Server 实例。但是在下列情况下需要进行服务器管理：如要添加新的服务器，设置特定的服务器配置，更改网络连接，或者设置服务器配置选项以提高 SQL Server 性能。


如何注册服务器（企业管理器）

注册服务器

  1. 右击一个服务器或服务器组，然后单击"新建 SQL Server 注册"命令。

    说明 如果上次使用注册服务器向导时，选择了"我希望今后在执行该任务时不使用向导"复选框，则 SQL Server 企业管理器将显示"已注册的 SQL Server 属性"对话框。否则，将启动注册服务器向导。

  2. 在"服务器"框中，键入服务器名。

  3. 若要指定 SQL Server 企业管理器（作为客户端）与运行正在注册的 Microsoft® SQL Server™ 实例的服务器之间的连接，请执行下列操作之一：
    • 单击"使用 Windows 身份验证"

    -或-

    • 单击"使用 SQL Server 身份验证"

      使用这种类型的连接，必须提供登录名和密码。选择"总是提示输入登录名和密码"复选框，以便总是提示用户输入登录名和密码，而不要将登录 ID 和密码保存在注册表中。

  4. 在"服务器组"列表中，单击一个服务器组。

    说明 如果所需要的组尚不存在，则单击生成（"..."）按钮创建它，并完成"服务器组"对话框。

  5. 执行下列一个或多个操作：
    • 选择"在控制台中显示 SQL Server 服务器的状态"复选框以打开服务轮询。

    • 选择"显示系统数据库和系统对象"复选框以显示所有系统数据库和对象。

    • 选择"在连接时自动启动 SQL Server"复选框以自动启动 SQL Server 实例。
  6. 重复步骤 1 到 5，在"SQL Server 企业管理器"中注册每个服务器。

请参见

如何创建服务器组

管理服务器

注册服务器


如何创建服务器组（企业管理器）

创建服务器组

  1. 右击一个服务器组，然后单击"新建 SQL Server 注册"命令。

  2. 在"选项"下，单击添加（"..."）按钮。

  3. 在"名称"框中，为该新组输入唯一名称。

  4. 从下列组级别中选择：
    • 顶层组

    • 下面项目子组

      如果选择了此选项，则需要选择一个希望新组位于其下的顶层组。

  5. 重复步骤 2 到 4，创建每个新服务器组。

请参见

如何注册服务器（企业管理器）

管理服务器

注册服务器


如何更改服务器的注册（企业管理器）

更改服务器的注册

  1. 展开一个服务器组，然后右击一个服务器。

  2. 单击"编辑 SQL Server 注册属性"，然后将服务器的注册更改为合适的值。

请参见

注册服务器


如何删除运行 SQL Server 的注册服务器（企业管理器）

删除运行 SQL Server 的注册服务器

  1. 展开一个服务器组，然后右击一个服务器。

  2. 单击"删除 SQL Server 注册"。

  3. 确认删除。


如何连接到运行 SQL Server 的注册服务器（企业管理器）

连接到运行 SQL Server 的注册服务器

  1. 展开一个服务器组，然后右击一个服务器。

  2. 单击"连接"或展开服务器。


如何断开与运行 SQL Server 的注册服务器的连接（企业管理器）

断开与运行 SQL Server 的注册服务器的连接

  1. 展开一个服务器组，然后右击一个服务器。

  2. 单击"断开"。


如何在新安装的服务器上指派 sa 密码（企业管理器）

指派 sa 密码

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，再单击"登录"。

  3. 在详细信息窗格中，右击"sa"，然后单击"属性"命令。

  4. 在"密码"框中，键入新密码。


如何查看服务器属性（企业管理器）

查看服务器属性

  1. 展开一个服务器组，然后右击一个服务器。

  2. 单击"属性"。


如何检查和设置远程服务器配置选项（企业管理器）

检查和设置远程服务器配置选项

  1. 展开一个服务器组，然后右击一个服务器。

  2. 单击"属性"，然后单击"连接"选项卡。

  3. 在"远程服务器连接"下，复查并在合适时更改下列配置选项的值：
    • 允许其它 SQL Server 使用 RPC 远程连接到本 SQL Server。

    • 查询超时设定（秒，0 = 无限制）

      此选项指定从处理查询返回之前等待的秒数。0 值允许无限的等待。默认值为 0。

    • 强制分布式事务处理 (MTS)。

    更改配置选项需要停止并重新启动服务器。如果更改了配置选项，则继续步骤 4，否则跳到步骤 6。

  4. 右击该服务器，然后单击"停止"按钮。

  5. 停止服务器之后，右击该服务器，然后单击"启动"按钮。

  6. 为远程服务器对的另一台服务器重复步骤 1 到 5。


如何建立服务器注册信息的中央存储（企业管理器）

在远程服务器上建立服务器注册信息的中央存储

  1. 单击该服务器，然后在"工具"菜单上单击"选项"子菜单。

  2. 在"常规"选项卡上，清除"与用户无关的读取/存储"复选框。

  3. 使用 SQL Server 企业管理器创建服务器组并注册服务器。

在本地服务器上建立服务器注册信息的中央存储

  1. 单击该服务器，然后在"工具"菜单上单击"选项"子菜单。

  2. 在"常规"选项卡上，单击"远程读取"。

  3. 在"服务器名"框中，键入要从中使用注册信息的远程服务器名。


如何设置对您显示的服务器和组的访问（企业管理器）

设置对您显示的服务器和组的访问

  1. 展开一个服务器组，然后单击一个服务器。

  2. 单击"工具"菜单的"选项"选项。

  3. 在"常规"选项卡上，单击"本地读取/存储"，然后选择或清除"与用户无关的读取/存储"复选框。


如何设置轮询间隔（企业管理器）

设置轮询间隔

  1. 展开一个服务器组，然后单击一个服务器。

  2. 单击"工具"菜单的"选项"选项。

  3. 在"常规"选项卡上，选择"对服务器进行轮询以查找服务器的状态和相关服务"复选框。

  4. 在"服务"列表中，单击要轮询的服务。

  5. 在"轮询间隔（秒）"框中，键入或选择轮询间隔。

请参见

如何设置轮询间隔（服务管理器）


如何禁用远程服务器设置（企业管理器）

禁用远程服务器设置

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，单击"远程服务器"以列出在所选服务器上定义的远程服务器。

  3. 右击要禁用的远程服务器，然后单击"删除"按钮。


如何管理或查看 SQL Server 消息（企业管理器）

管理或查看 SQL Server 消息

  1. 展开一个服务器组，然后右击一个服务器。

  2. 指向"所有任务"，然后单击"管理 SQL Server 消息"命令。

  3. 若要指定搜索选项，请执行以下一个或多个操作：
    • 在"消息正文包含"框中，键入要搜索的文本。

    • 在"错误号"框中，键入要搜索的错误号。

    • 在"严重度"下，选择要搜索的严重级别。
  4. 若要指定要包含的消息，请执行下列操作之一：
    • 选择"仅包含已日志记录的消息"复选框。

    -或-

    • 选择"仅包含用户定义的消息"复选框。
  5. 单击"查找"以查找所有满足搜索条件的消息。


如何编辑 SQL Server 消息（企业管理器）

编辑 SQL Server 消息

  1. 展开一个服务器组，然后右击一个服务器。

  2. 指向"所有任务"，然后单击"管理 SQL Server 消息"命令。

  3. 单击"消息"选项卡，选择要编辑的消息，然后单击"编辑"按钮。


如何删除 SQL Server 消息（企业管理器）

删除 SQL Server 消息

  1. 展开一个服务器组，然后右击一个服务器。

  2. 指向"所有任务"，然后单击"管理 SQL Server 消息"命令。

  3. 在"消息"选项卡上，选择要删除的消息，然后单击"删除"按钮。

  4. 确认删除。


如何添加 SQL Server 新消息（企业管理器）

添加 SQL Server 新消息

  1. 展开一个服务器组，然后右击一个服务器。

  2. 指向"所有任务"，然后单击"管理 SQL Server 消息"命令。

  3. 在"消息"选项卡中，单击"新建"命令。

  4. 若要指定消息选项，请执行下列操作之一：
    • 在"新建 SQL Server 消息"对话框中，选择该消息的错误号。

    • 在"严重度"框中，输入或选择严重级别。

    • 在"消息正文"框中，输入消息的正文。

    • 在"语言"框中，单击消息使用的语言。默认值为英语。
  5. 如果希望该消息总是写入到 Microsoft® Windows® 应用程序日志中，则选择"始终写入 Windows NT 事件日志"复选框。


如何查找 SQL Server 消息（企业管理器）

查找 SQL Server 消息

  1. 展开一个服务器组，然后右击一个服务器。

  2. 指向"全部任务"，然后单击"管理 SQL Server 消息"命令。

  3. 在"搜索"选项卡上，指定消息的正文、错误号和严重级别。还可以选择仅包括已记录的或者用户定义的消息。

  4. 单击"查找"按钮。


如何设置链接服务器（企业管理器）

设置链接服务器

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性",右击"链接服务器"，然后单击"新建链接服务器"。

  3. 单击"常规"选项卡，在"链接服务器"框中，键入要链接的服务器名称。

  4. 在"服务器类型"下，单击一个选项。

    如果选择"其它数据源"，则必须指定提供程序的属性。


如何删除链接服务器（企业管理器）

删除链接服务器

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后再展开"链接服务器"。

  3. 右击要删除的链接服务器，然后单击"删除"按钮。

  4. 确认删除。


如何配置日志传送（企业管理器）

使用数据库维护计划向导配置日志传送

说明 在配置日志传送之前，必须在主数据库上创建一个共享以使事务日志可用。这是从事务日志转储目录创建的共享。例如，如果将日志转储到目录 e:\data\tlogs\，则可以从该目录创建 \\logshipping\tlogs 共享。

  1. 在"选择数据库"屏幕上，选择"如下数据库"复选框，然后选择要进行日志传送的数据库。

    如果选择了多个数据库，则不会执行日志传送，日志传送选项也不可用。不允许选择已配置了日志传送的数据库。

  2. 选择"将事务日志传送到其它的 SQL Server（日志传送）"复选框。

  3. 继续执行向导，指定其余的数据库维护选项，直到到达"指定日志传送目的"屏幕。

  4. 单击"添加"按钮添加目的数据库。

    要使该选项可用，必须已经在向导的前面步骤中选择了使用日志传送。

  5. 在"添加目的数据库"屏幕中，选择一个服务器名。

    该服务器必须已经注册，而且正在运行 Microsoft® SQL Server™ 2000 企业版，这样才能显示在下拉列表中。如果要使该目的成为可用的源目的，必须选择"允许数据库采用主角色"复选框。如果该复选框未被选中，则该目的数据库将来就无法采用源目的角色。如果已选定"允许数据库采用主角色"复选框，还必须在日志将要备份到的目的数据库中指定"事务日志备份目录"。

  6. 若要从默认位置更改事务日志目的数据库，请在"目录"框中输入一个位置。

  7. 如果源数据库不在目的数据库上，则选择"创建新数据库"复选框。

    "数据库名称"框将默认为源数据库名。如果想要在目的服务器上用另一个数据库名，则指定一个新名称。如果已经选择了允许该目的数据库承担源角色，就无法从默认值改变该数据库的名称。

  8. 如果已经选择了"创建新数据库"复选框，则还必须在"用于数据"和"用于日志"框中指定目的数据库上数据和日志的文件目录。

  9. 如果源数据库已经存在于目的数据库上，则选择"使用现有数据库"复选框。如果目的服务器上的数据库名不同，则在"数据库名称"框中输入该名。该数据库必须是使用 WITH STANDBY 选项还原过的，以便正确接受日志。

  10. 在"初始化目的数据库"屏幕上，执行下列操作之一：
    • 单击"立即提取完全数据库备份"。

    –或-

    • 单击"使用最新备份文件"以初始化目的数据库。
  11. 在"日志传送调度"屏幕上，查看默认的日志传送调度。如果要改变调度，请单击"更改"。

  12. 在"复制/装载的频率"框中，设置希望目的服务器从源服务器备份和还原事务日志的频率（以分钟计）。

  13. 在"装载延迟"框中，设置希望目的数据库从源服务器还原事务日志之前要等待的延迟（以分钟计）。

    该框的默认值为 0 分钟，表示目的数据库应立即还原所有事务日志备份。

  14. 在"文件保持期"框中指定事务日志在删除之前应该存留的时间长度。

  15. 从"日志传送阈值"对话框中，设置"备份警报阈值"。

    这是距离源服务器上一次事务日志备份时间的最长期限。一旦时间超过此指定阈值，监视服务器将生成警报。

  16. 在"不同步警报阈值"框中，指定源服务器上最近一次事务日志备份与目的服务器最近一次事务日志还原之间的时间。

    一旦时间超过此指定阈值，监视服务器将生成警报。

  17. 在"指定日志传送监视器信息"屏幕中，键入将监视日志传送的服务器名称。

  18. 单击"使用 Windows 身份验证"或"使用 SQL Server 身份验证"连接到监视服务器。log_shipping_monitor_probe 登录名是固定的，必须使用它连接到监视服务器。如果这是一个新帐户，则选择一个新密码。如果该帐户已经存在于监视服务器上，则必须指定现有的密码。

说明 使用数据库维护向导设置日志传送，只可以向磁盘传送日志，而不能使用"备份到磁带"选项。


如何删除日志传送（企业管理器）

删除日志传送

  1. 展开一个服务器组，然后展开一个主服务器。

  2. 展开管理，然后单击"数据库维护计划"。

  3. 在详细信息窗格中，右击要删除的数据库维护计划，然后单击"属性"。

  4. 单击"日志传送"选项卡，然后单击"删除日志传送"。

    这可以停止主服务器上的日志传送，并删除所有辅助服务器以及监视服务器。必须删除数据库维护计划，才能删除附加的作业。


如何添加或编辑目的服务器（企业管理器）

添加或编辑目的服务器

  1. 展开一个服务器组，然后展开一个主服务器。

  2. 展开管理，然后单击"数据库维护计划"。

  3. 在详细信息窗格中，右击要编辑的数据库维护计划，然后选择"属性"命令。

  4. 单击"日志传送"选项卡，然后单击"添加"或"编辑"按钮。

  5. 在"目录"框中，输入或选择存储事务日志的目录。

  6. 执行下列操作之一：
    • 单击"创建新数据库"以在目的服务器上创建新数据库。如果选择创建新数据库，则必须指定数据库名称，以及数据和日志的文件目录。

    • 如果目的服务器上已存在该数据库，则单击"使用现有数据库"。


如何删除目的服务器（企业管理器）

删除目的服务器

  1. 展开一个服务器组，然后展开一个主服务器。

  2. 展开管理，然后单击"数据库维护计划"。

  3. 在详细信息窗格中，右击要编辑的数据库维护计划，然后选择"属性"命令。

  4. 单击"日志传送"选项卡，选择要删除的目的服务器，然后单击"删除"按钮。

  5. 确认删除。

说明 如果删除了唯一的目的服务器，那么所有日志传送都将从目的、源和监视服务器中删除。必须使用数据库维护计划向导或"数据库属性"对话框来添加其它目的服务器。


如何查看配置了日志传送的服务器的状态（企业管理器）

查看为日志传送配置的服务器状态

  1. 展开一个服务器组，然后展开一个主服务器。

  2. 展开管理，然后单击"日志传送监视器"。

  3. 在详细信息窗格中，右击要监视的日志传送对，然后单击"属性"命令。

  4. 单击"状态"选项卡，然后查看源服务器和目的服务器的状态信息。

    它还显示了有关上一次备份的文件、上一次复制的文件以及上一次还原的文件的信息。


如何查看或编辑有关源服务器的信息（企业管理器）

查看或编辑有关源服务器的信息

  1. 展开一个服务器组，然后展开监视服务器。

  2. 展开管理，然后单击"日志传送监视器"。

  3. 在详细信息窗格中，右击要监视的日志传送对，然后单击"属性"命令。

  4. 单击"源"选项卡，然后查看或编辑源服务器的信息（例如备份失败警报和警报生成抑制值）。

    还有一个选项可以查看源服务器的备份调度。


如何查看或编辑有关目的服务器的信息（企业管理器）

查看或编辑有关目的服务器的信息

  1. 展开一个服务器组，然后展开监视服务器。

  2. 展开管理，然后单击"日志传送监视器"。

  3. 在详细信息窗格中，右击要监视的日志传送对，然后选择"属性"命令。

  4. 单击"目的"选项卡，然后查看或编辑目的服务器的信息（例如备份失败警报和警报生成抑制）。

    还有一个选项可以查看和/或启用目的服务器的复制和还原调度。


如何将外部工具添加到工具菜单（企业管理器）

将外部工具添加到工具菜单

  1. 在"工具"菜单上，单击"外部工具"命令。

  2. 单击"添加"按钮。

  3. 输入命令和参数。

    可以从 SQL Server 企业管理器启动任何 Microsoft® Windows NT® 4.0 或 Windows® 2000 应用程序。可以在"工具"菜单上添加和运行外部应用程序。

说明 在"参数"框中可以使用 [SVR] 和 [DBN] 代表当前的服务器和数据库。运行该工具时，SQL Server 企业管理器将它们替换为当前的服务器名称和数据库名称，并将它们作为参数传递到应用程序中。


如何在计算机管理控制台中启动 SQL Server 企业管理器

说明 在 Microsoft® Windows® 2000 中，可以从计算机管理控制台访问 SQL Server 企业管理器。

在计算机管理控制台中启动 SQL Server 企业管理器

  1. 在"开始"菜单上，指向"程序"，进而指向"管理工具"，然后单击"计算机管理"命令。

  2. 展开"服务和应用程序"组。

  3. 展开"Microsoft SQL Server"组。

请参见

如何启用子窗口（企业管理器）


如何在 SQL Server 企业管理器中启用子窗口

说明 首次使用计算机管理控制台访问 SQL Server 企业管理器时，可能需要更改控制台模式以启用子窗口。

在 SQL Server 企业管理器中启用子窗口

  1. 在"开始"菜单中，指向"搜索"子菜单，然后单击"文件或文件夹"。

  2. 在"要搜索的文件或文件夹名为"框中，键入"Compmgmt.msc"，然后单击"开始搜索"。

  3. 右击"Compmgmt.msc"，然后单击"作者"。

  4. 单击"控制台"菜单的"选项"选项。

  5. 在"控制台模式"列表中，单击"用户模式 – 受限访问，多窗口"。

请参见

如何在计算机管理控制台中启动 SQL Server 企业管理器 (Windows)


如何配置亲和力掩码（企业管理器）

配置亲和力掩码

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"处理器"选项卡。

  4. 在"处理器控制"项下，选择一或多个将亲和力掩码组合在一起的处理器。


如何设置允许更新选项（企业管理器）

设置允许更新选项

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"服务器设置"选项卡。

  4. 在"服务器行为"项下，选择或清除"允许对系统目录直接进行修改"复选框。


如何配置并行性成本阈值（企业管理器）

配置并行性成本阈值

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"处理器"选项卡。

  4. 在"并行性"项下的"为允许查询并行执行须满足的最小查询计划阈值（成本估计）"框中，键入或选择一个介于 0 到 32767 之间的值。

    此阈值仅适用于对称的多处理 (SMP) 环境中。


如何设置默认语言（企业管理器）

设置默认语言

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"服务器设置"选项卡。

  4. 在"用户的默认语言"框中，选择 Microsoft® SQL Server™ 用以显示系统消息的语言。

    默认语言为英语。


如何设置固定的填充因子（企业管理器）

设置固定的填充因子

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"数据库设置"选项卡。

  4. 在"设置"项下选择"固定"复选框，然后将填充因子滑块放在适当位置。


如何配置可用于并行查询的处理器数目（企业管理器）

配置可用于并行查询的处理器的数目

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"处理器"选项卡。

  4. 在"并行性"项下，选择执行并行查询的处理器数目。

    默认情况下，使用所有可用的处理器。


如何设置最小查询内存（企业管理器）

设置最小查询内存

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"内存"选项卡。

  4. 在"最小查询内存"框中，键入或选择一个介于 512 到 2147483647 KB 之间的值。

    默认值为 1024 KB。


如何配置最大工作线程数（企业管理器）

配置最大工作线程数

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"处理器"选项卡。

  4. 在"最大工作线程"框中，键入或选择一个介于 32 到 32767 之间的值。

    默认值为 255。


如何设置备份保持期（企业管理器）

设置备份保持期

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"数据库设置"选项卡。

  4. 在"默认的备份媒体保持期（天）"框中，键入或选择一个介于 0 到 365 之间的值，以设置备份媒体在数据库或事务日志备份后保留的天数。

    默认值为 0 天。


如何设置固定的内存量（企业管理器）

设置固定的内存量

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"内存"选项卡。

  4. 单击"使用固定的内存大小 (MB)"，然后将固定内存滑块放在适当的位置。

说明 如果使用默认设置，则 Microsoft® SQL Server™ 将动态配置内存。


如何设置嵌套触发器选项（企业管理器）

设置嵌套触发器选项

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"服务器设置"选项卡。

  4. 在"服务器行为"下，选择或清除"允许激发会激发其它触发器（嵌套触发器）的触发器"复选框。

请参见

嵌套触发器


如何设置优先级提升选项（企业管理器）

设置优先级提升选项

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"处理器"选项卡。

  4. 在"处理器控制"下，选择"在 Windows 上提升 SQL Server 的优先级"复选框。


如何设置恢复间歇（企业管理器）

设置恢复间歇

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"数据库设置"选项卡。

  4. 在"恢复"下的"恢复间歇（分钟）"框中，选择一个介于 0 到 32767 之间的值，以设置 Microsoft® SQL Server™ 在启动时用于恢复每个数据库所花的最多时间（以分钟计）。

    默认值为 0 分钟，表示自动配置。


如何设置远程服务器访问（企业管理器）

设置远程服务器访问

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"连接"选项卡。

  4. 在"远程服务器连接"项下，选择或清除"允许其它 SQL Server 使用 RPC 远程连接到本 SQL Server"复选框。


如何为远程过程强制分布式事务处理（企业管理器）

为远程过程强制分布式事务处理

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"连接"选项卡。

  4. 在"远程服务器连接"项下，选择"强制分布式事务处理 (MTS)"复选框。

说明 在设定此值前，必须允许远程服务器连接。


如何设置远程查询时间限制（企业管理器）

设置远程查询时间限制

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"连接"选项卡。

  4. 在"远程服务器连接"项下的"查询超时设定（秒，0 = 无限制）"框中，键入或选择一个介于 0 到 2147483647 之间的值，以设置 Microsoft® SQL Server™ 在超时之前等待的最多秒数。

说明 在设定此值前，必须允许远程服务器连接。


如何设置工作集大小选项（企业管理器）

设置工作集大小选项

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"内存"选项卡。

  4. 选择或清除"为 SQL Server 保留物理内存"复选框。


如何设置两位数年份截止点选项（企业管理器）

设置两位数年份截止点选项

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"服务器设置"选项卡。

  4. 在"两位数年份支持"下的"在输入两位数的年份时，将其解释为介于下面范围内的年份"框中，键入或选择作为时间范围结束年份的值。

    Microsoft® SQL Server™ 默认的时间范围是 1950-2049，表示截止年份是 2049。这说明 SQL Server 将两位数年份 49 解释为 2049 年，将两位数年份 50 解释为 1950 年，而将两位数年份 99 解释为 1999 年。若要维护向后兼容性，请保持设置为默认值。

    许多客户应用程序（例如基于自动化对象的程序）以 2030 为截止年份。若要使 SQL Server 与这些客户应用程序保持兼容，请指定 1931-2030 作为时间范围。


如何设置用户连接（企业管理器）

设置用户连接

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"连接"选项卡。

  4. 在连接下的"并发用户连接的最大数目（0 = 无限制）"框中，键入或选择一个介于 0 到 32767 之间的值，以设置 Microsoft® SQL Server™ 实例允许的最大同时连接用户数。


如何配置用户选项（企业管理器）

配置用户选项

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"连接"选项卡。

  4. 在"默认连接选项"框中，选择一个或多个特性，为所有已连接用户配置默认的查询处理选项。

    默认情况下，不配置用户选项。


如何配置数据包的大小（企业管理器）

配置数据包的大小

  1. 单击"工具"菜单的"选项"选项。

  2. 单击"高级"选项卡。

  3. 在"数据包的大小（字节）"框中，键入值。


如何设置 query governor cost limit 选项（企业管理器）

设置 query governor cost limit 选项

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"服务器设置"选项卡。

  4. 在"服务器行为"项下，选择或清除"使用查询调控器防止超出指定成本的查询"复选框。

    如果选择该复选框，则在该旋转框中输入一个非零的非负值，查询调控器将禁止执行运行长度超过该值的所有查询。


如何在安装 SQL Server 后启用加密（网络实用工具）

说明 如果想对故障转移群集使用加密功能，则必须在该故障转移群集的所有节点上安装服务器证书和虚拟服务器完全合法的 DNS 名称。例如，如果有一个两节点的群集，其节点名为 test1.redmond.corp.microsoft.com 和 test2.redmond.corp.microsoft.com，而且还有虚拟 SQL Server"Virtsql"，则需要获得"virtsql.redmond.corp.microsoft.com"的证书并在两个节点上安装该证书。然后可以复选服务器网络实用工具上的"强制协议加密"复选框，以配置故障转移群集用于加密。

启用加密

  1. 在"开始"菜单中，指向"程序"，接着指向"Microsoft SQL Server"，然后单击"SQL Server 网络实用工具"。

  2. 如果在"启用的协议"下没有出现"多协议"，则在"禁用的协议"下单击它，然后单击"启用"。否则跳到第 3 步。

  3. 在"启用的协议"下单击"多协议"，然后单击"属性"。

  4. 选择"启用加密"复选框。

请参见

多协议客户端


如何通过 Microsoft Proxy Server 连接到 SQL Server（设置）

说明 若要通过远程 WinSock (RWS) 的方法远程监听，请定义代理服务器的本地地址表 (LAT) 以使监听节点地址不在 LAT 地址范围内。

通过 Microsoft Proxy Server 连接到 SQL Server

  1. 在"开始"菜单中，指向"程序"，接着指向"Microsoft SQL Server"，然后单击"SQL Server 网络实用工具"。

  2. 如果在"启用的协议"下没有出现"TCP/IP"，则在"禁用的协议"下单击它，然后单击"启用"。否则跳到第 3 步。

  3. 在"启用的协议"下单击"TCP/IP"，然后单击"属性"。

  4. 确认端口是正确的。


如何设置轮询间隔（服务管理器）

设置轮询间隔

  1. 如果 SQL Server 服务管理器还没有运行，则启动它。

  2. 在 Microsoft® Windows® 任务栏中，右击"SQL Server 服务管理器"，然后单击"选项"。

  3. 在"轮询间隔（秒）"框中，输入轮询间隔。

    轮询间隔决定 SQL Server 服务管理器检查 Microsoft SQL Server™、SQL Server 代理程序和 Microsoft 分布式事务处理协调器 (MS DTC) 状态的频率。

  4. 如果想让 SQL Server 服务管理器在停止、暂停、启动或继续服务（包括 SQL Server 代理程序等相关服务）之前提供一个确认框，则选择"验证服务控制操作"复选框。（可选）

请参见

如何设置轮询间隔（企业管理器）


如何配置邮件配置文件 (Windows)

配置邮件配置文件

  1. 通过指定启动 Microsoft SQL Server™ 服务所使用的名称和密码，登录到 Microsoft® Windows NT® 4.0 或 Microsoft Windows® 2000 服务器。

  2. 在"控制面板"中，双击"邮件"图标以创建和配置或者复制现有的邮件配置文件。选择适当的邮件服务与邮件主机进行交互。为配置文件选择一个名称，此名称将帮助收件人识别消息。

  3. 在 SQL Server 的实例上，使用新创建的邮件配置文件启动邮件客户程序。

  4. 发送一个接收地址为同一配置文件名的消息，以确保邮件客户程序、邮件配置文件和电子邮件提供程序正常工作。

    如果电子邮件没有出现，可能需要转到"工具"菜单中单击"立即传送"按钮以建立邮件同步。


如何设置 SQL 邮件（企业管理器）

设置 SQL 邮件

  1. 展开服务器组，然后展开服务器。

  2. 展开"支持服务"项，右击"SQL 邮件"项，然后单击"属性"菜单项。

  3. 在"配置文件名"列表中，键入或选择为 SQL 邮件配置的邮件配置文件。

  4. 单击"测试"按钮，以检查系统使用输入的配置文件启动和停止邮件客户程序服务的能力。

    应收到一个消息，指出 SQL 邮件已使用该配置文件成功启动和停止邮件会话。


如何设置 SQLAgentMail（企业管理器）

设置 SQLAgentMail

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"项，右击"SQL Server 代理程序"项，然后单击"属性"菜单项。

  3. 如果使用与 Microsoft® SQL Server™ 所用域帐户不同的域帐户配置了邮件配置文件，则单击"此帐户"，然后输入为 SQLAgentMail 创建邮件配置文件时所使用的 Microsoft Windows NT® 4.0 或 Windows 2000® 帐户名和密码。

  4. 在"邮件配置文件"框中，选择为 SQLAgentMail 创建的邮件配置文件。

  5. 单击"测试"按钮，以检查系统使用输入的配置文件启动和停止邮件客户程序服务的能力。

    应收到一个消息，指出 SQL 邮件已使用该配置文件成功启动和停止邮件会话。


如何启用锁定内存页选项 (Windows)

说明 只有运行 Microsoft® Windows® 2000 操作系统时，才能使用该功能。

启用锁定内存页选项

  1. 在"开始"菜单上单击"运行"子菜单，然后在"打开"框中键入"gpedit.msc"。

  2. 在"组策略"控制台上，展开"计算机配置"，然后展开"Windows 设置"。

  3. 展开"安全设置"，然后展开"本地策略"。

  4. 选择"用户权限分配"复选框。

    详细资料窗格中随即显示出策略。

  5. 在详细资料窗格中，双击"锁定内存页"。

  6. 在"本地安全策略设置"对话框中，单击"添加"按钮。

  7. 在"选择用户或组"对话框中，添加有权运行 sqlservr.exe 的帐户。


如何启动 SQL Sever 网络实用工具（网络实用工具）

启动 SQL Server 网络实用工具

  • 在"开始"菜单中，指向"程序"，接着指向"Microsoft SQL Server"，然后单击"服务器网络实用工具"。


如何装载已安装的服务器网络库（网络实用工具）

装载已安装的服务器网络库

  1. 在"开始"菜单中，指向"程序"，接着指向"Microsoft SQL Server"，然后单击"服务器网络实用工具"。

  2. 在"常规"选项卡上，选择要装载已安装服务器网络库的 Microsoft® SQL Server™ 实例的名称。

  3. 在"禁用的协议"下，单击要启用的协议，然后单击"启用"按钮。

    取决于要装载的服务器网络库，可能需要指定必要的连接参数。若要更改任何需要的连接参数，单击协议，然后单击"属性"命令。


如何停用服务器网络库配置（网络实用工具）

停用服务器网络库配置

  1. 在"开始"菜单中，指向"程序"，接着指向"Microsoft SQL Server"，然后单击"服务器网络实用工具"。

  2. 在"启用的协议"下，单击相应的服务器网络库配置，然后单击"禁用"按钮。


如何编辑服务器网络库配置（网络实用工具）

编辑服务器网络库配置

  1. 在"开始"菜单中，指向"程序"，接着指向"Microsoft SQL Server"，然后单击"服务器网络实用工具"。

  2. 在"启用的协议"下，单击要编辑的服务器网络库配置，然后单击"属性"命令。

  3. 在指定协议的对话框中，更改要编辑的服务器名称或参数。


如何查看已安装的 SQL Server 服务器网络库（网络实用工具）

查看已安装的 SQL Server 服务器网络库

  1. 在"开始"菜单中，指向"程序"，接着指向"Microsoft SQL Server"，然后单击"服务器网络实用工具"。

  2. 单击"网络库"选项卡。将显示已安装的 Microsoft® SQL Server™ 服务器网络库。


管理客户端

客户程序是前端应用程序，它使用服务器提供的服务。该应用程序的宿主计算机称为客户计算机。客户端软件使计算机可以连接到网络中的 Microsoft® SQL Server™ 实例。

SQL Server 客户程序可以包括各种应用程序，如：

  • OLE DB 使用者。

    这些应用程序使用用于 SQL Server 的 Microsoft OLE DB 提供程序或用于 ODBC 的 Microsoft OLE DB 提供程序与 SQL Server 实例连接和会话。OLE DB 提供程序充当 SQL Server 实例与客户应用程序之间的中介，这些客户应用程序使用 SQL Server 数据作为 OLE DB 行集。

  • ODBC 应用程序。

    这些程序包括与 SQL Server 一起安装的客户端实用工具（如 SQL Server 企业管理器和 SQL 查询分析器），以及其它使用 SQL Server ODBC 驱动程序与 SQL Server 实例连接和会话的应用程序。

  • DB-Library 客户程序，包括 SQL Server isql 命令提示实用工具和写到 DB-Library 中的客户程序。

无论应用程序是何类型，管理客户端主要包括配置它与 SQL Server 服务器组件的连接。根据您的站点要求，客户端管理的范围可以从小到输入服务器计算机名称，大到生成自定义配置项目库以满足各种多服务器环境。


如何启动客户端网络实用工具 (Windows)

启动客户端网络实用工具

  • 在"开始"菜单上，指向"程序"，进而指向"Microsoft SQL Server"子菜单，然后单击"客户端网络实用工具"命令。


如何显示网络库的版本号（客户端网络实用工具）

显示库的版本号

  • 单击"网络库"选项卡。

    显示网络库、库文件名、版本、文件日期和大小。


如何设置 DB-Library 转换首选项（客户端网络实用工具）

说明 此过程适用于 Microsoft® Windows® 32 位操作系统客户端。

设置 DB-Library 转换首选项

  1. 单击"DB-Library 选项"选项卡。

  2. 选择或清除"ANSI 到 OEM 的自动转换"复选框。

  3. 选择或清除"使用国际设置"复选框。


如何添加网络库配置（客户端网络实用工具）

添加网络库配置

  1. 单击"别名"选项卡，然后单击"添加"按钮。

  2. 在"添加网络库配置"对话框中的"网络库"下，选择其中一个网络库。

  3. 输入服务器别名，以及选定网络库需要的任何参数信息。


如何编辑网络库配置（客户端网络实用工具）

编辑网络库配置

  1. 单击"别名"选项卡，然后单击要编辑的网络协议配置。

  2. 单击"编辑"按钮。

  3. 在"编辑网络库配置"对话框中，编辑要更改的信息。


如何删除网络库配置（客户端网络实用工具）

删除网络库配置

  1. 单击"别名"选项卡，然后单击要删除的网络库配置。

  2. 单击"删除"按钮。


如何将客户的别名设置为一个备用管道（客户端网络实用工具）

将客户的别名设置为一个备用管道

  1. 单击"别名"选项卡，然后单击"添加"按钮。

  2. 在"添加网络库配置"对话框中，单击"命名的管道"按钮。

  3. 在"服务器别名"框中，输入该服务器的别名。

  4. 在"连接"参数下的"管道名称"框中，键入备用管道名的名称（例如 \\myserver\pipe\altpipe）。


如何将客户端配置为使用多协议 Net-Library（客户端网络实用工具）

说明 在创建多协议客户端配置之前，确保您的计算机至少有一 IPC 协议加载在服务器的多协议下（命名的管道、NWLink IPX/SPX、TCP/IP 或 Windows 套接字）。

配置使用多协议 Net-Library 的客户端

  1. 单击"别名"选项卡，然后单击"添加"按钮。

  2. 在"添加网络库配置"对话框中单击"多协议"复选框。

  3. 在"服务器别名"框中，输入监听多协议 Net-Library 的 Microsoft® SQL Server™ 实例的名称。

  4. 除非服务器要求特定参数，否则应保留"其它参数"框为空。在输入参数之前向网络管理员核实。


如何将客户端配置为使用 TCP/IP（客户端网络实用工具）

将客户端配置为使用 TCP/IP

  1. 单击"常规"选项卡，然后单击"添加"按钮。

  2. 在"添加网络库配置"对话框中单击"TCP/IP"。

  3. 在"服务器别名"框中，输入监听 Windows 套接字 Net-Library 的 Microsoft® SQL Server™ 实例的别名。

    使用 TCP/IP，您还可以用服务器的 IP 地址代替它的名称来指定服务器。

  4. 执行下列操作中的一种：
    • 选择"动态确定端口"复选框自动确定端口。

    • 清除"动态确定端口"复选框以手工设置端口，然后在"端口号"框中键入端口号。

有关其它支持 Windows 套接字的 TCP/IP 协议的更多信息，请参阅 TCP/IP 文档。


如何将客户端配置为使用 NWLink IPX/SPX 网络库（客户端网络实用工具）

将客户端配置为使用 NWLink IPX/SPX 网络库

  1. 单击"别名"选项卡，然后单击"添加"按钮。

  2. 在"添加网络库配置"对话框中单击"NWLink IPX/SPX"。

  3. 在"服务器别名"框中，输入监听 NWLink IPX/SPX Net-Library 的 Microsoft® SQL Server™ 实例的别名。

  4. 在"连接"参数下，单击"服务名"或"网络地址"，然后执行下列操作之一：
    • 如果单击了"服务名"，则输入该服务名称。

      "服务名"是正运行 SQL Server 实例的 Microsoft Windows NT® 4.0 或 Windows® 2000 计算机名。该名称存储在服务器计算机的平构数据库中。

    • 如果单击了"网络地址"，则输入地址（MAC 地址）、端口（套接字号），以及网络（NetWare 网络号）。


如何将客户端配置为使用 AppleTalk 网络库（客户端网络实用工具）

将客户端配置为使用 AppleTalk 网络库

  1. 单击"别名"选项卡，然后单击"添加"按钮。

  2. 在"添加网络库配置"对话框中，单击"AppleTalk"。

  3. 在"服务器别名"框中，输入监听 AppleTalk Net-Library 的 Microsoft® SQL Server™ 实例的名称。

  4. 在"连接"参数下，键入 AppleTalk 对象名和可选区域标识符。


如何将客户端配置为使用 Banyan VINES 网络库（客户端网络实用工具）

将客户端配置为使用 Banyan VINES 网络库

  1. 单击"别名"选项卡，然后单击"添加"按钮。

  2. 在"添加网络库配置"对话框中单击"Banyan VINES"。

  3. 在"服务器别名"框中，输入监听 Banyan VINES Net-Library 的 Microsoft® SQL Server™ 实例的别名。

  4. 在"连接"参数下键入服务和 VINES 组织。对于组可以使用 MSSQL 的默认值。


如何将客户端配置为使用 VIA 网络库（客户端网络实用工具）

将客户端配置为使用 Banyan VINES 网络库

  1. 单击"别名"选项卡，然后单击"添加"按钮。

  2. 在"添加网络库配置"对话框中单击"VIA"。

  3. 在"服务器别名"框中，输入监听 Banyan VINES Net-Library 的 Microsoft® SQL Server™ 实例的别名。

  4. 在"连接"参数下键入服务器名和服务器端口号。


如何将客户端配置为使用非标准的网络库（客户端网络实用工具）

将客户端配置为使用非标准的网络库

  1. 单击"别名"选项卡，然后单击"添加"按钮。

  2. 在"添加网络库配置"对话框中单击"其它"。

  3. 在"服务器别名"框中，输入监听您计划安装的 Net-Library 的 Microsoft® SQL Server™ 实例的别名。

  4. 在"连接"参数下键入安装的 Net-Library 的文件名（文件必须是一个 DLL）。不要输入 DLL 扩展名。

  5. 如有必要，在"参数"框中输入任意附加信息（如用户名和密码）。参数之间使用逗号分隔。


如何验证 SQL Server 正在监听 AppleTalk 而且能够接受客户端连接（客户端网络实用工具）

验证 SQL Server 正在监听 AppleTalk 而且能够接受客户端连接

  1. 从服务器的 \WINNT\system32 目录，将客户端 AppleTalk Net-Library (Dbmsadsn.dll) 复制到运行 Microsoft® Windows NT® 或 Microsoft Windows® 2000 Macintosh 服务的远程计算机的同一目录下。

  2. 在远程工作站上启动"SQL Server 客户端配置"。

  3. 如果"被禁用的协议"列表中列出了"AppleTalk"，则单击它，然后单击"启用"。

  4. 在"按顺序启用协议"列表中单击"AppleTalk"，然后单击"上移"按钮直到"AppleTalk"位于列表的顶端。

  5. 单击"确定"按钮。

  6. 试着使用 AppleTalk 服务对象名建立一个 ISQL 连接。

    例如，在命令行键入：

    isql -Usa -P -Sservicename

    如果能够与 ISQL 连接并执行查询，则服务器配置正确并正在接受连接。

说明 Microsoft Win32® AppleTalk (ADSP) 客户端 Net-Library (Dbmsadsn.dll) 也包含在内，用于测试 ADSP 连接，以及诊断 Macintosh 客户机和 Microsoft SQL Server™ 之间的 AppleTalk 连接故障。这个 Net-Library 只是在测试从远程客户到 SQL Server 的实例的连接时才使用。如果试图通过 ADSP Net-Library 本地连接到监听 AppleTalk 的 SQL Server 的实例，就会收到如下网络错误：Net-Library 错误 11：getsockopt()。


如何检查 ODBC SQL Server 驱动程序的版本 (Windows)

说明 只有在运行 Microsoft® Windows NT® 4.0 操作系统时才可按下面步骤操作：

检查 ODBC SQL Server 驱动程序的版本（32 位 ODBC）

  1. 在控制面板中双击"ODBC 数据源"项。

  2. 单击"驱动程序"选项卡。

    有关 Microsoft SQL Server™ 条目的信息显示在"版本"列中。


使管理任务自动化

本主题定义自动化管理及其组件和多服务器管理，并介绍可用来定义自动化任务的 Microsoft® SQL Server™ 工具。

什么是自动化管理？

自动化管理就是按照计划对可预测的管理职责和服务器事件作出响应。管理员、应用程序编写人员以及操作数据仓库的分析人员可以从任务自动化中获益。若要使管理自动化，必须：

  • 确定哪些管理职责或服务器事件定期执行并可以通过编程方式进行管理。

  • 定义一套作业和警报。

  • 运行 SQL Server 代理服务。
为何要使管理自动化？

在管理员的工作中，有许多管理职责每天都是固定不变的，非常单调乏味。通过使重复的管理任务及对服务器事件的响应自动化，可以留出时间来执行另一些管理任务，这些管理任务需要创造性而缺乏可预测性或可编程性的响应。


如何设置 SQL Server 代理程序的服务启动帐户（企业管理器）

设置 SQL Server 代理程序的服务启动帐户：

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 在"服务启动帐户"下执行下列操作之一：
    • 单击"系统帐户"选项（如果作业只需要本地服务器上的资源）。

    • 单击"本帐户"选项（如果作业需要网络上的资源（包括应用程序资源）；需要将事件转发到其它 Windows® 应用程序日志中；或者需要通过电子邮件或呼叫程序来通知操作员）。
  4. 如果选择了"本帐户"选项，则输入 SQL Server 代理程序要使用的 Microsoft® Windows NT® 4.0 或 Windows 2000 帐户名，然后在"密码"框中输入该帐户的密码。

必须重新启动 SQL Server 代理程序才能使这些配置更改生效。


如何设置 SQL Server 代理程序的邮件配置文件（企业管理器）

设置 SQL Server 代理程序的邮件配置文件

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 在"邮件会话"下，从"邮件配置文件"框中选择一个配置文件。如果没有列出配置文件，则输入要使用的配置文件。


如何设置 SQL Server 连接（企业管理器）

设置 SQL Server 连接

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 单击"连接"选项卡，然后在"SQL Server 连接"下执行下列操作：
    • 单击"使用 Windows 身份验证"（如果在 Microsoft® Windows NT® 4.0 或 Windows 2000 服务器上运行 SQL Server 代理程序）。

    • 单击"使用 SQL Server 身份验证"（如果在 Windows 98 上运行 SQL Server 代理程序）。

      如果单击"使用 SQL Server 身份验证"，在"系统管理员登录 ID"框中输入属于 sysadmin 角色成员的 Microsoft SQL Server™ 登录的登录 ID。在"密码"框中，输入该 SQL Server 登录的密码。


如何设置 SQL Server 别名（企业管理器）

设置 SQL Server 别名

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 单击"连接"选项卡，并在"本地主机服务器"列表中，单击 SQL Server 代理程序应连接的别名。

    请选择引用本地 Microsoft® SQL Server™ 实例的别名，否则 SQL Server 代理程序将无法正常工作。


如何创建作业（企业管理器）

创建作业

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 右击"作业"，然后单击"新建作业"命令。

  4. 在"名称"框中输入作业的名称。

  5. 如果不希望作业在创建后立即运行，则清除"启用"复选框。例如，如果要在按计划运行之前测试某个作业，则禁用该作业。

  6. 在"源"下执行下列操作之一：
    • 单击"以本地服务器为目标"选项（如果作业仅在此服务器上运行）。如果选择该选项，则跳到第 9 步。

    • 单击"以多个服务器为目标"选项（如果作业在其它服务器上运行）。然后单击"更改"。

      只有服务器是主服务器时，才启用此选项。

  7. 在"更改作业的目标服务器"对话框中，在"可用服务器"选项卡上单击某台服务器，然后单击向右箭头将该服务器移动到"选定的目标服务器"列表中。

  8. 单击"确定"按钮返回"新建作业属性"对话框。

  9. 在"所有者"列表中选择将成为作业所有者的用户。

  10. 在"描述"框中输入对作业功能的描述。最大字符数为 512。

重要 每个作业至少要有一个步骤。必须先为作业创建一个步骤后，作业才可以保存。有关更多信息，请参阅创建作业步骤。


如何禁用作业（企业管理器）

禁用作业

  1. 在详细信息窗格中右击作业，然后单击"属性"命令。

  2. 清除"启用"复选框。


如何创建作业分类（企业管理器）

创建作业分类

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 右击"作业"，指向"所有任务"，然后单击"管理作业分类"命令。

  4. 在"作业分类"对话框中单击"添加"按钮。

  5. 在"名称"框中输入作业分类的名称。

请参见

如何将作业指派给作业分类（企业管理器）


如何删除作业分类（企业管理器）

删除作业分类

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 右击"作业"，指向"所有任务"，然后单击"管理作业分类"命令。

  4. 单击作业分类，然后单击"删除"命令。


如何将作业指派给作业分类（企业管理器）

将作业指派给作业分类

  1. 在详细信息窗格中右击作业，然后单击"属性"命令。

  2. 在"分类"列表中，选择想要指派给作业的作业分类。


如何更改作业分类的成员资格（企业管理器）

更改作业分类的成员资格

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 右击"作业"，指向"所有任务"，然后单击"管理作业分类"命令。

  4. 在"作业分类"对话框中，选择一种作业分类，然后单击"属性"命令。

  5. 单击"显示全部作业"按钮。

  6. 在"选定该分类的作业"列表中，选择或清除"成员"复选框。


如何为其他人授予作业的所有权（企业管理器）

将作业所有权授予其他人

  1. 在详细信息窗格中右击作业，然后单击"属性"命令。

  2. 在"所有者"列表中，选择一个登录。

    将作业指派给另一个登录并不保证新所有者有足够的权限来成功运行该作业。


如何创建 CmdExec 作业步骤（企业管理器）

创建 CmdExec 作业步骤

  1. 创建新的作业或右击现有的作业，然后单击"属性"命令。

    有关创建作业的更多信息，请参阅创建作业。

  2. 在"作业属性"对话框中，单击"步骤"选项卡，然后单击"新建"按钮。

  3. 在"步骤名称"框中，输入作业步骤的名称。

  4. 在"类型"列表中单击"操作系统命令 (CmdExec)"选项。

  5. 在"成功命令的进程退出代码"框中，输入介于 0 到 999999 之间的值。

  6. 在"命令"框中输入操作系统命令或可执行程序。


如何重置 SQLAgentCmdExec 权限（企业管理器）

重置 SQLAgentCmdExec 权限

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 单击"作业系统"选项卡。

  4. 在"非系统管理员作业步骤代理帐户"下，清除"只有具有系统管理员特权的用户才能执行 CmdExe 和 ActiveScripting 作业步骤"复选框，然后单击"重置代理帐户"按钮。

  5. 在运行非系统管理员的用户所拥有的作业时，应键入 SQL Server 代理程序要使用的用户帐户的用户名、密码和域。


如何创建 Transact-SQL 作业步骤（企业管理器）

创建 Transact-SQL 作业步骤

  1. 创建新的作业或右击现有的作业，然后单击"属性"命令。

    有关创建作业的更多信息，请参阅创建作业。

  2. 在"作业属性"对话框中，单击"步骤"选项卡，然后单击"新建"按钮。

  3. 在"步骤名称"框中，输入作业步骤的名称。

  4. 在"类型"列表中，单击"Transact-SQL 脚本 (TSQL)"。

  5. 在"数据库"列表中，单击此作业步骤要使用的数据库。

  6. 在"命令"对话框中输入 Transact-SQL 命令批处理，或单击"打开"命令选择一个 Transact-SQL 文件作为命令。

  7. 单击"分析"命令检查语法。

    如果语法正确，将显示"分析成功"的消息。如果发现错误，在继续下一步之前更正语法。


如何定义 Transact-SQL 作业步骤选项（企业管理器）

定义 Transact-SQL 作业步骤选项

  1. 在详细信息窗格中右击作业，然后单击"属性"命令。

  2. 单击"步骤"选项卡，单击一个作业步骤，然后单击"编辑"按钮。

  3. 确认作业类型是 Transact-SQL 脚本 (TSQL)，然后单击"高级"选项卡。

  4. 输入输出文件的名称，并确定是重写此文件还是追加到此文件上。

  5. 如果想在步骤历史记录中包含输出，请选择"将输出追加到步骤的历史记录"复选框。

    仅当没有错误时，才会显示输出。此外，输出可能会被截断。

  6. 在"作为用户运行"列表中，单击用户（只适用于系统管理员）。


如何创建活动脚本作业步骤（企业管理器）

创建活动脚本作业步骤

  1. 创建新的作业或右击现有的作业，然后单击"属性"命令。

    有关创建作业的更多信息，请参阅创建作业。

  2. 单击"步骤"选项卡，然后单击"新建"按钮。

  3. 在"步骤名称"框中，输入作业步骤的名称。

  4. 在"类型"列表中，单击"ActiveX 脚本"。

  5. 在"语言"列表中单击一种脚本语言，或者单击"其它"，然后输入编写命令时要使用的 Microsoft® ActiveX® 脚本语言的名称。

  6. 在"命令"框中输入作业步骤的源。

  7. 单击"分析"命令检查语法。

    如果语法正确，将显示"分析成功"的消息。如果发现错误，在继续下一步之前更正语法。

说明 有时虽然显示了"分析成功"的消息，但命令并未成功运行。若要确定命令是否会成功运行，可在一种 ActiveXScript 创作环境下（如 Microsoft Visual Basic®）运行该命令。


如何设置作业步骤的成功流或失败流（企业管理器）

设置作业步骤的成功流或失败流

  1. 在详细信息窗格中右击作业，然后单击"属性"命令。

  2. 单击"步骤"选项卡，单击一个步骤，然后单击"编辑"按钮。

  3. 单击"高级"选项卡。

  4. 在"成功时操作"列表中，单击如果作业步骤成功完成则要执行的操作。

  5. 在"重试"框中输入 0 到 9999 之间的某个次数，作业步骤重复该次数后才会被认为失败。如果在"重试"框中输入的值大于 0，则在"重试间隔（分钟）"框中输入 1 到 9999 之间的某个分钟数，必须经过该间隔后作业步骤才重试。

  6. 在"失败时操作"列表中，单击作业步骤失败后要执行的操作。


如何设置作业历史记录日志（企业管理器）

设置作业历史记录日志

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 单击"作业系统"选项卡，选择"限制作业历史记录日志的大小"复选框，然后增加或减少作业历史记录中的最大日志行数。


如何查看作业历史记录（企业管理器）

查看作业历史记录

  1. 在详细信息窗格中，右击某个作业，然后执行下列操作之一：
    • 单击"查看作业历史记录"菜单（如果要查看本地作业的历史记录）。

    • 单击"作业状态"菜单（如果要查看多服务器作业的历史记录）。
  2. 如果单击了"作业状态"，则在"多服务器作业执行状态"对话框中单击"作业"选项，单击某个作业名，然后单击"查看远程作业历史记录"命令。

  3. 若要更新作业历史记录，请单击"刷新"命令。


如何生成主服务器（企业管理器）

生成主服务器

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"使之成为主服务器"命令。

    服务器必须在 Microsoft® Windows NT® 4.0 或 Microsoft Windows® 2000 上运行才能成为主服务器。生成 MSX 向导将引导您完成使此服务器成为主服务器的过程。


如何生成目标服务器（企业管理器）

生成目标服务器

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"使之成为目标服务器"命令。

    服务器必须在 Microsoft® Windows NT® 4.0 或 Windows® 2000 上运行才能成为目标服务器。生成 TSX 向导将引导您完成使此服务器成为目标服务器的过程。


如何从主服务器中登记目标服务器（企业管理器）

从主服务器中登记目标服务器

  1. 展开一个服务器组，然后展开一个配置为主服务器的服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"添加目标服务器"命令。

  4. 选择一个或多个已注册的服务器，然后单击"登记"。


如何使目标服务器脱离主服务器（企业管理器）

使目标服务器脱离主服务器

  1. 展开一个服务器组，然后展开一个配置为目标服务器的服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"脱离 MSX"命令。

  4. 单击"是"确认想将此目标服务器与主服务器脱离。


如何使多台目标服务器脱离主服务器（企业管理器）

使多台目标服务器脱离主服务器

  1. 展开一个服务器组，然后展开一个配置为主服务器的服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"管理目标服务器"命令。

  4. 单击"发布指令"，然后在"指令类型"列表中单击"脱离"。

  5. 在"收件人"下执行下列操作之一：
    • 单击"全部目标服务器"选项，使所有目标服务器与此主服务器脱离。如果要完全卸载当前的多服务器管理配置，则使用此选项。

    • 单击"这些目标服务器"选项，然后单击相应的"选择"框，使某些而不是全部目标服务器与此主服务器脱离。


如何查看主 SQL Server 代理错误日志（企业管理器）

查看主 SQL Server 代理错误日志

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"管理目标服务器"命令。

  4. 在"目标服务器状态"选项卡中，右击服务器，然后单击"查看 SQLServerAgent 错误日志"命令。


如何检查目标服务器的状态（企业管理器）

检查目标服务器的状态

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"管理目标服务器"命令。

  4. 在"目标服务器状态"选项卡中，右击服务器，然后单击"检查 SQLServerAgent 状态"命令。


如何调度作业（企业管理器）

调度作业

  1. 在详细信息窗格中，右击作业，单击"属性"，单击"调度"选项卡，然后单击"新建调度"。

  2. 在"名称"框中输入新调度的名称。

  3. 如果不希望调度在创建后立即生效，则清除"启用"选项。

  4. 在"调度类型"下执行下列操作之一：
    • 单击"启动SQL Server 代理程序时自动启动"，在启动 SQL Server 代理服务时启动作业。

    • 单击"每当CPU闲置时启动"，在 CPU 达到闲置条件时启动作业。

    • 如果希望调度运行一次，则单击"一次"。若要设置运行一次的调度，请在"发生日期"和"发生时间"框中输入值。

    • 如果希望调度反复运行，单击"反复出现"。若要设置反复出现的调度，请单击"更改"按钮，然后完成"编辑反复出现的作业调度"对话框。


如何设置 CPU 空闲时间和持续时间（企业管理器）

设置 CPU 空闲时间和持续时间

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 单击"高级"选项卡，然后选择"计算机闲置的条件"复选框。

  4. 在"CPU 闲置的条件"下执行下列操作：
    • 指定平均的 CPU 使用必须低于的百分比（全部 CPU 间）。

    • 指定计算机达到闲置条件前经过的秒数。


如何通知操作员作业的状态（企业管理器）

通知操作员作业的状态

  1. 在详细信息窗格中右击作业，然后单击"属性"命令。

  2. 在"作业属性"对话框中单击"通知"选项卡。

  3. 如果想通过电子邮件通知操作员，请选择"电子邮件操作员"复选框，然后在列表中执行下列操作之一：
    • 单击"当作业成功时"选项，在作业成功完成后通知操作员。

    • 单击"当作业失败时"选项，在作业未能成功完成时通知操作员。

    • 单击"只要作业完成"选项，无论完成状态如何均通知操作员。
  4. 如果想通过寻呼程序通知操作员，请选择"呼叫操作员"复选框，然后在列表中执行下列操作之一：
    • 单击"当作业成功时"选项，在作业成功完成后通知操作员。

    • 单击"当作业失败时"选项，在作业未能成功完成时通知操作员。

    • 单击"只要作业完成"选项，无论完成状态如何均通知操作员。
  5. 如果想通过"网络发送"通知操作员，请选择"网络发送操作员"复选框，单击一个操作员，然后执行下列操作之一：
    • 单击"当作业成功时"选项，在作业成功完成后通知操作员。

    • 单击"当作业失败时"选项，在作业未能成功完成时通知操作员。

    • 单击"只要作业完成"选项，无论完成状态如何均通知操作员。


如何将作业状态写入 Windows 应用程序日志（企业管理器）

将作业状态写入 Windows 应用程序日志

  1. 在详细信息窗格中右击作业，然后单击"属性"命令。

  2. 单击"通知"选项卡。

  3. 选择"写入 Windows 应用程序事件日志"复选框，然后在列表中执行下列操作之一：
    • 单击"当作业成功时"选项，在作业成功完成时记录作业状态。

    • 单击"当作业失败时"选项，在作业未能成功完成时记录作业状态。

    • 单击"只要作业完成"选项，无论完成状态如何均记录作业状态。


如何自动删除作业（企业管理器）

自动删除作业

  1. 在详细信息窗格中右击作业，然后单击"属性"命令。

  2. 单击"通知"选项卡。

  3. 选择"自动删除作业"复选框，然后在列表中执行下列操作之一：
    • 单击"当作业成功时"选项，在作业成功完成时删除作业。

    • 单击"当作业失败时"选项，在作业未能成功完成时删除作业。

    • 单击"只要作业完成"选项，无论完成状态如何均删除作业。


如何设置目标服务器的轮询间隔（企业管理器）

设置目标服务器的轮询间隔

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"管理目标服务器"命令。

  4. 在"目标服务器状态"选项卡中，单击"发布指令"。

  5. 在"指令类型"列表中，选择"设置轮询间隔"。

  6. 在"轮询间隔"框中输入 10 到 28,800 之间的某个秒数，目标服务器必须在经过该秒数后才轮询主服务器。

  7. 在"收件人"下执行下列操作之一：
    • 单击"全部目标服务器"选项（如果所有目标服务器共享同一轮询间隔）。

    • 单击"这些目标服务器"选项（如果并非所有的目标服务器都共享同一轮询间隔），然后选择每台将使用该轮询间隔的目标服务器。


如何启动作业（企业管理器）

启动作业

  • 在详细信息窗格中，右击某个作业，然后执行下列操作之一：
    • 单击"启动作业"（如果在单台服务器上工作，或在目标服务器上工作，或在主服务器上运行本地服务器作业）。

    • 单击"启动作业"，然后单击"在所有目标服务器上启动"（如果在主服务器上工作，并且想要所有目标服务器同时运行该作业）。

    • 单击"启动作业"，然后选择"在指定的目标服务器上启动"选项（如果在主服务器上工作，并且想要指定该作业的目标服务器）。

      在"发布下载指令"对话框中，选择"这些目标服务器"复选框，然后选择每台运行该作业的目标服务器。


如何停止作业（企业管理器）

停止作业

  • 在详细信息窗格中右击作业，然后单击"停止作业"命令。

    对于多服务器作业，针对该作业的 STOP 指令将发布到该作业的所有目标服务器中。


如何强制目标服务器轮询主服务器（企业管理器）

强制目标服务器轮询主服务器

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"管理目标服务器"命令。

  4. 单击目标服务器，然后单击"强制轮询"。


如何查看作业（企业管理器）

查看作业

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，展开"SQL Server 代理程序"，然后单击"作业"命令。

  3. 在详细信息窗格中右击作业，然后单击"属性"命令。

    只能查看所拥有的作业。


如何调整作业历史记录日志的大小（企业管理器）

调整作业历史记录日志的大小

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 单击"作业系统"选项卡，然后选择"限制作业历史记录日志的大小"复选框。

  4. 在"作业历史记录日志的最大大小（行数）"框中输入作业历史记录日志允许的最大行数。

  5. 在"每个作业历史记录的最大行数"框中输入一个作业允许的历史记录的最大行数。


如何清除作业历史记录日志（企业管理器）

清除作业历史记录日志

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，展开"SQL Server 代理程序"，然后单击"作业"命令。

  3. 在详细信息窗格中右击某个作业，然后执行下列操作之一：
    • 单击"查看作业历史记录"（如果要清除本地作业的历史记录日志）。

    • 单击"作业状态"选项（如果要清除多服务器作业的历史记录日志）。单击"作业"按钮，单击某个作业名，然后单击"查看远程作业历史记录"按钮。
  4. 单击"全部清除"命令。


如何修改作业（企业管理器）

修改作业

  1. 在详细信息窗格中右击作业，然后单击"属性"命令。

  2. 在"作业属性"对话框中，使用相应的选项卡更新作业的属性、步骤、调度和通知。

    除非是 sysadmin 角色成员，否则只能修改自己所拥有的作业。

请参见

如何创建作业（企业管理器）

如何通知操作员作业的状态（企业管理器）

如何调度作业（企业管理器）


如何修改作业的目标服务器（企业管理器）

修改作业的目标服务器

  1. 在详细信息窗格中右击某个作业，然后单击"属性"命令。

  2. 在"常规"选项卡上，单击"更改"。

  3. 单击一台或多台服务器，然后单击右箭头将其选为作业的目标服务器。

  4. 在"选定的目标服务器"框中选择一台或多台服务器，然后单击向左箭头，删除这些作为作业目标的服务器。


如何修改目标服务器的位置（企业管理器）

修改目标服务器的位置

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"文件夹。

  3. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"管理目标服务器"命令。

  4. 右击一个服务器，然后单击"属性"命令。

  5. 在"位置"框中，输入服务器的位置。


如何删除作业（企业管理器）

删除作业

  • 在详细信息窗格中右击作业，然后单击"删除"命令。

    除非是 sysadmin 角色成员，否则只能修改自己所拥有的作业。


如何同步目标服务器的时钟（企业管理器）

同步目标服务器的时钟

  1. 展开服务器组，然后展开服务器。

  2. 右击"SQL Server 代理程序"，指向"多服务器管理"，然后单击"管理目标服务器"命令。

  3. 单击"发布指令"命令。

  4. 在"指令类型"列表中，选择"同步时钟"。

  5. 在"收件人"下执行下列操作之一：
    • 单击"全部目标服务器"选项，使所有目标服务器的时钟与主服务器的时钟同步。

    • 单击"这些目标服务器"选项同步某些服务器时钟，然后选择每台想使其时钟与主服务器时钟同步的目标服务器。


如何使用 Transact-SQL 编写作业脚本（企业管理器）

使用 Transact-SQL 编写作业脚本

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 右击"作业"，指向"所有任务"子菜单，然后单击"生成 SQL 脚本"命令。

  4. 在"文件名称"框中，键入该脚本的名称。

  5. 在"文件格式"下执行下列操作之一：
    • 单击"MS-DOS 文本 (OEM)"选项，将该脚本保存为 OEM 格式。

    • 单击"Windows 文本 (ANSI)"选项，将该脚本保存为 ANSI 格式。

    • 单击"国际化文本 (Unicode)"选项，将该脚本保存为 Unicode 格式。
  6. 在"SQL 生成选项"下执行下列一项或两项操作：（可选）
    • 选择"如果作业已存在，将其替换"复选框，包含脚本命令以删除与脚本生成的作业同名的作业。

    • 选择"包含目标服务器"复选框，包含用于生成目标服务器分配的脚本命令。只有在编写多服务器作业的脚本时，才可以使用此选项。
  7. 在"TSQL 批处理分隔符"框中，输入 Transact-SQL 批处理分隔符。


如何创建操作员（企业管理器）

创建操作员

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 右击"操作员"，然后单击"新建操作员"命令。

  4. 在"名称"框中，键入操作员的姓名。

  5. 若要定义通知操作员的方法，请执行下列一项或多项操作：
    • 如果要通过电子邮件通知操作员，则在"电子邮件名称"框中输入操作员的电子邮件地址。

    • 如果要通过呼叫程序通知操作员，则在"呼叫程序电子邮件名称"框中输入操作员呼叫程序服务的呼叫程序地址。此外还要单击操作员可以接收呼叫通知的日期。

    • 如果要通过网络发送通知操作员，则在"网络发送地址"框中输入操作员的网络发送地址。

请参见

如何将警报指派给操作员（企业管理器）


如何将警报指派给操作员（企业管理器）

将警报指派给操作员

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 单击"操作员"。

  4. 在详细信息窗格中右击某个操作员，单击"属性"命令，然后单击"通知"选项卡。

  5. 在"通知送达该操作员的方式"下，选择下列一个或多个复选框，定义在必要时每个警报的通知方式："电子邮件"、"寻呼程序"或"网络发送"。

  6. 选择"操作员可用于接收通知"复选框，对该操作员启用（所有类型的）通知。


如何设置呼叫程序地址的格式（企业管理器）

设置呼叫程序地址的格式

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，单击"属性"，然后单击"警报系统"选项卡。

  3. 在"收件人"框和"抄送"框中输入呼叫程序地址的前缀或后缀。发送通知时，将插入操作员的实际呼叫程序地址。

  4. 在"主题"框中输入主题行的前缀或后缀。

  5. 选择"在通知页中包含电子邮件的正文部分"选项，在寻呼消息中包括完整的电子邮件（与仅包含主题行相对）。


如何指派防故障操作员（企业管理器）

指派防故障操作员

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，单击"属性"，然后单击"警报系统"选项卡。

  3. 在"防故障操作员"下的"操作员"列表中，单击某个操作员。

  4. 单击适当的通知类型，指定如何通知操作员。


如何使用错误号创建警报（企业管理器）

使用错误号创建警报

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"警报"，然后单击"新建警报"命令。

  3. 在"名称"框中输入此警报的名称。

  4. 选择"启用"复选框以使警报能够运行。

  5. 单击"错误号"，然后为该警报输入有效的错误号。

    如果在 sysmessages 表中找到错误号，将显示该错误号的消息文本。否则，将显示"无效的错误号"。

    说明 若要按消息文本、错误号或严重度搜索错误，请单击浏览（"..."）按钮打开"管理 SQL Server 消息"对话框。

  6. 在"数据库名称"列表中单击数据库，以便将警报限制于特定的数据库。

  7. 在"错误信息包含此文本"框中输入一个关键字或字符串，以便将警报限制于特定的字符序列。最大字符数为 100。

请参见

如何定义对警报的响应


如何使用严重级别创建警报（企业管理器）

使用严重级别创建警报

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"警报"，然后单击"新建警报"命令。

  3. 在"名称"框中，键入该警报的名称。

  4. 选择"启用"复选框以使警报能够运行。

  5. 单击"严重度"，然后单击一种严重级别。

    如果严重级别在 19 到 25 之间，就会向 Microsoft Windows NT® 应用程序日志发送 Microsoft® SQL Server™ 消息，并触发一个警报。对于严重级别小于 19 的事件，只有在使用 sp_altermessage、RAISERROR WITH LOG 或 xp_logevent 强制这些事件写入 Windows 应用程序日志时，才会触发警报。

  6. 在"数据库名称"列表中单击数据库，以便将警报限制于特定的数据库。

  7. 在"错误信息包含此文本"框中输入一个关键字或字符串，以便将警报限制于特定的字符序列。

    最大字符数为 100。

请参见

如何定义对警报的响应


如何定义对警报的响应（企业管理器）

定义对警报的响应

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 单击"警报"，并在详细信息窗格中右击一个警报。

  4. 单击"属性"，然后单击"响应"选项卡。

  5. 选择"执行作业"复选框，然后单击警报发生时要执行的作业。

    可以通过单击（"新建作业"）创建新的作业，或通过单击浏览（"..."）按钮修改现有的作业。

  6. 在"要通知的操作员"下，为一个或多个操作员选择下列一个或多个复选框："电子邮件"、"寻呼程序"或"网络发送"。

    确保每个操作员的通知方法均有效。

  7. 如果要将警报错误文本随通知一同发送，则为使用的通知方法选择"警报错误文本包含于"选项。

  8. 在"要发送给操作员的其它通知消息"中，输入用于该操作员的其它信息。

    最大字符数为 512。

请参见

如何将警报指派给操作员（企业管理器）

如何创建操作员（企业管理器）

如何修改作业（企业管理器）


如何创建用户定义的事件错误信息（企业管理器）

创建用户定义的事件错误信息

  1. 展开一个服务器组。

  2. 右击服务器，单击"所有任务"，然后单击"管理 SQL Server 消息"。

  3. 单击"步骤"选项卡，然后单击"新建"按钮。

  4. 在"严重度"列表中，单击严重级别。

  5. 在"消息文本"框中输入新的事件消息。

    最大字符数为 255。

  6. 选择"始终写入 Windows 事件日志"复选框，以将事件消息写入 Microsoft® Windows® 应用程序日志。


如何编辑用户定义的事件错误信息（企业管理器）

编辑用户定义的事件错误信息

  1. 展开一个服务器组。

  2. 右击服务器，单击"所有任务"，然后单击"管理 SQL Server 消息"。

  3. 在"常规"选项卡上，单击"仅包含用户定义的消息"。

    若要限定搜索条件，可指定搜索查找指定的错误号、消息文本或严重级别。搜索结果显示在"消息"选项卡中。

  4. 在"消息"选项卡上，单击要编辑的消息，然后单击"编辑"按钮。

    在"编辑 SQL Server 消息"对话框中，可以编辑严重级别和消息文本。


如何删除用户定义的事件错误信息（企业管理器）

删除用户定义的事件错误信息

  1. 展开一个服务器组。

  2. 右击服务器，单击"所有任务"，然后单击"管理 SQL Server 消息"。

  3. 在"常规"选项卡上，单击"仅包含用户定义的消息"。

    若要限定搜索条件，可指定搜索查找指定的错误号、消息文本或严重级别。搜索结果显示在"消息"选项卡中。

  4. 在"消息"选项卡上，单击要删除的消息，然后单击"删除"按钮。


如何禁用或重新激活警报（企业管理器）

禁用或重新激活警报

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 单击"警报"，在详细信息窗格中右击某个警报，然后单击"属性"命令。

  4. 选择或清除"启用"复选框。

请参见

如何删除警报


如何指派事件转发服务器（企业管理器）

指派事件转发服务器

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"项，单击"属性"命令，然后单击"高级"选项卡。

  3. 在"转发 SQL Server 事件"下，选择"向另一服务器转发事件"复选框。

    事件转发功能仅在 Microsoft® Windows NT® 4.0 和 Microsoft Windows® 2000上可用。

  4. 在"服务器"列表中，单击一台服务器，然后执行下列操作之一：
    • 单击"未处理的事件"选项，仅转发本地警报尚未处理的事件。

    • 单击"全部事件"选项转发所有事件，无论本地警报是否已处理这些事件。
  5. 在"如果事件具有等于或高于以下值的严重度"列表中，单击事件转发到所选服务器时事件的严重级别。


如何查看有关操作员的信息（企业管理器）

查看操作员信息

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 单击"操作员"，在详细信息窗格中右击某个操作员，然后单击"属性"命令。

    "常规"选项卡显示为操作员定义的通知方法和呼叫程序调度。"通知"选项卡显示操作员收到的通知以及最近的通知尝试。


如何编辑操作员（企业管理器）

编辑操作员

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 单击"操作员"，在详细信息窗格中右击某个操作员，然后单击"属性"命令。

请参见

如何将警报指派给操作员（企业管理器）

如何创建操作员（企业管理器）


如何更改操作员的可用性（企业管理器）

更改操作员的可用性

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 单击"操作员"，在详细信息窗格中右击一个操作员，单击"属性"命令，然后单击"通知"选项卡。

  4. 选择或清除"操作员可用于接收通知"复选框。

请参见

如何删除操作员


如何删除操作员（企业管理器）

删除操作员

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 单击"操作员"，在详细信息窗格中右击某个操作员，然后单击"删除"命令。

  4. 如果出现"删除操作员"对话框，则执行下列操作之一：
    • 在"重新指派到"列表中，单击一个操作员，如果想要另一个操作员收到发送给已删除的操作员的警报和作业，则请单击"重新指派"。

    • 如果希望在不重新分配警报和作业的情况下删除操作员，则单击"不重新分配而删除"选项。

请参见

如何更改操作员的可用性


如何查看有关警报的信息（企业管理器）

查看有关警报的信息

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 单击"警报"，在详细信息窗格中右击某个警报，然后单击"属性"命令。

    在"常规"选项卡的"历史记录"下，可以查看上次警报发生的日期、上次响应警报的日期，以及自上次重置计数后触发警报的次数。在"响应"选项卡上可查看触发警报时发生的操作。


如何编辑警报（企业管理器）

编辑警报

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 在详细信息窗格中右击某个警报，然后单击"属性"命令。

  4. 在"常规"和"响应"选项卡上更新警报属性。

请参见

如何使用错误号创建警报（企业管理器）

如何使用严重级别创建警报（企业管理器）

如何定义对警报的响应（企业管理器）


如何删除警报（企业管理器）

删除警报

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 单击"警报"，在详细信息窗格中右击某个警报，然后单击"删除"命令。

  4. 确认删除。

请参见

如何禁用或重新激活警报（企业管理器）


如何使用 Transact-SQL 编写操作员脚本（企业管理器）

使用 Transact-SQL 编写操作员脚本

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 右击"操作员"，指向"所有任务"，然后单击"生成 SQL 脚本"命令。

  4. 在"文件名称"框中，键入脚本的名称。

  5. 在"文件格式"下执行下列操作之一：
    • 单击"MS-DOS 文本 (OEM)"选项，将脚本保存为 OEM 格式。

    • 单击"Windows 文本 (ANSI)"选项，将脚本保存为 ANSI 格式。

    • 单击"国际化文本 (Unicode)"选项，将脚本保存为 Unicode 格式。
  6. 在"SQL Server 生成选项"下，执行下列一项或两项操作：
    • 选择"如果操作员存在，将其替换"复选框，包含脚本命令以删除与脚本生成的作业同名的操作员。

    • 选择"包含通过警报发送到操作员的通知"复选框，包含脚本命令以便为由脚本生成的操作员生成警报分配。
  7. 输入一个 Transact-SQL 批处理分隔符。


如何使用 Transact-SQL 编写警报脚本（企业管理器）

使用 Transact-SQL 编写警报脚本

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 右击"警报"，指向"所有任务"，然后单击"生成 SQL 脚本"命令。

  4. 在"文件名称"框中，键入脚本的名称。

  5. 在"文件格式"下执行下列操作之一：
    • 单击"MS-DOS 文本 (OEM)"选项，将脚本保存为 OEM 格式。

    • 单击"Windows 文本 (ANSI)"选项，将脚本保存为 ANSI 格式。

    • 单击"国际化文本 (Unicode)"选项，将脚本保存为 Unicode 格式。
  6. 在"SQL 生成选项"下执行下列一项或多项操作：
    • 选择"如果警报存在，将其替换"复选框，包含脚本命令以删除与脚本生成的作业同名的警报。

    • 选择"包含通过警报发送到操作员的通知"复选框，包含脚本命令以便为由脚本生成的操作员生成警报分配。

    • 选择"包含通过警报执行的作业名"复选框，包含脚本命令以便为由警报执行的作业提供名称。
  7. 在"TSQL 批处理分隔符"框中，输入 Transact-SQL 批处理分隔符。

    包含由警报执行的作业名，以使脚本生成的警报引用各自的响应作业。


如何设置作业执行关闭（企业管理器）

设置作业执行关闭

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，单击"属性"命令，然后单击"作业系统"选项卡。

  3. 在"作业执行"下的"关闭超时间隔（秒）"框中，增加或减少关闭的超时间隔。

    这决定了 SQL Server 代理程序自行结束之前，将用多长时间等待正在执行的作业结束。


如何自动启动 SQL Server 代理程序（企业管理器）

自动启动 SQL Server 代理程序

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 单击"高级"选项卡，然后选择"SQL Server 代理程序意外停止时自动重新启动"复选框。


如何发送 SQL Server 代理错误信息（企业管理器）

发送 SQL Server 代理错误信息

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 在"错误日志"下的"网络发送接收者"框中，键入用户名或计算机名。

    此特性仅在 Microsoft® Windows NT® 4.0 和 Microsoft Windows® 2000 上可用。


如何查看 SQL Server 代理错误日志（企业管理器）

查看 SQL Server 代理错误日志

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"显示错误日志"命令。

  3. 在"类型"列表中，单击一种用以筛选日志内容的记录项。

  4. 在"包含文字"框中，输入用以筛选日志内容的消息文本。（可选）

  5. 如果选择了筛选参数，则单击"应用筛选"命令。

  6. 在"已筛选内容"下面查看日志内容。


如何重命名 SQL Server 代理错误日志（企业管理器）

重命名 SQL Server 代理错误日志

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 在"错误日志"下的"文件名"框中，输入新的路径和文件名，或使用浏览（"..."）按钮查找。

    只能在 SQL Server 代理程序停止时才可以重命名错误日志。


如何将执行跟踪消息写入 SQL Server 代理错误日志（企业管理器）

将执行跟踪消息写入 SQL Server 代理错误日志

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，右击"SQL Server 代理程序"，然后单击"属性"命令。

  3. 在"错误日志"下，选择"包含执行跟踪消息"复选框。

    由于该选项会导致错误日志变得很大，因此仅当调查特定的 SQL Server 代理程序问题时才设置该选项。


如何使用 SQLServerAgent 服务调度 DTS 包（企业管理器）

使用 SQLServerAgent 服务调度 DTS 包

  1. 展开服务器，然后展开服务器组。

  2. 展开"管理"，然后展开"SQL Server 代理程序"。

  3. 右击"作业"，然后单击"新建作业"命令。

  4. 完成"常规"选项卡上的信息，然后单击"步骤"选项卡。

  5. 单击"新建"按钮，然后完成"新建作业步骤"对话框中的信息：
    • 对于"类型"，单击列表中的"操作系统命令 (CmdExec)"。

    • 对于"命令"，输入包的 dtsrun 命令。

    • 单击"高级"选项卡进一步处理其它作业自定义选项。

请参见

如何创建作业（企业管理器）


如何创建 SQL Server 7.0 兼容脚本（企业管理器）

创建 SQL Server 7.0 兼容脚本

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹。

  3. 右击数据库，指向"所有任务"，然后单击"生成 SQL 脚本"命令。

  4. 在"常规"选项卡上，单击"全部显示"以显示要编写脚本的所有对象。

  5. 选择要编写脚本的对象类型，或选择"编写全部对象脚本"复选框。

  6. 单击"格式"选项卡，然后选择"仅为与 7.0 版兼容的功能编写脚本"复选框。

    该选项仅在 Microsoft® SQL Server™ 2000 计算机上可用。


安全管理

若要确保存储在 Microsoft® SQL Server™ 中的数据及对象仅由经授权的用户访问，必须正确地设置安全性。必须设置的安全因素包括身份验证模式、登录、用户、角色、授权、废除和拒绝 Transact-SQL 语句和对象上的权限以及数据加密。


如何设置 Windows 身份验证模式的安全性（企业管理器）

设置 Windows 身份验证模式的安全性

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 在"安全性"选项卡的"身份验证"下，单击"仅 Windows"。

  4. 在"审核级别"中选择在 SQL Server 错误日志中记录的用户访问 Microsoft® SQL Server™ 的级别：
    • "无"表示不执行审核。

    • "成功"表示只审核成功的登录尝试。

    • "失败"表示只审核失败的登录尝试。

    • "全部"表示审核成功的和失败的登录尝试。

请参见

身份验证模式


设置混合模式安全性的方法（企业管理器）

设置混合模式安全性

  1. 展开一个服务器组。

  2. 右击一个服务器，再单击"属性"。

  3. 单击"安全性"选项卡。

  4. 在"身份验证"下，单击"SQL Server 和 Windows"。

  5. 在"审核级别"中选择在 SQL Server 错误日志中记录的用户访问 Microsoft® SQL Server™ 的级别：
    • "无"表示不执行审核。

    • "成功"表示只审核成功的登录尝试。

    • "失败"表示只审核失败的登录尝试。

    • "全部"表示审核成功的和失败的登录尝试。

请参见

身份验证模式


授权 Windows 用户或组登录访问 SQL Server 的方法（企业管理器）

授权 Windows NT 4.0 或 Windows 2000 用户或组登录访问 SQL Server

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，右击"登录"，然后单击"新建登录"。

  3. 在"名称"框中，输入要被授权访问 Microsoft SQL Server™ 的 Microsoft® Windows NT® 4.0 或 Windows® 2000 帐户（以 DOMAIN\User 的形式）。

  4. 在"身份验证"下，单击"Windows 身份验证"。

  5. 可选：
    • 在"数据库"中，单击用户在登录到 SQL Server 实例后所连接的默认数据库。

    • 在"语言"中，单击显示给用户的信息所用的默认语言。

请参见

添加 Windows NT 用户或组


授权 Windows 用户或组访问数据库的方法（企业管理器）

授权 Windows NT 4.0 或 Windows 2000 用户或组访问数据库

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开将授权用户或组访问的数据库。

  3. 右击"用户"，然后单击"新建数据库用户"命令。

  4. 在"登录名"框中，键入或选择将被授权访问数据库的 Microsoft® Windows NT® 4.0 或 Windows® 2000 用户名或组名。

  5. 在"用户名"中，输入在数据库中识别登录所用的用户名。（可选）在默认的情况下，它设置为登录名。

  6. 除 public（默认）外，还选择授权给用户或组的其它数据库角色成员。（可选）

请参见

授权 Windows NT 的用户或组访问数据库


添加 SQL Server 登录的方法（企业管理器）

添加 SQL Server 登录

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，右击"登录"，然后单击"新建登录"。

  3. 在"名称"框中，输入 Microsoft® SQL Server™ 登录的名称。

  4. 在"身份验证"下，选择"SQL Server 身份验证"。

  5. 在"密码"中输入密码。（可选）

  6. 可选：
    • 在"数据库"中，单击在登录到 SQL Server 实例之后登录将连接到的默认数据库。

    • 在"语言"中，单击显示给用户的信息所用的默认语言。

请参见

添加 SQL Server 登录


添加链接服务器登录的方法（企业管理器）

添加链接服务器的登录

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后再单击"链接服务器"。

  3. 在"详细信息"窗格中,右击登录将被加入的链接服务器，然后单击"属性"。

  4. 在"安全性"选项卡中，单击要添加的本地登录。

  5. 如果本地登录应该使用自己的用户安全凭据连接到链接服务器上，则选择"模拟"复选框。（可选）

  6. 输入本地登录在不使用用户的安全凭据（"模拟"未被选中）的情况下连接到链接服务器时应使用的远程用户和远程密码。

请参见

建立链接服务器的安全性

如何设置链接服务器（企业管理器）


授权 SQL Server 登录访问数据库的方法（企业管理器）

授权 SQL Server 登录访问数据库

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开将授权登录访问的数据库。

  3. 右击"用户"，然后单击"新建数据库用户"命令。

  4. 在"登录名"框中，单击要授权访问数据库的 Microsoft® SQL Server™ 登录。

  5. 在"用户名"中，输入在数据库中识别登录所用的用户名。（可选）在默认的情况下，它设置为登录名。

  6. 除 public（默认值）外，还可选择其它数据库角色成员。（可选）

请参见

授权 SQL Server 登录访问数据库

guest 用户


创建 SQL Server 数据库角色的方法（企业管理器）

创建 SQL Server 数据库角色

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开要在其中创建角色的数据库。

  3. 右击"角色"，然后单击"新建数据库角色"命令。

  4. 在"名称"框中输入新角色的名称。

  5. 单击"添加"将成员添加到"标准角色"列表中，然后单击要添加的一个或多个用户。（可选）

    只有选定数据库中的用户才能被添加到角色中。

请参见

创建用户定义的 SQL Server 数据库角色


将成员添加到 SQL Server 数据库角色中的方法（企业管理器）

向 SQL Server 数据库角色添加成员

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开角色所在的数据库。

  3. 单击"角色"。

  4. 在"详细信息"窗格中,右击用户所要加入的角色，然后单击"属性"。

  5. 单击"添加"，然后单击要添加的一个或多个用户。

    只有选定数据库中的用户才能被添加到角色中。

请参见

将成员添加到预定义角色中

将成员添加到 SQL Server 数据库角色


将成员添加到固定服务器角色中的方法（企业管理器）

向固定服务器角色添加成员

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"服务器角色"。

  3. 在"详细信息"窗格中，右击该角色，然后单击"属性"。

  4. 在"常规"选项卡中单击"添加"按钮,然后单击要添加的登录。

请参见

将成员添加到预定义角色中


使用创建登录向导向用户授予 SQL Server 登录访问权的方法（企业管理器）

使用创建 SQL Server 登录向导向用户授予 SQL Server 登录访问权

  1. 在"工具"菜单上单击"向导"命令。

  2. 在"选择向导"对话框中，展开"数据库"，然后双击"创建登录向导"。

  3. 完成向导中的步骤。

请参见

使用创建登录向导


查看 SQL Server 登录或 Windows 用户或组的方法（企业管理器）

查看 SQL Server 登录或 Windows NT 4.0 或 Windows 2000 用户或组

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"登录"。

  3. 在"详细信息"窗格中，右击要查看的登录，然后单击"属性"。

请参见

查看登录


查看数据库用户的方法（企业管理器）

查看数据库用户

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开用户所属的数据库。

  3. 单击"用户"。

  4. 在"详细信息"窗格中右击要查看的用户，然后单击"属性"。

请参见

查看数据库用户


更改 SQL Server 登录密码的方法（企业管理器）

更改 SQL Server 登录的密码

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"登录"。

  3. 在"详细信息"窗格中右击要修改的登录，然后单击"属性"。

  4. 在"常规"选项卡上的"密码"框中输入新的密码。

  5. 确认该密码。

请参见

修改登录


更改登录的默认数据库的方法（企业管理器）

更改登录的默认数据库

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"登录"。

  3. 在"详细信息"窗格中右击要修改的登录，然后单击"属性"。

  4. 在"常规"选项卡上的"数据库"列表中，单击登录到 Microsoft® SQL Server™ 实例之后登录所连接的新的默认数据库。

请参见

修改登录


更改登录的默认语言的方法（企业管理器）

更改登录的默认语言

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"登录"。

  3. 在"详细信息"窗格中右击要修改的登录，然后单击"属性"。

  4. 在"常规"选项卡上的"语言"列表中，单击显示给用户的消息所用的新默认语言。

请参见

修改登录


从数据库中删除用户或组的方法（企业管理器）

从数据库中删除用户或组

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开用户或组所属的数据库。

  3. 单击"用户"。

  4. 在"详细信息"窗格中右击要删除的用户或组，然后单击"删除"。

  5. 确认删除。

请参见

删除登录和用户


删除 SQL Server 登录的方法（企业管理器）

删除 SQL Server 登录

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"登录"。

  3. 在"详细信息"窗格中右击要删除的登录，然后单击"删除"。

  4. 确认删除。

请参见

删除登录和用户


从 SQL Server 中废除 Windows 用户或组的登录访问权的方法（企业管理器）

从 SQL Server 中废除 Windows NT 4.0 或 Windows 2000 用户和组的登录访问权

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"登录"。

  3. 在"详细信息"窗格中，右击要废除的 Microsoft® Windows NT® 4.0 或 Windows® 2000 用户或组，然后单击"删除"命令。

  4. 确认删除。

请参见

删除登录和用户


拒绝 Windows 用户或组的登录访问的方法（企业管理器）

拒绝 Windows NT 4.0 或 Windows 2000 用户或组的登录访问

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"登录"。

  3. 在"详细信息"窗格中，右击要拒绝的 Microsoft® Windows NT® 4.0 或 Windows® 2000 用户或组，然后单击"属性"命令。

  4. 在"身份验证"下，单击"拒绝访问"。

请参见

拒绝 Windows NT 帐户的登录访问

授权 Windows NT 用户或组对 SQL Server 的登录访问（企业管理器）


删除链接服务器登录的方法（企业管理器）

删除链接服务器登录

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"链接服务器"。

  3. 在"详细信息"窗格中，右击要删除的链接服务器登录所映射的链接服务器，然后单击"属性"。

  4. 在"安全性"选项卡上的"本地登录"下，单击要删除的链接服务器登录，然后在列表的顶部选择空的登录。

请参见

删除登录和用户


查看在当前数据库中定义的角色的方法（企业管理器）

查看当前数据库中定义的角色

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开要查看的数据库。

  3. 单击"角色"。

请参见

查看角色


查看固定服务器角色的方法（企业管理器）

查看固定服务器角色

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"服务器角色"。

请参见

查看角色


查看数据库角色成员的方法（企业管理器）

查看数据库角色的成员

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开用户所属的数据库。

  3. 单击"角色"。

  4. 在"详细信息"窗格中右击要查看的角色，然后单击"属性"以查看成员。

请参见

查看和修改角色成员


从数据库角色中删除用户帐户的方法（企业管理器）

从数据库角色中删除用户帐户

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开角色所在的数据库。

  3. 单击"角色"。

  4. 在"详细信息"窗格中，右击用户帐户所属的角色，然后单击"属性"。

  5. 选择要删除的用户，然后单击"删除"。

请参见

查看和修改角色成员


查看固定服务器角色的成员的方法（企业管理器）

查看固定服务器角色的成员

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"服务器角色"。

  3. 在"详细信息"窗格中右击要查看的服务器角色，然后单击"属性"。

请参见

查看和修改角色成员


从固定服务器角色中删除登录的方法（企业管理器）

从固定服务器角色中删除登录

  1. 展开服务器组，然后展开服务器。

  2. 展开"安全性"，然后单击"服务器角色"。

  3. 在"详细信息"窗格中右击要修改的服务器角色，然后单击"属性"。

  4. 在"常规"选项卡上选择要删除的登录，然后单击"删除"。

请参见

查看和修改角色成员


删除 SQL Server 角色的方法（企业管理器）

删除 SQL Server 角色

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开角色所在的数据库。

  3. 单击"角色"。

  4. 在"详细信息"窗格中，右击该角色，然后单击"删除"。

    说明 在删除角色之前，必须先除去所有的角色成员。但不能删除固定角色。

  5. 确认删除。

请参见

删除 SQL Server 数据库角色


通过授予权限而允许访问的方法（企业管理器）

通过授权而允许访问（对象上）

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开对象所属的数据库。

  3. 根据对象类型，单击下列对象之一：
    • 表

    • 视图

    • 存储过程
  4. 在"详细信息"窗格中，右击授予权限所在的对象，指向"所有任务"，然后单击"管理权限"。

  5. 单击"列出全部用户/用户定义的数据库角色/public"，然后选择授予每位用户的权限。

    选中标记表示授予权限。只列出适用于该对象的权限。

请参见

授予权限


为数据库内的用户授予语句权限的方法（企业管理器）

向用户授予数据库中的语句权限

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击将被授予语句权限的用户所在的数据库，然后单击"属性"。

  3. 在"权限"选项卡上，选择授予每位用户的语句权限。

    选中标记表示授予权限。

请参见

授予权限


为用户、组或角色授予在多个对象中的权限的方法（企业管理器）

向用户、组或角色授予多个对象的权限

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开用户、组或角色所属的数据库。

  3. 根据权限所要授予的用户、组或角色的类型，单击"用户"或"角色"。

  4. 在"详细信息"窗格中，右击权限所要授予的用户、组或角色，指向"所有任务",然后单击"管理权限"。

  5. 单击"列出全部对象"，然后选择授予每个对象的权限。

    选中标记表示授予权限。只列出适用于该对象的权限。

请参见

授予权限


通过拒绝权限防止访问的方法(企业管理器)

通过拒绝权限防止访问（在对象上）

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开对象所属的数据库。

  3. 根据将拒绝访问的对象类型，单击下列选项之一：
    • 表

    • 视图

    • 存储过程
  4. 在"详细信息"窗格中，右击要拒绝访问的对象，指向"所有任务"，然后单击"管理权限"。

  5. 单击"列出全部用户/用户定义的数据库角色/public"，然后选择拒绝授予每位用户的权限。

    "X"表示拒绝权限。只列出适用于该对象的权限。

请参见

拒绝权限


拒绝数据库内用户的语句权限的方法（企业管理器）

拒绝用户在数据库中的语句权限

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击要拒绝语句权限的用户所在的数据库，然后单击"属性"。

  3. 在"权限"选项卡中，选择拒绝授予每位用户的语句权限。

    "X"表示拒绝权限。

请参见

拒绝权限


拒绝用户、组或角色在多个对象中的权限的方法（企业管理器）

拒绝用户、组或角色在多个对象上的权限

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开用户、组或角色所属的数据库。

  3. 根据要被拒绝权限的用户、组或角色的类型，单击"用户"或"角色"。

  4. 在"详细信息"窗格中，右击权限将被拒绝的用户或组，然后指向"所有任务"，再单击"管理权限"。如果对某个角色拒绝权限，则右击将被拒绝权限的角色，单击"属性"，然后单击"权限"。

  5. 单击"列出全部对象"，然后选择拒绝授予每个对象的权限。

    "X"表示拒绝权限。只列出适用于该对象的权限。

请参见

拒绝权限


废除在对象上的权限的方法（企业管理器）

废除对象上的权限

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开对象所属的数据库。

  3. 根据将被废除访问权限的对象类型，单击下列对象之一：
    • 表

    • 视图

    • 存储过程
  4. 在"详细信息"窗格中，右击要被废除访问权的对象，指向"所有任务"，然后单击"管理权限"。

  5. 单击"列出全部用户/用户定义的数据库角色/public"，然后选择要废除的每位用户的权限。

    空的框表示废除的权限。只列出适用于该对象的权限。

请参见

废除权限


废除数据库中用户的语句权限的方法（企业管理器）

废除用户在数据库中的语句权限

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击要被废除语句权限的用户所在的数据库，然后单击"属性"。

  3. 在"权限"选项卡中，选择要废除的每位用户的语句权限。

    空的框表示废除的权限。

请参见

废除权限


废除用户、组或角色在多个对象中的权限的方法（企业管理器）

废除用户、组或角色在多个对象上的权限

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开用户、组或角色所属的数据库。

  3. 根据要被废除权限的用户、组或角色的类型，单击"用户"或"角色"。

  4. 在"详细信息"窗格中，右击要被废除权限的用户或组，指向"所有任务"，然后单击"管理权限"。如果废除某个角色的权限，则右击将被拒绝权限的角色，单击"属性"，然后单击"权限"。

  5. 单击"列出全部对象"，然后选择要废除的每个对象的权限。

    空的框表示废除的权限。只列出适用于该对象的权限。

请参见

废除权限


创建应用程序角色的方法（企业管理器）

创建应用程序角色

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开要在其中创建角色的数据库。

  3. 右击"角色"，然后单击"新建数据库角色"命令。

  4. 在"名称"框中，输入新的应用程序角色的名称。

  5. 在"数据库角色类型"下，单击"应用程序角色"，然后输入密码。

请参见

建立应用程序安全和应用程序角色


删除应用程序角色的方法（企业管理器）

删除应用程序角色

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开应用程序角色所在的数据库。

  3. 单击"角色"。

  4. 在"详细信息"窗格中右击要删除的应用程序角色，然后单击"删除"。

  5. 确认删除。

请参见

建立应用程序安全和应用程序角色


如何在网络上显示或取消 SQL Server 公告 (Windows)

在网络上显示或取消 SQL Server 公告

  1. 在"控制面板"中双击"网络"图标。

  2. 单击"服务"选项卡。

  3. 在"网络服务"列表中单击"服务器"选项，然后单击"属性"按钮。

  4. 选中"使浏览器广播到 LAN Manager 2.x 客户"以显示服务器，或者清除该复选框以隐藏服务器。

请参见

在网络上公布 SQL Server


如何授予、拒绝或撤消用户定义的角色在多个对象中的权限（企业管理器）

授予、拒绝或废除用户定义角色在多个对象上的权限

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开角色所属的数据库。

  3. 单击"角色"。

  4. 在"详细信息"窗格中，右击要授予、拒绝、取消其权限的用户定义的角色，然后单击"属性"命令。

  5. 在"名称"下单击"权限"。

  6. 单击"列出全部对象"，然后选择在每个对象上授予、拒绝或废除的权限。

    选中标志表示授予权限；"X"表示拒绝权限，空框表示废除权限。只列出适用于该对象的权限。


监视服务器性能和活动

有许多工具和技术可用于监视 Microsoft® SQL Server™。了解如何监视 SQL Server 有助于：

  • 确定是否可以改进性能。

  • 确定用户活动以查明用户正在发出什么查询以及谁正与 SQL Server 连接。

  • 解决问题。

  • 测试应用程序。


如何启动 SQL 事件探查器（企业管理器）

启动 SQL 事件探查器

  1. 在"开始"菜单上，指向"程序"，进而指向"Microsoft SQL Server"子菜单，然后单击"企业管理器"命令。

  2. 在"工具"菜单上单击"SQL 事件探查器"命令。

请参见

启动 SQL Server


如何查看当前服务器活动（企业管理器）

查看当前服务器活动

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"当前活动"。

  3. 单击"进程信息"。

    服务器的当前活动即会显示在详细信息窗格中。

请参见

用 SQL Server 企业管理器进行监视

用 Transact-SQL 语句监视


如何查看某个连接的最新批处理命令（企业管理器）

查看连接的上一批命令

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"当前活动"。

  3. 单击"进程信息"。

    服务器的当前活动即会显示在详细信息窗格中。

  4. 在详细信息窗格中，右击一个进程 ID，然后单击"属性"命令。

  5. 另外，可单击"刷新"按钮更新显示。

请参见

用 SQL Server 企业管理器进行监视

用 Transact-SQL 语句监视


如何查看当前锁（企业管理器）

查看当前的锁

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"当前活动"。

  3. 执行下列操作中的一种：
    • 展开"锁/进程 ID"以查看每个连接的当前锁。

    • 展开"锁/对象"以查看每个对象的当前锁。
  4. 在控制台树中单击要查看的连接 (SPID) 或对象。

    该连接或对象的当前锁显示在详细信息窗格中。

请参见

显示锁定信息

用 SQL Server 企业管理器进行监视

用 Transact-SQL 语句监视

SQL Server 中的锁定介绍


如何向当前连接的用户发送消息（企业管理器）

给当前连接的用户发送消息

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"当前活动"。

  3. 单击"进程信息"。

    服务器的当前活动即会显示在详细信息窗格中。

  4. 在详细信息窗格中，右击一个进程 ID，然后单击"发送消息"命令。

    说明 当 SQL Server 企业管理器在 Microsoft® Windows® 98 上运行时，不可能向用户发送消息。

  5. 在"消息"框中键入消息。

  6. 另外，可选择"使用主机名"，然后输入计算机名以便将消息发送到指定的计算机。

请参见

用 SQL Server 企业管理器进行监视


如何终止进程（企业管理器）

终止进程

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"当前活动"。

  3. 单击"进程信息"。

    服务器的当前活动即会显示在详细信息窗格中。

  4. 在详细信息窗格中，右击一个进程 ID，然后单击"取消进程"。

  5. 确认进程已终止。

请参见

用 SQL Server 企业管理器进行监视


如何查看 SQL Server 错误日志（企业管理器）

查看 SQL Server 错误日志

  1. 展开服务器组，然后展开服务器。

  2. 展开"管理"，然后展开"SQL Server 日志"。

  3. 单击"SQL Server 日志"进行查看。

    错误日志的详细信息显示在详细信息窗格内。

请参见

查看 SQL Server 错误日志


如何启动性能监视器 (Windows)

在 Windows NT 4.0 中启动性能监视器

  • 在"开始"菜单上，指向"程序"菜单，单击"管理工具"子菜单，然后单击"性能监视器"。

请参见

运行系统监视器


如何启动系统监视器 (Windows)

在 Windows 2000 中启动系统监视器

  • 在"开始"菜单上，指向"程序"菜单，进而指向"管理工具"子菜单，然后单击"性能"命令。

请参见

运行系统监视器


如何设置 SQL Server 数据库警报 (Windows NT)

创建 SQL Server 数据库警报

  1. 在"视图"菜单上单击"警报"。

  2. 在"编辑"菜单上单击"添加到警报"。

  3. 在"对象"列表中单击一个 SQL Server 对象，然后在"计数器"框中单击警报将基于的计数器。

  4. 在"满足下列条件则生成警报"下单击"超过"或"低于"，然后输入一个阈值。

    当计数器的数值超过或低于该阈值（取决于所选的是"超过"还是"低于"）时，将生成警报。

  5. 单击"首次"或"每次"以确定警报的生成频率。

    默认选择为"每次"。

请参见

创建 SQL Server 数据库警报


如何设置 SQL Server 数据库警报 (Windows)

创建一个 SQL Server 数据库警报

  1. 在"性能"窗口的"树"选项卡上，展开"性能日志和警报"。

  2. 右击"警报"，然后单击"新警报设置"命令。

  3. 在"新警报设置"对话框中，输入新警报的名称，然后单击"确定"按钮。

  4. 单击"添加"按钮添加警报计数器。

    所有警报必须至少有一个计数器。

  5. 在"性能对象"列表中，选择 Microsoft® SQL Server™ 对象，然后在"从列表中选择计数器"框中选择计数器。

  6. 若要添加警报计数器，请单击"添加"按钮。可以继续添加计数器，也可以单击"关闭"按钮返回"警报"对话框。

  7. 在"警报"对话框中，从"警报阈值"列表中单击"超过"或"低于"，然后输入阈值。

    当计数器的值超过或低于该阈值（取决于所选的是"超过"还是"低于"）时，将生成警报。

  8. 在"数据采样间隔"框中，设置采样频率。

  9. 在"操作"选项卡上，设置每次触发警报时发生的操作。

  10. 在"调度"选项卡上，设置警报扫描的开始和停止调度。

请参见

创建 SQL Server 数据库警报


如何查看 Windows 应用程序日志 (Windows)

查看 Windows 应用程序日志

  1. 在"开始"菜单上指向"程序"菜单，单击"管理工具"，然后单击"事件查看器"。

  2. 如果未显示 Microsoft® Windows® 应用程序日志，请在"日志"菜单上单击"应用程序"命令。

    Microsoft® SQL Server™ 事件由 Source 列中的 MSSQLSERVER 项标识。SQL Server 代理事件由 SQLServerAgent 项来标识。Microsoft 搜索服务由"Microsoft 搜索"项标识。

  3. 若要查看另一台计算机的日志，请在"日志"菜单上，单击"选择计算机"并完成"选择计算机"对话框。

  4. 另外，若要只显示 SQL Server 事件，请在"视图"菜单上单击"筛选事件"命令，然后单击"源"列表中的"MSSQLServer"。若要只查看 SQL Server 代理事件，则请选择"SQLServerAgent"。

  5. 若要查看有关某事件的更多信息，请双击该事件。

请参见

如何查看 SQL Server 错误日志

查看 Windows NT 应用程序日志


如何在 Windows 98 上启用 SQL Server 的 SNMP 支持（SQL Server 网络实用工具）

在 Windows 98 上启用 SQL Server 的 SNMP 支持

  1. 单击"控制面板"中的"网络"图标以安装 Microsoft® Windows® 98 SNMP 代理。单击"添加"按钮，选择"服务"作为要安装的网络组件的类型，单击"添加"按钮，然后单击"从磁盘安装"按钮。

  2. 从 Tools\Reskit\Netadmin\Snmp 目录安装 SNMP 代理程序。


如何将 SQL Server MSSQL-MIB 复制到 SNMP 工作站 (Windows)

将 SQL Server MSSQL-MIB 复制到 SNMP 工作站

  1. 在 C:\Program Files\Microsoft SQL Server\MSSQL\Binn 中找到 Mssql.mib 文件。

  2. 将 Mssql.mib 文件复制到监视工作站上的适当目录中。

  3. 对于将监视 Microsoft® SQL Server™ 的所有工作站重复上述步骤。

    有关装载 Microsoft SQL Server 管理信息库 (MSSQL-MIB) 和监视 SQL Server 的更多信息，请参阅简单网络管理协议 (SNMP) 应用程序文档。


如何设置跟踪定义默认值（SQL 事件探查器）

设置跟踪定义默认值

  1. 在"工具"菜单上，单击"选项"命令。

  2. 在"跟踪选项"对话框中，从"模板名"列表或"模板文件名"列表中选择模板。

  3. 选择或清除"进行连接后立即启动跟踪"复选框。

请参见

用 SQL 事件探查器进行监视


如何设置跟踪显示默认值（SQL 事件探查器）

设置跟踪显示默认值

  1. 在"工具"菜单上，单击"选项"命令。

  2. 在"跟踪选项"对话框中，单击"显示"选项卡。

  3. 在"字体名称"框中，选择 SQL 事件探查器用来显示跟踪的字体。

  4. 在"字体大小"列表中，选择 6 到 24 之间的数字。

请参见

用 SQL 事件探查器进行监视


如何创建跟踪（SQL 事件探查器）

创建跟踪

  1. 在"文件"菜单上，指向"新建"子菜单，再单击"跟踪"命令。

  2. 在"SQL Server"列表中，选择要跟踪的服务器，然后选择一个连接。

  3. 在"跟踪名称"框中，键入跟踪的名称，然后执行下列操作：
    • 在"跟踪 SQL Server"列表中，选择将要运行跟踪的服务器。

    • 在"模板名"列表中，选择此跟踪将基于的跟踪模板。
  4. 执行下列操作之一：
    • 单击"保存到文件"将跟踪捕获到其它位置中的文件。

    • 单击"保存到表"将跟踪捕获到数据库表。
  5. 选择"启用跟踪停止时间"复选框以指定停止的日期和时间。（可选）

  6. 若要完成其它跟踪属性，请单击"事件"、"数据列"或"筛选"选项卡，然后设置这些选项卡上的选项。

  7. 可以在开始跟踪时单击"运行"按钮。

请参见

用 SQL 事件探查器进行监视


如何在跟踪模板或跟踪文件中添加或删除事件（SQL 事件探查器）

在跟踪模板或跟踪文件中添加或删除事件

  1. 单击"文件"菜单，指向"打开"子菜单，然后单击"跟踪模板"或"跟踪文件"命令。

  2. 选择要打开的模板文件或跟踪文件。

  3. 在"跟踪模板属性"对话框中，单击"事件"选项卡。

  4. 在"可用事件类"列表中，展开一个事件组，然后单击单个事件，或者单击整个事件组。

  5. 单击"添加"按钮，将选定的事件或事件组添加到要跟踪的事件中。

  6. 在"选定的事件类"列表中，展开一个事件组，然后单击单个事件，或者单击整个事件组。

  7. 单击"删除"按钮，将选定的事件或事件组从要跟踪的事件中删除。

请参见

用 SQL 事件探查器进行监视


如何在跟踪模板中添加或删除数据列（SQL 事件探查器）

在跟踪模板中添加或删除数据列

  1. 在"文件"菜单上，指向"打开"子菜单，然后单击"跟踪模板"命令。

  2. 选择要打开的模板文件。

  3. 在"跟踪模板属性"对话框中，单击"数据列"选项卡。

  4. 在"未选定的数据"列表中，单击一个数据列，然后单击"添加"按钮，将该数据列添加到要捕获的数据中。

  5. 在"选定的数据"列表中，单击一个数据列，然后单击"删除"按钮，将该数据列从要捕获的数据中删除。

  6. 在"选定的数据"列表中，单击单个数据列，然后单击"向上"或"向下"按钮，对数据列排序。

请参见

用 SQL 事件探查器进行监视


如何筛选跟踪模板中的事件（SQL 事件探查器）

筛选跟踪模板中的事件

  1. 单击"文件"菜单，指向"打开"子菜单，然后单击"跟踪文件"或"跟踪模板"命令。

  2. 选择要打开的模板文件或跟踪文件。

  3. 在"跟踪模板属性"对话框中，单击"筛选"选项卡。

  4. 在"跟踪事件准则"列表中，单击一种准则。

  5. 在跟踪事件准则下显示的字段中输入一个值。


如何将跟踪结果保存到文件（SQL 事件探查器）

将跟踪结果保存到文件

  1. 在"文件"菜单上，指向"新建"子菜单，再单击"跟踪"命令。

  2. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 在"跟踪名"框中，键入跟踪的名称，然后选择"保存到文件"复选框。

  4. 在"设置最大文件大小 (MB)"复选框中设置最大文件大小。如果将跟踪结果保存到文件，则必须设置最大文件大小。

  5. 保存了文件后，执行下列操作：（可选）
    • 选择"启用文件翻转"复选框，如果达到最大文件大小，它将创建新文件来存储跟踪数据。如果将跟踪结果保存到文件，默认情况下选择该选项。

    • 选择"服务器进程 SQL Server 跟踪数据"复选框。

      若要避免丢失事件，请选择此选项。

请参见

用 SQL 事件探查器进行监视


如何将跟踪结果保存到表（SQL 事件探查器）

将跟踪结果保存到表

  1. 在"文件"菜单上，指向"新建"子菜单，再单击"跟踪"命令。

  2. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 在"跟踪名"框中，键入跟踪的名称，然后单击"保存到表"。

  4. 在"目的表"对话框中，执行下列操作：
    • 在"数据库"列表中，选择目的数据库。

    • 在"表"列表中，键入或选择跟踪结果的表名。
  5. 选择"设置最大行数（以千为单位）"复选框以指定要保存的最大行数。

请参见

用 SQL 事件探查器进行监视


如何修改跟踪模板（SQL 事件探查器）

修改跟踪模板

  1. 在"文件"菜单上，指向"打开"子菜单，然后单击"跟踪模板"命令。

  2. 选择要打开的跟踪模板文件。

  3. 在"跟踪模板属性"对话框中，通过执行下列操作指定跟踪模板配置：
    • 单击"事件"选项卡以修改选定事件类列表。

    • 单击"数据列"选项卡以修改选定数据列表。

    • 单击"筛选"选项卡以修改用于确定要捕获的事件的准则。若要添加或编辑准则，请展开跟踪事件，然后在跟踪准则下出现的字段中键入准则。

    所做的修改只有在下次将跟踪模板用于跟踪时才生效。

  4. 单击"保存"或"另存为"以其它名称保存跟踪模板。

请参见

用 SQL 事件探查器进行监视


如何暂停跟踪（SQL 事件探查器）

暂停跟踪

  1. 选择包含正在运行的跟踪的窗口。

  2. 在"文件"菜单上，单击"暂停跟踪"命令。

请参见

用 SQL 事件探查器进行监视


如何在跟踪暂停或停止之后运行跟踪（SQL 事件探查器）

在跟踪暂停或停止之后运行跟踪

  1. 选择包含已停止或暂停的跟踪的窗口。

  2. 在"文件"菜单上，单击"运行跟踪"命令。

请参见

用 SQL 事件探查器进行监视


如何清除跟踪窗口（SQL 事件探查器）

清除跟踪窗口

  1. 当有多个跟踪处于活动状态时，选择要清除的跟踪窗口。

  2. 在"编辑"菜单上，单击"清除跟踪窗口"命令。

    跟踪窗口中的内容将被删除。

请参见

用 SQL 事件探查器进行跟踪


如何关闭跟踪窗口（SQL 事件探查器）

关闭跟踪窗口（即关闭跟踪）

  1. 选择要关闭的跟踪窗口。关闭跟踪窗口即关闭跟踪。

  2. 在"文件"菜单上，单击"关闭"命令。

请参见

用 SQL 事件探查器进行监视


如何停止跟踪（SQL 事件探查器）

停止跟踪

  1. 选择一个正在运行的跟踪。

  2. 在"文件"菜单上，单击"停止跟踪"命令，或关闭跟踪窗口。

请参见

用 SQL 事件探查器进行监视


如何查看筛选信息（SQL 事件探查器）

查看筛选信息

  1. 创建一个跟踪，或是打开跟踪模板、跟踪文件或 SQL 脚本。

  2. 如果创建了跟踪，则在"文件"菜单上单击"属性"命令。

  3. 单击"筛选"选项卡以查看筛选信息。

请参见

用 SQL 事件探查器进行监视


如何打开跟踪数据文件（SQL 事件探查器）

打开跟踪数据文件

  1. 在"文件"菜单上，指向"打开"子菜单，然后单击"跟踪文件"命令。

  2. 选择要打开的跟踪数据文件。

请参见

用 SQL 事件探查器进行跟踪


如何打开跟踪表（SQL 事件探查器）

打开跟踪表

  1. 在"文件"菜单上，指向"打开"子菜单，然后单击"跟踪表"命令。

  2. 在"连接到 SQL Server"对话框中，选择含有跟踪表和连接方法的 Microsoft® SQL Server™ 实例。

  3. 在"源表"对话框的"数据库"列表中，单击保存表的数据库。

  4. 在"表"列表中，单击表的名称。

请参见

用 SQL 事件探查器进行监视


如何重播跟踪表（SQL 事件探查器）

重播跟踪表

  1. 在"文件"菜单上，指向"打开"子菜单，然后单击"跟踪表"命令。

  2. 在"连接到 SQL Server"对话框中，选择含有跟踪表和连接方法的 Microsoft® SQL Server™ 实例。

  3. 在"源表"对话框的"数据库"列表中，单击保存表的数据库。

  4. 单击"重播"菜单上的"开始"命令。

  5. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  6. 在"重播 SQL Server"对话框中，选择目的服务器，然后选择下列任一操作：
    • 按跟踪的顺序重播事件

    • 使用多线程重播事件

    • 显示重播结果

请参见

用 SQL 事件探查器进行监视


如何重播跟踪文件（SQL 事件探查器）

重播跟踪文件

  1. 在"文件"菜单上，指向"打开"子菜单，然后单击"跟踪文件"命令。

  2. 选择要打开的文件。

  3. 在"重播"菜单上，单击"开始"命令。

  4. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  5. 在"重播 SQL Server"对话框中，选择目的服务器，然后选择下列任项操作：
    • 按跟踪的顺序重播事件

    • 使用多线程重播事件

    • 显示重播结果


如何一次重播一个事件（SQL 事件探查器）

一次重播一个事件

  1. 单击"文件"菜单，指向"打开"子菜单，然后单击"跟踪文件"或"跟踪表"命令。

  2. 如果选择重播跟踪表中的事件，则必须输入连接信息。在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法，并在"源表"对话框中指定保存表的数据库。

  3. 除非已经选择了跟踪表，否则选择要打开的跟踪文件。

  4. 在"重播"菜单上，单击"步进"命令。

  5. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  6. 在"重播 SQL Server"对话框中，更改任何必要的设置，然后单击"开始"按钮。

  7. 在"重播"菜单上，单击"步进"命令。

  8. 重复步骤 6，直到重播了所有必要的事件步骤。

请参见

用 SQL 事件探查器进行监视


如何重播到断点（SQL 事件探查器）

重播到断点

  1. 单击"文件"菜单，指向"打开"子菜单，然后单击"跟踪文件"或"跟踪表"命令。

  2. 如果选择重播跟踪表，则必须输入连接信息。在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法，并在"源表"对话框中指定保存表的数据库。

  3. 除非已经选择了跟踪表，否则选择要打开的跟踪文件。

  4. 在跟踪窗口中，单击跟踪事件。

  5. 在"重播"菜单上，单击"切换断点"命令。

  6. 在"重播"菜单上，单击"开始"命令。

  7. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  8. 在"重播 SQL Server"对话框中，更改任何必要的设置，然后单击"开始"按钮。

请参见

用 SQL 事件探查器进行监视


如何重播到游标（SQL 事件探查器）

重播到游标

  1. 单击"文件"菜单，指向"打开"，然后单击"跟踪文件"或"跟踪表"命令。

  2. 如果选择重播跟踪表，则必须输入连接信息。在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法，并在"源表"对话框中指定保存表的数据库。

  3. 除非已经选择了跟踪表，否则选择要打开的跟踪文件。

  4. 在跟踪窗口中，单击事件。

  5. 在"重播"菜单上，单击"运行到游标处"命令。

  6. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  7. 在"重播 SQL Server"对话框中，更改任何必要的设置，然后单击"开始"按钮。

请参见

用 SQL 事件探查器进行监视


如何重播 SQL 脚本（SQL 事件探查器）

重播 SQL 脚本

  1. 单击"文件"菜单，指向"打开"子菜单，然后单击"SQL 脚本"命令。

  2. 选择要打开的 Transact-SQL 脚本文件。

  3. 在"重播"菜单上，单击"开始"命令。

  4. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  5. 在"重播 SQL Server"对话框中，更改任何必要的设置，然后单击"开始"按钮。

请参见

用 SQL 事件探查器进行监视


如何修改筛选（SQL 事件探查器）

修改筛选

  1. 在"文件"菜单上，指向"打开"子菜单，然后单击"跟踪模板"命令。

  2. 选择要打开的跟踪模板。

  3. 在"跟踪模板属性"对话框中，单击"筛选"选项卡。

  4. 在"跟踪事件准则"列表中，单击一种准则。

  5. 在准则下显示的字段中输入一个值。

请参见

用 SQL 事件探查器进行监视


如何设置跟踪文件的最大文件大小（SQL 事件探查器）

设置跟踪文件的最大文件大小

  1. 在"文件"菜单上，指向"新建"子菜单，然后单击"跟踪"命令。

  2. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 在"跟踪属性"对话框中，执行下列操作：
    • 在"跟踪名"框中键入跟踪的名称。

    • 在"模板名"列表中，选择跟踪模板。
  4. 选择"保存到文件"复选框，并指定存储跟踪信息的文件。

  5. 在"设置最大文件大小 (MB)"复选框中，指定跟踪的最大文件大小。默认情况下启用文件翻转。

    文件大小达到此最大值时，就不再记录跟踪事件。

请参见

用 SQL 事件探查器进行监视


如何设置跟踪表的最大表大小（SQL 事件探查器）

设置跟踪表的最大表大小

  1. 在"文件"菜单上，指向"新建"子菜单，然后单击"跟踪"命令。

  2. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 在"跟踪属性"对话框中，在"跟踪名"框中键入跟踪的名称。

  4. 选择"保存到表"复选框，并指定存储跟踪信息的表。

    将提示您连接到希望跟踪存储到的服务器。

  5. 在"目的表"对话框中的"数据库"列表中，选择跟踪的数据库，然后在"表"框中键入或选择表名。

  6. 选择"设置最大行数（以千为单位）"复选框，并指定跟踪表的最大行数。

    表中的行数超过此最大值时，就不再记录跟踪事件。

请参见

用 SQL 事件探查器进行监视


如何设置跟踪的即时开始时间（SQL 事件探查器）

设置跟踪的即时开始时间

  1. 在"工具"菜单上，单击"选项"命令。

  2. 选择"进行连接后立即启动跟踪"复选框。

请参见

用 SQL 事件探查器进行监视


如何设置跟踪的开始时间筛选（SQL 事件探查器）

设置跟踪的开始时间筛选

  1. 在"文件"菜单上，指向"新建"子菜单，然后单击"跟踪"命令。

  2. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 在"跟踪属性"对话框中，执行下列操作：
    • 在"跟踪名"框中键入跟踪的名称。

    • 在"模板名"列表中，选择跟踪模板。

    • 为跟踪结果指定保存目的位置。（可选）
  4. 在"筛选"选项卡的"跟踪事件准则"框中，展开"开始时间"。

  5. 展开"大于"或"小于"，然后在准则下面出现的字段中输入时间值。

请参见

用 SQL 事件探查器进行监视


如何设置跟踪的结束时间筛选（SQL 事件探查器）

设置跟踪的结束时间筛选

  1. 在"文件"菜单上，指向"新建"子菜单，然后单击"跟踪"命令。

  2. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 在"跟踪属性"对话框中，执行下列操作：
    • 在"跟踪名"框中键入跟踪的名称。

    • 在"模板名"列表中，选择跟踪模板。

    • 为跟踪结果指定保存目的位置。（可选）
  4. 在"筛选"选项卡的"跟踪事件准则"框中，展开"结束时间"选项。

  5. 展开"大于"或"小于"，然后在准则下面出现的字段中输入时间值。

请参见

用 SQL 事件探查器进行监视


如何在跟踪中筛选系统 ID（SQL 事件探查器）

在跟踪中筛选系统 ID

  1. 在"文件"菜单上，指向"新建"子菜单，然后单击"跟踪"命令。

  2. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 在"跟踪属性"对话框中，执行下列操作：
    • 在"跟踪名"框中，键入跟踪的名称。

    • 在"模板名"列表中，选择跟踪模板。

    • 为跟踪结果指定保存目的位置。（可选）
  4. 在"筛选"选项卡的"跟踪事件准则"框中，展开"SPID"。

  5. 展开"等于"、"不等于"、"大于等于"或"小于等于"，然后在准则下面出现的字段中输入值。

请参见

用 SQL 事件探查器进行监视


如何创建跟踪模板（SQL 事件探查器）

创建跟踪模板

  1. 在"文件"菜单上，指向"新建"子菜单，然后单击"跟踪模板"命令。

  2. 单击"事件"、"数据列"或"筛选"选项卡上的选项以选择模板属性。

  3. 单击"另存为"命名并保存模板。

请参见

如何从正在运行的跟踪导出模板

如何从跟踪文件或跟踪表导出模板

用 SQL 事件探查器进行监视


如何设置全局跟踪选项（SQL 事件探查器）

设置全局跟踪选项

  1. 在"工具"菜单上，单击"选项"命令。

  2. 从"模板名"列表中，选择默认的跟踪模板。

  3. 选择"进行连接后立即启动跟踪"复选框。（可选）

  4. 单击"显示"选项卡，然后从"字体名称"列表中选择 SQL 事件探查器用来显示跟踪的字体。

  5. 在"字体大小"列表中，键入或选择 6 到 24 之间的一个数。

请参见

用 SQL 事件探查器进行监视


如何在跟踪时查找值或数据列（SQL 事件探查器）

在跟踪时查找值或数据列

  1. 单击"文件"菜单并指向"新建"子菜单然后单击"跟踪"命令以创建一个跟踪。

  2. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 若要在跟踪窗口中显示数据，请运行 SQL 查询分析器，然后再次单击 SQL 事件探查器中的跟踪窗口。

  4. 在"编辑"菜单中单击"查找"命令。

  5. 在"查找"对话框中，输入搜索值或指定数据列。

  6. 单击"查找上一个"按钮。

    即从跟踪的起始位置开始搜索。

请参见

用 SQL 事件探查器进行监视


如何启动带有当前模板的新跟踪（SQL 事件探查器）

启动带有当前模板的新跟踪

  1. 在"文件"菜单上，指向"新建"子菜单，然后单击"跟踪"命令。

  2. 在"连接到 SQL Server"对话框中，选择要跟踪的服务器和连接方法。

  3. 在"跟踪属性"对话框中，执行下列操作：
    • 在"跟踪名"框中，输入新跟踪的名称。

    • 在"模板名"列表中，选择与当前运行的跟踪相同的模板。

请参见

用 SQL 事件探查器进行监视


如何从正在运行的跟踪导出模板（SQL 事件探查器）

从正在运行的跟踪导出模板

  1. 在"文件"菜单上，指向"新建"子菜单，然后单击"跟踪"命令。

  2. 在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 在"跟踪属性"对话框中，执行下列操作：
    • 在"跟踪名"框中，输入新跟踪的名称。

    • 在"模板名"列表中选择一个模板。
  4. 通过添加或删除事件、列或筛选来修改模板，然后单击"运行"按钮开始跟踪。

  5. 在"文件"菜单上，指向"另存为"子菜单，然后单击"跟踪模板"命令。

  6. 键入名称并保存模板文件。

请参见

用 SQL 事件探查器进行监视


如何从跟踪文件或跟踪表导出模板（SQL 事件探查器）

从跟踪文件或跟踪表导出模板

  1. 在"文件"菜单上，指向"打开"子菜单，然后单击"跟踪文件"或"跟踪表"命令。

  2. 如果选择重播跟踪表，则必须输入连接信息。在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法，并在"源表"对话框中指定保存表的数据库。

  3. 除非已经选定要打开的跟踪表，否则选择要打开的跟踪文件。

  4. 在"文件"菜单上，指向"另存为"子菜单，然后单击"跟踪模板"命令。

  5. 键入名称并保存模板文件。

请参见

用 SQL 事件探查器进行监视


如何将模板、跟踪文件或跟踪表保存到 SQL 脚本（SQL 事件探查器）

将模板、跟踪文件或跟踪表保存到 SQL 脚本

  1. 在"文件"菜单上，指向"打开"子菜单，然后单击"跟踪模板"、"跟踪文件"或"跟踪表"命令。

  2. 如果选择保存跟踪表，则必须输入连接信息。在"连接到 SQL Server"对话框中，选择要连接的服务器和连接方法。

  3. 从"打开"对话框中选择要保存的跟踪模板、跟踪文件或跟踪表。

  4. 在"文件"菜单上，指向"另存为"子菜单，然后单击"SQL 脚本"命令。

请参见

用 SQL 事件探查器进行监视


如何为正在运行的跟踪创建 SQL 脚本（SQL 事件探查器）

为正在运行的跟踪创建 SQL 脚本

  1. 创建并运行一个新跟踪，或是创建或打开一个跟踪模板。

  2. 在"文件"菜单上，指向"脚本跟踪"子菜单，然后单击"用于 SQL Server 2000"或"用于 SQL Server 7.0"命令，具体取决于将要跟踪的服务器。

请参见

用 SQL 事件探查器进行监视


创建和维护数据库

Microsoft® SQL Server™ 2000 数据库结构设计包括创建和维护许多相关的组件。

数据库组件 | 描述
数据库 | 包含用于表示、管理和访问数据的各种对象。
表 | 存储数据行，并且定义多个表之间的关系。
索引 | 优化对表中数据的访问速度。
视图 | 提供查看一个或多个表中数据的另一种方法。
存储过程 | 用 Transact-SQL 程序将服务器上的业务规则、任务和进程集中在一起。
触发器 | 用特殊类型的存储过程将服务器上的业务规则、任务和进程集中在一起。只有表中的数据被修改时才执行这些存储过程。

要创建为业务需求服务的数据库，需要对如何设计、创建和维护数据库有所了解，以确保数据库工作在最佳状态。


数据库

Microsoft® SQL Server™ 2000 中的数据库由表的集合组成。表中包含数据和其它对象，例如：视图、索引、存储过程和触发器等，通过定义这些对象可以支持对数据执行的各种操作。在创建数据库对象之前，您应先创建数据库，并且了解如何更改数据库的设置和配置。所包括的任务如展开或收缩数据库，或指定用于创建数据库的文件等。

请参见

数据库


如何创建数据库（企业管理器）

创建数据库

  1. 展开服务器组，然后展开服务器。

  2. 右击"数据库"，然后单击"新建数据库"命令。

  3. 键入新数据库的名称。

    用指定的数据库名作为前缀创建主数据库和事务日志文件，例如：newdb_Data.mdf 和 newwdb_Log.ldf。数据库和事务日志文件的初始大小与为 model 数据库指定的默认大小相同。主文件中包含数据库的系统表。

  4. 要更改新建主数据库文件的默认值，单击"常规"选项卡。若要更改新建事务日志文件的默认值，单击"事务日志"选项卡。

  5. 要更改"文件名"、"位置"、"初始大小 （MB）"和"文件组"（不适用于事务日志）等列的默认值，单击要更改的适当单元格，再键入新值。

  6. 要指定文件如何增长，请从以下选项中选择：
    • 当需要更多的数据空间时，若要允许当前选定的文件增长，选择"文件自动增长"命令。

    • 要指定文件按固定步长增长，选择"按兆字节"命令并指定一个值。

    • 若要指定文件按当前大小的百分比增长，选择"按百分比"命令，并且指定一个值。
  7. 若要指定文件大小的限制，请从以下选项中选择：
    • 若要允许文件按需求增长，选择"文件增长不受限制"命令。

    • 若要指定允许文件增长到的最大值，选择"将文件增长限制为 (MB)"命令。

说明 数据库大小的最大值由可用磁盘空间量决定，许可限制则由所使用的 Microsoft® SQL Server™ 版本决定。

请参见

创建数据库

创建文件组


如何用创建数据库向导创建数据库（企业管理器）

用创建数据库向导创建数据库

  1. 展开服务器组，再展开要创建数据库的服务器。

  2. 在"工具"菜单上单击"向导"命令。

  3. 展开"数据库"文件夹。

  4. 双击"创建数据库向导"。

  5. 完成向导中的步骤。

请参见

创建数据库


如何增加数据库的大小（企业管理器）

增加数据库的大小

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击要增加大小的数据库，然后单击"属性"命令。

  3. 若要增加数据空间，单击"常规"选项卡。若要增加事务日志空间，单击"事务日志"选项卡。

  4. 若要添加新文件，单击下一个空行，在"文件名"列中输入将容纳附加空间的文件名。

    文件位置是自动生成的，数据库文件名的后缀名为 .ndf，事务日志文件名的后缀为 .ldf。

  5. 若要更改"文件名"、"位置"、"分配的空间 (MB)"和"文件组"（不适用于事务日志）等列的默认值，单击要更改的单元格，再输入新值。

    对于现有的文件，只能更改"分配的空间 （MB）"值，并且新值必须大于现有的值。

  6. 要指定文件如何增长，请从以下选项中选择：
    • 当需要更多的数据空间时，若要允许当前选定的文件增长，选择"文件自动增长"命令。

    • 要指定文件按固定步长增长，选择"按兆字节"命令并指定一个值。

    • 若要指定文件按当前大小的百分比增长，选择"按百分比"命令，并且指定一个值。
  7. 若要指定文件大小的限制，请从以下选项中选择：
    • 若要允许文件按需求增长，选择"文件增长不受限制"命令。

    • 若要指定允许文件增长到的最大值，选择"将文件增长限制为 (MB)"命令。

说明 数据库大小的最大值是由可用磁盘空间量决定，许可限制由正在使用的 SQL Server 版本决定。

请参见

添加和删除数据和事务日志文件

创建文件组

扩充数据库


如何收缩数据库（企业管理器）

收缩数据库

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击要收缩的数据库，指向"所有任务"，然后单击"收缩数据库"命令。

  3. 要指定数据库的收缩量，请从以下选项中选择：
    • 在"收缩后文件中的最大可用空间"中输入收缩后数据库中剩余的可用空间量。以"数据库大小，可用空间"值作为依据。

    • 选择"在收缩前将页移到文件起始位置"，使释放的文件空间保留在数据库文件中，并使包含数据的页移到数据库文件的起始位置。
  4. 单击"调度"命令创建或更改自动收缩数据库的频率和时间。

  5. 如果要收缩个别的数据库文件，请单击"收缩文件"。

说明 不能将数据库的大小收缩到小于 model 数据库的大小。

请参见

收缩数据库


如何从数据库中删除数据或日志文件（企业管理器）

从数据库中删除数据或日志文件

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击要从中删除数据或日志文件的数据库，然后单击"属性"命令。

  3. 若要删除数据文件，单击"常规"选项卡。若要删除日志文件，单击"事务日志"选项卡。

  4. 在"文件名"列中，单击要删除的文件名旁边的箭头，再按 DELETE 键。文件名旁出现十字光标，表明将删除此文件。

说明 只能删除空文件。从数据库中删除文件之前，应先删除文件中的所有对象，并收缩该数据库。

请参见

添加和删除数据和日志文件


如何更改数据库的配置设置（企业管理器）

更改数据库的配置设置

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击要更改的数据库，然后单击"属性"命令。

  3. 单击"选项"选项卡，再选择或清除要更改的配置设置。

请参见

嵌套触发器

重命名数据库

设置数据库选项

收缩数据库


如何查看数据库（企业管理器）

查看数据库

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开要查看的数据库。

  3. 单击"常规"、"表和索引"或"分配的空间"命令，以查看关于数据库的更多信息。

请参见

查看数据库


如何查看数据库的设置（企业管理器）

查看数据库的设置

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击要查看的数据库，然后单击"属性"命令。

  3. 单击"选项"选项卡。

请参见

查看数据库


如何查看服务器上的数据库列表（企业管理器）

查看服务器上的数据库列表

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，这将列出服务器上的所有数据库。

请参见

查看数据库


如何显示数据库的数据和日志空间信息（企业管理器）

显示数据库的数据和日志空间信息

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后单击要查看的数据库。

  3. 在详细信息窗格中，单击"分配的空间"，以查看数据库空间信息。

请参见

显示数据库和事务日志空间

用 Transact-SQL 语句监视


如何生成脚本（企业管理器）

生成脚本

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击要编写脚本的数据库，指向"所有任务"，然后单击"生成 SQL 脚本"命令。

  3. 在"常规"选项卡中，选择要编写脚本的数据库对象。默认情况下，将编写数据库中所有对象的脚本。

  4. 在"设置格式"选项卡上，选择脚本格式选项：
    • 选择"为每个对象生成 CREATE <对象> 命令"命令，以用现有的定义显式创建要生成其脚本的对象。这是默认选项。

    • 选择"为每个对象生成 DROP <对象> 命令"命令，以将 DROP 语句添加到每个要为其编写脚本的对象脚本中。这是默认选项。

      注意 执行脚本时，当数据库中任何现有对象与脚本中列出的对象同名时，将首先删除数据库中的现有对象。

    • 选择"生成全部相关对象的脚本"命令，这样，对于创建脚本中所列出的对象时需要的所有数据库中的对象，如果尚未选择，都将自动包括进来。

    • 选择"在脚本文件中包含说明性的页头"命令，以在文件中为脚本中所列出的每个对象添加注释。
  5. 在"选项"选项卡中，选择与安全有关、与表有关和与脚本文件有关的选项。

  6. 在"常规"选项卡上单击"预览"，查看所生成脚本的预览。

请参见

编写数据库文档和脚本


如何启动数据库维护计划向导（企业管理器）

启动数据库维护计划向导

  1. 展开服务器组，然后展开分发服务器。

  2. 在"工具"菜单上单击"数据库维护计划器"命令。

  3. 完成向导中的步骤。

请参见

数据库维护计划向导


如何删除数据库（企业管理器）

删除数据库

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，右击要删除的数据库，然后单击"删除"命令。

  3. 确认删除。

请参见

删除数据库


如何附加和分离数据库（企业管理器）

附加数据库

  1. 展开服务器组，然后展开服务器。

  2. 右击"数据库"，然后选择"所有任务"/"附加数据库"。

  3. 输入要附加的数据库的 MDF（master 数据文件）名称。如果不确定文件位于何处，单击浏览（"..."）搜索。最多可以指定 16 个文件名。有关更多信息，请参阅 sp_attach_db。

  4. 若要确保指定的 MDF 文件正确，请单击"验证"。"原文件名"列列出了数据库中的所有文件（数据文件和日志文件）。"当前文件位置"列列出了文件的名称和路径。如果 Microsoft® SQL Server™ 找不到指定位置的文件，则附加操作将失败。可以对"当前文件位置"列进行编辑，并且文件的当前位置必须在该列中才能使附加操作得以进行。例如，如果在分离操作前改变了文件的默认位置，则必须指定当前位置才能使附加操作顺利进行。

  5. 在"附加为"框内，输入数据库的名称。数据库名称不能与任何现有数据库名称相匹配。

  6. 指定数据库的所有者。

  7. 单击"确定"按钮。新附加的数据库的数据库节点即创建在"数据库"文件夹中。

分离数据库

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹。

  3. 右击数据库，然后选择"所有任务"/"分离数据库"命令。该菜单只有在您是 sysadmin 固定服务器角色成员并且所连接的服务器是 SQL Server 2000 时才可用。无法分离 master、model 和 tempdb 数据库。

  4. 在"分离数据库"对话框中，检查数据库的状态。要成功地分离数据库，STATUS 应为：数据库已就绪，可以分离。或者可以选择在分离操作前更新统计信息。

  5. 若要终止任何现有的数据库连接，请单击"清除"。

  6. 单击"确定"按钮。已分离的数据库的数据库节点即从"数据库"文件夹中被删除。


如何创建用户定义的数据类型（企业管理器）

创建用户定义的数据类型

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，再展开要在其中创建用户定义的数据类型的数据库。

  3. 右击"用户定义数据类型"，然后单击"新建用户定义数据类型"命令。

  4. 输入新建数据类型的名称。

  5. 在"数据类型"列表中，选择基数据类型。

  6. 如"长度"处于活动状态，若要更改此数据类型可存储的最大数据长度，请键入另外的值。长度可变的数据类型有：binary、char、nchar、nvarchar、varbinary 和 varchar。

  7. 若要允许此数据类型接受空值，请选择"允许空值"命令。

  8. 在"规则"和"默认值"列表中选择一个规则或默认值（若有）以将其绑定到用户定义数据类型上。（可选）

请参见

创建用户定义的数据类型

sp_addtype

使用数据类型


如何删除用户定义的数据类型（企业管理器）

使用方法

如何删除用户定义数据类型（企业管理器）

删除用户定义数据类型

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开数据库，然后单击"用户定义数据类型"命令。

  3. 在详细信息窗格中右击要删除的数据类型，然后单击"删除"。

  4. 要查看删除此数据类型对数据库的影响，单击"显示相关性"命令。

  5. 在"除去对象"对话框中，单击"全部除去"按钮。

请参见

创建用户定义的数据库类型

sp_droptype

使用数据类型


如何创建自反关系（企业管理器）

创建自反关系

  1. 打开数据库关系图。

  2. 单击数据库中要与其它列相关的列的行选择器。

  3. 当指针定位到行选择器上时，将指针拖动到表外直到出现联接线。

  4. 将联接线拖回到选定的表。

  5. 松开鼠标按钮。

    "创建关系"对话框出现，并试图对主键列和刚拖进新行的无键列进行匹配。

  6. 确认要相关的列显示在"主键表"和"外键表"列表中。

请参见

绘制自反关系


如何在表之间创建多对多关系（企业管理器）

在表间创建多对多关系

  1. 打开数据库关系图。

  2. 添加要创建多对多关系的表。

  3. 通过在数据库关系图中右击，然后单击"新建表"可创建第三个表。

    该表将成为连接表。

  4. 在"选择名称"对话框中，输入该表的名称。

    例如：titles 表和 authors 表之间的连接表可以叫做 titleauthors。

  5. 将主键列从其它两个相关表分别复制到连接表。

    与任何其它表一样，在连接表中也可以添加其它列。

  6. 在连接表中，设置主键以包括其它两个表中的主键列。

  7. 分别在两个主表和连接表间定义一对多关系。

请参见

将表添加到关系图

将列从一个表复制到另一个表

将多对多关系映射到数据库关系图


如何删除关系（企业管理器）

删除关系

  1. 打开数据库关系图。

  2. 右击要从关系图中删除的关系线，然后单击"删除数据库中的关系"命令。

请参见

删除关系


如何创建 DEFAULT 对象（企业管理器）

创建 DEFAULT 对象

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，再展开要在其中创建 DEFAULT 对象的数据库。

  3. 右击"默认"，然后单击"新建默认"命令。

  4. 在"名称"框中输入该 DEFAULT 对象的名称。

  5. 在"值"框中输入该 DEFAULT 对象的值。值可以是常量、表达式或变量。

  6. 可选：
    • 单击"绑定 UDTS"，将新的 DEFAULT 对象绑定到用户定义数据类型上。

    • 单击"绑定列"，将此 DEFAULT 对象绑定到表中现有的列上。

请参见

创建和修改 DEFAULT 定义


如何删除 DEFAULT 对象（企业管理器）

删除 DEFAULT 对象

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，再展开 DEFAULT 对象所属的数据库，然后单击"默认"。

  3. 在详细信息窗格中右击要删除的 DEFAULT 对象，然后单击"删除"命令。

  4. 要查看删除此表对数据库的影响，单击"显示相关性"按钮。

  5. 单击"全部除去"按钮。

请参见

创建和修改 DEFAULT 定义


如何查看表的相关性（企业管理器）

查看表的相关性

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该表所属的数据库，然后单击"表"文件夹。

  3. 在详细信息窗格中右击表，指向"所有任务"，然后单击"显示相关性"命令。

请参见

查看表


索引

要创建通过提高查询速度来改善数据库应用程序性能的有效的索引，需要了解如何在数据库中创建和维护表中的索引。

请参见

索引


如何用索引分析分析查询（查询分析器）

启动索引优化向导

  1. 展开服务器组，再展开要在其中创建索引的服务器。

  2. 在"工具"菜单上单击"向导"命令。

  3. 展开"管理"文件夹。

  4. 双击"索引优化向导"命令。

  5. 完成向导中的步骤。

请参见

索引优化向导


如何用索引优化向导分析查询（查询分析器）

用索引优化向导分析查询

  1. 输入要在查询窗格中分析的 Transact-SQL 查询或批处理语句。

  2. 在"查询"菜单上，单击"索引优化向导"。

请参见

索引优化向导


如何用创建索引向导创建索引（企业管理器）

用创建索引向导创建索引

  1. 展开服务器组，再展开要在其中创建索引的服务器。

  2. 在"工具"菜单上单击"向导"命令。

  3. 展开"数据库"文件夹。

  4. 双击"创建索引向导"。

  5. 完成向导中的步骤。

请参见

创建索引


如何查看数据库中的全部索引（企业管理器）

如何查看数据库中的全部索引

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开要查看的数据库。

  3. 单击"表和索引"，查看有关数据库中的索引的信息。

请参见

查看索引


视图

通过创建、修改和维护视图，可以自定义每位用户从不同的角度使用数据库。

请参见

视图


如何用创建视图向导创建视图（企业管理器）

用创建视图向导创建视图

  1. 展开服务器组，再展开要在其中创建视图的服务器。

  2. 在"工具"菜单上单击"向导"命令。

  3. 展开"数据库"文件夹。

  4. 双击"创建视图向导"。

  5. 完成向导中的步骤。

请参见

创建视图


如何重命名视图（企业管理器）

重命名视图

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该视图所属的数据库，然后单击"视图"。

  3. 在详细信息窗格中，右击视图，然后单击"重命名"命令。

  4. 输入视图的新名称。

  5. 确认新名称。

请参见

修改和重命名视图


如何修改视图（企业管理器）

修改视图

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该视图所属的数据库，然后单击"视图"。

  3. 在详细信息窗格中，右击视图，然后单击"设计视图"命令。

  4. 若要在视图中添加附加表或视图，右击关系图窗格，然后单击"添加表"命令。
    • 在"表"或"视图"选项卡中，单击要添加到新视图中的表或视图，然后单击"添加"按钮。对每一个要添加到新视图中的表或视图重复以上操作。
  5. 若要从视图中删除整个表或视图，在关系图窗格中，右击表的标题栏，然后单击"删除"按钮。

  6. 在网格窗格的"列"框中，选择要在视图中引用的列。

  7. 若要在视图的结果集中显示此列，选择"输出"命令。

  8. 要按列分组，右击此列，然后单击"分组依据"命令。

  9. 在"准则"列中，输入指定要检索行的准则。该准则决定了 WHERE 子句。若指定了"分组依据"，则该准则决定 HAVING 子句。

  10. 在"或"列中，输入任何指定要检索行的附加准则。

  11. 右击网格窗格的任意处，然后单击"属性"命令。

  12. 选择：（可选）
    • "输出所有列"命令，在视图的结果集中显示所有列。

    • "DISTINCT 值"，以筛选出结果集中的重复值。

    • "加密视图"命令，加密视图的定义。
  13. 在"顶层"中，输入要在结果集中返回的行数。在行号之后输入词 PERCENT，以按行数的百分比将行返回到结果集中。（可选）

  14. 右击关系图窗格的任意处，然后单击"运行"命令（查看结果集），或"保存"命令（保存视图）。

请参见

修改和重命名视图


如何获取关于视图的信息（企业管理器）

获取关于视图的信息

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该视图所属的数据库，然后单击"视图"。

  3. 在详细信息窗格中，右击视图，然后单击"属性"命令。

请参见

获取有关视图的信息


如何显示视图的相关性（企业管理器）

显示视图的相关性

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该视图所属的数据库，然后单击"视图"。

  3. 在详细信息窗格中，右击视图，指向"所有任务"菜单，然后单击"显示相关性"命令。

请参见

获取有关视图的信息


如何删除视图（企业管理器）

删除视图

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该视图所属的数据库，然后单击"视图"。

  3. 在详细信息窗格中，右击视图，然后单击"删除"命令。

  4. 要查看删除此视图对数据库的影响，单击"显示相关性"命令。

  5. 单击"全部除去"按钮。

请参见

删除视图


存储过程

通过创建、修改和使用存储过程，可以简化您的业务应用程序，并且改善应用程序和数据库性能。

请参见

存储过程


如何创建存储过程（企业管理器）

创建存储过程

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，再展开要在其中创建过程的数据库。

  3. 右击"存储过程"，然后单击"新建存储过程"命令。

  4. 输入存储过程的文本。按 TAB 键可以缩进存储过程的文本。按下 CTRL+TAB 键或单击合适的按钮来退出文本框。

  5. 若要检查语法，单击"检查语法"命令。

  6. 若要设置权限，单击"权限"命令。

请参见

创建存储过程


如何用创建存储过程向导创建存储过程（企业管理器）

用创建存储过程向导创建存储过程

  1. 展开一个服务器组，再展开要在其中创建视图的服务器。

  2. 在"工具"菜单上单击"向导"命令。

  3. 展开"数据库"文件夹。

  4. 双击"创建存储过程向导"命令。

  5. 完成向导中的步骤。

请参见

创建存储过程


如何添加扩展存储过程（企业管理器）

添加扩展存储过程

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，再展开 master 数据库。

  3. 右击"扩展存储过程"，然后单击"新建扩展存储过程"命令。

  4. 在"名称"框中输入扩展存储过程的名称。

  5. 在"路径"中，输入包含此扩展存储过程的动态链接库的路径。单击（"..."）按钮，查找包含此扩展存储过程的 DLL。（可选）

请参见

创建存储过程

扩展存储过程


如何修改存储过程（企业管理器）

修改存储过程

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，再展开过程所属的数据库，然后单击"存储过程"文件夹。

  3. 在详细信息窗格中，右击存储过程，然后单击"属性"命令。

  4. 在"文本"框中，按需要更改存储过程的文本。按 CTRL+TAB 键缩进 SQL Server 企业管理器存储过程的文本。

  5. 若要检查语法，请单击"检查语法"命令。

  6. 若要更改权限，单击"权限"命令。

请参见

修改和重命名存储过程


如何重命名存储过程（企业管理器）

重命名存储过程

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，再展开过程所属的数据库，然后单击"存储过程"文件夹。

  3. 在详细信息窗格中，右击存储过程，然后单击"重命名"命令。

  4. 输入存储过程的新名称。

  5. 确认新名称。

请参见

修改和重命名存储过程


如何查看存储过程的定义（企业管理器）

查看存储过程的定义

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开存储过程所属的数据库，然后单击"存储过程"文件夹。

  3. 在详细信息窗格中，右击存储过程，然后单击"属性"命令。

请参见

查看存储过程


如何查看存储过程的相关性（企业管理器）

查看存储过程的相关性

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开存储过程所属的数据库，然后单击"存储过程"文件夹。

  3. 在详细信息窗格中，右击存储过程，指向"所有任务"菜单，然后单击"显示相关性"命令。

请参见

查看存储过程


如何查看关于扩展存储过程的信息（企业管理器）

查看关于扩展存储过程的信息

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开 master 数据库，然后单击"扩展存储过程"文件夹。

  3. 在详细信息窗格中，右击扩展存储过程，然后单击"属性"命令。

  4. 单击（"..."）按钮，查找包含此扩展存储过程的 DLL。（可选）

  5. 单击"权限"，查看或设置此扩展存储过程的权限。（可选）

请参见

查看存储过程


如何删除存储过程（企业管理器）

删除存储过程

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开存储过程所属的数据库，然后单击"存储过程"文件夹。

  3. 在详细信息窗格中右击要删除的存储过程，然后单击"删除"命令。

  4. 若要查看删除此存储过程对数据库的影响，单击"显示相关性"命令。

  5. 单击"全部除去"按钮。

请参见

查看存储过程


如何删除扩展存储过程（企业管理器）

删除扩展存储过程

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开 master 数据库，然后单击"扩展存储过程"文件夹。

  3. 在详细信息窗格中右击要删除的扩展存储过程，然后单击"删除"命令。

  4. 要查看删除此扩展存储过程对数据库的影响，单击"显示相关性"命令。

  5. 单击"全部除去"按钮。

请参见

删除存储过程


触发器

通过了解如何创建、修改和维护触发器，可用触发器：

  • 通过数据库中相关的表层叠更改。

  • 禁止或回滚违反引用完整性的更改，从而取消所尝试的数据修改事务。

  • 实现比 CHECK 约束定义的限制更为复杂的限制。

  • 找到数据修改前后表状态的差异，并基于此差异采取行动。

请参见

用触发器强制执行业务规则


如何创建触发器（企业管理器）

创建触发器

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开含触发器的表所属的数据库，然后单击"表"文件夹。

  3. 在详细信息窗格中，右击将在其上创建触发器的表，指向"所有任务"菜单，然后单击"管理触发器"命令。

  4. 在"名称"中，单击 <新建>。

  5. 在"文本"框中输入触发器的文本。用 CTRL-TAB 键来缩进触发器的文本。

  6. 若要检查语法，单击"检查语法"命令。

请参见

创建触发器


如何修改触发器（企业管理器）

修改触发器

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开含触发器的表所属的数据库，然后单击"表"文件夹。

  3. 在详细信息窗格中，右击触发器所在的表，指向"所有任务"菜单，然后单击"管理触发器"命令。

  4. 在"名称"框中选择触发器的名称。

  5. 按需要在"文本"字段中更改触发器的文本。按 CTRL+TAB 缩进 SQL Server 企业管理器触发器的文本。

  6. 若要检查触发器的语法，单击"检查语法"命令。

请参见

修改和重命名触发器


如何查看触发器（企业管理器）

查看触发器

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开含触发器的表所属的数据库，然后单击"表"文件夹。

  3. 在详细信息窗格中，右击触发器所在的表，指向"所有任务"菜单，然后单击"管理触发器"命令。

请参见

查看触发器


如何查看触发器的相关性（企业管理器）

查看触发器的相关性

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开触发器所属的数据库，然后单击"表"文件夹。

  3. 在详细信息窗格中，右击触发器所属的表，指向"所有任务"菜单，然后单击"显示相关性"命令。

  4. 在"对象"中，单击要查看其相关性的触发器。

请参见

修改和重命名触发器

查看触发器


如何删除触发器（企业管理器）

删除触发器

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开含触发器的表所属的数据库，然后单击"表"文件夹。

  3. 在详细信息窗格中，右击触发器所在的表，指向"所有任务"菜单，然后单击"管理触发器"命令。

  4. 在"名称"框中单击要删除的触发器的名称。

  5. 单击"删除"按钮。

  6. 确认删除。

请参见

删除触发器


全文索引

对 Microsoft® SQL Server™ 2000 数据的全文支持需要两个任务：启用数据库以允许能对字符数据进行查询，并能创建和维护基础索引以简化这些查询。


如何启用数据库以进行全文索引（企业管理器）

启用数据库以进行全文索引

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后单击要启用的数据库。

  3. 在"工具"菜单上单击"全文索引"命令。

  4. 完成全文索引向导的各步骤。

请参见

全文索引


如何启用表以进行全文索引（企业管理器）

启用表以进行全文索引

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该表所属的数据库，然后单击"表"文件夹。

  3. 在"详细信息"窗格内右击相应的表，再单击"全文索引表"菜单，然后单击"在表上定义全文索引"命令。

  4. 完成全文索引向导的各步骤。

请参见

全文索引


如何启用列以进行全文索引（企业管理器）

启用列以进行全文索引

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该表所属的数据库，然后单击"表"文件夹。

  3. 在"详细信息"窗格内右击相应的表，再单击"全文索引表"菜单，然后单击"在表上定义全文索引"命令。

  4. 完成全文索引向导的各步骤以启用特定的列。

请参见

全文索引


如何编辑表中的全文索引（企业管理器）

编辑表中的全文索引

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该表所属的数据库，然后单击"表"文件夹。

  3. 在"详细信息"窗格内右击相应的表，再单击"全文索引表"菜单，然后单击"编辑全文索引"命令。

  4. 在全文索引向导中进行更改。

请参见

全文索引


如何删除表中的全文索引（企业管理器）

删除表中的全文索引

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该表所属的数据库，然后单击"表"文件夹。

  3. 在"详细信息"窗格内右击相应的表，再单击"全文索引表"菜单，然后单击"删除全文索引"命令。

  4. 单击"是"按钮确认从表中删除全文索引。

请参见

全文索引


如何创建全文目录（企业管理器）

创建全文目录

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后右击要在其中创建全文目录的数据库。

  3. 单击"新建"子菜单，然后单击"新建全文目录"命令。

  4. 完成"新建全文目录"对话框。

请参见

全文索引


如何重建全文目录（企业管理器）

重建全文目录

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开含有要重建的全文目录的数据库。

  3. 单击"全文目录"，然后右击要重建的特定目录。

  4. 选择"重建目录"命令。

  5. 单击"是"按钮重建目录。

请参见

全文索引


如何在数据库中重建所有全文目录（企业管理器）

重建所有全文目录

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开含有要重建的目录的数据库。

  3. 右击"全文目录"，然后单击"重建全部目录"命令。

  4. 单击"是"按钮重建全部目录。

请参见

全文索引


如何启动与停止全文索引的完全填充或增量填充（企业管理器）

启动与停止全文索引的填充

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开含有要重建的全文目录的数据库。

  3. 单击"全文目录"，然后右击要填充的特定目录。

  4. 单击"启动完全填充"或"启动增量填充"。或者在适当时候单击"停止填充"按钮。

请参见

全文索引


如何检查全文目录的状态、表和调度（企业管理器）

检查全文目录的状态、表和调度

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开含有要复查的全文目录的数据库。

  3. 单击"全文目录"，然后右击要复查的特定目录。

  4. 单击"属性"命令，然后在适当的时候单击"状态"、"表"和"调度"选项卡。

请参见

全文索引

sp_fulltext_catalog


如何更改或创建全文目录的新调度（企业管理器）

更改或创建全文目录的新调度

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开含有要复查的全文目录的数据库。

  3. 单击"全文目录"，然后右击要复查的特定目录。

  4. 单击"调度"，修改调度或建立新的调度。

请参见

全文索引

sp_add_job

sp_add_jobschedule

sp_add_jobserver

sp_fulltext_catalog

sp_delete_job

sp_update_job


如何从数据库中删除全文目录（企业管理器）

删除全文目录

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开含有要重建的全文目录的数据库。

  3. 单击"全文目录"，然后右击要删除的特定目录，再单击"删除"命令。

  4. 单击"是"按钮删除该目录。

请参见

全文索引


如何删除数据库中的所有全文目录（企业管理器）

删除数据库中的所有全文目录

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开含有要删除的全文目录的数据库。

  3. 右击"全文目录"，然后单击"删除所有目录"命令。

  4. 单击"是"按钮确认删除这些目录。

请参见

全文索引


如何重新填充数据库的所有全文目录（企业管理器）

在数据库中重新填充所有全文目录

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，然后展开含有要重新填充的目录的数据库。

  3. 右击"全文目录"，然后单击"重新填充所有目录"命令。

  4. 单击"是"按钮重新填充所有目录。

请参见

全文索引


如何清理服务器上的全文目录（企业管理器）

清理服务器上的全文目录

  1. 展开服务器组，然后展开服务器。

  2. 展开"支持服务"文件夹，然后右击"全文检索"，再单击"清除目录"命令。

  3. 单击"是"按钮清理服务器上的所有全文目录。

请参见

全文索引


如何启动与停止用于全文支持的 Microsoft 搜索服务（企业管理器）

如果必要，可以以下列方法之一启动（和停止）全文服务：

  1. 展开服务器组，然后展开服务器。

  2. 展开"支持服务"文件夹，然后右击"全文检索"，再单击"启动"（或"停止"）命令。

  3. 另外，还可以通过下列方法启动和停止该服务：
    • 在 SQL Server 服务管理器中选择 Microsoft 搜索服务并单击启动或停止。

    • 从命令行键入"net start mssearch"（或"net stop mmsearch"）。

请参见

全文索引


访问和更改数据

SQL Server 企业管理器包括一个使用图形用户界面进行交互式设计查询的工具。查询可用于：

  • 视图中。

  • 数据转换服务 (DTS) 包中。

  • 显示 Microsoft® SQL Server™ 表中的数据。


如何访问数据转换服务中的查询设计器（企业管理器）

使用数据转换服务中的查询设计器

  1. 右击一个"执行 SQL 任务"对象，然后单击"属性"命令。

  2. 在"执行 SQL 属性"窗口中单击"生成查询"按钮。

查询设计器将打开，其中关系图窗格和 SQL 窗格可见。若要打开窗格，请参阅查询和视图设计器布局。

说明 若要生成查询，包中必须有有效的数据源连接。如果没有，则在试图访问查询设计器前必须创建连接。


优化数据库性能

优化数据库性能的目的是通过使网络流量、磁盘 I/O 和 CPU 时间最小化，而使每次查询的响应时间最短，同时使整个数据库服务器的吞吐量最大化。了解如何设计数据的逻辑结构和物理结构、如何优化查询以及如何配置 Microsoft® SQL Server™ 2000 和操作系统有助于优化数据库性能。


数据库设计

数据库的设计包括两个组成部分：逻辑设计和物理设计。在数据库应用程序的开发阶段，及早弄清如何正确设计数据库对建立企业要求的模型并充分利用硬件和软件功能非常重要。在开发周期后期，要更改这些组件十分困难。


如何将现有的表置于不同的文件组上（企业管理器）

在其它文件组上放置现有的表

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开该表所属的数据库，然后单击"表"文件夹。

  3. 在详细信息窗格中右击表，然后单击"设计表"命令。

  4. 右击任意列，然后单击"属性"命令。

  5. 在"表"选项卡的"表文件组"列表中，选择要在其中放置表的文件组。

  6. 在"文本文件组"列表中，选择要放置任意 text、image 和 ntext 列的文件组。（可选）

请参见

将表置于文件组上


如何将现有索引置于不同的文件组上（企业管理器）

在其它文件组上放置现有的索引

  1. 展开服务器组，然后展开服务器。

  2. 展开"数据库"文件夹，展开含索引的表所属的数据库，然后单击"表"文件夹。

  3. 在详细信息窗格中右击表，然后单击"设计表"命令。

  4. 右击任意列，然后单击"属性"命令。

  5. 在"已选索引"列表中的"索引/键"选项卡上，选择要移动的索引。

  6. 在"索引文件组"列表中，选择要放置该索引的文件组。

请参见

在文件组上放置索引


查询优化

查询优化包括监视和确定查询是否以及为何没有尽可能地优化运行，并采取措施解决所有问题。理解如何创建和更新列统计和索引可显著地改善查询性能。


如何创建统计（查询分析器）

创建统计

  1. 在"查询"菜单上单击"显示执行计划"命令。

  2. 执行查询窗格中的 Transact-SQL 脚本。

  3. 在结果窗格中单击"执行计划"选项卡。

  4. 右击表示需要创建统计的物理运算符的图标（表名用红色字体表示），然后单击"创建缺少的统计"按钮。将自动选择"图形执行计划"建议需要新统计的数据库、表和列。

  5. 在"统计名"文本框中输入统计的名称。（可选）

  6. 在"采样的数据量"中选择：（可选）
    • "默认"为让 Microsoft® SQL Server™ 自动决定要采样的行数。

    • "对所有数据采样"，让 SQL Server 对该表所有数据采样。

    • "采样数据的 %"并输入采样数据的百分比，以此为基础进行统计。
  7. 选择"不自动重新计算统计（不推荐使用）"选项，防止 SQL Server 在数据更新时自动更新统计。（可选）

  8. 单击"编辑 SQL"按钮，查看和编辑用于创建或更新统计的 Transact-SQL 语句。（可选）

请参见

使用 SQL 查询分析器以图形方式显示执行计划

统计信息


如何更新统计（查询分析器）

更新统计

  1. 在"查询"菜单上单击"显示执行计划"命令。

  2. 执行查询窗格中的 Transact-SQL 脚本。

  3. 在结果窗格中单击"执行计划"选项卡。

  4. 右击表示需要更新统计的物理运算符的图标，然后单击"管理统计"按钮。图形执行计划自动选择适当的数据库和表。

  5. 在"数据库"和"表"中单击要更新统计的不同数据库和表的名称。（可选）

  6. 单击"更新"按钮。

  7. 在"名称"中选择要更新的统计。

  8. 在"采样的数据量"中选择：（可选）
    • "默认"为让 Microsoft® SQL Server™ 自动决定要采样的行数。

    • "对所有数据采样"，让 SQL Server 对该表所有数据采样。

    • "采样数据的 %"并输入采样数据的百分比，以此为基础进行统计。

    • "采样行"并输入采样的行数，以此为基础进行统计。
  9. 在"更新统计选项"中选择：（可选）
    • "包括列"，更新列以及索引的统计。

    • "不自动重新计算统计（不推荐使用）"，防止 SQL Server 在更新数据时自动更新统计。
  10. 单击"编辑 SQL"按钮，查看和编辑用于创建或更新统计的 Transact-SQL 语句。（可选）

请参见

使用 SQL 查询分析器以图形方式显示执行计划

统计信息


如何删除统计（查询分析器）

删除统计

  1. 在"查询"菜单上单击"显示执行计划"命令。

  2. 执行查询窗格中的 Transact-SQL 脚本。

  3. 在结果窗格中单击"执行计划"选项卡。

  4. 右击代表表（其中包含需要删除的统计）的物理运算符图标，然后单击"管理统计"按钮。

  5. 在"数据库"和"表"中单击要删除统计的不同数据库和表的名称。（可选）

  6. 在"现有索引"中，单击要删除的统计名，然后单击"删除"按钮。

  7. 确认删除。

请参见

使用 SQL 查询分析器以图形方式显示执行计划

统计信息


如何新建索引（查询分析器）

创建新索引

  1. 在"查询"菜单上单击"显示执行计划"命令。

  2. 执行查询窗格中的 Transact-SQL 脚本。

  3. 在结果窗格中单击"执行计划"选项卡。

  4. 右击表示需要创建索引的物理运算符图标，然后单击"管理索引"按钮。图形执行计划自动选择适当的数据库和表。单击"新建"按钮。

  5. 在"索引名称"中，输入索引名。

  6. 在"列"中，选择要出现在索引中的列。选择一个以上的列可以创建组合索引。

  7. 选择一列，然后单击"上移"或"下移"以更改索引中列的顺序。（可选）

  8. 在"索引选项"中选择：（可选）
    • "唯一值"，创建唯一索引。

    • "聚集索引"，创建聚集索引。如果已存在一个聚集索引，则该选项不可用。

    • 当 INSERT 语句向索引中插入多个、非唯一键值时，"忽略重复值"可控制所发生的情况。有关详细信息，请参阅 CREATE INDEX。

    • "不重新计算统计（不推荐使用）"，指定在索引更新时不自动重新计算索引统计。

    • "文件组"，指定要创建索引的文件组。单击该文件组名。

    • "填充索引"，在索引各内部节点上留出空间。有关详细信息，请参阅 CREATE INDEX。

    • "除去现有索引"，在创建新索引之前将任何现有的同名索引删除。

    • "填充因子"，指定 SQL Server 在创建索引过程中，对各索引页的叶级所进行填充的程度。有关详细信息，请参阅 CREATE INDEX。
  9. 单击"编辑 SQL"以查看和编辑用于创建索引的 Transact-SQL 语句。（可选）

请参见

使用 SQL 查询分析器以图形方式显示执行计划

在文件组上放置索引


如何修改索引（查询分析器）

修改索引

  1. 在"查询"菜单上单击"显示执行计划"命令。

  2. 执行查询窗格中的 Transact-SQL 脚本。

  3. 在结果窗格中单击"执行计划"选项卡。

  4. 右击表示需要修改索引的物理运算符图标，然后单击"管理索引"按钮。将自动选择"图形执行计划"建议需要修改索引的数据库和表。

  5. 在"数据库"和"表"中选择不同数据库和表的名称。（可选）

  6. 在"现有索引"中，单击要修改的索引名，然后单击"编辑"按钮。

  7. 在"列"中，选择要出现在索引中的列。选择一个以上的列可以创建组合索引。

  8. 选择一列，然后单击"上移"或"下移"以更改索引中列的顺序。（可选）

  9. 在"索引选项"中选择：（可选）
    • "唯一值"，创建唯一索引。

    • "聚集索引"，创建聚集索引。如果已存在一个聚集索引，则该选项不可用。

    • 当 INSERT 语句向索引中插入多个、非唯一键值时，"忽略重复值"可控制所发生的情况。有关详细信息，请参阅 CREATE INDEX。

    • "不重新计算统计（不推荐使用）"，指定在索引更新时不自动重新计算索引统计。

    • "文件组"，指定要创建索引的文件组。单击该文件组名。

    • "填充索引"，在索引各内部节点上留出空间。有关详细信息，请参阅 CREATE INDEX。

    • "除去现有索引"，在创建新索引之前将任何现有的同名索引删除。

    • "填充因子"，指定 SQL Server 在创建索引过程中，对各索引页的叶级所进行填充的程度。有关详细信息，请参阅 CREATE INDEX。
  10. 单击"编辑 SQL"以查看和编辑用于创建索引的 Transact-SQL 语句。（可选）

请参见

使用 SQL 查询分析器以图形方式显示执行计划

在文件组上放置索引


如何删除索引（查询分析器）

删除索引

  1. 在"查询"菜单上单击"显示执行计划"命令。

  2. 执行查询窗格中的 Transact-SQL 脚本。

  3. 在结果窗格中单击"执行计划"选项卡。

  4. 右击代表表（其中包含要删除的索引）的物理运算符图标，然后单击"管理索引"按钮。

  5. 在"数据库"和"表"中选择不同数据库和表的名称。（可选）

  6. 在"现有索引"中，单击要删除的索引名，然后单击"删除"按钮。

  7. 确认删除。

请参见

使用 SQL 查询分析器以图形方式显示执行计划


复制

Microsoft® SQL Server™ 2000 复制是从一个数据库向另一个数据库复制并分发数据和数据库对象，然后在数据库之间进行一致性同步的过程。

使用复制可以将数据分发到不同位置，通过局域网、使用拨号连接、通过 Internet 分发给远程或移动用户。复制还能够使用户提高应用程序性能，根据数据的使用方式物理分隔数据（例如，将联机事务处理 (OLTP) 和决策支持系统分开），或者跨越多个服务器分布数据库处理。


复制类型（企业管理器）

Microsoft® SQL Server™ 2000 提供以下复制类型，可以在分布式应用程序中使用：

  • 快照复制

  • 事务复制

  • 合并复制

每种类型提供不同的能力，主要依据应用程序以及事务和站点独立的不同 ACID 属性级别。例如，合并复制使得用户可以自主使用和更新数据，即使没有确定的 ACID 属性。但是，当重新连接服务器时，复制拓扑中的所有站点都汇聚为相同的数据值。事务复制维持事务的一致性，但订阅服务器站点的自治功能不如在合并复制中那样强，因为发布服务器和订阅服务器的连接通常必须是可靠且连续的，以便更新能传播到订阅服务器上。

一个应用程序可以使用多个复制类型和选项。应用程序中的有些数据可能不需要在订阅服务器上更新，有些数据集可能需要偶尔更新，但是这种更新只在一个或几个服务器上进行，而有些数据集可能需要在多个服务器上每天更新。

为应用程序选择何种复制类型取决于分布式数据的因素、数据是否需要在订阅服务器上更新、复制环境，以及被复制数据的需要和要求。有关更多信息，请参阅复制计划。

每种类型的复制都是以在订阅服务器上生成和应用快照开始的，所以了解快照复制以及其它类型的复制和所选选项是很重要的。


如何启用交互式冲突解决程序（企业管理器）

  1. 在 SQL Server 企业管理器的创建发布向导中，在"指定项目"页，单击要发布的表，然后单击其属性（"..."）按钮。

  2. 在"冲突解决程序"选项卡上，单击"允许订阅服务器在按需同步时交互式地解决冲突"。

  3. 在 SQL Server 企业管理器中，在请求订阅向导中创建订阅时，可以选择允许订阅服务器按需同步时交互式地解决冲突的选项。

    在创建完请求订阅后，还可以在"属性"对话框的"同步"选项卡中为订阅设置此选项。


在合并同步过程中激活交互式冲突解决程序（Windows 同步管理器）

  1. 在 Windows 的"开始"菜单中，依次指向"程序"、"附件"子菜单，然后单击"同步"命令。

  2. 在"要同步的项目"对话框中，单击要同步的订阅，单击"属性"按钮，然后单击"其它"选项卡。

  3. 在"冲突解决模式"下，单击"交互式解决冲突"，然后单击"确定"按钮。

  4. 为每一项要同步的订阅重复第 1 至第 3 步，并使用交互式冲突解决程序。

  5. 单击"同步"按钮。


如何为项目设置行级或列级跟踪（企业管理器）

  1. 在创建发布向导中的"指定项目"页，单击计划在合并发布中用作项目的"表"。

  2. 选定表后单击属性（"..."）按钮。

  3. 在项目"属性"页的"常规"选项卡上，在"在合并不同数据源的更改时"下，对于行级跟踪单击"对相同行的更改视为冲突"，或对于列级跟踪单击"对相同列的更改视为冲突（将合并对相同行中不同列的更改）"。


如何选择解决程序（企业管理器）

  1. 在创建发布向导中的"指定项目"页，单击计划在合并发布中用作项目的"表"（如果它未被配置为活动项目）。

  2. 选定表后单击属性（"..."）按钮。

  3. 在项目"属性"页的"冲突解决程序"选项卡中，单击"使用默认的冲突解决程序"以启用项目的默认解决程序。

  4. 如果希望使用项目的自定义冲突解决程序，请单击"使用此自定义的冲突解决程序"，然后在列表中单击所需的冲突解决程序。如果希望使用自定义存储过程冲突解决程序，请单击"Microsoft SQL Server 存储过程冲突解决程序"。

  5. 如果想使用自定义存储过程冲突解决程序，可以按 TAB 键转到"自定义冲突解决程序信息"框，然后输入存储过程的名称。如果正在使用 COM 自定义冲突解决程序，则只有在需要输入自定义冲突解决程序所需的其它信息（如输入参数）时才使用信息框。


复制工具（企业管理器）

Microsoft® SQL Server™ 2000 提供了几种执行和管理复制的方法，包括 SQL Server 企业管理器、程序接口和其它 Microsoft Windows® 组件。

SQL Server 企业管理器包括一个复制对象的图形化结构、几个向导和对话框，可以用来简化复制的配置和管理。可以使用 SQL Server 企业管理器查看及修改复制配置的属性，对复制活动进行监视和疑难解答。

还可以使用诸如复制的 Microsoft ActiveX® 控件、SQL-DMO 和 Transact-SQL 系统存储过程的脚本等编程接口来执行、监控和维护复制。

可以使用 Windows 同步管理器和 Microsoft Windows 2000 Active Directory™ 服务在 Windows 应用程序中同步数据、订阅发布以及组织并访问复制对象。


如何打开发布服务器和分发服务器属性（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 Replication 文件夹，然后右击 Publications 文件夹。

  2. 单击"配置发布、订阅服务器和分发"。

发布服务器和分发服务器属性对话框的标题带有发布服务器和分发服务器属性以及分发服务器的名称。


如何打开发布属性（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 Replication 文件夹，然后展开 Publications 文件夹。

  2. 右击发布，然后单击"属性"命令。

如果发布已有订阅，某些属性不能修改，将出现一个对话框通知您。发布属性的标题带有发布属性和发布的名称。


如何打开强制订阅属性（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 Replication 文件夹，然后展开 Publications 文件夹。

  2. 单击一个发布，右击强制订阅，然后单击"属性"命令。


如何打开请求订阅属性（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 Replication 文件夹，然后单击 Subscriptions 文件夹。

  2. 右击请求订阅，然后单击"属性"命令。


如何打开代理属性（企业管理器）

  1. 在 SQL Server 企业管理器中，展开复制监视器然后展开 Agents 文件夹。

  2. 单击要查看的代理程序的文件夹（例如快照代理程序），右击一个代理程序，然后单击"代理程序属性"命令。

    代理程序属性对话框的标题带有分发服务器的名称、发布的数据库、发布和作业编号。


如何打开 Windows 同步管理器

说明 在 Microsoft® Windows® 2000，或者安装了 Microsoft Internet Explorer 5.0 或者更新版本都自动安装了 Windows 同步管理器。

  • 在 Windows"开始"菜单中，依次单击"程序"、"附件"子菜单，然后单击"同步"命令。


执行复制（企业管理器）

无论使用快照复制、事务复制还是合并复制，以下阶段都将帮助您执行复制。

阶段 | 任务
配置复制 | 在拓扑中标识发布服务器、分发服务器和订阅服务器。使用 SQL Server 企业管理器、SQL-DMO 脚本或 Transact-SQL 系统存储过程配置发布服务器，创建分发数据库并启用订阅服务器。
发布数据和数据库对象 | 在发布中创建发布并定义数据和数据库对象项目，并将必要的筛选器应用到要发布的数据。
订阅到发布 | 创建强制、请求或匿名订阅说明需要传播到个人订阅服务器发布的类型和时间。
应用初始快照 | 说明在何处保存快照文件，这些文件是否已被压缩，以及在应用初始快照之前或之后要运行的脚本。 指定在创建订阅之后或指定时间使快照代理在订阅服务器上立即应用快照。 通过将快照保存到网络位置或能够传送到订阅服务器的可移动介质来手工应用快照，然后在订阅服务器上手工应用快照文件。
同步数据 | 当快照、日志读取器或合并代理运行并且更新在发布服务器和订阅服务器之间传播时，将同步数据。 对于快照复制，快照将在订阅服务器上重新应用。 对于事务复制，更新将传播到订阅服务器。 如果在快照复制或事务复制使用可更新订阅，数据将从订阅服务器传播到发布服务器以及其它订阅服务器。 对于合并复制，在合并过程中进行数据同步（所有服务器的数据更改进行汇聚，如果有冲突，会进行检测和解决）。


如何配置发布和分发（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 SQL Server 组，展开一个服务器，然后右击 Replication 文件夹，然后单击"配置发布、订阅服务器和分发"命令。

  2. 根据向导页选择一个分发服务器，创建分发数据库，然后在"自定义配置"页，接受默认的发布服务器和订阅服务器，或者选择"是，让我设置分发数据库属性，启用发布服务器或设置发布设置"。

    允许用户使用向导设置分发数据库属性、启用发布服务器、启用发布数据库并启用订阅服务器。以后还可以在发布服务器和分发服务器属性中配置这些属性。


如何修改发布服务器和分发服务器属性（企业管理器）

添加、修改或删除发布服务器

  1. 在 SQL Server 企业管理器中，展开一个服务器组，展开分发服务器，右击 Replication 文件夹，然后单击"配置发布"、"订阅服务器"和"分发"按钮。

  2. 选择对发布服务器执行的操作。
    • 若要添加一个发布服务器，请单击"发布服务器"选项卡然后选择要启用的发布服务器。

    • 若要修改发布服务器，请单击"发布服务器"选项卡，单击要修改的发布服务器，然后单击属性（"..."）按钮。

    • 若要删除发布服务器，请单击"发布服务器"选项卡，然后清除发布服务器名称旁边的框。

    说明 如果发布服务器没有分发数据库中的项目，将出现确认提示。

修改分发服务器或者添加或修改分发数据库

  1. 在 SQL Server 企业管理器中，展开一个服务器组，展开分发服务器，右击 Replication 文件夹，然后单击"配置发布、订阅服务器和分发"按钮。

  2. 选择对分发服务器执行的操作。
    • 若要修改分发服务器属性，请单击"分发"选项卡更改连接到分发服务器的密码或设置代理程序配置的密码。

    • 若要添加分发数据库，请单击"分发服务器"选项卡，单击"新建"按钮，然后输入数据库名称以及数据库和日志文件的位置。

    • 若要修改分发数据库，请单击分发数据库的"属性"按钮以更改事务保持期，历史记录保持期。


如何添加、修改或禁用订阅服务器（企业管理器）

启用或禁用订阅服务器

  1. 在 SQL Server 企业管理器中，展开一个服务器组，展开分发服务器，右击 Replication 文件夹，然后单击"配置发布、订阅服务器和分发"按钮。

  2. 选择对分发服务器执行的操作。
    • 若要启用订阅服务器，请单击"订阅服务器"选项卡，如果列出了订阅服务器，请选择订阅服务器。

    • 如果订阅服务器没有列出，要想启用它，请在"订阅服务器"选项卡上，单击"新建订阅服务器"，单击要注册的订阅服务器类型，然后输入服务器、ODBC 数据源或 OLE DB 数据源以及连接信息。

    • 若要禁用订阅服务器，请单击"订阅服务器"选项卡，然后清除订阅服务器旁边的框。

修改订阅服务器

  1. 在 SQL Server 企业管理器中，展开一个服务器组，展开分发服务器，右击 Replication 文件夹，然后单击"配置发布、订阅服务器和分发"按钮。

  2. 单击"订阅服务器"选项卡，单击要修改的订阅服务器，然后单击属性（"..."）按钮。

  3. 在"常规"选项卡上，更改订阅服务器的描述或安全模式。

  4. 单击"调度"选项卡修改默认调度选项。


如何禁用发布和分发（企业管理器）

禁用分发服务器

  1. 在 SQL Server 企业管理器中，展开一个服务器组，展开分发服务器，右击 Replication 文件夹，单击"禁用发布"。

  2. 完成向导中的步骤。

删除分发数据库

  1. 在 SQL Server 企业管理器中，展开一个服务器组，展开分发服务器，右击 Replication 文件夹，然后单击"配置发布和分发"命令。

  2. 单击"分发服务器"选项卡，选择要删除的数据库，然后单击"删除"按钮。


如何创建发布和定义项目（企业管理器）

创建发布

  1. 在发布服务器上打开 SQL Server 企业管理器，展开一个服务器组，展开 Replication 文件夹，右击 Publications 文件夹，然后单击"新建发布"命令。

  2. 在欢迎进入创建发布向导页中，选择"显示本向导中的高级选项"启用可更新的订阅或可转换的订阅（快照复制或事务复制可使用的选项。）

  3. 向导指导您执行以下操作：
    • 选择发布数据库。

    • 使用发布模板。

    • 选择发布类型。

    • 选择可更新的订阅或可传送的订阅（快照复制或事务复制可使用的选项。）

    • 指定订阅服务器类型。

    • 指定要发布的数据和数据库对象项目。

    • 选择发布名称和描述。发布名称中不能包含下列字符：/ \ < >。

    • 自定义发布属性，包括筛选列、筛选行、启用动态筛选器、验证订阅信息、优化同步、允许匿名订阅以及设置快照代理调度。


修改发布和项目的方式（企业管理器）

说明 如果订阅是为发布创建的，某些属性被禁用而且不能更改。

查看或修改发布属性

  1. 在发布服务器上打开 SQL Server 企业管理器，展开一个服务器组，展开 Replication 文件夹，展开 Publications 文件夹，右击发布并选择"属性"命令。

  2. 在"发布属性"对话框中，单击"常规"选项卡以查看发布名称、数据库名称和发布类型。

  3. 还可以查看和修改发布描述、初始快照文件格式或同步时间限制。

  4. 选择在"常规"选项卡上要执行的操作。
    • 若要添加、删除或更改项目的属性，请单击"项目"选项卡。若要查看或更改被发布的架构对象，请单击项目的属性按钮（"..."）然后单击"快照"选项卡。

    • 若要在已发布表中筛选列，请单击"筛选列"。

    • 若要在已发布表中筛选行，请单击"筛选行"。

    • 若要强制、删除、重新初始化或查看订阅的属性，请单击"订阅"选项卡。

    • 对于快照或事务发布，单击"订阅选项"允许请求订阅、允许匿名订阅、允许通过附加订阅数据库创建新订阅，以及查看发布是否允许转换已发布数据、即时更新或排队更新。

    • 对于合并发布，单击"订阅选项"允许请求订阅、允许匿名订阅、允许通过附加订阅数据库创建新订阅，查看数据冲突是否集中存储在发布服务器，查看是否使用了动态筛选（如果是，订阅服务器信息是否有效），并查看同步是否是优化的。

    • 对于快照和事务发布，单击"可更新的"选项卡查看是否允许即时更新或排队更新，并启用在发布服务器的集中报告冲突，指定冲突解决策略，以及是否允许排队更新，指定在何处排队订阅服务器的更改。

    • 若要修改快照格式（SQL Server 或字符模式），请指定在应用快照之前或之后运行的脚本，对于要启用并发快照处理的事务复制，单击"快照"选项卡。

    • 若要指定其它位置保存快照、压缩快照文件及指定订阅服务器使用 FTP 访问快照文件夹时的文件传输协议 (FTP) 信息，请单击"快照位置"选项卡。

    • 若要指定有发布访问权限的登录，请单击"发布访问列表"。

    • 若要查看快照代理程序的状态、运行代理程序、查看代理程序属性或启动发布所需的服务，请单击"状态"选项卡。

    • 对于合并发布，单击"同步伙伴"选项卡启用要与服务器而不是初始发布服务器同步的订阅服务器，然后选择用作此发布的可选合作伙伴的服务器。

授权或废除对发布的访问权

  1. 在发布服务器上打开 SQL Server 企业管理器，展开一个服务器组，展开 Replication 文件夹，展开 Publications 文件夹，右击发布然后单击"属性"命令。

  2. 若要添加或删除用于访问发布的登录，请单击"发布访问列表"选项卡，然后单击"添加"、"删除"或"全部删除"按钮。

说明 如果使用远程分发服务器，则新的登录必须同时存在于发布服务器和分发服务器的发布访问列表中。如果请求订阅登录不在发布访问列表之中，则在订阅服务器上会出现一个错误。

添加或删除项目

说明 在订阅创建完成后，项目就添加到了现有的发布中。不允许从已订阅发布中删除项目。若要删除项目，必须首先删除所有订阅。

  1. 在发布服务器上打开 SQL Server 企业管理器，展开一个服务器组，展开 Replication 文件夹，展开 Publications 文件夹，右击发布并选择"属性"命令。

  2. 选择要对项目执行的操作。
    • 若要查看所有可用对象的列表，请单击"项目"选项卡，然后选择"显示未发布的对象"。

    • 若要添加项目，请选择列出的"对象类型"旁边的"显示"复选框。选择要添加到发布的项目对象旁边的复选框，或者选择要发布对象类型旁的"全部发布"复选框。

    • 若要删除对象，请选择列出的"对象类型"旁边的"显示"复选框。清除要删除的发布的项目对象旁边的复选框，或者清除要从发布中拒绝的对象类型旁的"全部发布"复选框。

    • 若要设置项目选项，请单击生成按钮（"..."）。


如何删除发布和项目（企业管理器）

删除发布

  • 在发布服务器上打开 SQL Server 企业管理器，展开一个服务器组，展开 Replication 文件夹，展开 Publications 文件夹，右击发布然后单击"删除"命令。

删除项目

说明 不允许从已订阅发布中删除项目。若要删除项目，必须首先删除对发布的所有订阅。

  1. 在发布服务器上打开 SQL Server 企业管理器，展开一个服务器组，展开 Replication 文件夹，展开 Publications 文件夹，右击发布然后单击"属性"命令。

  2. 单击"项目"选项卡，选择要删除的项目，然后清除要删除项目旁边的复选框。


如何创建强制订阅（企业管理器）

创建强制订阅

  1. 在发布管理器中打开 SQL Server 企业管理器，依次展开服务器组、Replication 文件夹、publications 文件夹，右击想要订阅的发布，然后单击"强制新订阅"命令。

  2. 完成向导中的步骤。


如何修改强制订阅(企业管理器)

修改强制订阅属性

  1. 在发布服务器中打开 SQL Server 企业服务器，依次展开服务器组、Replication 文件夹、publications 文件夹，单击带有要修改订阅的发布，右击该发布的强制订阅，然后单击"属性"命令。

  2. 选择您要对订阅属性执行的操作。
    • 若要查看所选的订阅属性，请单击"常规"选项卡。

    • 若要指定分发代理程序或合并代理程序运行的位置，请单击"同步"选项卡。


如何删除强制订阅（企业管理器）

删除强制订阅

  • 在发布服务器打开 SQL Server 企业管理器，依次展开服务器组、Replication 文件夹、publications 文件夹，单击带有要删除订阅的发布，右击 SQL Server 企业管理器中该发布的强制订阅，然后单击"删除"按钮。


如何创建请求或匿名订阅（企业管理器）

创建请求或匿名订阅

  1. 在订阅服务器的 SQL Server 企业管理器中，依次展开服务器组、Replication 文件夹、右击订阅文件夹，然后单击"新建请求订阅"按钮。

  2. 遵循"请求订阅向导"中的步骤。

如果发布允许匿名订阅，请求订阅向导中将显示"允许匿名订阅"页，您可将新的订阅指定为匿名。


如何查看或修改请求或匿名订阅（企业管理器）

  • 在订阅服务器的 SQL Server 企业管理器中，依次展开服务器组、Replication 文件夹、单击订阅文件夹，右击要在 SQL Server 企业管理器的右窗格中修改的订阅，然后单击"属性"命令。


如何删除请求或匿名订阅（企业管理器）

  • 在订阅服务器的 SQL Server 企业管理器中，依次展开服务器组、Replication 文件夹、单击订阅文件夹，右击要在 SQL Server 企业管理器的右窗格中删除的订阅，然后单击"删除"命令。


如何创建匿名订阅（Windows 同步管理器）

  1. 在"开始"菜单中，依次指向"程序"、"附件"子菜单，然后单击"同步"命令。

  2. 单击"创建订阅：先选择此项，然后单击"属性""，单击"属性"按钮，然后选择"通过手工指定发布和订阅信息"。

  3. 输入订阅名称、订阅服务器名称、订阅数据库名称、发布服务器名称、发布数据库名称、发布类型和分发服务器名称。


如何查看或修改默认快照文件夹位置（企业管理器）

  1. 在 SQL Server 企业管理器中，依次展开服务器组、发布服务器，右击 Replication 文件夹，然后单击"配置发布服务器、订阅服务器和分发"命令。

  2. 单击"发布服务器"选项卡，然后单击特定发布服务器的分发数据库属性按钮（"..."）。

  3. 若要修改默认快照文件夹位置，请单击属性按钮（"..."）并进行浏览以设置新的默认位置。


如何指定备用快照位置（企业管理器）

  1. 在 SQL Server 企业管理器中，依次展开 Replication 和 Publications 目录，选择一个发布并右击该发布，然后单击"属性"命令。

  2. 在"快照位置"选项卡中，选择"在下列位置生成快照"选项，然后输入通用命名规则路径或单击浏览按钮（"..."）浏览要保存快照文件的位置。

  3. 若要使用压缩，请选择"压缩此文件夹中的快照文件"。

  4. 如果使用 FTP 传送快照，请选择"订阅服务器可以使用 FTP（文件传输协议）访问该文件夹"。


如何压缩和传送快照文件(企业管理器)

压缩快照文件

  1. 在 SQL Server 企业管理器中，展开 Replication 和 Publications 目录，右击某个发布，然后单击"属性"命令。

  2. 在"快照位置"选项卡上，选择"在下列位置中生成快照"复选框，为文件指定位置，然后选择"压缩此文件夹中的快照文件"复选框。

在订阅服务器上配置快照传送

  1. 在 Microsoft SQL Server 企业管理器中，展开订阅数据库和 Subscriptions 目录，右击某个订阅，然后单击"属性"命令。

  2. 在"快照文件位置"选项卡上，选择"从下列文件夹中获得快照"。

  3. 输入路径或单击浏览（"..."）按钮并浏览您想放置快照文件的目录。


如何设置 &#150;UseInprocLoader 属性（企业管理器）

 使用方法

如何设置 –UseInprocLoader 属性（企业管理器）

  1. 在运行分发代理程序或合并代理程序的服务器上，展开"复制监视器"节点，单击 Distribution Agents 或 Merge Agents 文件夹，右击将应用快照的代理程序，然后单击"代理程序属性"命令。

  2. 在"步骤"选项卡上，双击订阅代理程序步骤，然后在"命令"文本框中添加 – UseInprocLoader 属性。


如何在应用快照之前和之后执行脚本(企业管理器)

  1. 在发布服务器上，打开 SQL Server 企业管理器，展开 Replication 和 Publications 目录，右击某个发布，然后单击"属性"命令。

  2. 在"快照"选项卡上，单击浏览（"..."）按钮查找"应用快照之前执行该脚本"或"应用快照之后执行该脚本"，然后选择您希望在同步之前或之后执行的脚本。


如何重新初始化订阅（企业管理器）

重新初始化强制订阅

  • 在发布服务器上，打开 SQL Server 企业管理器，依次展开服务器组、Replication 文件夹和 Publications 文件夹，然后单击需要重新初始化订阅的发布。

  • 右击要重新初始化的订阅，然后单击"重新初始化"命令。

重新初始化请求订阅或匿名订阅

  • 在订阅服务器上，打开 SQL Server 企业管理器，展开某个服务器组，展开 Replication 文件夹，然后单击 Subscriptions 文件夹。

  • 右击要重新初始化的订阅，然后单击"重新初始化"命令。


如何浏览和复制快照文件（企业管理器）

使用快照资源管理器

  • 在 SQL Server 企业管理器中，展开 Replication 和 Publications 目录，选择某个发布，右击该发布，然后单击"浏览最新快照文件夹"命令。


如何同步订阅（企业管理器）

同步强制订阅

  1. 在发布服务器上，打开 SQL Server 企业管理器，依次展开服务器组，展开 Replication 文件夹，展开 Publications 文件夹，然后单击需要同步订阅的发布。

  2. 右击要同步的订阅，然后单击"启动同步处理"命令。

同步请求订阅或匿名订阅

  1. 在订阅服务器上，打开 SQL Server 企业管理器，展开某个服务器组，展开 Replication 文件夹，然后单击 Subscriptions 文件夹。

  2. 右击要同步的订阅，然后单击"启动同步处理"命令。


如何同步匿名订阅（Windows 同步管理器）

同步匿名订阅

  1. 在"开始"菜单中，依次指向"程序"、"附件"子菜单，然后单击"同步"命令。

  2. 单击要同步的订阅，然后单击"同步"按钮。


如何查看和解决合并同步冲突（企业管理器）

查看和进一步解决同步冲突

  1. 展开服务器组，然后展开服务器。

  2. 展开 Databases，然后展开数据库名。

  3. 展开 Publications，右击该发布，然后单击"查看冲突"命令。

  4. 在"数据库中的发布内容"列表中，选择要查看的发布。

  5. 在"有冲突的表"列表中，选择要查看的冲突表。

说明 确保连接到正确的服务器以便查看冲突。依据复制是否已经被配置为用来集中冲突的分散日志，冲突表的位置会有所不同。如果集中，则冲突表存储在发布服务器上，并且为了查看冲突，您必须连接到发布服务器上。如果分散，则取决于丢失冲突的服务器，冲突表将存储在发布服务器或订阅服务器上。


如何为复制生成脚本（企业管理器）

  1. 在发布服务器上，打开 SQL Server 企业管理器，展开服务器组，右击 Replication 文件夹，然后单击"生成 SQL 脚本"命令。

  2. 选择将生成脚本的复制组件（分发服务器属性、发布和强制订阅，或请求订阅）以及您是希望用脚本来启用或创建组件，还是禁用或除去组件。


如何在发布数据库上应用架构更改（企业管理器）

将列添加到项目

  1. 在 SQL Server 企业管理器中的 Replication 下，展开 Publications，然后右击需要修改架构的发布。

  2. 单击"属性"命令，单击"筛选列"，然后单击"添加列"。

  3. 在"将列添加到复制的表"对话框中，输入列名和定义该列的 SQL 语法。在用于列定义的 SQL 中，必须指定默认值，或者允许 NULL 值。

  4. 有关定义列所要求的语法的信息，请参阅 Transact-SQL ALTER TABLE 语句。

  5. 在"将列添加到复制的表"对话框中，选择要添加列的发布。

从项目中除去列

  1. 在 SQL Server 企业管理器中，展开 Replication，展开 Publications，然后右击要修改架构的发布。

  2. 单击"属性"命令，单击"筛选列"，在"发布中的表"列表中选择表，在"选定表中的列"列表中选择列，然后单击"除去列"。

  3. 如果列受到约束，那么您会被提示；不能除去带有主键或唯一约束的列，以及 uniqueidentifier 列。如果您试图删除这类列中的一个，则会显示错误信息。对于其它限制，则显示警告消息，单击"确定"按钮除去列。


如何指定 FTP 信息（企业管理器）

将快照文件夹作为 FTP 主目录进行设置

  1. 在"开始"菜单中，依次指向"程序"、"Microsoft Internet Server"子菜单，然后单击"Internet 服务管理器"命令。

  2. 单击相应于 FTP 服务的服务器名。

  3. 在"属性"菜单上，单击"服务属性"子菜单，然后在"目录"选项卡上单击"添加"按钮。

  4. 输入路径到 FTP 目录（例如，C:\Microsoft SQL Server\Mssql\Repldata\Ftp），然后单击"主目录"。

将 FTP 主目录配置为 FTP 站点

  1. 在"开始"菜单上，依次指向"程序"、"Microsoft SQL Server 2000"子菜单，然后单击"客户端网络实用工具"命令。

  2. 在"常规"选项卡上，确保 TCP/IP 出现在"按顺序启用协议"列表中。如果 TCP/IP 出现在"禁用的协议"列表中，则选择它，然后单击"启用"按钮。

  3. 在"服务器别名"中，输入服务器名。

  4. 在"计算机名"中，重写带有 IP 地址的现有名称。

  5. 您的系统管理员可以为您提供正确的 IP 地址。

  6. 在"端口号"中，必要时重写现有的端口号。


复制选项（企业管理器）

复制选项使您得以按照最适合您应用程序和环境的方式来配置复制。

选项 | 复制类型 | 益处
筛选已发布数据 快照复制

事务复制

合并复制

 筛选使您得以创建数据的垂直和/或水平分区，该数据可作为复制的一部分进行发布。通过向不同的订阅服务器分配数据分区，您可以：
  • 将网络上发送的数据量减到最少。

  • 减少订阅服务器上需要的存储空间量。

  • 根据个别订阅服务器的要求，自定义发布和应用程序。

  • 减少冲突，因为不同的数据分区可以被发送到不同的订阅服务器中。
可更新的订阅（即时更新，排队更新) 快照复制

事务复制

 即时更新和排队更新选项使用户得以在订阅服务器上更新数据，并立即将这些更新传播到发布服务器，或者将更新存储在队列中。

可更新的订阅最适合下列情况的复制拓扑：当发布服务器、分发服务器以及订阅服务器大部分时间保持连接，并且当引起多个用户更新相同数据的冲突经常发生时，在订阅服务器上经常读取复制数据并且偶尔进行更新。
转换已发布的数据 快照复制

事务复制

 您可以在复制期间调节数据转换服务 (DTS) 的数据移动、转换映射和筛选能力。通过可转换的订阅，您可以：
  • 创建快照和事务发布的自定义分区。

  • 当数据与数据类型映射（如整型到实型）、列操作（如将名列和姓列连成一个列）、字符串操作以及函数一起发布时，则转换该数据。
可选同步伙伴 | 合并复制 | 可选同步伙伴使订阅服务器得以合并发布，以便将数据与产生订阅的发布服务器之外的服务器同步。这使得订阅服务器得以在原始发布服务器不可用时同步数据，同时，这对可以通过备用服务器访问更快捷和更可靠网络连接的移动订阅服务器也很有用。
优化同步 | 合并复制 | 合并复制期间，通过优化同步，您可以在发布服务器上存储更多的信息，而不用将这些信息通过网络传输到订阅服务器。合并复制期间，通过优化同步，您可以在发布服务器上存储更多的信息，而不用将这些信息通过网络传输到订阅服务器。
可连接的订阅数据库 快照复制

事务复制

合并复制

 可连接的订阅数据库使您得以将带有复制数据和订阅的数据库从一个订阅服务器传输到另一个订阅服务器。在数据库连接到新的订阅服务器后，新订阅服务器上的数据库将自动地接收其自身对那些发布服务器上的发布所作的请求订阅。这为您在多个订阅服务器上创建订阅数据库和订阅节省了时间和精力。


如何通过使用创建发布向导水平地筛选发布（企业管理器）

  1. 在创建发布向导的"自定义发布的属性"页中，选择"是，我将定义数据筛选，启用匿名订阅或自定义其它属性"。

  2. 在"筛选数据"页上，选择"水平地，通过筛选已发布数据的行"。

  3. 在"筛选表的行"页上，单击要筛选项目旁边的筛选子句（"..."）按钮，然后在"指定筛选"对话框中完成带有筛选条件的 WHERE 子句。

说明 这不是指要输入联接筛选的页，这些联接筛选在表间关系的基础上跨表。在创建发布向导中的该页被称为"自动生成筛选"页。


如何通过使用创建发布向导垂直地筛选发布（企业管理器）

说明 如果您正在创建合并发布以便与运行 Microsoft® SQL Server™ 7.0 版的订阅服务器一起使用，则您将不能创建垂直筛选，并且在创建发布向导中您看不到"筛选列"页。

  1. 在创建发布向导的"自定义发布的属性"页中，选择"是，我将定义数据筛选，启用匿名订阅或自定义其它属性"。

  2. 在"筛选数据"页中，选择"垂直地，通过筛选已发布数据的列"。

  3. 在"筛选表的列"页中，单击要添加垂直筛选的发布中的表，然后清除不想包括在发布中的列。


如何通过使用发布属性垂直地筛选发布（企业管理器）

说明 如果您正在 Microsoft® SQL Server™ 7.0 版上查看合并发布的属性，则您将不能看到"筛选列"页。

  1. 在 SQL Server 企业管理器中，展开 Replication 和 Publications 文件夹，右击要添加列筛选的发布，然后单击"属性"命令。

  2. 在"筛选列"选项卡上，单击要添加列筛选的发布中的表，然后清除不想包括在发布中的列。


如何通过使用创建发布向导验证订阅服务器信息（企业管理器）

  1. 在创建发布向导的"自定义发布的属性"页中，选择"是，我将定义数据筛选，启用匿名订阅或自定义其它属性"。

  2. 在"筛选数据"页中，选择"水平地，通过筛选已发布数据的行"，然后在"启用动态筛选"页中选择"是，启用动态筛选"。

  3. 在"筛选表的行"页上，单击要筛选项目旁边的筛选子句（"..."）按钮，然后在"指定筛选"对话框中完成带有在订阅服务器检索信息并动态地筛选发布的函数的 WHERE 子句。

  4. 在"验证订阅服务器信息"页中，选择"是，验证订阅服务器的信息"，然后为该发布输入在动态筛选中所使用的函数。


如何通过使用发布属性水平地筛选发布（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 Replication 和 Publications 文件夹，右击要添加行筛选的发布，然后单击"属性"命令。

  2. 在"筛选行"选项卡上，单击要筛选项目旁边的筛选子句（"..."）按钮，然后在"指定筛选"对话框中完成带有筛选条件的 WHERE 子句。


如何创建动态快照（企业管理器）

生成动态快照

说明 您必须在创建动态快照之前，生成到动态筛选的合并发布的常规快照。

  1. 创建带有在任何必要项目上启用和指定的动态筛选的合并发布。

  2. 通过运行快照代理程序生成常规快照。

  3. 在发布服务器的 SQL Server 企业管理器中，展开 Replication 和 Publications 文件夹，右击动态筛选的合并发布，然后单击"创建动态快照作业"命令。

  4. 在"指定筛选准则"页中，输入发布的动态筛选中所使用的系统函数（SUSER_SNAME() 或 HOSTNAME()）或发布服务器的登录值。

  5. 在"指定快照文件位置"页中，将路径输入到要保存快照文件的文件夹中，或者单击浏览按钮（"..."），浏览文件夹位置。通过使用备用的快照位置功能，您可以在网络、可移动介质或 FTP 服务器上指定快照文件夹位置。

  6. 在"设置作业调度"页上，选择"使用下列调度"，然后选择"更改"指定生成动态快照时的调度，或者选择"仅按需"。选择"立即创建第一个快照"复选框以便立即生成动态快照。

  7. 在"指定作业名称"页中，输入该动态快照代理程序的名称。

  8. 运行动态快照代理程序作业。

应用动态快照

  1. 在订阅服务器中，通过使用请求订阅向导创建请求订阅。在"快照文件位置"页，选择"应用下列文件夹内文件中的快照"，指定或浏览文本框中动态快照的位置，然后选择"这是动态地已筛选订阅的快照"复选框。

  2. 完成请求订阅向导中的步骤。当快照可以在订阅服务器上应用合并代理程序时，请手动地启动合并代理程序（通过使用发布服务器上的复制监视器或通过编程方式）。


如何通过创建发布向导使用用户定义函数进行筛选（企业管理器）

  1. 在创建发布向导的"自定义发布的属性"页中，选择"是，我将定义数据筛选，启用匿名订阅服务器或自定义其它属性"。

  2. 在"筛选数据"页上，选择"水平地，通过筛选已发布数据的行"。

  3. 如果在"筛选数据"页上还选择了"垂直地，通过筛选已发布数据的列"，则在"筛选表列"页上，选择要从发布内容中筛选的列。

  4. 在"筛选表的行"对话框中，单击要筛选项目旁边的属性按钮（"..."），然后通过使用条件中的用户定义函数完成 WHERE 子句。


如何通过发布属性使用用户定义函数进行筛选（企业管理器）

  1. 在 SQL Server 企业管理器的"工具"菜单中，单击"复制"，然后单击"创建和管理发布"。

  2. 展开包含要修改发布的数据库，单击要修改的发布，然后单击"属性和订阅"。

  3. 如果该发布有订阅，则需要在修改发布筛选前删除它们。


如何除去对某个发布的所有订阅（企业管理器）

  1. 在"订阅"选项卡上，单击订阅名，然后单击"删除"。

  2. 单击"确定"按钮以关闭"发布属性"对话框，然后通过单击"属性和订阅"在"创建和管理发布"对话框中重新打开它。

  3. 在"发布属性"对话框中，单击"筛选行"选项卡，然后使用作为筛选条件一部分的用户定义函数来完成 WHERE 子句。


如何在分发服务器和订阅服务器上安装消息队列（企业管理器）

  1. 在"控制面板"中，双击"添加/删除程序"，单击"添加/删除 Windows 组件"，然后选择"消息队列服务"。

  2. 选择"消息队列服务器"。


如何设置排队更新冲突解决策略（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 Replication 和 Publications 目录。

  2. 右击允许排队更新的发布，然后单击"属性"命令。

  3. 在"可更新的"选项卡的"冲突解决策略"下，您可以选择将所进行的更改保留在发布服务器中，将所进行的修改保留在订阅服务器中或重新初始化订阅。


如何允许分散冲突报告（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 Replication 和 Publications 目录。

  2. 右击允许排队更新的发布，然后单击"属性"命令。在"可更新的"选项卡的"数据冲突"下，可以清除"仅报告发布服务器上发生冲突数据的更改"。冲突数据的更改将在发布服务器和订阅服务器中报告。


如何查看冲突（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 Replication 和 Publications 目录。

  2. 右击允许排队更新的发布，然后选择"查看冲突"命令。


如何在故障转移时使用排队更新启用即时更新（企业管理器）

  1. 在创建发布向导的"欢迎"页中，选择"显示本向导中的高级选项"。

  2. 选择"快照发布"或"事务发布"，然后在"可更新的订阅"页中选择"即时更新"和"排队更新"。

  3. 当使用请求订阅向导或强制订阅向导创建订阅时，在"可更新的订阅"页中选择"即时更新并用排队更新作为备用以防失败"。


如何在故障转移时从即时更新切换到排队更新（企业管理器）

  1. 对于强制订阅：展开 Replication 和 Subscriptions 目录，右击该订阅，单击"设置更新方法"命令，然后选择"即时更新"或"排队更新"。

  2. 对于强制订阅：在订阅服务器上，展开 Pull Subscriptions 目录，右击该订阅，单击"属性"命令，然后在"同步"选项卡上选择"即时更新"或"排队更新"。


如何在故障转移时从即时更新切换到排队更新 (Transact-SQL)

  • 使用 sp_setreplfailovermode 存储过程并设置以下参数。
    参数

            描述

    @publisher

            发布服务器名。

    @publisher_db

            发布数据库的名称。

    @publication

            发布名。

    @failover_mode

            可以是"即时"或"排队"。


如何在故障转移时从即时更新切换到排队更新（Windows 同步管理器）

  1. 在"开始"菜单，依次指向"程序"、"附件"子菜单，然后单击"同步"命令。

  2. 双击该订阅，然后在"属性"对话框的"其它"选项卡上选择"即时更新"或"排队更新"。

将使用按需同步创建的请求订阅自动地添加到 Windows 同步管理器。通过打开订阅属性，然后在"同步"选项卡上选中"使用 Windows 同步管理器对该订阅进行同步"复选框，您可以将没有使用按需同步的请求订阅添加到 Windows 同步管理器。


如何创建可转换的订阅（企业管理器）

  1. 使用创建发布向导创建一个为可转换的订阅启用的发布，在创建发布向导的"欢迎"页中依次单击"显示高级选项"、"下一步"，然后单击列表中的数据库。

  2. 在"选择发布类型"页中，单击"快照发布"或"事务发布"。

  3. 在"可更新的订阅"页中，不选择"即时更新"或"排队更新"，因为可转化的订阅也将不可用。

  4. 在"转换已发布的数据"页，单击"是"按钮，然后继续创建发布。

  5. 使用转换已发布数据向导生成复制 DTS 包。
    1. 在 SQL Server 企业管理器中，右击为可转换订阅启用的发布，然后单击"属性"命令。

    2. 在用于发布的"属性"对话框中，单击"订阅"，然后单击"转换"。

    3. 在转换已发布数据向导中，单击"下一步"直到显示出"选择目的"页为止。选择连接到订阅服务器的提供程序（DTS 的 Microsoft® SQL Server™ 2000 复制 OLE DB 提供程序仅用于从包到分发服务器的源连接）。在"定义转换"页中单击转换（"..."）按钮查找在其上定义转换的已发布的表。

    4. 在"列映射和转换"页中，单击"列映射"选项卡，然后单击下列项中的一个：保持现有表不变、DROP 现有表并重新创建它，或删除现有表中所有的数据。如果要垂直分区数据，则在列表中选择要包括的目的列。

    5. 如果要水平分区发布的数据，或在发布分区上映射转换，请单击发布表的"转换"选项卡。单击"使用以下脚本转换数据"。从下拉列表中选择脚本语言的类型，在脚本窗口中直接编辑或单击"装载文件"装载脚本。对您要添加转换的发布中的所有表，重复这一步骤。

    6. 在"保存 DTS 包"页，依次输入"名称"、"描述"，然后输入包的可选密码信息或使用所提供的默认值。继续执行，直到包创建成功为止。如果您要使用该包进行强制订阅，则在分发服务器（默认）中保存该包。如果要将该包用于请求订阅，则将其保存在订阅服务器中。
  6. 下面这组步骤是用来创建可转换的订阅。
    1. 打开强制订阅向导或请求订阅向导。

    2. 在"指定 DTS 包"页中，单击要与订阅一起使用的 DTS 包，可以选择输入一个包密码，单击"下一步"，然后继续执行向导，直到订阅创建成功为止。


如何使订阅服务器与可选同步伙伴同步（企业管理器）

  1. 在 SQL Server 企业管理器中，展开 Replication 和 Publications 目录，右击某个发布，然后单击"属性"命令。

  2. 单击"同步伙伴"选项卡，然后启用"允许订阅服务器与创建订阅的发布服务器之外的其它方法来进行同步"。

  3. 启用可作为该发布的订阅服务器的备用发布服务器的发布服务器和订阅服务器。


如何启用位于可选同步伙伴（用于命名订阅）的订阅服务器（企业管理器）

  1. 在发布服务器中，右击 SQL Server 企业管理器中的 Replication 目录，然后单击"配置发布、订阅服务器和分发"命令。

  2. 在"订阅服务器"选项卡中，选择要启用的订阅服务器旁边的框或单击"新订阅服务器"并且注册订阅服务器。


如何与可选同步伙伴同步（Windows 同步管理器）

  1. 在"开始"菜单上，依次指向"程序"、"附件"子菜单，然后单击"同步"命令。

  2. 选择要同步的发布，单击"属性"按钮，然后在"标识"选项卡选择要同步的发布服务器。

  3. 单击"确定"按钮，然后单击"同步"按钮。


如何使请求订阅与可选同步伙伴同步（企业管理器）

  1. 在订阅服务器中，展开 Replication 目录，单击 Subscriptions 目录，右击某个请求订阅，然后单击"属性"命令。

  2. 在"同步"选项卡中，单击"合并代理程序属性"。

  3. 在"步骤"选项卡，双击订阅代理程序步骤，然后在"命令"文本框中添加 –SyncToAlternate 开关。


如何使强制订阅与可选同步伙伴同步（企业管理器）

  1. 在订阅服务器中，展开 Replication Monitor 和 Agents 目录，选择 Merge Agents 目录，右击发布，然后单击"代理程序属性"。

  2. 在"步骤"选项卡中，双击订阅代理程序步骤，并在"命令"文本框中添加 –SyncToAlternate 开关。


如何在合并复制期间最小化通过网络发送的数据量 (Transact-SQL)

  • 执行 sp_addmergepublication 系统存储过程并将 @keep_partition_changes 参数设置为 'true'。


如何配置发布以允许订阅数据库的复制（企业管理器）

  1. 使用创建发布向导创建发布。

  2. 在 SQL Server 企业管理器中，展开 Replication 和 Publications 目录，然后右击您要为新订阅启用的发布。

  3. 对于快照复制和事务复制，单击"发布属性"中的"订阅选项"选项卡，选择"使用独立于该数据库的其它发布的分发代理程序"复选框，然后选择"始终可以使用快照文件来立即初始化新订阅"。如果您正在使用合并复制，则不需在该步骤进行任何操作。

  4. 选择"允许通过附加一个订阅数据库的复本来创建新订阅"。


如何复制订阅数据库（企业管理器）

  1. 在订阅服务器的 SQL Server 企业管理器中，展开 Replication 和 Subscriptions 目录，右击具备您要复制的订阅数据库的请求订阅，然后单击"复制订阅数据库"命令。

  2. 在"复制订阅数据库"对话框中，浏览您要保存订阅数据库的复本的目录或驱动器。

  3. 该位置可以在网络上，使用可移动介质（如 CD-ROM 或磁带设备），或在文件传输协议 (FTP) 站点上。

  4. 在"文件名"框中，输入订阅数据库文件的名称（该文件的扩展名为 .msf）。


如何启用订阅服务器来接收发布数据（企业管理器）

  1. 在发布服务器的 SQL Server 企业管理器中，右击 Replication 目录，然后单击"配置发布、订阅服务器和分发"命令。

  2. 在"订阅服务器"选项卡中，选择要启用的订阅服务器旁边的框或单击"新订阅服务器"并且注册订阅服务器。


如何将命名订阅附加到订阅数据库（企业管理器）

  1. 在新订阅服务器的 SQL Server 企业管理器中，展开 Replication 目录。

  2. 右击 Subscriptions 目录，然后单击"附加订阅数据库"命令。

  3. 输入通用命名规则 (UNC) 路径或单击浏览（"..."）按钮，并且浏览 .msf 文件的位置。

  4. 在"要创建的数据库名称"框中，输入数据库名称。


如何将匿名订阅附加到订阅数据库（企业管理器）

  1. 在新订阅服务器的 SQL Server 企业管理器中，展开 Replication 目录。

  2. 右击 Subscriptions 目录，然后单击"附加订阅数据库"命令。

  3. 输入 UNC 路径或单击浏览（"..."）按钮，并且浏览 .msf 文件的位置。

  4. 在"附加为数据库"框中，输入数据库名称。


管理和监视复制（企业管理器）

SQL Server 复制提供管理和监视复制代理程序、复制警报和复制进程的工具，以便您能确保复制满足您的应用程序和单位的需求。

监视复制将有助于您：

  • 设置复制代理程序的配置文件、调度和提示。

  • 疑难解答代理程序活动，包括验证上一次运行代理程序的时间，并监视代理程序的活动。

  • 疑难解答代理程序错误。

  • 确保数据值在发布服务器和订阅服务器上都相同。


如何更改复制监视属性（企业管理器）

更改复制监视属性

  1. 展开服务器组，然后展开分发服务器。

  2. 右击"复制监视器"，然后单击"刷新速率和设置"命令。

选择列进行监视查看

  1. 展开服务器组，然后展开分发服务器。

  2. 右击"复制监视器"，然后单击"选择列"。


如何监视复制代理程序的历史记录（企业管理器）

监视复制代理程序的历史记录

  1. 展开服务器组，然后展开分发服务器。

  2. 展开复制监视器，然后单击代理程序。

  3. 单击要进行监视的代理程序，右击详细信息窗格中的行，然后单击"代理程序历史记录"。


如何配置 DCOM 以远程运行分发代理程序

配置 DCOM 以远程运行分发代理程序

说明 若要运行 DCOM 配置，请在 Microsoft® Windows NT® 4.0 或 Microsoft Windows® 2000 上运行位于 \Winnt\System32 的 Dcomcnfg.exe。在 Microsoft Windows 98 上运行位于 \windows\system 的 dcomcnfg.exe。

  1. 在您要运行代理程序的计算机上，单击"开始"菜单中的"运行"，键入 dcomcnfg 命令，然后单击"确定"按钮。

  2. 在"应用程序"选项卡，选择"Microsoft SQL Server Replication Remote Dist Agent 8.0"，然后单击"属性"按钮。

  3. 在"安全性"选项卡中，选择"使用自定义启动权限"，然后单击"编辑"按钮。

  4. 在"注册表值权限"窗口中，添加在分发服务器（用于强制订阅）上运行 SQL Server 代理程序或在订阅服务器上（用于请求订阅）上运行 SQL Server 代理程序的帐户，然后单击"确定"按钮。

  5. 单击"标识"选项卡，选择"此用户"，然后输入分发服务器（用于强制订阅）上的 SQL Server 代理或在订阅服务器（用于请求订阅）上的 SQL Server 代理所用的用户帐户。


如何配置 DCOM 以远程运行合并代理

配置 DCOM 以远程运行合并代理

说明 若要运行 DCOM 配置，请在 Microsoft® Windows NT® 4.0 或 Microsoft Windows® 2000 上运行位于 \Winnt\System32 的 Ecomcnfg.exe。在 Microsoft Windows 98 上运行位于 \windows\system 的 dcomcnfg.exe。

  1. 单击"开始"菜单中的"运行"，输入 dcomcnfg 命令，然后单击"确定"按钮。

  2. 在"应用程序"选项卡中，选择"Microsoft SQL Server Replication Remote Merge Agent 8.0"，然后单击"属性"按钮。

  3. 在"安全性"选项卡中，选择"使用自定义启动权限"，然后单击"编辑"按钮。

  4. 在"注册表值权限"窗口中，添加在分发服务器（用于强制订阅）上运行 SQL Server 代理程序或在订阅服务器上（用于请求订阅）上运行 SQL Server 代理程序的帐户，然后单击"确定"按钮。

  5. 单击"标识"选项卡，选择"此用户"，然后输入与在分发服务器（用于强制订阅）上 SQL Server 代理程序或在订阅服务器上（用于请求订阅）上 SQL Server 代理程序所使用的相同的用户帐户。


如何启用强制订阅以使用远程代理程序激活

配置强制订阅以使用远程代理程序激活

  1. 在分发服务器上的 Microsoft® 管理控制台中，展开 Microsoft SQL Servers 2000，展开 SQL Server Group，选择"分发服务器"，然后展开 Replication 目录。

  2. 在发布服务器中，展开 Publications 目录，右击发布，然后选择"强制新订阅"。

  3. 在用于事务复制的"设置分发代理程序位置"窗口或在用于合并复制的"设置合并代理程序位置"窗口，选择"在订阅服务器上运行该代理程序"。

  4. 若要验证代理程序是否能远程运行，请单击"验证订阅服务器"。

  5. 分发服务器连接到订阅服务器，并使用 DCOM 启动分发代理程序或合并代理程序。如果连接成功，则您会收到消息："订阅服务器'SubscriberName'准备运行已卸载的代理程序"。

重要 当您指定在创建订阅时代理程序应在何处运行后，如果您指定订阅应自动同步并且您没有为远程代理程序激活配置 DCOM，则同步会失败。


如何启用请求订阅以使用远程代理程序激活

配置请求订阅以使用远程代理程序激活

  1. 在订阅服务器的 SQL Server 企业管理器中，展开 Replication 文件夹，右击 Subscriptions 文件夹，然后单击"新建请求订阅"。

  2. 按照向导中的步骤创建新的请求订阅。

  3. 在创建请求订阅后，右击它，然后选择"属性"命令。

  4. 单击"同步"选项卡，然后选择"在分发服务器运行该代理程序"以便从订阅服务器中卸载代理程序处理。

重要 当您指定在创建订阅时代理程序应在何处运行后，如果您指定订阅应自动同步并且您没有为远程代理程序激活配置 DCOM，则同步会失败。


如何配置现有的订阅以使用远程代理程序激活

配置现有订阅以使用远程代理程序激活

  1. 右击某个发布，然后选择"属性"命令。

  2. 单击"订阅"选项卡，然后选择"属性"按钮。

  3. 单击"同步"选项卡，然后选择"在订阅服务器运行分发代理程序"进行强制订阅或选择"在分发服务器运行分发代理程序"进行请求订阅。


如何监视复制代理程序性能（企业管理器）

监视复制代理程序性能

  1. 展开服务组，然后展开服务器。

  2. 右击复制监视器，然后单击"性能监视器"。

  3. 在"编辑"菜单中，单击"添加到图表"。

  4. 在"对象"列表中，选择要监视的 SQL Server 复制对象。

  5. 在"计数器"列表中，选择要使用的计数器。

监视复制代理程序会话细节

  1. 展开服务器组，然后展开分发服务器。

  2. 展开复制监视器，然后单击"代理程序"。

  3. 单击要监视的代理程序。

  4. 右击详细信息窗格中的行，然后单击"代理程序历史记录"。

  5. 在会话列表中选择会话，然后单击"会话细节"。


如何创建复制代理程序配置（企业管理器）

创建复制代理程序配置

  1. 展开服务器组，然后展开分发服务器。

  2. 在"工具"菜单中指向"复制"子菜单，然后单击"配置发布、订阅服务器和分发"命令。

  3. 单击"代理程序配置"，单击代理程序类型的选项卡以获取新的配置，然后单击"复制选定的配置"。

  4. 输入新配置的名称以及可选的描述，单击您要更改的参数，然后输入新值。

设置复制代理程序类型的默认配置

  1. 展开服务器组，然后单击分发服务器的名称。

  2. 在"工具"菜单中指向"复制"子菜单，然后单击"配置发布、订阅服务器和分发"命令。

  3. 单击"分发服务器"，单击"代理程序配置"，然后单击复制代理程序类型的选项卡。

  4. 选择用来作为默认配置的配置旁边的"默认"列。

  5. 选择"将全部的现有类型代理程序更改为使用选定的配置"选项，以便将新的默认配置应用到所有现有的类型代理程序。清除该选项将会使新的默认配置仅应用到在该点之前创建的新代理程序中。

查看或修改复制代理程序配置

  1. 依次展开服务器组、服务器，然后展开复制监视器。

  2. 展开 Publisher，展开将修改配置的发布服务器名称，然后单击发布。

  3. 在详细信息窗格中，右击代理程序或订阅，然后单击"代理程序配置"命令。

  4. 选择代理程序配置文件，单击"查看详细信息"，然后输入要更改的参数值。如果创建了代理程序配置文件，可单击"修改"以修改该代理程序的参数。

说明 不能删除系统配置文件，如果配置文件正在被任何代理程序使用，则无法删除这个配置文件。

删除复制代理程序配置

  1. 展开服务器组，然后单击分发服务器的名称。

  2. 在"工具"菜单中指向"复制"子菜单，然后单击"配置发布、订阅服务器和分发"命令。

  3. 单击"分发服务器"选项卡，单击"代理程序配置"，然后单击该复制代理程序类型的选项卡。

  4. 选择要删除的配置，然后单击"删除配置"。


复制和异类数据源（企业管理器）

Microsoft® SQL Server™ 2000 提供某些能力，可以将数据复制到异类数据源，条件是这些异类数据源在 Microsoft Windows® 2000、Microsoft Windows NT® Server 4.0 或 Windows 98 操作系统上提供 32 位的 ODBC 或 OLE DB 驱动程序。此外，SQL Server 2000 可以接收某些数据复本，这些数据复本是从 Microsoft Access、Microsoft Exchange、Oracle、DB2 Universal、DB2/MVS，以及 DB2 AS400 复制而来的。

异类订阅服务器

发布到异类数据源允许那些拥有不同数据库的公司可以继续将 SQL Server 2000 提供给那些使用其它数据库的个人或办公室。

将数据发布到异类数据源最简单的方法就是使用 ODBC，并且创建一个从发布服务器到 ODBC 订阅服务器的强制订阅。

异类发布服务器

SQL Server 2000 可以订阅那些从 Oracle、DB2、Access 以及其它数据源复制过来的快照或事务数据。这样，如果有的公司计划利用 SQL Server 来布署大的数据库或数据仓库，或者想布署 Internet 及 Intranet 应用程序，那么这些公司就可以访问各种数据源。因此，可以使用复制将那些数据合并进 SQL Server 2000，然后将它们放入数据集市、数据仓库或多维数据库，这些数据集市、数据仓库或多维数据库是专门为 SQL Server 2000 Analysis Services 设计的。

若要执行由异类数据源发布到 SQL Server 2000 应用程序的快照或事务复制，请使用第三方软件或使用通过 SQL-DMO 和复制分发服务器接口生成的应用程序来配置 SQL Server。

有关更多信息，请参阅从异类数据源对复制编程。


如何发布到异类订阅服务器（企业管理器）

  1. 展开服务器组，然后展开发布服务器。

  2. 在"工具"菜单上指向"复制"子菜单，然后单击"创建和管理发布"命令。

  3. 在"数据库和发布"列表中，单击从中创建发布的数据库，然后单击"创建发布"。

  4. 当提示您指定将使用发布的订阅服务器类型时，请选择"将不会成为 SQL Server 的一个或多个订阅服务器"。

  5. 完成向导中的步骤。

  6. 在"工具"菜单中，指向"复制"子菜单，然后单击"配置发布、订阅服务器和分发"命令。

  7. 单击"订阅服务器"选项卡。

  8. 单击"新订阅服务器"，然后单击数据源的类型。

  9. 选择异类订阅服务器，如果需要，则指定登录信息。


如何使 Jet 4.0 数据库成为订阅服务器（企业管理器）

  1. 展开服务器组，然后展开 Jet 订阅服务器将订阅的发布的发布服务器。

  2. 在"工具"菜单中，指向"复制"子菜单，然后单击"配置发布、订阅服务器和分发"命令。

  3. 在"订阅服务器"选项卡中，单击"新订阅服务器"按钮。

  4. 选择"Microsoft Jet 4.0 数据库 (Microsoft Access)"。

  5. 从显示的 Microsoft ®Jet 4.0 数据库列表中选择新的订阅服务器。输入登录名，或者输入 Microsoft Jet 数据库的密码。Microsoft Jet 数据库不需要存在。如果数据库是新的或不安全，则必须输入 admin 作为登录名。

  6. 如果数据库没有列出，则单击"添加"按钮。在"链接服务器名称"框中，输入链接服务器的名称（例如，输入 Jet 数据库的名称）。

  7. 在"数据库路径"中，输入数据库的路径和文件名。如果数据库和分发服务器位于同一台服务器上，则您可以在路径中使用本地驱动器号。如果数据库与分发服务器不在同一台服务器中，则输入 UNC 路径。如果数据库不存在，则在初始化订阅时会自动创建数据库。


如何创建 Jet 4.0 订阅服务器的发布（企业管理器）

  1. 展开服务器组，然后展开发布服务器。

  2. 在"工具"菜单上指向"复制"子菜单，然后单击"创建和管理发布"命令。

  3. 在"数据库和发布"列表中，单击从中生成发布列表的数据库，然后单击"创建发布"

  4. 遵循向导中的步骤。

  5. 如果创建事务发布，则当询问"什么类型的订阅服务器将订阅此发布"时，请选择"将不会成为运行 SQL Server 的服务器的一个或多个订阅服务器"。

  6. 如果创建合并发布，则当询问"什么类型的订阅服务器将订阅此发布"时，请选择"将成为 Microsoft Jet 4.0 数据库的一些订阅服务器"。

  7. 遵循向导中的其余步骤。


如何将强制订阅添加到 Jet 4.0 订阅服务器（企业管理器）

  1. 展开服务器组，然后展开发布服务器。

  2. 在"工具"菜单中，指向"发布"，然后单击"强制其它服务器订阅"。

  3. 展开包含将添加强制订阅的发布的数据库。

  4. 单击该发布，然后单击"强制新订阅"。

  5. 遵循向导中的步骤。

  6. 如果是对合并发布的订阅，则当要求设置订阅优先级时，单击对应于 Microsoft® Access 已知订阅类型的优先级。如果您希望订阅是访问本地或匿名副本，则选择"使用创建这个订阅的发布服务器的优先级设置"。如果您希望订阅成为访问全局副本，则选择"使用下列优先级来解决冲突"并设置需要的优先级。

  7. 遵循向导中的其余步骤。


复制安全性（企业管理器）

复制安全性是设计和执行分布式应用程序的重要部分。复制将网络其它地方发生的数据变化应用到您服务器上的数据库中，反之亦然。

复制数据的分散性增加了管理的复杂性，或者限制了对数据的访问。Microsoft® SQL Server™ 2000 复制使用安全机制的组合，以保护您应用程序中的数据和商务逻辑:

  • 角色要求

    通过映射用户登录名到特定的 SQL Server 2000 角色，SQL Server 2000 允许用户只执行授权给该角色的复制活动和数据库活动。复制将某些权限授予 sysadmin 固定服务器角色、db_owner 固定数据库角色、当前登录以及 public 角色。例如，只有作为 sysadmin 服务器角色的成员才可以配置复制。

  • 分发服务器管理链接安全性

    SQL Server 2000 在分发服务器与远程发布服务器之间提供安全的管理链接。发布服务器可被看作受信任或不受信任的服务器。

  • 快照文件夹安全性

    操作系统或 FTP 服务阻止用户访问服务器上的特定文件。用户必须有效登录，才能读取或写入复制进程中使用的文件。

  • 已注册的订阅服务器

    SQL Server 2000 使您得以将对发布的访问限制在发布服务器已知或匿名的注册订阅服务器中，或者限制在发布访问列表中含有登录的订阅服务器中。SQL Server 2000 使用异类订阅服务器的链接服务器定义以保护带有异类数据源的数据复制。

  • 发布访问列表

    通过支持每一台服务器上的发布访问列表 (PAL)，SQL Server 2000 使您得以确定能够访问登录的发布。SQL Server 2000 用默认的登录名创建 PAL，用户可根据需要增加或删除登录者。

  • 代理程序登录安全性

    通过支持代理程序登录安全性，SQL Server 2000 要求每个用户提供一个有效的登录帐户以便连接到服务器。当与发布服务器、分发服务器和订阅服务器连接时，复制代理程序必须使用有效的登录帐户。但是，当同时与不同的服务器连接时，代理程序也可以使用不同的登录和安全模式。

  • 即时更新订阅服务器安全性

    对于即时更新订阅服务器，SQL Server 2000 复制将安全机制应用到 Publisher-RPC 链接和发布服务器存储过程中。

当一起使用时，这些安全机制可为您应用程序中的数据和商务逻辑提供最高级别的安全保护。


如何更改请求订阅的登录属性

  1. 在"工具"菜单中，指向"复制"子菜单，然后单击"请求订阅"命令。

  2. 单击"属性"，然后在"同步"选项卡上，单击"分发代理程序属性"。

  3. 在"步骤"选项卡中，单击"编辑"按钮。

  4. 在命令行中，编辑 SubscriberSecurityMode 和 SubscriberLogin 的值。


如何在分发服务器上添加或更改密码

在分发服务器上添加或更改密码

  1. 展开服务器组，然后单击分发服务器的名称。

  2. 在"工具"菜单中指向"复制"子菜单，然后单击"配置发布、订阅服务器和分发"命令。

  3. 单击"分发服务器"选项卡。

  4. 输入新的或更改后的密码。


授权或废除对发布的访问权

授权或废除对发布的访问权

  1. 展开服务器组，然后单击发布服务器的名称。

  2. 在"工具"菜单上指向"复制"子菜单，然后单击"创建和管理发布"命令。

  3. 展开数据库，然后单击发布。

  4. 单击"属性和订阅"。

  5. 单击"发布访问列表"选项卡。

  6. 添加或删除访问发布的登录。

说明 如果使用远程分发服务器，则新的登录必须同时存在于发布服务器和分发服务器的发布访问列表中。如果请求订阅登录不在发布访问列表之中，则在订阅服务器上会出现一个错误。


数据转换服务

本节包含以下操作的过程：

  • 使用数据转换服务 (DTS) 工具。

  • 使用 DTS 连接、任务、转换和工作流元素生成 DTS 包。

  • 管理包。


DTS 工具

本节包含使用数据转换服务 (DTS) 工具的过程。


如何在 DTS 设计器中创建到 Northwind 的连接（企业管理器）

在 DTS 设计器中创建到 Northwind 的连接

  1. 从"连接"工具栏，将用于 SQL Server 的 Microsoft® OLE DB 提供程序连接拖到数据转换服务 (DTS) 设计器设计表上。

  2. 在"新建连接"框中键入 Cn1。

  3. 在"数据源"列表中，单击"用于 SQL Server 的 Microsoft SQL OLE DB 提供程序"。

  4. 在"服务器"列表中，单击"本地"。

  5. 执行下列操作中的一种：
    • 单击"使用 Windows 身份验证"。

    -或-

    • 单击"使用 SQL Server 身份验证"，然后输入用户名及密码。
  6. 在"数据库"列表中，单击"Northwind"。


如何使用 DTS 设计器再创建一个到 Northwind 数据库的连接（企业管理器）

使用 DTS 设计器再创建一个到 Northwind 数据库的连接

  1. 从"连接"工具栏，将第二个用于 SQL Server 的 Microsoft® OLE DB 提供程序连接拖到数据转换服务 (DTS) 设计器设计表上。

  2. 在"新建连接"框中键入 Cn2。

  3. 象为第一个连接所执行的操作那样，完成其余的属性选择。


如何使用 DTS 设计器从 Northwind 表复制数据（企业管理器）

使用 DTS 设计器从 Northwind 表复制数据

  1. 在数据转换服务 (DTS) 设计器设计表上，按住 CTRL 键并单击"Cn1"，然后按住 CTRL 键并单击"Cn2"。

按住 CTRL 键单击操作所采用的次序就是 DTS 设计器引导数据流所采用的次序。

  2. 在"任务"工具栏上，单击"转换数据任务"。

这时会出现一个箭头，从"Cn1"指向"Cn2"。

  3. 右击"转换数据"箭头，然后单击"属性"命令。

  4. 在"描述"框中键入"Copy Categories data"，然后在"表/视图"列表中，单击"[Northwind].[dbo].[Categories]"。

  5. 单击"目的"选项卡，然后单击"创建"按钮。

创建一个新表以接收源数据的复本。

  6. 在"创建目的表"对话框中，在"SQL 语句"框中，将插入点定位在第一行，然后编辑 CREATE TABLE 语句，使其格式如下：

CREATE TABLE [Categories2]

  7. 单击"转换"选项卡并查看两个表中的源列和目的列之间的映射。然后单击"确定"按钮，退出"转换数据任务属性"对话框并保存设置。

    说明 在这个示例中，您是在复制数据，但也可以使用该对话框映射转换或操作列。


如何配置执行 SQL 任务除去并重新创建目的表（企业管理器）

配置执行 SQL 任务除去并重新创建目的表

  1. 从"任务"工具栏，将执行 SQL 任务拖到数据转换服务 (DTS) 设计器设计表上。

  2. 在"描述"框中键入"Drop Dest Table"。

在配置任务之后，该文本将显示在设计表中的"执行 SQL 任务"图标下。

  3. 在"现有连接"列表中，单击"Cn2"。

    在本示例中，可以使用两个连接中的任何一个，这是因为 Cn1 和 Cn2 都连接到了相同的数据库。但是，使用目的连接更好一些。

  4. 在"SQL 语句"文本框中，键入下列 SQL 代码：
    IF EXISTS (SELECT * from sysobjects
   WHERE id = object_id(N'[Northwind].[dbo].[Categories2]') AND
   OBJECTPROPERTY(id, N'IsUserTable') = 1)
   DROP Table [Northwind].[dbo].[Categories2]
GO

CREATE TABLE [Northwind].[dbo].[Categories2]
(
   [CategoryID]  [int]  IDENTITY (1,1)  NOT NULL  PRIMARY KEY,
   [CategoryName]  [nvarchar]  (15)  NOT NULL,
   [Description]  [ntext],
   [Picture]  [image]
)
GO

这段 SQL 代码检查目的表是否存在。如果并不存在该表，那么就创建它。如果存在该表，那么将其除去然后重新创建它。如果没有这个包步骤，那么每次运行包时，来自源表的相同数据就会被追加到目的表。

  5. 单击"确定"按钮以保存执行 SQL 任务的配置设置及 SQL 代码。


如何在执行 SQL 任务中配置工作流（企业管理器）

在执行 SQL 任务中配置工作流

  1. 在数据转换服务 (DTS) 设计表上，按住 CTRL 键并单击"除去目的表"（创建的执行 SQL 任务），然后按住 CTRL 键并单击"Cn1"（第一个 Northwind 连接）。

  2. 单击"工作流"菜单，然后单击"成功时"命令。

这时出现一个绿色的带有条纹的箭头，从"除去目的表"指向"Cn1"。该箭头是一个条件优先约束。它引导工作流，以便必须成功地执行第一个任务后，才能运行下一个任务（转换数据任务）。


如何将 DTS 包保存到 SQL Server msdb 表（企业管理器）

将 DTS 包保存到 SQL Server msdb 表

  1. 在数据转换服务 (DTS) 设计器中的"包"菜单上，单击"保存"命令。

  2. 在"包名"框中键入"Northwind Package"。

  3. 在"位置"列表中，单击"SQL Server"。


如何访问 DTS 包模板（企业管理器）

访问 DTS 包模板

  1. 在 SQL Server 企业管理器中，右击"数据转换服务"节点，指向"所有任务"，然后单击"打开模板"命令。

  2. 在"选择文件"对话框中，双击所需的模板（.dtt 文件）。


如何创建和保存 DTS 包模板（企业管理器）

创建和保存 DTS 包模板

  1. 在数据转换服务 (DTS) 设计器中，右击 DTS 包的设计表，单击"脱接编辑"并存根模板用户以后要输入的属性值。根据需要重复此步骤。

    通过用标签或说明替换属性值，或者通过删除当前值来存根属性值。

  2. 右击该设计表，单击"添加文本批注"，然后添加标签和说明。根据需要重复此步骤。

  3. 在"包"菜单上单击"保存"命令。

  4. 在"包名"框中键入模板的名称，也可以输入任意密码。

  5. 在"位置"列表中单击"结构化存储文件"。

  6. 在"文件名"框中键入包模板的名称并将文件后缀由 .dts 改为 .dtt。

  7. 单击浏览（"..."）按钮，选择保存模板的目录位置。


DTS 包元素

以下是添加、配置和使用数据转换服务 (DTS) 任务、转换、连接和工作流项目的过程。


如何创建转换数据任务（企业管理器）

创建转换数据任务

  1. 在数据转换服务 (DTS) 设计器的设计表上，单击要用作源的连接，然后按住 CTRL 键并单击要用作目的的连接。

    在配置转换数据任务之前，必须定义源连接和目的连接。

  2. 从"任务"工具栏中，将转换数据任务拖动到设计表中。

请参见

DTS 连接

转换数据的任务

转换数据任务


如何为转换数据任务配置连接（企业管理器）

配置转换数据任务的连接

  1. 指向数据转换服务 (DTS) 设计器设计表中的转换数据任务直到光标改变，然后双击打开"转换数据任务属性"对话框。

  2. 在"源"选项卡上键入对该任务的描述。

  3. 在"连接"下执行下列操作之一：
    • 单击"表/视图"并从列表中选择表或视图。

    • 单击"SQL 查询"。可以在框中输入查询文本，也可单击"生成查询"按钮通过 DTS 查询设计器创建查询。如果使用输入参数来创建查询，则单击"参数"指派 DTS 包全局变量的参数。
  4. 单击"目的"选项卡，然后执行下列操作之一：
    • 在"表名"列表中选择目的表。

    • 通过单击"创建"按钮并编辑"创建目的表"对话框中的 CREATE TABLE 脚本来创建一个新表。

请参见

DTS 连接

DTS 转换

转换数据的任务

转换数据任务


如何为转换数据任务配置新的转换（企业管理器）

为转换数据任务配置新的转换

  1. 在配置了源连接及目的连接之后，单击"转换"选项卡。

  2. 执行下列操作之一：
    • 如果所需的列还没有映射到另一个转换中，则单击"新建"按钮。

    • 如果所需的列已经映射到其它转换中，则单击该转换的映射行并单击"删除"按钮，然后单击"新建"按钮。
  3. 在"创建新转换"对话框中单击希望添加的转换类型。出现"转换选项"对话框。

  4. 单击"源列"选项卡，然后使用箭头按钮选择转换的列。

  5. 单击"目的列"选项卡，然后使用箭头按钮选择转换的列。

  6. 单击"常规"选项卡，单击"属性"，然后接受或编辑选定转换的属性。

  7. 对于要创建的每一个转换，重复第 2 步到第 6 步。

请参见

映射列转换

DTS 转换

转换数据的任务

转换数据任务


如何激活多阶段数据抽取功能（企业管理器）

激活多阶段数据抽取功能

  1. 在 SQL Server 企业管理器控制台树中，右击"数据转换服务"，然后单击"属性"命令。

  2. 在"设计器"下，选择"在 DTS 设计器中显示多阶段抽取"复选框。

请参见

多阶段数据抽取功能


如何使用 ActiveX 脚本添加多阶段数据抽取转换功能（企业管理器）

使用 ActiveX 脚本添加多阶段数据抽取转换功能

  1. 在激活了多阶段数据抽取功能并配置了源连接和目的连接之后，单击"转换"选项卡。

  2. 在"阶段筛选"列表中单击要添加的数据抽取阶段。

"阶段筛选"列表显示为特定的数据抽取阶段而配置的所有转换。在默认情况下，"行转换"阶段已选定。

  3. 执行下列操作之一：
    • 如果所需的列还没有映射到另一个转换中，则单击"新建"按钮。

    • 如果所需的列已经映射到其它转换中，则单击该转换的映射行并单击"删除"按钮，然后单击"新建"按钮。
  4. 在"创建新转换"对话框中单击"ActiveX 脚本"按钮。

  5. 单击"源列"选项卡，然后使用箭头按钮选择转换的列。

  6. 单击"目的列"选项卡，然后使用箭头按钮将某列包含在转换中。

  7. 单击"常规"选项卡，并单击"属性"，然后单击"阶段"选项卡。

  8. 选择将为其添加 Microsoft® ActiveX® 脚本函数的数据抽取阶段，然后为选定阶段在它们各自的框中键入这些函数的名称。

  9. 在"ActiveX 脚本"文本框中输入每个函数的 ActiveX 脚本代码。

    在"ActiveX 脚本"文本框中指定的函数名称必须与在"阶段"选项卡上输入的名称相匹配。

请参见

ActiveX 脚本转换

多阶段数据抽取功能

转换数据的任务


如何调用自定义一个或多个数据抽取阶段的 COM 对象（企业管理器）

调用自定义一个或多个数据抽取阶段的 COM 对象

  1. 在激活了多阶段数据抽取功能并配置了源连接和目的连接之后，单击"转换"选项卡。

  2. 在"阶段筛选"列表中单击要自定义的数据抽取阶段。

    "阶段筛选"列表显示为特定的数据抽取阶段而配置的所有转换。在默认情况下，"行转换"阶段已选定。

  3. 执行下列操作之一：
    • 如果所需的列还没有映射到另一个转换中，则单击"新建"按钮。

    • 如果所需的列已经映射到其它转换中，则单击该转换的映射行并单击"删除"按钮，然后单击"新建"按钮。
  4. 在"创建新转换"对话框中单击与要调用的自定义转换（COM 对象）相对应的项。

    说明 如果该 COM 对象在计算机上已安装但未显示于"创建新转换"对话框中，并且已启用数据转换服务 (DTS) 高速缓存，就必须刷新该高速缓存。在 SQL Server 企业管理器中，右击"数据转换服务"节点并单击"属性"命令。在"高速缓存"下，单击"刷新高速缓存"按钮。

  5. 单击"源列"选项卡，然后使用箭头按钮选择转换的列。

  6. 单击"目的列"选项卡，然后使用箭头按钮将列包含在转换中。

  7. 单击"阶段"选项卡，然后单击所提供的、将调用自定义转换的数据抽取阶段。

    说明 如果自定义转换中包含用户接口，则可以单击"常规"选项卡并单击"属性"按钮以输入有关转换的任何附加信息。

请参见

多阶段数据抽取功能

转换数据的任务


如何启用转换数据任务快速装载选项（企业管理器）

启用转换数据任务快速装载选项

  1. 在为转换数据任务配置了连接和转换后，单击"选项"选项卡。

  2. 选择"使用快速装载"复选框，然后选择希望使用的任何其它 Microsoft® SQL Server™ 快速装载选项。

    只有在把用于 SQL Server 的 Microsoft OLE DB 提供程序作为目的连接时，快速装载选项才会生效。

请参见

DTS 转换

转换数据的任务

转换数据任务


如何配置快速装载批处理选项（企业管理器）

配置快速装载批处理选项

  1. 在为转换数据任务配置了连接和转换后，单击"选项"选项卡。

  2. 选择"使用快速装载"复选框。

    只有在将用于 SQL Server 的 Microsoft® OLE DB 提供程序作为目的连接时，快速装载选项才会生效。

  3. 在"插入批处理大小"框中输入批处理大小的值。

  4. 如果希望在上一次批处理中（该批处理将在错误发生前复制）提交所有行，请选择"提交最终批处理"复选框。（可选）

  5. 在"最大错误计数"框中输入一个值以指定转换数据任务所检测的行级错误数加上在任务的数据抽取操作中止前必须超过的批处理失败数。

请参见

DTS 转换

转换数据的任务

转换数据任务


如何配置数据抽取异常错误文件（企业管理器）

配置数据抽取异常错误文件

  1. 在数据转换服务 (DTS) 设计表上，双击转换数据任务或数据驱动的查询任务。

    在配置转换数据任务之前，必须定义源连接和目的连接。

  2. 单击"选项"选项卡。

  3. 在"异常错误文件"下的"名称"框内，键入想将其用作异常错误文件的文本文件的文件路径，或单击浏览（"..."）按钮定位文件。

    如果输入的文件不存在，就会在运行与该转换任务相关的步骤时创建该文件。

  4. 若想使用 Microsoft® SQL Server™ 2000 数据抽取异常错误文件选项，请在"文件类型"下，清除"7.0 格式"复选框并选择要生成的异常错误文件。（可选）

  5. 在"文件格式"下选择异常错误文件的任何附加选项。

请参见

DTS 连接

转换数据的任务

转换数据任务


如何向 DTS 包添加 DTS 任务（企业管理器）

在 DTS 设计器中向 DTS 包添加 DTS 任务

  • 从"任务"工具栏中，将任务拖动到数据转换服务 (DTS) 的设计表上。

请参见

DTS 任务


如何向 DTS 包添加大容量插入任务（企业管理器）

在 DTS 设计器中向 DTS 包添加大容量插入任务

  1. 从"连接"工具栏中将用于 SQL Server 的 Microsoft® OLE DB 提供程序连接拖动到数据转换服务 (DTS) 设计表上，并对该连接进行配置。

    说明 大容量插入任务需要一个用于 SQL Server 的 Microsoft OLE DB 提供程序连接。如果已在包中对这样的连接进行了配置，则可以跳过步骤 1。

  2. 从"任务"工具栏中，将大容量插入任务拖至该设计表上。

请参见

大容量插入任务


如何向 DTS 包添加执行 SQL 任务（企业管理器）

在 DTS 设计器中向 DTS 包添加执行 SQL 任务

  1. 从"连接"工具栏，将一个连接拖动到数据转换服务 (DTS) 设计表上，并配置该连接。

    说明 执行 SQL 任务要求一个连接。如果已在包中配置了某个连接，并且可通过该连接访问数据源，则可跳过步骤 1。

  2. 从"任务"工具栏中，将执行 SQL 任务拖至设计表上。

请参见

执行 SQL 任务


如何执行带有输入参数的存储过程（企业管理器）

使用执行 SQL 任务执行带有输入参数的存储过程

  1. 在"执行 SQL 任务属性"对话框的"SQL 语句"框中键入参数化 SQL 存储过程语句。例如：
    exec byRoyalty ?
  2. 单击"参数"，再单击"输入参数"选项卡，然后指派该参数的全局变量及其值。


如何将行值保存到全局变量中（企业管理器）

将行值保存到全局变量中

  1. 从"连接"工具栏中，将用于 SQL Server 的 Microsoft® OLE DB 提供程序的连接拖动到数据转换服务 (DTS) 设计表上。

  2. 在"连接属性"对话框内的"数据库"列表上单击"pubs"。

  3. 从"任务"工具栏中，将执行 SQL 任务拖至设计表上。

  4. 在"执行 SQL 任务属性"对话框的"现有连接"列表中，单击刚刚创建的"pubs"连接。

  5. 在"SQL 语句"框中键入 SQL 代码。例如：
    SELECT *
FROM titleauthor
WHERE (royaltyper = '40')
  6. 单击"参数"，再单击"创建全局变量"，然后输入全局变量的名称。例如：o_au_id、o_title_id、o_au_order 和 o_royaltyper。

  7. 单击"输出参数"选项卡，再单击"行值"，然后在"输出全局变量"列中单击某行并从包含列数据的列表中选择全局变量。

    当将值保存到全局变量中时，可以跳过一列。例如，如果不想存储 title_id 列的值，可对"输出全局变量"列进行修改，将 title_id 列的值指派为<无>。

    说明 如果包已经执行，而且以前已有一个值返回到 o_title_id 全局变量中，那么把 title_id 列设置为<无>，就无法重置或无法将 o_title_id 全局变量的值设置为空。全局变量包含上次设置的值。有关更多信息，请参阅在 DTS 包中使用全局变量。


如何检索行值数据（企业管理器）

检索行值数据

  1. 从"任务"工具栏中将 Microsoft® ActiveX® 脚本任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"ActiveX 脚本属性"对话框中的 Function Main() 语句之后，键入下列 Microsoft Visual Basic® Scripting Edition (VBScript) 代码：
    MsgBox "The author ID is " & DTSGlobalVariables("o_au_id").value
MsgBox "The title ID is " & DTSGlobalVariables("o_title_id").value
MsgBox "The au_ord is " & DTSGlobalVariables("o_au_ord").value
MsgBox "The royalty is " & DTSGlobalVariables("o_royaltyper").value

Main = DTSTaskExecResult_Success
  3. 在设计表上单击执行 SQL 任务，然后按住 CTRL 键并单击ActiveX 脚本任务。

  4. 在"工作流"菜单上单击"成功时"或"完成时"。


如何将整个行集保存到全局变量中（企业管理器）

使用执行 SQL 任务将 SELECT 语句的整个结果集存入全局变量

  1. 从"连接"工具栏中，将用于 SQL Server 的 Microsoft® OLE DB 提供程序连接拖至设计表上。

  2. 在"数据库"列表中，单击"pubs"。

  3. 从"任务"工具栏中将执行 SQL 任务拖动到数据转换服务 (DTS) 设计表中。

  4. 在"执行 SQL 属性"对话框的"现有连接"列表中，单击刚刚创建的 pubs 连接。

  5. 在"SQL 语句"框中键入下列代码：
    SELECT *
FROM titleauthor
  6. 单击"参数"，然后单击"创建全局变量"。

  7. 在"名称"列表中键入 Authors，然后在"类型"列表中，单击"<其它>"。将"值"框保留为空白。

  8. 单击"输出参数"选项卡，再单击"行集"，然后在"输出参数类型"列表中选择 Authors 全局变量。

    该过程指派所有从 SELECT 语句返回的记录都存储在 Authors 全局变量中。


如何检索存储于全局变量中的行集数据（企业管理器）

使用执行 SQL 任务检索存储于全局变量中的行集数据

  1. 从"任务"工具栏中将 Microsoft® ActiveX® 脚本任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"ActiveX 脚本属性"对话框中，在 Function Main() 语句之后输入下列 Microsoft Visual Basic® Scripting Edition (VBScript) 代码：
    dim countr
dim RS
set RS = CreateObject("ADODB.Recordset")
set RS = DTSGlobalVariables("Authors").value

for countr = 1 to RS.RecordCount
    MsgBox "The author ID is " & RS.Fields("au_id").value
    RS.MoveNext
Next

Main = DTSTaskExecResult_Success
  3. 在设计表上单击执行 SQL 任务，然后按住 CTRL 键并单击 ActiveX 脚本任务。

  4. 在"工作流"菜单上，单击"成功时"或"完成时"命令。

    此时显示从 SELECT 语句中返回的每一行的 au_id 列。


如何使用消息队列任务发送消息（企业管理器）

使用消息队列任务发送消息

  1. 从"任务"工具栏中，将消息队列任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息队列任务属性"对话框的"描述"框中键入在设计表上标识该任务的标签。

  3. 在"消息"列表中单击"接收消息"。

  4. 在"队列"框中键入 computer_name\queue_type$\queue_name 组合的名称，用以标识要从中读取消息的队列。

  5. 单击"添加"，然后在"消息类型"列表中，选择一种类型的消息队列，并对每条消息进行配置：
    • 选择"字符串消息"，并在"字符串消息"框中键入消息。

    • 选择"数据文件消息"，并在"文件名"框中键入要将消息发送到的文件路径，或单击浏览（"..."）按钮定位文件。

    • 选择"全局变量消息"。若要添加现有的包全局变量，请单击"新建"，然后在名称列表中单击一个全局变量。若要创建包中不存在的并要用作消息的全局变量，请单击"创建全局变量"。


如何使用消息队列任务接收字符串消息（企业管理器）

使用消息队列任务接收字符串消息

  1. 从"任务"工具栏中，将消息队列任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息队列任务属性"对话框的"描述"框中输入在设计表上标识该任务的标签。

  3. 在"消息"列表中单击"接收消息"。

  4. 在"队列"框中输入 computer_name\queue_type$\queue_name 组合的名称，用以标识要从中读取消息的队列。

  5. 在"消息类型"列表内单击"字符串消息"，并在"比较"下单击筛选消息的选项。

  6. 如果在"比较字符串"框中单击"完全匹配"、"忽略大小写"或"包含"，则键入查找文本。

  7. 选中"从消息队列删除"复选框以删除从队列中接收的任何消息。清除该复选框可使消息在任务完成后留在队列中。

  8. 清除"之后超时"复选框以无限期等待可接受的消息，或选择"之后超时"复选框以输入超时间隔。

    超时间隔可以是 1 至 9999 间的任意值（以秒为单位）。


如何使用消息队列任务接收数据文件消息（企业管理器）

使用消息队列任务接收数据文件消息

  1. 从"任务"工具栏，将消息队列任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息队列任务属性"对话框的"描述"框中键入在设计表上标识该任务的标签。

  3. 在"消息"列表内单击"接收消息"。

  4. 在"队列"框内，输入 computer_name\queue_type$\queue_name 组合的名称，用以标识要从中读取消息的队列。

  5. 在"消息类型"列表中单击"数据文件消息"。

  6. 在"将文件另存为"框中输入计算机上文件或目录的路径，或者单击浏览（"..."）按钮定位文件。

  7. 在"仅接收来自特定包或版本的消息"下单击一个筛选选项。

  8. 如果选择"从包"或"从版本"，则将"标识符"设置为全局唯一标识符 (GUID) 字符串，用以标识适当的 DTS 包或版本。使用浏览（"..."）按钮搜索可用的包和版本。

  9. 清除"之后超时"复选框以无限期等待可接收的消息，或选择"之后超时"复选框以输入超时间隔。超时间隔可以是 1 至 9999 之间的任意值（以秒为单位）。


如何使用消息队列任务接收全局变量消息（企业管理器）

使用消息队列任务接收全局变量消息

  1. 从"任务"工具栏，将消息队列任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息队列任务属性"对话框的"描述"框中键入在设计表上标识该任务的标签。

  3. 在"消息"列表内单击"接收消息"。

  4. 在"队列"框中输入 computer_name\queue_type$\queue_name 组合的名称，用以标识要从中读取消息的队列。

  5. 在"消息类型"框中单击"全局变量消息"。

  6. 在"仅从特定的包或版本接收消息"下，单击一个筛选选项。

  7. 如果选择"从包"或"从版本"，则将"标识符"设置为全局唯一标识符 (GUID) 字符串，用以标识适当的 DTS 包或版本。使用浏览（"..."）按钮搜索可用的包和版本。

  8. 清除"之后超时"复选框可无限期等待可接受的消息。选择"之后超时"复选框以输入超时间隔。超时间隔可以是 1 至 9999 之间的任意值（以秒为单位）。


如何配置请求发货情况任务（企业管理器）

配置请求发货情况任务

  1. 从"任务"工具栏，将消息队列任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息队列任务属性"对话框的"描述"框中键入"Ask For Facts"。

  3. 在"消息"框内单击"发送消息"。

  4. 在"队列"框中输入 computer_name\queue_type$\queue_name 组合的名称，用以标识这些消息将发往的位置。

  5. 在"要发送的消息"下，单击"新建"，然后在"消息类型"框中单击"字符串消息"。

  6. 在"字符串消息"框中键入"Summarize shipments"。

  7. 在设计表上，右击"Ask For Facts"，指向"工作流"，然后单击"工作流属性"命令。

  8. 单击"选项"选项卡，然后清除以下复选框：
    • 有事务时联接

    • 成功完成此步骤时提交事务

    • 失败时回滚事务


如何配置等待触发任务（企业管理器）

配置等待触发任务

  1. 从"任务"工具栏，将"消息队列"任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息队列任务属性"对话框的"描述"框中键入"Wait for Trigger"。

  3. 在"消息"列表内单击"接收消息"。在"队列"框中输入与"Ask For Facts"任务内相同的 computer_name\queue_type$\queue_name 组合。

  4. 在"消息类型"列表中单击"字符串消息"。

  5. 在"比较"下单击"完全匹配"，然后在"比较字符串"框中键入"Summarize shipments"。

  6. 选择"从消息队列中删除"复选框。

  7. 在设计表上右击"Wait for Trigger"，指向"工作流"，然后单击"工作流属性"命令。

  8. 在"工作流属性"对话框内单击"选项"选项卡，然后清除以下复选框：
    • 有事务时联接

    • 成功完成此步骤时提交事务

    • 失败时回滚事务


如何创建并配置添加新职员（企业管理器）

创建并配置添加新职员包

  1. 在 SQL Server 企业管理器控制台树中，右击"数据转换服务"节点，然后单击"新建包"命令。

  2. 在"包"菜单上单击"保存"命令。

  3. 在"包名称"框内键入"Add New Employees"，然后在"位置"列表中单击"SQL Server"。

  4. 右击数据转换服务 (DTS) 设计表，然后单击"包属性"命令。

  5. 单击"高级"选项卡，选择"使用事务"复选框，然后清除"成功完成包时提交"复选框。

  6. 单击"日志"选项卡，然后在"错误"处理下清除"第一次出错时使包失败"复选框。


如何配置新职员任务（企业管理器）

配置新职员任务

  1. 从"任务"工具栏，将"消息队列"任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息队列任务属性"对话框的"描述"框中键入"New Employee"。

  3. 在"消息"框内单击"接收消息"。

  4. 在"队列"框内输入 computer_name\queue_type$\queue_name 组合的名称，用以标识将接收全局变量消息的队列。

  5. 在"消息类型"列表内单击"全局变量消息"，然后单击"无筛选"。

  6. 指定下列选项：
    • 选择"从消息队列删除"复选框，否则该 DTS 包将因重复尝试添加相同的职员而无限期循环。

    • 选择"之后超时"复选框以在清空队列后强制包中止，然后在"秒"框内键入 1。
  7. 在设计表上右击"New Employee"，指向"工作流"，然后选择"工作流属性"。

  8. 在"工作流属性"对话框内单击"选项"选项卡，然后清除以下复选框：
    • 有事务时联接

    • 成功完成此步骤时提交事务

    • 失败时回滚事务


如何为全局变量消息配置转换数据任务（企业管理器）

为全局变量消息配置转换数据任务

  1. 单击"未使用"，然后按住 CTRL 键并单击"企业"。

  2. 在"任务"工具栏上单击"转换数据任务"，然后在数据转换服务 (DTS) 设计表上双击所得到的箭头。

  3. 在"数据转换属性"对话框中执行以下操作：
    1. 在"描述"框中键入"Insert One Employee"。

    2. 在"连接"下单击"SQL 查询"，然后键入"SELECT 'xxx' AS xxx"。

      这样就生成了一个带有一个行的源行集。因此，插入只能尝试一次。

  4. 单击"目的"选项卡，然后在"表名"列表内选择"职员"表。

  5. 单击"转换"选项卡，然后执行下列操作：
    1. 单击"全部删除"以清除任何默认的转换。

    2. 在"目的"列表内单击"EmployeeID"，然后按住 CTRL 键并单击"EmployeeName"。

    3. 单击"新建"按钮。
  6. 在"创建新转换"对话框中单击"ActiveX 脚本"按钮。

  7. 在"转换选项"对话框中单击"属性"按钮。

  8. 在"Active X 脚本转换属性"对话框的"入口函数"下键入下列代码：
    DTSDestination ("EmployeeID") = DTSGlobalVariables("ID")
DTSDestination("EmployeeName") = DTSGlobalVariables("Name")
  9. 右击"转换数据"任务，然后单击"工作流属性"。

  10. 在"工作流属性"对话框内单击"选项"选项卡，执行下列操作：
    • 选择"有事务时联接"复选框。

    • 选择"成功完成此步骤时提交事务"复选框。

    • 清除"失败时回滚事务"复选框。
  11. 单击"优先"选项卡，然后添加一个新项，其中的"源步骤"设置为"New Employee"，"优先"设置为"成功"。


如何配置记录坏的更新任务（企业管理器）

配置记录坏的更新任务

  1. 从"任务"工具栏，将"消息队列"任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息队列任务属性"对话框内"描述"框中键入"Log Bad Update"。

  3. 在"消息"列表中，单击"发送消息"。

  4. 在"队列"框内输入 computer_name\queue_type$\queue_name 组合的名称用以标识坏的更新消息将发往的位置。

  5. 单击"添加"，然后在"消息类型"列表内单击"全局变量消息"。

  6. 通过执行下列操作添加全局变量 ID 和 Name：
    1. 单击"创建全局变量"。

    2. 在"全局变量"对话框的"变量"列表中的空白项下键入 ID，然后单击"新建"创建新项并输入 Name。

    3. 在"消息队列消息属性"对话框中单击"新建"，在"名称"下的框中单击，然后从列表中选择 ID。对全局变量 Name 重复该步骤。

      说明 在本应用程序中，Type 和 Value 的项不起作用。不需要输入值。

  7. 在设计表上右击"Log Bad Update"，指向"工作流"，然后单击"工作流属性"命令。

  8. 单击"选项"选项卡，然后执行下列操作：
    • 选择"有事务时联接"复选框。

    • 选择"成功完成此步骤时提交事务"复选框。

    • 清除"失败时回滚事务"复选框。
  9. 单击"优先"选项卡，然后添加一个新项，其中的"源步骤"设置为"Insert One Employee"，"优先"设置为"失败"。


如何配置一个循环任务（企业管理器）

配置一个循环任务

  1. 在数据转换服务 (DTS) 设计表上右击"New Employee"，指向"工作流"，然后单击"工作流属性"命令。

  2. 在"工作流属性"对话框内单击"选项"选项卡并注意"名称"框内该步骤的名称。

    有可能是 DTSStep_DTSMessageQueueTask_1。在过程的后面部分需要在另一个框内单击该名称。

  3. 从"任务"工具栏中，将动态属性任务拖动到设计表上。

  4. 在"动态属性任务属性"对话框的"描述"框中键入 Loop，然后单击"添加"。

  5. 在左窗格中显示的树中，展开"步骤"，然后展开 DTSStep_DTSMessageQueueTask_1（在步骤 2 中所注意的名称）。

  6. 在右窗格中"属性名称"下双击"ExecutionStatus"。

  7. 在"添加/编辑分配"对话框的"源"列表中，单击"常量"，然后在"常量"框中键入 1。

    1 是分配给 DTSStepExecStat_Waiting 的值。

  8. 在设计表上，右击"Loop"，指向"工作流"，然后单击"工作流属性"命令。

  9. 单击"优先"选项卡，然后添加一个新项，其中"源步骤"设置为"Insert One Employee"或"Log Bad Update"，"优先"设置为"成功"。


如何创建并配置装载开支包（企业管理器）

创建并配置装载开支包

  1. 在 SQL Server 企业管理器控制台树中，右击"数据转换服务"节点，然后单击"新建包"命令。

  2. 在"包"菜单上单击"保存"命令。

  3. 在"包名称"框中键入 Load Expenses。

  4. 右击数据转换服务 (DTS) 设计表，然后单击"包属性"。

  5. 单击"日志"选项卡，然后清除"第一次出错时使包失败"复选框。

  6. 单击"高级"选项卡，选择"使用事务"复选框，然后清除"成功完成包时提交"复选框。


如何配置电子表格等待任务（企业管理器）

配置电子表格等待任务

  1. 从"任务"工具栏，将消息队列任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息"列表内单击"接收消息"。

  3. 在"队列"框内输入 computer_name\queue_type$\queue_name 组合的名称，用以标识开支工作表将要发往的队列。

  4. 在"消息类型"列表内单击"数据文件消息"。

  5. 在"将文件另存为"框内键入 C:\Temp\Expense.xls。

  6. 执行下列操作：
    • 选择"重写"复选框以防止第一个工作表阻止进一步上载。

    • 选择"从消息队列删除"复选框，否则该包将因重复尝试装载相同的工作表而无限期循环。

    • 因为该包一直运行到被取消为止，所以清除"之后超时"复选框。
  7. 在设计表上右击"等待"，指向"工作流"，然后单击"工作流属性"命令。

  8. 单击"选项"选项卡，然后清除以下复选框：
    • 有事务时联接

    • 成功完成此步骤时提交事务

    • 失败时回滚事务


如何配置删除原始数据任务（企业管理器）

配置删除原始数据任务

  1. 从"任务"工具栏，将执行 SQL任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"执行 SQL 任务属性"对话框的"描述"框中键入"Delete Raw Data"。

  3. 在"现有连接"列表中单击"原始数据"。

  4. 在"SQL 语句"文本框内键入以下代码：
    DELETE FROM RawExpense.
  5. 在设计表上右击"Delete Raw Data"，指向"工作流"，然后单击"工作流属性"命令。

  6. 单击"选项"选项卡，然后清除以下复选框：
    • 有事务时联接

    • 成功完成此步骤时提交事务

    • 失败时回滚事务
  7. 单击"优先"选项卡，然后添加一个新项，其中的"源步骤"设置为"Spreadsheet Wait"，"优先"设置为"成功"。


如何配置装载原始数据任务（企业管理器）

配置装载原始数据任务

  1. 单击"开支报告"，然后按住 CTRL 键并单击"原始数据"。

  2. 在"任务"工具栏中单击"转换数据任务"，然后在数据转换服务 (DTS) 设计表中双击所得到的箭头。

  3. 在"描述"框中键入"Load Raw Data"，然后在"表/视图"列表中单击"开支"以从适当的电子表格范围内装载数据。

  4. 单击"目的"选项卡，然后在"表名"列表中，单击"RawExpense"。

  5. 单击"转换"选项卡，然后单击"确定"按钮。

    在没有编辑转换时单击"确定"按钮将保存默认的列映射。

  6. 在设计表上右击转换数据任务，指向"工作流"，然后单击"工作流属性"命令。

  7. 单击"选项"选项卡，然后执行下列操作：
    • 清除"成功完成此步骤时提交事务"复选框。

    • 清除"失败时回滚事务"复选框。

    • 选择"有事务时联接"复选框。
  8. 单击"优先"选项卡，然后添加一个新项，其中的"源步骤"设置为"Delete Raw Data"，"优先"设置为"成功"。


如何配置装载筛选数据任务（企业管理器）

配置装载筛选数据任务

  1. 单击"原始数据"，然后按住 CTRL 键并单击"企业"。

  2. 在"任务"工具栏中单击"转换数据任务"，然后在数据转换服务 (DTS) 设计表中双击所得到的箭头。

  3. 在"描述"框中键入"Load Final Data"。

  4. 在"连接"下单击"SQL 查询"，然后在文本框内键入以下 SQL 语句：
    SELECT FROM RawExpense WHERE ExpenseDate IS NOT NULL

    这样就生成一个不含任何空行的源行集。

  5. 单击"目的"选项卡，然后在"表名"列表中单击"Expense"。

  6. 单击"转换"选项卡，然后单击"确定"按钮。

    在没有编辑转换的情况下单击"确定"将保存默认的列映射。

  7. 在设计表上右击转换数据任务，指向"工作流"，然后单击"工作流属性"命令。

  8. 单击"选项"选项卡，然后执行下列操作：
    • 选择"成功完成此步骤时提交事务"复选框。

    • 选择"有事务时联接"复选框。

    • 清除"失败时回滚事务"复选框。
  9. 单击"优先"选项卡，然后添加一个新项，其中的"源步骤"设置为"Load Raw Data"，"优先"设置为"成功"。


如何配置失败的开支装载（或失败的 XLS 装载）任务（企业管理器）

配置失败的开支装载（或失败的 XLS 装载）任务

  1. 从"任务"工具栏，将消息队列任务拖动到数据转换服务 (DTS) 设计表上。

  2. 在"消息队列任务属性"对话框的"描述"框中键入"Failed Expense Load"（或"Failed XLS Load"）。

  3. 在"消息"列表中单击"发送消息"。

  4. 在"队列"框中输入 computer_name\queue_type$\queue_name 组合的名称，用以标识不可装载的工作表将要发往的位置。

  5. 在"要发送的消息"列表中单击"添加"按钮。

  6. 在"消息类型"框中单击"数据文件消息"，然后在"文件名"框中输入 C:\Temp\Expense.xls。

  7. 在设计表上右击"Failed Expense Load"（或"Failed XLS Load"），指向"工作流"，然后单击"工作流属性"命令。

  8. 单击"选项"选项卡，然后选择以下复选框：
    • 成功完成此步骤时提交事务

    • 有事务时联接

    • 失败时回滚事务
  9. 单击"优先"选项卡，然后添加一个新项，其中的"源步骤"设置为"Load Filtered Data"（或"Load Raw Data"），"优先"设置为"失败"。


如何创建并配置三个循环任务（企业管理器）

创建并配置三个循环任务

  1. 在数据转换服务 (DTS) 设计表上，右击"电子表格等待"，指向"工作流"，然后单击"工作流属性"命令。

  2. 在"工作流属性"对话框内单击"选项"选项卡并注意"名称"框内该步骤的名称。

    有可能是 DTSStep_DTSMessageQueueTask_1。在此过程的后面部分需要在另一个框中单击该名称。

  3. 从"任务"工具栏中，将动态属性任务拖动到设计表上。

  4. 在"描述"框中键入 Loop，然后单击"添加"。

  5. 在左窗格中显示的树中，展开"步骤"，然后展开 DTSStep_DTSMessageQueueTask_1（在步骤 2 中所注意的名称）。

  6. 在右窗格中"属性名称"下双击"执行状态"。

  7. 在"添加/编辑分配"对话框的"源"列表中，单击"常量"，然后在"常量"框中键入 1。

    1 是赋给 DTSStepExecStat_Waiting 的值。

  8. 在设计表上执行下列操作：
    • 右击"Loop"，然后单击"复制"命令。

    • 右击该设计表然后单击"粘贴"。再重复该粘贴一次。

    • 将这三个"Loop"任务放在设计表右侧的某列中。
  9. 右击每个粘贴的"Loop"任务，指向"工作流"，然后单击"工作流属性"。

  10. 单击"优先"选项卡，然后添加一个新项，其中的"源步骤"设置为适当的步骤："Failed XLS Load"、"Failed Expense Load"或"Load Filtered Data"。将"优先"设置为"成功"。


如何转换日期时间字符串转换的格式（企业管理器）

转换日期时间字符串转换的格式

  1. 在"转换数据任务属性"或"数据驱动的查询任务属性"对话框的"转换"选项卡上，单击包含要修改的日期和时间的"源"列，然后单击修改过的字符串所要放到的"目的"列。

  2. 执行下列操作中的一种：
    • 如果有映射箭头连接这两列，则单击"删除"按钮，然后单击"新建"按钮。

    • 如果没有映射箭头，则单击"新建"按钮。
  3. 在"创建新转换"对话框中，单击"DateTime 字符串"按钮。

  4. 单击"常规"选项卡，然后单击"属性"按钮。

  5. 在"日期格式"列表中，选择所需的格式。

  6. 单击"命名"按钮显示"日历名称"对话框，在此对话框中可选择日或月的全称或缩写，以及所需的 am/pm 指示器。

  7. 在"语言"列表中，选择所需的语言，然后单击"设置默认语言"按钮。

请参见

日期时间字符串转换

转换数据任务


如何将字符串转换为小写字符（企业管理器）

将字符串转换为小写字符

  1. 在"转换数据任务属性"或"数据驱动的查询任务属性"对话框的"转换"选项卡上，单击包含要修改的字符串的"源"列，然后单击修改过的字符串所要放到的"目的"列。

  2. 执行下列操作中的一种：
    • 如果有映射箭头连接这两列，则单击"删除"按钮，然后单击"新建"按钮。

    • 如果没有映射箭头，则单击"新建"按钮。
  3. 在"创建新转换"对话框中，选择"小写字符串"。

请参见

小写字符串转换

转换数据任务


如何将字符串转换为大写字符（企业管理器）

将字符串转换为大写字符

  1. 在"转换数据任务属性"或"数据驱动的查询任务属性"对话框的"转换"选项卡上，单击包含要修改的字符串的"源"列，然后单击修改过的字符串所要放到的"目的"列。

  2. 执行下列操作中的一种：
    • 如果有映射箭头连接这两列，则单击"删除"按钮，然后单击"新建"按钮。

    • 如果没有映射箭头，则单击"新建"按钮。
  3. 在"创建新转换"对话框中，选择"大写字符串"。

请参见

大写字符串转换

转换数据任务


如何执行字符串中间部分转换（企业管理器）

执行字符串中间部分转换

  1. 在"转换数据任务属性"或"数据驱动的查询任务属性"对话框的"转换"选项卡上，单击包含要修改的字符串的"源"列，然后单击修改过的字符串所要放到的"目的"列。

  2. 执行下列操作中的一种：
    • 如果有映射箭头连接这两列，则单击"删除"按钮，然后单击"新建"按钮。

    • 如果没有映射箭头，则单击"新建"按钮。
  3. 在"创建新转换"对话框中，选择"字符串中间部分"。

  4. 单击"常规"选项卡，然后单击"属性"按钮。

  5. 在"起始位置（基于 1）"框中，键入或选择子串所在的第一个字符的位置。

  6. 如果希望删除源字符串末端的字符，则选中"将字符个数限制为"复选框并输入子串的最大长度。

请参见

字符串中间部分转换

转换数据任务


如何执行剪裁字符串转换（企业管理器）

执行剪裁字符串转换

  1. 在"转换数据任务属性"或"数据驱动的查询任务属性"对话框的"转换"选项卡上，单击包含要修改的字符串的"源"列，然后单击修改过的字符串所要放到的"目的"列。

  2. 执行下列操作中的一种：
    • 如果有映射箭头连接这两列，则单击"删除"按钮，然后单击"新建"按钮。

    • 如果没有映射箭头，则单击"新建"按钮。
  3. 在"创建新转换"对话框中，选择"剪裁字符串"。

  4. 单击"常规"选项卡，然后单击"属性"按钮。

请参见

剪裁字符串转换

转换数据任务


如何执行读取文件转换（企业管理器）

执行读取文件转换

  1. 在"转换数据任务属性"或"数据驱动的查询任务属性"对话框的"转换"选项卡上，单击包含文件规范信息的"源"列，然后单击要将文件内容复制到的"目的"列。

  2. 执行下列操作中的一种：
    • 如果有映射箭头连接这两列，则单击"删除"按钮，然后单击"新建"按钮。

    • 如果没有映射箭头，则单击"新建"按钮。
  3. 在"创建新转换"对话框中，选择"读取文件"。

  4. 单击"常规"选项卡，然后单击"属性"按钮。

  5. 在"读取文件转换"对话框中，执行以下操作：
    • 在"目录"列表中，键入被读取文件所在目录的名称。

    • 在"文件类型"列表中，单击所需的文件类型。

    • 选择"没有找到文件时显示错误信息"复选框，以便在没有文件与源列匹配时使步骤失败。清除该复选框以清空目的列。

请参见

读取文件转换

转换数据任务


如何执行写入文件转换（企业管理器）

执行写入文件转换

  1. 在"转换数据任务属性"或"数据驱动的查询任务属性"对话框的"转换"选项卡上，单击包含文件名列的"源"列和包含数据列的"源"列。

  2. 单击"新建"按钮，并在"创建新转换"对话框中单击"写入文件"。

  3. 单击"常规"选项卡，然后单击"属性"按钮。

  4. 在"写入文件转换属性"对话框中，执行以下操作：
    • 在"目录"列表中，键入保存文件所使用的目录名称。

    • 在"文件类型"列表中，单击所需的文件类型。

    • 在"文件名列"列表中，单击包含文件名的列。

    • 在"处理现有文件"下，单击所需的选项。

请参见

写入文件转换

转换数据任务


如何创建连接（企业管理器）

在 DTS 设计器中创建连接

  1. 在"连接"工具栏上，拖动要放在数据转换服务 (DTS) 设计器设计表上的连接。

  2. 执行下列操作中的一种：
    • 单击"新建连接"按钮。

    • 单击"现有连接"，然后从列表中单击一项可用连接。
  3. 填完其余的连接配置信息。

    信息的类型随具体所选数据提供程序的不同而不同。


如何创建运行时解析的数据链接（企业管理器）

创建运行时解析的数据链接

  1. 在"连接属性"对话框中，在"数据资源"列表中，单击"Microsoft 数据链接"。

  2. 选择"总是从 UDL 文件读取属性"复选框。

    如果已清除该复选框，则必须通过数据转换服务 (DTS) 包编辑连接属性。

  3. 单击"属性"以显示"数据链接属性"对话框。

请参见

数据链接连接


DTS 包管理

本节中的主题包括从 SQL Server 企业管理器以及从 DTS 工具内部管理数据转换服务 (DTS) 包的过程。


如何使用 DTS 设计器创建 DTS 包（企业管理器）

使用 DTS 设计器创建 DTS 包

  • 在 SQL Server 企业管理器控制台树中，右击"数据转换服务"节点，然后单击"新建包"命令。

    说明 选择"本地包"或"Meta Data Services 包"决定在默认情况下文件所保存的格式（本地包保存到 Microsoft® SQL Server™ 中，Meta Data Services 包保存到 SQL Server 2000 Meta Data Services 中）。

请参见

管理 DTS 包


如何使用 DTS 导入/导出向导创建 DTS 包（企业管理器）

使用 DTS 导入/导出向导创建一个新包

  • 在 SQL Server 企业管理器控制台树中，右击"数据转换服务"节点，指向"所有任务"选项，然后单击"导入数据"或"导出数据"命令。

请参见

dtswiz 实用工具

DTS 导入/导出向导

管理 DTS 包


如何编辑保存到 SQL Server 或 Meta Data Services 中的 DTS 包（企业管理器）

编辑保存到 SQL Server 或 Meta Data Services 的 DTS 包

  1. 在 SQL Server 企业管理器控制台树中，展开"数据转换服务"节点。

  2. 执行下列操作之一：
    • 对于保存到 Microsoft® SQL Server™ 中的数据转换服务 (DTS) 包，单击"本地包"。

    • 对于保存到 SQL Server 2000 Meta Data Services 中的包，单击"Meta Data Services 包"。
  3. 在"详细信息"窗格中双击要在 DTS 设计器中打开的 DTS 包。

请参见

管理 DTS 包

将 DTS 包保存到 Meta Data Services

将 DTS 包保存到 SQL Server 中


如何编辑保存到结构化存储文件的 DTS 包（企业管理器）

编辑保存到结构化存储文件的 DTS 包

  1. 在 SQL Server 企业管理器控制台树中，右击"数据转换服务"节点，然后单击"打开包"命令。

  2. 在"选择文件"对话框中浏览需要的文件，单击此文件，然后单击"打开"。

  3. 如果该文件包含多个包或包的多个版本，则出现"选择包"对话框。双击一个数据转换服务 (DTS) 包或包的版本。若需要最新版本的包，请单击该包节点或最高版本节点。

请参见

将 DTS 包保存到结构化存储文件

管理 DTS 包


如何删除 DTS 包（企业管理器）

删除保存到 SQL Server 或 Meta Data Services 中的 DTS 包

  1. 在 SQL Server 企业管理器控制台树中，展开"数据转换服务"节点。

  2. 执行下列操作之一：
    • 对于保存到 Microsoft® SQL Server™ 中的数据转换服务 (DTS) 包，单击"本地包"。

    • 对于保存到 SQL Server 2000 Meta Data Services 中的包，单击"Meta Data Services 包"文件夹。
  3. 在"详细信息"窗格中右击一个数据转换服务 (DTS) 包，然后单击"删除"按钮。

    这将删除该包的所有版本。

删除保存到 SQL Server 的 DTS 包版本

  1. 在 SQL Server 企业管理器控制台树中，展开"本地包"节点。

  2. 在"详细信息"窗格中右击该包，然后单击"版本"命令。

  3. 在"DTS 包版本"对话框中，单击包版本，然后单击"删除"按钮。

删除保存到文件中的 DTS 包

  1. 使用一种文件管理器如 Microsoft Windows Explorer，单击包含 DTS 包的文件夹。

  2. 右击所需的包文件，然后单击"删除"命令。

请参见

管理 DTS 包


如何从 SQL Server 企业管理器中执行 DTS 包（企业管理器）

从 SQL Server 企业管理器中执行 DTS 包

  1. 在 SQL Server 企业管理器控制台树中，展开"数据转换服务"节点。

  2. 执行下列操作之一：
    • 对于保存到 Microsoft® SQL Server™ 中的数据转换服务 (DTS) 包，单击"本地包"。

    • 对于保存到 SQL Server 2000 Meta Data Services 中的包，单击"Meta Data Services 包"文件夹。
  3. 在"详细信息"窗格中右击包，然后单击"执行包"命令。

请参见

执行 DTS 包


如何从 DTS 设计器执行 DTS 包（企业管理器）

从 DTS 设计器执行 DTS 包

  • 在 DTS 设计器中打开数据转换服务 (DTS) 包，单击工具栏上的"执行"按钮。

请参见

执行 DTS 包


如何从 DTS 导入/导出向导中执行 DTS 包（企业管理器）

从 DTS 导入/导出向导中执行 DTS 包

  1. 在"保存、调度和复制包"对话框中，单击"立即运行"命令，然后单击"下一步"按钮。

  2. 在"完成 DTS 向导"对话框上，单击"完成"按钮。

请参见

执行 DTS 包


如何使用 DTS 运行实用工具执行 DTS 包（命令提示符）

使用 DTS 运行实用工具执行 DTS 包

  1. 打开一个命令提示窗口，键入 dtsrunui，而无需任何命令开关。

  2. 在"DTS 运行"和"高级 DTS 运行"对话框中，输入有关连接设置和日志的任何信息。

  3. 当准备好执行包时，单击"确定"按钮。

请参见

DTS 包执行实用工具

执行 DTS 包


如何使用 dtsrun 执行 DTS 包（命令提示符）

使用 dtsrun 执行 DTS 包

  • 打开一个命令提示窗口，键入 dtsrun 以及任何必要的和可选的命令开关。

请参见

dtsrun 实用工具

执行 DTS 包


如何将 DTS 包保存到 SQL Server 中（企业管理器）

将 DTS 包保存到 SQL Server 中

  1. 在数据转换服务 (DTS) 设计器中的工具栏上，单击"保存"按钮。

  2. 在"位置"列表中，单击"SQL Server"。

  3. 完成其它所需字段。

    说明 如果该 DTS 包已经保存到 Microsoft® SQL Server™ 中，则不会出现"保存 DTS 包"对话框，而将保存一个新的版本。如果该包已保存为结构化存储或 Microsoft Visual Basic® 文件，或已保存到 SQL Server 2000 Meta Data Services 中，则单击"另存为"命令以保存到 SQL Server 中。

请参见

将 DTS 包保存到 SQL Server 中


如何打开保存到 SQL Server 中的 DTS 包（企业管理器）

打开保存到 SQL Server 中的 DTS 包

  1. 在 SQL Server 企业管理控制台树中，展开"数据转换服务"节点，然后单击"本地包"文件夹。

  2. 执行下列操作之一：
    • 双击要在 DTS 设计器中打开的数据转换服务 (DTS) 包。

    • 右击想要打开的 DTS 包，然后单击"版本"命令。在"DTS 包版本"对话框中，单击想要的版本，然后单击"编辑"按钮。

请参见

将 DTS 包保存到 SQL Server 中


如何将 DTS 包保存到 Meta Data Services（企业管理器）

将 DTS 包保存到 Meta Data Services

  1. 在数据转换服务 (DTS) 设计器中的"包"菜单上，单击"保存"命令。

  2. 在"位置"列表中单击"Meta Data Services"。

  3. 完成其它所需字段。

说明 如果该包已经保存于 Microsoft® SQL Server™ 2000 Meta Data Services 中，则不会出现"保存 DTS 包"对话框，而将保存一个新的版本。如果该包已保存为结构化存储或 Microsoft Visual Basic® 文件，或已保存到 SQL Server 中，则单击"另存为"命令以保存到 Meta Data Services 中。

请参见

将 DTS 包保存到 Meta Data Services


如何打开保存到 Meta Data Services 的 DTS 包（企业管理器）

打开保存到 Meta Data Services 的 DTS 包

  1. 在 SQL Server 企业管理器控制台树中，展开"数据转换服务"节点并双击"Meta Data Services 包"文件夹。

  2. 执行下列操作之一：
    • 双击要在 DTS 设计器中打开的数据转换服务 (DTS) 包。

    • 右击想要打开的 DTS 包，然后单击"版本"命令。在"DTS 包版本"对话框中，单击想要的版本，然后单击"编辑"按钮。

请参见

将 DTS 包保存到 Meta Data Services


如何将 DTS 包保存到结构化存储文件（企业管理器）

将 DTS 包保存到结构化存储文件

  1. 在数据转换服务 (DTS) 设计器中的工具栏上，单击"保存"按钮。

  2. 在"位置"列表中单击"结构化存储文件"。

  3. 完成其它所需字段。

说明 如果该 DTS 包已经保存到结构化存储文件中，则"保存 DTS 包"对话框不会出现，而将保存一个新的版本。如果该包已经保存到 Microsoft® SQL Server™、SQL Server 2000 Meta Data Services 或是一个 Microsoft Visual Basic® 文件中，则单击"另存为"命令以保存到一个结构化存储文件中。

请参见

将 DTS 包保存到结构化存储文件


如何打开保存到结构化存储文件的 DTS 包（企业管理器）

打开保存到结构化存储文件的 DTS 包

  1. 在 SQL Server 企业管理器控制台树中，右击"数据转换服务"节点，然后单击"打开包"命令。

  2. 在"选择文件"对话框中，单击所需的 .dts 文件，然后单击"打开"按钮。

  3. 如果保存了多个数据转换服务 (DTS) 包或包版本，则出现"选择包"对话框。单击要打开的包或包的版本。

请参见

将 DTS 包保存到结构化存储文件


如何使用调度包选项调度 DTS 包（企业管理器）

使用调度包选项调度 DTS 包

  1. 在 SQL Server 企业管理器控制台树中，展开"数据转换服务"节点，然后单击"本地包"或是"Meta Data Services 包"。

  2. 在"详细信息"窗格中右击要调度的数据转换服务 (DTS) 包，然后单击"调度包"命令。

  3. 在"编辑反复出现的作业调度"对话框中，完成所需的信息。

说明 所调度的包将由 SQL Server 代理执行，执行时使用服务器注册时指定的权限。如果使用了 Windows 身份验证，则 SQL Server 代理将试图用它本身的安全性装载该包，这种安全性可能并不足以装载该包。有关更多信息，请参阅在 DTS 中处理包安全性。

请参见

调度 DTS 包的执行


如何使用 SQL Server 代理调度 DTS 包（企业管理器）

使用 SQL Server 代理调度 DTS 包

  1. 在 SQL Server 企业管理器的控制台树中，展开"管理"节点，然后单击"SQL Server 代理"。

  2. 在"详细信息"窗格中右击"作业"，然后单击"新建作业"命令。

  3. 在"常规"选项卡上，完成配置新作业的信息。

  4. 单击"步骤"选项卡，单击"新建"按钮，然后执行下列操作之一：
    • 在"步骤名"框中键入名称。

    • 在"类型"列表中单击"操作系统命令 (CmdExec)"选项。

    • 在"命令"文本框中为此包键入 dtsrun 命令。

说明 所调度的包是由 SQL Server 代理运行的，其本身不具备该包创建者的共享驱动器号和权限。

请参见

调度 DTS 包的执行


如何查看或修改 DTS 包属性（企业管理器）

查看或修改 DTS 包属性

  1. 数据转换服务 (DTS) 包在 DTS 设计器中处于打开状态，右击设计表，然后单击"包属性"命令。

  2. 单击所需的选项卡，即可查看或修改值。

请参见

查看和配置 DTS 包属性


如何使用脱接编辑修改 DTS 包属性（企业管理器）

使用脱接编辑修改 DTS 包属性

  1. 在 DTS 设计器中打开数据转换服务 (DTS) 包，右击设计表，然后单击"脱接编辑"命令。

  2. 在"编辑所有包属性"对话框中，展开左窗格中的属性节点，然后双击所需编辑的属性组。

  3. 在右窗格中选择想要的属性并单击"编辑"。

  4. 在"类型"列表中选择一种属性，然后在"值"框中键入新属性值。

    说明 并不是所有属性值都可以通过"脱接编辑"功能进行修改。

请参见

查看和配置 DTS 包属性


如何将 DTS 包保存到 Visual Basic 文件中（企业管理器）

使用 DTS 导入/导出向导将 DTS 包保存到 Visual Basic 文件中

  • 在"保存、调度和复制包"屏幕上选择"保存 DTS 包"复选框，然后单击"Visual Basic 文件"。

使用 DTS 设计器将 DTS 包保存到 Visual Basic 文件中

  1. 在"包"菜单中单击"另存为"命令。

  2. 在"位置"列表中单击"Visual Basic 文件"。

  3. 在"文件名"框中键入 Microsoft® Visual Basic® 文件的名称。

请参见

将 DTS 包保存到 Visual Basic 文件中


如何查看包日志（企业管理器）

查看 DTS 包日志

  1. 在 SQL Server 企业管理器中，展开"数据转换服务"。

  2. 执行下列操作之一：
    • 右击"本地包"（如果数据转换服务 (DTS) 包日志保存到 Microsoft® SQL Server™ 中），然后单击"包日志"命令。

    • 右击"Meta Data Services 包"（如果包日志保存到 SQL Server 2000 Meta Data Services 中），然后单击"包日志"命令。

    • 单击"本地包"或"Meta Data Services 包"，并在"详细信息"窗格中右击一个包或单击"包日志"。

请参见

使用 DTS 包日志


如何启用包日志记录功能（企业管理器）

启用包日志记录功能

  1. 打开要创建日志的数据转换服务 (DTS) 包。

  2. 在"包"菜单上单击"属性"命令以显示"DTS 包属性"对话框。

  3. 执行下列操作之一：
    • 单击"日志记录"选项卡，选择"将包执行记录到 SQLServer"复选框，然后单击可用于保存包日志的服务器，就可把包日志保存到 Microsoft® SQL Server™ 中。

    • 单击"高级"选项卡，然后选择"将沿袭变量显示为源列"和"将沿袭写入知识库"复选框，就可把包日志保存到 SQL Server 2000 Meta Data Services 中。在"包"菜单上单击"另存为"命令，然后在"保存 DTS 包"对话框的"位置"列表中，选择"Meta Data Services"。

请参见

如何查看包日志

使用 DTS 包日志


如何设置 DTS 包密码（企业管理器）

在 DTS 设计器中设置 DTS 包的密码

  1. 在"包"菜单中单击"保存"或"另存为"命令。

  2. 在"位置"列表中，单击"SQL Server"或"结构化存储文件"选项。

  3. 执行下列操作之一：
    • 输入"所有者"密码。指派"所有者"密码将限制既能编辑包又能运行包的用户。

    • 输入"用户"密码。指派"用户"密码将只限制能编辑包的用户。如果创建了"用户"密码，则必须同时创建一个"所有者"密码。

请参见

在 DTS 中处理包安全性


如何修改身份验证信息的持续性（企业管理器）

在 DTS 包中修改身份验证信息的持续性

  1. 在数据转换服务 (DTS) 设计器的设计表中双击一个连接。

  2. 在"连接属性"对话框中，单击"高级"按钮。

  3. 在"值"列下，单击"持续安全消息"属性的值。

  4. 执行下列操作之一：
    • 键入 0 以禁用用 DTS 包保存身份验证信息。

    • 键入 1 以持续保存身份验证信息。

请参见

在 DTS 中处理包安全性


如何选择启用实时调试选项（企业管理器）

选择启用实时调试选项

  1. 在 SQL Server 企业管理器的控制台树中，右击"数据转换服务"节点，然后单击"属性"命令。

  2. 选择"启用实时调试"复选框。


如何在 DTS 设计器中添加 ActiveX 工作流脚本（企业管理器）

在 DTS 设计器中添加 ActiveX 工作流脚本

  1. 右击与想要配置的步骤相关的任务图标，然后单击"工作流属性"命令。

  2. 单击"选项"选项卡，选择"使用 ActiveX 脚本"复选框，然后单击"属性"按钮。

  3. 在 Microsoft® ActiveX® 脚本文本框中输入工作流步骤的脚本代码。


如何在 DTS 设计器中执行单个包步骤（企业管理器）

在 DTS 设计器中执行单个包步骤

  1. 在"任务"工具栏上右击要执行的任务。

  2. 单击"执行步骤"命令。


Transact-SQL

这些过程使您得以使用 Transact-SQL 语句来管理 SQL Server 的安装或复制。


管理 SQL Server

Microsoft® SQL Server™ 管理应用程序及其附带的服务旨在协助系统管理员执行和维护与监视服务器性能和活动有关的所有管理任务。


如何创建数据库备份 (Transact-SQL)

创建数据库备份

  1. 执行 BACKUP DATABASE 语句以创建数据库备份，同时指定：
    • 要备份的数据库的名称。

    • 数据库备份将写入的备份设备。
  2. 指定（可选）：
    • INIT 子句，通过它可以重写备份媒体，并在备份媒体上将该备份作为第一个文件写入。如果没有现成的媒体头，备份过程将自动写入一个。

    • SKIP 和 INIT 子句，通过它们可以在备份媒体中仍然存在未失效的备份，或在媒体本身的名称与备份媒体中的名称不匹配时重写备份媒体。

    • FORMAT 子句，通过它可以在第一次使用媒体时对备份媒体进行完全初始化，并覆盖任何现有的媒体头。

      如果已经指定了 FORMAT 子句，则不需要指定 INIT 子句。

重要 当使用 BACKUP 语句的 FORMAT 子句或 INIT 子句时，一定要十分小心，因为它们会破坏以前存储在备份媒体中的所有备份。

示例

下例将整个 MyNwind 数据库备份到磁带上：

USE MyNwind
GO
BACKUP DATABASE MyNwind
   TO TAPE = '\\.\Tape0'
   WITH FORMAT,
   NAME = 'Full Backup of MyNwind'
GO

请参见

sp_addumpdevice

数据库备份

追加备份集

差异数据库备份

备份 master 数据库

删除数据库

还原 model、msdb 和 distribution 数据库

重写备份媒体

BACKUP

减少恢复时间

事务日志备份

初始化备份媒体


如何还原数据库备份 (Transact-SQL)

还原数据库备份

重要 还原数据库备份的系统管理员必须是唯一一位当前使用要还原的数据库的人。

  1. 执行 RESTORE DATABASE 语句以还原数据库备份，同时指定：
    • 要还原的数据库名称。

    • 要从其中还原数据库备份的备份设备。

    • NORECOVERY 子句，如果要在还原数据库备份后应用事务日志或差异数据库备份的话。
  2. 指定（可选）：
    • FILE 子句，以此标识备份设备上要还原的备份集。
示例

下例从磁带还原 MyNwind 数据库备份：

USE master
GO
RESTORE DATABASE MyNwind
   FROM TAPE = '\\.\Tape0'
GO

请参见

数据库备份

设置数据库选项

RESTORE

标识要还原的备份集

事务日志备份

差异数据库备份

重建 master 数据库

还原 model、msdb 和 distribution 数据库

减少恢复时间


如何重新开始被中断的备份操作 (Transact-SQL)

重新开始被中断的备份操作

  • 再次执行中断的 BACKUP 语句，同时指定：
    • 原 BACKUP 语句中使用的相同子句。

    • RESTART 子句。
示例

下例重新开始被中断的数据库备份操作：

-- Create a database backup of the MyNwind database
BACKUP DATABASE MyNwind
   TO MyNwind_1
-- The backup operation halts due to power outage.
-- Repeat the original BACKUP statement specifying WITH RESTART
BACKUP DATABASE MyNwind
   TO MyNwind_1
   WITH RESTART

请参见

BACKUP

数据库备份


如何重新开始被中断的还原操作 (Transact-SQL)

重新开始被中断的还原操作

重要 还原备份的系统管理员必须是唯一一位当前使用要还原的数据库的人。

  • 再次执行中断的 RESTORE 语句，同时指定：
    • 原 RESTORE 语句中使用的相同子句。

    • RESTART 子句。
示例

下例重新开始被中断的还原操作：

-- Restore a database backup of the MyNwind database
RESTORE DATABASE MyNwind
   FROM MyNwind_1
GO
-- The restore operation halted prematurely.
-- Repeat the original RESTORE statement specifying WITH RESTART
RESTORE DATABASE MyNwind
   FROM MyNwind_1
   WITH RESTART
GO

请参见

数据库备份

RESTORE

复制数据库


如何创建事务日志备份 (Transact-SQL)

创建事务日志备份

  1. 执行 BACKUP LOG 语句备份事务日志，同时指定：
    • 要备份的事务日志所属的数据库名称。

    • 事务日志备份将写入的备份设备。
  2. 指定（可选）：
    • INIT 子句，通过它可以重写备份媒体，并在备份媒体上将该备份作为第一个文件写入。如果没有现成的媒体头，备份过程将自动写入一个。

    • SKIP 和 INIT 子句，通过它们可以在备份媒体中仍然存在未失效的备份，或在媒体本身的名称与备份媒体中的名称不匹配时重写备份媒体。

    • FORMAT 子句，通过它可以在第一次使用媒体时对备份媒体进行完全初始化，并覆盖任何现有的媒体头。

      如果已经指定了 FORMAT 子句，则不需要指定 INIT 子句。

重要 当使用 BACKUP 语句的 FORMAT 子句或 INIT 子句时，一定要十分小心，因为它们会破坏以前存储在备份媒体中的所有备份。

示例

下例在以前创建的命名备份设备 MyNwind_log1 上创建 MyNwind 数据库的事务日志备份：

BACKUP LOG MyNwind
   TO MyNwind_log1
GO

请参见

BACKUP

事务日志备份

将数据库还原到前一个状态

减少恢复时间

文件和文件组的备份及还原


如何在数据库损坏时备份事务日志 (Transact-SQL)

创建当前活动事务日志的备份

  1. 执行 BACKUP LOG 语句以备份当前活动的事务日志，同时指定：
    • 要备份的事务日志所属的数据库名称。

    • 事务日志备份将写入的备份设备。

    • NO_TRUNCATE 子句，通过它备份事务日志而不截断该事务日志的非活动部分。

      只要事务日志文件是可访问的并且没有损坏，那么即使数据库不可访问，此子句也允许备份事务日志的活动部分。

  2. 指定（可选）：
    • INIT 子句，通过它可以重写备份媒体，并在备份媒体上将该备份作为第一个文件写入。如果没有现成的媒体头，备份过程将自动写入一个。

    • SKIP 和 INIT 子句，通过它们可以重写备份媒体，即使在备份媒体中仍然存在未过期的备份，或在媒体本身的名称与备份媒体中的名称不匹配时也可重写。

    • FORMAT 子句，通过它可以在第一次使用媒体时对备份媒体进行完全初始化，并重写任何现有的媒体头。

      如果已经指定了 FORMAT 子句，则不需要指定 INIT 子句。

重要 当使用 BACKUP 语句的 FORMAT 子句或 INIT 子句时，一定要十分小心，因为它们会破坏以前存储在备份媒体中的所有备份。

示例

下例备份 MyNwind 数据库当前活动的事务日志，即使 MyNwind 已损坏且无法访问。但事务日志未损坏且可以访问。

BACKUP LOG MyNwind
   TO MyNwind_log1
   WITH NO_TRUNCATE
GO

请参见

BACKUP

事务日志备份

将数据库还原到前一个状态

减少恢复时间

文件和文件组的备份及还原


如何应用事务日志备份 (Transact-SQL)

必须满足以下条件才能应用事务日志备份：

  • 先还原事务日志备份之前的数据库备份或差异数据库备份。

  • 除非自备份数据库或差异数据库以后创建的所有前面的事务日志都首先被应用。

  • 如果数据库已经恢复并且所有未完成的事务已经回滚或者前滚。

应用事务日志备份

  1. 执行 RESTORE LOG 语句应用事务日志备份，同时指定：
    • 事务日志将应用到的数据库的名称。

    • 要从其中还原事务日志备份的备份设备。

    • NORECOVERY 子句，前提是在当前事务日志备份之后，还要应用其它事务日志备份，否则应指定 RECOVERY 子句。
  2. 为每个需要应用的事务日志备份重复步骤 1。
示例
A. 应用单个事务日志备份

下例将一个事务日志备份应用到 MyNwind 数据库中。

RESTORE LOG MyNwind
   FROM MyNwind_log1
   WITH RECOVERY
GO
B. 应用多个事务日志备份

下例将多个事务日志备份应用到 MyNwind 数据库中。

RESTORE LOG MyNwind
   FROM MyNwind_log1
   WITH NORECOVERY
GO
RESTORE LOG MyNwind
   FROM MyNwind_log2
   WITH NORECOVERY
GO
RESTORE LOG MyNwind
   FROM MyNwind_log3
   WITH RECOVERY
GO

请参见

事务日志备份

RESTORE

减少恢复时间

文件和文件组的备份及还原


如何创建差异数据库备份 (Transact-SQL)

创建差异数据库备份

重要 除非首先备份数据库，否则不可能创建差异数据库备份。

  1. 执行 BACKUP DATABASE 语句以创建差异数据库备份，同时指定：
    • 要备份的数据库的名称。

    • 数据库备份将写入的备份设备。

    • DIFFERENTIAL 子句，通过它可以指定只对在创建最新的数据库备份后数据库中发生变化的部分进行备份。
  2. 指定（可选）：
    • INIT 子句，通过它可以重写备份媒体，并在备份媒体上将该备份作为第一个文件写入。如果没有现成的媒体头，备份过程将自动写入一个。

    • SKIP 和 INIT 子句，通过它们可以在备份媒体中仍然存在未失效的备份，或在媒体本身的名称与备份媒体中的名称不匹配时重写备份媒体。

    • FORMAT 子句，通过它可以在第一次使用媒体时对备份媒体进行完全初始化，并覆盖任何现有的媒体头。

      如果已经指定了 FORMAT 子句，则不需要指定 INIT 子句。

重要 当使用 BACKUP 语句的 FORMAT 子句或 INIT 子句时，一定要十分小心，因为它们会破坏以前存储在备份媒体中的所有备份。

示例

下例为 MyNwind 数据库创建一个完整的数据库备份和一个差异数据库备份。

-- Create a full database backup first.
BACKUP DATABASE MyNwind
   TO MyNwind_1
   WITH INIT
GO
-- Time elapses.
-- Create a differential database backup, appending the backup
-- to the backup device containing the database backup.
BACKUP DATABASE MyNwind
   TO MyNwind_1
   WITH DIFFERENTIAL
GO

请参见

BACKUP

差异数据库备份

减少恢复时间


如何还原差异数据库备份 (Transact-SQL)

还原差异数据库备份

  1. 执行 RESTORE DATABASE 语句，同时指定 NORECOVERY 子句，以还原差异数据库备份之前的数据库备份。有关更多信息，请参阅如何还原数据库备份。

  2. 执行 RESTORE DATABASE 语句以还原差异数据库备份，同时指定：
    • 差异数据库备份将应用到的数据库的名称。

    • 要从其中还原差异数据库备份的备份设备。

    • NORECOVERY 子句，前提是在还原差异数据库备份后，还要应用事务日志备份，否则应指定 RECOVERY 子句。
示例
A. 还原数据库和差异数据库备份

下例还原 MyNwind 数据库的数据库和差异数据库备份。

-- Assume the database is lost at this point. Now restore the full
-- database. Specify the original full backup and NORECOVERY.
-- NORECOVERY allows subsequent restore operations to proceed.
RESTORE DATABASE MyNwind
   FROM MyNwind_1
   WITH NORECOVERY
GO
-- Now restore the differential database backup, the second backup on
-- the MyNwind_1 backup device.
RESTORE DATABASE MyNwind
   FROM MyNwind_1
   WITH FILE = 2,
      RECOVERY
GO
B. 还原数据库、差异数据库以及事务日志备份

下例还原 MyNwind 数据库的数据库、差异数据库和事务日志备份。

-- Assume the database is lost at this point. Now restore the full
-- database. Specify the original full backup and NORECOVERY.
-- NORECOVERY allows subsequent restore operations to proceed.
RESTORE DATABASE MyNwind
   FROM MyNwind_1
   WITH NORECOVERY
GO
-- Now restore the differential database backup, the second backup on
-- the MyNwind_1 backup device.
RESTORE DATABASE MyNwind
   FROM MyNwind_1
   WITH FILE = 2,
      NORECOVERY
GO
-- Now restore each transaction log backup created after
-- the differential database backup.
RESTORE LOG MyNwind
   FROM MyNwind_log1
   WITH NORECOVERY
GO
RESTORE LOG MyNwind
   FROM MyNwind_log2
   WITH RECOVERY
GO

请参见

差异数据库备份

RESTORE

减少恢复时间


如何恢复数据库但不还原 (Transact-SQL)

恢复数据库但不还原

  • 执行 RESTORE DATABASE 语句，同时指定：
    • 要恢复的数据库名称。

    • RECOVERY 子句。
示例

下例恢复 MyNwind 数据库但不从备份中还原。

-- Restore database using WITH RECOVERY.
RESTORE DATABASE MyNwind
   WITH RECOVERY

请参见

恢复数据库但不还原

RESTORE


如何还原到故障点 (Transact-SQL)

还原到故障点

  1. 执行使用 NO_TRUNCATE 子句的 BACKUP LOG 语句以备份当前活动的事务日志。

  2. 执行使用 NORECOVERY 子句的 RESTORE DATABASE 语句以还原数据库备份。

  3. 执行使用 NORECOVERY 子句的 RESTORE LOG 语句以应用每个事务日志备份。

  4. 执行使用 RECOVERY 子句的 RESTORE LOG 语句以应用步骤 1 中创建的事务日志备份。
示例

下例备份 MyNwind 数据库的当前活动事务日志（即使 MyNwind 不可访问），然后使用以前创建的备份将数据库还原到故障点：

-- Back up the currently active transaction log.
BACKUP LOG MyNwind
   TO MyNwind_log2
   WITH NO_TRUNCATE
GO
-- Restore the database backup.
RESTORE DATABASE MyNwind
   FROM MyNwind_1
   WITH NORECOVERY
GO
-- Restore the first transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log1
   WITH NORECOVERY
GO
-- Restore the final transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log2
   WITH RECOVERY
GO

请参见

RESTORE

将数据库还原到前一个状态


如何建立、维护以及联机备用服务器 (Transact-SQL)

备用服务器的建立通常包括在主服务器上创建数据库备份和定期事务日志备份，然后按照顺序将这些备份应用到备用服务器。在还原操作之间，备用服务器保持只读状态。当需要使用备用服务器时，任何未完成的事务日志备份，包括来自主服务器的活动事务日志备份都将应用到备用服务器中，同时还要恢复数据库。

在主服务器上创建备份

  1. 执行 BACKUP DATABASE 语句以创建数据库备份。

  2. 执行 BACKUP LOG 语句以创建事务日志备份。

  3. 为每个希望随着时间的变化而创建的事务日志重复步骤 2。

建立和维护备用服务器

  1. 执行使用 STANDBY 子句的 RESTORE DATABASE 语句以便还原步骤 1 中在主服务器上创建的数据库备份。在回滚未提交事务影响的数据页之前，指定包含这些数据页内容的撤消文件名称。

  2. 执行使用 STANDBY 子句的 RESTORE LOG 语句以便应用步骤 2 中在主服务器上创建的每个事务日志。

  3. 为每个在主服务器上创建的事务日志重复步骤 2。

使备用服务器联机（主服务器发生故障）

  1. 执行使用 NO_TRUNCATE 子句的 BACKUP LOG 语句以备份当前活动的事务日志。当备用服务器联机时，这是将应用到备用服务器的最新事务日志备份。有关更多信息，请参阅如何创建当前活动事务日志的备份。

  2. 执行使用 STANDBY 子句的 RESTORE LOG 语句以便应用所有事务日志备份，包括步骤 1 中创建的仍未应用到备用服务器的活动事务日志备份。

  3. 执行 RESTORE DATABASE WITH RECOVERY 语句以恢复数据库并使备用服务器联机。
示例

下例在备用服务器上安装 MyNwind 数据库。在还原操作之间，可以只读模式使用数据库。

-- Restore the initial database backup on the standby server.
USE master
GO
RESTORE DATABASE MyNwind
   FROM MyNwind_1
   WITH STANDBY = 'c:\undo.ldf'
GO
-- Apply the first transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log1
   WITH STANDBY = 'c:\undo.ldf'
GO
-- Apply the next transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log2
   WITH STANDBY = 'c:\undo.ldf'
GO
-- Repeat for each transaction log backup created on the
-- primary server.
--
-- Time elapses.. .. ..
--
-- The primary server has failed. Back up the
-- active transaction log on the primary server.
BACKUP LOG MyNwind
   TO MyNwind_log3
   WITH NO_TRUNCATE
GO
-- Apply the final (active) transaction log backup
-- to the standby server. All preceding transaction
-- log backups must have been already applied.
RESTORE LOG MyNwind
   FROM MyNwind_log3
   WITH STANDBY = 'c:\undo.ldf'
GO
-- Recover the database on the standby server,
-- making it available for normal operations.
RESTORE DATABASE MyNwind
   WITH RECOVERY
GO

请参见

RESTORE

将数据库还原到前一个状态

使用备用服务器


如何还原到某个即时点 (Transact-SQL)

还原到某个即时点

  1. 执行使用 NORECOVERY 子句的 RESTORE DATABASE 语句。

  2. 执行 RESTORE LOG 语句以应用每个事务日志备份，同时指定：
    • 事务日志将应用到的数据库的名称。

    • 要从其中还原事务日志备份的备份设备。

    • RECOVERY 和 STOPAT 子句。如果事务日志备份不包含要求的时间（例如，如果指定的时间超出了事务日志所包含的时间范围），则会生成警告，并且数据库将保持未恢复的状态。
示例

下例将数据库还原到它在 1998 年 7 月 1 日上午 10:00 点的状态，并且举例说明涉及多个日志以及多个备份设备的还原操作。

-- Restore the database backup.
RESTORE DATABASE MyNwind
   FROM MyNwind_1, MyNwind_2
   WITH NORECOVERY
GO
RESTORE LOG MyNwind
   FROM MyNwind_log1
   WITH RECOVERY, STOPAT = 'Jul 1, 1998 10:00 AM'
GO
RESTORE LOG MyNwind
   FROM MyNwind_log2
   WITH RECOVERY, STOPAT = 'Jul 1, 1998 10:00 AM'
GO

请参见

RESTORE

将数据库还原到前一个状态

RESTORE HEADERONLY


如何还原 master 数据库 (Transact-SQL)

还原 master 数据库

  1. 以单用户模式启动 Microsoft® SQL Server™。

  2. 执行 RESTORE DATABASE 语句以还原 master 数据库备份，同时指定：
    • 要从其中还原 master 数据库备份的备份设备。
示例

下例从磁带中还原 master 数据库备份而不使用永久（命名）的备份设备。

USE master
GO
RESTORE DATABASE master
   FROM TAPE = '\\.\Tape0'
GO

请参见

RESTORE

从当前备份还原 master 数据库

如何在单用户模式下启动 SQL Server 的默认实例（命令提示符）


如何备份文件和文件组 (Transact-SQL)

备份文件和文件组

  • 执行 BACKUP DATABASE 语句以创建文件和文件组备份，同时指定：
    • 要备份的数据库的名称。

    • 数据库备份将写入的备份设备。

    • 对于每个要备份的文件，指定 FILE 子句。

    • 对于每个要备份的文件组，指定 FILEGROUP 子句。
示例

下例执行 MyNwind 数据库的文件和文件组的备份操作。

-- Back up the MyNwind file(s) and filegroup(s)
BACKUP DATABASE MyNwind
   FILE = 'MyNwind_data_1',
   FILEGROUP = 'new_customers',
   FILE = 'MyNwind_data_2',
   FILEGROUP = 'first_qtr_sales'
   TO MyNwind_1
GO

请参见

BACKUP

文件和文件组的备份及还原


如何还原文件和文件组 (Transact-SQL)

还原文件和文件组

重要 还原文件和文件组的系统管理员必须是唯一一位当前使用要还原的数据库的人。

  1. 执行 RESTORE DATABASE 语句以还原文件和文件组备份，同时指定：
    • 要还原的数据库名称。

    • 要从其中还原数据库备份的备份设备。

    • 对于每个要还原的文件，指定 FILE 子句。

    • 对于每个要还原的文件组，指定 FILEGROUP 子句。

    • NORECOVERY 子句。如果在创建文件备份之后没有对文件进行修改，则指定 RECOVERY 子句。
  2. 如果在创建文件备份之后对文件进行了修改，则执行 RESTORE LOG 语句以应用事务日志备份，同时指定：
    • 事务日志将应用到的数据库的名称。

    • 要从其中还原事务日志备份的备份设备。

    • NORECOVERY 子句，前提是在当前事务日志备份之后，还要应用其它事务日志备份，否则应指定 RECOVERY 子句。

      事务日志备份（如果可用）必须包括截止到日志结尾处的文件和文件组备份（除非已还原 ALL 数据库文件）。

示例

下例还原 MyNwind 数据库的文件和文件组。为了将数据库还原到当前时间，还应用了两个事务日志。

USE master
GO
-- Restore the files and filesgroups for MyNwind.
RESTORE DATABASE MyNwind
   FILE = 'MyNwind_data_1',
   FILEGROUP = 'new_customers',
   FILE = 'MyNwind_data_2',
   FILEGROUP = 'first_qtr_sales'
   FROM MyNwind_1
   WITH NORECOVERY
GO
-- Apply the first transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log1
   WITH NORECOVERY
GO
-- Apply the last transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log2
   WITH RECOVERY
GO

请参见

RESTORE

文件和文件组的备份及还原


如何在现有文件上还原文件和文件组 (Transact-SQL)

在现有文件上还原文件和文件组

重要 还原文件和文件组的系统管理员必须是唯一一位当前使用要还原的数据库的人。

  1. 执行 RESTORE DATABASE 语句以还原文件和文件组备份，同时指定：
    • 要还原的数据库名称。

    • 要从其中还原数据库备份的备份设备。

    • 对于每个要还原的文件，指定 FILE 子句。

    • 对于每个要还原的文件组，指定 FILEGROUP 子句。

    • REPLACE 子句，用来指定每个文件都可以在名称以及位置相同的现有文件上还原。

    • NORECOVERY 子句。如果在创建文件备份之后没有对文件进行修改，则指定 RECOVERY 子句。
  2. 如果在创建文件备份之后对文件进行了修改，则执行 RESTORE LOG 语句以应用事务日志备份，同时指定：
    • 事务日志将应用到的数据库的名称。

    • 要从其中还原事务日志备份的备份设备。

    • NORECOVERY 子句，前提是在当前事务日志备份之后，还要应用其它事务日志备份，否则应指定 RECOVERY 子句。

      如果要应用事务日志备份，则事务日志备份必须包含备份文件和文件组时的时间。

示例

下例还原 MyNwind 数据库的文件和文件组，并替换所有名称相同的现有文件。为将数据库还原到当前时间，还应用两个事务日志。

USE master
GO
-- Restore the files and filesgroups for MyNwind.
RESTORE DATABASE MyNwind
   FILE = 'MyNwind_data_1',
   FILEGROUP = 'new_customers',
   FILE = 'MyNwind_data_2',
   FILEGROUP = 'first_qtr_sales'
   FROM MyNwind_1
   WITH NORECOVERY,
   REPLACE
GO
-- Apply the first transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log1
   WITH NORECOVERY
GO
-- Apply the last transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log2
   WITH RECOVERY
GO

请参见

RESTORE

复制数据库


如何将文件还原到新位置 (Transact-SQL)

将文件还原到新位置

重要 还原文件的系统管理员必须是唯一一位当前使用要还原的数据库的人。

  1. 执行 RESTORE FILELISTONLY 语句以确定数据库备份中文件的数量及名称（可选）。

  2. 执行 RESTORE DATABASE 语句以还原数据库备份，同时指定：
    • 要还原的数据库名称。

    • 要从其中还原数据库备份的备份设备。

    • 为每个要还原到新位置的文件指定 MOVE 子句。

    • NORECOVERY 子句。如果在创建文件备份之后没有对文件进行修改，则指定 RECOVERY 子句。
  3. 如果在创建文件备份之后对文件进行了修改，则执行 RESTORE LOG 语句以应用事务日志备份，同时指定：
    • 事务日志将应用到的数据库的名称。

    • 要从其中还原事务日志备份的备份设备。

    • NORECOVERY 子句，前提是在当前事务日志备份之后，还要应用其它事务日志备份，否则应指定 RECOVERY 子句。

      如果要应用事务日志备份，则事务日志备份必须包含备份文件和文件组时的时间。

示例

下例将 MyNwind 数据库中两个最初位于 C:\ 驱动器上的文件还原到 D:\ 驱动器上的新位置。为将数据库还原到当前时间，还应用两个事务日志。RESTORE FILELISTONLY 语句用来确定即将还原的数据库中文件的数量以及文件的逻辑和物理名称。

USE master
GO
-- First determine the number and names of the files in the backup.
RESTORE FILELISTONLY
   FROM MyNwind_1
-- Restore the files for MyNwind.
RESTORE DATABASE MyNwind
   FROM MyNwind_1
   WITH NORECOVERY,
   MOVE 'MyNwind_data_1' TO 'D:\MyData\MyNwind_data_1.mdf',
   MOVE 'MyNwind_data_2' TO 'D:\MyData\MyNwind_data_2.ndf'
GO
-- Apply the first transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log1
   WITH NORECOVERY
GO
-- Apply the last transaction log backup.
RESTORE LOG MyNwind
   FROM MyNwind_log2
   WITH RECOVERY
GO

请参见

RESTORE

复制数据库


如何用新的名称还原数据库 (Transact-SQL)

用新名称还原数据库

  1. 执行 RESTORE FILELISTONLY 语句以确定数据库备份中文件的数量及名称（可选）。

  2. 执行 RESTORE DATABASE 语句以还原数据库备份，同时指定：
    • 数据库的新名称。

    • 要从其中还原数据库备份的备份设备。

    • NORECOVERY 子句，前提是还原了文件备份后，还要应用事务日志备份。否则应指定 RECOVERY 子句。

      如果要应用事务日志备份，则事务日志备份必须包含备份文件时的时间。

    • 如果文件名已经存在，则为每个要还原到新位置的文件指定 MOVE 子句。例如，在同一台服务器上创建现有数据库的复本以便用于测试可能是必要的。在这种情况下，由于原始数据库的数据库文件已经存在，因此在还原操作期间，创建数据库复本时需要指定不同的文件名。
示例

下例创建一个称为 MyNwind2_Test 的新数据库。MyNwind2_Test 是现有 MyNwind2 数据库的复本，它包含两个文件：MyNwind2_data 和 MyNwind2_log。由于 MyNwind2 数据库已经存在，因此在还原操作期间需要移动备份中的文件。RESTORE FILELISTONLY 语句用于确定待还原数据库内的文件的数目和逻辑及物理名称。

USE master
GO
-- First determine the number and names of the files in the backup.
-- MyNwind_2 is the name of the backup device.
RESTORE FILELISTONLY
   FROM MyNwind_2
-- Restore the files for MyNwind2_Test.
RESTORE DATABASE MyNwind2_Test
   FROM MyNwind_2
   WITH RECOVERY,
   MOVE 'MyNwind2_data' TO 'D:\MyData\MyNwind2_Test_data.mdf',
   MOVE 'MyNwind2_log' TO 'D:\MyData\MyNwind2_Test_log.ldf'
GO

请参见

RESTORE

复制数据库


管理服务器

Microsoft® SQL Server™ 服务器管理由多种管理任务组成，其中包括：

  • 注册服务器和指派密码。

  • 重新配置网络连接。

  • 配置链接服务器。这使您得以对整个企业内的 OLE DB 数据源执行分布式查询和分布式事务。

  • 配置远程服务器，这使您得以使用一个 SQL Server 安装执行驻留在另一个 SQL Server 安装上的存储过程。

  • 配置备用和故障转移服务器。

  • 设置服务器配置选项。

  • 管理 SQL Server 消息。

  • 设置轮询间隔。

在大多数情况下，您无须重新配置服务器。SQL Server 安装过程中将按照默认设置对服务器组件进行配置，使您在安装结束时可以立即运行 SQL Server。但是在下列情况下需要进行服务器管理：如要添加新的服务器，设置特定的服务器配置，更改网络连接，或者设置服务器配置选项以提高 SQL Server 性能。


如何设置远程服务器以便允许使用远程存储过程 (Transact-SQL)

设置远程服务器以便允许使用远程存储过程

  1. 在第一台运行 Microsoft® SQL Server™ 的服务器上运行下列代码：
    EXEC sp_addlinkedserver ServerName1, N'SQL Server'
EXEC sp_addlinkedserver ServerName2
EXEC sp_configure 'remote access', 1
RECONFIGURE
GO
  2. 停止并重新启动第一台 SQL Server。

  3. 在第二台 SQL Server 上运行下列代码。确保使用 SQL Server 身份验证登录。
    -- The example shows how to set up access for a login 'sa'
--  from ServerName1 on ServerName2.
EXEC sp_addlinkedserver ServerName2, local
EXEC sp_addlinkedserver ServerName1
EXEC sp_configure 'remote access', 1
RECONFIGURE
GO
-- Assumes that the login 'sa' in ServerName2 and ServerName1
--  have the same password.
EXEC sp_addremotelogin ServerName1, sa, sa
GO
  4. 停止并重新启动第二台 SQL Server。

  5. 使用 sa 登录，现在就可以在第一台 SQL Server 上执行第二台 SQL Server 上的存储过程。

请参见

sp_addremotelogin

sp_configure

sp_addlinkedserver

RECONFIGURE


如何禁用远程服务器设置 (Transact-SQL)

禁用远程服务器设置

  1. 在第二台运行 Microsoft® SQL Server™ 的服务器上运行下列代码：
    EXEC sp_remoteoption ServerName1,sa, sa, trusted, false
EXEC sp_dropremotelogin ServerName1, sa, sa
RECONFIGURE
GO

EXEC sp_configure 'remote access', 0
EXEC sp_dropserver ServerName1
EXEC sp_dropserver ServerName2
RECONFIGURE
GO
  2. 停止并重新启动第二台 SQL Server。

  3. 在第一台 SQL Server 上运行下列代码：
    EXEC sp_configure 'remote access', 0
EXEC sp_dropserver ServerName2
EXEC sp_dropserver ServerName1
RECONFIGURE
GO
  4. 停止并重新启动第一台 SQL Server。

请参见

sp_configure

sp_remoteoption

sp_dropremotelogin

RECONFIGURE

sp_dropserver


如何设置和执行日志传送角色转变 (Transact-SQL)

日志传送支持角色转变，而角色转变需要下列基本步骤：

  1. 创建数据转换服务 (DTS) 包，将当前的主服务器复制到当前的辅助服务器。

  2. 创建作业，从当前的主服务器备份 syslogins，并将文件复制到当前的辅助服务器的某个目录下，然后执行该 DTS 包。

  3. 执行角色更改，使当前的辅助服务器成为当前的主服务器。

在执行日志传送角色更改前，该日志传送对的维护计划必须在辅助服务器上已经存在。可以使用数据库维护计划向导创建维护计划，或者通过使用主数据库维护计划用户界面上的"添加辅助服务器"对话框来添加辅助服务器。

创建 DTS 包，将登录从当前的主服务器复制到当前的辅助服务器

  4. 使用 DTS 设计器在当前的主服务器上创建 DTS 包。

    该包应使用位于设计器任务列表中的"传输登录任务"。

  5. 在"源"服务器列表中的"源"选项卡上的"传输登录"对话框内，输入源服务器（当前的主服务器）。

  6. 单击"使用 Windows 身份验证"或"使用 SQL Server 身份验证"。

  7. 在"目的服务器"列表的"目的"选项卡上，输入目的服务器（当前的辅助服务器）。

  8. 单击"使用 Windows 身份验证"或"使用 SQL Server 身份验证"。

  9. 在"登录"选项卡上，单击"包运行时检测到的所有服务器登录"或"选定数据库的登录"。

  10. 保存该包。

创建作业，从当前的主服务器备份 syslogins，并将文件复制到当前的辅助服务器的某个目录下，然后执行该 DTS 包

  1. 选择"新建作业"以打开"常规"选项卡上的"新建作业属性"对话框。在当前的主服务器上，创建由 sa 拥有的作业，或由对两台服务器都拥有 sysadmin 权限的登录。

  2. 在"步骤"选项卡上单击"新建"按钮以打开"新建作业步骤"对话框，然后创建下列作业步骤：
    • 向外大容量复制

      在"类型"列表中，选择"操作系统命令 (CmdExec)"选项。在"命令"文本框内输入如下命令：

      bcp master..syslogins out localpath\syslogins.dat /N /S current_primary_servername /U sa /P sa_password

      单击"高级"选项卡，然后在"成功时操作"列表中选择"转到下一步"。在"失败时操作"列表中选择"退出报告失败的作业"。

    • 复制文件

      在"类型"列表中，选择"Transact-SQL 脚本 (T-SQL)"。在"数据库"列表中，指定 master。在"命令"文本框内输入如下命令：

      EXEC xp_cmdshell 'copy localpath\syslogins.dat destination_share'

      单击"高级"选项卡，然后在"成功时操作"列表中选择"转到下一步"。在"失败时操作"列表中选择"退出报告失败的作业"。

    • 传输登录

      在"类型"列表中，选择"操作系统命令 (CmdExec)"选项。在"命令"文本框内输入如下命令：

      DTSRun /Scurrent_primary_server /Uuser_nName /Ppassword /Npackage_name /Mpackage_password
  3. 在"新建作业属性"对话框中单击"调度"选项卡，然后创建运行一次或反复运行的作业调度。

建议使作业运行时间尽可能接近角色转变的时间，以便作业从主服务器获得最多的当前登录信息。

执行角色转变，使当前的辅助服务器成为当前的主服务器

必须由 SQL Server 管理员执行服务器角色转变。

  1. 在标记为当前主服务器的 SQL Server 实例上运行 sp_change_primary_role。下例显示如何使主数据库不再是主数据库。current_primary_dbname 是当前主数据库的名称。
    EXEC sp_change_primary_role
    @db_name = 'current_primary_dbname',
    @backup_log = 1,
    @terminate = 0,
    @final_state = 2,
    @access_level = 1
GO
  2. 在标记为当前辅助服务器的 SQL Server 实例上运行 sp_change_secondary_rol。下例显示如何使辅助数据库成为主数据库。current_secondary_dbname 是当前辅助数据库的名称。
    EXEC sp_change_secondary_role
    @db_name = 'current_secondary_dbname',
    @do_load = 1,
    @force_load = 1,
    @final_state = 1,
    @access_level = 1,
    @terminate = 1,
    @stopat = NULL
GO
  3. 在标记为监视器的 SQL Server 实例上运行 sp_change_monitor_role。下例显示如何更改监视器以反映新的主数据库。new_source_directory 是主服务器转储事务日志的位置的路径。
    EXEC sp_change_monitor_role
    @primary_server = 'current_primary_server_name',
    @secondary_server = 'current_secondary_server_name',
    @database = 'current_secondary_dbname',
    @new_source = 'new_source_directory'
GO
  4. 在现在标记为主服务器（从前的辅助服务器）的 SQL Server 实例上运行 sp_resolve_logins。必须从目标数据库运行存储过程。

    下例显示如何用从前的主服务器中的登录解析新的主服务器上的登录。destination_path 是在复制文件作业步骤中指定的目的共享。filename 与 BCP 输出作业步骤中指定的相同，dbname 为新主数据库的名称。

    EXEC sp_resolve_logins
    @dest_db = 'dbname',
    @dest_path = 'destination_path',
    @filename = 'filename'
GO

从前的辅助服务器现在是当前的主服务器，并准备承担主服务器的功能。从前的主服务器已不再是日志传送对的一方了。必须将从前的主服务器作为辅助服务器添加到新的主服务器，才能在两个数据库之间建立日志传送对。

请参见

sp_change_monitor_role

sp_change_primary_role

sp_change_secondary_role

sp_resolve_logins


如何设置日志传送监视器 (Transact-SQL)

在 SQL Server 实例上设置日志传送监视器

在运行 Microsoft® SQL Server™ 2000 实例的服务器上执行下列存储过程，这些服务器将监视日志传送。

  1. 运行 sp_add_log_shipping_primary 以通知监视服务器哪台计算机在日志传送对中是主服务器。存储过程的输出将是 primary_id，它将用于 sp_add_log_shipping_secondary 存储过程。

  2. 运行 sp_add_log_shipping_secondary 以通知监视服务器哪台计算机在日志传送对中是辅助服务器。
示例

下例为 Northwind 数据库的现有日志传送对设置日志传送监视器。在手工设置该监视器之前，必须已使用数据库维护计划向导设置了日志传送。注意，在向导设置过程中也要创建监视器。

EXEC sp_add_log_shipping_primary
   @primary_server_name = 'MyPrimaryServer',
   @primary_database_name = 'Northwind',
   @maintenance_plan_id = '9B4E380E-11D2-41FC-9BA5-A8EB040A3DEF',
   @backup_threshold = 15,
   @threshold_alert = 14420,
   @threshold_alert_enabled = 1,
   @planned_outage_start_time = 0,
   @planned_outage_end_time = 0,
   @planned_outage_weekday_mask = 0

EXEC sp_add_log_shipping_secondary
   @primary_id = 1,
   @secondary_server_name = 'MySecondaryServer',
   @secondary_database_name = 'Northwind',
   @secondary_plan_id = 'B5C330FF-1081-4FCB-83D0-955DDFB56BA5',
   @copy_enabled = 1,
   @load_enabled = 1,
   @out_of_sync_threshold = 15,
   @threshold_alert = 14421,
   @threshold_alert_enabled = 1,
   @planned_outage_start_time = 0,
   @planned_outage_end_time = 0,
   @planned_outage_weekday_mask = 0,
   @allow_role_change = 0
GO

请参见

sp_add_log_shipping_primary

sp_add_log_shipping_secondary


如何从日志传送监视器中删除日志传送对 (Transact-SQL)

从 Microsoft® SQL Server™ 2000 实例上的日志传送监视器中删除日志传送对

  • 在监视服务器上运行 sp_delete_log_shipping_monitor_info。这将通知监视服务器将删除哪个日志传送对。注意，并未删除实际的日志传送对。只有监视器受此操作的影响。

  • 在主服务器或辅助服务器上运行 sp_delete_database_backuphistory（可选）。这将删除有关被删除的日志传送对成员的备份历史记录信息。
示例

下例从 Northwind 数据库的现有日志对的日志传送监视器中删除日志传送对：

EXEC sp_delete_log_shipping_monitor_info
   @primary_server_name = 'MyPrimaryServer',
   @primary_database_name = 'Northwind',
   @secondary_server_name = 'MySecondaryServer',
   @secondary_database_name = 'Northwind'
GO

也可以使用下列存储过程调用来删除有关被删除的日志传送对成员的备份历史记录信息。在每台主服务器和辅助服务器上执行该命令：

EXEC sp_delete_database_backuphistory 'Northwind'
GO

请参见

sp_delete_log_shipping_monitor_info

''''''''


管理任务自动化

在管理 Microsoft® SQL Server™ 系统时，许多重复执行的任务都可以自动完成。

可以将作业和任务定义在特定时间到来时或特定事件发生后运行。这些作业经常使用 SQL Server 企业管理器定义，但是也可以使用 Transact-SQL 语句定义。


如何创建作业 (Transact-SQL)

创建作业

  1. 执行 sp_add_job 创建作业。

  2. 执行 sp_add_jobstep 创建一个或多个作业步骤。

  3. 执行 sp_add_jobschedule 创建作业调度。

说明 建议在执行完 sp_add_jobstep 后再执行 sp_add_jobserver，以便最高效率地将作业更改传送给所有涉及的服务器。

因为本地 SQL Server 代理缓存本地作业，所以任何修改都会隐性地强制 SQL Server 代理重新缓存该作业。因为直到调用 sp_add_jobserver 时，SQL Server 代理才缓存作业，所以最后调用 sp_add_jobserver 更为高效。

请参见

创建作业

系统存储过程（SQL Server 代理过程）


如何创建主 SQL Server 代理作业 (Transact-SQL)

创建主 SQL Server 代理作业

  1. 执行 sp_add_job 创建作业。

  2. 执行 sp_add_jobstep 创建一个或多个作业步骤。

  3. 执行 sp_add_jobschedule 创建作业调度。

  4. 执行 sp_add_jobserver 以指定运行该作业的目标服务器。

说明 建议在执行完 sp_add_jobstep 后再执行 sp_add_jobserver，以便最高效率地将作业更改传送给所有涉及的服务器。

对主 SQL Server 代理作业的更改必须传播给所有涉及的目标服务器。因为直到调用 sp_add_jobserver 时，目标服务器才开始下载作业，所以建议在执行 sp_add_jobserver 之前，创建特定作业的所有作业步骤和作业调度。否则，必须随后调用 sp_post_msx_operation，请求目标服务器重新下载修改过的作业。

请参见

系统存储过程（SQL Server 代理过程）


如何修改主 SQL Server 代理作业 (Transact-SQL)

更改作业定义的调度详细信息

  • 执行 sp_update_jobschedule。

通过处理作业步骤，在某个作业中添加、更改或删除步骤

  1. 执行 sp_add_jobstep 添加新的作业步骤。

  2. 执行 sp_update_jobstep 更改原先存在的作业步骤。

  3. 执行 sp_delete_jobstep 删除原先存在的作业。

修改与作业关联的目标服务器

  1. 执行 sp_delete_jobserver 删除当前与某个作业关联的服务器。

  2. 执行 sp_add_jobserver 将某个服务器与当前作业相关联。

说明 主 SQL Server 代理作业不能同时把本地服务器和远程服务器作为目标。

请参见

创建作业

系统存储过程（SQL Server 代理过程）


如何创建操作员 (Transact-SQL)

创建本地作业的操作员

  • 执行 sp_add_operator。

创建主 SQL Server 代理的操作员

  1. 执行 sp_add_operator 指定主 SQL Server 代理操作员。

  2. 执行 sp_add_targetsvrgrp_member，将指定的目标服务器添加到目标服务器组。

  3. 执行 sp_msx_enlist，在作业中登记目标服务器。

  4. 执行"如何创建主 SQL Server 代理作业 (Transact-SQL)"中的步骤，创建主 SQL Server 代理作业。

请参见

定义操作员

系统存储过程（SQL Server 代理过程）


如何修改操作员 (Transact-SQL)

修改本地操作员

  • 执行 sp_update_operator。

修改主 SQL Server 代理的操作员

  1. 执行 sp_msx_defect，从主 SQL Server 代理中删除目标服务器。

  2. 执行 sp_update_operator 更改操作员。

请参见

修改和查看操作员

系统存储过程（SQL Server 代理过程）


监视服务器性能和活动

有许多工具和技术可用于监视 Microsoft® SQL Server™ 2000。监视 SQL Server 的一般原因是：

  • 判断能否改善性能。

  • 判断用户活动以确定用户正在发出的查询以及正连接到 SQL Server 的用户。

  • 排除故障。

  • 测试应用程序。


如何创建跟踪 (Transact-SQL)

创建跟踪

  1. 执行带所需参数的 sp_trace_create 以创建新的跟踪。新的跟踪将处于停止状态（status 为 0）。

  2. 执行带所需参数的 sp_trace_setevent 以选择要跟踪的事件和列。

  3. 也可以执行 sp_trace_setfilter 以设置任意筛选或筛选组合。

    sp_trace_setevent 和 sp_trace_setfilter 只能在已停止的现有跟踪上执行。

    重要 与常规存储过程不同的是，必须严格键入所有 SQL 事件探查器存储过程 (sp_trace_xx) 的参数，而且这些参数不支持自动数据类型转换。如果没有用正确的输入参数数据类型（与在参数描述中指定的相同）调用这些参数，则存储过程将返回错误。

请参见

创建并管理跟踪和模板

sp_trace_create

sp_trace_setevent


如何设置跟踪筛选 (Transact-SQL)

设置跟踪筛选

  1. 如果已经运行跟踪，则执行 sp_trace_setstatus 并指定 @status = 0 以停止跟踪。

  2. 执行 sp_trace_setfilter 以配置要为跟踪的事件检索的信息类型。

    重要 与常规存储过程不同的是，必须严格键入所有 SQL 事件探查器存储过程 (sp_trace_xx) 的参数，而且这些参数不支持自动数据类型转换。如果没有用正确的输入参数数据类型（与在参数描述中指定的相同）调用这些参数，则存储过程将返回错误。

请参见

创建并管理跟踪和模板

限制跟踪

sp_trace_setfilter

sp_trace_setstatus

系统存储过程（SQL 事件探查器过程）


如何修改现有的跟踪 (Transact-SQL)

修改现有的跟踪

  1. 如果已经运行跟踪，则执行 sp_trace_setstatus 并指定 @status = 0 以停止跟踪。

  2. 若要修改跟踪事件，请执行 sp_trace_setevent，并通过参数指定更改。以下按顺序列出了这些参数：
    • @traceid (Trace ID)

    • @eventid (Event ID)

    • @columnid (Column ID)

    • @on (ON)

    修改 @on 参数时，要记住它与 @columnid 参数是相互影响的：

    ON | Column ID | 结果
    ON (1) NULL 打开事件。
    清除所有列。
    NOT NULL | 为指定的事件打开列。
    OFF (0) NULL 关闭事件。
    清除所有列。
    NOT NULL | 为指定的事件关闭列。

    重要 与常规存储过程不同的是，必须严格键入所有 SQL 事件探查器存储过程 (sp_trace_xx) 的参数，而且这些参数不支持自动数据类型转换。如果没有用正确的输入参数数据类型（与在参数描述中指定的相同）调用这些参数，则存储过程将返回错误。

请参见

创建并管理跟踪和模板

修改模板

sp_trace_setevent

系统存储过程（SQL 事件探查器过程）


如何查看保存过的跟踪 (Transact-SQL)

查看特定的跟踪

  • 执行 fn_trace_getinfo 并指定所需信息的跟踪 ID。该函数将返回一个表，表中列出了跟踪、跟踪属性和有关属性的信息。

    通过以下方式唤醒调用该函数：

    SELECT *
FROM ::fn_trace_getinfo(trace_id)

查看所有现有跟踪

  • 执行 fn_trace_getinfo 并指定"0"或术语"default"。该函数将返回一个表，表中列出了跟踪、跟踪属性和有关这些属性的信息。

    通过以下方式唤醒调用该函数：

    SELECT *
FROM ::fn_trace_getinfo(default)

请参见

创建并管理跟踪和模板

fn_trace_getinfo

查看和分析跟踪


如何查看筛选信息 (Transact-SQL)

查看筛选信息

  • 执行 fn_trace_getfilterinfo 并指定所需的筛选信息的跟踪 ID。该函数将返回一个表，表中列出了筛选、应用筛选的列和应用筛选的值。

    通过以下方式唤醒调用该函数：

    SELECT *
FROM ::fn_trace_getfilterinfo(trace_id)

请参见

创建并管理跟踪和模板

fn_trace_getfilterinfo

系统存储过程（SQL 事件探查器过程）

查看和分析跟踪


如何删除跟踪 (Transact-SQL)

删除跟踪

  1. 执行 sp_trace_setstatus 并指定 @status = 0 以停止跟踪。

  2. 执行 sp_trace_setstatus 并指定 @status = 2 以关闭跟踪并从服务器中删除它的信息。

    说明 在关闭跟踪前必须先停止它。

请参见

创建并管理跟踪和模板

删除跟踪

sp_trace_setstatus

系统存储过程（SQL 事件探查器过程）


将 SQL Server 与其它工具集成

Microsoft® SQL Server™ 应用程序可以在 Transact-SQL 语句中引用自动化对象。SQL Server 还可以使用遵从 MAPI 标准的电子邮件系统发送和接收电子邮件。


如何创建 OLE 自动化对象 (Transact-SQL)

创建 OLE 自动化对象

  1. 调用 sp_OACreate 创建对象。

  2. 使用该对象。
    • 调用 sp_OAGetProperty 获取属性值。

    • 调用 sp_OASetProperty 将属性设为新值。

    • 调用 sp_OAMethod 以调用某个方法。

    • 调用 sp_OAGetErrorInfo 获取最新的错误信息。
  3. 调用 sp_OADestroy 释放对象。

说明 所有这些步骤都必须在单个 Transact-SQL 语句批处理内执行。在每个语句批处理结束时将自动释放所有创建的 OLE 对象。

请参见

系统存储过程

使用 OLE 自动化存储过程进行数据类型转换

如何调试自定义 OLE 自动化服务器 (Transact-SQL)

OLE 自动化脚本示例


如何调试自定义 OLE 自动化服务器 (Transact-SQL)

可以调试由 32 位 Microsoft® Visual Basic® 4.0 版创建的自定义 OLE 自动化服务器。为此，必须在 Microsoft SQL Server™ 计算机上安装 Visual Basic，并且必须在同一个 Microsoft Windows NT® 用户帐户下运行 SQL Server 和 Visual Basic。SQL Server 必须独立于 Windows NT 服务控制管理器，从命令行启动（使用 sqlservr /c 命令），或者必须使用登录系统时所使用的 Windows NT 用户帐户启动 SQL Server 服务。

调试自定义 OLE 自动化服务器

  1. 将自定义 OLE 自动化服务器工程装入 Visual Basic。

  2. 在需要的源代码行上设置断点。

  3. 在"运行"菜单上，单击"全编译执行"命令。

    此步骤将注册并运行自定义 OLE 自动化服务器。

  4. 使用 OLE 自动化存储过程调用由自定义 OLE 自动化服务器表现的 OLE 对象。

    遇到断点时，将激活 Visual Basic 调试程序。

有关更多信息，请参阅 Visual Basic 文档。

使用 32 位 Visual Basic 4.0 创建的自定义进程内 OLE 服务器必须具有用于 Class_Initialize 和 Class_Terminate 子例程的错误处理程序（用 On Error GoTo 语句指定）。该错误处理程序可以防止这些子例程中出现未处理的错误。Class_Initialize 和 Class_Terminate 子例程中未处理的错误可能会导致不可预期的 SQL Server 问题，如 SQL Server 违规访问。建议其它子例程也使用错误处理程序。

请参见

系统存储过程

如何创建 OLE 自动化对象 (Transact-SQL)

使用 OLE 自动化存储过程进行数据类型转换

OLE 自动化脚本示例


如何使用 SQL 邮件 (Transact-SQL)

SQL 邮件使用了几个启用邮件功能所必需的扩展存储过程。这些扩展存储过程都包含在一个动态链接库 SQLMAP70.DLL 中，该动态链接库是随 Microsoft® SQL Server™ 2000 一起安装的。

手工处理电子邮件

  1. 在 SQL 查询分析器中，通过执行 xp_startmail 启动 SQL Server 邮件客户程序会话。

  2. 若要查找邮箱中下一个未读邮件的 ID，请执行 xp_findnextmsg。

  3. 若要读取邮件或附件，请执行 xp_readmail（使用特定的邮件 ID）,并且在 SELECT 语句中使用输出变量，在结果窗格中显示邮件。

  4. 若要删除邮件，请执行 xp_deletemail（使用特定的邮件 ID）。

  5. 若要将邮件或查询结果集发送给指定的收件人，请执行 xp_sendmail（在邮件正文中包含该查询）。

  6. 通过执行 xp_stopmail 停止 SQL Server 邮件客户程序会话。

将多个电子邮件作为调度作业处理

  1. 在 SQL 查询分析器中，通过执行 xp_startmail 启动 SQL Server 邮件客户程序会话。

  2. 执行 sp_processmail 查找、读取、响应和删除多个邮件。

  3. 通过执行 xp_stopmail 停止 SQL Server 邮件客户程序会话。

请参见

sp_processmail

xp_sendmail

xp_deletemail

xp_startmail

xp_findnextmsg

xp_stopmail

xp_readmail


复制类型

Microsoft® SQL Server™ 2000 提供以下复制类型，可以在分布式应用程序中使用：

  • 快照复制

  • 事务复制

  • 合并复制

每种类型提供不同的能力，主要依据应用程序以及事务和站点独立的不同 ACID 属性级别。例如，合并复制使得用户可以自主使用和更新数据，即使没有确定的 ACID 属性。但是，当重新连接服务器时，复制拓扑中的所有站点都汇聚为相同的数据值。事务复制维持事务的一致性，但订阅服务器站点的自治功能不如在合并复制中那样强，因为发布服务器和订阅服务器的连接通常必须是可靠且连续的，以便更新能传播到订阅服务器上。

一个应用程序可以使用多个复制类型和选项。应用程序中的有些数据可能不需要在订阅服务器上更新，有些数据集可能需要偶尔更新，但是这种更新只在一个或几个服务器上进行，而有些数据集可能需要在多个服务器上每天更新。

为应用程序选择何种复制类型取决于分布式数据的因素、数据是否需要在订阅服务器上更新、复制环境，以及被复制数据的需要和要求。有关更多信息，请参阅复制计划。

每种类型的复制都是以在订阅服务器上生成和应用快照开始的，所以了解快照复制以及其它类型的复制和所选选项是很重要的。


如何设置项目的行级或列级跟踪 (Transact-SQL)

  • 如果正在向发布中添加合并项目，则应将复制存储过程 sp_addmergearticle 的 @column_tracking 参数设置为 true（对于列级跟踪）或 false（对于行级跟踪）。

  • 如果正在更改发布中现有非活动合并项目的属性，则应将复制存储过程 sp_changemergearticle 的 @property = 参数设置为 column_tracking，然后将 @value = 参数设置为 true（对于列级跟踪）或 false（对于行级跟踪）。

如果该属性在发布得到活动订阅后出现更改，当前快照就将作废，而现有订阅将被标记以便重新初始化。


如何选择冲突解决程序 (Transact-SQL)

  • 如果正在使用存储过程创建发布并且需要指定冲突解决程序，则应将复制存储过程 sp_addmergearticle 的 @article_resolver = 参数设置为自定义冲突解决程序的名称。如果自定义冲突解决程序是一个存储过程，还应将 @resolver_info = 参数设置为该存储过程的名称。

  • 如果正在更改发布中现有合并项目的冲突解决程序属性，则应将复制存储过程 sp_changemergearticle 的 @property = 参数设置为 article_resolver，然后将 @value = 参数设置为自定义冲突解决程序的名称。如果自定义冲突解决程序是一个存储过程，则应执行第二个 sp_changemergearticle 语句，并将 @property = 参数设置为 resolver_info，然后将 @value = 参数设置为该存储过程的名称。


执行复制 (Transact-SQL)

无论使用快照复制、事务复制还是合并复制，以下阶段都将帮助您执行复制。

阶段 | 任务
配置复制 | 在拓扑中标识发布服务器、分发服务器和订阅服务器。使用 SQL Server 企业管理器、SQL-DMO 脚本或 Transact-SQL 系统存储过程配置发布服务器，创建分发数据库并启用订阅服务器。
发布数据和数据库对象 | 在发布中创建发布并定义数据和数据库对象项目，并将必要的筛选器应用到要发布的数据。
订阅到发布 | 创建强制、请求或匿名订阅说明需要传播到个人订阅服务器发布的类型和时间。
应用初始快照 | 说明在何处保存快照文件，这些文件是否已被压缩，以及在应用初始快照之前或之后要运行的脚本。 指定在创建订阅之后或指定时间使快照代理在订阅服务器上立即应用快照。 通过将快照保存到网络位置或能够传送到订阅服务器的可移动介质来手工应用快照，然后在订阅服务器上手工应用快照文件。
同步数据 | 当快照、日志读取器或合并代理运行并且更新在发布服务器和订阅服务器之间传播时，将同步数据。 对于快照复制，快照将在订阅服务器上重新应用。 对于事务复制，更新将传播到订阅服务器。 如果在快照复制或事务复制使用可更新订阅，数据将从订阅服务器传播到发布服务器以及其它订阅服务器。 对于合并复制，在合并过程中进行数据同步（所有服务器的数据更改进行汇聚，如果有冲突，会进行检测和解决）。


如何配置发布和分发 (Transact-SQL)

  1. 在将成为分发服务器的服务器上执行 sp_adddistributor。

  2. 在分发服务器上执行 sp_adddistributiondb，以创建一个新的分发数据库。

  3. 在将成为（使用分发服务器的）发布服务器的每台服务器上执行 sp_adddistpublisher。

在发布服务器的 master 数据库上，对将成为发布数据库的每个数据库执行 sp_replicationdboption。


如何修改发布服务器和分发服务器属性 (Transact-SQL)

查看分发服务器属性

  1. 执行 sp_helpdistributor，以列出有关分发服务器、分发数据库、工作目录和 SQL Server 代理程序用户帐户的信息。

  2. 执行 sp_helpdistributiondb，以返回指定分发数据库的属性。

修改分发服务器

  1. 执行 sp_changedistributor_property，以修改分发服务器属性。

  2. 执行 sp_changedistributiondb，以修改分发数据库属性。

在分发服务器上添加密码

  • 执行 sp_add_distributor 并指定 password 参数。

在分发服务器上更改密码

  • 执行 sp_changedistributor_password。

创建新的分发数据库

  • 执行 sp_adddistributiondb，以创建新的分发数据库并安装分发架构。

在分发数据库中添加发布服务器

  • 执行 sp_adddistpublisher n 次，以定义使用分发服务器的各个发布服务器。

从分发数据库中删除发布服务器

  • 执行 sp_dropdistpublisher，以除去同时也是分发服务器的发布服务器。


如何禁用发布和分发 (Transact-SQL)

禁用分发服务器 (Transact-SQL)

  1. 执行 sp_dropdistpublisher，以除去同时也是分发服务器的发布服务器。

  2. 执行 sp_dropdistributiondb，以删除分发数据库。

  3. 执行 sp_dropdistributor，以从服务器中删除分发服务器指定。

删除分发数据库 (Transact-SQL)

  • 执行 sp_dropdistributiondb，以删除分发数据库。

在未连接分发服务器 (Transact-SQL) 的发布服务器上手工删除复制

  • 用 @no_checks=1 和 @ignore_distributor=1 执行 sp_dropdistributor。


如何创建发布并定义项目 (Transact-SQL)

创建快照发布或事务发布

  1. 执行 sp_replicationdboption，以启用当前数据库的发布。

  2. 执行 sp_addpublication 并将 repl_freq 设置为快照，以定义发布。

  3. 执行 sp_addpublication_snapshot 以创建一个快照代理程序，设置发布 agent_id，并在复制工作目录中放入架构和数据。

  4. 执行 sp_addarticle n 次，以定义发布中的各个项目。

定义快照或事务发布的项目

  1. 执行 sp_addarticle，以定义一个项目。

  2. 执行 sp_articlefilter，以对表进行水平筛选。

  3. 执行 sp_articlecolumn，以对表进行垂直筛选。

  4. 执行 sp_articleview，以在垂直或水平筛选表时为项目创建同步对象。

创建合并发布

  1. 执行 sp_replicationdboption，以启用当前数据库的发布。

  2. 执行 sp_addmergepublication，以定义发布。

  3. 执行 sp_addpublication_snapshot，以创建一个快照代理程序，并在复制工作目录中放入架构和数据。

  4. 执行 sp_addmergearticle n 次，以定义发布中的各个项目。

定义合并项目

  1. 执行 sp_addmergearticle，以定义一个项目。

  2. 执行 sp_addmergefilter，以创建一个分区发布。


如何修改发布和项目 (Transact-SQL)

查看快照或事务发布属性

  • 执行 sp_helppublication，以显示有关发布的信息。

查看合并发布属性

  • 执行 sp_helpmergepublication，以显示有关发布的信息。

修改发布属性

  • 执行 sp_changepublication，以修改发布的属性。

修改合并发布属性

  • 执行 sp_changemergepublication，以修改发布的属性。

查看快照或事务发布的项目属性

  1. 执行 sp_helparticle，以显示有关项目的信息。

  2. 执行 sp_helparticlecolumns，以显示项目的基础表中的所有列。

查看合并项目属性

  1. 执行 sp_helpmergearticle，以显示有关合并项目的信息。

  2. 执行 sp_helpmergefilter，以显示有关合并筛选的信息。

修改快照或事务发布的项目属性

  • 执行 sp_changearticle，以更改项目的属性。

修改合并项目属性

  1. 执行 sp_changemergearticle，以更改项目的属性。

  2. 执行 sp_changemergefilter，以更改筛选的属性。


如何删除发布和项目 (Transact-SQL)

删除快照或事务发布

  1. 执行 sp_dropsubscription，以删除所有快照订阅。

  2. 执行 sp_droppublication，以删除发布及其所有项目。

  3. 执行 sp_replicationdboption，以禁用当前数据库的复制。

说明 如果只删除一个发布并且仍需要从当前数据库中发布，则不应调用 sp_replicationdboption 禁用数据库的发布。

删除快照或事务发布的项目

  • 执行 sp_droparticle，以从发布中删除项目。

删除合并发布

  1. 执行 sp_dropmergesubscription，以删除所有的合并订阅。

  2. 执行 sp_mergesubscription_cleanup，以删除订阅数据库中所有合并项目的合并配置。

  3. 执行 sp_dropmergepublication，以删除发布及其所有项目。

  4. 执行 sp_replicationdboption，以禁用当前数据库的复制。

说明 如果只删除一个发布并且需要从当前数据库中发布，则不应调用 sp_replicationdboption 禁用数据库的发布。

删除合并项目

  • 执行 sp_dropmergearticle，以从发布中删除项目。


如何创建强制订阅 (Transact-SQL)

添加对快照发布的强制订阅 (Transact-SQL)

  1. 执行 sp_addsubscriber，以在发布服务器上注册订阅服务器。

  2. 执行 sp_addpublication 并将 allow_push 设置为 TRUE，以启用强制订阅。

  3. 执行 sp_addsubscription，以创建订阅。

创建强制订阅（事务）

  1. 执行 sp_addsubscriber，以在发布服务器上注册订阅服务器。

  2. 执行 sp_addpublication 并将 allow_push 设置为 true，以启用强制订阅。

  3. 执行 sp_addsubscription，以创建订阅。

添加强制订阅（合并）

  1. 执行 sp_addsubscriber，以在发布服务器上注册订阅服务器。

  2. 执行 sp_addmergepublication 并将 allow_push 设置为 true，以启用强制订阅。

  3. 执行 sp_addmergesubscription，以创建订阅。


如何修改强制订阅 (Transact-SQL)

查看快照发布的强制订阅属性

  1. 执行 sp_helpsubscription，以列出与某一特定发布、项目、订阅服务器或订阅集相关的订阅信息。

  2. 执行 sp_helpsubscriberinfo，以显示有关订阅服务器的信息。

修改快照发布的强制订阅属性

  1. 执行 sp_changesubscriber，以更改订阅服务器选项。

  2. 执行 sp_changesubstatus，以更改订阅服务器状态。

查看事务发布的强制订阅属性

  1. 执行 sp_helpsubscription，以列出与某一特定发布、项目、订阅服务器或订阅集相关的订阅信息。

  2. 执行 sp_helpsubscriberinfo，以显示有关订阅服务器的信息。

修改事务发布的强制订阅属性

  1. 执行 sp_changesubscriber，以更改订阅服务器选项。

  2. 执行 sp_changesubstatus，以更改订阅服务器状态。

查看合并发布的强制订阅属性

  • 执行 sp_helpmergesubscription，以列出与某一特定发布、项目、订阅服务器或订阅集相关的订阅信息。

修改合并发布的强制订阅属性

  • 执行 sp_changemergesubscription，以更改订阅服务器选项。


如何删除强制订阅 (Transact-SQL)

删除对快照发布的强制订阅

  1. 执行 sp_dropsubscription，以删除订阅。

  2. 执行 sp_dropsubscriber，以删除订阅服务器的注册项。

说明 不必除去订阅服务器，除非您正在除去它所订阅的最后一个发布。

删除对事务发布的强制订阅

  1. 执行 sp_dropsubscription，以删除订阅。

  2. 执行 sp_dropsubscriber，以删除订阅服务器的注册项。

说明 不必除去订阅服务器，除非您正在除去它所订阅的最后一个发布。

删除对合并发布的强制订阅

  • 执行 sp_dropmergesubscription，以删除订阅。


如何创建请求订阅 (Transact-SQL)

添加对快照发布的请求订阅

  1. 执行 sp_addpublication 并将 allow_pull 设置为 true，以在发布服务器上启用请求订阅。

  2. 执行 sp_addsubscriber，以在发布服务器上注册订阅服务器。

  3. 执行 sp_addsubscription，以在发布服务器上创建订阅。

  4. 执行 sp_addpullsubscription，以在订阅服务器上创建请求订阅。

  5. 执行 sp_addpullsubscription_agent，以在订阅服务器上为分发代理程序创建一个已调度作业。

创建请求订阅（事务）

  1. 执行 sp_addpublication 并将 allow_pull 设置为 TRUE，以在发布服务器上启用请求订阅。

  2. 执行 sp_addsubscriber，以在发布服务器上注册订阅服务器。

  3. 执行 sp_addsubscription，以在发布服务器上创建订阅。

  4. 执行 sp_addpullsubscription，以在订阅服务器上创建请求订阅。

  5. 执行 sp_addpullsubscription_agent，以在订阅服务器上为分发代理程序创建一个已调度作业。

添加请求订阅（合并）

  1. 执行 sp_addmergepublication 并将 allow_pull 设置为 TRUE，以在发布服务器上启用请求订阅。

  2. 执行 sp_addsubscriber，以在发布服务器上注册订阅服务器。

  3. 执行 sp_addmergesubscription，以在发布服务器上创建订阅。

  4. 执行 sp_addmergepullsubscription，以在订阅服务器上创建订阅。

  5. 执行 sp_addmergepullsubscription_agent，以在订阅服务器上为分发代理程序创建一个已调度作业。


如何查看或修改请求或匿名订阅 (Transact-SQL)

查看快照发布的请求和匿名订阅属性

  1. 执行 sp_helpsubscription，以列出与某一特定发布、项目、订阅服务器或订阅集相关的订阅信息。

  2. 执行 sp_helppullsubscription，以显示有关订阅服务器上一个或多个订阅的信息。

  3. 执行 sp_helpsubscriberinfo，以显示有关订阅服务器的信息。

修改快照发布的请求和匿名订阅属性

  1. 执行 sp_changesubscriber，以更改订阅服务器选项。

  2. 执行 sp_changesubstatus，以更改订阅服务器状态。

查看请求和匿名订阅属性（事务）

  1. 执行 sp_helpsubscription，以列出与某一特定发布、项目、订阅服务器或订阅集相关的订阅信息。

  2. 执行 sp_helppullsubscription，以显示有关订阅服务器上一个或多个订阅的信息。

  3. 执行 sp_helpsubscriberinfo，以显示有关订阅服务器的信息。

修改请求和匿名订阅属性（事务）

  1. 执行 sp_changesubscriber，以更改订阅服务器选项。

  2. 执行 sp_changesubstatus，以更改订阅服务器状态。

查看请求和匿名订阅属性（合并）

  • 执行 sp_helpmergepullsubscription，以列出与某一特定发布、项目、订阅服务器或订阅集相关的订阅信息。

修改请求和匿名订阅属性（合并）

  • 执行 sp_changemergepullsubscription，以更改订阅服务器选项。


如何删除请求订阅 (Transact-SQL)

删除对快照发布的请求订阅

  1. 执行 sp_dropsubscription，以删除订阅。

  2. 执行 sp_dropsubscriber，以删除订阅服务器的注册项。

删除请求订阅（事务）

  1. 执行 sp_dropsubscription，以删除订阅。

  2. 执行 sp_dropsubscriber，以删除订阅服务器的注册项。

  3. 在订阅服务器上执行 sp_droppullsubscription。

删除请求订阅（合并）

  • 执行 sp_dropmergepullsubscription，以删除订阅。


如何创建匿名订阅 (Transact-SQL)

添加对快照发布的匿名订阅 (Transact-SQL)

  1. 执行 sp_addpublication 并将 allow_pull、allow_anonymous 和 immediate_sync 设置为 TRUE，以启用匿名订阅。

  2. 执行 sp_addpullsubscription，以在订阅服务器上创建匿名订阅。

  3. 执行 sp_addpullsubscription_agent，以在订阅服务器上为分发代理程序创建一个已调度作业。

添加匿名订阅（事务）

  1. 执行 sp_addpublication 并将 allow_pull、allow_anonymous 和 immediate_sync 设置为 TRUE，以启用匿名订阅。

  2. 执行 sp_addpullsubscription，以在订阅服务器上创建匿名订阅。

  3. 执行 sp_addpullsubscription_agent，以在订阅服务器上为分发代理程序创建一个已调度作业。

添加对合并发布的匿名订阅

  1. 执行 sp_addmergepublication 并将 allow_pull 和 allow_anonymous 设置为 TRUE，以在发布服务器上启用匿名订阅。

  2. 执行 sp_addmergepullsubscription，以在订阅服务器上创建匿名订阅。

  3. 执行 sp_addmergepullsubscription_agent，以在订阅服务器上为匿名的合并代理程序创建一个已调度作业。


如何删除匿名订阅 (Transact-SQL)

禁用允许匿名订阅的快照发布

  1. 执行 sp_droparticle n 次，以删除发布中的各个项目。

  2. 执行 sp_droppublication，以删除发布。

  3. 执行 sp_replicationdboption，以禁用当前数据库的复制。

说明 匿名订阅对于发布服务器来说是未知的。上述步骤通过除去一个发布禁用了对该发布的所有匿名订阅。

禁用允许匿名订阅的事务发布

  1. 执行 sp_droparticle n 次，以删除发布中的各个项目。

  2. 执行 sp_droppublication，以删除发布。

  3. 执行 sp_replicationdboption，以禁用当前数据库的复制。

说明 匿名订阅对于发布服务器来说是未知的。上述步骤通过除去一个发布禁用了对该发布的所有匿名订阅。

禁用允许匿名订阅的合并发布

  1. 执行 sp_dropmergearticle n 次，以删除发布中的各个项目。

  2. 执行 sp_dropmergepublication，以删除发布。

  3. 执行 sp_replicationdboption，以禁用当前数据库的复制。

说明 匿名订阅对于发布服务器来说是未知的。上述步骤通过除去一个发布禁用了对该发布的所有匿名订阅。


如何浏览和复制快照文件 (Transact-SQL)

浏览快照文件

  • 对于事务发布，在发布服务器上执行 sp_browsesnapshotfolder Transact-SQL 系统存储过程。

  • 对于合并发布，在发布服务器上执行 sp_browsemergesnapshotfolder Transact-SQL 系统存储过程。

复制快照文件

  • 对于事务发布，在发布服务器上执行 sp_copysnapshot Transact-SQL 系统存储过程。

  • 对于合并发布，在发布服务器上执行 sp_copymergesnapshot Transact-SQL 系统存储过程。


如何在发布数据库上应用架构更改 (Transact-SQL)

将列添加到项目

  • 执行 sp_repladdcolumn 存储过程并设置以下参数。
    参数

            功能

    @source_object

            对要将列添加到的表进行命名。

    @column

            对将要添加的列进行命名。

    @typetext

            定义列（数据类型信息、默认值等）。在用于列定义的 SQL 中，必须指定默认值，或者允许 NULL 值。

    有关定义列所需语法的信息，请参阅 ALTER TABLE。

    @publication_to_add

            列出要向其添加列的发布的名称；也可以使用 all 或 none 这两个值。

    @force_invalidate_snapshot

            当设置为 0 时，仍然会在需要时提供带有先前架构信息的当前快照。该参数只影响用 immediate_sync 选项创建的发布。

    @force_reinit_subscription

            当设置为 1 时，将不会向订阅服务器传播架构更改命令。架构更改影响到的所有订阅都将进行重新初始化，但非同步订阅除外，对它不会有任何影响。

从项目中除去列

  • 执行 sp_repldropcolumn 存储过程并设置以下参数。
    参数

            功能

    @source_object

            对将从其中除去列的表进行命名。

    @column

            对将要除去的列进行命名。

    @force_invalidate_snapshot

            当设置为 0 时，仍然会在需要时提供带有先前架构信息的当前快照。该参数只影响用 immediate_sync 选项创建的发布。

    @force_reinit_subscription

            当设置为 1 时，将不会向订阅服务器传播架构更改命令。架构更改影响到的所有订阅都将进行重新初始化，但非同步订阅除外，对它不会有任何影响。


如何在 Internet 上发布数据 (Transact-SQL)

使用快照复制在 Internet 上进行发布 (Transact-SQL)

  • 当定义发布时，执行 sp_addpublication 并将 enabled_for_internet 设置为 TRUE，以启用 Internet 订阅。

使用事务复制在 Internet 上进行发布 (Transact-SQL)

  • 当定义发布时，执行 sp_addpublication 并将 enabled_for_internet 设置为 TRUE，以启用 Internet 订阅。

使用合并复制在 Internet 上进行发布

  • 当定义发布时，执行 sp_addmergepublication 并将 enabled_for_internet 设置为 TRUE，以启用 Internet 订阅。


复制选项 (Transact-SQL)

复制选项使您得以按照最适合您应用程序和环境的方式来配置复制。

选项 		复制类型
益处
筛选已发布数据 快照复制

事务复制

合并复制

 筛选使您得以创建数据的垂直分区和/或水平分区，该数据可作为复制的一部分进行发布。通过向不同的订阅服务器分配数据分区，可以：
  • 将网络上发送的数据量减到最少。

  • 减少订阅服务器上需要的存储空间量。

  • 根据个别订阅服务器的要求，自定义发布和应用程序。

  • 减少冲突，因为不同的数据分区可以被发送到不同的订阅服务器中。
可更新的订阅（立即更新，排队更新） 快照复制

事务复制

 立即更新和排队更新选项使用户得以在订阅服务器上更新数据，并立即将这些更新传播到发布服务器，或者将更新存储在队列中。

可更新的订阅最适合下列情况的复制拓扑：当发布服务器、分发服务器以及订阅服务器大部分时间保持连接，并且当引起多个用户更新相同数据的冲突很少发生时，在订阅服务器上经常读取复制数据并且偶尔进行更新。
转换已发布的数据 快照复制

事务复制

 您可以在复制期间调节数据转换服务 (DTS) 的数据移动、转换映射和筛选能力。通过可转换的订阅，您可以：
  • 创建快照和事务发布的自定义分区。

  • 当数据与数据类型映射（如整型到实型）、列操作（如将名列和姓列连成一个列）、字符串操作以及函数一起发布时，则转换该数据。
可选同步伙伴 | 合并复制 | 可选同步伙伴使订阅服务器得以合并发布，以便将数据与产生订阅的发布服务器之外的服务器同步。这使得订阅服务器得以在原始发布服务器不可用时同步数据，同时，这对可以通过备用服务器访问更快捷和更可靠网络连接的移动订阅服务器也很有用。
优化同步 | 合并复制 | 合并复制期间，通过优化同步，您可以在发布服务器上存储更多的信息，而不用将这些信息通过网络传输到订阅服务器。合并复制期间，通过优化同步，您可以在发布服务器上存储更多的信息，而不用将这些信息通过网络传输到订阅服务器。
可连接的订阅数据库 快照复制

事务复制

合并复制

 可连接的订阅数据库使您得以将带有复制数据和订阅的数据库从一个订阅服务器传输到另一个订阅服务器。在数据库连接到新的订阅服务器后，新订阅服务器上的数据库将自动地接收其自身对那些发布服务器上的发布所作的请求订阅。这为您在多个订阅服务器上创建订阅数据库和订阅节省了时间和精力。


如何验证订阅服务器信息 (Transact-SQL)

  • 在创建合并发布时，执行 sp_addmergepublication 系统存储过程，并在 @validate_subscriber_info 参数中列出正用来检索订阅服务器信息的函数。

例如，如果在动态筛选中使用 SUSER_SNAME()，则参数应读取：@validate_subscriber_info=N'SUSER_SNAME()'。


管理和监视复制 (Transact-SQL)

SQL Server 复制提供管理和监视复制代理程序、复制警报和复制进程的工具，以便能确保复制满足应用程序和单位的需求。

监视复制将有助于您：

  • 设置复制代理程序的配置文件、调度和提示。

  • 疑难解答代理程序活动，包括验证上一次运行代理程序的时间，并监视代理程序的活动。

  • 疑难解答代理程序错误。

确保数据值在发布服务器和订阅服务器上都相同。


如何创建复制代理程序配置 (Transact-SQL)

创建复制代理程序配置

  1. 执行 sp_add_agent_profile。

  2. 执行 sp_add_agent_parameter。

设置复制代理程序类型的默认配置

  1. 执行 sp_update_agent_profile。

  2. 执行 sp_help_agent_profile。

  3. 执行 sp_help_agent_parameter。

查看或修改复制代理程序配置

  1. 执行 sp_help_agent_profile。

  2. 执行 sp_help_agent_parameter。

  3. 执行 sp_update_agent_profile。

删除复制代理程序配置

  • 执行 sp_drop_agent_profile。


复制安全性 (Transact-SQL)

复制安全性是设计和执行分布式应用程序的重要部分。复制将网络其它地方发生的数据变化应用到您服务器上的数据库中，反之亦然。

复制数据的分散性增加了管理的复杂性，或者限制了对数据的访问。Microsoft® SQL Server™ 2000 复制使用安全机制的组合，以保护应用程序中的数据和业务逻辑:

  • 角色要求

    通过映射用户登录名到特定的 SQL Server 2000 角色，SQL Server 2000 允许用户只执行授权给该角色的复制活动和数据库活动。复制将某些权限授予 sysadmin 固定服务器角色、db_owner 固定数据库角色、当前登录以及 public 角色。例如，只有 sysadmin 服务器角色的成员才能配置复制。

  • 分发服务器管理链接安全性

    SQL Server 2000 在分发服务器与远程发布服务器之间提供安全的管理链接。发布服务器可被看作受信任或不受信任的服务器。

  • 快照文件夹安全性

    操作系统或 FTP 服务阻止用户访问服务器上的特定文件。用户必须具有有效登录，才能读取或写入复制进程中使用的文件。

  • 已注册的订阅服务器

    SQL Server 2000 使您得以将对发布的访问限制在发布服务器已知的或匿名的注册订阅服务器中，或者限制在发布访问列表中含有登录的订阅服务器中。SQL Server 2000 使用异类订阅服务器的链接服务器定义以保护带有异类数据源的数据复制。

  • 发布访问列表

    通过支持每一台服务器上的发布访问列表 (PAL)，SQL Server 2000 使您得以确定能够访问登录的发布。SQL Server 2000 用默认的登录名创建 PAL，用户可根据需要增加或删除登录者。

  • 代理程序登录安全性

    通过支持代理程序登录安全性，SQL Server 2000 要求每个用户提供一个有效的登录帐户以便连接到服务器。当与发布服务器、分发服务器和订阅服务器连接时，复制代理程序必须使用有效的登录帐户。但是，当同时与不同的服务器连接时，代理程序也可以使用不同的登录和安全模式。

  • 立即更新订阅服务器安全性

    对于立即更新订阅服务器，SQL Server 2000 复制将安全机制应用到 Publisher-RPC 链接和发布服务器存储过程中。

当一起使用时，这些安全机制可为您应用程序中的数据和商务逻辑提供最高级别的安全保护。


如何在分发服务器上添加或更改密码

在分发服务器上添加密码

  • 执行 sp_add_distributor 并指定 password 参数。

在分发服务器上更改密码

  • 执行 sp_changedistributor_password。


授权或废除对发布的访问权

授予对发布的访问权

  • 执行 sp_grant_publication_access。

废除对发布的访问权

  • 执行 sp_revoke_publication_access。


OLE DB

为使用用于 SQL Server 的 Microsoft OLE DB 提供程序 (SQLOLEDB)，必须了解如何与服务器建立连接、执行命令和处理结果。


处理结果 (OLE DB)

在 OLE DB 应用程序中，对结果的处理包括先确定结果集的特性，然后将数据检索到程序变量内。如果命令执行存储过程，则还必须知道如何处理存储过程中的返回代码和输出参数。


执行存储过程（使用 ODBC CALL 语法）和处理返回代码及输出参数 (OLE DB)

Microsoft® SQL Server™ 存储过程可包含整型返回代码及输出参数。返回代码和输出参数在服务器发送出的最后一个数据包中，因此直到行集完全释放后才能由应用程序使用。如果命令返回多个结果，输出参数数据在 IMultipleResults::GetResult 返回 DB_S_NORESULT 或当 IMultipleResults 接口完全释放（不论哪种情况先发生）时可用。

处理返回代码和输出参数

  1. 构造一个使用 ODBC CALL 转义序列的 SQL 语句。该语句应对每个输入/输出、输出参数和过程返回值（若有）使用参数标记。对输入参数可使用参数标记或将值硬编码。

  2. 通过使用 DBBINDING 结构的数组创建一组绑定（每个参数标记有一个绑定）。

  3. 通过使用 IAccessor::CreateAccessor 方法为定义的参数创建存取程序。CreateAccessor 通过一组绑定创建存取程序。

  4. 填充 DBPARAMS 结构。

  5. 调用 Execute 命令（这里是指调用存储过程）。

  6. 处理行集并使用 IRowset::Release 方法释放该行集。

  7. 处理从存储过程接收到的返回代码和输出参数值。

下例说明如何处理行集、返回代码和输出参数。不处理结果集。下面是由应用程序使用的示例存储过程。

USE pubs
DROP PROCEDURE myProc
GO

CREATE PROCEDURE myProc
    @inparam int,
    @outparam int OUTPUT

AS
SELECT title, price
FROM titles WHERE royalty > @inparam
SELECT @outparam = 100

IF  (@outparam > 0)
    RETURN 999
ELSE
    RETURN 888
GO

下面是示例代码：

void InitializeAndEstablishConnection();

#define UNICODE
#define DBINITCONSTANTS
#define INITGUID
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <iostream.h>
#include <oledb.h>
#include <oledberr.h>
#include <SQLOLEDB.h>

IDBInitialize*      pIDBInitialize          = NULL;
IDBCreateSession*   pIDBCreateSession       = NULL;
IDBCreateCommand*   pIDBCreateCommand       = NULL;
ICommandText*       pICommandText           = NULL;
IRowset*            pIRowset                = NULL;
ICommandWithParameters* pICommandWithParams = NULL;
IAccessor*          pIAccessor              = NULL;
IDBProperties*      pIDBProperties          = NULL;
WCHAR*              pStringsBuffer;
DBBINDING*          pBindings;
const ULONG         nInitProps = 4;
DBPROP              InitProperties[nInitProps];
const ULONG         nPropSet = 1;
DBPROPSET           rgInitPropSet[nPropSet];
HRESULT             hr;
HACCESSOR           hAccessor;
const ULONG         nParams = 3; //Number of parameters in the command
DBPARAMBINDINFO     ParamBindInfo[nParams];
ULONG               i;
ULONG               cbColOffset = 0;

ULONG               ParamOrdinals[nParams];
LONG                cNumRows = 0;
DBPARAMS            Params;
/*
Declare an array of DBBINDING structures, one for each parameter
in the command.
*/
DBBINDING           acDBBinding[nParams];
DBBINDSTATUS        acDBBindStatus[nParams];

//The following buffer is used to store parameter values.
typedef struct tagSPROCPARAMS
{
    long    lReturnValue;
    long    outParam;
    long    inParam;
} SPROCPARAMS;

void main() {

    //The command to execute.
   WCHAR* wCmdString = L"{? = call myProc(?,?)}";

    SPROCPARAMS sprocparams = {0,0,14};

    //All the initialization activities in a separate function.
    InitializeAndEstablishConnection();

    //Create a new activity from the data source object.
    if(FAILED(pIDBInitialize->QueryInterface(
                                    IID_IDBCreateSession,
                                    (void**) &pIDBCreateSession)))
    {
        cout << "Failed to access IDBCreateSession interface.\n";
        goto EXIT;
    }
    if(FAILED(pIDBCreateSession->CreateSession(
                                     NULL,
                                     IID_IDBCreateCommand,
                                     (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed.\n";
        goto EXIT;
    }

    //Create a Command object.
    if(FAILED(pIDBCreateCommand->CreateCommand(
                                        NULL,
                                        IID_ICommandText,
                                        (IUnknown**) &pICommandText)))
    {
        cout << "Failed to access ICommand interface.\n";
        goto EXIT;
    }

    //Set the command text.
    if(FAILED(pICommandText->SetCommandText(DBGUID_DBSQL, wCmdString)))
    {
        cout << "Failed to set command text.\n";
        goto EXIT;
    }
   /* No need to describe command parameters (parameter name, data type
   etc) in DBPARAMBINDINFO structure and then SetParameterInfo(). The
   provider obtains this information by calling appropriate helper
   function.
   */

    /*Describe the consumer buffer by filling in the array
    of DBBINDING structures.  Each binding associates
    a single parameter to the consumer's buffer.*/
    for(i = 0; i < nParams; i++)
    {
        acDBBinding[i].obLength = 0;
        acDBBinding[i].obStatus = 0;
        acDBBinding[i].pTypeInfo = NULL;
        acDBBinding[i].pObject = NULL;
        acDBBinding[i].pBindExt = NULL;
        acDBBinding[i].dwPart = DBPART_VALUE;
        acDBBinding[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
        acDBBinding[i].dwFlags = 0;
        acDBBinding[i].bScale = 0;
    } //endfor

    acDBBinding[0].iOrdinal = 1;
    acDBBinding[0].obValue = offsetof(SPROCPARAMS, lReturnValue);
    acDBBinding[0].eParamIO = DBPARAMIO_OUTPUT;
    acDBBinding[0].cbMaxLen = sizeof(long);
    acDBBinding[0].wType = DBTYPE_I4;
    acDBBinding[0].bPrecision = 11;

    acDBBinding[1].iOrdinal = 2;
    acDBBinding[1].obValue = offsetof(SPROCPARAMS, inParam);
    acDBBinding[1].eParamIO = DBPARAMIO_INPUT;
    acDBBinding[1].cbMaxLen = sizeof(long);
    acDBBinding[1].wType = DBTYPE_I4;
    acDBBinding[1].bPrecision = 11;

    acDBBinding[2].iOrdinal = 3;
    acDBBinding[2].obValue = offsetof(SPROCPARAMS, outParam);
    acDBBinding[2].eParamIO = DBPARAMIO_OUTPUT;
    acDBBinding[2].cbMaxLen = sizeof(long);
    acDBBinding[2].wType = DBTYPE_I4;
    acDBBinding[2].bPrecision = 11;

    //Create an accessor from the above set of bindings.
    hr = pICommandText->QueryInterface(
                                    IID_IAccessor,
                                    (void**)&pIAccessor);
    if (FAILED(hr))
    {
        cout << "Failed to get IAccessor interface.\n";
    }

    hr = pIAccessor->CreateAccessor(
                            DBACCESSOR_PARAMETERDATA,
                            nParams,
                            acDBBinding,
                            sizeof(SPROCPARAMS),
                            &hAccessor,
                            acDBBindStatus);
    if (FAILED(hr))
    {
       cout << "Failed to create accessor for the defined parameters.\n";
    }
    /*
    Fill in DBPARAMS structure for the command execution. This structure
    specifies the parameter values in the command and is then passed
    to Execute.
    */
    Params.pData = &sprocparams;
    Params.cParamSets = 1;
    Params.hAccessor = hAccessor;

    //Execute the command.
    if(FAILED(hr = pICommandText->Execute(
                                    NULL,
                                    IID_IRowset,
                                    &Params,
                                    &cNumRows,
                                    (IUnknown **) &pIRowset)))
    {
        cout << "Failed to execute command.\n";
        goto EXIT;
    }

    printf("After command execution but before rowset processing.\n\n");
    printf("  Return value = %d\n", sprocparams.lReturnValue);
    printf("  Output parameter value = %d\n", sprocparams.outParam);
    printf("  These are the same default values set in the application.\n\n\n");

    /*The result set does not matter in this example, so release it
    without processing.*/
    pIRowset->Release();

    printf("After processing the result set...\n");
    printf("  Return value = %d\n", sprocparams.lReturnValue);
    printf("  Output parameter value = %d\n\n", sprocparams.outParam);

    //Free up memory.
    pIAccessor->ReleaseAccessor(hAccessor, NULL);
    pIAccessor->Release();
    pICommandText->Release();
    pIDBCreateCommand->Release();
    pIDBCreateSession->Release();
    if(FAILED(pIDBInitialize->Uninitialize()))
    {
        /*Uninitialize is not required, but it fails if an interface
        has not been released.  This can be used for debugging.*/
        cout << "Problem uninitializing.\n";
    } //endif
    pIDBInitialize->Release();

    //Release COM.
    CoUninitialize();
    return;

EXIT:
    if(pIAccessor != NULL)
        pIAccessor->Release();
    if(pICommandText != NULL)
        pICommandText->Release();
    if(pIDBCreateCommand != NULL)
        pIDBCreateCommand->Release();
    if(pIDBCreateSession != NULL)
       pIDBCreateSession->Release();
    if (pIDBInitialize != NULL)
    {
        if (FAILED(pIDBInitialize->Uninitialize()))
        {
            /*Uninitialize is not required, but it fails if an
            interface has not been released.  This can be used
            for debugging.*/
            cout << "Problem in uninitializing.\n";
        } //if inner
        pIDBInitialize->Release();
    } //endif outer

    CoUninitialize();
};
//---------------------------------------------------------------------
void InitializeAndEstablishConnection()
{
    //Initialize the COM library.
    CoInitialize(NULL);

    //Obtain access to the SQLOLEDB provider.
    hr = CoCreateInstance(
                    CLSID_SQLOLEDB,
                    NULL,
                    CLSCTX_INPROC_SERVER,
                    IID_IDBInitialize,
                    (void **) &pIDBInitialize);
    if (FAILED(hr))
    {
        cout << "Failed in CoCreateInstance().\n";
    }

    /*
    Initialize the property values needed
    to establish the connection.
    */
    for(i = 0; i < nInitProps; i++)
        VariantInit(&InitProperties[i].vValue);
    //Specify server name.
    InitProperties[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
    InitProperties[0].vValue.vt = VT_BSTR;
    InitProperties[0].vValue.bstrVal =
                                SysAllocString(L"mohanv1");
    InitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[0].colid = DB_NULLID;

    //Specify database name.
    InitProperties[1].dwPropertyID = DBPROP_INIT_CATALOG;
    InitProperties[1].vValue.vt = VT_BSTR;
    InitProperties[1].vValue.bstrVal =
                                SysAllocString(L"pubs");
    InitProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[1].colid = DB_NULLID;

    //Specify username (login).
    InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;
    InitProperties[2].vValue.vt = VT_BSTR;
    InitProperties[2].vValue.bstrVal =
                                SysAllocString(L"sa");
    InitProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[3].colid = DB_NULLID;

    //Specify password.
    InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;
    InitProperties[3].vValue.vt = VT_BSTR;
    InitProperties[3].vValue.bstrVal = SysAllocString(L"");
    InitProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[3].colid = DB_NULLID;

    /*
    Now that properties are set, construct the DBPROPSET structure
    (rgInitPropSet).  The DBPROPSET structure is used to pass an array
    of DBPROP structures (InitProperties) to the SetProperties method.
    */
    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
    rgInitPropSet[0].cProperties = 4;
    rgInitPropSet[0].rgProperties = InitProperties;

    //Set initialization properties.
    hr = pIDBInitialize->QueryInterface(
                                IID_IDBProperties,
                                (void **)&pIDBProperties);
    if (FAILED(hr))
    {
        cout << "Failed to obtain IDBProperties interface.\n";
    }

    hr = pIDBProperties->SetProperties(
                                nPropSet,
                                rgInitPropSet);
    if(FAILED(hr))
    {
        cout << "Failed to set initialization properties.\n";
    }
    pIDBProperties->Release();

    //Now establish a connection to the data source.
    if(FAILED(pIDBInitialize->Initialize()))
    {
        cout << "Problem in initializing.\n";
    }
} //end of InitializeAndEstablishConnection.


执行存储过程（使用 RPC 语法）和处理返回代码及输出参数 (OLE DB)

Microsoft® SQL Server™ 存储过程可包含整型返回代码及输出参数。返回代码和输出参数在服务器发送出的最后一个数据包中，因此直到行集完全释放后才能由应用程序使用。如果命令返回多个结果，输出参数数据在 IMultipleResults::GetResult 返回 DB_S_NORESULT 或当 IMultipleResults 接口完全释放（不论哪种情况先发生）时可用。

处理返回代码和输出参数

  1. 使用 RPC 转义序列构造一个 SQL 语句。

  2. 调用 ICommandWithParameters::SetParameterInfo 方法以便向提供程序描述参数。在 PARAMBINDINFO 结构的数组中填充参数信息。

  3. 通过使用 DBBINDING 结构的数组创建一组绑定（每个参数标记有一个绑定）。

  4. 通过使用 IAccessor::CreateAccessor 方法为定义的参数创建存取程序。CreateAccessor 通过一组绑定创建存取程序。

  5. 填充 DBPARAMS 结构。

  6. 调用 Execute 命令（这里是指调用存储过程）。

  7. 处理行集并使用 IRowset::Release 方法释放该行集。

  8. 处理从存储过程收到的返回代码和输出参数值。

下例说明如何处理行集、返回代码和输出参数。不处理结果集。下面是由应用程序使用的示例存储过程。

USE pubs
DROP PROCEDURE myProc
GO

CREATE PROCEDURE myProc
    @inparam int,
    @outparam int OUTPUT

AS
SELECT title, price
FROM titles WHERE royalty > @inparam
SELECT @outparam = 100

IF  (@outparam > 0)
    RETURN 999
ELSE
    RETURN 888
GO

下面是示例代码：

void InitializeAndEstablishConnection();

#define UNICODE
#define DBINITCONSTANTS
#define INITGUID
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <iostream.h>
#include <oledb.h>
#include <oledberr.h>
#include <SQLOLEDB.h>

IDBInitialize*      pIDBInitialize          = NULL;
IDBCreateSession*   pIDBCreateSession       = NULL;
IDBCreateCommand*   pIDBCreateCommand       = NULL;
ICommandText*       pICommandText           = NULL;
IRowset*            pIRowset                = NULL;
ICommandWithParameters* pICommandWithParams = NULL;
IAccessor*          pIAccessor              = NULL;
IDBProperties*      pIDBProperties          = NULL;
WCHAR*              pStringsBuffer;
DBBINDING*          pBindings;
const ULONG         nInitProps = 4;
DBPROP              InitProperties[nInitProps];
const ULONG         nPropSet = 1;
DBPROPSET           rgInitPropSet[nPropSet];
HRESULT             hr;
HACCESSOR           hAccessor;
const ULONG         nParams = 3; //Number of parameters in the command
DBPARAMBINDINFO     ParamBindInfo[nParams];
ULONG               i;
ULONG               cbColOffset = 0;

ULONG               ParamOrdinals[nParams];
LONG                cNumRows = 0;
DBPARAMS            Params;
/*
Declare an array of DBBINDING structures, one for each parameter
in the command.
*/
DBBINDING           acDBBinding[nParams];
DBBINDSTATUS        acDBBindStatus[nParams];

//The following buffer is used to store parameter values.
typedef struct tagSPROCPARAMS
{
    long    lReturnValue;
    long    outParam;
    long    inParam;
} SPROCPARAMS;

void main() {

    //The command to execute.
    //WCHAR* wCmdString = L"{? = call myProc(?,?)}";
   WCHAR* wCmdString=L"{rpc myProc}";
    SPROCPARAMS sprocparams = {0,0,14};

    //All the initialization activities in a separate function.
    InitializeAndEstablishConnection();

    //Create a new activity from the data source object.
    if(FAILED(pIDBInitialize->QueryInterface(
                                    IID_IDBCreateSession,
                                    (void**) &pIDBCreateSession)))
    {
        cout << "Failed to access IDBCreateSession interface.\n";
        goto EXIT;
    }
    if(FAILED(pIDBCreateSession->CreateSession(
                                     NULL,
                                     IID_IDBCreateCommand,
                                     (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed.\n";
        goto EXIT;
    }

    //Create a Command object.
    if(FAILED(pIDBCreateCommand->CreateCommand(
                                        NULL,
                                        IID_ICommandText,
                                        (IUnknown**) &pICommandText)))
    {
        cout << "Failed to access ICommand interface.\n";
        goto EXIT;
    }

    //Set the command text.
    if(FAILED(pICommandText->SetCommandText(DBGUID_DBSQL, wCmdString)))
    {
        cout << "Failed to set command text.\n";
        goto EXIT;
    }

    /*
    Describe the command parameters (parameter name, provider
    specific name of the parameter's data type, and so on.) in an array of
    DBPARAMBINDINFO structures.  This information is then used by
    SetParameterInfo().
    */
    ParamBindInfo[0].pwszDataSourceType = L"DBTYPE_I4";
    ParamBindInfo[0].pwszName = L"ReturnVal"; //return value from sp
    ParamBindInfo[0].ulParamSize = sizeof(long);
    ParamBindInfo[0].dwFlags = DBPARAMFLAGS_ISOUTPUT;
    ParamBindInfo[0].bPrecision = 11;
    ParamBindInfo[0].bScale = 0;
    ParamOrdinals[0] = 1;

    ParamBindInfo[1].pwszDataSourceType = L"DBTYPE_I4";
    ParamBindInfo[1].pwszName = L"@inparam";
    ParamBindInfo[1].ulParamSize = sizeof(long);
    ParamBindInfo[1].dwFlags = DBPARAMFLAGS_ISINPUT;
    ParamBindInfo[1].bPrecision = 11;
    ParamBindInfo[1].bScale = 0;
    ParamOrdinals[1] = 2;

    ParamBindInfo[2].pwszDataSourceType = L"DBTYPE_I4";
    ParamBindInfo[2].pwszName = L"@outparam";
    ParamBindInfo[2].ulParamSize = sizeof(long);
    ParamBindInfo[2].dwFlags = DBPARAMFLAGS_ISOUTPUT;
    ParamBindInfo[2].bPrecision = 11;
    ParamBindInfo[2].bScale = 0;
    ParamOrdinals[2] = 3;

    //Set the parameters information.
    if(FAILED(pICommandText->QueryInterface(
                                    IID_ICommandWithParameters,
                                    (void**)&pICommandWithParams)))
    {
        cout << "Failed to obtain ICommandWithParameters.\n";
        goto EXIT;
    }
    if(FAILED(pICommandWithParams->SetParameterInfo(
                                        nParams,
                                        ParamOrdinals,
                                        ParamBindInfo)))
    {
        cout << "Failed in setting parameter information.(SetParameterInfo)\n";
        goto EXIT;
    }

    /*Describe the consumer buffer by filling in the array
    of DBBINDING structures.  Each binding associates
    a single parameter to the consumer's buffer.*/
    for(i = 0; i < nParams; i++)
    {
        acDBBinding[i].obLength = 0;
        acDBBinding[i].obStatus = 0;
        acDBBinding[i].pTypeInfo = NULL;
        acDBBinding[i].pObject = NULL;
        acDBBinding[i].pBindExt = NULL;
        acDBBinding[i].dwPart = DBPART_VALUE;
        acDBBinding[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
        acDBBinding[i].dwFlags = 0;
        acDBBinding[i].bScale = 0;
    } //endfor

    acDBBinding[0].iOrdinal = 1;
    acDBBinding[0].obValue = offsetof(SPROCPARAMS, lReturnValue);
    acDBBinding[0].eParamIO = DBPARAMIO_OUTPUT;
    acDBBinding[0].cbMaxLen = sizeof(long);
    acDBBinding[0].wType = DBTYPE_I4;
    acDBBinding[0].bPrecision = 11;

    acDBBinding[1].iOrdinal = 2;
    acDBBinding[1].obValue = offsetof(SPROCPARAMS, inParam);
    acDBBinding[1].eParamIO = DBPARAMIO_INPUT;
    acDBBinding[1].cbMaxLen = sizeof(long);
    acDBBinding[1].wType = DBTYPE_I4;
    acDBBinding[1].bPrecision = 11;

    acDBBinding[2].iOrdinal = 3;
    acDBBinding[2].obValue = offsetof(SPROCPARAMS, outParam);
    acDBBinding[2].eParamIO = DBPARAMIO_OUTPUT;
    acDBBinding[2].cbMaxLen = sizeof(long);
    acDBBinding[2].wType = DBTYPE_I4;
    acDBBinding[2].bPrecision = 11;

    //Create an accessor from the above set of bindings.
    hr = pICommandWithParams->QueryInterface(
                                    IID_IAccessor,
                                    (void**)&pIAccessor);
    if (FAILED(hr))
    {
        cout << "Failed to get IAccessor interface.\n";
    }

    hr = pIAccessor->CreateAccessor(
                            DBACCESSOR_PARAMETERDATA,
                            nParams,
                            acDBBinding,
                            sizeof(SPROCPARAMS),
                            &hAccessor,
                            acDBBindStatus);
    if (FAILED(hr))
    {
       cout << "Failed to create accessor for the defined parameters.\n";
    }
    /*
    Fill in DBPARAMS structure for the command execution. This structure
    specifies the parameter values in the command and is then passed
    to Execute.
    */
    Params.pData = &sprocparams;
    Params.cParamSets = 1;
    Params.hAccessor = hAccessor;

    //Execute the command.
    if(FAILED(hr = pICommandText->Execute(
                                    NULL,
                                    IID_IRowset,
                                    &Params,
                                    &cNumRows,
                                    (IUnknown **) &pIRowset)))
    {
        cout << "Failed to execute command.\n";
        goto EXIT;
    }

    printf("After command execution but before rowset processing.\n\n");
    printf("  Return value = %d\n", sprocparams.lReturnValue);
    printf("  Output parameter value = %d\n", sprocparams.outParam);
    printf("  These are the same default values set in the application.\n\n\n");

    /*The result set does not matter in this example, so release it
    without processing.*/
    pIRowset->Release();

    printf("After processing the result set...\n");
    printf("  Return value = %d\n", sprocparams.lReturnValue);
    printf("  Output parameter value = %d\n\n", sprocparams.outParam);

    //Free up memory.
    pIAccessor->ReleaseAccessor(hAccessor, NULL);
    pIAccessor->Release();
    pICommandWithParams->Release();
    pICommandText->Release();
    pIDBCreateCommand->Release();
    pIDBCreateSession->Release();
    if(FAILED(pIDBInitialize->Uninitialize()))
    {
        /*Uninitialize is not required, but it fails if an interface
        has not been released.  This can be used for debugging.*/
        cout << "Problem uninitializing.\n";
    } //endif
    pIDBInitialize->Release();

    //Release COM.
    CoUninitialize();
    return;

EXIT:
    if(pIAccessor != NULL)
        pIAccessor->Release();
    if(pICommandWithParams != NULL)
        pICommandWithParams->Release();
    if(pICommandText != NULL)
        pICommandText->Release();
    if(pIDBCreateCommand != NULL)
        pIDBCreateCommand->Release();
    if(pIDBCreateSession != NULL)
       pIDBCreateSession->Release();
    if (pIDBInitialize != NULL)
    {
        if (FAILED(pIDBInitialize->Uninitialize()))
        {
            /*Uninitialize is not required, but it fails if an
            interface has not been released.  This can be used
            for debugging.*/
            cout << "Problem in uninitializing.\n";
        } //if inner
        pIDBInitialize->Release();
    } //endif outer

    CoUninitialize();
};
//---------------------------------------------------------------------
void InitializeAndEstablishConnection()
{
    //Initialize the COM library.
    CoInitialize(NULL);

    //Obtain access to the SQLOLEDB provider.
    hr = CoCreateInstance(
                    CLSID_SQLOLEDB,
                    NULL,
                    CLSCTX_INPROC_SERVER,
                    IID_IDBInitialize,
                    (void **) &pIDBInitialize);
    if (FAILED(hr))
    {
        cout << "Failed in CoCreateInstance().\n";
    }

    /*
    Initialize the property values needed
    to establish the connection.
    */
    for(i = 0; i < nInitProps; i++)
        VariantInit(&InitProperties[i].vValue);
    //Specify server name.
    InitProperties[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
    InitProperties[0].vValue.vt = VT_BSTR;
    InitProperties[0].vValue.bstrVal =
                                SysAllocString(L"mohanv1");
    InitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[0].colid = DB_NULLID;

    //Specify database name.
    InitProperties[1].dwPropertyID = DBPROP_INIT_CATALOG;
    InitProperties[1].vValue.vt = VT_BSTR;
    InitProperties[1].vValue.bstrVal =
                                SysAllocString(L"pubs");
    InitProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[1].colid = DB_NULLID;

    //Specify username (login).
    InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;
    InitProperties[2].vValue.vt = VT_BSTR;
    InitProperties[2].vValue.bstrVal =
                                SysAllocString(L"sa");
    InitProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[3].colid = DB_NULLID;

    //Specify password.
    InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;
    InitProperties[3].vValue.vt = VT_BSTR;
    InitProperties[3].vValue.bstrVal = SysAllocString(L"");
    InitProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[3].colid = DB_NULLID;

    /*
    Now that properties are set, construct the DBPROPSET structure
    (rgInitPropSet).  The DBPROPSET structure is used to pass an array
    of DBPROP structures (InitProperties) to the SetProperties method.
    */
    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
    rgInitPropSet[0].cProperties = 4;
    rgInitPropSet[0].rgProperties = InitProperties;

    //Set initialization properties.
    hr = pIDBInitialize->QueryInterface(
                                IID_IDBProperties,
                                (void **)&pIDBProperties);
    if (FAILED(hr))
    {
        cout << "Failed to obtain IDBProperties interface.\n";
    }

    hr = pIDBProperties->SetProperties(
                                nPropSet,
                                rgInitPropSet);
    if(FAILED(hr))
    {
        cout << "Failed to set initialization properties.\n";
    }
    pIDBProperties->Release();

    //Now establish a connection to the data source.
    if(FAILED(pIDBInitialize->Initialize()))
    {
        cout << "Problem in initializing.\n";
    }
} //end of InitializeAndEstablishConnection.


执行用户定义函数和处理返回代码 (OLE DB)

在下例中，执行用户定义函数并输出返回代码。下面是由应用程序使用的示例用户定义函数。

drop function fn_RectangleArea
go
CREATE FUNCTION fn_RectangleArea
   (@Width int,
@Height int )
RETURNS int
AS
BEGIN
   RETURN ( @Width * @Height )
END
GO

下面是示例代码。

/*
Example shows how to execute user-defined functions and process return code value.
*/
void InitializeAndEstablishConnection();
#define UNICODE
#define DBINITCONSTANTS
#define INITGUID
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <iostream.h>
#include <oledb.h>
#include <oledberr.h>
#include <sqloledb.h>

IDBInitialize*      pIDBInitialize          = NULL;
IDBCreateSession*   pIDBCreateSession       = NULL;
IDBCreateCommand*   pIDBCreateCommand       = NULL;
ICommandText*       pICommandText           = NULL;
IRowset*            pIRowset                = NULL;
ICommandWithParameters* pICommandWithParams = NULL;
IAccessor*          pIAccessor              = NULL;
IDBProperties*      pIDBProperties          = NULL;
WCHAR*              pStringsBuffer;
DBBINDING*          pBindings;
const ULONG         nInitProps = 4;
DBPROP              InitProperties[nInitProps];
const ULONG         nPropSet = 1;
DBPROPSET           rgInitPropSet[nPropSet];
HRESULT             hr;
HACCESSOR           hAccessor;
const ULONG         nParams = 3; //No. of parameters in the command
DBPARAMBINDINFO     ParamBindInfo[nParams];
ULONG               i;
ULONG               cbColOffset = 0;

ULONG               ParamOrdinals[nParams];
LONG                cNumRows = 0;
DBPARAMS            Params;
/*
Declare an array of DBBINDING structures, one for each parameter
in the command
*/
DBBINDING           acDBBinding[nParams];
DBBINDSTATUS        acDBBindStatus[nParams];

//The following buffer is used to store parameter values.
typedef struct tagSPROCPARAMS
{
    long    lReturnValue;
    long    inParam1;
    long    inParam2;
} SPROCPARAMS;

void main() {

    //The command to execute.
 WCHAR* wCmdString = L"{? = CALL fn_RectangleArea(?, ?) }";
// WCHAR* wCmdString = L"EXEC ? = fn_RectangleVolume(?, ?)";

    SPROCPARAMS sprocparams = {0,5,10};

    //All the initialization stuff in a separate function.
    InitializeAndEstablishConnection();

    //Let us create a new session from the data source object.
    if(FAILED(pIDBInitialize->QueryInterface(
                                    IID_IDBCreateSession,
                                    (void**) &pIDBCreateSession)))
    {
        cout << "Failed to access IDBCreateSession interface\\n";
        goto EXIT;
    }
    if(FAILED(pIDBCreateSession->CreateSession(
                                        NULL,
                                        IID_IDBCreateCommand,
                                        (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed\\n";
        goto EXIT;
    }

    //Create a Command
    if(FAILED(pIDBCreateCommand->CreateCommand(
                                        NULL,
                                        IID_ICommandText,
                                        (IUnknown**) &pICommandText)))
    {
        cout << "Failed to access ICommand interface\\n";
        goto EXIT;
    }

    //Set the command text.
    if(FAILED(pICommandText->SetCommandText(DBGUID_DBSQL, wCmdString)))
    {
        cout << "failed to set command text\\n";
        goto EXIT;
    }

    /*
    Describe the command parameters (parameter name, provider
    specific name of the parameter's data type etc.) in an array of
    DBPARAMBINDINFO structures.  This information is then used by
    SetParameterInfo().
    */
    ParamBindInfo[0].pwszDataSourceType = L"DBTYPE_I4";
    ParamBindInfo[0].pwszName = NULL; // L"ReturnVal"; //return value from sp
    ParamBindInfo[0].ulParamSize = sizeof(long);
    ParamBindInfo[0].dwFlags = DBPARAMFLAGS_ISOUTPUT;
    ParamBindInfo[0].bPrecision = 11;
    ParamBindInfo[0].bScale = 0;
    ParamOrdinals[0] = 1;

    ParamBindInfo[1].pwszDataSourceType = L"DBTYPE_I4";
    ParamBindInfo[1].pwszName = NULL;      //L"@inparam1";
    ParamBindInfo[1].ulParamSize = sizeof(long);
    ParamBindInfo[1].dwFlags = DBPARAMFLAGS_ISINPUT;
    ParamBindInfo[1].bPrecision = 11;
    ParamBindInfo[1].bScale = 0;
    ParamOrdinals[1] = 2;

    ParamBindInfo[2].pwszDataSourceType = L"DBTYPE_I4";
    ParamBindInfo[2].pwszName = NULL;      // L"@inparam2";
    ParamBindInfo[2].ulParamSize = sizeof(long);
    ParamBindInfo[2].dwFlags = DBPARAMFLAGS_ISINPUT;
    ParamBindInfo[2].bPrecision = 11;
    ParamBindInfo[2].bScale = 0;
    ParamOrdinals[2] = 3;

    //Set the parameters information.
    if(FAILED(pICommandText->QueryInterface(
                                    IID_ICommandWithParameters,
                                    (void**)&pICommandWithParams)))
    {
        cout << "failed to obtain ICommandWithParameters\\n";
        goto EXIT;
    }
    if(FAILED(pICommandWithParams->SetParameterInfo(
                                        nParams,
                                        ParamOrdinals,
                                        ParamBindInfo)))
    {
        cout << "failed in setting parameter info.(SetParameterInfo)\\n";
        goto EXIT;
    }

    //Let us describe the consumer buffer by filling in the array
    //of DBBINDING structures.  Each binding associates
    //a single parameter to the consumer's buffer.
    for(i = 0; i < nParams; i++)
    {
        acDBBinding[i].obLength = 0;
        acDBBinding[i].obStatus = 0;
        acDBBinding[i].pTypeInfo = NULL;
        acDBBinding[i].pObject = NULL;
        acDBBinding[i].pBindExt = NULL;
        acDBBinding[i].dwPart = DBPART_VALUE;
        acDBBinding[i].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
        acDBBinding[i].dwFlags = 0;
        acDBBinding[i].bScale = 0;
    } //for

    acDBBinding[0].iOrdinal = 1;
    acDBBinding[0].obValue = offsetof(SPROCPARAMS, lReturnValue);
    acDBBinding[0].eParamIO = DBPARAMIO_OUTPUT;
    acDBBinding[0].cbMaxLen = sizeof(long);
    acDBBinding[0].wType = DBTYPE_I4;
    acDBBinding[0].bPrecision = 11;

    acDBBinding[1].iOrdinal = 2;
    acDBBinding[1].obValue = offsetof(SPROCPARAMS, inParam1);
    acDBBinding[1].eParamIO = DBPARAMIO_INPUT;
    acDBBinding[1].cbMaxLen = sizeof(long);
    acDBBinding[1].wType = DBTYPE_I4;
    acDBBinding[1].bPrecision = 11;

    acDBBinding[2].iOrdinal = 3;
    acDBBinding[2].obValue = offsetof(SPROCPARAMS, inParam2);
    acDBBinding[2].eParamIO = DBPARAMIO_INPUT;
    acDBBinding[2].cbMaxLen = sizeof(long);
    acDBBinding[2].wType = DBTYPE_I4;
    acDBBinding[2].bPrecision = 11;

    //Let us create an accessor from the above set of bindings.
    hr = pICommandWithParams->QueryInterface(
                                    IID_IAccessor,
                                    (void**)&pIAccessor);
    if (FAILED(hr))
    {
        cout << "Failed to get IAccessor interface\\n";
    }

    hr = pIAccessor->CreateAccessor(
                            DBACCESSOR_PARAMETERDATA,
                            nParams,
                            acDBBinding,
                            sizeof(SPROCPARAMS),
                            &hAccessor,
                            acDBBindStatus);
    if (FAILED(hr))
    {
        cout << "failed to create accessor for the defined parameters\\n";
    }
    /*
    Fill in DBPARAMS structure for the command execution. This structure
    specify the parameter values in the command.  This structure is
    then passed to Execute.
    */
    Params.pData = &sprocparams;
    Params.cParamSets = 1;
    Params.hAccessor = hAccessor;

    //Execute the command.
    if(FAILED(hr = pICommandText->Execute(
                                    NULL,
                                    IID_IRowset,
                                    &Params,
                                    &cNumRows,
                                    (IUnknown **) &pIRowset)))
    {
        cout << "failed to execute command\\n";
        goto EXIT;
    }

    printf("  Return value = %d\n", sprocparams.lReturnValue);

    //we are not interested in the resultset so release it
    //without processing.
   if (pIRowset != NULL)
      pIRowset->Release();
    //Free up memory.
    pIAccessor->ReleaseAccessor(hAccessor, NULL);
    pIAccessor->Release();
    pICommandWithParams->Release();
    pICommandText->Release();
    pIDBCreateCommand->Release();
    pIDBCreateSession->Release();
    if(FAILED(pIDBInitialize->Uninitialize()))
    {
        //Uninitialize is not required, but it fails if an interface
        //has not not been released.  This can be used for debugging.
        cout << "Problem uninitializing\\n";
    } //if
    pIDBInitialize->Release();

    //Release COM.
    CoUninitialize();
    return;

EXIT:
    if(pIAccessor != NULL)
        pIAccessor->Release();
    if(pICommandWithParams != NULL)
        pICommandWithParams->Release();
    if(pICommandText != NULL)
        pICommandText->Release();
    if(pIDBCreateCommand != NULL)
        pIDBCreateCommand->Release();
    if(pIDBCreateSession != NULL)
       pIDBCreateSession->Release();
    if (pIDBInitialize != NULL)
    {
        if (FAILED(pIDBInitialize->Uninitialize()))
        {
            //Uninitialize is not required, but it fails if an
            //interface has not been released.  This can be used
            //for debugging.
            cout << "problem in uninitializing\\n";
        } //if inner
        pIDBInitialize->Release();
    } //if outer

    CoUninitialize();
}
//---------------------------------------------------------------
void InitializeAndEstablishConnection()
{
    //Initialize the COM library.
    CoInitialize(NULL);

    //Obtain access to the SQLOLEDB provider.
    hr = CoCreateInstance(
                    CLSID_SQLOLEDB,
                    NULL,
                    CLSCTX_INPROC_SERVER,
                    IID_IDBInitialize,
                    (void **) &pIDBInitialize);
    if (FAILED(hr))
    {
        cout << "Failed in CoCreateInstance()\\n";
    }

    /*
    Let us initialize the property values needed
    to establish the connection.
    */
    for(i = 0; i < nInitProps; i++)
        VariantInit(&InitProperties[i].vValue);
    //Specify server name.
    InitProperties[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
    InitProperties[0].vValue.vt = VT_BSTR;
    InitProperties[0].vValue.bstrVal =
                                SysAllocString(L"server");
    InitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[0].colid = DB_NULLID;

    //Specify database name.
    InitProperties[1].dwPropertyID = DBPROP_INIT_CATALOG;
    InitProperties[1].vValue.vt = VT_BSTR;
    InitProperties[1].vValue.bstrVal =
                                SysAllocString(L"database");
    InitProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[1].colid = DB_NULLID;

    //Specify user name (login).
    InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;
    InitProperties[2].vValue.vt = VT_BSTR;
    InitProperties[2].vValue.bstrVal =
                                SysAllocString(L"login");
    InitProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[3].colid = DB_NULLID;

    //Specify password.
    InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;
    InitProperties[3].vValue.vt = VT_BSTR;
    InitProperties[3].vValue.bstrVal = SysAllocString(L"password");
    InitProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;
    InitProperties[3].colid = DB_NULLID;

    /*
    Now that properties are set, construct the DBPROPSET structure
    (rgInitPropSet).  The DBPROPSET structure is used to pass an array
    of DBPROP structures (InitProperties) to SetProperties method.
    */
    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
    rgInitPropSet[0].cProperties = 4;
    rgInitPropSet[0].rgProperties = InitProperties;

    //Set initialization properties.
    hr = pIDBInitialize->QueryInterface(
                                IID_IDBProperties,
                                (void **)&pIDBProperties);
    if (FAILED(hr))
    {
        cout << "Failed to obtain IDBProperties interface.\\n";
    }

    hr = pIDBProperties->SetProperties(
                                nPropSet,
                                rgInitPropSet);
    if(FAILED(hr))
    {
        cout << "Failed to set initialization properties\\n";
    }
    pIDBProperties->Release();

    //Now we establish connection to the data source.
    if(FAILED(pIDBInitialize->Initialize()))
    {
        cout << "Problem in initializing\\n";
    }
} //end of InitializeAndEstablishConnection.


如何从结果集提取行 (OLE DB)

从结果集提取行

/*
    Example shows how to fetch rows from a result set.
*/
void InitializeAndEstablishConnection();
void ProcessResultSet();

#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID

#include <stdio.h>
#include <tchar.h>
#include <stddef.h>
#include <windows.h>
#include <iostream.h>
#include <oledb.h>
#include <SQLOLEDB.h>

IDBInitialize*       pIDBInitialize     = NULL;
IDBProperties*       pIDBProperties     = NULL;
IDBCreateSession*    pIDBCreateSession  = NULL;
IDBCreateCommand*    pIDBCreateCommand  = NULL;
ICommandText*        pICommandText      = NULL;
IRowset*             pIRowset           = NULL;
IColumnsInfo*        pIColumnsInfo      = NULL;
DBCOLUMNINFO*        pDBColumnInfo      = NULL;
IAccessor*           pIAccessor        =  NULL;
DBPROP               InitProperties[4];
DBPROPSET            rgInitPropSet[1];
ULONG                i, j;
HRESULT              hr;
LONG                 cNumRows = 0;
ULONG                lNumCols;
WCHAR*               pStringsBuffer;
DBBINDING*           pBindings;
ULONG                ConsumerBufColOffset = 0;
HACCESSOR            hAccessor;
ULONG                lNumRowsRetrieved;
HROW                 hRows[10];
HROW*                pRows = &hRows[0];
BYTE*                pBuffer;

void main() {

    //Here is the command to execute.
    WCHAR* wCmdString
        = OLESTR(" SELECT title, price FROM titles WHERE royalty > 14");
  // Call a function to initialize and establish connection.
    InitializeAndEstablishConnection();

    //Create a session object.
    if(FAILED(pIDBInitialize->QueryInterface(
                                IID_IDBCreateSession,
                                (void**) &pIDBCreateSession)))
    {
        cout << "Failed to obtain IDBCreateSession interface.\n";
    }

    if(FAILED(pIDBCreateSession->CreateSession(
                                     NULL,
                                     IID_IDBCreateCommand,
                                     (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed.\n";
    }

    //Access the ICommandText interface.
    if(FAILED(pIDBCreateCommand->CreateCommand(
                                    NULL,
                                    IID_ICommandText,
                                    (IUnknown**) &pICommandText)))
    {
        cout << "Failed to access ICommand interface.\n";
    }

    //Use SetCommandText() to specify the command text.
    if(FAILED(pICommandText->SetCommandText(DBGUID_DBSQL, wCmdString)))
    {
        cout << "Failed to set command text.\n";
    }

    //Execute the command.
    if(FAILED(hr = pICommandText->Execute(NULL,
                                    IID_IRowset,
                                    NULL,
                                    &cNumRows,
                                    (IUnknown **) &pIRowset)))
    {
        cout << "Failed to execute command.\n";
    }

    //Process the result set.
    ProcessResultSet();

    pIRowset->Release();

    //Free up memory.
    pICommandText->Release();
    pIDBCreateCommand->Release();
    pIDBCreateSession->Release();

    if(FAILED(pIDBInitialize->Uninitialize()))
    {
        /*Uninitialize is not required, but it fails if an interface
        has not been released.  This can be used for debugging.
        cout << "Problem uninitializing.\n"; */
    } //endif.
    pIDBInitialize->Release();

    //Release the COM library.
    CoUninitialize();
};
//--------------------------------------------------------------------
void InitializeAndEstablishConnection()
{
    //Initialize the COM library.
    CoInitialize(NULL);

    //Obtain access to the SQLOLEDB provider.
    hr = CoCreateInstance(CLSID_SQLOLEDB,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IDBInitialize,
                          (void **) &pIDBInitialize);
    if(FAILED(hr))
    {
        printf("Failed to get IDBInitialize interface.\n");
    } //end if

    /*
    Initialize the property values needed
    to establish the connection.
    */
    for(i = 0; i < 4; i++)
        VariantInit(&InitProperties[i].vValue);

    //Server name.
    InitProperties[0].dwPropertyID  = DBPROP_INIT_DATASOURCE;
    InitProperties[0].vValue.vt     = VT_BSTR;
    InitProperties[0].vValue.bstrVal=
                            SysAllocString(L"server");
    InitProperties[0].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[0].colid         = DB_NULLID;

//Database.
    InitProperties[1].dwPropertyID  = DBPROP_INIT_CATALOG;
    InitProperties[1].vValue.vt     = VT_BSTR;
    InitProperties[1].vValue.bstrVal= SysAllocString(L"database");
    InitProperties[1].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[1].colid         = DB_NULLID;

//Username (login).
    InitProperties[2].dwPropertyID  = DBPROP_AUTH_USERID;
    InitProperties[2].vValue.vt     = VT_BSTR;
    InitProperties[2].vValue.bstrVal= SysAllocString(L"login");
    InitProperties[2].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[2].colid         = DB_NULLID;

//Password.
    InitProperties[3].dwPropertyID  = DBPROP_AUTH_PASSWORD;
    InitProperties[3].vValue.vt     = VT_BSTR;
    InitProperties[3].vValue.bstrVal= SysAllocString(L"Password");
    InitProperties[3].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[3].colid         = DB_NULLID;

    /*
    Now that the properties are set, construct the DBPROPSET structure
    (rgInitPropSet). The DBPROPSET structure is used to pass an array
    of DBPROP structures (InitProperties) to the SetProperties method.
    */
    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
    rgInitPropSet[0].cProperties    = 4;
    rgInitPropSet[0].rgProperties   = InitProperties;

    //Set initialization properties.
    hr = pIDBInitialize->QueryInterface(IID_IDBProperties,
                                   (void **)&pIDBProperties);
    if(FAILED(hr))
    {
        cout << "Failed to get IDBProperties interface.\n";
    }

    hr = pIDBProperties->SetProperties(1, rgInitPropSet);
    if(FAILED(hr))
    {
        cout << "Failed to set initialization properties.\n";
    } //end if

    pIDBProperties->Release();

    //Now establish the connection to the data source.
    if(FAILED(pIDBInitialize->Initialize()))
    {
        cout << "Problem in establishing connection to the data
        source.\n";
    }
} //end of InitializeAndEstablishConnection.
//--------------------------------------------------------------------
//Retrieve and display data resulting from a query.
void ProcessResultSet()
{
    //Obtain access to the IColumnInfo interface, from the Rowset
    object.
    hr = pIRowset->QueryInterface(IID_IColumnsInfo,
                                 (void **)&pIColumnsInfo);
    if(FAILED(hr))
    {
        cout << "Failed to get IColumnsInfo interface.\n";
    } //end if

    //Retrieve the column information.
    pIColumnsInfo->GetColumnInfo(&lNumCols,
                                 &pDBColumnInfo,
                                 &pStringsBuffer);

    //Free the column information interface.
    pIColumnsInfo->Release();

    //Create a DBBINDING array.
    pBindings = new DBBINDING[lNumCols];

    //Using the ColumnInfo structure, fill out the pBindings array.
    for(j=0; j<lNumCols; j++) {
        pBindings[j].iOrdinal = j+1;
        pBindings[j].obValue = ConsumerBufColOffset;
        pBindings[j].pTypeInfo = NULL;
        pBindings[j].pObject = NULL;
        pBindings[j].pBindExt = NULL;
        pBindings[j].dwPart = DBPART_VALUE;
        pBindings[j].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
        pBindings[j].eParamIO = DBPARAMIO_NOTPARAM;
        pBindings[j].cbMaxLen = pDBColumnInfo[j].ulColumnSize;
        pBindings[j].dwFlags = 0;
        pBindings[j].wType = pDBColumnInfo[j].wType;
        pBindings[j].bPrecision = pDBColumnInfo[j].bPrecision;
        pBindings[j].bScale = pDBColumnInfo[j].bScale;

        //Compute the next buffer offset.
        ConsumerBufColOffset = ConsumerBufColOffset +
                               pDBColumnInfo[j].ulColumnSize;
    };
    //Get the IAccessor interface.
    hr = pIRowset->QueryInterface(IID_IAccessor, (void **) &pIAccessor);
    if(FAILED(hr))
    {
        cout << "Failed to obtain IAccessor interface.\n";
    }
//Create an accessor from the set of bindings (pBindings).
    pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
                                lNumCols,
                                pBindings,
                                0,
                                &hAccessor,
                                NULL);

    //Print column names.
    for(j=0; j<lNumCols; j++) {
        printf("%-40S", pDBColumnInfo[j].pwszName);
    };
    //Get a set of 10 rows.
    pIRowset->GetNextRows(
                        NULL,
                        0,
                        10,
                        &lNumRowsRetrieved,
                        &pRows);

    //Allocate space for the row buffer.
    pBuffer = new BYTE[ConsumerBufColOffset];

    //Display the rows.
    while(lNumRowsRetrieved > 0) {
        //For each row, print the column data.
        for(j=0; j<lNumRowsRetrieved; j++) {
            //Clear the buffer.
            memset(pBuffer, 0, ConsumerBufColOffset);
            //Get the row data values.
            pIRowset->GetData(hRows[j], hAccessor, pBuffer);
            //Print title and price values.
            printf("%-40s%f\n", &pBuffer[pBindings[0].obValue],
                                (FLOAT) pBuffer[pBindings[0].obValue]);

        }; //for.

        //Release the rows retrieved.
        pIRowset->ReleaseRows(lNumRowsRetrieved,
                              hRows,
                              NULL,
                              NULL,
                              NULL);
        //Get the next set of 10 rows.
        pIRowset->GetNextRows(NULL,
                              0,
                              10,
                              &lNumRowsRetrieved,
                              &pRows);
    };  //while lNumRowsRetrieved > 0.

    //Free up all allocated memory.
    delete [] pBuffer;
    pIAccessor->ReleaseAccessor(hAccessor, NULL);
    pIAccessor->Release();
    delete [] pBindings;
} //ProcessResultSet.


处理大数据

SQLOLEDB 表现 ISequentialStream 接口以支持使用者将 Microsoft® SQL Server™ ntext、text 和 image 数据类型当作二进制大对象 (BLOB) 进行访问。


如何设置大数据 (OLE DB)

为将指针传递给自己的存储对象，使用者创建一个存取程序来绑定 BLOB 列值，然后调用 IRowsetChange::SetData 或 IRowsetChange::InsertRow 方法。

设置 BLOB 数据

  1. 创建一个 DBOBJECT 结构来描述如何访问 BLOB 列。在这个 DBOBJECT 结构中，将 dwFlag 元素设置为 STGM_READ，将 iid 元素设置为 IID_ISequentialStream（要表现的接口）。

  2. 设置 DBPROPSET_ROWSET 属性组中的属性以使行集可更新。

  3. 通过使用 DBBINDING 结构的数组创建一组绑定（每列一个）。在 DBBINDING 结构中，将 wType 元素设置为 DBTYPE_IUNKNOWN，将 pObject 元素设置为指向已创建的 DBOBJECT 结构。

  4. 使用 DBBINDINGS 结构数组内的绑定信息创建存取程序。

  5. 调用 GetNextRows 将接下来的行提取到行集内。调用 GetData 从行集读取数据。

  6. 若要设置数据，请创建一个包含这些数据（还有长度指示符）的存储对象，然后用绑定 BLOB 列的存取程序调用 IRowsetChange::SetData（或 IRowsetChange::InsertRow）。

下例说明如何设置 BLOB 数据。下例创建一个表、添加一条示例记录，在行集内提取该记录，然后设置 BLOB 字段的值：

#define UNICODE
#define DBINITCONSTANTS
#define INITGID

#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <iostream.h>

#include <oledb.h>
#include <oledberr.h>

#include <SQLOLEDB.h>

#define SAFE_RELEASE(pIUnknown) if(pIUnknown) (pIUnknown)->Release();
HRESULT GetCommandObject(REFIID riid, IUnknown** ppIUnknown);
HRESULT CreateTable(ICommandText* pICommandText);

class CSeqStream : public ISequentialStream
{
public:
    //Constructors
    CSeqStream();
    virtual ~CSeqStream();

    virtual BOOL Seek(ULONG iPos);
    virtual BOOL Clear();
    virtual BOOL CompareData(void* pBuffer);
    virtual ULONG Length()  { return m_cBufSize; };

    virtual operator void* const() { return m_pBuffer; };

    STDMETHODIMP_(ULONG)    AddRef(void);
    STDMETHODIMP_(ULONG)    Release(void);
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv);

    STDMETHODIMP Read(
            /* [out] */ void __RPC_FAR *pv,
            /* [in]  */ ULONG cb,
            /* [out] */ ULONG __RPC_FAR *pcbRead);

    STDMETHODIMP Write(
            /* [in] */ const void __RPC_FAR *pv,
            /* [in] */ ULONG cb,
            /* [out]*/ ULONG __RPC_FAR *pcbWritten);

protected:
    //Data

private:

    ULONG       m_cRef;         // reference count
    void*       m_pBuffer;      // buffer
    ULONG       m_cBufSize;     // buffer size
    ULONG       m_iPos;         // current index position in the buffer
};

//class implementation

CSeqStream::CSeqStream()
{
    m_iPos         = 0;
    m_cRef         = 0;
    m_pBuffer      = NULL;
    m_cBufSize     = 0;

    //The constructor AddRef's
    AddRef();
}

CSeqStream::~CSeqStream()
{
    //Shouldn't have any references left
//    ASSERT(m_cRef == 0);
    CoTaskMemFree(m_pBuffer);
}

ULONG    CSeqStream::AddRef(void)
{
    return ++m_cRef;
}

ULONG    CSeqStream::Release(void)
{
//    ASSERT(m_cRef);

    if(--m_cRef)
        return m_cRef;

    delete this;
    return 0;
}

HRESULT CSeqStream::QueryInterface(REFIID riid, void** ppv)
{
//    ASSERT(ppv);
    *ppv = NULL;

    if (riid == IID_IUnknown)
        *ppv = this;
    if (riid == IID_ISequentialStream)
        *ppv = this;

    if(*ppv)
    {
        ((IUnknown*)*ppv)->AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

BOOL CSeqStream::Seek(ULONG iPos)
{
    //Make sure the desired position is within the buffer
//    ASSERT(iPos == 0 || iPos < m_cBufSize);

    //Reset the current buffer position
    m_iPos = iPos;
    return TRUE;
}

BOOL CSeqStream::Clear()
{
    //Frees the buffer
    m_iPos         = 0;
    m_cBufSize     = 0;

    CoTaskMemFree(m_pBuffer);
    m_pBuffer = NULL;

    return TRUE;
}

BOOL CSeqStream::CompareData(void* pBuffer)
{
//    ASSERT(pBuffer);

    //Quick and easy way to compare user buffer with the stream
    return memcmp(pBuffer, m_pBuffer, m_cBufSize)==0;
}

HRESULT CSeqStream::Read(void *pv, ULONG cb, ULONG* pcbRead)
{
    //Parameter checking
    if(pcbRead)
        *pcbRead = 0;

    if(!pv)
        return STG_E_INVALIDPOINTER;

    if(cb == 0)
        return S_OK;

    //Actual code
    ULONG cBytesLeft = m_cBufSize - m_iPos;
    ULONG cBytesRead = cb > cBytesLeft ? cBytesLeft : cb;

    //if no more bytes to retrieve return
    if(cBytesLeft == 0)
        return S_FALSE;

    //Copy to users buffer the number of bytes requested or remaining
    memcpy(pv, (void*)((BYTE*)m_pBuffer + m_iPos), cBytesRead);
    m_iPos += cBytesRead;

    if(pcbRead)
        *pcbRead = cBytesRead;

    if(cb != cBytesRead)
        return S_FALSE;

    return S_OK;
}

HRESULT CSeqStream::Write(const void *pv, ULONG cb, ULONG* pcbWritten)
{
    //Parameter checking
    if(!pv)
        return STG_E_INVALIDPOINTER;

    if(pcbWritten)
        *pcbWritten = 0;

    if(cb == 0)
        return S_OK;

    //Enlarge the current buffer
    m_cBufSize += cb;

    //Need to append to the end of the stream
    m_pBuffer = CoTaskMemRealloc(m_pBuffer, m_cBufSize);
    memcpy((void*)((BYTE*)m_pBuffer + m_iPos), pv, cb);
    //m_iPos += cb;

    if(pcbWritten)
        *pcbWritten = cb;

    return S_OK;
}
//...........................................................
void main()
{
    CoInitialize(NULL);

    DBOBJECT ObjectStruct;
    ObjectStruct.dwFlags = STGM_READ;
    ObjectStruct.iid     = IID_ISequentialStream;

    struct BLOBDATA
    {
        DBSTATUS            dwStatus;
        DWORD               dwLength;
        ISequentialStream*  pISeqStream;
    };

    BLOBDATA BLOBGetData;
    BLOBDATA BLOBSetData;

    const ULONG cBindings = 1;
    DBBINDING rgBindings[cBindings];
    HRESULT hr = S_OK;
    IAccessor*          pIAccessor          = NULL;
    ICommandText*       pICommandText       = NULL;
    ICommandProperties* pICommandProperties = NULL;
    IRowsetChange*      pIRowsetChange      = NULL;
    IRowset*            pIRowset            = NULL;
    CSeqStream*         pMySeqStream        = NULL;
    ULONG cRowsObtained = 0;
    HACCESSOR hAccessor = DB_NULL_HACCESSOR;
    DBBINDSTATUS rgBindStatus[cBindings];
    HROW* rghRows = NULL;
    const ULONG cPropSets = 1;
    DBPROPSET   rgPropSets[cPropSets];
    const ULONG cProperties = 1;
    DBPROP      rgProperties[cProperties];
    const ULONG cBytes = 10;
    BYTE        pBuffer[cBytes];
    ULONG       cBytesRead = 0;

    BYTE pReadData[cBytes];  //read BLOB data in this array
    memset(pReadData, 0xAA, cBytes);

    BYTE pWriteData[cBytes];  //write BLOB data from this array
    memset(pWriteData, 'D', cBytes);

    //Get Command object
    hr = GetCommandObject(IID_ICommandText,
                          (IUnknown**)&pICommandText);
    if (FAILED(hr))
    {
        printf("Failed to get ICommandText interface.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    //Create table with image column and index
    hr = CreateTable(pICommandText);
    if (FAILED(hr))
    {
        printf("Failed to create table.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    /*
    Set the DBPROPSET structure.  It is used to pass an array
    of DBPROP structures to SetProperties().
    */
    rgPropSets[0].guidPropertySet = DBPROPSET_ROWSET;
    rgPropSets[0].cProperties = cProperties;
    rgPropSets[0].rgProperties = rgProperties;

    //Now set properties in the property group (DBPROPSET_ROWSET)
    rgPropSets[0].rgProperties[0].dwPropertyID = DBPROP_UPDATABILITY;
    rgPropSets[0].rgProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
    rgPropSets[0].rgProperties[0].dwStatus = DBPROPSTATUS_OK;
    rgPropSets[0].rgProperties[0].colid = DB_NULLID;
    rgPropSets[0].rgProperties[0].vValue.vt = VT_I4;
    V_I4(&rgPropSets[0].rgProperties[0].vValue) = DBPROPVAL_UP_CHANGE;

    //Set the rowset properties
    hr = pICommandText->QueryInterface(IID_ICommandProperties,
                            (void **)&pICommandProperties);
    if (FAILED(hr))
    {
        printf("Failed to get ICommandProperties to set rowset properties.\n");
        //Release any references and return.
        goto Exit;
    } //end if
    hr = pICommandProperties->SetProperties(cPropSets, rgPropSets);
    if (FAILED(hr))
    {
        printf("Execute failed to set rowset properties.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    //Execute a command (SELECT * FROM TestISeqStream)
    hr = pICommandText->SetCommandText(DBGUID_DBSQL,
                                       L"SELECT * FROM TestISeqStream");
    if (FAILED(hr))
    {
        printf("Failed to set command text SELECT * FROM.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    hr = pICommandText->Execute(NULL, IID_IRowsetChange, NULL, NULL,
                                (IUnknown**)&pIRowsetChange);
    if (FAILED(hr))
    {
        printf("Failed to execute the command SELECT * FROM.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    //Fill the DBBINDINGS array.
    rgBindings[0].iOrdinal = 2; //ordinal position
    rgBindings[0].obValue = offsetof(BLOBDATA, pISeqStream);
    rgBindings[0].obLength = offsetof(BLOBDATA, dwLength);
    rgBindings[0].obStatus = offsetof(BLOBDATA, dwStatus);
    rgBindings[0].pTypeInfo = NULL;
    rgBindings[0].pObject = &ObjectStruct;
    rgBindings[0].pBindExt = NULL;
    rgBindings[0].dwPart =  DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH;
    rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
    rgBindings[0].eParamIO = DBPARAMIO_NOTPARAM;
    rgBindings[0].cbMaxLen = 0;
    rgBindings[0].dwFlags = 0;
    rgBindings[0].wType = DBTYPE_IUNKNOWN;
    rgBindings[0].bPrecision = 0;
    rgBindings[0].bScale = 0;

    //Create an accessor using the binding information.
    hr = pIRowsetChange->QueryInterface(IID_IAccessor,
                                        (void**)&pIAccessor);
    if (FAILED(hr))
    {
        printf("Failed to get IAccessor interface.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
                                    cBindings,
                                    rgBindings,
                                    sizeof(BLOBDATA),
                                    &hAccessor,
                                    rgBindStatus);
    if (FAILED(hr))
    {
        printf("Failed to create an accessor.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    //Now get the first row.
    hr = pIRowsetChange->QueryInterface(IID_IRowset,
                                        (void **)&pIRowset);
    if (FAILED(hr))
    {
        printf("Failed to get IRowset interface.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    hr = pIRowset->GetNextRows(NULL,
                               0,
                               1,
                               &cRowsObtained,
                               &rghRows);

    hr = pIRowset->GetData(rghRows[0],
                           hAccessor,
                           &BLOBGetData);

    //Verify the retrieved data, only if data is not null.
    if (BLOBGetData.dwStatus == DBSTATUS_S_ISNULL)
    {
        //Process null data
        printf("Provider returned a null value.\n");
    } else if(BLOBGetData.dwStatus == DBSTATUS_S_OK)
      //Provider returned a nonNULL value
    {
        BLOBGetData.pISeqStream->Read(
                                    pBuffer,
                                    cBytes,
                                    &cBytesRead);
        if(memcmp(pBuffer, pReadData, cBytes) != 0)
        {
            //cleanup
         }

        SAFE_RELEASE(BLOBGetData.pISeqStream);
    }

    //Set up data for SetData.
    pMySeqStream = new CSeqStream();

    /*
    Put data in to the ISequentialStream object
    for the provider to write.
    */
    pMySeqStream->Write(pWriteData,
                        cBytes,
                        NULL);

    BLOBSetData.pISeqStream = (ISequentialStream*)pMySeqStream;
    BLOBSetData.dwStatus    = DBSTATUS_S_OK;
    BLOBSetData.dwLength    = pMySeqStream->Length();

    //Set the data.
    hr = pIRowsetChange->SetData(rghRows[0],
                                 hAccessor,
                                 &BLOBSetData);
        if (FAILED(hr))
    {
        printf("Failed to set data.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    hr = pIAccessor->ReleaseAccessor(hAccessor, NULL);
    if (FAILED(hr))
    {
        printf("Failed to release accessor.\n");
        //Release any references and return.
        goto Exit;
    } //end if
    hr = pIRowset->ReleaseRows(cRowsObtained,
                            rghRows,
                            NULL,
                            NULL,
                            NULL);
    if (FAILED(hr))
    {
        printf("Failed to release rows.\n");
        //Release any references and return.
        goto Exit;
    } //end if
Exit:
    //Free up all allocated memory and release interface pointers.

    CoUninitialize();
} //end main.
//..........................................................
HRESULT GetCommandObject(REFIID riid, IUnknown** ppIUnknown)
{
    HRESULT hr = S_OK;

    //Local interface pointers, until a connection is made.
    IDBInitialize* pIDBInitialize = NULL;
    IDBProperties*  pIDBProperties = NULL;
    IDBCreateSession* pIDBCreateSession = NULL;
    IDBCreateCommand* pIDBCreateCommand = NULL;

    const ULONG cPropSets = 1;
    DBPROPSET rgPropSets[cPropSets];

    const ULONG cProperties = 4;
    DBPROP rgProperties[cProperties];

    /*
    Initialize the property values needed to
    establish the connection.
    */
    for(ULONG i = 0; i < 4; i++)
        VariantInit(&rgProperties[i].vValue);

    //Server name.
    rgProperties[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
    rgProperties[0].vValue.vt = VT_BSTR;
    rgProperties[0].vValue.bstrVal =
                    SysAllocString(L"server");
    rgProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
    rgProperties[0].colid = DB_NULLID;

    //Database.
    rgProperties[1].dwPropertyID = DBPROP_INIT_CATALOG;
    rgProperties[1].vValue.vt = VT_BSTR;
    rgProperties[1].vValue.bstrVal =
                    SysAllocString(L"pubs");
    rgProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;
    rgProperties[1].colid = DB_NULLID;

    //Username (login).
    rgProperties[2].dwPropertyID = DBPROP_AUTH_USERID;
    rgProperties[2].vValue.vt = VT_BSTR;
    rgProperties[2].vValue.bstrVal =
                    SysAllocString(L"login");
    rgProperties[2].dwOptions = DBPROPOPTIONS_REQUIRED;
    rgProperties[2].colid = DB_NULLID;

    //Password.
    rgProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;
    rgProperties[3].vValue.vt = VT_BSTR;
    rgProperties[3].vValue.bstrVal =
                    SysAllocString(L"password");
    rgProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;
    rgProperties[3].colid = DB_NULLID;

    /*
    Now that the properties are set, construct the DBPROPSET
    structure (rgInitPropSet).  The DBPROPSET structure is used
    to pass an array of DBPROP structures (InitProperties) to the
    SetProperties method.
    */
    rgPropSets[0].guidPropertySet   = DBPROPSET_DBINIT;
    rgPropSets[0].cProperties       = cProperties;
    rgPropSets[0].rgProperties      = rgProperties;

    //Get the IDBInitialize interface.
    hr = CoCreateInstance(CLSID_SQLOLEDB,
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            IID_IDBInitialize,
                            (void**)&pIDBInitialize);
    if(FAILED(hr))
    {
        printf("Failed to get IDBInitialize interface.\n");
        //Release any references and return.
        goto Exit;

    } //end if

    //Set initialization properties.
    hr = pIDBInitialize->QueryInterface(IID_IDBProperties,
                                        (void **)&pIDBProperties);
    if(FAILED(hr))
    {
        printf("Failed to get IDBProperties interface.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    hr = pIDBProperties->SetProperties(cPropSets, rgPropSets);
     if(FAILED(hr))
    {
        printf("Failed to set properties for DBPROPSET_DBINIT.\n");
        //Release any references and return.
        goto Exit;
    } //end if

     hr = pIDBInitialize->Initialize();
      if(FAILED(hr))
    {
        printf("Failed to initialize.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    //Create a session object.
      hr = pIDBInitialize->QueryInterface(
                                IID_IDBCreateSession,
                                (void **)&pIDBCreateSession);
       if(FAILED(hr))
    {
        printf("Failed to get pIDBCreateSession interface.\n");
        //Release any references and return.
        goto Exit;
    } //end if

       hr = pIDBCreateSession->CreateSession(
                                    NULL,
                                    IID_IDBCreateCommand,
                                    (IUnknown**)&pIDBCreateCommand);
     if(FAILED(hr))
    {
        printf("Failed to create session object.\n");
        //Release any references and return.
        goto Exit;
    } //end if

     //Get CommandText object
     hr = pIDBCreateCommand->CreateCommand(
                                    NULL,
                                    riid,
                                    (IUnknown**)ppIUnknown);
     if(FAILED(hr))
    {
        printf("Failed to create CommandText object.\n");
        //Release any references and return.
        goto Exit;
    } //end if

     return hr;
Exit:
    //Free up all allocated memory and release interface pointers.
     return hr;

} //end function
//...............................................................
HRESULT CreateTable(ICommandText* pICommandText)
{
    HRESULT hr = S_OK;

    //Drop existing table.
    hr = pICommandText->SetCommandText(
                            DBGUID_DBSQL,
                            L"DROP TABLE TestISeqStream");
    if(FAILED(hr))
    {
        printf("Failed to set command text DROP TABLE.\n");
        //Release any references and return.
        goto Exit;

    } //end if

    hr = pICommandText->Execute(NULL, IID_NULL, NULL, NULL, NULL);
    if(FAILED(hr))
    {
        printf("Failed to drop the table.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    //Create a new table.
    hr = pICommandText->SetCommandText(DBGUID_DBSQL,
         L"CREATE TABLE TestISeqStream (col1 int,col2 image)");
    if(FAILED(hr))
    {
        printf("Failed to set command text CREATE TABLE.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    hr = pICommandText->Execute(NULL, IID_NULL, NULL, NULL, NULL);
    if(FAILED(hr))
    {
        printf("Failed to create new table.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    //Insert one row into table.
    hr = pICommandText->SetCommandText(DBGUID_DBSQL,
    L"INSERT INTO TestISeqStream(col1,col2) VALUES (1,0xAAAAAAAAAAAAAAAAA)");
    if(FAILED(hr))
    {
        printf("Failed to set command text INSERT INTO.\n");
        //Release any references and return.
        goto Exit;
    } //end if

    hr = pICommandText->Execute(NULL, IID_NULL, NULL, NULL, NULL);
    if(FAILED(hr))
    {
        printf("Failed to insert record in the table.\n");
        //Release any references and return.
        goto Exit;
    } //end if

Exit:
    //Free up all allocated memory and release interface pointers.
     return hr;

} //end function


枚举 OLE DB 数据源

SQLOLEDB 有枚举符，使用者可将其调用以搜索可访问的数据源。使用者应使用枚举符搜索数据源，而不要直接搜索注册表。那样，使用者在注册表信息更改时仍将继续工作。


如何枚举 OLE DB 数据源 (OLE DB)

为列出对于 SQLOLEDB 枚举符可见的数据源，使用者调用 ISourcesRowset::GetSourcesRowset 方法。此方法返回有关当前可见的数据源信息的行集。

根据所使用的网络库，为数据源搜索适当的域。对于命名管道，则是客户登录到的域。对于 AppleTalk，是默认区域。对于 SPX/IPX，则是在平构数据库中的 SQL Server 安装列表。对于 Banyan VINES，是在本地网络上的 SQL Server 安装。不支持多协议和 TCP/IP 套接字。

服务器在关闭或打开时，会用几分钟更新这些域中的信息。

枚举 OLE DB 数据源

  1. 通过调用 ISourceRowset::GetSourcesRowset 检索源行集。

  2. 通过调用 GetColumnInfo::IcolumnInfo 查找对枚举符行集的描述。

  3. 根据列信息创建绑定结构。

  4. 通过调用 IAccessor::CreateAccessor 创建行集存取程序。

  5. 通过调用 IRowset::GetNextRows 提取行。

  6. 通过调用 IRowset::GetData 从行集的行复本中检索数据并对数据进行处理。
//How to use the enumerator object to list
//the data sources available.

#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID

#include <windows.h>
#include <stddef.h>
#include <oledb.h>
#include <oledberr.h>
#include <SQLOLEDB.h>
#include <stdio.h>

#define NUMROWS_CHUNK  5

//AdjustLen supports binding on four-byte boundaries.
_inline ULONG AdjustLen(ULONG cb)
{
    return ((cb + 3) & ~3);
}

// Get the characteristics of the rowset (the IColumnsInfo interface).
HRESULT GetColumnInfo
    (
    IRowset*                       pIRowset,
    UINT*                          pnCols,
    DBCOLUMNINFO**                 ppColumnsInfo,
    OLECHAR**                      ppColumnStrings
    )
    {
    IColumnsInfo*   pIColumnsInfo;
    HRESULT         hr;

    *pnCols = 0;
    if (FAILED(pIRowset->QueryInterface(IID_IColumnsInfo,
                                       (void**) &pIColumnsInfo)))
        {
        return (E_FAIL);
        }

    hr = pIColumnsInfo->GetColumnInfo((ULONG*) pnCols,
                                      ppColumnsInfo,
                                      ppColumnStrings);
    if (FAILED(hr))
        {
        //Process error.
        }
    pIColumnsInfo->Release();

    return (hr);
    }

// Create binding structures from column information. Binding structures
// will be used to create an accessor that allows row value retrieval.
void CreateDBBindings
    (
    UINT               nCols,
    DBCOLUMNINFO*      pColumnsInfo,
    DBBINDING**        ppDBBindings,
    BYTE**             ppRowValues
    )
    {
    ULONG              nCol;
    ULONG              cbRow = 0;
    ULONG              cbCol;
    DBBINDING*         pDBBindings;
    BYTE*              pRowValues;

    pDBBindings = new DBBINDING[nCols];

    for (nCol = 0; nCol < nCols; nCol++)
        {
        pDBBindings[nCol].iOrdinal = nCol+1;
        pDBBindings[nCol].pTypeInfo = NULL;
        pDBBindings[nCol].pObject = NULL;
        pDBBindings[nCol].pBindExt = NULL;
        pDBBindings[nCol].dwPart = DBPART_VALUE;
        pDBBindings[nCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
        pDBBindings[nCol].eParamIO = DBPARAMIO_NOTPARAM;
        pDBBindings[nCol].dwFlags = 0;
        pDBBindings[nCol].wType = pColumnsInfo[nCol].wType;
        pDBBindings[nCol].bPrecision = pColumnsInfo[nCol].bPrecision;
        pDBBindings[nCol].bScale = pColumnsInfo[nCol].bScale;

        cbCol = pColumnsInfo[nCol].ulColumnSize;

        switch (pColumnsInfo[nCol].wType)
            {
            case DBTYPE_STR:
                {
                cbCol += 1;
                break;
                }

            case DBTYPE_WSTR:
                {
                cbCol = (cbCol + 1) * sizeof(WCHAR);
                break;
                }

            default:
                break;
            }

        pDBBindings[nCol].obValue = cbRow;

        pDBBindings[nCol].cbMaxLen = cbCol;
        cbRow += AdjustLen(cbCol);
      }

    pRowValues = new BYTE[cbRow];

    *ppDBBindings = pDBBindings;
    *ppRowValues = pRowValues;

    return;
    }

int main()
{
    ISourcesRowset*       pISourceRowset = NULL;
    IRowset*              pIRowset = NULL;
    IAccessor*            pIAccessor = NULL;
    DBBINDING*            pDBBindings = NULL;
    HROW*                 pRows = new HROW[500];
    BYTE*                 pData = NULL;
    HACCESSOR             hAccessorRetrieve = NULL;
    ULONG                 cRows = 0;
    ULONG                 DSSeqNumber = 0;
    HRESULT               hr;
    UINT                  nCols;
    DBCOLUMNINFO*         pColumnsInfo = NULL;
    OLECHAR*              pColumnStrings = NULL;
    DBBINDSTATUS*         pDBBindStatus = NULL;
    BYTE*                 pRowValues = NULL;
    ULONG                 cRowsObtained;
    ULONG                 iRow;
    char*                 pMultiByte = NULL;
    short*                psSourceType = NULL;
    BYTE*                 pDatasource = NULL;

    //Initialize COM library.
    CoInitialize(NULL);

    //Initialize the enumerator.
    if(FAILED(CoCreateInstance(CLSID_SQLOLEDB_ENUMERATOR,
                               NULL,
                               CLSCTX_INPROC_SERVER,
                               IID_ISourcesRowset,
                               (void**)&pISourceRowset)))
    {
        //Process error.
        return TRUE;
    }

    //Retrieve the source rowset.
    hr = pISourceRowset->GetSourcesRowset(NULL,
                                        IID_IRowset,
                                        0,
                                        NULL,
                                        (IUnknown**)&pIRowset);
    pISourceRowset->Release();
    if(FAILED(hr))
    {
        //Process error.
        return TRUE;
    }
    //Get the description of the enumerator's rowset.
    if(FAILED(hr = GetColumnInfo(pIRowset,
                                &nCols,
                                &pColumnsInfo,
                                &pColumnStrings)))
    {
        //Process error.
        goto SAFE_EXIT;
    }

    //Create the binding structures.
    CreateDBBindings(nCols,
                    pColumnsInfo,
                    &pDBBindings,
                    &pRowValues);
    pDBBindStatus = new DBBINDSTATUS[nCols];

    if (sizeof(TCHAR) != sizeof(WCHAR))
    {
        pMultiByte = new char[pDBBindings[0].cbMaxLen];
    }
    if(FAILED(pIRowset->QueryInterface(IID_IAccessor, (void**)&pIAccessor)))
    {
        //Process error.
        goto SAFE_EXIT;
    }
    //Create the rowset accessor.
    if(FAILED(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
                                             nCols,
                                             pDBBindings,
                                             0,
                                             &hAccessorRetrieve,
                                             pDBBindStatus)))
    {
        //Process error.
        goto SAFE_EXIT;
    }

    //Process all the rows, NUMROWS_CHUNK rows at a time.
    while (SUCCEEDED(hr))
    {
    hr=pIRowset->GetNextRows(NULL,
                             0,
                             NUMROWS_CHUNK,
                             &cRowsObtained,
                             &pRows);
    if(FAILED(hr))
    {
        //process error
    }
    if(cRowsObtained == 0 || FAILED(hr))
        break;

        for(iRow = 0; iRow < cRowsObtained; iRow++)
        {
            //Get the rowset data.
            if(SUCCEEDED(hr = pIRowset->GetData(pRows[iRow],
                                               hAccessorRetrieve,
                                               pRowValues)))
            {
            psSourceType = (short *)(pRowValues +
                                     pDBBindings[3].obValue);

            if (*psSourceType == DBSOURCETYPE_DATASOURCE)
            {
                DSSeqNumber = DSSeqNumber + 1; //Data source counter.
                pDatasource = (pRowValues + pDBBindings[0].obValue);

                if(sizeof(TCHAR) != sizeof(WCHAR))
                {
                    WideCharToMultiByte(CP_ACP, 0,
                        (WCHAR*)pDatasource, -1, pMultiByte,
                        pDBBindings[0].cbMaxLen, NULL, NULL);

                    printf( "DataSource# %d\tName: %S\n",
                                    DSSeqNumber, (WCHAR *) pMultiByte );
                }
                else
                {
                    printf( "DataSource# %d\tName: %S\n",
                             DSSeqNumber, (WCHAR *) pDatasource );
                } //if
            }  //if
        } //if

    } //for
        pIRowset->ReleaseRows(cRowsObtained, pRows, NULL, NULL, NULL);
    } //while
    //Release COM library.
    CoUninitialize();

    return(0);
SAFE_EXIT:
//Do the clean-up.
    return TRUE;
};


大容量复制行集

SQLOLEDB 实现提供程序专用 IRowsetFastLoad 接口，以表现支持 Microsoft® SQL Server™ 从使用者大容量复制到 SQL Server 表。


如何使用 IRowsetFastLoad 大容量复制数据 (OLE DB)

使用者通过将 SQLOLEDB 提供程序专用属性 SSPROP_ENABLEFASTLOAD 设置为 VARIANT_TRUE，通知 SQLOLEDB 需要进行大容量复制。使用者通过在数据源上设置该属性创建一个 SQLOLEDB 会话。这个新会话使使用者得以访问 IRowsetFastLoad。

将数据大容量复制到 SQL Server 表中

  1. 建立与数据源的连接。

  2. 将 SQLOLEDB 提供程序专用数据源属性 SSPROP_ENABLEFASTLOAD 设置为 VARIANT_TRUE。将该属性设置为 VARIANT_TRUE 即创建一个新会话，这个新会话使使用者得以访问 IRowsetFastLoad。

  3. 创建一个会话以请求 IOpenRowset 接口。

  4. 调用 IOpenRowset::OpenRowset 打开包含表中（通过大容量复制操作将数据复制到该表中）所有行的行集。

  5. 做必要的绑定并用 IAccessor::CreateAccessor 创建存取程序。

  6. 设置内存缓冲区，数据将从该缓冲区复制到表中。

  7. 调用 IRowsetFastLoad::InsertRow 将数据大容量复制到表中。

下例说明使用 IRowsetFastLoad 将记录大容量复制到表中的方法。在下例中，将 10 个记录添加到表 IRFLTable 中。需要在数据库中创建表 IRFLTable。

CREATE TABLE IRFLTable (col_vchar varchar(30))

#define DBINITCONSTANTS

#include <oledb.h>
#include <oledberr.h>
#include <stdio.h>
#include <stddef.h>  //for offsetof
#include <sqloledb.h>

/* @type UWORD    | 2 byte unsigned integer. */
typedef unsigned short        UWORD;
/* @type SDWORD    | 4 byte signed integer. */
typedef signed long            SDWORD;

WCHAR g_wszTable[]      = L"IRFLTable";
WCHAR g_strTestLOC[100] = L"server ";
WCHAR g_strTestDSN[]    = L"database";
WCHAR g_strTestUID[]    = L"login";
WCHAR g_strTestPWD[]    = L"password";
const UWORD g_cOPTION   = 4;
const UWORD MAXPROPERTIES = 5;
const ULONG DEFAULT_CBMAXLENGTH = 20;
IMalloc*    g_pIMalloc = NULL;
IDBInitialize*  g_pIDBInitialize = NULL;

/*
Given an ICommand pointer, properties, and query, a
rowsetpointer is returned.
*/
HRESULT   CreateSessionCommand
    (
    DBPROPSET*  rgPropertySets,
    ULONG        ulcPropCount,
    CLSID        clsidProv
    );

//Use to set properties and execute a given query.
HRESULT   ExecuteQuery
    (
    IDBCreateCommand*  pIDBCreateCommand,
    WCHAR*               pwszQuery,
    DBPROPSET*           rgPropertySets,
    ULONG               ulcPropCount,
    LONG*               pcRowsAffected,
    IRowset**           ppIRowset,
    BOOL               fSuccessOnly = TRUE
    );

//Use to set up options for call to IDBInitialize::Initialize.
void  SetupOption
    (
    DBPROPID PropID,
    WCHAR *wszVal,
    DBPROP * pDBProp
    );

//Sets fastload property on/off for session.
HRESULT SetFastLoadProperty(BOOL fSet);

//IRowsetFastLoad inserting data.
HRESULT  FastLoadData(void);

// How to lay out each column in memory.
struct COLUMNDATA {
    SDWORD            dwLength; // Length of data (not space allocated).
    DWORD            dwStatus; // Status of column.
    BYTE            bData[1]; // Store data here as a variant.
};

#define    COLUMN_ALIGNVAL         8

#define ROUND_UP(Size, Amount)(((DWORD)(Size) + ((Amount)-1)) & ~((Amount)-1))

int main()
    {

    HRESULT             hr = NOERROR;
    HRESULT             hr2 = NOERROR;
    BOOL                fResults = FALSE;
                        //OLE initialized?
    BOOL                fInitialized = FALSE;
                        //One property set for initializing.
    DBPROPSET           rgPropertySets[1];
                        //Properties within above property set.
    DBPROP              rgDBProperties[g_cOPTION];
                        //Property count.
    ULONG               ulPropCount  = 0;
                        //# of initialization properties.
    ULONG               cOptions =     g_cOPTION;
      IDBCreateCommand* pIDBCreateCommand   = NULL;
    IRowset*            pIRowset            = NULL;
    DBPROPSET*            rgProperties      = NULL;
    IAccessor*            pIAccessor        = NULL;

    //Basic initialization.
    if(FAILED(CoInitialize(NULL)))
        goto cleanup;
    else
        fInitialized = TRUE;

    hr = CoGetMalloc(MEMCTX_TASK, &g_pIMalloc);
    if((!g_pIMalloc) || FAILED(hr))
        {
        goto cleanup;
        }

    /*
    Set up property set for call to IDBInitialize
    in CreateSessionCommand.
    */
    rgPropertySets[0].rgProperties = rgDBProperties;
    rgPropertySets[0].cProperties = g_cOPTION;
    rgPropertySets[0].guidPropertySet = DBPROPSET_DBINIT;

     SetupOption(DBPROP_INIT_CATALOG,
                 g_strTestDSN,
                 &rgDBProperties[0]);
    SetupOption(DBPROP_AUTH_USERID,
                g_strTestUID,
                &rgDBProperties[1]);
    SetupOption(DBPROP_AUTH_PASSWORD,
                g_strTestPWD,
                &rgDBProperties[2]);
    SetupOption(DBPROP_INIT_DATASOURCE,
                g_strTestLOC,
                &rgDBProperties[3]);

    if(!SUCCEEDED(hr=CreateSessionCommand(rgPropertySets,
                                            1,
                                            CLSID_SQLOLEDB)))
        goto cleanup;

    //Get IRowsetFastLoad and insert data into IRFLTable.
    if(FAILED(hr = FastLoadData()))
        goto cleanup;

cleanup:
    //Free memory.
    if(rgProperties && rgProperties->rgProperties)
        delete [](rgProperties->rgProperties);
    if(rgProperties)
        delete []rgProperties;
    if(pIDBCreateCommand)
        pIDBCreateCommand->Release();

    if(pIAccessor)
        pIAccessor->Release();

    if(pIRowset)
        pIRowset->Release();
    if(g_pIMalloc)
        g_pIMalloc->Release();

    if(g_pIDBInitialize)
    {
        hr2 = g_pIDBInitialize->Uninitialize();
        if(FAILED(hr2))
            printf("Uninitialize failed\n");
    }

    if(fInitialized)
        CoUninitialize();

    if(SUCCEEDED(hr))
        printf("Test completed successfully.\n\n");
    else
        printf("Test failed.\n\n");

    return(0);
    }
//--------------------------------------------------------------
HRESULT  FastLoadData(void)
{
    HRESULT           hr                = E_FAIL;
    HRESULT           hr2               = E_FAIL;
    DBID              TableID;
    IDBCreateSession* pIDBCreateSession = NULL;
    IOpenRowset*      pIOpenRowsetFL    = NULL;
    IRowsetFastLoad*  pIFastLoad        = NULL;
    IAccessor*        pIAccessor        = NULL;
    HACCESSOR         hAccessor         = 0;
    DBBINDSTATUS      oneStatus         = 0;
    DBBINDING         oneBinding;
    ULONG             ulOffset          = 0;
    TableID.uName.pwszName              = NULL;
    LONG              i                 = 0;
    void*             pData             = NULL;
    COLUMNDATA*       pcolData          = NULL;
    CHAR              strData[] = "Show me the money!";

    TableID.eKind = DBKIND_NAME;
    TableID.uName.pwszName = new WCHAR[wcslen(g_wszTable)+2];
    wcscpy(TableID.uName.pwszName, g_wszTable);

    //Get the fastload pointer.
    if(FAILED(hr = SetFastLoadProperty(TRUE)))
        goto cleanup;

    if( FAILED( hr = g_pIDBInitialize->QueryInterface(
                                    IID_IDBCreateSession,
                                    (void **) &pIDBCreateSession )))
        goto cleanup;

    if( FAILED( hr = pIDBCreateSession->CreateSession(
                                NULL,
                                IID_IOpenRowset,
                                (IUnknown **) &pIOpenRowsetFL )))
        goto cleanup;

    //Get IRowsetFastLoad initialized to use the test table.
    if(FAILED(hr = pIOpenRowsetFL->OpenRowset(
                                NULL,
                                &TableID,
                                NULL,
                                IID_IRowsetFastLoad,
                                0,
                                NULL,
                                (LPUNKNOWN *)&pIFastLoad)))
        goto cleanup;

    //Next set up an accessor for the data.

    //Set up custom bindings.
    oneBinding.dwPart    = DBPART_VALUE |
                            DBPART_LENGTH |
                            DBPART_STATUS;
    oneBinding.iOrdinal  = 1;
    oneBinding.pTypeInfo = NULL;
    oneBinding.obValue   = ulOffset + offsetof(COLUMNDATA,bData);
    oneBinding.obLength  = ulOffset + offsetof(COLUMNDATA,dwLength);
    oneBinding.obStatus  = ulOffset + offsetof(COLUMNDATA,dwStatus);
    oneBinding.cbMaxLen  = 30;  //Size of varchar column.
    oneBinding.pTypeInfo = NULL;
    oneBinding.pObject   = NULL;
    oneBinding.pBindExt  = NULL;
    oneBinding.dwFlags   = 0;
    oneBinding.eParamIO  = DBPARAMIO_NOTPARAM;
    oneBinding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
    oneBinding.bPrecision= 0;
    oneBinding.bScale    = 0;
    oneBinding.wType     = DBTYPE_STR;
    ulOffset = oneBinding.cbMaxLen + offsetof(COLUMNDATA, bData);
    ulOffset = ROUND_UP( ulOffset, COLUMN_ALIGNVAL );

    if( FAILED( hr = pIFastLoad->QueryInterface(
                                    IID_IAccessor,
                                    (void **) &pIAccessor)))
        return hr;

    if(FAILED(hr = pIAccessor->CreateAccessor(
                                DBACCESSOR_ROWDATA,
                                1,
                                &oneBinding,
                                ulOffset,
                                &hAccessor,
                                &oneStatus)))
        return hr;

    //Set up memory buffer.
    pData = new BYTE[40];
    pcolData = (COLUMNDATA*)pData;
    pcolData->dwLength = strlen("Show the data") + 1;
    pcolData->dwStatus =  0;
    memcpy(&(pcolData->bData), "Show the data",
                            strlen("Show me data") + 1);

    for(i=0; i<10; i++)
    {
        if(FAILED(hr = pIFastLoad->InsertRow(hAccessor, pData)))
            goto cleanup;
    }

    if(FAILED(hr = pIFastLoad->Commit(TRUE)))
        printf("Error on IRFL::Commit\n");

cleanup:
    if(FAILED(hr2 = SetFastLoadProperty(FALSE)))
    {
        printf("SetFastLoadProperty(FALSE) failed with %x", hr2);
    }

    if(pIAccessor && hAccessor)
    {
        if(FAILED(pIAccessor->ReleaseAccessor(hAccessor, NULL)))
            hr = E_FAIL;
    }
    if(pIAccessor)
        pIAccessor->Release();
    if(pIFastLoad)
        pIFastLoad->Release();
    if(pIOpenRowsetFL)
        pIOpenRowsetFL->Release();
    if(pIDBCreateSession)
        pIDBCreateSession->Release();

    if(TableID.uName.pwszName)
        delete []TableID.uName.pwszName;

    return hr;
}
//--------------------------------------------------------------
HRESULT SetFastLoadProperty(BOOL fSet)
{
        HRESULT                hr          = S_OK;
        IDBProperties *        pIDBProps = NULL;
        DBPROP                rgProps[1];
        DBPROPSET           PropSet;

        VariantInit(&rgProps[0].vValue);

        rgProps[0].dwOptions    = DBPROPOPTIONS_REQUIRED;
        rgProps[0].colid        = DB_NULLID;
        rgProps[0].vValue.vt    = VT_BOOL;
        rgProps[0].dwPropertyID = SSPROP_ENABLEFASTLOAD;

        if(fSet == TRUE)
            rgProps[0].vValue.boolVal = VARIANT_TRUE;
        else
            rgProps[0].vValue.boolVal = VARIANT_FALSE;

        PropSet.rgProperties    = rgProps;
        PropSet.cProperties     = 1;
        PropSet.guidPropertySet = DBPROPSET_SQLSERVERDATASOURCE;

        if(SUCCEEDED(hr = g_pIDBInitialize->QueryInterface(
                                    IID_IDBProperties,
                                    (LPVOID *)&pIDBProps)))
        {
            hr = pIDBProps->SetProperties(1, &PropSet);
        }

        VariantClear(&rgProps[0].vValue);

        if(pIDBProps)
            pIDBProps->Release();

        return hr;
}
//--------------------------------------------------------------
HRESULT  CreateSessionCommand
    (
    DBPROPSET*  rgPropertySets, //@parm [in] property sets.
    ULONG        ulcPropCount,   //@parm [in] count of prop sets.
    CLSID        clsidProv      //@parm [in] Provider CLSID.
    )
    {
    HRESULT hr = NOERROR;
    IDBCreateSession*    pIDBCreateSession = NULL;
    IDBProperties*        pIDBProperties      = NULL;
    UWORD                i=0, j=0;   //indexes.

    if(ulcPropCount    && !rgPropertySets)
        {
        hr = E_INVALIDARG;
        return hr;
        }

    if (!SUCCEEDED(hr = CoCreateInstance(clsidProv,
                                    NULL,CLSCTX_INPROC_SERVER,
                                    IID_IDBInitialize,
                                    (void **)&g_pIDBInitialize)))
    {
        goto CLEANUP;
    }

    if (!SUCCEEDED(hr = g_pIDBInitialize->QueryInterface(
                                    IID_IDBProperties,
                                    (void **)&pIDBProperties)))
    {
        goto CLEANUP;
    }

    if (!SUCCEEDED(hr = pIDBProperties->SetProperties(
                                        ulcPropCount,
                                        rgPropertySets)))
    {
        goto CLEANUP;
    }

    if (!SUCCEEDED(hr = g_pIDBInitialize->Initialize()))
    {
        printf("Call to initialize failed.\n");
        goto CLEANUP;
    }

CLEANUP:
    if(pIDBProperties)
        pIDBProperties->Release();
    if(pIDBCreateSession)
        pIDBCreateSession->Release();

    for(i = 0; i < ulcPropCount; i++)
        for(j = 0; j < rgPropertySets[i].cProperties; j++)
        {
        VariantClear(&(rgPropertySets[i].rgProperties[j]).vValue);
        }

    return hr;
    }
//--------------------------------------------------------------
void SetupOption
    (
    DBPROPID PropID,
    WCHAR *wszVal,
    DBPROP * pDBProp
    )
    {
    pDBProp->dwPropertyID = PropID;
    pDBProp->dwOptions = DBPROPOPTIONS_REQUIRED;
    pDBProp->colid = DB_NULLID;
    pDBProp->vValue.vt = VT_BSTR;
    pDBProp->vValue.bstrVal = SysAllocStringLen(
                                wszVal,
                                wcslen(wszVal));
    }


获得 FAST_FORWARD 游标

使用者可以通过设置某些行集属性，在行集内请求不同的游标行为。如果使用者不设置这些行集属性中的任何一个或将这些属性全部设置为默认值，SQLOLEDB 将使用默认结果集实现行集。如果将这些属性中的任何一个设置为默认值以外的值，SQLOLEDB 则使用服务器游标实现行集。


如何获得 FAST_FORWARD 游标

若要获得只进、只读游标，请将行集属性 DBPROP_SERVERCURSOR、DBPROP_OTHERINSERT、DBPROP_OTHERUPDATEDELETE、DBPROP_OWNINSERT、DBPROP_OWNUPDATEDELETE 设置为 VARIANT_TRUE。

获得 FAST_FORWARD 游标

  1. 建立与数据源的连接。

  2. 设置行集属性，应将 DBPROP_SERVERCURSOR、DBPROP_OTHERINSERT、DBPROP_OTHERUPDATEDELETE、DBPROP_OWNINSERT、DBPROP_OWNUPDATEDELETE 设置为 VARIANT_TRUE。

  3. 执行命令。

下例说明如何设置行集属性以获得 FAST_FORWARD 游标。设置属性后将执行 SELECT 语句以在 pubs 数据库内查找作者的姓名。

#define INITGUID
#define DBINITCONSTANTS

#include <windows.h>
#include <stdio.h>
#include <oledb.h>
#include <sqloledb.h>
#include <oledberr.h>

IDBInitialize* pIDBInitialize = NULL;
ICommandText*  pICommandText  = NULL;

// Connect to the server and create a command object.
void InitializeAndConnect();

// Set the properties to get a FAST_FORWARD cursor.
void SetRowsetProperties();

// This function executes a command and displays the results.
void ExecuteAndDisplay();

// Clean up the memory.
void Cleanup();

void main()
{
    // Initialize.
    InitializeAndConnect();

    // Set the row properties to FAST_FORWARD cursor.
    SetRowsetProperties();

    // Execute a command and display the results.
    ExecuteAndDisplay();

    // Cleanup.
    Cleanup();
}

void InitializeAndConnect()
{
    HRESULT              hr                   = S_OK;
    IDBProperties*       pIDBProperties       = NULL;
    IDBCreateSession*    pIDBCreateSession    = NULL;
    IDBCreateCommand*    pIDBCreateCommand    = NULL;
    DBPROPSET            dbPropSet;
    DBPROP               dbProp[4];

    // Initialize OLE
    if( FAILED( hr = OleInitialize( NULL ) ) )
    {
        // Handle errors here.
    }

    // Create an instance of Microsoft OLE DB Provider for SQL Server.
    if( FAILED( hr = CoCreateInstance(
                                CLSID_SQLOLEDB,
                                NULL,
                                CLSCTX_INPROC_SERVER,
                                IID_IDBProperties,
                                (void **) &pIDBProperties ) ) )
    {
        // Handle errors here.
    }

    // Set up the connection properties.
    dbProp[0].dwPropertyID      = DBPROP_INIT_DATASOURCE;
    dbProp[0].dwOptions         = DBPROPOPTIONS_REQUIRED;
    dbProp[0].colid             = DB_NULLID;
    V_VT(&(dbProp[0].vValue))   = VT_BSTR;
    V_BSTR(&(dbProp[0].vValue)) = SysAllocString( L"server " );

    dbProp[1].dwPropertyID      = DBPROP_AUTH_USERID;
    dbProp[1].dwOptions         = DBPROPOPTIONS_REQUIRED;
    dbProp[1].colid             = DB_NULLID;
    V_VT(&(dbProp[1].vValue))   = VT_BSTR;
    V_BSTR(&(dbProp[1].vValue)) = SysAllocString( L"login" );

    dbProp[2].dwPropertyID      = DBPROP_AUTH_PASSWORD;
    dbProp[2].dwOptions         = DBPROPOPTIONS_REQUIRED;
    dbProp[2].colid             = DB_NULLID;
    V_VT(&(dbProp[2].vValue))   = VT_BSTR;
    V_BSTR(&(dbProp[2].vValue)) = SysAllocString( L"" );

    dbProp[3].dwPropertyID      = DBPROP_INIT_CATALOG;
    dbProp[3].dwOptions         = DBPROPOPTIONS_REQUIRED;
    dbProp[3].colid             = DB_NULLID;
    V_VT(&(dbProp[3].vValue))   = VT_BSTR;
    V_BSTR(&(dbProp[3].vValue)) = SysAllocString( L"pubs" );

    dbPropSet.rgProperties      = dbProp;
    dbPropSet.cProperties       = 4;
    dbPropSet.guidPropertySet   = DBPROPSET_DBINIT;

    if( FAILED( hr = pIDBProperties->SetProperties(
                                        1,
                                        &dbPropSet )))
    {
        // Handle errors here.
    }

    SysFreeString( V_BSTR(&(dbProp[0].vValue)) );
    SysFreeString( V_BSTR(&(dbProp[1].vValue)) );
    SysFreeString( V_BSTR(&(dbProp[2].vValue)) );
    SysFreeString( V_BSTR(&(dbProp[3].vValue)) );

    // Get an IDBInitialize interface.
    if( FAILED( hr = pIDBProperties->QueryInterface(
                                   IID_IDBInitialize,
                                   (void **) &pIDBInitialize )))
    {
        // Handle errors here.
    }

    // Call Initialize.
    if( FAILED( hr = pIDBInitialize->Initialize()))
    {
        // Handle errors here.
    }

    // Get a IDBCreateSession interface.
    if( FAILED( hr = pIDBInitialize->QueryInterface(
                                IID_IDBCreateSession,
                                (void **) &pIDBCreateSession )))
    {
        // Handle errors here.
    }

    // Create a session
    if( FAILED( hr = pIDBCreateSession->CreateSession(
                                 NULL,
                                 IID_IDBCreateCommand,
                                 (IUnknown **) &pIDBCreateCommand)))
    {
        // Handle errors here.
    }

    // Create a command.
    if( FAILED( hr = pIDBCreateCommand->CreateCommand(
                                     NULL,
                                     IID_ICommandText,
                                     (IUnknown **) &pICommandText)))
    {
        // Handle errors here.
    }

    // Release all the objects not needed anymore.
    pIDBProperties->Release();
    pIDBCreateSession->Release();
    pIDBCreateCommand->Release();
}

void SetRowsetProperties()
{
    HRESULT              hr                    = S_OK;
    ICommandProperties*  pICommandProperties   = NULL;
    DBPROPSET            dbPropSet;
    DBPROP               dbProp[5];

    // Get an ICommandProperties object.
    if( FAILED( hr = pICommandText->QueryInterface(
                        IID_ICommandProperties,
                        (void **) &pICommandProperties )))
    {
        // Handle errors here.
    }

    // Set up the properties to get a FAST_FORWARD cursor.
    dbProp[0].dwPropertyID       = DBPROP_SERVERCURSOR;
    dbProp[0].dwOptions          = DBPROPOPTIONS_REQUIRED;
    dbProp[0].colid              = DB_NULLID;
    V_VT(&(dbProp[0].vValue))    = VT_BOOL;
    V_BOOL(&(dbProp[0].vValue))  = VARIANT_TRUE;

    dbProp[1].dwPropertyID       = DBPROP_OTHERINSERT;
    dbProp[1].dwOptions          = DBPROPOPTIONS_REQUIRED;
    dbProp[1].colid              = DB_NULLID;
    V_VT(&(dbProp[1].vValue))    = VT_BOOL;
    V_BOOL(&(dbProp[1].vValue))  = VARIANT_TRUE;

    dbProp[2].dwPropertyID       = DBPROP_OTHERUPDATEDELETE;
    dbProp[2].dwOptions          = DBPROPOPTIONS_REQUIRED;
    dbProp[2].colid              = DB_NULLID;
    V_VT(&(dbProp[2].vValue))    = VT_BOOL;
    V_BOOL(&(dbProp[2].vValue))  = VARIANT_TRUE;

    dbProp[3].dwPropertyID       = DBPROP_OWNINSERT;
    dbProp[3].dwOptions          = DBPROPOPTIONS_REQUIRED;
    dbProp[3].colid              = DB_NULLID;
    V_VT(&(dbProp[3].vValue))    = VT_BOOL;
    V_BOOL(&(dbProp[3].vValue))  = VARIANT_TRUE;

    dbProp[4].dwPropertyID       = DBPROP_OWNUPDATEDELETE;
    dbProp[4].dwOptions          = DBPROPOPTIONS_REQUIRED;
    dbProp[4].colid              = DB_NULLID;
    V_VT(&(dbProp[4].vValue))    = VT_BOOL;
    V_BOOL(&(dbProp[4].vValue))  = VARIANT_TRUE;

    dbPropSet.rgProperties       = dbProp;
    dbPropSet.cProperties        = 5;
    dbPropSet.guidPropertySet    = DBPROPSET_ROWSET;

    if( FAILED( hr = pICommandProperties->SetProperties(
                                            1,
                                            &dbPropSet)))
    {
        // Handle errors here.
    }

    // Release the ICommandProperties object.
    pICommandProperties->Release();
}

void ExecuteAndDisplay()
{
    HRESULT             hr                  = S_OK;
    IRowset*            pIRowset            = NULL;
    IAccessor*          pIAccessor          = NULL;
    BYTE*               pData               = NULL;
    ULONG               cRowsObtained       = 0;
    ULONG               cCount              = 0;
    HROW*               pRows               = new HROW[10];
    HACCESSOR           hAccessor;
    DBBINDING           Bind[2];

    // Set the command text.
    if( FAILED( hr = pICommandText->SetCommandText(
                        DBGUID_SQL,
                        L"select au_lname, au_fname from authors")))
    {
        // Handle errors here.
    }

    // Execute the command.
    if( FAILED( hr = pICommandText->Execute(
                                          NULL,
                                          IID_IRowset,
                                          NULL,
                                          NULL,
                                          (IUnknown **) &pIRowset )))
    {
        // Handle errors here.
    }

    // Set up the binding structure for au_lname (varchar(40)).
    Bind[0].dwPart      = DBPART_VALUE;
    Bind[0].eParamIO    = DBPARAMIO_NOTPARAM;
    Bind[0].iOrdinal    = 1;
    Bind[0].pTypeInfo   = NULL;
    Bind[0].pObject     = NULL;
    Bind[0].pBindExt    = NULL;
    Bind[0].dwFlags     = 0;
    Bind[0].dwMemOwner  = DBMEMOWNER_CLIENTOWNED;
    Bind[0].obLength    = 0;
    Bind[0].obStatus    = 0;
    Bind[0].obValue     = 0;
    Bind[0].cbMaxLen    = 40;
    Bind[0].wType       = DBTYPE_STR;
    Bind[0].bPrecision  = 0;
    Bind[0].bScale      = 0;

    // Set up the binding structure for au_fname (varchar(20)).
    Bind[1].dwPart      = DBPART_VALUE;
    Bind[1].eParamIO    = DBPARAMIO_NOTPARAM;
    Bind[1].iOrdinal    = 2;
    Bind[1].pTypeInfo   = NULL;
    Bind[1].pObject     = NULL;
    Bind[1].pBindExt    = NULL;
    Bind[1].dwFlags     = 0;
    Bind[1].dwMemOwner  = DBMEMOWNER_CLIENTOWNED;
    Bind[1].obLength    = 0;
    Bind[1].obStatus    = 0;
    Bind[1].obValue     = 50;
    Bind[1].cbMaxLen    = 20;
    Bind[1].wType       = DBTYPE_STR;
    Bind[1].bPrecision  = 0;
    Bind[1].bScale      = 0;

    // Get an IAccessor interface.
    if( FAILED( hr = pIRowset->QueryInterface(
                                IID_IAccessor,
                                (void **) &pIAccessor)))
    {
        // Handle errors here.
    }

    // Create an accessor.
    if( FAILED( hr = pIAccessor->CreateAccessor(
                                DBACCESSOR_ROWDATA,
                                2,
                                Bind,
                                0,
                                &hAccessor,
                                NULL)))
    {
        // Handle errors here.
    }

    // Allocate memory for the data.
    pData = new BYTE[100];

    // Loop through all of the rows.
    while( TRUE )
    {
        if( FAILED( hr = pIRowset->GetNextRows(
                                    NULL,
                                    0,
                                    10,
                                    &cRowsObtained,
                                    &pRows ) ) )
        {
            // Handle errors here.
        }

        // Make sure some rows were obtained.
        if( cRowsObtained == 0 )
        {
            break;
        }

        // Get the data for the each of the rows.
        for( cCount = 0; cCount < cRowsObtained; cCount++ )
        {
            // Get the row data needed.
            if( FAILED( hr = pIRowset->GetData(
                                        pRows[cCount],
                                        hAccessor,
                                        pData )))
            {
                // Handle errors here.
            }

            // Display row data.
            printf( "%s, %s\n", pData, ( pData + 50 ));
        }

        // Release the rows.
        if( FAILED( hr = pIRowset->ReleaseRows(
                                    cRowsObtained,
                                    pRows,
                                    NULL,
                                    NULL,
                                    NULL )))
        {
            // Handle errors here.
        }
    }

    // Free the memory allocated for the data.
    delete [] pData;

    // Release the HACCESSOR.
    if( FAILED( hr = pIAccessor->ReleaseAccessor(
                                        hAccessor,
                                        NULL )))
    {
        // Handle errors here.
    }

    // Release the IAccessor object.
    pIAccessor->Release();

    // Release the rowset.
    pIRowset->Release();
}

void Cleanup()
{
    HRESULT  hr = S_OK;

    // Release the ICommandText object.
    pICommandText->Release();

    // Uninitialize the IDBInitialize object.
    if( FAILED( hr = pIDBInitialize->Uninitialize() ) )
    {
        // Handle errors here.
    }

    // Release the IDBInitialize object.
    pIDBInitialize->Release();

    // Uninitialize OLE.
    OleUninitialize();
}


使用书签

书签使使用者得以快速返回到某行。书签列在行集内的编号是 0。


如何使用书签检索行 (OLE DB)

使用者将绑定结构的 dwFla 字段值设置为 DBCOLUMNSINFO_ISBOOKMARK，以指出将该列作为书签使用。使用者还将行集属性 DBPROP_BOOKMARKS 设置为 VARIANT_TRUE。这使得行集内有编号为 0 的列。使用者然后使用 RowsetLocate::GetRowsAt 从书签内的偏移量所指定的行开始提取行。

使用书签检索行

  1. 建立与数据源的连接。

  2. 将行集属性 DBPROP_IRowsetLocate 设置为 VARIANT_TRUE。

  3. 执行命令。

  4. 对于将作为书签使用的列，将绑定结构的 dwFlags 字段设置为 DBCOLUMNSINFO_ISBOOKMARK 标记。

  5. 使用 IRowsetLocate::GetRowsAt 从书签内的偏移量所指定的行开始提取行。

下例说明如何使用书签提取行。在下例中，从执行 SELECT 语句所生成的结果集中检索第 5 行。

/*
    How to use bookmarks
*/
void InitializeAndEstablishConnection();
void ProcessResultSet();

#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID

#include <stdio.h>
#include <tchar.h>
#include <stddef.h>
#include <windows.h>
#include <iostream.h>
#include <oledb.h>
#include <sqloledb.h>

IDBInitialize*       pIDBInitialize     = NULL;
IDBProperties*       pIDBProperties     = NULL;
IDBCreateSession*    pIDBCreateSession  = NULL;
IDBCreateCommand*    pIDBCreateCommand  = NULL;
ICommandProperties*  pICommandProperties = NULL;
ICommandText*        pICommandText    = NULL;
IRowset*             pIRowset         = NULL;
IColumnsInfo*        pIColumnsInfo       = NULL;
DBCOLUMNINFO*        pDBColumnInfo      = NULL;
IAccessor*           pIAccessor         = NULL;
IRowsetLocate*       pIRowsetLocate      = NULL;

DBPROP               InitProperties[4];
DBPROPSET            rgInitPropSet[1];
DBPROPSET            rgPropSets[1];
DBPROP               rgProperties[1];
ULONG                i, j;
HRESULT              hr;
LONG                 cNumRows = 0;
ULONG                lNumCols;
WCHAR*               pStringsBuffer;
DBBINDING*           pBindings;
ULONG                ConsumerBufferColOffset = 0;
HACCESSOR            hAccessor;
ULONG                lNumRowsRetrieved;
HROW                 hRows[5];
HROW*                pRows = &hRows[0];
char*                pBuffer;

void main() {

    //The command to execute.
    WCHAR* wCmdString
        = OLESTR(" SELECT title_id, title FROM titles ");

  // Initialize and establish a connection to the data source.
    InitializeAndEstablishConnection();

    //Create a session object.
    if(FAILED(pIDBInitialize->QueryInterface(
                                IID_IDBCreateSession,
                                (void**) &pIDBCreateSession)))
    {
        cout << "Failed to obtain IDBCreateSession interface.\n";
    }

    if(FAILED(pIDBCreateSession->CreateSession(
                                    NULL,
                                    IID_IDBCreateCommand,
                                    (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed.\n";
    }

    //Access the ICommandText interface.
    if(FAILED(pIDBCreateCommand->CreateCommand(
                                    NULL,
                                    IID_ICommandText,
                                    (IUnknown**) &pICommandText)))
    {
        cout << "Failed to access ICommand interface.\n";
    }

    //Set DBPROP_IRowsetLocate
    if(FAILED(pICommandText->QueryInterface(
                                    IID_ICommandProperties,
                                    (void **) &pICommandProperties )))
    {
        cout << "Failed to obtain ICommandProperties interface.\n";
    }

    /*
    Set DBPROP_IRowsetLocate to VARIANT_TRUE to
    get the IRowsetLocate interface.
    */
    VariantInit(&rgProperties[0].vValue);

    rgPropSets[0].guidPropertySet   = DBPROPSET_ROWSET;
    rgPropSets[0].cProperties       = 1;
    rgPropSets[0].rgProperties      = rgProperties;

    //Set properties in the property group (DBPROPSET_ROWSET)
    rgPropSets[0].rgProperties[0].dwPropertyID  = DBPROP_IRowsetLocate;
    rgPropSets[0].rgProperties[0].dwOptions     = DBPROPOPTIONS_REQUIRED;
    rgPropSets[0].rgProperties[0].colid         = DB_NULLID;
    rgPropSets[0].rgProperties[0].vValue.vt     = VT_BOOL;
    rgPropSets[0].rgProperties[0].vValue.boolVal = VARIANT_TRUE;

    //Set the rowset properties.
    hr = pICommandText->QueryInterface(
                                IID_ICommandProperties,
                                (void **)&pICommandProperties);
    if (FAILED(hr))
    {
        printf("Failed to get ICommandProperties to set rowset properties.\n");
        //Release any references and return.
    } //end if

    hr = pICommandProperties->SetProperties(1, rgPropSets);
    if (FAILED(hr))
    {
        printf("Execute failed to set rowset properties.\n");
        //Release any references and return.
    } //end if

    pICommandProperties->Release();

    //Specify the command text.
    if(FAILED(pICommandText->SetCommandText(
                                    DBGUID_DBSQL,
                                    wCmdString)))
    {
        cout << "Failed to set command text.\n";
    }

    //Execute the command.
    if(FAILED(hr = pICommandText->Execute(
                                    NULL,
                                    IID_IRowset,
                                    NULL,
                                    &cNumRows,
                                    (IUnknown **) &pIRowset)))
    {
        cout << "Failed to execute command.\n";
    }

    ProcessResultSet();

    pIRowset->Release();

    //Free up memory.
    pICommandText->Release();
    pIDBCreateCommand->Release();
    pIDBCreateSession->Release();

    if(FAILED(pIDBInitialize->Uninitialize()))
    {
        /*
        Uninitialize is not required, but it fails if an interface
        has not been released.  This can be used for debugging.
        */
        cout << "Problem uninitializing.\n";
    } //if.
    pIDBInitialize->Release();

    //Release COM library.
    CoUninitialize();
};
//--------------------------------------------------------------------
void InitializeAndEstablishConnection()
{
    //Initialize the COM library.
    CoInitialize(NULL);

    //Obtain access to the SQLOLEDB provider.
    CoCreateInstance(   CLSID_SQLOLEDB,
                        NULL, CLSCTX_INPROC_SERVER,
                        IID_IDBInitialize,
                        (void **) &pIDBInitialize);

    //Initialize the property values that are the same for each property.
    for(i = 0; i < 5; i++) {
        VariantInit(&InitProperties[i].vValue);
        InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
        InitProperties[i].colid     = DB_NULLID;
    }

    //Server name.
    InitProperties[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
    InitProperties[0].vValue.vt = VT_BSTR;
    InitProperties[0].vValue.bstrVal =
                            SysAllocString((LPOLESTR)L"server");

    //Database.
    InitProperties[1].dwPropertyID = DBPROP_INIT_CATALOG;
    InitProperties[1].vValue.vt = VT_BSTR;
    InitProperties[1].vValue.bstrVal = SysAllocString((LPOLESTR)L"pubs");

    //Login.
    InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;
    InitProperties[2].vValue.vt = VT_BSTR;
    InitProperties[2].vValue.bstrVal = SysAllocString((LPOLESTR)L"login");

    //Password.
    InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;
    InitProperties[3].vValue.vt = VT_BSTR;
    InitProperties[3].vValue.bstrVal = SysAllocString((LPOLESTR)"password");

    //Construct the PropertySet array.
    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
    rgInitPropSet[0].cProperties = 4;
    rgInitPropSet[0].rgProperties = InitProperties;

    //Set initialization properties.
    pIDBInitialize->QueryInterface(IID_IDBProperties,
                                    (void **)&pIDBProperties);

    hr = pIDBProperties->SetProperties(1, rgInitPropSet);
    if(FAILED(hr))
    {
        cout << "Failed to set initialization properties.\n";
    }

    pIDBProperties->Release();

    //Call the initialization method to establish the connection.
    if(FAILED(pIDBInitialize->Initialize()))
    {
        cout << "Problem initializing and connecting to the data source.\n";
    }
} //end of InitializeAndEstablishConnection.
//-------------------------------------------------------------------
void ProcessResultSet()
{
    //Retrieve 5th row from the rowset (for example).
    int iBookmark = 5;

    pIRowset->QueryInterface(
                    IID_IColumnsInfo,
                    (void **)&pIColumnsInfo);

    pIColumnsInfo->GetColumnInfo(
                        &lNumCols,
                        &pDBColumnInfo,
                        &pStringsBuffer);

    //Create a DBBINDING array.
    pBindings = new DBBINDING[lNumCols];

    //Using the ColumnInfo strucuture, fill out the pBindings array.
    for(j=0; j<lNumCols; j++) {
        pBindings[j].iOrdinal  = j;
        pBindings[j].obValue   = ConsumerBufferColOffset;
        pBindings[j].pTypeInfo = NULL;
        pBindings[j].pObject   = NULL;
        pBindings[j].pBindExt  = NULL;
        pBindings[j].dwPart    = DBPART_VALUE;
        pBindings[j].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
        pBindings[j].eParamIO  = DBPARAMIO_NOTPARAM;
        pBindings[j].cbMaxLen  = pDBColumnInfo[j].ulColumnSize + 1;
                                 // + 1 for null terminator
        pBindings[j].dwFlags   = 0;
        pBindings[j].wType      = pDBColumnInfo[j].wType;
        pBindings[j].bPrecision = pDBColumnInfo[j].bPrecision;
        pBindings[j].bScale     = pDBColumnInfo[j].bScale;

        //Recalculate the next buffer offset.
        ConsumerBufferColOffset = ConsumerBufferColOffset +
                                    pDBColumnInfo[j].ulColumnSize;
    };
        /*
        Indicate that the first field is used as a bookmark by setting
        dwFlags to DBCOLUMNFLAGS_ISBOOKMARK.
        */
        pBindings[0].dwFlags = DBCOLUMNFLAGS_ISBOOKMARK;

    //Get IAccessor interface.
    hr = pIRowset->QueryInterface(
                            IID_IAccessor,
                            (void **)&pIAccessor);
    if (FAILED(hr))
    {
        printf("Failed to get IAccessor interface.\n");
    }
    //Create accessor.
    hr = pIAccessor->CreateAccessor(
                        DBACCESSOR_ROWDATA,
                        lNumCols,
                        pBindings,
                        0,
                        &hAccessor,
                        NULL);
    if(FAILED(hr))
    {
        printf("Failed to create an accessor.\n");
    }

    HRESULT hr = pIRowset->QueryInterface(
                                IID_IRowsetLocate,
                                (void **) &pIRowsetLocate);
    if (FAILED(hr))
    {
        printf("Failed to get IRowsetLocate interface.\n");
    }
        hr = pIRowsetLocate->GetRowsAt(
                                    0,
                                    NULL,
                                    sizeof(int),
                                    (BYTE *) &iBookmark,
                                    0,
                                    1,
                                    &lNumRowsRetrieved,
                                    &pRows);

        if (FAILED(hr))
        {
            printf("Calling the GetRowsAt method failed.\n");
        }
    //Create buffer and retrieve data.
    pBuffer = new char[ConsumerBufferColOffset];
    memset(pBuffer, 0, ConsumerBufferColOffset);

    hr = pIRowset->GetData(hRows[0], hAccessor, pBuffer);
    if (FAILED(hr))
    {
        printf("Failed GetDataCall.\n");
    }

    printf("%d\t%s%s\n", &pBuffer[pBindings[0].obValue],
                        &pBuffer[pBindings[1].obValue],
                        &pBuffer[pBindings[2].obValue]);

    pIRowset->ReleaseRows(lNumRowsRetrieved,
                            hRows,
                            NULL,
                            NULL,
                            NULL);

    //Free  all allocated memory.
    delete [] pBuffer;
    pIAccessor->ReleaseAccessor(hAccessor, NULL);
    pIAccessor->Release();
    delete [] pBindings;
} //ProcessResultSet.


使用 IRow::GetColumns（或 IRow::Open）和 IsequentialStream 提取列

较大的数据可以使用 IsequentialStream 接口来绑定或检索。对于绑定列，状态标志会表明该数据是否是通过设置 DBSTATUS_S_TRUNCATED 截断的。

使用 IRow::GetColumns（或 IRow::Open）和 IsequentialStream 提取列

  1. 建立与数据源的连接。

  2. 执行命令（在下例中，是通过 IID_Irow 调用 IcommandExecute::Execute()）。

  3. 可以使用 IRow::Open() 或 IRow::GetColumns() 来提取列数据。
    1. IRow::Open() 可用以打开行中的 IsequentialStream。指定 DBGUID_STREAM 以表明该列中含有二进制数据流（然后可以使用 IStream 或 ISequentialStream 来读取该列中的数据）。

    2. 如果使用的是 IRow::GetColumns()，则 DBCOLUMNACCESS 结构中的 pData 元素将设置为指向一个流对象。
  4. IsequentialStream::Read() 可用来反复将指定数目的字节读入使用者缓冲区。

下面是应用程序所使用的示例表。

use pubs
go

if exists (select name from sysobjects where name = 'MyTable')
     drop table MyTable
go

create table MyTable
(
     col1  int,
     col2  varchar(50),
     col3  char(50),
     col4  datetime,
     col5  float,
     col6  money,
     col7  sql_variant,
     col8  binary(50),
     col9  text,
     col10 image
)
go

/* Enter data */
insert into MyTable
values
(
     10,
     'abcdefghijklmnopqrstuvwxyz',
     'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
     '11/1/1999 11:52 AM',
     3.14,
     99.95,
     convert(nchar(50), N'AbCdEfGhIjKlMnOpQrStUvWxYz'),
     0x123456789,
     replicate('AAAAABBBBB', 500),
     replicate(0x123456789, 500)
)
go

下面是示例代码：

/*
    Example shows how to fetch a single row using IRow. In this example
    one column at a time is retrieved from the row. This example illustrate
    the use of IRow::Open() as well as IRow::GetColumns(). To read the
    column data, the example uses ISequentialStream::Read.

*/

#define DBINITCONSTANTS
#define INITGUID

#include <stdio.h>
#include <windows.h>
#include <iostream.h>
#include <oledb.h>
#include <sqloledb.h>

//constants
const int kMaxBuff = 50;

void    InitializeAndEstablishConnection();
HRESULT GetColumnSize(IRow* pUnkRow, ULONG iCol);
ULONG    PrintData(ULONG iCols, ULONG iStart, DBCOLUMNINFO* prgInfo,
                DBCOLUMNACCESS* prgColumns);
HRESULT GetColumns(IRow* pUnkRow, ULONG iStart, ULONG iEnd);
HRESULT GetSequentialColumn(IRow* pUnkRow, ULONG iCol, BOOL fOpen = TRUE);

IDBInitialize*       pIDBInitialize     = NULL;
IDBProperties*       pIDBProperties     = NULL;
IDBCreateSession*    pIDBCreateSession  = NULL;
IDBCreateCommand*    pIDBCreateCommand  = NULL;
ICommandText*        pICommandText      = NULL;
IRow   *             pIRow                = NULL;
IColumnsInfo*        pIColumnsInfo      = NULL;
DBCOLUMNINFO*        pDBColumnInfo      = NULL;
IAccessor*           pIAccessor         = NULL;
DBPROP               InitProperties[4];
DBPROPSET            rgInitPropSet[1];
ULONG                i, j;
HRESULT              hr;
LONG                 cNumRows = 0;
ULONG                lNumCols;
WCHAR*               pStringsBuffer;
DBBINDING*           pBindings;
ULONG                ConsumerBufColOffset = 0;
HACCESSOR            hAccessor;
ULONG                lNumRowsRetrieved;
HROW                 hRows[10];
HROW*                pRows = &hRows[0];
BYTE*                pBuffer;

void main()
{
    ULONG    iidx = 0;
    WCHAR* wCmdString
        = OLESTR(" SELECT * FROM MyTable ");
  // Call a function to initialize and establish connection.
    InitializeAndEstablishConnection();

    //Create a session object.
    if(FAILED(pIDBInitialize->QueryInterface(
                                IID_IDBCreateSession,
                                (void**) &pIDBCreateSession)))
    {
        cout << "Failed to obtain IDBCreateSession interface.\n";
    }

    if(FAILED(pIDBCreateSession->CreateSession(
                                     NULL,
                                     IID_IDBCreateCommand,
                                     (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed.\n";
    }

    //Access the ICommandText interface.
    if(FAILED(pIDBCreateCommand->CreateCommand(
                                    NULL,
                                    IID_ICommandText,
                                    (IUnknown**) &pICommandText)))
    {
        cout << "Failed to access ICommand interface.\n";
    }

    //Use SetCommandText() to specify the command text.
    if(FAILED(pICommandText->SetCommandText(DBGUID_DBSQL, wCmdString)))
    {
        cout << "Failed to set command text.\n";
    }

    //Execute the command.
    if(FAILED(hr = pICommandText->Execute(NULL,
                                    IID_IRow,
                                    NULL,
                                    &cNumRows,
                                    (IUnknown **) &pIRow)))
    {
        cout << "Failed to execute command.\n";
    }

    //Get columns (one at a time) using ISequentialStream and Open

    for(iidx = 1; iidx <= 10; iidx++)
        //the 3rd parameter is by default TRUE indicating use of ISequentialStream
        //and Open.
        hr = GetSequentialColumn(pIRow, iidx);

    //Release the Row object.
    pIRow->Release();

    //Execute the command again.
    if(FAILED(hr = pICommandText->Execute(NULL,
                                    IID_IRow,
                                    NULL,
                                    &cNumRows,
                                    (IUnknown **) &pIRow)))
    {
        cout << "Failed to execute command.\n";
    }

    /*
    Now get columns (one at a time) using ISequentialStream and
    GetColumns. The 3rd parameter is by default TRUE indicating use
    of ISequentialStream and GetColumns.
    */
    for(iidx = 1; iidx <= 10; iidx++)
        hr = GetSequentialColumn(pIRow, iidx, FALSE);

    //Free up memory.
    pICommandText->Release();
    pIDBCreateCommand->Release();
    pIDBCreateSession->Release();

    if(FAILED(pIDBInitialize->Uninitialize()))
    {
        /*Uninitialize is not required, but it fails if an interface
        has not been released.  This can be used for debugging.
        cout << "Problem uninitializing.\n"; */
    } //endif.
    pIDBInitialize->Release();

    //Release the COM library.
    CoUninitialize();
};
//--------------------------------------------------------------------
HRESULT GetSequentialColumn(IRow* pUnkRow, ULONG iCol, BOOL fOpen)
{
    HRESULT hr = NOERROR;
    ULONG cbRead = 0;
    ULONG cbTotal = 0;
    ULONG cColumns = 0;
    ULONG cReads = 0;
    ISequentialStream* pIStream = NULL;
    WCHAR* pBuffer[kMaxBuff];//50 chars read by ISequentialStream::Read()
    DBCOLUMNINFO* prgInfo;
    OLECHAR* pColNames;
    IColumnsInfo* pIColumnsInfo;
    DBID columnid;
    DBCOLUMNACCESS column;

    wprintf(TEXT("[RETRIEVING COLUMN %d SEQUENTIALLY]\n"), iCol);

    //Get column information (basically get column id)
    hr = pUnkRow->QueryInterface(IID_IColumnsInfo,
                            (void**) &pIColumnsInfo);
    if(FAILED(hr))
        goto CLEANUP;

    hr = pIColumnsInfo->GetColumnInfo(&cColumns, &prgInfo, &pColNames);
    if (FAILED(hr))
        goto CLEANUP;

    //Get Column ID
    columnid = (prgInfo + (iCol - 1))->columnid;
    if (fOpen) //Get columns using Open and ISequentialStream.
    {
        wprintf(TEXT("[RETRIEVING COLUMNS USING "));
        wprintf(TEXT(" ISequentialSteam and Open]\n"));
        //Open sequential stream
        hr = pUnkRow->Open(NULL,
                            &columnid,
                            DBGUID_STREAM,
                            0,
                            IID_ISequentialStream,
                            (LPUNKNOWN *)&pIStream);
        if (FAILED(hr))
        {
            wprintf(TEXT("Unable to get ISequentialStream interface.\n"));
            goto CLEANUP;
        }
    }

    else    //Get Columns using GetColumns and ISequentialStream.
    {
        IUnknown* pUnkStream = NULL;

        ZeroMemory(&column, sizeof(column));
        column.columnid = prgInfo[iCol - 1].columnid;
        column.wType    = DBTYPE_IUNKNOWN;
        column.pData    = (LPVOID*) &pUnkStream;

        hr = pUnkRow->GetColumns(1, &column);
        if (FAILED(hr))
        {
            wprintf(TEXT("Error executing IRow::GetColumns.\n"));
            goto CLEANUP;
        }

        hr = pUnkStream->QueryInterface(IID_ISequentialStream,
                                        (LPVOID*) &pIStream);
        if (FAILED(hr))
        {
            wprintf(TEXT("Unable to get ISequentialStream interface "));
            wprintf(TEXT("via IRow::GetColumns.\n"));
            goto CLEANUP;
        }

        pUnkStream->Release();
    }

    ZeroMemory(pBuffer, kMaxBuff * sizeof(WCHAR));

    //Read 50 chars at a time until no more data.
    do
    {
        hr = pIStream->Read(pBuffer, kMaxBuff, &cbRead);
        if(FAILED(hr))
        {
            wprintf(TEXT("Error reading data.\n"));
            goto CLEANUP;
        }
        cbTotal = cbTotal + cbRead;
        //Print the data
        wprintf(TEXT("READ #%d: %-*S\n"), ++cReads, kMaxBuff, pBuffer);
    } while(cbRead > 0);

    wprintf(TEXT("[READ %d bytes for column %d.\n"), cbTotal, iCol);

CLEANUP:
    if(pIColumnsInfo)
        pIColumnsInfo->Release();

    if(pIStream)
        pIStream->Release();

    return hr;
}

//--------------------------------------------------------------------
BOOL InitColumn(DBCOLUMNACCESS* pCol, DBCOLUMNINFO* pInfo)
{
    /*
    If text or image column is being read, in which case the max possible
    length of a value is the column is hugh, we will limit that size to
    512 bytes (for illustration purposes).
    */

    ULONG ulSize=
        (pInfo->ulColumnSize < 0x7fffffff) ? pInfo->ulColumnSize : 512;

    //Verify dta buffer is large enough.
    if(pCol->cbMaxLen < (ulSize + 1))
    {
        if(pCol->pData)
        {
            delete [] pCol->pData;
            pCol->pData = NULL;
        }

        //Allocate data buffer
        pCol->pData = new WCHAR[ulSize + 1];
        //set the max length of caller-initialized memory.
        pCol->cbMaxLen = sizeof(WCHAR) * (ulSize + 1);
        /*
        In the above 2 steps, pData is pointing to memory (it is not NULL)
        and cbMaxLen has a value (not 0), so next call to IRow->GetData()
        will read the data from the column.
        */
    }

        //Clear memory buffer
        ZeroMemory((void*) pCol->pData, pCol->cbMaxLen);

        //Set properties.
        pCol->wType = DBTYPE_WSTR;
        pCol->columnid = pInfo->columnid;
        pCol->cbDataLen = 0;
        pCol->dwStatus = 0;
        pCol->dwReserved = 0;
        pCol->bPrecision = 0;
        pCol->bScale = 0;

        return TRUE;
}

//--------------------------------------------------------------------
HRESULT GetColumns(IRow* pUnkRow, ULONG iStart, ULONG iEnd)
//Start and end are same. Thus, get only one column.
{
    HRESULT            hr;
    ULONG            iidx;        //loop counter
    ULONG            cColumns;    //Count of columns
    ULONG            cUserCols;    //Count of user columns
    DBCOLUMNINFO*    prgInfo;    //Column of info. array
    OLECHAR*        pColNames;    //Array of column names
    DBCOLUMNACCESS* prgColumns; //Ptr to column access structures array
    DBCOLUMNINFO*    pCurrInfo;
    DBCOLUMNACCESS* pCurrCol;

    IColumnsInfo* pIColumnsInfo = NULL;

    //Initialize
    cColumns    = 0;
    prgInfo        = NULL;
    pColNames    = NULL;
    prgColumns    = NULL;

    printf("Retrieving data\n");

    //Get column info to build column access array
    hr=pUnkRow->QueryInterface(IID_IColumnsInfo, (void**)&pIColumnsInfo);
    if(FAILED(hr))
        goto CLEANUP;
    hr=pIColumnsInfo->GetColumnInfo(&cColumns, &prgInfo, &pColNames);
    if(FAILED(hr))
        goto CLEANUP;

    printf("In GetColumns(), Columns= %d\n", cColumns);

    /*
    Determine no. of columns to retrieve.
    Since iEnd and iStart is same, this is redundent step.
    cUserCols will always be 1.
    */
    cUserCols = iEnd - iStart + 1;
    //Walk list of columns and setup a DBCOLUMNACCESS structure
    prgColumns= new DBCOLUMNACCESS[cUserCols]; //cUserCols is only 1
    ZeroMemory((void*) prgColumns, sizeof(DBCOLUMNACCESS) * cUserCols);

    for(iidx=0; iidx < cUserCols; iidx++)
    {
        pCurrInfo = prgInfo + iidx + iStart - 1;
        pCurrCol = prgColumns + iidx;
        //Here the values of pData and cbMaxLen elements of
        //DBCOLUMNACCESS elements is set. Thus IRow->GetColumns()
        //will return actual data.
        if(InitColumn(pCurrCol, pCurrInfo) == FALSE)
            goto CLEANUP;
    }
    hr = pUnkRow->GetColumns(cUserCols, prgColumns); //cUserCols=1
    if(FAILED(hr))
    {
        printf("Error occured\n");
    }

    //Show data.
    PrintData(cUserCols, iStart, prgInfo, prgColumns);

CLEANUP:
    if(pIColumnsInfo)
        pIColumnsInfo->Release();
    if(prgColumns)
        delete [] prgColumns;

    return hr;
}
//--------------------------------------------------------------------
/*
This function returns the actual width of the data in the column
(not the columnwidth in DBCOLUMNFO structure which is the width of the
column)
*/

HRESULT GetColumnSize(IRow* pUnkRow, ULONG iCol)
{
    HRESULT            hr = NOERROR;
    ULONG            iidx = 0;      //Loop counter
    ULONG            cColumns = 0; //Count the columns
    DBCOLUMNINFO*    prgInfo;      //Column info array
    OLECHAR*        pColNames;
    DBCOLUMNACCESS    column;
    DBCOLUMNINFO*    pCurrInfo;
    IColumnsInfo*    pIColumnsInfo = NULL;

    //Initialize
    prgInfo = NULL;
    pColNames = NULL;

    printf("Checking column size\n");

    //Get column info to build column access array
    hr=pUnkRow->QueryInterface(IID_IColumnsInfo, (void**) &pIColumnsInfo);
    if (FAILED(hr))
        goto CLEANUP;

    hr=pIColumnsInfo->GetColumnInfo(&cColumns, &prgInfo, &pColNames);
    if (FAILED(hr))
        goto CLEANUP;
    printf("Value of cColumns is %d\n", cColumns);

    /*
    Setup a DBCOLUMNACCESS structure: Here pData is set to NULL and
    cbMaxLen is set to 0. Thus IRow->GetColumns() returns only the actual
    column length in cbDataLen member of DBCOLUMNACCESS structure.In this
    case you can call IRow->GetColumns() again for the same column to
    retrieve actual data in the second call.
    */
    ZeroMemory((void*) &column, sizeof(DBCOLUMNACCESS));
    column.pData=NULL;

    pCurrInfo = prgInfo + iCol - 1;
    //Get the column id in DBCOLUMNACCESS structure.
    //It is then used in GetColumn().
    column.columnid = pCurrInfo->columnid;

    printf("column.columnid value is %d\n", column.columnid);
    //We know which column to get.
    //The column.columnid gives the column number.
    hr = pUnkRow->GetColumns(1, &column);
    if (FAILED(hr))
    {
        printf("Errors occured\n");
    }
    //Show data
    PrintData(1, iCol, prgInfo, &column);

CLEANUP:
    if (pIColumnsInfo)
        pIColumnsInfo->Release();
    return hr;
}

//--------------------------------------------------------------------
BOOL GetStatus(DWORD dwStatus, WCHAR* pwszStatus)
{
    switch (dwStatus)
    {
    case DBSTATUS_S_OK:
        wcscpy(pwszStatus, TEXT("DBSTATUS_S_OK"));
        break;
    case DBSTATUS_E_UNAVAILABLE:
        wcscpy(pwszStatus, TEXT("DBSTATUS_E_UNAVAILABLE"));
        break;
    case DBSTATUS_S_TRUNCATED:
        wcscpy(pwszStatus, TEXT("DBSTATUS_S_TRUNCATED"));
        break;
    }
    return TRUE;
}
//--------------------------------------------------------------------

ULONG PrintData(ULONG iCols,
                ULONG iStart,
                DBCOLUMNINFO* prgInfo,
                DBCOLUMNACCESS* prgColumns)
{
    WCHAR wszStatus[255];
    DBCOLUMNINFO* pCurrInfo;
    DBCOLUMNACCESS* pCurrCol;

    printf("No. Name       Status     Length  Max  Data\n");

    for(ULONG iidx=0; iidx < iCols; iidx++)
    {
        pCurrInfo=prgInfo + iidx + iStart - 1;
        pCurrCol=prgColumns+iidx;

        GetStatus(pCurrCol->dwStatus, wszStatus);
        //was the data successfully retrieved?
        wprintf(TEXT("%-3d %-*s %-20s %-3d %-3d %-20s\n"),
            iStart+iidx,
            10,
            pCurrInfo->pwszName,
            wszStatus,
            pCurrCol->cbDataLen,
            pCurrCol->cbMaxLen,
            (WCHAR*) pCurrCol->pData);
    }
    wprintf(TEXT("\n"));
    return iidx;
}

//--------------------------------------------------------------------
void InitializeAndEstablishConnection()
{
    //Initialize the COM library.
    CoInitialize(NULL);

    //Obtain access to the SQLOLEDB provider.
    hr = CoCreateInstance(CLSID_SQLOLEDB,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IDBInitialize,
                          (void **) &pIDBInitialize);
    if(FAILED(hr))
    {
        printf("Failed to get IDBInitialize interface.\n");
    } //end if

    /*
    Initialize the property values needed
    to establish the connection.
    */
    for(i = 0; i < 4; i++)
        VariantInit(&InitProperties[i].vValue);

    //Server name.
    InitProperties[0].dwPropertyID  = DBPROP_INIT_DATASOURCE;
    InitProperties[0].vValue.vt     = VT_BSTR;
    InitProperties[0].vValue.bstrVal=
                            SysAllocString(L"mohanv1");
    InitProperties[0].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[0].colid         = DB_NULLID;

//Database.
    InitProperties[1].dwPropertyID  = DBPROP_INIT_CATALOG;
    InitProperties[1].vValue.vt     = VT_BSTR;
    InitProperties[1].vValue.bstrVal= SysAllocString(L"pubs");
    InitProperties[1].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[1].colid         = DB_NULLID;

//Username (login).
    InitProperties[2].dwPropertyID  = DBPROP_AUTH_USERID;
    InitProperties[2].vValue.vt     = VT_BSTR;
    InitProperties[2].vValue.bstrVal= SysAllocString(L"sa");
    InitProperties[2].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[2].colid         = DB_NULLID;

//Password.
    InitProperties[3].dwPropertyID  = DBPROP_AUTH_PASSWORD;
    InitProperties[3].vValue.vt     = VT_BSTR;
    InitProperties[3].vValue.bstrVal= SysAllocString(L"");
    InitProperties[3].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[3].colid         = DB_NULLID;

    /*
    Now that the properties are set, construct the DBPROPSET structure
    (rgInitPropSet). The DBPROPSET structure is used to pass an array
    of DBPROP structures (InitProperties) to the SetProperties method.
    */
    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
    rgInitPropSet[0].cProperties    = 4;
    rgInitPropSet[0].rgProperties   = InitProperties;

    //Set initialization properties.
    hr = pIDBInitialize->QueryInterface(IID_IDBProperties,
                                   (void **)&pIDBProperties);
    if(FAILED(hr))
    {
        cout << "Failed to get IDBProperties interface.\n";
    }

    hr = pIDBProperties->SetProperties(1, rgInitPropSet);
    if(FAILED(hr))
    {
        cout << "Failed to set initialization properties.\n";
    } //end if

    pIDBProperties->Release();

    //Now establish the connection to the data source.
    if(FAILED(pIDBInitialize->Initialize()))
    {
        cout << "Problem establishing connection to the data source.\n";
    }
} //end of InitializeAndEstablishConnection.
//--------------------------------------------------------------------


使用 IRow::GetColumns (OLE DB) 提取列

IRow 接口允许直接访问结果集中的单行列。这样，IRow 即成为从只有一行的结果集中检索列的有效方法。

使用 IRow::GetColumns 来提取列

  1. 建立与数据源的连接。

  2. 执行命令（在下例中，通过 IID_Irow 调用 IcommandExecute::Execute()）。

  3. 执行 IRow::GetColumns() 以提取结果行中的一列或多列。如果想在提取数据之前查找实际列大小，应将 DBCOLUMNACCESS 中的 pData 设置为 NULL。调用 IRow::GetColumns() 将只返回列宽。再一次调用 IRow::GetColumns() 才提取数据。

  4. 执行 IRow::GetColumns() 直到访问过所需的所有列。必须按顺序访问列。

下例说明如何使用 IRow 提取单行。同时还说明两种访问该行中的列的方法。

  • 在组中提取列，并且

  • 先获取列宽，然后提取列数据。

下面是应用程序所使用的示例表。

use pubs
go

if exists (select name from sysobjects where name = 'MyTable')
     drop table MyTable
go

create table MyTable
(
     col1  int,
     col2  varchar(50),
     col3  char(50),
     col4  datetime,
     col5  float,
     col6  money,
     col7  sql_variant,
     col8  binary(50),
     col9  text,
     col10 image
)
go
insert into MyTable
values
(
     10,
     'abcdefghijklmnopqrstuvwxyz',
     'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
     '11/1/1999 11:52 AM',
     3.14,
     99.95,
     convert(nchar(50), N'AbCdEfGhIjKlMnOpQrStUvWxYz'),
     0x123456789,
     replicate('AAAAABBBBB', 500),
     replicate(0x123456789, 500)
)
go

下面是示例代码：

/*
    This example shows how to fetch a single row using IRow. In this
    example one column at a time is retrieved from the row. The example
    shows 2 things
     1) How to fetch a group of columns (in sequence)
     2) How to access a column twice - the first time the actual column
     width is obtained and then later the actual data is accessed. In the
     DBCOLUMNACCESS structure, if pData is NULL and cbMaxLen is 0, the
     call to IRow->GetColumns() returns only the actual column length. In
     this case IRow->GetColumns() can be called again on the
     same column to retrieve the actual data.
*/
#define DBINITCONSTANTS

#include <stdio.h>
#include <windows.h>
#include <iostream.h>
#include <oledb.h>
#include <sqloledb.h>

void     InitializeAndEstablishConnection();
HRESULT GetColumnSize(IRow* pUnkRow, ULONG iCol);
ULONG     PrintData(ULONG iCols, ULONG iStart, DBCOLUMNINFO* prgInfo,
                    DBCOLUMNACCESS* prgColumns);
HRESULT GetColumns(IRow* pUnkRow, ULONG iStart, ULONG iEnd);

IDBInitialize*       pIDBInitialize     = NULL;
IDBProperties*       pIDBProperties     = NULL;
IDBCreateSession*    pIDBCreateSession  = NULL;
IDBCreateCommand*    pIDBCreateCommand  = NULL;
ICommandText*        pICommandText      = NULL;
IRow   *             pIRow                 = NULL;
IColumnsInfo*        pIColumnsInfo      = NULL;
DBCOLUMNINFO*        pDBColumnInfo      = NULL;
IAccessor*           pIAccessor         = NULL;
DBPROP               InitProperties[4];
DBPROPSET            rgInitPropSet[1];
ULONG                i, j;
HRESULT              hr;
LONG                 cNumRows = 0;
ULONG                lNumCols;
WCHAR*               pStringsBuffer;
DBBINDING*           pBindings;
ULONG                ConsumerBufColOffset = 0;
HACCESSOR            hAccessor;
ULONG                lNumRowsRetrieved;
HROW                 hRows[10];
HROW*                pRows = &hRows[0];
BYTE*                pBuffer;

void main()
{
     ULONG     iidx = 0;
     WCHAR* wCmdString
        = OLESTR(" SELECT * FROM MyTable ");
  // Call a function to initialize and establish connection.
    InitializeAndEstablishConnection();

    //Create a session object.
    if(FAILED(pIDBInitialize->QueryInterface(
                                IID_IDBCreateSession,
                                (void**) &pIDBCreateSession)))
    {
        cout << "Failed to obtain IDBCreateSession interface.\n";
    }

    if(FAILED(pIDBCreateSession->CreateSession(
                                     NULL,
                                     IID_IDBCreateCommand,
                                     (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed.\n";
    }

    //Access the ICommandText interface.
    if(FAILED(pIDBCreateCommand->CreateCommand(
                                    NULL,
                                    IID_ICommandText,
                                    (IUnknown**) &pICommandText)))
    {
        cout << "Failed to access ICommand interface.\n";
    }

    //Use SetCommandText() to specify the command text.
    if(FAILED(pICommandText->SetCommandText(DBGUID_DBSQL, wCmdString)))
    {
        cout << "Failed to set command text.\n";
    }

     /*
     Fetch columns 1-5 and then 6-10 and display the contents
     */
     if(FAILED(hr = pICommandText->Execute(NULL,
                                    IID_IRow,
                                    NULL,
                                    &cNumRows,
                                    (IUnknown **) &pIRow)))
    {
        cout << "Failed to execute command.\n";
    }
     hr = GetColumns(pIRow, 1, 5);
     hr = GetColumns(pIRow, 6, 10);

     hr = pIRow->Release();

    //Execute the command.
    if(FAILED(hr = pICommandText->Execute(NULL,
                                    IID_IRow,
                                    NULL,
                                    &cNumRows,
                                    (IUnknown **) &pIRow)))
    {
        cout << "Failed to execute command.\n";
    }

     //Get columns
     for(iidx=1; iidx <=10; iidx++)
     {
          hr=GetColumnSize(pIRow, iidx);
          hr=GetColumns(pIRow, iidx, iidx);
     }

    pIRow->Release();

    //Free up memory.
    pICommandText->Release();
    pIDBCreateCommand->Release();
    pIDBCreateSession->Release();

    if(FAILED(pIDBInitialize->Uninitialize()))
    {
        /*Uninitialize is not required, but it fails if an interface
        has not been released.  This can be used for debugging.
        cout << "Problem uninitializing.\n"; */
    } //endif.
    pIDBInitialize->Release();

    //Release the COM library.
    CoUninitialize();
};
//--------------------------------------------------------------------
BOOL InitColumn(DBCOLUMNACCESS* pCol, DBCOLUMNINFO* pInfo)
{
     //If text or image column is being read,in which case the max
     // possible length of a value is the column is hugh,we will limit
     //that size to 512 bytes (for illustration purposes).

     ULONG ulSize=
          (pInfo->ulColumnSize < 0x7fffffff) ? pInfo->ulColumnSize : 512;

     //Verify dta buffer is large enough.
     if(pCol->cbMaxLen < (ulSize + 1))
     {
          if(pCol->pData)
          {
               delete [] pCol->pData;
               pCol->pData = NULL;
          }

          //Allocate data buffer
          pCol->pData = new WCHAR[ulSize + 1];
          //set the max length of caller-initialized memory.
          pCol->cbMaxLen = sizeof(WCHAR) * (ulSize + 1);
          /*
          In the above 2 steps, pData is pointing to memory (it is not
          NULL) and cbMaxLen has a value (not 0), so next call to
          IRow->GetData() will read the data from the column.
          */
     }

          //Clear memory buffer
          ZeroMemory((void*) pCol->pData, pCol->cbMaxLen);

          //Set properties.
          pCol->wType = DBTYPE_WSTR;
          pCol->columnid = pInfo->columnid;
          pCol->cbDataLen = 0;
          pCol->dwStatus = 0;
          pCol->dwReserved = 0;
          pCol->bPrecision = 0;
          pCol->bScale = 0;
          return TRUE;
}

//--------------------------------------------------------------------
HRESULT GetColumns(IRow* pUnkRow, ULONG iStart, ULONG iEnd)
//Start and end are same. Thus, get only one column.
{
     HRESULT               hr;
     ULONG               iidx;          //loop counter
     ULONG               cColumns; //Count of columns
     ULONG               cUserCols; //Count of user columns
     DBCOLUMNINFO*     prgInfo;     //Column of info. array
     OLECHAR*          pColNames;     //Array of column names
     DBCOLUMNACCESS* prgColumns; //Ptr to column access structures array
     DBCOLUMNINFO*     pCurrInfo;
     DBCOLUMNACCESS* pCurrCol;

     IColumnsInfo* pIColumnsInfo = NULL;

     //Initialize
     cColumns     = 0;
     prgInfo          = NULL;
     pColNames     = NULL;
     prgColumns     = NULL;

     printf("Retrieving data\n");

     //Get column info to build column access array
     hr=pUnkRow->QueryInterface(IID_IColumnsInfo, (void**)&pIColumnsInfo);
     if(FAILED(hr))
          goto CLEANUP;
     hr=pIColumnsInfo->GetColumnInfo(&cColumns, &prgInfo, &pColNames);
     if(FAILED(hr))
          goto CLEANUP;

     printf("In GetColumns(), Columns= %d\n", cColumns);

     /*
     Determine no. of columns to retrieve.
     Since iEnd and iStart is same, this is redundent step.
     cUserCols will always be 1.
    */
     cUserCols = iEnd - iStart + 1;
     //Walk list of columns and setup a DBCOLUMNACCESS structure
     prgColumns= new DBCOLUMNACCESS[cUserCols]; //cUserCols is only 1
     ZeroMemory((void*) prgColumns, sizeof(DBCOLUMNACCESS) * cUserCols);

     for(iidx=0; iidx < cUserCols; iidx++)
     {
          pCurrInfo = prgInfo + iidx + iStart - 1;
          pCurrCol = prgColumns + iidx;
          //Here the values of DBCOLUMNACCESS elements is set
          //(pData and cbMaxLen)Thus IRow->GetColumns() will return actual
          //data.
          if(InitColumn(pCurrCol, pCurrInfo) == FALSE)
               goto CLEANUP;
     }
     hr = pUnkRow->GetColumns(cUserCols, prgColumns); //cUserCols = 1
     if(FAILED(hr))
     {
          printf("Error occured\n");
     }

     //Show data.
     PrintData(cUserCols, iStart, prgInfo, prgColumns);

CLEANUP:
     if(pIColumnsInfo)
          pIColumnsInfo->Release();
     if(prgColumns)
          delete [] prgColumns;

     return hr;
}
//--------------------------------------------------------------------
/*
This function returns the actual width of the data in the column
(not the columnwidth in DBCOLUMNFO structure which is the width of the
column)
*/

HRESULT GetColumnSize(IRow* pUnkRow, ULONG iCol)
{
     HRESULT               hr = NOERROR;
     ULONG               iidx = 0;  //Loop counter
     ULONG               cColumns = 0; //Count the columns
     DBCOLUMNINFO*     prgInfo;   //Column info array
     OLECHAR*          pColNames;
     DBCOLUMNACCESS     column;
     DBCOLUMNINFO*     pCurrInfo;
     IColumnsInfo*     pIColumnsInfo = NULL;

     //Initialize
     prgInfo = NULL;
     pColNames = NULL;

     printf("Checking column size\n");

     //Get column info to build column access array
     hr=pUnkRow->QueryInterface(IID_IColumnsInfo, (void**) &pIColumnsInfo);
     if (FAILED(hr))
          goto CLEANUP;

     hr=pIColumnsInfo->GetColumnInfo(&cColumns, &prgInfo, &pColNames);
     if (FAILED(hr))
          goto CLEANUP;
     printf("Value of cColumns is %d\n", cColumns);

     /*
     Setup a DBCOLUMNACCESS structure: Here pData is set to NULL and
     cbMaxLen is set to 0. Thus IRow->GetColumns() returns only the
     actual column length in cbDataLen member of DBCOLUMNACCESS structure.
     In this case you can call IRow->GetColumns() again for the same
     column to retrieve actual data in the second call.
     */
     ZeroMemory((void*) &column, sizeof(DBCOLUMNACCESS));
     column.pData=NULL;

     pCurrInfo = prgInfo + iCol - 1;
     //Get the column id in DBCOLUMNACCESS structure.
     //It is then used in GetColumn().
     column.columnid = pCurrInfo->columnid;

     printf("column.columnid value is %d\n", column.columnid);
     //We know which column to get. The column.columnid gives the column no.
     hr = pUnkRow->GetColumns(1, &column);
     if (FAILED(hr))
     {
          printf("Errors occured\n");
     }
     //Show data
     PrintData(1, iCol, prgInfo, &column);

CLEANUP:
     if (pIColumnsInfo)
          pIColumnsInfo->Release();
     return hr;
}
//--------------------------------------------------------------------
BOOL GetStatus(DWORD dwStatus, WCHAR* pwszStatus)
{
     switch (dwStatus)
     {
     case DBSTATUS_S_OK:
          wcscpy(pwszStatus, TEXT("DBSTATUS_S_OK"));
          break;
     case DBSTATUS_E_UNAVAILABLE:
          wcscpy(pwszStatus, TEXT("DBSTATUS_E_UNAVAILABLE"));
          break;
     case DBSTATUS_S_TRUNCATED:
          wcscpy(pwszStatus, TEXT("DBSTATUS_S_TRUNCATED"));
          break;
     }
     return TRUE;
}
//--------------------------------------------------------------------
ULONG PrintData(ULONG iCols,
                    ULONG iStart,
                    DBCOLUMNINFO* prgInfo,
                    DBCOLUMNACCESS* prgColumns)
{
     WCHAR wszStatus[255];
     DBCOLUMNINFO* pCurrInfo;
     DBCOLUMNACCESS* pCurrCol;

     printf("No. Name       Status     Length  Max  Data\n");

     for(ULONG iidx=0; iidx < iCols; iidx++)
     {
          pCurrInfo=prgInfo + iidx + iStart - 1;
          pCurrCol=prgColumns+iidx;

          GetStatus(pCurrCol->dwStatus, wszStatus);
          //was the data successfully retrieved?
          wprintf(TEXT("%-3d %-*s %-20s %-3d %-3d %-20s\n"),
               iStart+iidx,
               10,
               pCurrInfo->pwszName,
               wszStatus,
               pCurrCol->cbDataLen,
               pCurrCol->cbMaxLen,
               (WCHAR*) pCurrCol->pData);
     }
     wprintf(TEXT("\n"));
     return iidx;
}

//--------------------------------------------------------------------
void InitializeAndEstablishConnection()
{
    //Initialize the COM library.
    CoInitialize(NULL);

    //Obtain access to the SQLOLEDB provider.
    hr = CoCreateInstance(CLSID_SQLOLEDB,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IDBInitialize,
                          (void **) &pIDBInitialize);
    if(FAILED(hr))
    {
        printf("Failed to get IDBInitialize interface.\n");
    } //end if

    /*
    Initialize the property values needed
    to establish the connection.
    */
    for(i = 0; i < 4; i++)
        VariantInit(&InitProperties[i].vValue);

    //Server name.
    InitProperties[0].dwPropertyID  = DBPROP_INIT_DATASOURCE;
    InitProperties[0].vValue.vt     = VT_BSTR;
    InitProperties[0].vValue.bstrVal=
                            SysAllocString(L"mohanv1");
    InitProperties[0].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[0].colid         = DB_NULLID;

//Database.
    InitProperties[1].dwPropertyID  = DBPROP_INIT_CATALOG;
    InitProperties[1].vValue.vt     = VT_BSTR;
    InitProperties[1].vValue.bstrVal= SysAllocString(L"pubs");
    InitProperties[1].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[1].colid         = DB_NULLID;

//Username (login).
    InitProperties[2].dwPropertyID  = DBPROP_AUTH_USERID;
    InitProperties[2].vValue.vt     = VT_BSTR;
    InitProperties[2].vValue.bstrVal= SysAllocString(L"sa");
    InitProperties[2].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[2].colid         = DB_NULLID;

//Password.
    InitProperties[3].dwPropertyID  = DBPROP_AUTH_PASSWORD;
    InitProperties[3].vValue.vt     = VT_BSTR;
    InitProperties[3].vValue.bstrVal= SysAllocString(L"");
    InitProperties[3].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[3].colid         = DB_NULLID;

    /*
    Now that the properties are set, construct the DBPROPSET structure
    (rgInitPropSet). The DBPROPSET structure is used to pass an array
    of DBPROP structures (InitProperties) to the SetProperties method.
    */
    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
    rgInitPropSet[0].cProperties    = 4;
    rgInitPropSet[0].rgProperties   = InitProperties;

    //Set initialization properties.
    hr = pIDBInitialize->QueryInterface(IID_IDBProperties,
                                   (void **)&pIDBProperties);
    if(FAILED(hr))
    {
        cout << "Failed to get IDBProperties interface.\n";
    }

    hr = pIDBProperties->SetProperties(1, rgInitPropSet);
    if(FAILED(hr))
    {
        cout << "Failed to set initialization properties.\n";
    } //end if

    pIDBProperties->Release();

    //Now establish the connection to the data source.
    if(FAILED(pIDBInitialize->Initialize()))
    {
        cout << "Problem establishing connection to the data source.\n";
    }
} //end of InitializeAndEstablishConnection.
//--------------------------------------------------------------------


使用 ICommandStream 将 XML 设置为命令并将检索结果设置为 XML 文档

可以使用 ICommandStream 接口将 XML 文档设置为命令，并将检索结果设置为 XML 文档。

使用 XPath 查询执行模板

使用 ICommandStream 将下面包含 XPath 查询的 XML 模板指定为命令：

<ROOT xmlns:sql="urn:schemas-microsoft-com:xml-sql">
<sql:xpath-query mapping-schema="Schema.xml">Employees</sql:xpath-query>
</ROOT>

对下列映射架构执行模板中的 XPath 查询：

<?xml version="1.0" ?>
<Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes" xmlns:sql="urn:schemas-microsoft-com:xml-sql">
<ElementType name="Employees" >
<AttributeType name="EmployeeID" />
<AttributeType name="FirstName" />
<AttributeType name="LastName" />
<attribute type="EmployeeID" />
<attribute type="FirstName" />
<attribute type="LastName" />
</ElementType>
</Schema>

该查询返回所有的 employee 元素。通过默认映射，<Employees> 元素映射到 Northwind 数据库中的 Employees 表。

将 XML 设置为命令并将检索结果设置为 XML 文档

  1. 初始化并建立到数据库的连接。

  2. 从 ICommand 中获得 ICommandStream 接口。

  3. 设置必需的命令属性。在下例中，提供程序专用属性 SSPROP_STREAM_BASEPATH 设置到存储映射构架和模板文件的目录。

  4. 使用 ICommandStream::SetCommandStream 指定命令流。在下例中，所执行的 XML 模板是从文件中读取的。当希望执行较大的 XML 模板时，这一点很有用。

  5. 使用 ICommand::Execute 执行 XML 命令，并请求 IID_ISequentialStream 接口 ID。

  6. 处理结果。在下例中，从流中读取的 XML 显示在屏幕上。
void InitializeAndEstablishConnection();
void SetCommandProperties();
void ProcessResultSet();

#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID

#include <stdio.h>
#include <tchar.h>
#include <stddef.h>
#include <windows.h>
#include <iostream.h>
#include <oledb.h>
#include <SQLOLEDB.h>

class CSequentialStream : public ISequentialStream
{
   private:
      ULONG       m_cRef;              // reference count
      HANDLE      m_hFile;         // handle to the file
      LPWSTR      m_wszFileName;      // the file name

   public:
      CSequentialStream( LPWSTR );
      virtual ~CSequentialStream();

      // IUnknown Methods
      STDMETHODIMP_(ULONG)    AddRef();
      STDMETHODIMP_(ULONG)    Release();
      STDMETHODIMP QueryInterface( REFIID, LPVOID* );

      // ISequentialStream Methods
      STDMETHODIMP Read(
            /* [out] */ void __RPC_FAR*,
            /* [in]  */ ULONG,
            /* [out] */ ULONG __RPC_FAR* );

      STDMETHODIMP Write(
            /* [in] */ const void __RPC_FAR*,
            /* [in] */ ULONG,
            /* [out]*/ ULONG __RPC_FAR* );
};

IDBInitialize*       pIDBInitialize     = NULL;
IDBProperties*       pIDBProperties     = NULL;
IDBCreateSession*    pIDBCreateSession  = NULL;
IDBCreateCommand*    pIDBCreateCommand  = NULL;
ICommand*            pICommand          = NULL;
ICommandStream*      pICommandStream    = NULL;
ICommandProperties*    pICommandProperties = NULL;
IColumnsInfo*        pIColumnsInfo      = NULL;
ISequentialStream*    pIXMLOutput      = NULL;
DBCOLUMNINFO*        pDBColumnInfo      = NULL;
IAccessor*           pIAccessor        =  NULL;
DBPROP               InitProperties[4];
DBPROPSET            rgInitPropSet[1];
ULONG                i, j;
HRESULT              hr;
LONG                 cNumRows = 0;
ULONG                lNumCols;
WCHAR*               pStringsBuffer;
DBBINDING*           pBindings;
ULONG                ConsumerBufColOffset = 0;
HACCESSOR            hAccessor;
ULONG                lNumRowsRetrieved;
HROW                 hRows[10];
HROW*                pRows = &hRows[0];
BYTE*                pBuffer;
CSequentialStream    XMLInput( L"Query.xml" );

CSequentialStream::CSequentialStream
(
   LPWSTR      wszFileName
)
:
   m_cRef( 0 ),
   m_hFile( NULL ),
   m_wszFileName( NULL )
{
    // The constructor AddRefs.
    AddRef();

   // Allocate memory for the file name.
   m_wszFileName = (LPWSTR) CoTaskMemAlloc( ( wcslen( wszFileName ) + 1 ) * 2 );

   // Copy the file name.
   wcscpy( m_wszFileName, wszFileName );
}

CSequentialStream::~CSequentialStream
(
)
{
   // Free any allocated memory.
   if( m_wszFileName )
      CoTaskMemFree( m_wszFileName );

   // Close the file.
   if( m_hFile )
      CloseHandle( m_hFile );
}

ULONG
CSequentialStream::AddRef
(
)
{
    return ++m_cRef;
}

ULONG
CSequentialStream::Release()
{
    if(--m_cRef)
        return m_cRef;

    delete this;
    return 0;
}

HRESULT
CSequentialStream::QueryInterface
(
   REFIID riid,
   void** ppv
)
{
    *ppv = NULL;

    if (riid == IID_IUnknown)
        *ppv = this;

    if (riid == IID_ISequentialStream)
        *ppv = this;

    if(*ppv)
    {
        ((IUnknown*)*ppv)->AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

HRESULT
CSequentialStream::Read
(
   void *pv,
   ULONG cb,
   ULONG* pcbRead
)
{
   ULONG   cBytesRead = 0;

    // Parameter checking.
    if(pcbRead)
        *pcbRead = 0;

    if(!pv)
        return STG_E_INVALIDPOINTER;

    if(cb == 0)
        return S_OK;

   // Do we need to open the file?
   if( m_hFile == NULL )
   {
      // Open the file.
      m_hFile = CreateFile( m_wszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );

      // If the file failed to open, return E_FAIL.
      if( m_hFile == INVALID_HANDLE_VALUE )
         return E_FAIL;
   }

   // Clear the buffer.
   ZeroMemory( pv, cb );

   // Read cb bytes from the stream.
   if( !ReadFile( m_hFile, pv, cb, &cBytesRead, NULL ) )
      return E_FAIL;

   // Inform the user of how many bytes to read.
   if( NULL != pcbRead )
      *pcbRead = cBytesRead;

    if(cb != cBytesRead)
        return S_FALSE;

    return S_OK;
}

HRESULT
CSequentialStream::Write
(
   const void *pv,
   ULONG cb,
   ULONG* pcbWritten
)
{
   // For this example, only a read-only stream is needed.
   return STG_E_CANTSAVE;
}

void main()
{
   // Call a function to initialize and establish a connection.
    InitializeAndEstablishConnection();

    // Create a session object.
    if(FAILED(pIDBInitialize->QueryInterface(
                                IID_IDBCreateSession,
                                (void**) &pIDBCreateSession)))
    {
        cout << "Failed to obtain IDBCreateSession interface.\n";
    }

    if(FAILED(pIDBCreateSession->CreateSession(
                                     NULL,
                                     IID_IDBCreateCommand,
                                     (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed.\n";
    }

    // Access the ICommand interface.
    if(FAILED(pIDBCreateCommand->CreateCommand(
                                    NULL,
                                    IID_ICommand,
                                    (IUnknown**) &pICommand)))
    {
        cout << "Failed to access ICommand interface.\n";
    }

   // Get an ICommandStream interface.
   if(FAILED(pICommand->QueryInterface( IID_ICommandStream, (void**) &pICommandStream)))
   {
      cout << "Failed to get an ICommandStream interface.\n";
   }

   // Get an ICommandProperties interface.
   if(FAILED(pICommand->QueryInterface( IID_ICommandProperties, (void**) &pICommandProperties)))
   {
      cout << "Failed to get an ICommandProperties interface.\n";
   }

   // Set the command properties.
   SetCommandProperties();

    // Use SetCommandStream() to specify the command stream.
    if(FAILED(pICommandStream->SetCommandStream(IID_ISequentialStream, DBGUID_DEFAULT, (ISequentialStream*) &XMLInput )))
    {
        cout << "Failed to set command stream.\n";
    }

    // Execute the command.
    if(FAILED(hr = pICommand->Execute(NULL,
                                    IID_ISequentialStream,
                                    NULL,
                                    &cNumRows,
                                    (IUnknown **) &pIXMLOutput )))
    {
        cout << "Failed to execute command.\n";
    }

    // Process the result set.
    ProcessResultSet();

    // Free memory.
   if( pIXMLOutput )
      pIXMLOutput->Release();
   pICommandProperties->Release();
   pICommandStream->Release();
    pICommand->Release();
    pIDBCreateCommand->Release();
    pIDBCreateSession->Release();

    if(FAILED(pIDBInitialize->Uninitialize()))
    {
        /*Uninitialize is not required, but it fails if an interface
        has not been released. This can be used for debugging.
        cout << "Problem uninitializing.\n"; */
    } // endif.
    pIDBInitialize->Release();

    // Release the COM library.
    CoUninitialize();
};

//--------------------------------------------------------------------
void InitializeAndEstablishConnection()
{
    // Initialize the COM library.
    CoInitialize(NULL);

    // Obtain access to the SQLOLEDB Provider.
    hr = CoCreateInstance(CLSID_SQLOLEDB,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IDBInitialize,
                          (void **) &pIDBInitialize);
    if(FAILED(hr))
    {
        printf("Failed to get IDBInitialize interface.\n");
    } // end if

    /*
    Initialize the property values needed
    to establish the connection.
    */
    for(i = 0; i < 4; i++)
        VariantInit(&InitProperties[i].vValue);

    // Server name.
    InitProperties[0].dwPropertyID  = DBPROP_INIT_DATASOURCE;
    InitProperties[0].vValue.vt     = VT_BSTR;
    InitProperties[0].vValue.bstrVal=
                            SysAllocString(L"Server");
    InitProperties[0].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[0].colid         = DB_NULLID;

// Database.
    InitProperties[1].dwPropertyID  = DBPROP_INIT_CATALOG;
    InitProperties[1].vValue.vt     = VT_BSTR;
    InitProperties[1].vValue.bstrVal= SysAllocString(L"northwind");
    InitProperties[1].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[1].colid         = DB_NULLID;

// Username (login).
    InitProperties[2].dwPropertyID  = DBPROP_AUTH_USERID;
    InitProperties[2].vValue.vt     = VT_BSTR;
    InitProperties[2].vValue.bstrVal= SysAllocString(L"Login");
    InitProperties[2].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[2].colid         = DB_NULLID;

// Password.
//    InitProperties[3].dwPropertyID  = DBPROP_AUTH_PASSWORD;
//    InitProperties[3].vValue.vt     = VT_BSTR;
//    InitProperties[3].vValue.bstrVal= SysAllocString(L"Password");
//    InitProperties[3].dwOptions     = DBPROPOPTIONS_REQUIRED;
//    InitProperties[3].colid         = DB_NULLID;

    /*
    Now that the properties are set, construct the DBPROPSET structure.
    (rgInitPropSet). The DBPROPSET structure is used to pass an array
    of DBPROP structures (InitProperties) to the SetProperties method.
    */
    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
//  rgInitPropSet[0].cProperties    = 4;
    rgInitPropSet[0].cProperties    = 3;
    rgInitPropSet[0].rgProperties   = InitProperties;

    // Set initialization properties.
    hr = pIDBInitialize->QueryInterface(IID_IDBProperties,
                                   (void **)&pIDBProperties);
    if(FAILED(hr))
    {
        cout << "Failed to get IDBProperties interface.\n";
    }

    hr = pIDBProperties->SetProperties(1, rgInitPropSet);
    if(FAILED(hr))
    {
        cout << "Failed to set initialization properties.\n";
    } // end if

    pIDBProperties->Release();

    // Establish the connection to the data source.
    if(FAILED(pIDBInitialize->Initialize()))
    {
        cout << "Problem establishing connection to the data source.\n";
    }
} // End of InitializeAndEstablishConnection.
void SetCommandProperties()
{
//    for(i = 0; i < 4; i++)
        VariantInit(&InitProperties[0].vValue);

    // Server name.
    InitProperties[0].dwPropertyID  = SSPROP_STREAM_BASEPATH;
    InitProperties[0].vValue.vt     = VT_BSTR;
    InitProperties[0].vValue.bstrVal=
                            SysAllocString(L"C:\\MyDir");
    InitProperties[0].dwOptions     = DBPROPOPTIONS_REQUIRED;
    InitProperties[0].colid         = DB_NULLID;

    /*
    Now that the properties are set, construct the DBPROPSET structure
    (rgInitPropSet). The DBPROPSET structure is used to pass an array
    of DBPROP structures (InitProperties) to the SetProperties method.
    */
    rgInitPropSet[0].guidPropertySet = DBPROPSET_SQLSERVERSTREAM;
    rgInitPropSet[0].cProperties    = 1;
    rgInitPropSet[0].rgProperties   = InitProperties;

    // Set initialization properties.
    hr = pICommandProperties->SetProperties(1, rgInitPropSet);
    if(FAILED(hr))
    {
        cout << "Failed to set command properties.\n";
    } // end if
} // End of InitializeAndEstablishConnection.

//--------------------------------------------------------------------
// Retrieve and display data resulting from a query.
void ProcessResultSet()
{
   CHAR   szBuf[1000];
   ULONG   ulNumRead;
   HRESULT   hr;

   if( pIXMLOutput == NULL )
      return;

   // Read from the stream.
   ZeroMemory( szBuf, 1000 );
   while( ( hr = pIXMLOutput->Read( szBuf, 1000, &ulNumRead ) ) == S_OK )
   {
      cout << szBuf;
   }
} // Process resultset.
将参数传递给模板

下例显示参数值如何传递给 XML 命令。将 XML 模板指定为命令：

<ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'>
<sql:header><sql:param name='CategoryName'>Confections</sql:param></sql:header>
<sql:query>select * from Categories where CategoryName = @CategoryName for XML AUTO</sql:query>
</ROOT>

该模板包含 SQL 查询。该查询需要其参数 (@CategoryName) 的值。如果未传递任何参数值，则使用默认值 (Condiments)。

在将参数值传递给模板的过程中，参数名称及其值都必须指定。

下面是代码：

#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID

#include <stdio.h>
#include <tchar.h>
#include <stddef.h>
#include <windows.h>
#include <iostream.h>
#include "oledb.h"
#include "SQLOLEDB.h"

HRESULT InitializeAndEstablishConnection(IDBInitialize ** ppIDBInitialize);
HRESULT SetCommandProperties(ICommand * pICommand);
HRESULT ProcessResultSet(ISequentialStream * pStreamOutput);

//---------------------------------------------------------------------
// Structure Definition Section
//---------------------------------------------------------------------
struct COLUMNDATA
{
    DBLENGTH    dwLength;   // The length of the data field
    DBSTATUS    dwStatus;   // The status value
    BYTE        bData[1];   // The start of the data field
};

class CSequentialStream : public ISequentialStream
{
    private:
        ULONG       m_cRef;             // reference count
        HANDLE      m_hFile;            // handle to the file
        LPWSTR      m_wszFileName;      // the file name

    public:
        CSequentialStream( LPWSTR );
        virtual ~CSequentialStream();

        // IUnknown Methods
        STDMETHODIMP_(ULONG)    AddRef();
        STDMETHODIMP_(ULONG)    Release();
        STDMETHODIMP QueryInterface( REFIID, LPVOID* );

        // ISequentialStream Methods
        STDMETHODIMP Read(
                /* [out] */ void __RPC_FAR*,
                /* [in]  */ ULONG,
                /* [out] */ ULONG __RPC_FAR* );

        STDMETHODIMP Write(
                /* [in] */ const void __RPC_FAR*,
                /* [in] */ ULONG,
                /* [out]*/ ULONG __RPC_FAR* );
};

CSequentialStream::CSequentialStream
(
    LPWSTR      wszFileName
)
:
    m_cRef( 0 ),
    m_hFile( NULL ),
    m_wszFileName( NULL )
{
    // The constructor AddRef's.
    AddRef();

    // Allocate memory for the file name.
    m_wszFileName = (LPWSTR) CoTaskMemAlloc( ( wcslen( wszFileName ) + 1 ) * 2 );

    // Copy the file name
    wcscpy( m_wszFileName, wszFileName );
}

CSequentialStream::~CSequentialStream
(
)
{
    // Free any allocated memory.
    if( m_wszFileName )
        CoTaskMemFree( m_wszFileName );

    // Close the file.
    if( m_hFile )
        CloseHandle( m_hFile );
}

ULONG
CSequentialStream::AddRef
(
)
{
    return ++m_cRef;
}
ULONG CSequentialStream::Release()
{
    if(--m_cRef)
        return m_cRef;

    delete this;
    return 0;
}

HRESULT CSequentialStream::QueryInterface
(
    REFIID riid,
    void** ppv
)
{
    *ppv = NULL;

    if (riid == IID_IUnknown)
        *ppv = this;

    if (riid == IID_ISequentialStream)
        *ppv = this;

    if(*ppv)
    {
        ((IUnknown*)*ppv)->AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

HRESULT CSequentialStream::Read
(
    void *pv,
    ULONG cb,
    ULONG* pcbRead
)
{
    ULONG   cBytesRead = 0;

    // Parameter checking.
    if(pcbRead)
        *pcbRead = 0;

    if(!pv)
        return STG_E_INVALIDPOINTER;

    if(cb == 0)
        return S_OK;

    // Do we need to open the file?
    if( m_hFile == NULL )
    {
        // Open the file.
        m_hFile = CreateFile( m_wszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );

        // If we failed to open the file, return E_FAIL.
        if( m_hFile == INVALID_HANDLE_VALUE )
            return E_FAIL;
    }

    // Clear the buffer.
    ZeroMemory( pv, cb );

    // Read cb bytes from the stream.
    if( !ReadFile( m_hFile, pv, cb, &cBytesRead, NULL ) )
        return E_FAIL;

    // Inform the user how many bytes were read.
    if( NULL != pcbRead )
        *pcbRead = cBytesRead;

    if(cb != cBytesRead)
        return S_FALSE;

    return S_OK;
}

HRESULT CSequentialStream::Write
(
    const void *pv,
    ULONG cb,
    ULONG* pcbWritten
)
{
    // For purposes of this example, only a read-only stream is needed.
    return STG_E_CANTSAVE;
}
void main()
{
    HRESULT                 hr = S_OK;
    IDBInitialize         * pIDBInitialize          = NULL;
    IDBCreateSession      * pIDBCreateSession       = NULL;
    IDBCreateCommand      * pIDBCreateCommand       = NULL;
    ICommand              * pICommand               = NULL;
    ICommandStream        * pICommandStream         = NULL;
    ICommandWithParameters* pICommandWithParameters = NULL;
    ICommandText          * pICommandText           = NULL;
    IAccessor             * pIAccessor              = NULL;
    const ULONG             nParams = 1;
    DBPARAMS              * pParams                 = NULL;
    DBPARAMS                params;
    DBBINDING               acDBBinding[nParams];
    DBBINDSTATUS            acDBBindStatus[nParams];
    DBORDINAL               rgParamOrdinals[1];
    DBPARAMBINDINFO         rgParamBindInfo[1];
    const WCHAR           * wszParamName =      L"@CategoryName";
    const WCHAR           * wszDataSourceType = L"DBTYPE_WCHAR";
    BYTE                    sprocparams[1000];
    COLUMNDATA            * pCol = (COLUMNDATA *) sprocparams;
    ISequentialStream     * pStreamOutput       = NULL;
    DBCOLUMNINFO          * pDBColumnInfo       = NULL;
    HACCESSOR               hAccessor;
    CSequentialStream       XMLInput( L"TemplateFile.xml" );

    typedef struct tagSPROCPARAMS
    {
        WCHAR CategoryName[25];
    } SPROCPARAMS;

    CoInitialize(0);

    // Call a function to initialize and establish connection.
    if (FAILED(hr = InitializeAndEstablishConnection(&pIDBInitialize)))
        goto Cleanup;

    //Create a session object.
    if(FAILED(hr = pIDBInitialize->QueryInterface(
                                IID_IDBCreateSession,
                                (void**) &pIDBCreateSession)))
    {
        cout << "Failed to obtain IDBCreateSession interface.\n";
        goto Cleanup;
    }

    if(FAILED(hr = pIDBCreateSession->CreateSession(
                                     NULL,
                                     IID_IDBCreateCommand,
                                     (IUnknown**) &pIDBCreateCommand)))
    {
        cout << "pIDBCreateSession->CreateSession failed.\n";
        goto Cleanup;
    }

    //Access the ICommand interface.
    if(FAILED(hr = pIDBCreateCommand->CreateCommand(
                                    NULL,
                                    IID_ICommand,
                                    (IUnknown**) &pICommand)))
    {
        cout << "Failed to access ICommand interface.\n";
        goto Cleanup;
    }

    // Get an ICommandStream interface
    if(FAILED(pICommand->QueryInterface( IID_ICommandStream, (void**) &pICommandStream)))
    {
        cout << "Failed to get an ICommandStream interface.\n";
        goto Cleanup;
    }

    //Use SetCommandStream() to specify the command stream.
    if(FAILED(hr = pICommandStream->SetCommandStream(IID_ISequentialStream, DBGUID_DEFAULT, (ISequentialStream*) &XMLInput )))
    {
        cout << "Failed to set command stream.\n";
        goto Cleanup;
    }

    // Set the command properties.
    if (FAILED(hr = SetCommandProperties(pICommand)))
        goto Cleanup;

    //***************************************
    pCol->dwStatus = DBSTATUS_S_OK;
    wcscpy( (LPWSTR) pCol->bData, L"Condiments" );
    pCol->dwLength = wcslen( (LPWSTR) pCol->bData) * sizeof(WCHAR);

    /*Describe the consumer buffer by filling in the array.
    of DBBINDING structures.  Each binding associates
    a single parameter to the consumer's buffer.*/
    acDBBinding[0].iOrdinal     = 1;
    acDBBinding[0].obLength     = offsetof( COLUMNDATA, dwLength );
    acDBBinding[0].obStatus     = offsetof( COLUMNDATA, dwStatus );
    acDBBinding[0].pTypeInfo    = NULL;
    acDBBinding[0].pObject      = NULL;
    acDBBinding[0].pBindExt     = NULL;
    acDBBinding[0].dwPart       = DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH;
    acDBBinding[0].dwMemOwner   = DBMEMOWNER_CLIENTOWNED;
    acDBBinding[0].dwFlags      = 0;
    acDBBinding[0].bScale       = 0;
    acDBBinding[0].obValue      = offsetof( COLUMNDATA, bData );
    acDBBinding[0].eParamIO     = DBPARAMIO_INPUT;
    acDBBinding[0].cbMaxLen     = 50;
    acDBBinding[0].wType        = DBTYPE_WSTR;
    acDBBinding[0].bPrecision   = 0;

    rgParamOrdinals[0]              = 1;
    rgParamBindInfo[0].bPrecision   = 0;
    rgParamBindInfo[0].bScale       = 0;
    rgParamBindInfo[0].dwFlags      = DBPARAMFLAGS_ISINPUT;
    rgParamBindInfo[0].pwszDataSourceType = (WCHAR *)wszDataSourceType;
    rgParamBindInfo[0].pwszName     = (WCHAR *)wszParamName;
    rgParamBindInfo[0].ulParamSize  = 35;

    if (FAILED(hr = pICommandStream->QueryInterface(
                        IID_ICommandWithParameters,
                        (LPVOID *)&pICommandWithParameters)))
    {
        cout << "Error.\n";
        goto Cleanup;
    }

    if (FAILED(hr = pICommandWithParameters->SetParameterInfo(
                        nParams,
                        rgParamOrdinals,
                        rgParamBindInfo)))
    {
        cout << "Error.\n";
        goto Cleanup;
    }

    //Create an accessor from the above set of bindings.
    if (FAILED(hr = pICommandStream->QueryInterface(
                                    IID_IAccessor,
                                    (void**)&pIAccessor)))
    {
        cout << "Failed to get IAccessor interface.\n";
        goto Cleanup;
    }

    if (FAILED(hr = pIAccessor->CreateAccessor(
                            DBACCESSOR_PARAMETERDATA,
                            nParams,
                            acDBBinding,
                            sizeof(SPROCPARAMS),
                            &hAccessor,
                            acDBBindStatus)))
    {
        cout << "Failed to create accessor for the defined parameters.\n";
        goto Cleanup;
    }
    /*
    Fill in DBPARAMS structure for the command execution. This structure
    specifies the parameter values in the command and is then passed
    to Execute.
    */
    params.pData = sprocparams; //pCol->bData; //sprocparams;
    params.cParamSets = 1;
    params.hAccessor = hAccessor;

    pParams = &params;

    //***************************************
    //Execute the command.
    if(FAILED(hr = pICommand->Execute(NULL,
                                    IID_ISequentialStream,
                                    pParams,
                                    NULL,
                                    (IUnknown **) &pStreamOutput )))
    {
        cout << "Failed to execute command.\n";
        goto Cleanup;
    }

    //Process the result set.
    if (FAILED(hr = ProcessResultSet(pStreamOutput)))
    {
        goto Cleanup;
    }

Cleanup:
    //Free up memory.
    if( pStreamOutput )
        pStreamOutput->Release();
    if (pICommandStream)
        pICommandStream->Release();
    if (pICommand)
        pICommand->Release();
    if (pIDBCreateCommand)
        pIDBCreateCommand->Release();
    if (pIDBCreateSession)
        pIDBCreateSession->Release();
    if (pIDBInitialize)
        pIDBInitialize->Release();

    if (hr)
    {
        IErrorInfo* pErrorInfo = NULL;
        BSTR        bstrDesc = NULL;
        GetErrorInfo(0, &pErrorInfo);
        if (pErrorInfo)
        {
            pErrorInfo->GetDescription(&bstrDesc);
            printf ("\r\nError: %S\r\n", bstrDesc ? bstrDesc : L"Unknown error");
            SysFreeString(bstrDesc);
            pErrorInfo->Release();
        }
    }

    //Release the COM library.
    CoUninitialize();
};

//--------------------------------------------------------------------
HRESULT InitializeAndEstablishConnection(IDBInitialize ** ppIDBInitialize)
{
    HRESULT         hr = S_OK;
    IDBInitialize * pIDBInitialize = NULL;
    IDBProperties * pIDBProperties = NULL;
    DBPROP          rgIDBProps[4];
    DBPROPSET       rgIDBPropSet[1];
    int             ii;

    if (!ppIDBInitialize)
        return E_INVALIDARG;

    *ppIDBInitialize = NULL;

    /*
    Initialize the property values needed
    to establish the connection.
    */
    for(ii = 0; ii < 4; ii++)
        VariantInit(&rgIDBProps[ii].vValue);

    //Obtain access to the SQLOLEDB provider.
    if(FAILED(hr = CoCreateInstance(CLSID_SQLOLEDB,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IDBInitialize,
                          (void **) &pIDBInitialize)))
    {
        printf("Failed to get IDBInitialize interface.\n");
        goto Cleanup;
    }

    //Server name.
    rgIDBProps[0].dwPropertyID  = DBPROP_INIT_DATASOURCE;
    rgIDBProps[0].vValue.vt     = VT_BSTR;
    rgIDBProps[0].vValue.bstrVal= SysAllocString(L"server");
    rgIDBProps[0].dwOptions     = DBPROPOPTIONS_REQUIRED;
    rgIDBProps[0].colid         = DB_NULLID;

//Database.
    rgIDBProps[1].dwPropertyID  = DBPROP_INIT_CATALOG;
    rgIDBProps[1].vValue.vt     = VT_BSTR;
    rgIDBProps[1].vValue.bstrVal= SysAllocString(L"Northwind");
    rgIDBProps[1].dwOptions     = DBPROPOPTIONS_REQUIRED;
    rgIDBProps[1].colid         = DB_NULLID;

//User name (login).
    rgIDBProps[2].dwPropertyID  = DBPROP_AUTH_USERID;
    rgIDBProps[2].vValue.vt     = VT_BSTR;
    rgIDBProps[2].vValue.bstrVal= SysAllocString(L"sa");
    rgIDBProps[2].dwOptions     = DBPROPOPTIONS_REQUIRED;
    rgIDBProps[2].colid         = DB_NULLID;

//Password.
//    rgIDBProps[3].dwPropertyID  = DBPROP_AUTH_PASSWORD;
//    rgIDBProps[3].vValue.vt     = VT_BSTR;
//    rgIDBProps[3].vValue.bstrVal= SysAllocString(L"password");
//    rgIDBProps[3].dwOptions     = DBPROPOPTIONS_REQUIRED;
//    rgIDBProps[3].colid         = DB_NULLID;

    /*
    Now that the properties are set, construct the DBPROPSET structure
    (rgInitPropSet). The DBPROPSET structure is used to pass an array
    of DBPROP structures (rgIDBProps) to the SetProperties method.
    */
    rgIDBPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
//  rgInitPropSet[0].cProperties    = 4;
    rgIDBPropSet[0].cProperties    = 3;
    rgIDBPropSet[0].rgProperties   = rgIDBProps;

    //Set initialization properties.
    if (FAILED(hr = pIDBInitialize->QueryInterface(IID_IDBProperties,
                                   (void **)&pIDBProperties)))
    {
        cout << "Failed to get IDBProperties interface.\n";
        goto Cleanup;
    }

    if (FAILED(hr = pIDBProperties->SetProperties(1, rgIDBPropSet)))
    {
        cout << "Failed to set initialization properties.\n";
        goto Cleanup;
    } //end if

    //Now establish the connection to the data source.
    if(FAILED(hr = pIDBInitialize->Initialize()))
    {
        cout << "Problem in establishing connection to the data source.\n";
        goto Cleanup;
    }

    *ppIDBInitialize = pIDBInitialize;

Cleanup:
    for(ii = 0; ii < 4; ii++)
        VariantClear(&rgIDBProps[ii].vValue);

    if (pIDBProperties)
        pIDBProperties->Release();
    return hr;
} //End of InitializeAndEstablishConnection.

HRESULT SetCommandProperties(ICommand * pICommand)
{
    HRESULT     hr = S_OK;
    DBPROP      rgProps[1];
    DBPROPSET   rgPropSet[1];
    ICommandProperties* pICommandProperties = NULL;

    VariantInit(&rgProps[0].vValue);

    //Server name.
    rgProps[0].dwPropertyID  = SSPROP_STREAM_BASEPATH;
    rgProps[0].vValue.vt     = VT_BSTR;
    rgProps[0].vValue.bstrVal= SysAllocString(L"D:\\Test");
    rgProps[0].dwOptions     = DBPROPOPTIONS_REQUIRED;
    rgProps[0].colid         = DB_NULLID;

    /*
    Now that the properties are set, construct the DBPROPSET structure
    (rgInitPropSet). The DBPROPSET structure is used to pass an array
    of DBPROP structures (rgProps) to the SetProperties method.
    */
    rgPropSet[0].guidPropertySet = DBPROPSET_SQLSERVERSTREAM;
    rgPropSet[0].cProperties    = 1;
    rgPropSet[0].rgProperties   = rgProps;

    // Get an ICommandProperties interface.
    if(FAILED(pICommand->QueryInterface( IID_ICommandProperties, (void**) &pICommandProperties)))
    {
        cout << "Failed to get an ICommandProperties interface.\n";
        goto Cleanup;
    }

    //Set initialization properties.
    if(FAILED(hr = pICommandProperties->SetProperties(1, rgPropSet)))
    {
        cout << "Failed to set command properties.\n";
        goto Cleanup;
    }
Cleanup:
    VariantClear(&rgProps[0].vValue);
    if (pICommandProperties)
        pICommandProperties->Release();
    return hr;
}

//--------------------------------------------------------------------
//Retrieve and display data resulting from a query.
HRESULT ProcessResultSet(ISequentialStream * pStreamOutput)
{
    CHAR    szBuf[1000];
    ULONG   ulNumRead;
    HRESULT hr;

    if( pStreamOutput == NULL )
        return E_INVALIDARG;

    // Read from the stream
    ZeroMemory( szBuf, 1000 );
    while( ( hr = pStreamOutput->Read( szBuf, 1000, &ulNumRead ) ) == S_OK )
    {
        cout << szBuf;
        cout.flush();
    }
    return hr;
} //ProcessResultSet.


ODBC

若要使用 Microsoft® SQL Server™ 2000 ODBC 驱动程序，首先必须能够创建 ODBC 数据源，并确保该服务器所使用的目录存储过程的版本正确。若要对使用 SQL Server 的 ODBC 应用程序进行编码，必须知道如何分配 ODBC 句柄、设置特性、与 SQL Server 实例连接、执行查询以及处理结果。


配置 SQL Server ODBC 驱动程序 (ODBC)

在使用 Microsoft® SQL Server™ 2000 的 ODBC 应用程序之前，必须知道如何升级 SQL Server 早期版本中的目录存储过程的版本，以及如何添加、删除和测试数据源。


如何添加数据源 (ODBC)

可通过使用 ODBC 管理器、编程方式（使用 SQLConfigDataSource）或创建文件的方法添加数据源。

使用 ODBC 管理器添加数据源

  1. 在"开始"菜单中指向"设置"子菜单，然后单击"控制面板"命令。

  2. 双击"ODBC"。

  3. 单击"用户 DSN"、"系统 DSN"或"文件 DSN"选项卡，然后单击"添加"按钮。

  4. 单击 SQL Server，然后单击"完成"按钮。

  5. 完成向 SQL Server 新建数据源向导中的步骤。

编程方式添加数据源

  • 调用 SQLConfigDataSource，调用时将 fOption 设置为 ODBC_ADD_DSN 或 ODBC_ADD_SYS_DSN。

添加文件数据源

  • 调用 SQLDriverConnect，调用时连接字符串中带参数 SAVEFILE=file_name。如果该连接成功，ODBC 驱动程序将在 SAVEFILE 参数所指向的位置创建带连接参数的文件数据源。
示例
A. 使用 SQLConfigDataSource 创建数据源
#include <stdio.h>
#include <windows.h>
#include "sql.h"
#include <odbcinst.h>

int main()
{
RETCODE retcode;

UCHAR   *szDriver = "SQL Server";
UCHAR   *szAttributes =
"DSN=MyDSN\0DESCRIPTION=SQLConfigDSN Sample\0"
"SERVER=MySQL\0ADDRESS=MyServer\0NETWORK=dbmssocn\0"
"DATABASE=pubs\0";

retcode = SQLConfigDataSource(NULL,
                       ODBC_ADD_DSN,
                       szDriver,
                       szAttributes);
B. 创建文件数据源

在 SQLDriverConnect 中使用 SAVEFILE 关键字创建文件数据源，然后使用 SQLDriverConnect 与该文件数据源进行连接。这是删除错误处理后的简化示例。

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

#define MAXBUFLEN   255

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;

int main() {

   RETCODE      retcode;

   // This format of the SAVEFILE keyword saves a successful
   // connection as the file Myfiledsn.dsn in the ODBC default
   // directory for file DSNs.
   SQLCHAR      szConnStrIn[MAXBUFLEN] =
            "SAVEFILE=MyFileDSN;DRIVER={SQL Server};SERVER=MySQL;"
            "NETWORK=dbmssocn;UID=sa;PWD=MyPassWord;";

   SQLCHAR      szConnStrOut[MAXBUFLEN];
   SQLSMALLINT   cbConnStrOut = 0;

    // Allocate the ODBC Environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);

   //Notify ODBC that this is an ODBC 3.0 application.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);

   // Allocate an ODBC connection handle and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLDriverConnect(hdbc1,      // Connection handle
                     NULL,         // Window handle
                     szConnStrIn,      // Input connect string
                     SQL_NTS,         // Null-terminated string
                     szConnStrOut,   // Addr of output buffer
                     MAXBUFLEN,      // Size of output buffer
                     &cbConnStrOut,   // Address of output length
                     SQL_DRIVER_NOPROMPT);

   // Disconnect, set up a new connect string, and then test file DSN.
   SQLDisconnect(hdbc1);
   strcpy(szConnStrIn, "FILEDSN=MyFileDSN;UID=sa;PWD=MyPassWord;");
   retcode = SQLDriverConnect(hdbc1,      // Connection handle
                     NULL,         // Window handle
                     szConnStrIn,      // Input connect string
                     SQL_NTS,         // Null-terminated string
                     szConnStrOut,   // Addr of output buffer
                     MAXBUFLEN,      // Size of output buffer
                     &cbConnStrOut,   // Address of output length
                     SQL_DRIVER_NOPROMPT);

   /* Clean up. */
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

请参见

添加或删除 ODBC 数据源


如何删除数据源 (ODBC)

可通过使用 ODBC 管理器、编程方式（使用 SQLConfigDataSource）或删除文件来删除数据源。

使用 ODBC 管理器删除数据源

  1. 在"开始"菜单中指向"设置"子菜单，然后单击"控制面板"命令。

  2. 双击"32 位 ODBC"。

  3. 单击"用户 DSN"、"系统 DSN"或"文件 DSN"选项卡。

  4. 单击要删除的数据源。

  5. 单击"删除"按钮并确认删除。

编程方式删除用户或系统数据源

  • 调用 SQLConfigDataSource，调用时将 fOption 参数设置为 ODBC_REMOVE_DSN 或 ODBC_REMOVE_SYS_DSN。

删除文件数据源

  1. 在"开始"菜单中指向"设置"子菜单，然后单击"控制面板"命令。

  2. 双击"32 位 ODBC"。

  3. 单击"文件 DSN"。

  4. 单击要删除的文件 DSN。

  5. 单击"删除"按钮。
示例

此示例展示使用 SQLConfigDataSource 删除数据源。已经通过删除错误检查对其进行了简化。

#include <stdio.h>
#include <windows.h>
#include "sql.h"
#include <odbcinst.h>

int main() {

RETCODE retcode;

UCHAR   *szDriver = "SQL Server";
UCHAR   *szAttributes = "DSN=MyFileDSN";

retcode = SQLConfigDataSource(NULL,
                       ODBC_REMOVE_DSN,
                       szDriver,
                       szAttributes);
}

请参见

删除数据源


如何升级目录存储过程

只有在下列情况下才需要此过程：

  • 对 SQL Server 早期版本运行新的 Microsoft® SQL Server™ 2000 ODBC 驱动程序时。

  • 对 SQL Server 早期版本运行新的 SQL Server OLE DB 提供程序时。

  • 在新版本的 SQL Server 中的 sp_addlinkedserver、OPENROWSET 或 OPENQUERY 语句中引用 SQL Server 的早期版本时。这些语句使用 SQL Server OLE DB 提供程序访问目标 SQL Server。

若要确保 SQL Server OLE DB 提供程序或 SQL Server ODBC 驱动程序的正确操作，请务必使用 SQL Server 新版本自带的Instcat.sql 脚本来升级 SQL Server 早期版本中的目录存储过程。例如，对 SQL Server 6.5 运行 SQL Server 7.0 版的 ODBC 驱动程序时，必须对 SQL Server 6.5 运行 SQL Server 7.0 版的 Instcat.sql。

升级目录存储过程

若要升级目录存储过程，系统管理员应使用 isql 实用工具运行脚本。若要运行 isql，必须将该计算机安装成 SQL Server 的客户工作站。系统管理员应在运行 Instcat.sql 前备份 master 数据库。

在命令提示符处，使用 isql 实用工具运行 Instcat.sql 脚本。例如：

C:>ISQL -Usa -P sa_password -S server_name -i location\Instcat.sql

参数

sa_password

是系统管理员的密码。

server_name

是 SQL Server 所驻留的服务器名称。

location

是 Instcat.sql 位置的完整路径。可以从已安装的 SQL Server（默认位置为 C:\Mssql7\Install）或是从 SQL Server 光盘（默认位置为 D:\platform，其中 D: 为 CD-ROM 驱动器号，platform 是相应的服务器平台目录，比如 386）中使用 Instcat.sql。

Instcat.sql 脚本可生成许多消息。多数消息表示该脚本所发出的 Transact-SQL 语句对行的影响。这些消息可以忽略，尽管应对那些表示执行错误的消息输出进行扫描。对 SQL Server 6.0 版运行 Instcat.sql 时，可以忽略所生成的有关对象 sp_MS_upd_sysobj_category 不存在的消息。最后一条消息应表示 Instcat.sql 已成功完成。

当 master 数据库中没有足够的可用空间以存储目录存储过程或记录对现有过程所做的更改时，Instcat.sql 脚本将失败。如果 Instcat.sql 脚本失败，请与系统管理员联系。

请参见

升级目录存储过程


与 SQL Server (ODBC) 连接

初始化 ODBC 应用程序包括分配环境和连接句柄，设置句柄特性以适应驱动程序和服务器的行为，然后与 Microsoft® SQL Server™ 2000 连接。


如何分配句柄并与 SQL Server (ODBC) 连接

分配句柄并与 SQL Server 连接

  1. 加入 ODBC 头文件 Sql.h、Sqlext.h 和 Sqltypes.h。

  2. 加入 Microsoft® SQL Server™ 2000 驱动程序专用的头文件 Odbcss.h。

  3. 调用 SQLAllocHandle，调用时将 HandleType 设置为 SQL_HANDLE_ENV 以初始化 ODBC 并分配环境句柄。

  4. 调用 SQLSetEnvAttr，调用时将 Attribute 设置为 SQL_ATTR_ODBC_VERSION 并将 ValuePtr 设置为 SQL_OV_ODBC3，以表明该应用程序将使用 ODBC 3.x 格式的函数调用。

  5. 可以调用 SQLSetEnvAttr 设置其它环境选项或调用 SQLGetEnvAttr 获得环境选项（可选）。

  6. 调用 SQLAllocHandle，调用时将 HandleType 设置为 SQL_HANDLE_DBC 以分配连接句柄。

  7. 调用 SQLSetConnectAttr 设置连接选项或调用 SQLSetConnectAttr 获得连接选项（可选）。

  8. 调用 SQLConnect 使用现有数据源与 SQL Server 连接。

    或

    调用 SQLDriverConnect 使用连接字符串与 SQL Server 连接。

    SQL Server 最小的完整连接字符串应具有下列两种形式之一：

    DSN=dsn_name;UID=login_id;PWD=password;

    DRIVER={SQL Server};SERVER=server;UID=login_id;PWD=password;

    如果连接字符串不完整，SQLDriverConnect 可提示所需信息。这由为 DriverCompletion 参数指定的值控制。

    或

    以迭代方式多次调用 SQLBrowseConnect 以生成连接字符串并与 SQL Server 连接。

  9. 调用 SQLGetInfo 获得驱动程序特性和 SQL Server 数据源的行为（可选）。

  10. 分配和使用语句。

  11. 调用 SQLDisconnect 与 SQL Server 断开，使该连接句柄可用于新连接。

  12. 调用 SQLFreeHandle，调用时将 HandleType 设置为 SQL_HANDLE_DBC 以释放该连接句柄。

  13. 调用 SQLFreeHandle，调用时将 HandleType 设置为 SQL_HANDLE_ENV 以释放该环境句柄。
示例
A. 分配句柄，然后使用 SQLConnect 进行连接

此示例显示分配一个环境句柄和一个连接句柄，然后再使用 SQLConnect 进行连接的情况。已经通过删除许多错误检查对其进行了简化。

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <odbcss.h>

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;

int main() {
   RETCODE retcode;
   UCHAR   szDSN[SQL_MAX_DSN_LENGTH+1] = "MyDSN",
         szUID[MAXNAME] = "sa",
         szAuthStr[MAXNAME] = "MyPassword";

    // Allocate the ODBC Environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);

   // Notify ODBC that this is an ODBC 3.0 application.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER)SQL_OV_ODBC3,
                     SQL_IS_INTEGER);

   // Allocate an ODBC connection handle and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLConnect(hdbc1, szDSN, (SWORD)strlen(szDSN),
                  szUID, (SWORD)strlen(szUID),
                  szAuthStr, (SWORD)strlen(szAuthStr));
   if ( (retcode != SQL_SUCCESS) &&
      (retcode != SQL_SUCCESS_WITH_INFO) ) {
         // Connect failed, call SQLGetDiagRec for errors.
   }
   else {
      // Connects to SQL Server always return
      // informational messages.  These messages can be
      // retrieved by calling SQLGetDiagRec.
   }

   // Allocate statement handles and do ODBC processing.

   /* Clean up. */
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}
B. 与 SQL Server 连接而不使用现有的 ODBC 数据源

此示例显示在不需要现有 ODBC 数据源的情况下调用 SQLDriverConnect 与 SQL Server 实例连接：

#define MAXBUFLEN   255

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;

SQLCHAR      ConnStrIn[MAXBUFLEN] =
         "DRIVER={SQL Server};SERVER=MyServer;"
         "UID=sa;PWD=MyPassWord;DATABASE=pubs;";

SQLCHAR      ConnStrOut[MAXBUFLEN];
SQLSMALLINT   cbConnStrOut = 0;

// Make connection without data source. Ask that driver not
// prompt if insufficient information. Driver returns
// SQL_ERROR and application prompts user
// for missing information. Window handle not needed for
// SQL_DRIVER_NOPROMPT.
retcode = SQLDriverConnect(hdbc1,      // Connection handle
                  NULL,         // Window handle
                  ConnStrIn,      // Input connect string
                  SQL_NTS,         // Null-terminated string
                  ConnStrOut,      // Address of output buffer
                  MAXBUFLEN,      // Size of output buffer
                  &cbConnStrOut,   // Address of output length
                  SQL_DRIVER_NOPROMPT);

请参见

SQLFreeHandle

SQLGetInfo

SQLBrowseConnect

SQLSetConnectAttr

SQLDriverConnect

SQLSetEnvAttr

SQLGetConnectAttr


执行查询 (ODBC)

在 ODBC 应用程序中执行 SQL 语句需要分配语句句柄、设置语句特性以及准备和执行该 SQL 语句。


如何使用语句 (ODBC)

使用语句

  1. 调用 SQLAllocHandle，调用时将 HandleType 设置为 SQL_HANDLE_STMT 以分配语句句柄。

  2. 调用 SQLSetStmtAttr 设置语句选项或调用 SQLGetStmtAttr 获得语句特性（可选）。

    若要使用服务器游标，必须将游标特性设置为其默认值以外的值。

  3. 如果要多次执行该语句，也可以用 SQLPrepare 准备要执行的语句（可选）。

  4. 如果该语句已绑定参数标记，也可以用 SQLBindParameter 将这些参数标记绑定到程序变量中（可选）。如果已准备好该语句，则可以调用 SQLNumParams 和 SQLDescribeParam 查找参数个数和参数特征。

  5. 使用 SQLExecDirect 直接执行语句。

    或

    如果已准备好语句，则可用 SQLExecute 多次执行该语句。

    或

    调用返回结果的目录函数。

  6. 处理这些结果的方法有：将结果集列绑定到程序变量，使用 SQLGetData 将数据从结果集列移至程序变量或者这两种方法的组合。

    每次在语句的结果集内提取一行。

    或

    使用块状光标，每次在该结果集内提取多行。

    或

    调用 SQLRowCount 以确定受 INSERT、UPDATE 或 DELETE 语句影响的行数。

    如果该 SQL 语句可以有多个结果集，则在每个结果集的结尾调用 SQLMoreResults 以查看是否有其它要处理的结果集。

  7. 处理完结果后，可能需要下列操作才能使得该语句句柄在执行新语句时可用：
    • 如果在返回 SQL_NO_DATA 前未调用 SQLMoreResults，请调用 SQLCloseCursor 关闭该游标。

    • 如果已将参数标记绑定到程序变量，请在调用 SQLFreeStmt 时将 Option 设置为 SQL_RESET_PARAMS 以释放绑定参数。

    • 如果已将结果集列绑定到程序变量，请在调用 SQLFreeStmt 时将 Option 设置为 SQL_UNBIND 以释放绑定列。

    • 若要再次使用该语句句柄，请转到步骤 2。
  8. 调用 SQLFreeHandle，调用时将 HandleType 设置为 SQL_HANDLE_STMT 以释放该语句句柄。

请参见

分配语句句柄

构造 SQL 语句

直接执行

释放语句句柄

已准备的执行

SQLBindParameter

SQLDescribeParam

SQLFreeHandle

SQLGetData

SQLGetStmtAttr

SQLMoreResults

SQLRowCount

SQLSetStmtAttr


如何设置游标选项 (ODBC)

设置游标选项

  • 调用 SQLSetStmtAttr 设置控制游标行为的语句选项，或调用 SQLGetStmtAttr 获得控制游标行为的语句选项。
    Foption | 指定
    SQL_ATTR_CURSOR_TYPE | 只进、静态、动态或键集驱动游标类型
    SQL_ATTR_CONCURRENCY | 只读、锁定、乐观使用时间戳或乐观使用值并发控制选项
    SQL_ATTR_ROW_ARRAY_SIZE | 每次提取所检索的行数
    SQL_ATTR_CURSOR_SENSITIVITY | 游标显示或不显示其它连接对游标行所做的更新
    SQL_ATTR_CURSOR_SCROLLABLE | 游标可以向前和向后滚动

    这些特性的默认值（只进、只读、行集大小为 1）不使用服务器游标。若要使用服务器游标，则必须将这些特性中的至少一个特性设置为默认值之外的值，而且所执行的语句必须是单个 SELECT 语句，或者是包含单个 SELECT 语句的存储过程。使用服务器游标时，SELECT 语句无法使用服务器游标不支持的子句：COMPUTE、COMPUTE BY、FOR BROWSE 和 INTO。

    通过设置 SQL_ATTR_CURSOR_TYPE 和 SQL_ATTR_CONCURRENCY，或设置 SQL_ATTR_CURSOR_SENSITIVITY 和 SQL_ATTR_CURSOR_SCROLLABLE，可以控制所用游标的类型。不应将这两种指定游标行为的方法混合起来。

示例
A. 分配语句句柄，用行版本控制乐观并发设置动态游标类型，然后执行 SELECT
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
retcode = SQLSetStmtAttr(hstmt1, SQL_ATTR_CURSOR_TYPE,
                  (SQLPOINTER)SQL_CURSOR_DYNAMIC,
                  SQL_IS_INTEGER);
retcode = SQLSetStmtAttr(hstmt1, SQL_ATTR_CONCURRENCY,
                  (SQLPOINTER)SQL_CONCUR_ROWVER,
                  SQL_IS_INTEGER);
retcode = SQLExecDirect(hstmt1,
                  "SELECT au_lname FROM authors",
                  SQL_NTS);
B. 分配语句句柄，设置可滚动、感知游标，然后执行 SELECT
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
// Set the cursor options and execute the statement.
retcode = SQLSetStmtAttr(hstmt1, SQL_ATTR_CURSOR_SCROLLABLE,
                  (SQLPOINTER)SQL_SCROLLABLE,
                  SQL_IS_INTEGER);
retcode = SQLSetStmtAttr(hstmt1, SQL_ATTR_CURSOR_SENSITIVITY,
                  (SQLPOINTER)SQL_INSENSITIVE,
                  SQL_IS_INTEGER);
retcode = SQLExecDirect(hstmt1,
                  "select au_lname from authors",
                  SQL_NTS);

请参见

为游标构造 SQL 语句

SQLGetStmtAttr

SQLSetStmtAttr


如何直接执行语句 (ODBC)

一次性直接执行语句

  1. 如果该语句有参数标记，则使用 SQLBindParameter 将每个参数绑定到程序变量。用数据值填充程序变量，然后设置所有执行中的数据参数。

  2. 调用 SQLExecDirect 执行语句。

  3. 如果使用了执行中的数据输入参数，SQLExecDirect 将返回 SQL_NEED_DATA。用 SQLParamData 和 SQLPutData 发送数据块。

使用专用于列的参数绑定多次执行语句

  1. 调用 SQLSetStmtAttr 设置以下特性：
    • 将 SQL_ATTR_PARAMSET_SIZE 设置为参数集的个数 (S)。

    • 将 SQL_ATTR_PARAM_BIND_TYPE 设置为 SQL_PARAMETER_BIND_BY_COLUMN。

    • 将 SQL_ATTR_PARAMS_PROCESSED_PTR 特性设置为指向 SQLUINTEGER 变量以保存已处理参数的数目。

    • 将 SQL_ATTR_PARAMS_STATUS_PTR 设置为指向 SQLUSSMALLINT 变量的数组 [S]，以保存参数状态指示符。
  2. 对于每个参数标记：
    • 分配 S 参数数组缓冲区以存储数据值。

    • 分配 S 参数数组缓冲区以存储数据长度。

    • 调用 SQLBindParameter 以将参数数据值数组和数据长度数组绑定到该语句参数。

    • 设置所有执行中的数据 text 或 image 参数。

    • 将 S 数据值和 S 数据长度放入绑定参数数组。
  3. 调用 SQLExecDirect 执行语句。驱动程序将有效执行该语句 S 次，对于每个参数集执行一次。

  4. 如果使用了执行中的数据输入参数，SQLExecDirect 将返回 SQL_NEED_DATA。用 SQLParamData 和 SQLPutData 发送数据块。

使用专用于行的参数绑定多次执行语句

  1. 分配一个结构数组 [S]，其中 S 是参数集的个数。此结构中每个参数有一个元素，每个元素有两部分：
    • 第一部分是一个可保存参数数据的相应数据类型的变量。

    • 第二部分是一个可保存状态指示符的 SQLINTEGER 变量。
  2. 调用 SQLSetStmtAttr 设置以下特性：
    • 将 SQL_ATTR_PARAMSET_SIZE 设置为参数集的个数 (S)。

    • 将 SQL_ATTR_PARAM_BIND_TYPE 设置为在步骤 1 中分配的结构大小。

    • 将 SQL_ATTR_PARAMS_PROCESSED_PTR 特性设置为指向 SQLUINTEGER 变量以保存已处理参数的数目。

    • 将 SQL_ATTR_PARAMS_STATUS_PTR 设置为指向 SQLUSSMALLINT 变量的数组 [S]，以保存参数状态指示符。
  3. 对于每个参数标记，调用 SQLBindParameter 以将参数的数据值和数据长度指针指向它们在步骤 1 中分配的结构数组第一个元素中的变量。如果该参数是执行中的数据参数，请对其进行设置。

  4. 用数据值填充绑定参数缓冲区数组。

  5. 调用 SQLExecDirect 执行语句。驱动程序将有效执行该语句 S 次，对于每个参数集执行一次。

  6. 如果使用了执行中的数据输入参数，SQLExecDirect 将返回 SQL_NEED_DATA。用 SQLParamData 和 SQLPutData 发送数据块。

通常，专用于列的绑定和专用于行的绑定较多与 SQLPrepare 和 SQLExecute 一起使用,而不与 SQLExecDirect 一起使用。

示例

此示例显示使用 SQLExecDirect 执行 SELECT 语句的情况。已经通过删除所有的错误检查对其进行了简化。

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

#define MAXBUFLEN   255

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;

int main()
{
   RETCODE retcode;
   // SQLBindCol variables
   SQLCHAR      szName[MAXNAME+1];
   SQLINTEGER   cbName;

    // Allocate the ODBC Environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 application.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   // Allocate an ODBC connection and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLConnect(hdbc1,
            "MyDSN", SQL_NTS,   "sa", SQL_NTS,
            "MyPassWord", SQL_NTS);

   // Allocate a statement handle.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);

   // Execute an SQL statement directly on the statement handle.
   // Uses a default result set because no cursor attributes are set.
   retcode = SQLExecDirect(hstmt1,
                     "SELECT au_lname FROM authors",
                     SQL_NTS);
   // Simplified result set processing. Bind one column and
   // then fetch until SQL_NO_DATA.
   retcode = SQLBindCol(hstmt1, 1, SQL_C_CHAR,
                  szName, MAXNAME, &cbName);
   while ( (retcode = SQLFetch(hstmt1) ) != SQL_NO_DATA )
      printf("Name = %s\n", szName);

   /* Clean up. */
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

请参见

绑定参数

直接执行

SQLBindParameter

SQLPutData

SQLSetStmtAttr

使用语句参数


如何准备和执行语句 (ODBC)

准备一次语句，然后多次执行该语句

  1. 调用 SQLPrepare 准备语句。

  2. 调用 SQLNumParams 确定已准备语句中的参数数目（可选）。

  3. 对于已准备语句中的每个参数（可选）：
    • 调用 SQLDescribeParam 获得参数信息。

    • 使用 SQLBindParam 将每个参数绑定到程序变量。设置所有执行中的数据参数。
  4. 对于每个已准备语句的执行：
    • 如果该语句有参数标记，则将数据值放入绑定参数缓冲区。

    • 调用 SQLExecute 执行已准备的语句。

    • 如果使用了执行中的数据输入参数，SQLExecute 将返回 SQL_NEED_DATA。用 SQLParamData 和 SQLPutData 发送数据块。

用专用于列的参数绑定准备语句

  1. 调用 SQLSetStmtAttr 设置以下特性：
    • 将 SQL_ATTR_PARAMSET_SIZE 设置为参数集的个数 (S)。

    • 将 SQL_ATTR_PARAM_BIND_TYPE 设置为 SQL_PARAMETER_BIND_BY_COLUMN。

    • 将 SQL_ATTR_PARAMS_PROCESSED_PTR 特性设置为指向 SQLUINTEGER 变量以保存已处理参数的数目。

    • 将 SQL_ATTR_PARAMS_STATUS_PTR 设置为指向 SQLUSSMALLINT 变量的数组 [S]，以保存参数状态指示符。
  2. 调用 SQLPrepare 准备语句。

  3. 调用 SQLNumParams 确定已准备语句中的参数数目（可选）。

  4. 对于已准备语句中的每个参数，调用 SQLDescribeParam 获得参数信息（可选）。

  5. 对于每个参数标记：
    • 分配 S 参数数组缓冲区以存储数据值。

    • 分配 S 参数数组缓冲区以存储数据长度。

    • 调用 SQLBindParameter 以将参数数据值数组和数据长度数组绑定到该语句参数。

    • 如果该参数为执行中的数据 text 或 image 参数，则对其进行设置。

    • 如果使用了任何执行中的数据参数，则对它们进行设置。
  6. 对于每个已准备语句的执行：
    • 将 S 数据值和 S 数据长度放入绑定参数数组。

    • 调用 SQLExecute 执行已准备的语句。

    • 如果使用了执行中的数据输入参数，SQLExecute 将返回 SQL_NEED_DATA。用 SQLParamData 和 SQLPutData 发送数据块。

用专用于行的绑定参数准备语句

  1. 分配一个结构数组 [S]，其中 S 是参数集的个数。此结构中每个参数有一个元素，每个元素有两部分：
    • 第一部分是一个可保存参数数据的相应数据类型的变量。

    • 第二部分是一个可保存状态指示符的 SQLINTEGER 变量。
  2. 调用 SQLSetStmtAttr 设置以下特性：
    • 将 SQL_ATTR_PARAMSET_SIZE 设置为参数集的个数 (S)。

    • 将 SQL_ATTR_PARAM_BIND_TYPE 设置为在步骤 1 中分配的结构大小。

    • 将 SQL_ATTR_PARAMS_PROCESSED_PTR 特性设置为指向 SQLUINTEGER 变量以保存已处理参数的数目。

    • 将 SQL_ATTR_PARAMS_STATUS_PTR 设置为指向 SQLUSSMALLINT 变量的数组 [S]，以保存参数状态指示符。
  3. 调用 SQLPrepare 准备语句。

  4. 对于每个参数标记，调用 SQLBindParameter 以将参数的数据值和数据长度指针指向它们在步骤 1 中分配的结构数组第一个元素中的变量。如果该参数是执行中的数据参数，请对其进行设置。

  5. 对于每个已准备语句的执行：
    • 用数据值填充绑定参数缓冲区数组。

    • 调用 SQLExecute 执行已准备的语句。驱动程序将有效执行 SQL 语句 S 次，对于每个参数集执行一次。

    • 如果使用了执行中的数据输入参数，SQLExecute 将返回 SQL_NEED_DATA。用 SQLParamData 和 SQLPutData 发送数据块。
示例

此示例显示使用 SQLPrepare 和 SQLExecute 执行 SELECT 语句的情况。已经通过删除所有的错误检查对其进行了简化。

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

#define MAXBUFLEN   255

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT   hstmt1 = SQL_NULL_HSTMT;

int main()
{
   RETCODE retcode;
   // SQLBindCol variables
   SQLCHAR      szName[MAXNAME+1];
   SQLINTEGER   cbName;

    // Allocate the ODBC Environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 application.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   // Allocate an ODBC connection and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLConnect(hdbc1,
            "MyDSN", SQL_NTS,   "sa", SQL_NTS,
            "MyPassWord", SQL_NTS);

   // Allocate a statement handle.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
   // Prepare and execute an SQL statement on the statement handle.
   // Uses a default result set because no cursor attributes are set.
   retcode = SQLPrepare(hstmt1,
                  "SELECT au_lname from authors", SQL_NTS);
   retcode = SQLExecute(hstmt1);
   // Simplified result set processing. Bind one column and
   // then fetch until SQL_NO_DATA.
   retcode = SQLBindCol(hstmt1, 1, SQL_C_CHAR,
                  szName, MAXNAME, &cbName);
   while ( ( retcode = SQLFetch(hstmt1) ) != SQL_NO_DATA )
      printf("Name = %s\n", szName);

   /* Clean up. */
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

请参见

绑定参数

SQLBindParameter

SQLDescribeParam

SQLPrepare

SQLPutData

SQLSetStmtAttr

已准备的执行

使用语句参数


处理结果 (ODBC)

在 ODBC 应用程序中处理结果包括要首先确定结果集特征，然后使用 SQLBindCol 或 SQLGetData 将数据检索到程序变量。


如何检索结果集信息 (ODBC)

获得有关结果集的信息

  1. 调用 SQLNumResultCols 获得该结果集内的列数。

  2. 对于该结果集内的每列：
    • 调用 SQLDescribeCol 获得有关该结果列的信息。

    或

    • 调用 SQLColAttribute 获得有关该结果列特定描述符的信息。

请参见

确定结果集的特征

如何处理结果 (ODBC)

SQLColAttribute

SQLDescribeCol

SQLNumResultCols


如何处理结果 (ODBC)

处理结果

  1. 检索结果集信息。

  2. 如果使用绑定列，则对于要绑定到的每一列，调用 SQLBindCol 将程序缓冲区绑定到该列。

  3. 对于该结果集内的每一行：
    • 调用 SQLFetch 获得下一行。

    • 如果使用绑定列，则使用目前在绑定列缓冲区中可用的数据。

    • 如果使用未绑定列，则一次或多次调用 SQLGetData 获得最后一个绑定列之后的未绑定列的数据。对 SQLGetData 的调用应按照列号递增的顺序进行。

    • 多次调用 SQLGetData 获得 text 列或 image 列中的数据。
  4. 通过返回 SQL_NO_DATA，SQLFetch 发出结果集结束的信号时，调用 SQLMoreResults 确定是否还有其它结果集可用。
    • 如果返回 SQL_SUCCESS，表明有另一个结果集可用。

    • 如果返回 SQL_NO_DATA，表明没有其它结果集可用。

    • 如果返回 SQL_SUCCESS_WITH_INFO 或 SQL_ERROR，则调用 SQLGetDiagRec 确定 PRINT 或 RAISERROR 语句的输出是否可用。

    如果绑定语句参数用于输出参数或存储过程的返回值，则使用目前在绑定参数缓冲区中可用的数据。同样，在使用绑定参数时，对 SQLExecute 或 SQLExecDirect 的每次调用都可能执行该 SQL 语句 S 次，其中 S 是绑定参数数组中的元素数。这意味着将有 S 个结果集要处理，其中每个结果集都包含通常执行单个 SQL 语句所返回的所有的结果集、输出参数和返回代码。

    注意，当结果集包含计算行时，每个计算行都可作为单独的结果集使用。这些计算结果集分散在普通行内，并将普通行断开到多个结果集内。

  5. 调用 SQLFreeStmt 时将 fOption 设置为 SQL_UNBIND 以释放所有绑定列的缓冲区（可选）。

  6. 如果有另一个可用的结果集，请转到步骤 1。

若要在 SQLFetch 返回 SQL_NO_DATA 前取消处理结果集，请调用 SQLCloseCursor。

示例

此示例显示如何使用 SQLBindCol 或 SQLGetData。已经通过删除所有的错误检查对其进行了简化。该程序可在注释掉 SQLBindCol 函数或 SQLGetData 函数的情况下进行编译，所得到的可执行文件将进行相同的操作。

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

#define MAXBUFLEN   255

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;

int main() {
   RETCODE retcode;
   // SQLBindCol variables
   SQLCHAR      szName[MAXNAME+1];
   SQLINTEGER   cbName;

    // Allocate the ODBC Environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 application.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   // Allocate an ODBC connection and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLConnect(hdbc1,
            "MyDSN", SQL_NTS,"sa", SQL_NTS, "MyPassWord", SQL_NTS);

   // Allocate a statement handle.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
   // Execute an SQL statement directly on the statement handle.
   // Uses a default result set because no cursor attributes are set.
   retcode = SQLExecDirect(hstmt1,
                     "SElECT au_lname FROM authors", SQL_NTS);

   // Simplified result set processing. Fetch until SQL_NO_DATA.
   // The application can be compiled with the SQLBindCol line
   // commented out to illustrate SQLGetData, or compiled with the
   // SQLGetData line commented out to illustrate SQLBindCol.
   // This sample shows that SQLBindCol is called once for the
   // result set, while SQLGetData must be called once for each
   // row in the result set.

   retcode = SQLBindCol(hstmt1, 1, SQL_C_CHAR,
                  szName, MAXNAME, &cbName);
   while ( (retcode = SQLFetch(hstmt1) ) != SQL_NO_DATA ) {
   //   SQLGetData(hstmt1, 1, SQL_C_CHAR, szName, MAXNAME, &cbName);
      printf("Name = %s\n", szName);
   }

   /* Clean up.*/
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);

   return(0);
}

请参见

分配存储（绑定）

确定结果集的特征

提取结果数据

如何检索结果集信息 (ODBC)

SQLBindCol

SQLCloseCursor

SQLFreeStmt

SQLGetData

SQLMoreResults


使用游标 (ODBC)

若要使用游标，则必须首先设置控制 ODBC 游标行为的连接特性和语句特性。游标允许应用程序在每次进行提取操作时检索多行，并在游标的当前位置执行 UPDATE、INSERT 或 DELETE 语句。


如何使用游标 (ODBC)

使用游标

  1. 调用 SQLSetStmtAttr 设置所需游标特性：

    设置 SQL_ATTR_CURSOR_TYPE 和 SQL_ATTR_CONCURRENCY 特性（这是首选选项）。

    或

    设置 SQL_CURSOR_SCROLLABLE 和 SQL_CURSOR_SENSITIVITY 特性。

  2. 使用 SQL_ATTR_ROW_ARRAY_SIZE 特性调用 SQLSetStmtAttr 以设置行集大小。

  3. 如果要使用 WHERE CURRENT OF 子句进行定位更新，则可调用 SQLSetCursorName 设置游标名称（可选）。

  4. 执行 SQL 语句。

  5. 如果要使用 WHERE CURRENT OF 子句进行定位更新，同时游标名称未在步骤 3 中通过 SQLSetCursorName 提供，则可调用 SQLGetCursorName 获得游标名称（可选）。

  6. 调用 SQLNumResultCols 以获得行集内的列数 (C)。

  7. 使用专用于列的绑定。

    或

    使用专用于行的绑定。

  8. 按照需要提取游标中的行集。

  9. 调用 SQLMoreResults 以确定是否还有其它结果集可用。
    • 如果返回 SQL_SUCCESS，表明有另一个结果集可用。

    • 如果返回 SQL_NO_DATA，表明没有其它结果集可用。

    • 如果返回 SQL_SUCCESS_WITH_INFO 或 SQL_ERROR，则调用 SQLGetDiagRec 确定 PRINT 或 RAISERROR 语句的输出是否可用。

    如果绑定语句参数用于输出参数或存储过程的返回值，则使用目前在绑定参数缓冲区中可用的数据。

    在使用绑定参数时，对 SQLExecute 或 SQLExecDirect 的每次调用都将执行该 SQL 语句 S 次，其中 S 是绑定参数数组中的元素数。这意味着将有 S 个结果集要处理，其中每个结果集都包含通常执行单个 SQL 语句所返回的所有的结果集、输出参数和返回代码。

    注意，当结果集包含计算行时，每个计算行都可作为单独的结果集使用。这些计算结果集分散在普通行内，并将普通行断开到多个结果集内。

  10. 调用 SQLFreeStmt 时将 fOption 设置为 SQL_UNBIND 以释放所有绑定列的缓冲区（可选）。

  11. 如果有另一个可用的结果集，请转到步骤 6。

在步骤 9 中，在部分处理过的结果集上调用 SQLMoreResults 将清除该结果集的剩余部分。清除已部分处理的结果集的另一个方法是调用 SQLCloseCursor。

通过设置 SQL_ATTR_CURSOR_TYPE 和 SQL_ATTR_CONCURRENCY，或设置 SQL_ATTR_CURSOR_SENSITIVITY 和 SQL_ATTR_CURSOR_SCROLLABLE，可以控制所用游标的类型。不应将这两种指定游标行为的方法混合起来。

请参见

游标的实现方式

如何使用行集绑定 (ODBC)

SQLFreeStmt

SQLGetCursorName

SQLMoreResults

SQLNumResultCols

SQLSetStmtAttr

使用默认结果集


如何使用行集绑定 (ODBC)

使用专用于列的绑定

  1. 对于每个绑定列
    • 分配一个（或多个）列缓冲区数组 R 以存储数据值，其中 R 是该行集内的行数。

    • 分配一个（或多个）列缓冲区数组 R 以存储数据长度（可选）。

    • 调用 SQLBindCol 将列的数据值数组和数据长度数组绑定到该行集的列中。
  2. 调用 SQLSetStmtAttr 设置以下特性：
    • 将 SQL_ATTR_ROW_ARRAY_SIZE 设置为该行集的行数 (R)。

    • 将 SQL_ATTR_ROW_BIND_TYPE 设置为 SQL_BIND_BY_COLUMN。

    • 将 SQL_ATTR_ROWS FETCHED_PTR 特性设置为指向 SQLUINTEGER 变量以保存所提取的行数。

    • 将 SQL_ATTR_ROW_STATUS_PTR 设置为指向 SQLUSSMALLINT 变量的数组 [R]，以保存行状态指示符。
  3. 执行语句。

  4. 对 SQLFetch 或 SQLFetchScroll 的每次调用都要检索 R 行，并将数据传输到绑定列。

使用专用于行的绑定

  1. 分配一个结构数组 [R]，其中 R 是该行集的行数。此结构中每列有一个元素，每个元素有两部分：
    • 第一部分是一个可保存列数据的相应数据类型的变量。

    • 第二部分是一个可保存列状态指示符的 SQLINTEGER 变量。
  2. 调用 SQLSetStmtAttr 设置以下特性：
    • 将 SQL_ATTR_ROW_ARRAY_SIZE 设置为该行集的行数 (R)。

    • 将 SQL_ATTR_ROW_BIND_TYPE 设置为在步骤 1 中分配的结构大小。

    • 将 SQL_ATTR_ROWS_FETCHED_PTR 特性设置为指向 SQLUINTEGER 变量以保存已提取行的数目。

    • 将 SQL_ATTR_PARAMS_STATUS_PTR 设置为指向 SQLUSSMALLINT 变量的数组 [R]，以保存行状态指示符。
  3. 对于该结果集内的每一列，调用 SQLBindCol 将列的数据值和数据长度指针指向其在步骤 1 中分配的结构数组的第一个元素中的变量。

  4. 执行语句。

  5. 对 SQLFetch 或 SQLFetchScroll 的每次调用都要检索 R 行，并将数据传输到绑定列。

请参见

游标的实现方式

如何使用游标 (ODBC)

SQLBindCol

SQLFetchScroll

SQLSetStmtAttr

使用默认结果集


如何提取和更新行集 (ODBC)

提取和更新行集

  1. 调用 SQLSetStmtAttr 时将 fOption 设置为 SQL_ROW_ARRAY_SIZE 以更改该行集内的行数 (R)（可选）。

  2. 调用 SQLFetch 或 SQLFetchScroll 获得行集。

  3. 如果使用绑定列，则使用目前在绑定列缓冲区中对该行集可用的数据值和数据长度。

    如果使用未绑定列，则对于每一行可在调用 SQLSetPos 时将 Operation 设置为 SQL_POSITION 以设置该游标的位置，然后对于每个未绑定列：

    • 一次或多次调用 SQLGetData 获得该行集最后一个绑定列之后的未绑定列的数据。对 SQLGetData 的调用应按照列号递增的顺序进行。

    • 多次调用 SQLGetData 获得 text 列或 image 列中的数据。
  4. 设置所有执行中的数据 text 列或 image 列。

  5. 调用 SQLSetPos 或 SQLBulkOperations 以设置游标位置，在行集内刷新、更新、删除或添加行。

    如果执行中的数据 text 列或 image 列用于更新或添加操作，则对这些列进行处理。

  6. 执行定位 UPDATE 或 DELETE 语句，指定游标名称（可从 SQLGetCursorName 中得到），在同一连接中使用不同的语句句柄（可选）。

请参见

制作行书签

使用定位操作更改行

滚动和检索行

SQLFetchScroll

SQLGetCursorName

SQLGetData

SQLSetStmtAttr


执行事务 (ODBC)

在 ODBC 中，事务无法跨越连接。ODBC 应用程序可使用标准 ODBC 事务管理功能处理单个连接中的事务。ODBC 应用程序还可以使用 Microsoft 分布式事务处理协调器 (MS DTC) 将多个 Microsoft® SQL Server™ 连接放在单个事务中，即使这些连接是连接到不同的服务器。


如何使用 Microsoft 分布式事务处理协调器 (ODBC)

使用 MS DTC 更新两个或多个 SQL Server

  1. 使用 MS DTC OLE DtcGetTransactionManager 函数与 MS DTC 连接。有关 MS DTC 的信息，请参阅 Microsoft 分布式事务处理协调器。

  2. 为每个需要建立的 Microsoft® SQL Server™ 连接调用一次 SQLDriverConnect。

  3. 调用 MS DTC OLE ITransactionDispenser::BeginTransaction 函数，开始 MS DTC 事务并获得代表该事务的事务对象。

  4. 对于每个要登记在 MS DTC 事务中的 ODBC 连接调用一次或多次 SQLSetConnectAttr。调用 SQLSetConnectAttr 时必须将 fOption 设置为 SQL_ATTR_ENLIST_IN_DTC 并使用该事务对象的 vParam（在步骤 3 中获得）。

  5. 为每个要更新的 SQL Server 调用一次 SQLExecDirect。

  6. 调用 MS DTC OLE ITransaction::Commit 函数提交该 MS DTC 事务。该事务对象将不再有效。

若要执行一系列 MS DTC 事务，请重复步骤 3 至步骤 6。

若要释放对该事务对象的引用，请调用 MS DTC OLE ITransaction::Return 函数。

若要将 ODBC 连接用于 MS DTC 事务，然后再将该连接用于本地 SQL Server 事务，请在调用 SQLSetConnectAttr 时将 vParam 设置为 SQL_DTC_DONE。

说明 也可以对每个 SQL Server 依次调用 SQLSetConnectAttr 和 SQLExecDirect，而不采用前面步骤 4 和步骤 5 中建议的方法。

请参见

执行分布式事务

SQLDriverConnect

SQLSetConnectAttr


运行存储过程 (ODBC)

Microsoft® SQL Server™ ODBC 驱动程序支持将存储过程作为远程存储过程执行。将存储过程作为远程存储过程执行使驱动程序和服务器得以优化存储过程的执行性能。


如何调用存储过程 (ODBC)

当 SQL 语句使用 ODBC CALL 转义子句调用存储过程时，Microsoft® SQL Server™ 驱动程序会使用远程存储过程调用 (RPC) 机制将此过程发送给 SQL Server。RPC 请求回避 SQL Server 中的许多语句分析和参数处理，因此比使用 Transact-SQL EXECUTE 语句的速度要快。

将过程作为 RPC 运行

  1. 构造一个使用 ODBC CALL 转义序列的 SQL 语句。该语句对每个输入、输入/输出和输出参数使用参数标记，对过程使用返回值（若有）：
    {? = CALL procname (?,?)}
  2. 对每个输入、输入/输出和输出参数调用 SQLBindParameter，对过程调用返回值（若有）。

  3. 用 SQLExecDirect 执行该语句。

说明 如果应用程序使用 Transact-SQL EXECUTE 语法（相对于 ODBC CALL 转义序列）提交过程，SQL Server ODBC 驱动程序将此过程调用（作为 SQL Server 语句而不是 RPC）传递给 SQL Server。而且，如果使用 Transact-SQL EXECUTE 语句，则不返回输出参数。

请参见

批处理存储过程调用

运行存储过程

调用存储过程

SQLBindParameter

过程


如何处理返回代码和输出参数 (ODBC)

Microsoft® SQL Server™ 存储过程可包含整型返回代码及输出参数。返回代码和输出参数在服务器发送的最后一个数据包中，在 SQLMoreResult 返回 SQL_NO_DATA 之前无法由应用程序使用。

处理返回代码和输出参数

  1. 构造一个使用 ODBC CALL 转义序列的 SQL 语句。该语句应对每个输入、输入/输出和输出参数使用参数标记，对过程使用返回值（若有）。

  2. 对每个输入、输入/输出和输出参数调用 SQLBindParameter，对过程调用返回值（若有）。

  3. 用 SQLExecDirect 执行该语句。

  4. 直到 SQLFetch 或 SQLFetchScroll 在处理最后的结果集时返回 SQL_NO_DATA 或直到 SQLMoreResults 返回 SQL_NO_DATA 时才处理结果集。此时，用返回的数据值填充与返回代码和输出参数绑定在一起的变量。
示例

本例说明对返回代码和输出参数的处理。为简化本示例，查错代码已删除。

// CREATE PROCEDURE TestParm @OutParm int OUTPUT AS
// SELECT au_lname FROM pubs.dbo.authors
// SELECT @OutParm = 88
// RETURN 99

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

#define MAXBUFLEN   255

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;

int main() {
   RETCODE retcode;
   // SQLBindParameter variables.
   SWORD   sParm1=0, sParm2=1;
   SDWORD   cbParm1=SQL_NTS, cbParm2=SQL_NTS;

    // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   // Allocate ODBC connection handle and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
                  "sa", SQL_NTS, "MyPassWord", SQL_NTS);

   // Allocate statement handle.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
   // Bind the return code to variable sParm1.
   retcode = SQLBindParameter(hstmt1,1,SQL_PARAM_OUTPUT,SQL_C_SSHORT,
         SQL_INTEGER,0,0,&sParm1,0,&cbParm1);
   // Bind the output parameter to variable sParm2.
   retcode = SQLBindParameter(hstmt1,2,SQL_PARAM_OUTPUT,SQL_C_SSHORT,
                        SQL_INTEGER,0,0,&sParm2,0,&cbParm2);
   // Execute the command.
   retcode = SQLExecDirect(hstmt1, "{? = call TestParm(?)}", SQL_NTS);

   // Show parameters are not filled.
   printf("Before result sets cleared: RetCode = %d, OutParm = %d.\n",
         sParm1, sParm2);

   // Clear any result sets generated.
   while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
      ;

   // Show parameters are now filled.
   printf("After result sets drained: RetCode = %d, OutParm = %d.\n",
         sParm1, sParm2);

   /* Clean up. */
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}


管理 text 和 image 列 (ODBC)

Microsoft® SQL Server™ ODBC 驱动程序支持使用 text 和 image 参数以及从结果集的 text、ntext 和 image 列中检索数据。


如何使用执行中的数据参数 (ODBC)

使用执行中的数据 text、ntext 或 image 参数

  1. 调用 SQLBindParameter 以将某个程序缓冲区与语句参数绑定在一起时：
    • 使用 SQL_LEN_DATA_AT_EXEC(length) 的 pcbValue，其中 length 是以字节为单位的 text、ntext 或 image 参数数据的总长度。

    • 使用程序定义参数标识符的 rgbValue。
  2. 调用 SQLExecDirect 或 SQLExecute 将返回 SQL_NEED_DATA，这表明执行中的数据参数已准备好进行处理。

  3. 对每个执行中的数据参数：
    • 调用 SQLParamData 以获得程序定义参数 ID。如果还有其它执行中的数据参数，将返回 SQL_NEED_DATA。

    • 一次或多次调用 SQLPutData 以发送参数数据，直到 length 全部送出。
  4. 调用 SQLParamData 以表明最后执行中的数据参数的所有数据已全部送出。不返回 SQL_NEED_DATA。
示例

本例说明使用 SQLPutData 在执行中的数据文本参数中填充数据的方法。为简化本示例，查错代码已删除。

// Sample ODBC3 console application to write SQL_LONGVARCHAR data
// using SQLPutData.
// Assumes DSN has table:
//  SQLSrvr: CREATE TABLE emp3 (NAME char(30), AGE int,
//           BIRTHDAY datetime, Memo1 text)

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

#define TEXTSIZE   12000

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;

int main() {
   RETCODE retcode;

   // SQLBindParameter variables.
   SDWORD      cbTextSize, lbytes;
   //SQLParamData variable.
   PTR         pParmID;
   //SQLPutData variables.
   UCHAR   Data[] =
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         "abcdefghijklmnopqrstuvwxyz";
   SDWORD   cbBatch = (SDWORD)sizeof(Data)-1;

    // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   // Allocate ODBC connection handle and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
                   "sa", SQL_NTS, "MyPassWord", SQL_NTS);

   // Allocate statement handle.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);

   // Set parameters based on total data to send.
   lbytes = (SDWORD)TEXTSIZE;
   cbTextSize = SQL_LEN_DATA_AT_EXEC(lbytes);
   // Bind the parameter marker.
   retcode = SQLBindParameter(hstmt1,   // hstmt
         1,                     // ipar
         SQL_PARAM_INPUT,            // fParamType
         SQL_C_CHAR,               // fCType
         SQL_LONGVARCHAR,            // FSqlType
         lbytes,                  // cbColDef
         0,                     // ibScale
         (VOID *)1,               // rgbValue
         0,                     // cbValueMax
         &cbTextSize);            // pcbValue

   // Execute the command.
   retcode = SQLExecDirect(hstmt1,
   "INSERT INTO emp3 VALUES('Paul Borm', 46,'1950-11-24 00:00:00', ?)",
                     SQL_NTS);
   // Check to see if NEED_DATA; if yes, use SQLPutData.
   retcode = SQLParamData(hstmt1, &pParmID);
   if (retcode == SQL_NEED_DATA)
   {
      while (lbytes > cbBatch)
      {
         SQLPutData(hstmt1, Data, cbBatch);
         lbytes -= cbBatch;
      }
      // Put final batch.
      SQLPutData(hstmt1, Data, lbytes);
   }
   else
   {
         ProcessErrorMessages(SQL_HANDLE_STMT, hstmt1,
                     "SQLPutData Failed\n\n");
         return(9);
   }

   // Make final SQLParamData call.
   retcode = SQLParamData(hstmt1, &pParmID);

   /* Clean up. */
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

请参见

绑定与未绑定的 text 和 image 列

SQLBindParameter

执行中的数据和 text、ntext 或 image 列

SQLPutData

管理 text 和 image 列


如何使用执行中的数据列 (ODBC)

使用执行中的数据 text、ntext 或 image 列

  1. 对每个执行中的数据列，在以前由 SQLBindCol 绑定的缓冲区中放入特殊值：
    • 在 pcbValue 数据值缓冲区中放入 SQL_LEN_DATA_AT_EXEC(length)，其中 length 是以字节为单位的 text、ntext 或 image 列数据的总长度。

    • 在 rgbValue 数据长度缓冲区中放入由程序定义的列标识符。
  2. 调用 SQLSetPos 返回 SQL_NEED_DATA，这表明执行中的数据列已准备好进行处理。

  3. 对每个执行中的数据列：
    • 调用 SQLParamData 以获得列数组指针。如果还有其它执行中的数据列，将返回 SQL_NEED_DATA。

    • 一次或多次调用 SQLPutData 以发送列数据，直到 length 全部送出。
  4. 调用 SQLParamData 以表明最后执行中的数据列的所有数据已全部发送。不返回 SQL_NEED_DATA。
示例

本例说明使用 SQLGetData 从执行中的数据 text 列中检索数据的方法。删除了查错代码以简化本示例。

// Sample ODBC3 console application to read SQL_LONGVARChar
// data using SQLGetData.
// Assumes DSN has table:
//  SQLSrvr: CREATE TABLE emp3 (NAME char(30), AGE int,
//           BIRTHDAY datetime, Memo1 text)

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

#define TEXTSIZE      12000
#define BUFFERSIZE   450

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;

int main() {
   RETCODE retcode;
   SWORD   cntr;

   //SQLGetData variables.
   UCHAR   Data[BUFFERSIZE];
   SDWORD   cbBatch = (SDWORD)sizeof(Data)-1;
   SDWORD   cbTxtSize;

   // Clear data array.
   for(cntr = 0; cntr < BUFFERSIZE; cntr++)
      Data[cntr] = 0x00;

    // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3,
                     SQL_IS_INTEGER);
   // Allocate ODBC connection handle and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
                   "sa", SQL_NTS, "MyPassWord, SQL_NTS);

   // Allocate statement handle; prepare, then execute command.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
   retcode = SQLExecDirect(hstmt1,
                     "SELECT Memo1 FROM emp3",
                     SQL_NTS);

   // Get first row.
   retcode = SQLFetch(hstmt1);
   // Get the SQL_LONG column.
   cntr = 1;
   do {
      retcode = SQLGetData(hstmt1,   // hstmt
         1,                  // ipar
         SQL_C_CHAR,            // fCType
         Data,               // rgbValue
         cbBatch,               // cbValueMax
         &cbTxtSize);            // pcbValue
      if ( retcode != SQL_NO_DATA ) {
      printf("GetData iteration %d, pcbValue = %d,\n",
            cntr++, cbTxtSize);
      printf("Data = %s\n\n", Data);
      }
   } while (retcode != SQL_NO_DATA);

   /* Clean up. */
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
} // End Main.

请参见

绑定与未绑定的 text 和 image 列

SQLBindCol

执行中的数据和 text/ntext/image 列

SQLPutData

管理 text 和 image 列


探查 ODBC 驱动程序性能 (ODBC)

Microsoft® SQL Server™ ODBC 驱动程序有两个驱动程序专用选项，以探查驱动程序的性能。

SQL Server ODBC 驱动程序可以在日志文件中记录性能统计信息。日志文件是一个用制表符分隔的文件，可以在任何支持用制表符分隔的文件的电子表格（如 Microsoft Excel）中进行分析。

该驱动程序还可以记录长时间运行的查询（即在指定的时间长度内未获得服务器响应的查询）。程序员和数据库管理员以后可以对这些查询进行分析。


如何探查驱动程序性能数据 (ODBC)

使用 ODBC Administrator 记录驱动程序性能数据

  1. 在"控制面板"上，双击"32 位 ODBC"菜单项。

  2. 单击"用户 DSN"、"系统 DSN"或"文件 DSN"选项卡。

  3. 单击要记录其性能的数据源。

  4. 单击"配置"按钮。

  5. 将 Microsoft SQL Server 配置 DSN 向导导航至带"将 ODBC 驱动程序统计记入日志文件"框的那一页。

  6. 选择"将 ODBC 驱动程序统计记入日志文件"框。在该框中，放入将记录统计的文件的名称。或者单击"浏览"按钮浏览文件系统中的统计日志。

通过编程记录驱动程序性能数据

  1. 调用 SQLSetConnectAttr，并将 fOption 设置为 SQL_COPT_SS_PERF_DATA_LOG，将 vParam 设置为性能数据日志文件的完整路径和文件名。例如：
    "C:\\Odbcperf.log"
  2. 调用 SQLSetConnectAttr，并将 fOption 设为 SQL_COPT_SS_PERF_DATA，将 vParam 设为 SQL_PERF_START 以开始记录性能数据。

  3. 或者调用 SQLSetConnectAttr，并将 fOption 设为 SQL_COPT_SS_LOG_NOW，将 vParam 设为 NULL，以将用制表符分隔的性能数据记录写入性能数据日志文件。这一调用可以在应用程序运行时执行多次。

  4. 调用 SQLSetConnectAttr，并将 fOption 设为 SQL_COPT_SS_PERF_DATA，将 vParam set 设为 SQL_PERF_STOP 以停止记录性能数据。

将驱动程序性能数据拉入某个应用程序

  1. 调用 SQLSetConnectAttr，并将 fOption 设为 SQL_COPT_SS_PERF_DATA，将 vParam 设为 SQL_PERF_START 以开始探查性能数据。

  2. 调用 SQLGetConnectAttr，并将 fOption 设为 SQL_COPT_SS_PERF_DATA，将 pvParam 设为 SQLPERF 结构的指针地址。第一次调用此函数时，将指针设为包含当前性能数据的有效 SQLPERF 结构的地址。驱动程序不连续刷新性能结构中的数据。任何时候只要应用程序需要用更多的当前性能数据刷新此结构，都必须再次调用 SQLGetConnectAttr。

  3. 调用 SQLSetConnectAttr，并将 fOption 设为 SQL_COPT_SS_PERF_DATA，将 vParam set 设为 SQL_PERF_STOP 以停止记录性能数据。

Odbcss.h 中定义的 SQLPERF 结构如下：

typedef struct sqlperf
{
   // Application profile statistics
   DWORD TimerResolution;
   DWORD SQLidu;
   DWORD SQLiduRows;
   DWORD SQLSelects;
   DWORD SQLSelectRows;
   DWORD Transactions;
   DWORD SQLPrepares;
   DWORD ExecDirects;
   DWORD SQLExecutes;
   DWORD CursorOpens;
   DWORD CursorSize;
   DWORD CursorUsed;
   LDOUBLE PercentCursorUsed;
   LDOUBLE AvgFetchTime;
   LDOUBLE AvgCursorSize;
   LDOUBLE AvgCursorUsed;
   DWORD SQLFetchTime;
   DWORD SQLFetchCount;
   DWORD CurrentStmtCount;
   DWORD MaxOpenStmt;
   DWORD SumOpenStmt;

   // Connection statistics
   DWORD CurrentConnectionCount;
   DWORD MaxConnectionsOpened;
   DWORD SumConnectionsOpened;
   DWORD SumConnectionTime;
   LDOUBLE AvgTimeOpened;

   // Network statistics
   DWORD ServerRndTrips;
   DWORD BuffersSent;
   DWORD BuffersRec;
   DWORD BytesSent;
   DWORD BytesRec;

   // Time statistics
   DWORD msExecutionTime;
   DWORD msNetworkServerTime;

}    SQLPERF;
示例

本例说明性能数据日志文件的创建，以及直接显示 SQLPERF 数据结构中的性能数据。为简化本示例，查错代码已删除。

// Sample showing the SQL Server ODBC driver-specific options
// to record performance statistics.  The sample creates
// one file:
//
// C:\Odbcperf.log contains performance statistics and
// can be imported to a spreadsheet application such as Microsoft Excel
// as a tab-delimited file for analysis.

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;

int main() {
   RETCODE retcode;
   // Pointer to the ODBC driver performance structure.
   SQLPERF      *PerfPtr;
   SQLINTEGER   cbPerfPtr;

    // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   // Allocate ODBC connection handle and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
                  "sa", SQL_NTS, "MyPassWord", SQL_NTS);

   // Set options to log performance statistics.
   // Specify file to use for the log.
   retcode = SQLSetConnectAttr
                     (hdbc1,
                     SQL_COPT_SS_PERF_DATA_LOG,
                     &"c:\\odbcperf.log",
                     SQL_NTS);
   // Start the performance statistics log.
   retcode = SQLSetConnectAttr
                     (hdbc1,
                     SQL_COPT_SS_PERF_DATA,
                     (SQLPOINTER)SQL_PERF_START,
                     SQL_IS_UINTEGER);

   // Allocate statement handle, then execute command.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
   retcode = SQLExecDirect(hstmt1,
         "SELECT * FROM pubs.dbo.authors", SQL_NTS);
   // Clear any result sets generated.
   while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
      ;

   retcode = SQLExecDirect(hstmt1,
         "SELECT * FROM pubs.dbo.stores", SQL_NTS);
   // Clear any result sets generated.
   while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
      ;

   // Generate a long-running query.
   retcode = SQLExecDirect(hstmt1,
                     "waitfor delay '00:00:04' ", SQL_NTS);
   // Clear any result sets generated.
   while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
      ;

   // Write current statistics to the performance log.
   retcode = SQLSetConnectAttr
                     (hdbc1,
                     SQL_COPT_SS_PERF_DATA_LOG_NOW,
                     (SQLPOINTER)NULL,
                     SQL_IS_UINTEGER);

   // Get pointer to current SQLPerf structure.
   // Print a couple of statistics.
   retcode = SQLGetConnectAttr
                     (hdbc1,
                     SQL_COPT_SS_PERF_DATA,
                     (SQLPOINTER)&PerfPtr,
                     SQL_IS_POINTER,
                     &cbPerfPtr);
   printf("SQLSelects = %d, SQLSelectRows = %d\n",
            PerfPtr->SQLSelects, PerfPtr->SQLSelectRows);

   /* Clean up. */
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

请参见

探查 ODBC 驱动程序性能

SQLSetConnectAttr

SQLGetConnectAttr


如何记录长时间运行的查询 (ODBC)

使用 ODBC Administrator 记录长时间运行的查询

  1. 在"控制面板"上，双击"32 位 ODBC"菜单项。

  2. 单击"用户 DSN"、"系统 DSN"或"文件 DSN"选项卡。

  3. 单击要为其记录长时间运行的查询的数据源。

  4. 单击"配置"按钮。

  5. 将 Microsoft SQL Server 配置 DSN 向导导航至带"将长时间运行的查询保存到日志文件"框的那一页。

  6. 选择"将长时间运行的查询保存到日志文件"框。在此框中放入将记录长时间运行的查询的文件的名称。或者单击"浏览"按钮浏览文件系统中的查询日志。

  7. 在"长查询时间（毫秒）"框中，设置一个以毫秒为单位的查询超时间隔。

通过编程记录长时间运行的查询数据

  1. 调用 SQLSetConnectAttr，并将 fOption 设为 SQL_COPT_SS_PERF_QUERY_LOG，将 vParam 设为长时间运行的查询日志文件的完整路径和文件名。例如：
    C:\\Odbcqry.log
  2. 调用 SQLSetConnectAttr，并将 fOption 设为 SQL_COPT_SS_PERF_QUERY_INTERVAL，将 vParam 设为以毫秒为单位的超时间隔。

  3. 调用 SQLSetConnectAttr，并将 fOption 设为 SQL_COPT_SS_PERF_QUERY，将 vParam 设为 SQL_PERF_START 以开始记录长时间运行的查询。

  4. 调用 SQLSetConnectAttr，并将 fOption 设为 SQL_COPT_SS_PERF_QUERY，将 vParam 设为 SQL_PERF_STOP 以停止记录长时间运行的查询。
示例

本例说明长时间运行的查询日志文件的创建。为简化本示例，查错代码已删除。

// Sample showing the SQL Server ODBC driver-specific options
// to log long-running queries. Creates C:\Odbcqry.log, which
// contains a list of queries whose execution
// exceeds an interval set by the application.

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;

int main() {

   RETCODE retcode;

    // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   // Allocate ODBC connection handle and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
               "sa", SQL_NTS, "MyPassWord", SQL_NTS));

   // Set options to log long-running queries, including the
   // file to use for the log.
   retcode = SQLSetConnectAttr
                     (hdbc1,
                     SQL_COPT_SS_PERF_QUERY_LOG,
                     &"c:\\odbcqry.log",
                     SQL_NTS);
   // Set the long-running query interval (in
   // milliseconds).  Note that for version 2.50 and 2.65
   // drivers, this value is specified in seconds, not milliseconds.
   retcode = SQLSetConnectAttr
                     (hdbc1,
                     SQL_COPT_SS_PERF_QUERY_INTERVAL,
                     (SQLPOINTER)3000,
                     SQL_IS_UINTEGER);
   // Start the long-running query log.
   retcode = SQLSetConnectAttr
                     (hdbc1,
                     SQL_COPT_SS_PERF_QUERY,
                     (SQLPOINTER)SQL_PERF_START,
                     SQL_IS_UINTEGER);

   // Allocate statement handle then execute commands.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);

   retcode = SQLExecDirect(hstmt1,
         "SELECT * FROM pubs.dbo.authors", SQL_NTS);
   // Clear any result sets generated.
   while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
      ;

   retcode = SQLExecDirect(hstmt1,
         "SELECT * FROM pubs.dbo.stores", SQL_NTS);
   // Clear any result sets generated.
   while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
      ;

   // Generate a long-running query.
   retcode = SQLExecDirect(hstmt1,
         "waitfor delay '00:00:04' ", SQL_NTS);
   // Clear any result sets generated.
   while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
      ;

   /* Clean up. */
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

请参见

探查 ODBC 驱动程序性能

SQLSetConnectAttr

SQLGetConnectAttr


如何处理 ODBC 错误 (ODBC)

可以使用两个 ODBC 函数调用来检索 ODBC 信息：SQLGetDiagRec 和 SQLGetDiagField。若要获得 SQLState、pfNative 和 ErrorMessage 诊断字段中与 ODBC 有关的主要信息，请调用 SQLGetDiagRec，直到它返回 SQL_NO_DATA 为止。可对每个诊断记录调用 SQLGetDiagField 以检索个别字段。所有驱动程序专用字段都必须用 SQLGetDiagField 检索。

SQLGetDiagRec 和 SQLGetDiagField 由 ODBC 驱动程序管理器而不是个别的驱动程序来处理。ODBC 驱动程序管理器在连接成功建立之前，不高速缓存驱动程序专用诊断字段。在连接成功建立之前无法对驱动程序专用诊断字段调用 SQLGetDiagField。这还包括 ODBC 连接命令，即便它们返回 SQL_SUCCESS_WITH_INFO。驱动程序专用诊断字段在下一个 ODBC 函数调用之前不可用。

示例

本例说明一个简单的错误处理程序，此程序对标准的 ODBC 信息调用 SQLGetDiagRec，然后进行有效连接测试，如果有，则为 Microsoft® SQL Server™ ODBC 驱动程序专用诊断字段调用 SQLGetDiagField。

// Example of SQL Server ODBC driver-specific options
// on SQLGetDiagField.
//
// This application assumes the existence of the following
// stored procedure:
//
// CREATE PROCEDURE BadOne AS SELECT * FROM NotThere
//
// where no object named NotThere exists.

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

#define MAXBUFLEN 256

SQLHENV      henv = SQL_NULL_HENV;
SQLHDBC      hdbc1 = SQL_NULL_HDBC;
SQLHSTMT      hstmt1 = SQL_NULL_HSTMT;
char         logstring[MAXBUFLEN] = "";

void      ProcessLogMessages(SQLSMALLINT plm_handle_type,
                     SQLHANDLE plm_handle, char *logstring,
                     int ConnInd);

int main() {
   RETCODE retcode;

   // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   if( (retcode != SQL_SUCCESS_WITH_INFO) &&
        (retcode != SQL_SUCCESS)) {
      printf("SQLAllocHandle(Env) Failed\n\n");
      return(9);
   }

   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   if( (retcode != SQL_SUCCESS_WITH_INFO) &&
        (retcode != SQL_SUCCESS)) {
      printf("SQLSetEnvAttr(ODBC version) Failed\n\n");
      return(9);
   }

   // Allocate ODBC connection handle and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   if( (retcode != SQL_SUCCESS_WITH_INFO) &&
        (retcode != SQL_SUCCESS)) {
      printf("SQLAllocHandle(hdbc1) Failed\n\n");
      return(9);
   }
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
      "sa", SQL_NTS, "MyPassWord", SQL_NTS);
   if ( (retcode != SQL_SUCCESS) &&
        (retcode != SQL_SUCCESS_WITH_INFO) ) {
         ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
               "SQLConnect() Failed\n\n", FALSE);
         return(9);
   }
   else {
         ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
                     "\nConnect Successful\n\n", FALSE);
      }

   // Allocate statement handle, and then execute command.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
   if ( (retcode != SQL_SUCCESS) &&
        (retcode != SQL_SUCCESS_WITH_INFO) ) {
         ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
                     "SQLAllocHandle(hstmt1) Failed\n\n",
                     TRUE);
         return(9);
   }
   retcode = SQLExecDirect(hstmt1, "exec BadOne", SQL_NTS);
   if ( (retcode != SQL_SUCCESS) &&
        (retcode != SQL_SUCCESS_WITH_INFO) ) {
         ProcessLogMessages(SQL_HANDLE_STMT, hstmt1,
                  "SQLExecute() Failed\n\n", TRUE);
         return(9);
   }
   // Clear any result sets generated.
   while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
      ;

   /* Clean up. */
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

void ProcessLogMessages(SQLSMALLINT plm_handle_type,
                  SQLHANDLE plm_handle,
                  char *logstring, int ConnInd)
{
   RETCODE      plm_retcode = SQL_SUCCESS;
   UCHAR      plm_szSqlState[MAXBUFLEN] = "",
            plm_szErrorMsg[MAXBUFLEN] = "";
   SDWORD      plm_pfNativeError = 0L;
   SWORD      plm_pcbErrorMsg = 0;
   SQLSMALLINT   plm_cRecNmbr = 1;
   SDWORD      plm_SS_MsgState = 0, plm_SS_Severity = 0;
   SQLINTEGER   plm_Rownumber = 0;
   USHORT      plm_SS_Line;
   SQLSMALLINT   plm_cbSS_Procname, plm_cbSS_Srvname;
   SQLCHAR      plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME];

   printf(logstring);

   while (plm_retcode != SQL_NO_DATA_FOUND) {
      plm_retcode = SQLGetDiagRec(plm_handle_type, plm_handle,
         plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError,
         plm_szErrorMsg, MAXBUFLEN - 1, &plm_pcbErrorMsg);

      // Note that if the application has not yet made a
      // successful connection, the SQLGetDiagField
      // information has not yet been cached by ODBC
      // Driver Manager and these calls to SQLGetDiagField
      // will fail.
      if (plm_retcode != SQL_NO_DATA_FOUND) {
         if (ConnInd) {
            plm_retcode = SQLGetDiagField(
               plm_handle_type, plm_handle, plm_cRecNmbr,
               SQL_DIAG_ROW_NUMBER, &plm_Rownumber,
               SQL_IS_INTEGER,
               NULL);
            plm_retcode = SQLGetDiagField(
               plm_handle_type, plm_handle, plm_cRecNmbr,
               SQL_DIAG_SS_LINE, &plm_SS_Line,
               SQL_IS_INTEGER,
               NULL);
            plm_retcode = SQLGetDiagField(
               plm_handle_type, plm_handle, plm_cRecNmbr,
               SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState,
               SQL_IS_INTEGER,
               NULL);
            plm_retcode = SQLGetDiagField(
               plm_handle_type, plm_handle, plm_cRecNmbr,
               SQL_DIAG_SS_SEVERITY, &plm_SS_Severity,
               SQL_IS_INTEGER,
               NULL);
            plm_retcode = SQLGetDiagField(
               plm_handle_type, plm_handle, plm_cRecNmbr,
               SQL_DIAG_SS_PROCNAME, &plm_SS_Procname,
               sizeof(plm_SS_Procname),
               &plm_cbSS_Procname);
            plm_retcode = SQLGetDiagField(
               plm_handle_type, plm_handle, plm_cRecNmbr,
               SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname,
               sizeof(plm_SS_Srvname),
               &plm_cbSS_Srvname);
         }
         printf("szSqlState = %s\n",plm_szSqlState);
         printf("pfNativeError = %d\n",plm_pfNativeError);
         printf("szErrorMsg = %s\n",plm_szErrorMsg);
         printf("pcbErrorMsg = %d\n\n",plm_pcbErrorMsg);
         if (ConnInd) {
            printf("ODBCRowNumber = %d\n", plm_Rownumber);
            printf("SSrvrLine = %d\n", plm_Rownumber);
            printf("SSrvrMsgState = %d\n",plm_SS_MsgState);
            printf("SSrvrSeverity = %d\n",plm_SS_Severity);
            printf("SSrvrProcname = %s\n",plm_SS_Procname);
            printf("SSrvrSrvname = %s\n\n",plm_SS_Srvname);
         }
      }
      plm_cRecNmbr++; //Increment to next diagnostic record.
   } // End while.
}

请参见

处理错误和消息

SQLGetDiagField

诊断记录和字段


如何使用 SQL Server ODBC 驱动程序进行大容量复制 (ODBC)

当用在 Microsoft® SQL Server™ 7.0 版中时，SQL Server ODBC 驱动程序与 DB-Library API 支持相同的大容量复制函数。


如何在没有格式文件的情况下进行大容量复制 (ODBC)

在没有格式文件的情况下进行大容量复制

  1. 分配环境句柄和连接句柄。

  2. 设置 SQL_COPT_SS_BCP 和 SQL_BCP_ON 以启用大容量复制操作。

  3. 连接到 Microsoft® SQL Server™。

  4. 调用 bcp_init 以设置下列信息：
    • 要大容量复制到（或从中复制）的表或视图的名称。

    • 包含向数据库中复制的数据（或从数据库复制时接收数据）的数据文件的名称。

    • 接收任何大容量复制错误信息的数据文件的名称（如果不想要消息文件，则指定 NULL）。

    • 复制的方向为：如果是从文件到视图或表，则为 DB_IN，如果是从表或视图到文件，则为 DB_OUT。
  5. 调用 bcp_exec 以执行大容量复制操作。

通过这些步骤设置 DB_OUT 后，将创建用本机格式的文件。然后可以遵循这些步骤，将创建的文件大容量复制到服务器，但不设置 DB_IN，而设置 DB_OUT。这只有在源表和目标表的结构完全相同时才可实现。

示例

本例说明如何使用大容量复制函数创建本机模式的数据文件。删除了大部分查错代码以简化本示例。

// Sample showing ODBC BCP_OUT in native mode format.
//

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

SQLHENV      henv = SQL_NULL_HENV;
HDBC         hdbc1 = SQL_NULL_HDBC;

int main() {
   RETCODE retcode;

   // Bulk copy variables.
   SDWORD   cRows;

    // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);

   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3,
                      SQL_IS_INTEGER);

   // Allocate ODBC connection handle, set bulk copy mode, and
   // then connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLSetConnectAttr(hdbc1, SQL_COPT_SS_BCP,
                        (void *)SQL_BCP_ON,
                         SQL_IS_INTEGER);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
            "sa", SQL_NTS, "MyPassWord", SQL_NTS);

   // Initialize the bulk copy.
   retcode = bcp_init(hdbc1, "pubs..authors", "c:\\BCPODBC.bcp",
                  "c:\\BCPERROR.out, DB_OUT);
   // Note that the test is for the bulk copy return of SUCCEED,
   // not the ODBC return of SQL_SUCCESS.
   if ( (retcode != SUCCEED) )
   {
         ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
                     "bcp_init(hdbc1) Failed\n\n");
         return(9);
   }

   // Execute the bulk copy.
   retcode = bcp_exec(hdbc1, &cRows);
   if ( (retcode != SUCCEED) )
   {
         ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
                     "bcp_exec(hdbc1) Failed\n\n");
         return(9);
   }
   printf("Number of rows bulk copied out = %d.\n", cRows);

   /* Clean up. */
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

本例所创建的数据文件是一个本机模式文件。若要将数据大容量复制回表，请将 bcp_init 调用从 BCP_OUT 更改为 BCP_IN，然后重新编译应用程序。若要将文件作为 bcp 实用工具的本机模式输入使用，请在命令提示符处输入：

bcp MyDB..DateTable in c:\BCPODBC.bcp /n /SMyServer
/Usa /PMyPassWord

请参见

bcp_exec

使用数据文件和格式文件

bcp_init


如何大容量复制 SELECT 结果集 (ODBC)

从 SELECT 语句的结果集向外大容量复制

  1. 分配环境句柄和连接句柄。

  2. 设置 SQL_COPT_SS_BCP 和 SQL_BCP_ON 以启用大容量复制操作。

  3. 连接到 Microsoft® SQL Server™。

  4. 调用 bcp_init 以设置下列信息：
    • 将 szTable 参数指定为 NULL。

    • 接收结果集数据的数据文件的名称。

    • 接收任何大容量复制错误信息的数据文件的名称（如果不想要消息文件，则指定 NULL）。

    • 复制的方向为：DB_OUT。
  5. 调用 bcp_control，将 eOption 设为 BCPHINTS，然后在 iValue 中放入指向包含 SELECT 语句的 SQLTCHAR 数组的指针。

  6. 调用 bcp_exec 以执行大容量复制操作。

通过这些步骤，文件将以本机格式创建。可以用 bcp_colfmt 将数据值转换为其它数据类型，有关更多信息，请参阅"如何创建大容量复制格式文件 (ODBC)"部分。

示例

下例说明如何使用大容量复制函数从 SELECT 语句的结果集向外大容量复制。为简化本示例，大部分查错代码已删除。

// Sample showing ODBC BCP_OUT of a SELECT result set
// using native mode format.

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

SQLHENV      henv = SQL_NULL_HENV;
HDBC         hdbc1 = SQL_NULL_HDBC;

int main() {
   RETCODE retcode;

   // Bulk copy variables.
   SDWORD   cRows;
   SQLTCHAR   szBCPQuery[] =
      "SELECT LastName, FirstName FROM Northwind.dbo.Employees";

    // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);

   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3,
                      SQL_IS_INTEGER);

   // Allocate ODBC connection handle, set bulk copy mode, and
   // then connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLSetConnectAttr(hdbc1, SQL_COPT_SS_BCP,
                        (void *)SQL_BCP_ON,
                         SQL_IS_INTEGER);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
            "sa", SQL_NTS, "MyPassWord", SQL_NTS);

   // Initialize the bulk copy.
   retcode = bcp_init(hdbc1, NULL, "c:\\BCPODBC.bcp",
                  "c:\\BCPERROR.out, DB_OUT);
   // Note that the test is for the bulk copy return of SUCCEED,
   // not the ODBC return of SQL_SUCCESS.
   if ( (retcode != SUCCEED) )
   {
         ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
                     "bcp_init(hdbc1) Failed\n\n");
         return(9);
   }

   // Specify the query to use.
   retcode = bcp_control(hdbc1, BCPHINTS, (void *)szBCPQuery);
   if ( (retcode != SUCCEED) )
   {
         ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
                     "bcp_control(hdbc1) Failed\n\n");
         return(9);
   }

   // Execute the bulk copy.
   retcode = bcp_exec(hdbc1, &cRows);
   if ( (retcode != SUCCEED) )
   {
         ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
                     "bcp_exec(hdbc1) Failed\n\n");
         return(9);
   }
   printf("Number of rows bulk copied out = %d.\n", cRows);

   /* Clean up. */
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

请参见

bcp_init

bcp_control

bcp_exec


如何创建大容量复制格式文件 (ODBC)

创建大容量复制格式文件

  1. 分配环境句柄和连接句柄。

  2. 设置 SQL_COPT_SS_BCP 和 SQL_BCP_ON 以启用大容量复制操作。

  3. 连接到 Microsoft® SQL Server™。

  4. 调用 bcp_init 以设置下列信息：
    • 要大容量复制到（或从中复制）的表或视图的名称。

    • 包含向数据库中复制的数据（或从数据库复制时接收数据）的数据文件的名称。

    • 接收任何大容量复制错误信息的数据文件的名称（如果不想要消息文件，则指定 NULL）。

    • 复制的方向为：从表或视图到文件为 DB_OUT。
  5. 调用 bcp_columns 以设置列数。

  6. 对每列调用 bcp_colfmt 以定义其在数据文件中的特性。

  7. 调用 bcp_writefmt 以创建格式文件，用来描述大容量复制操作将要创建的数据文件。

  8. 调用 bcp_exec 以执行大容量复制操作。

以这种方式运行的大容量复制操作将创建一个包含大容量复制数据的数据文件，以及一个描述数据文件布局的格式文件。

示例

下例说明如何使用大容量复制函数创建数据文件和格式文件。删除了查错代码以简化本示例。

// Sample showing ODBC BCP_OUT creating a format file.
//
// Assumes server has:
// CREATE TABLE BCPDate (cola int, colb datetime)

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

SQLHENV      henv = SQL_NULL_HENV;
HDBC         hdbc1 = SQL_NULL_HDBC;

int main() {
   RETCODE      retcode;
   // BCP variables.
   SDWORD   cRows;

    // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   // Allocate ODBC connection handle, set bulk copy mode, and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLSetConnectAttr(hdbc1, SQL_COPT_SS_BCP,
                        (void *)SQL_BCP_ON, SQL_IS_INTEGER);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
                     "sa",SQL_NTS, "MyPassWord", SQL_NTS);

   // Initialize the bulk copy.
   retcode = bcp_init(hdbc1, "pubs..BCPDate", "c:\\BCPODBC.bcp",
                  NULL, DB_OUT);
   // Set the number of output columns.
   retcode = bcp_columns(hdbc1, 2);

   // Describe the format of column 1 in the data file.
   retcode = bcp_colfmt(hdbc1, 1, SQLCHARACTER, -1, 5, NULL, 0, 1);
   // Describe the format of column 2 in the data file.
   retcode = bcp_colfmt(hdbc1, 2, SQLCHARACTER, -1, 20, NULL, 0, 2);

   // Create the format file.
   retcode = bcp_writefmt(hdbc1, "c:\\BCPFMT.fmt");

   // Execute the bulk copy.
   retcode = bcp_exec(hdbc1, &cRows);

   printf("Number of rows bulk copied out = %d.\n", cRows);

   /* Clean up. */
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

若要将此数据文件大容量复制回数据库，请参阅"如何使用格式文件进行大容量复制"。若要将此数据文件作为 bcp 实用工具的输入使用，请在命令提示符处输入：

bcp pubs..BCPDate in C:\Bcpodbc.bcp /fc:\Bcpfmt.fmt /SMyServer
/Usa /PMyPassWord

请参见

bcp_colfmt

bcp_writefmt

bcp_columns

如何使用格式文件进行大容量复制 (ODBC)

bcp_exec

使用数据文件和格式文件

bcp_init


如何使用格式文件进行大容量复制 (ODBC)

使用格式文件进行大容量复制

  1. 分配环境句柄和连接句柄。

  2. 设置 SQL_COPT_SS_BCP 和 SQL_BCP_ON 以启用大容量复制操作。

  3. 连接到 Microsoft® SQL Server™。

  4. 调用 bcp_init 以设置下列信息：
    • 要大容量复制到（或从中复制）的表或视图的名称。

    • 包含向数据库中复制的数据（或从数据库复制时接收数据）的数据文件的名称。

    • 接收任何大容量复制错误信息的数据文件的名称（如果不想要消息文件，则指定 NULL）。

    • 复制的方向为：从文件到表或视图，为 DB_IN。
  5. 调用 bcp_readfmt 以读取格式文件，该文件描述大容量复制操作将要使用的数据文件。

  6. 调用 bcp_exec 以执行大容量复制操作。
示例

下例说明如何对数据文件和格式文件使用大容量复制函数。删除了查错代码以简化本示例。

// Sample showing ODBC BCP_IN using a format file.
//
// Assumes server has:
// CREATE TABLE BCPDate (cola int, colb datetime)
// Assumes you have the format file and datafile from the example
// in How to create a bulk copy format file.

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

SQLHENV      henv = SQL_NULL_HENV;
HDBC         hdbc1 = SQL_NULL_HDBC;

int main() {
   RETCODE      retcode;
   // BCP variables.
   SDWORD   cRows;

   // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   // Allocate ODBC connection handle, set BCP mode, and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLSetConnectAttr(hdbc1, SQL_COPT_SS_BCP,
                        (void *)SQL_BCP_ON, SQL_IS_INTEGER);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
                     "sa", SQL_NTS, "MyPassWord", SQL_NTS);

   // Initialize the bulk copy.
   retcode = bcp_init(hdbc1, "pubs..BCPDate", "c:\\BCPODBC.bcp",
                  NULL, DB_IN);

   // Read the format file.
   retcode = bcp_readfmt(hdbc1, "c:\\BCPFMT.fmt");

   // Execute the bulk copy.
   retcode = bcp_exec(hdbc1, &cRows);

   printf("Number of rows bulk copied in = %d.\n", cRows);

   /* Clean up. */
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

请参见

bcp_exec

如何创建大容量复制格式文件 (ODBC)

bcp_init

使用数据文件和格式文件

bcp_readfmt


如何从程序变量大容量复制数据 (ODBC)

直接对程序变量使用大容量复制函数

  1. 分配环境句柄和连接句柄。

  2. 设置 SQL_COPT_SS_BCP 和 SQL_BCP_ON 以启用大容量复制操作。

  3. 连接到 Microsoft® SQL Server™。

  4. 调用 bcp_init 以设置下列信息：
    • 要大容量复制到（或从中复制）的表或视图的名称。

    • 将数据文件的名称指定为 NULL。

    • 接收任何大容量复制错误信息的数据文件的名称（如果不想要消息文件，则指定 NULL）。

    • 复制的方向为：从应用程序到视图或表为 DB_IN，从表或视图到应用程序为 DB_OUT。
  5. 对大容量复制中的每列调用 bcp_bind 以将每列与一个程序变量绑定在一起。

  6. 用数据填充程序变量，然后调用 bcp_sendrow 以发送数据行。

  7. 发送出几行后，调用 bcp_batch 对已发送出的行执行检查点操作。较好的方法是每 1000 行至少调用一次 bcp_batch。

  8. 发送出所有数据行后，调用 bcp_done 以完成此操作。

可以在大容量复制操作期间，通过调用 bcp_colptr 和 bcp_collen 改变程序变量的位置和长度。

使用 bcp_control 设置多种大容量复制选项。使用 bcp_moretext 将 text、ntext 和 image 数据分段发送到服务器。

示例

下例说明如何使用大容量复制函数 bcp_bind 和 bcp_sendrow 将数据从程序变量大容量复制到 SQL Server。为简化本示例，查错代码已删除。

// Sample showing ODBC bulk copy from program variables
// bound with bcp_bind; data sent with bcp_sendrow.
//
// Assumes server has:
//
// CREATE TABLE BCPSource (cola int PRIMARY KEY,
//                   colb CHAR(10) NULL)
// CREATE TABLE BCPTarget (cola int PRIMARY KEY,
//                     colb CHAR(10) NULL)
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

SQLHENV      henv = SQL_NULL_HENV;
HDBC         hdbc1 = SQL_NULL_HDBC, hdbc2 = SQL_NULL_HDBC;
SQLHSTMT      hstmt2 = SQL_NULL_HSTMT;

int main() {
   RETCODE      retcode;

   // BCP variables.
   char   *terminator = "\0";
   // bcp_done takes a different format return code
   // because it returns number of rows bulk copied
   // after the last bcp_batch call.
   DBINT      cRowsDone;
   // Set up separate return code for bcp_sendrow so
   // it is not using the same retcode as SQLFetch.
   RETCODE      SendRet;

   // Column variables.
   // cbCola and cbColb must be defined right before
   // Cola and szColb because they are used as
   // bulk copy indicator variables.
   struct ColaData{
      SQLINTEGER cbCola;
      SQLINTEGER Cola;
   } ColaInst;
   struct ColbData{
      SQLINTEGER cbColb;
      SQLCHAR   szColb[11];
   } ColbInst;

    // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                     (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);

   // Allocate ODBC connection handle, set bulk copy mode, and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   retcode = SQLSetConnectAttr(hdbc1, SQL_COPT_SS_BCP,
                        (void *)SQL_BCP_ON, SQL_IS_INTEGER);
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
                     "sa", SQL_NTS, "MyPassWord", SQL_NTS);

   // Initialize the bulk copy.
   retcode = bcp_init(hdbc1, "pubs..BCPTarget", NULL,
                  NULL, DB_IN);
   // Bind the program variables for the bulk copy.
   retcode = bcp_bind(hdbc1, (BYTE *)&ColaInst.cbCola, 4,
               SQL_VARLEN_DATA, NULL, (INT)NULL,
               SQLINT4, 1);
   // Could normally use strlen to calculate the bcp_bind
   // cbTerm parameter, but this terminator is a null byte
   // (\0), which gives strlen a value of 0. Explicitly give
   // cbTerm a value of 1.
   retcode = bcp_bind(hdbc1, (BYTE *)&ColbInst.cbColb, 4, 11,
               terminator, 1, SQLCHARACTER, 2);

   // Allocate second ODBC connection handle so that bulk copy
   // and cursor operations do not conflict.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc2);
   retcode = SQLConnect(hdbc2, "MyDSN", SQL_NTS,
                     "sa", SQL_NTS, "MyPassWord", SQL_NTS);
   // Allocate ODBC statement handle.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc2, &hstmt2);

   // Bind the SELECT statement to the same program variables
   // bound to the bulk copy operation.
   retcode = SQLBindCol(hstmt2, 1, SQL_C_SLONG, &ColaInst.Cola, 0,
                     &ColaInst.cbCola);
   retcode = SQLBindCol(hstmt2, 2, SQL_C_CHAR, &ColbInst.szColb, 11,
                     &ColbInst.cbColb);
   // Execute a SELECT statement to build a cursor containing
   // the data to be bulk copied to the new table.
   retcode = SQLExecDirect(hstmt2,
                     "SELECT * FROM BCPSource",
                     SQL_NTS);
   // Go into a loop fetching rows from the cursor until
   // each row is fetched. Because the bcp_bind calls
   // and SQLBindCol calls each reference the same
   // variables, each fetch fills the variables used by
   // bcp_sendrow, so all you have to do to send the data
   // to SQL Server is to call bcp_sendrow.

   while ( (retcode = SQLFetch(hstmt2) ) != SQL_NO_DATA) {
      if ( (retcode != SQL_SUCCESS) &&
         (retcode != SQL_SUCCESS_WITH_INFO) ) {
            // Process error.
            return(9);
      }
      if ( (SendRet = bcp_sendrow(hdbc1) ) != SUCCEED ) {
         // Process error.
         return(9);
      }
   }
   // Signal the end of the bulk copy operation.
   cRowsDone = bcp_done(hdbc1);
   printf("Number of rows bulk copied after last bcp_batch
               call = %d.\n", cRowsDone);
   /* Clean up. */
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt2);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLDisconnect(hdbc2);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc2);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return(0);
}

请参见

bcp_batch

bcp_init

bcp_bind

bcp_sendrow

bcp_done

从程序变量大容量复制


如何从 SQL Server 7.0 主动/被动故障转移群集升级（SQL Server 安装程序）

从 SQL Server 7.0 主动/被动故障转移群集升级

  1. 在节点 1 上，取消群集 Microsoft® SQL Server™ 7.0 版。

  2. 在节点 1 上，将 SQL Server 7.0 作为默认实例升级到 SQL Server 2000。

    必须将二进制文件安装到某个本地驱动器并对数据使用群集磁盘。该本地驱动器是路径，它是在群集的所有节点上都有效的非群集磁盘。在群集的所有节点上，该驱动器必须有至少 300 MB 的可用空间。

  3. 在节点 1 上，将 SQL Server 2000 默认实例作为 SQL Server 2000 群集实例升级。

    有关更多信息，请参见如何从默认实例升级到 SQL Server 2000 的默认群集实例（SQL Server 安装程序）。


如何转换日期时间字符串转换的格式（企业管理器）

转换日期时间字符串转换的格式

  1. 在"转换数据任务属性"或"数据驱动的查询任务属性"对话框的"转换"选项卡上，单击包含要修改的日期和时间的"源"列，然后单击修改过的字符串所要放到的"目的"列。

  2. 执行下列操作中的一种：
    • 如果有映射箭头连接这两列，则单击"删除"按钮，然后单击"新建"按钮。

    • 如果没有映射箭头，则单击"新建"按钮。
  3. 在"创建新转换"对话框中，单击"DateTime 字符串"按钮。

  4. 单击"常规"选项卡，然后单击"属性"按钮。

  5. 在"日期格式"列表中，选择所需的格式。

  6. 单击"命名"按钮显示"日历名称"对话框，在此对话框中可选择日或月的全称或缩写，以及所需的 am/pm 指示器。

  7. 在"语言"列表中，选择所需的语言，然后单击"设置默认语言"按钮。

请参见

日期时间字符串转换

Transform Data Task