知 名 IT 图 书 作 者 杨 中 科 的 又 一 扛 鼎 力 作 Chinapub 在 线 购 买 地 址 :hp://www. china-pub. com/301651 当 当 网 在 线 购 买 地 址 :hp://product.dangdang.com/product.aspx?product_id=20368319 程 序 员 的 SQL 金 典 将 子 查 询 表 连 接 数 据 库 语 法 差 异 等 用 通 俗 易 懂 诙 谐 幽 默 的 语 言 讲 解 出 来 配 合 大 量 真 实 案 例, 学 了 就 能 用, 在 短 时 间 内 成 为 数 据 库 开 发 高 手
高 度 提 取 不 同 数 据 库 的 共 同 点, 仔 细 分 析 不 同 点, 并 给 出 解 决 方 案, 同 时 学 会 MSSQLServer MYSQL Oracle DB2 数 据 库 不 再 是 梦 国 内 第 一 本 讲 解 开 窗 函 数 实 际 应 用 的 图 书 轻 举 技 术 之 纲, 张 合 用 之 目, 锻 造 SQL 高 可 用 性 数 据 库 应 用 指 南 从 理 论 到 实 践, 凝 聚 SQL 主 流 数 据 库 最 前 沿 的 技 术 要 领 本 书 特 色 : 主 要 介 绍 SQL 的 语 法 规 则 及 在 实 际 开 发 中 的 应 用, 并 且 对 SQL 在 MySQL MS SQL Server Oracle 和 DB2 中 的 差 异 进 行 了 分 析 ; 详 细 讲 解 数 据 库 对 增 删 改 查 等 SQL 的 支 持 并 给 出 了 相 应 的 SQL 应 用 案 例 ; 透 彻 分 析 函 数 子 查 询 表 连 接 不 同 DBMS 中 的 SQL 语 法 差 异 SQL 调 优 NULL 值 处 理 事 务 开 窗 函 数 等 高 级 技 术 ; 通 过 对 实 际 案 例 开 发 过 程 的 详 细 分 析, 使 读 者 掌 握 SQL 的 综 合 应 用 技 巧 内 容 提 要 本 书 主 要 介 绍 SQL 以 及 在 实 际 开 发 中 的 应 用, 并 且 对 SQL 在 MYSQL MSSQLServer Oracle 和 DB2 中 的 差 异 性 进 行 了 分 析 本 书 分 为 三 部 分 : 第 一 部 分 为 基 础 篇, 主 要 讲 解 数 据 库 对 增 删 改 查 等 SQL 的 支 持, 给 出 了 这 些 SQL 的 应 用 案 例 ; 第 二 部 分 为 进 阶 篇, 讲 解 了 函 数 子 查 询 表 联 接 不 同 DBMS 中 SQL 语 法 差 异 SQL 调 优 NULL 值 处 理 事 务 开 窗 函 数 等 高 级 技 术 ; 第 三 部 分 为 案 例 篇, 讲 解 了 前 两 部 分 的 知 识 的 综 合 运 用 此 书 适 用 于 学 习 数 据 库 编 程 的 读 者, 对 于 有 一 定 数 据 库 开 发 经 验 的 读 者 也 有 非 常 大 的 参 考 价 值 前 言 市 面 上 讲 解 数 现 在 据 库 的 书 都 花 了 很 多 篇 幅 讲 解 数 据 库 的 备 份 授 权 调 优 修 复 监 控 等 内 容, 这 些 内 容 是 数 据 库 管 理 员 (DBA) 应 该 掌 握 的, 而 对 于 程 序 员 来 说 更 需 要 去 掌 握 的 则 是 SQL 语 句 的 使 用 但 是 市 面 上 专 门 讲 解 SQL 语 句 的 书 非 常 少, 初 学 者 学 习 数 据 库 开 发 过 程 中 常 常 被 那 些 写 给 DBA 的 书 弄 的 晕 头 转 向, 无 法 真 正 快 速 的 掌 握 SQL 技 术 ; 而 且 这 些 书 中 讲 解 的 SQL 也 常 常 是 针 对 特 定 数 据 库 系 统 的 专 有 实 现, 无 法 很 容 易 的 在 其 他 数 据 库 系 统 中 运 行, 读 者 需 要 阅 读 大 量 的 书 和 查 阅 大 量 的 文 档 才 能 掌 握 不 同 数 据 库 系 统 的 使 用 本 书 是 专 门 写 给 程 序 员 的, 因 此 没 有 讲 解 备 份 授 权 调 优 修 复 监 控 等 开 发 人 员 不 关 心 的 内 容, 直 接 从 SQL 语 句 入 手 让 读 者 快 速 的 掌 握 数 据 库 开 发 的 技 能 面 向 开 发 人 员, 讲 解 对 开 发 人 员 最 有 用 的 知 识 是 本 书 的 编 写 宗 旨 MYSQL MSSQLServer Oracle 和 DB2 等 都 是 非 常 流 行 的 数 据 库 管 理 系 统 (DBMS), 虽 然 在 大 部 分 SQL 语 法 上 这 些 DBMS 实 现 都 是 一 致 的, 不 过 在 实 现 细 节 以 及 高 级 语 法 方 面 这 些 DBMS 的 实 现 差 异 还 是 非 常 大 的 如 果 编 写 能 够 兼 容 这 些 DBMS 的 SQL 语 句 是 开 发 人 员 经 常 需 要 面 对 的 问 题 本 书 将 帮 助 读 者 从 根 本 上 解 决 这 个 问 题 很 多 开 发 人 员 对 于 SQL 语 句 的 掌 握 只 限 于 简 单 的 SELECT UPDATE 语 句, 对 于 稍 微 复 杂 的 逻 辑 经 常 需 要 编 写 程 序 代 码 来 完 成, 这 不 仅 无 法 发 挥 数 据 库 的 优 势, 而 且 开 发 出 的 系 统 性 能 非 常 低, 而 如 果 能 够 使 用 数 据 库 函 数 子 查 询 表 联 接 开 窗 函 数 等 高 级 的 SQL 特 性 则 可 以 大 大 简 化 系 统 开 发 的 难 度, 并 且 提 高 系 统 的 性 能 本 书 将 对 这 些 高 级 特 性 进 行 详 细 的 讲 解
本 书 第 1 2 章 介 绍 数 据 库 系 统 的 基 本 知 识 以 及 基 本 操 作 ; 第 3 章 介 绍 Insert Delete 和 Update 语 句 的 基 本 应 用 ; 第 4 章 对 Select 语 句 进 行 全 面 的 介 绍, 对 模 糊 匹 配 分 组 限 制 数 据 条 数 计 算 字 段 组 合 查 询 等 高 级 内 容 进 行 了 重 点 的 讲 解 ; 第 5 章 介 绍 常 用 的 数 据 库 函 数 以 及 它 们 在 主 流 DBMS 中 的 实 现 差 异 ; 第 6 章 介 绍 索 引 与 约 束 等 知 识 点 ; 第 7 8 章 分 别 介 绍 表 连 接 子 查 询 等 高 级 查 询 技 术 ; 第 9 章 对 主 流 DBMS 的 语 法 差 异 进 行 分 析, 并 且 给 出 了 解 决 方 案 ; 第 10 章 介 绍 注 入 漏 洞 攻 击 SQL 调 优 事 务 自 动 增 长 字 段 NULL 值 处 理 开 窗 函 数 等 高 级 话 题 ; 第 11 章 以 一 个 案 例 讲 解 书 中 知 识 点 在 实 际 开 发 中 的 应 用 在 此, 我 要 感 谢 为 这 本 书 的 诞 生 给 于 我 帮 助 的 所 有 人 首 先 我 要 感 谢 CowNew 开 源 团 队 的 朋 友 们 一 直 以 来 的 无 私 奉 献 ; 感 谢 KingChou 在 开 发 CowNewSQL 过 程 中 的 卓 越 工 作, 没 有 CowNewSQL 也 就 不 会 有 这 本 书 的 问 世 ; 还 要 感 谢 EasyJF 的 蔡 世 友, 他 一 直 以 来 对 开 源 事 业 的 奉 献 是 值 得 我 学 习 的 ; 最 后 我 要 感 谢 电 子 工 业 出 版 社 的 田 小 康 经 理, 他 的 高 效 工 作 使 得 本 书 能 够 顺 利 的 完 成 和 出 版 如 果 您 对 我 的 书 有 任 何 意 见 和 建 议, 您 可 以 给 我 发 送 邮 件 :about521@163.com, 本 书 相 关 的 后 续 资 料 将 会 发 布 到 CowNew 开 源 团 队 网 站 (hp://www. cownew.com ) 中 第 1 章 数 据 库 入 门 1 1.1 数 据 库 概 述 1 1.1.1 数 据 库 与 数 据 库 管 理 系 统 1 1.1.2 数 据 库 能 做 什 么 2 1.1.3 主 流 数 据 库 管 理 系 统 介 绍 2 1.2 数 据 库 基 础 概 念 5 1.2.1 Catalog 5 1.2.2 表 (Table) 6 1.2.3 列 (Column) 7 1.2.4 数 据 类 型 (DataType) 8 1.2.5 记 录 (Record) 9 1.2.6 主 键 (PrimaryKey) 9 1.2.7 索 引 (Index) 10 1.2.8 表 关 联 12 1.2.9 数 据 库 的 语 言 SQL 13 1.2.10 DBA 与 程 序 员 14 第 2 章 数 据 表 的 创 建 和 管 理 17 2.1 数 据 类 型 17 2.1.1 整 数 类 型 17 2.1.2 数 值 类 型 19 2.1.3 字 符 相 关 类 型 21 2.1.4 日 期 时 间 类 型 23 2.1.5 二 进 制 类 型 24 2.2 通 过 SQL 语 句 管 理 数 据 表 25 2.2.1 创 建 数 据 表 25 2.2.2 定 义 非 空 约 束 26 2.2.3 定 义 默 认 值 27 2.2.4 定 义 主 键 27 2.2.5 定 义 外 键 29
2.2.6 修 改 已 有 数 据 表 30 2.2.7 删 除 数 据 表 31 2.2.8 受 限 操 作 的 变 通 解 决 方 案 31 第 3 章 数 据 的 增 删 改 33 3.1 数 据 的 插 入 34 3.1.1 简 单 的 INSERT 语 句 34 3.1.2 简 化 的 INSERT 语 句 36 3.1.3 非 空 约 束 对 数 据 插 入 的 影 响 36 3.1.4 主 键 对 数 据 插 入 的 影 响 37 3.1.5 外 键 对 数 据 插 入 的 影 响 38 3.2 数 据 的 更 新 38 3.2.1 简 单 的 数 据 更 新 39 3.2.2 带 WHERE 子 句 的 UPDATE 语 句 40 3.2.3 非 空 约 束 对 数 据 更 新 的 影 响 41 3.2.4 主 键 对 数 据 更 新 的 影 响 42 3.2.5 外 键 对 数 据 更 新 的 影 响 42 3.3 数 据 的 删 除 43 3.3.1 简 单 的 数 据 删 除 43 3.3.2 带 WHERE 子 句 的 DELETE 语 句 44 第 4 章 数 据 的 检 索 47 4.1 SELECT 基 本 用 法 48 4.1.1 简 单 的 数 据 检 索 48 4.1.2 检 索 出 需 要 的 列 49 4.1.3 列 别 名 51 4.1.4 按 条 件 过 滤 52 4.1.5 数 据 汇 总 53 4.1.6 排 序 56 4.2 高 级 数 据 过 滤 59 4.2.1 通 配 符 过 滤 59 4.2.2 空 值 检 测 63 4.2.3 反 义 运 算 符 64 4.2.4 多 值 检 测 65 4.2.5 范 围 值 检 测 66 4.2.6 低 效 的 WHERE 1=1 68 4.3 数 据 分 组 72 4.3.1 数 据 分 组 入 门 74 4.3.2 数 据 分 组 与 聚 合 函 数 76 4.3.3 HAVING 语 句 79 4.4 限 制 结 果 集 行 数 81 4.4.1 MySQL 81 4.4.2 MS SQL Server 2000 82 4.4.3 MS SQL Server 2005 83 4.4.4 Oracle 84 4.4.5 DB2 86
4.4.6 数 据 库 分 页 88 4.5 抑 制 数 据 重 复 90 4.6 计 算 字 段 91 4.6.1 常 量 字 段 92 4.6.2 字 段 间 的 计 算 93 4.6.3 数 据 处 理 函 数 95 4.6.4 字 符 串 的 拼 接 97 4.6.5 计 算 字 段 的 其 他 用 途 103 4.7 不 从 实 体 表 中 取 的 数 据 105 4.8 联 合 结 果 集 107 4.8.1 简 单 的 结 果 集 联 合 108 4.8.2 联 合 结 果 集 的 原 则 110 4.8.3 UNION ALL 112 4.8.4 联 合 结 果 集 应 用 举 例 114 第 5 章 函 数 119 5.1 数 学 函 数 122 5.1.1 求 绝 对 值 122 5.1.2 求 指 数 122 5.1.3 求 平 方 根 123 5.1.4 求 随 机 数 123 5.1.5 舍 入 到 最 大 整 数 125 5.1.6 舍 入 到 最 小 整 数 126 5.1.7 四 舍 五 入 127 5.1.8 求 正 弦 值 128 5.1.9 求 余 弦 值 129 5.1.10 求 反 正 弦 值 129 5.1.11 求 反 余 弦 值 130 5.1.12 求 正 切 值 130 5.1.13 求 反 正 切 值 131 5.1.14 求 两 个 变 量 的 反 正 切 131 5.1.15 求 余 切 132 5.1.16 求 圆 周 率 π 值 132 5.1.17 弧 度 制 转 换 为 角 度 制 133 5.1.18 角 度 制 转 换 为 弧 度 制 134 5.1.19 求 符 号 134 5.1.20 求 整 除 余 数 135 5.1.21 求 自 然 对 数 136 5.1.22 求 以 10 为 底 的 对 数 136 5.1.23 求 幂 137 5.2 字 符 串 函 数 137 5.2.1 计 算 字 符 串 长 度 138 5.2.2 字 符 串 转 换 为 小 写 138 5.2.3 字 符 串 转 换 为 大 写 139 5.2.4 截 去 字 符 串 左 侧 空 格 139
5.2.5 截 去 字 符 串 右 侧 空 格 140 5.2.6 截 去 字 符 串 两 侧 的 空 格 141 5.2.7 取 子 字 符 串 143 5.2.8 计 算 子 字 符 串 的 位 置 144 5.2.9 从 左 侧 开 始 取 子 字 符 串 145 5.2.10 从 右 侧 开 始 取 子 字 符 串 146 5.2.11 字 符 串 替 换 147 5.2.12 得 到 字 符 的 ASCII 码 148 5.2.13 得 到 一 个 ASCII 码 数 字 对 应 的 字 符 149 5.2.14 发 音 匹 配 度 151 5.3 日 期 时 间 函 数 153 5.3.1 日 期 时 间 日 期 时 间 与 时 间 戳 153 5.3.2 主 流 数 据 库 系 统 中 日 期 时 间 类 型 的 表 示 方 式 154 5.3.3 取 得 当 前 日 期 时 间 154 5.3.4 日 期 增 减 157 5.3.5 计 算 日 期 差 额 166 5.3.6 计 算 一 个 日 期 是 星 期 几 172 5.3.7 取 得 日 期 的 指 定 部 分 177 5.4 其 他 函 数 183 5.4.1 类 型 转 换 183 5.4.2 空 值 处 理 188 5.4.3 CASE 函 数 191 5.5 各 数 据 库 系 统 独 有 函 数 194 5.5.1 MySQL 中 的 独 有 函 数 195 5.5.2 MS SQL Server 中 的 独 有 函 数 202 5.5.3 Oracle 中 的 独 有 函 数 206 第 6 章 索 引 与 约 束 209 6.1 索 引 209 6.2 约 束 211 6.2.1 非 空 约 束 211 6.2.2 唯 一 约 束 212 6.2.3 CHECK 约 束 217 6.2.4 主 键 约 束 221 6.2.5 外 键 约 束 224 第 7 章 表 连 接 233 7.1 表 连 接 简 介 236 7.2 内 连 接 (INNER JOIN) 236 7.3 不 等 值 连 接 240 7.4 交 叉 连 接 241 7.5 自 连 接 245 7.6 外 部 连 接 248 7.6.1 左 外 部 连 接 250 7.6.2 右 外 部 连 接 251 7.6.3 全 外 部 连 接 252
第 8 章 子 查 询 255 8.1 子 查 询 入 门 261 8.1.1 单 值 子 查 询 261 8.1.2 列 值 子 查 询 263 8.2 SELECT 列 表 中 的 标 量 子 查 询 265 8.3 WHERE 子 句 中 的 标 量 子 查 询 267 8.4 集 合 运 算 符 与 子 查 询 270 8.4.1 IN 运 算 符 270 8.4.2 ANY 和 SOME 运 算 符 272 8.4.3 ALL 运 算 符 274 8.4.4 EXISTS 运 算 符 275 8.5 在 其 他 类 型 SQL 语 句 中 的 子 查 询 应 用 277 8.5.1 子 查 询 在 INSERT 语 句 中 的 应 用 277 8.5.2 子 查 询 在 UPDATE 语 句 中 的 应 用 283 8.5.3 子 查 询 在 DELETE 语 句 中 的 应 用 285 第 9 章 主 流 数 据 库 的 SQL 语 法 差 异 解 决 方 案 287 9.1 SQL 语 法 差 异 分 析 287 9.1.1 数 据 类 型 的 差 异 287 9.1.2 运 算 符 的 差 异 288 9.1.3 函 数 的 差 异 289 9.1.4 常 用 SQL 的 差 异 289 9.1.5 取 元 数 据 信 息 的 差 异 290 9.2 消 除 差 异 性 的 方 案 293 9.2.1 为 每 种 数 据 库 编 写 不 同 的 SQL 语 句 293 9.2.2 使 用 语 法 交 集 294 9.2.3 使 用 SQL 实 体 对 象 294 9.2.4 使 用 ORM 工 具 295 9.2.5 使 用 SQL 翻 译 器 296 9.3 CowNewSQL 翻 译 器 299 9.3.1 CowNewSQL 支 持 的 数 据 类 型 299 9.3.2 CowNewSQL 支 持 的 SQL 语 法 300 9.3.3 CowNewSQL 支 持 的 函 数 305 9.3.4 CowNewSQL 的 使 用 方 法 309 第 10 章 高 级 话 题 313 10.1 SQL 注 入 漏 洞 攻 防 313 10.1.1 SQL 注 入 漏 洞 原 理 313 10.1.2 过 滤 敏 感 字 符 314 10.1.3 使 用 参 数 化 SQL 315 10.2 SQL 调 优 316 10.2.1 SQL 调 优 的 基 本 原 则 317 10.2.2 索 引 317 10.2.3 全 表 扫 描 和 索 引 查 找 318 10.2.4 优 化 手 法 318 10.3 事 务 324
10.3.1 事 务 简 介 324 10.3.2 事 务 的 隔 离 325 10.3.3 事 务 的 隔 离 级 别 326 10.3.4 事 务 的 使 用 327 10.4 自 动 增 长 字 段 327 10.4.1 MySQL 中 的 自 动 增 长 字 段 327 10.4.2 MS SQL Server 中 的 自 动 增 长 字 段 328 10.4.3 Oracle 中 的 自 动 增 长 字 段 329 10.4.4 DB2 中 的 自 动 增 长 字 段 332 10.5 业 务 主 键 与 逻 辑 主 键 333 10.6 NULL 的 学 问 334 10.6.1 NULL 与 比 较 运 算 符 336 10.6.2 NULL 和 计 算 字 段 337 10.6.3 NULL 和 字 符 串 338 10.6.4 NULL 和 函 数 339 10.6.5 NULL 和 聚 合 函 数 339 10.7 开 窗 函 数 340 10.7.1 开 窗 函 数 简 介 342 10.7.2 PARTITION BY 子 句 344 10.7.3 ORDER BY 子 句 346 10.7.4 高 级 开 窗 函 数 353 10.8 WITH 子 句 与 子 查 询 360 第 11 章 案 例 讲 解 363 11.1 报 表 制 作 371 11.1.1 显 示 制 单 人 详 细 信 息 371 11.1.2 显 示 销 售 单 的 详 细 信 息 373 11.1.3 计 算 收 益 374 11.1.4 产 品 销 售 额 统 计 378 11.1.5 统 计 销 售 记 录 的 份 额 379 11.1.6 为 采 购 单 分 级 380 11.1.7 检 索 所 有 重 叠 日 期 销 售 单 383 11.1.8 为 查 询 编 号 385 11.1.9 标 记 所 有 单 内 最 大 销 售 量 386 11.2 排 序 389 11.2.1 非 字 段 排 序 规 则 389 11.2.2 随 机 排 序 390 11.3 表 间 比 较 391 11.3.1 检 索 制 作 过 采 购 单 的 人 制 作 的 销 售 单 391 11.3.2 检 索 没 有 制 作 过 采 购 单 的 人 制 作 的 销 售 单 392 11.4 表 复 制 394 11.4.1 复 制 源 表 的 结 构 并 复 制 表 中 的 数 据 394 11.4.2 只 复 制 源 表 的 结 构 395 11.5 计 算 字 符 在 字 符 串 中 出 现 的 次 数 396 11.6 去 除 最 高 分 最 低 分 396
11.6.1 去 除 所 有 最 低 最 高 值 397 11.6.2 只 去 除 一 个 最 低 最 高 值 397 11.7 与 日 期 相 关 的 应 用 398 11.7.1 计 算 销 售 确 认 日 和 制 单 日 之 间 相 差 的 天 数 398 11.7.2 计 算 两 张 销 售 单 之 间 的 时 间 间 隔 399 11.7.3 计 算 销 售 单 制 单 日 期 所 在 年 份 的 天 数 401 11.7.4 计 算 销 售 单 制 单 日 期 所 在 月 份 的 第 一 天 和 最 后 一 天 402 11.8 结 果 集 转 置 403 11.8.1 将 结 果 集 转 置 为 一 行 404 11.8.2 把 结 果 集 转 置 为 多 行 406 11.9 递 归 查 询 410 11.9.1 Oracle 中 的 CONNECT BY 子 句 410 11.9.2 Oracle 中 的 SYS_CONNECT_BY_PATH() 函 数 414 11.9.3 My SQL Server 和 DB2 中 递 归 查 询 415 附 录 A 常 用 数 据 库 系 统 的 安 装 和 使 用 417 A.1 DB2 的 安 装 和 使 用 417 A.2 MySQL 的 安 装 和 使 用 429 A.3 Oracle 的 安 装 和 使 用 441 A.4 Microso SQL Server 的 安 装 和 使 用 452 程 序 员 的 SQL 金 典 第 一 章 数 据 库 入 门 本 章 介 绍 数 据 库 的 入 门 知 识, 首 先 介 绍 什 么 是 数 据 库, 然 后 介 绍 数 据 库 中 的 一 些 基 本 概 念, 接 着 介 绍 操 纵 数 据 库 的 不 同 方 式, 最 后 介 绍 操 纵 数 据 库 时 使 用 的 语 言 SQL, 在 章 节 中 我 们 还 将 穿 插 一 些 非 常 有 趣 的 话 题 1.1 数 据 库 概 述 广 义 上 来 讲, 数 据 库 就 是 数 据 的 仓 库, 计 算 机 系 统 经 常 用 来 处 理 各 种 各 样 大 量 的 数 据, 比 如 使 用 计 算 机 系 统 收 集 一 个 地 区 的 人 口 信 息 检 索 符 合 某 些 条 件 的 当 地 人 口 信 息 当 一 个 人 去 世 后 还 要 从 系 统 中 删 除 此 人 的 相 关 信 息 我 们 可 以 自 定 义 一 个 文 件 格 式, 然 后 把 人 口 数 据 按 照 这 个 格 式 保 存 到 文 件 中, 当 需 要 对 已 经 存 入 的 数 据 进 行 检 索 或 者 修 改 的 时 候 就 重 新 读 取 这 个 文 件 然 后 进 行 相 关 操 作 这 种 数 据 处 理 方 式 存 在 很 多 问 题, 比 如 需 要 开 发 人 员 熟 悉 操 作 磁 盘 文 件 的 函 数 开 发 人 员 必 须 编 写 复 杂 的 搜 寻 算 法 才 能 快 速 的 把 数 据 从 文 件 中 检 索 出 来 当 数 据 格 式 发 生 变 化 的 时 候 要 编 写 复 杂 的 文 件 格 式 升 级 程 序 很 难 控 制 并 发 修 改 在 计 算 机 系 统 在 各 个 行 业 开 始 普 遍 应 用 以 后, 计 算 机 专 家 也 遇 到 了 同 样 的 问 题, 因 此 他 们 提 出 了 数 据 库 理 论, 从 而 大 大 简 化 了 开 发 信 息 系 统 的 难 度 数 据 库 理 论 的 鼻 祖 是 Charles W.Bachman, 他 也 因 此 获 得 了 1973 年 的 图 灵 奖 IBM 的 Ted Codd 则 首 先 提 出 了 关 系 数 据 库 理 论, 并 在 IBM 研 究 机 构 开 发 原 型, 这 个 项 目 就 是 R 系 统, 并 且 使 用 SQL 做 为 存 取 数 据 表 的 语 言,R 系 统 对 后 来 的 Oracle Ingres 和 DB2 等 关 系 型 数 据 库 系 统 都 产 生 了 非 常 重 要 的 影 响 1.1.1 数 据 库 与 数 据 库 管 理 系 统 前 面 我 们 讲 到 数 据 库 就 是 数 据 的 仓 库, 我 们 还 需 要 一 套 系 统 来 帮 助 我 们 管 理 这 些 数 据, 比 如 帮 助 我 们 查 询 到 我 们 需 要 的 数 据 帮 我 们 将 过 时 的 数 据 删 除, 这 样 的 系 统 我 们 称 之 为 数 据 库 管 理 系 统 (Database Management System,DBMS) 有 时 候 很 多 人 也 将 DBMS 简 称 为 数 据 库, 但 是 一 定 要 区 分 数 据 库 的 这 两 个 不 同 的 意 思 数 据 库 管 理 系 统 是 一 种 操 纵 和 管 理 数 据 库 的 系 统 软 件, 是 用 于 建 立 使 用 和 维 护 数 据 库
它 对 数 据 库 进 行 统 一 的 管 理 和 控 制, 以 保 证 数 据 库 的 安 全 性 和 完 整 性 用 户 通 过 DBMS 访 问 数 据 库 中 的 数 据, 数 据 库 管 理 员 也 通 过 DBMS 进 行 数 据 库 的 维 护 工 作 它 提 供 多 种 功 能, 可 使 多 个 应 用 程 序 和 用 户 用 不 同 的 方 法 在 同 时 或 不 同 时 刻 去 建 立, 修 改 和 询 问 数 据 库 它 使 用 户 能 方 便 地 定 义 和 操 纵 数 据, 维 护 数 据 的 安 全 性 和 完 整 性, 以 及 进 行 多 用 户 下 的 并 发 控 制 和 恢 复 数 据 库 通 俗 的 说,DBMS 就 是 数 据 库 的 大 管 家, 需 要 维 护 什 么 数 据 查 找 什 么 数 据 的 话 找 它 告 诉 他 了, 它 会 帮 你 办 的 干 净 利 落 1.1.2 数 据 库 能 做 什 么 数 据 库 能 够 帮 助 你 储 存 组 织 和 检 索 数 据 数 据 库 以 一 定 的 逻 辑 方 式 组 织 数 据, 当 我 们 要 对 数 据 进 行 增 删 改 查 的 时 候 数 据 库 能 非 常 快 速 的 完 成 所 要 求 的 操 作 ; 同 时 数 据 库 隐 藏 了 数 据 的 组 织 形 式, 我 们 只 要 对 数 据 的 属 性 进 行 描 述 就 可 以 了, 当 我 们 要 对 数 据 库 中 的 数 据 进 行 操 作 的 时 候 只 要 告 诉 做 什 么 ( What to do) 就 可 以 了,DBMS 会 决 定 一 个 比 较 好 的 完 成 操 作 的 方 式, 也 就 是 我 们 无 需 关 心 怎 么 做 ( How to do), 这 样 我 们 就 能 从 数 据 存 储 的 底 层 中 脱 身 出 来, 把 更 多 精 力 投 入 到 业 务 系 统 的 开 发 中 数 据 库 允 许 我 们 创 建 规 则, 以 确 保 在 增 加 更 新 以 及 删 除 数 据 的 时 候 保 证 数 据 的 一 致 性 ; 数 据 库 允 许 我 们 指 定 非 常 复 杂 的 数 据 过 滤 机 制, 这 样 无 论 业 务 规 则 多 么 复 杂, 我 们 都 能 轻 松 应 对 ; 数 据 库 可 以 处 理 多 用 户 并 发 修 改 问 题 ; 数 据 库 提 供 了 操 作 的 事 务 性 机 制, 这 样 可 以 保 证 业 务 数 据 的 万 无 一 失 1.1.3 主 流 数 据 库 管 理 系 统 介 绍 目 前 有 许 多 DBMS 产 品, 如 DB2 Oracle Microso SQL Server Sybase SQLServer Informix MySQL 等, 它 们 在 数 据 库 市 场 上 各 自 占 有 一 席 之 地 下 面 简 要 介 绍 几 种 常 用 的 数 据 库 管 理 系 统 (1)DB2 DB2 第 一 种 使 用 使 用 SQL 的 数 据 库 产 品 DB2 于 1982 年 首 次 发 布, 现 在 已 经 可 以 用 在 许 多 操 作 系 统 平 台 上, 它 除 了 可 以 运 行 在 OS/390 和 VM 等 大 型 机 操 作 系 统 以 及 中 等 规 模 的 AS/400 系 统 之 外,IBM 还 提 供 了 跨 平 台 ( 包 括 基 于 UNIX 的 LINUX,HP-UX,Sun Solaris, 以 及 SCO UnixWare; 还 有 用 于 个 人 电 脑 的 Windows 2000 系 统 ) 的 DB2 产 品 应 用 程 序 可 以 通 过 使 用 微 软 的 ODBC 接 口 Java 的 JDBC 接 口 或 者 CORBA 接 口 代 理 来 访 问 DB2 数 据 库 DB2 有 不 同 的 版 本, 比 如 DB2 Everyplace 是 为 移 动 用 户 提 供 的 一 个 内 存 占 用 小 且 性 能 出 色 的 版 本 ;DB2 for z/os 则 是 为 主 机 系 统 提 供 的 版 本 ;Enterprise Server Edi on(ese) 是 一 种 适 用 于 中 型 和 大 型 企 业 的 版 本 ; Workgroup Server Edi on(wse) 主 要 适 用 于 小 型 和 中 型 企 业, 它 提 供 除 大 型 机 连 接 之 外 的 所 有 ESE 特 性 ; 而 DB2 Express 则 是 为 开 发 人 员 提 供 的 可 以 免 费 使 用 的 版 本 IBM 是 最 早 进 行 关 系 数 据 库 理 论 研 究 和 产 品 开 发 的 公 司, 在 关 系 数 据 库 理 论 方 面 一 直 走 在 业 界 的 前 列, 所 以 DB2 的 功 能 和 性 能 都 是 非 常 优 秀 的, 不 过 对 开 发 人 员 的 要 求 也 比 其 他 数 据 库 系 统 更 高, 使 用 不 当 很 容 易 造 成 宕 机 死 锁 等 问 题 ;DB2 在 SQL 的 扩 展 方 面 比 较 保 守, 很 多 其 他 数 据 库 系 统 支 持 的 SQL 扩 展 特 性 在 DB2 上 都 无 法 使 用 ; 同 时 DB2 对 数 据 的 类 型 要 求 也 非 常 严 格, 在 数 据 类 型 不 匹 配 的 时 候 会 报 错 而 不 是 进 行 类 型 转 换, 而 且 如 果 发 生 精 度 溢 出 数 据 超 长 等 问 题 的 时 候 也 会 直 接 报 错, 这 虽 然 保 证 了 数 据 的 正 确 性, 但 是 也 使 得 基 于 DB2 的 开 发 更 加 麻 烦 因 此, 很 多 开 发 人 员 称 DB2 为 最 难 用 的 数 据 库 系 统 (2)Oracle Oracle 是 和 DB2 同 时 期 发 展 起 来 的 数 据 库 产 品, 也 是 第 二 个 采 用 SQL 的 数 据 库 产 品 Oracle 从 DB2 等 产 品 中 吸 取 到 了 很 多 优 点, 同 时 又 避 免 了 IBM 的 官 僚 体 制 与 过 度 学 术 化, 大 胆 的 引 进 了 许 多 新 的 理 论 与 特 性, 所 以 Oracle 无 论 是 功 能 性 能 还 是 可 用 性 都 是 非 常 好 的
(3)Microso SQL Server Microso SQL Server 是 微 软 推 出 的 一 款 数 据 库 产 品 细 心 的 读 者 也 许 已 经 发 现 我 们 前 面 提 到 了 另 外 一 个 名 字 非 常 相 似 的 Sybase SQLServer, 这 里 的 名 字 相 似 并 不 是 一 种 巧 合, 这 还 要 从 Microso SQL Server 的 发 展 史 谈 起 微 软 当 初 要 进 军 图 形 化 操 作 系 统, 所 以 就 开 始 和 IBM 合 作 开 发 OS/2, 最 终 当 然 无 疾 而 终, 但 是 微 软 就 很 快 的 推 出 了 自 己 的 新 一 代 视 窗 操 作 系 统 ; 而 当 微 软 发 现 数 据 库 系 统 这 块 新 的 市 场 的 时 候, 微 软 没 有 自 己 重 头 开 发 一 个 数 据 库 系 统, 而 是 找 到 了 Sybase 来 合 作 开 发 基 于 OS/2 的 数 据 产 品, 当 然 微 软 达 到 目 的 以 后 就 立 即 停 止 和 Sybase 的 合 作 了, 于 1995 年 推 出 了 自 己 的 Microso SQL Server6.0, 经 过 几 年 的 发 展 终 于 在 1998 年 推 出 了 轰 动 一 时 的 Microso SQL Server7.0, 也 正 是 这 一 个 版 本 使 得 微 软 在 数 据 库 产 品 领 域 有 了 一 席 之 地 正 因 为 这 段 合 作 历 史, 所 以 使 得 Microso SQL Server 和 Sybase SQLServer 在 很 多 地 方 非 常 类 似, 比 如 底 层 采 用 的 TDS 协 议 支 持 的 语 法 扩 展 函 数 等 等 微 软 在 2000 年 推 出 了 Microso SQL Server 2000, 这 个 版 本 继 续 稳 固 了 Microso SQL Server 的 市 场 地 位, 由 于 Windows 操 作 系 统 在 个 人 计 算 机 领 域 的 普 及,Microso SQL Server 理 所 当 然 的 成 为 了 很 多 数 据 库 开 发 人 员 的 接 触 的 第 一 个 而 且 有 可 能 也 是 唯 一 一 个 数 据 库 产 品, 很 多 人 甚 至 在 SQL Server 和 数 据 库 之 间 划 上 了 等 号, 而 且 用 SQL 一 次 来 专 指 Microso SQL Server, 可 见 微 软 的 市 场 普 及 做 的 还 是 非 常 好 的 做 足 足 够 的 市 场 以 后, 微 软 在 2005 年 审 时 度 势 的 推 出 了 Microso SQL Server 2005, 并 将 于 2008 年 发 布 新 一 代 的 Microso SQL Server 2008 Microso SQL Server 的 可 用 性 做 的 非 常 好, 提 供 了 很 多 了 外 围 工 具 来 帮 助 用 户 对 数 据 库 进 行 管 理, 用 户 甚 至 无 需 直 接 执 行 任 何 SQL 语 句 就 可 以 完 成 数 据 库 的 创 建 数 据 表 的 创 建 数 据 的 备 份 / 恢 复 等 工 作 ;Microso SQL Server 的 开 发 者 社 区 也 是 非 常 庞 大 的, 因 此 有 众 多 可 以 参 考 的 学 习 资 料, 学 习 成 本 非 常 低, 这 是 其 他 数 据 库 产 品 做 不 具 有 的 优 势 ; 同 时 从 Microso SQL Server 2005 开 始 开 发 人 员 可 以 使 用 任 何 支 持.Net 的 语 言 来 编 写 存 储 过 程, 这 进 一 步 降 低 了 Microso SQL Server 的 使 用 门 槛 不 过 正 如 微 软 产 品 的 一 贯 风 格,Microso SQL Server 的 劣 势 也 是 非 常 明 显 的 : 只 能 运 行 于 Windows 操 作 系 统, 因 此 我 们 无 法 在 Linux Unix 上 运 行 它 ; 不 管 微 软 给 出 什 么 样 的 测 试 数 据, 在 实 际 使 用 中 Microso SQL Server 在 大 数 据 量 和 大 交 易 量 的 环 境 中 的 表 现 都 是 不 尽 人 意 的, 当 企 业 的 业 务 量 到 达 一 个 水 平 后 就 要 考 虑 升 级 到 Oracle 或 者 DB2 了 (4)MySQL MySQL 是 一 个 小 型 关 系 型 数 据 库 管 理 系 统, 开 发 者 为 瑞 典 MySQL AB 公 司 目 前 MySQL 被 广 泛 地 应 用 在 中 小 型 系 统 中, 特 别 是 在 网 络 应 用 中 用 户 群 更 多 MySQL 没 有 提 供 一 些 中 小 型 系 统 中 很 少 使 用 的 功 能, 所 以 MySQL 的 资 源 占 用 非 常 小, 更 加 易 于 安 装 使 用 和 管 理 由 于 MySQL 是 开 源 的, 所 以 在 PHP 和 Java 开 发 人 员 心 中 更 是 首 选 的 数 据 库 开 发 搭 档, 目 前 Internet 上 流 行 的 网 站 构 架 方 式 是 LAMP(Linux+Apache+MySQL+PHP), 即 使 用 Linux 作 为 操 作 系 统,Apache 作 为 Web 服 务 器,MySQL 作 为 数 据 库,PHP 作 为 服 务 器 端 脚 本 解 释 器 MySQL 目 前 还 很 难 用 于 支 撑 大 业 务 量 的 系 统, 所 以 目 前 MySQL 大 部 分 还 是 用 来 运 行 非 核 心 业 务 ; 同 时 由 于 MySQL 在 国 内 没 有 足 够 的 技 术 支 持 力 量, 所 以 对 MySQL 的 技 术 支 持 工 作 是 由 ISV 或 者 系 统 集 成 商 来 承 担, 这 也 导 致 部 分 客 户 对 MySQL 比 较 抵 制, 他 们 更 倾 向 于 使 用 有 更 强 技 术 支 持 力 量 的 数 据 库 产 品 1.2 数 据 库 基 础 概 念 要 想 使 用 数 据 库, 我 们 必 须 熟 悉 一 些 基 本 概 念, 这 些 概 念 包 括 :Catalog 表 列 数 据 类 型 记 录 主 键 以 及 表 关 联 等 等 1.2.1 Catalog
数 据 库 就 是 数 据 的 仓 库, 而 DBMS 是 数 据 库 的 管 理 员 一 些 企 业 即 生 产 食 品 又 生 产 农 用 物 资, 这 些 产 品 都 要 保 存 到 仓 库 中, 同 时 企 业 内 部 也 有 一 些 办 公 用 品 需 要 保 存 到 仓 库 中 如 果 这 些 物 品 都 保 存 到 同 一 个 仓 库 中 的 话 会 造 成 下 面 的 问 题 : 不 便 于 管 理 食 品 的 保 存 和 复 印 纸 的 保 存 需 要 的 保 存 条 件 是 不 同 的, 食 品 需 要 低 温 保 鲜 而 复 印 纸 则 需 要 除 湿, 不 同 类 的 物 品 放 在 一 起 加 大 了 管 理 的 难 度 ; 可 能 会 造 成 货 位 冲 突 食 品 要 防 止 阳 光 直 射 造 成 的 变 质, 因 此 要 摆 放 到 背 阴 面, 同 时 为 了 防 止 受 潮, 也 要 把 它 们 摆 放 到 高 处 ; 办 公 用 胶 片 也 要 避 免 阳 光 直 射, 所 以 同 样 要 摆 放 到 背 阴 面, 而 且 胶 片 也 要 防 潮, 所 以 同 样 要 把 它 们 摆 放 到 高 处 这 就 造 成 两 种 货 物 占 据 的 货 位 相 冲 突 了 会 有 安 全 问 题 由 于 所 有 物 品 都 放 到 一 个 仓 库 中 没 有 进 行 隔 离, 所 以 来 仓 库 领 取 办 公 用 品 的 人 员 可 能 会 顺 手 牵 羊 将 食 品 偷 偷 带 出 仓 库 既 然 都 是 仓 库, 那 么 数 据 库 系 统 也 存 在 类 似 问 题 如 果 企 业 将 人 力 资 源 数 据 和 核 心 业 务 数 据 都 保 存 到 一 个 数 据 库 中 同 样 会 造 成 下 面 的 问 题 : 不 便 于 管 理 为 了 防 止 数 据 丢 失, 企 业 需 要 对 数 据 进 行 定 期 备 份, 不 过 和 核 心 业 务 数 据 比 起 来 人 力 资 源 数 据 的 重 要 性 要 稍 差, 所 以 人 力 资 源 数 据 只 要 一 个 月 备 份 一 次 就 可 以 了, 而 核 心 业 务 数 据 则 需 要 每 天 都 备 份 如 果 将 这 两 种 数 据 保 存 在 一 个 数 据 库 中 会 给 备 份 工 作 带 来 麻 烦 可 能 会 造 成 命 名 冲 突 比 如 人 力 资 源 数 据 中 需 要 将 保 存 员 工 数 据 的 表 命 名 为 Persons, 而 核 心 业 务 数 据 也 要 将 保 存 客 户 数 据 的 表 也 命 名 为 Persons, 这 就 会 相 冲 突 了 会 有 数 据 安 全 问 题 由 于 所 有 的 数 据 都 保 存 在 一 个 数 据 库 中, 这 样 人 力 资 源 系 统 的 用 户 也 可 以 访 问 核 心 业 务 系 统 中 的 数 据, 很 容 易 造 成 数 据 安 全 问 题 显 而 易 见, 对 于 上 边 提 到 的 多 种 物 品 保 存 在 一 个 仓 库 中 的 问 题, 最 好 的 解 决 策 略 就 是 使 用 多 个 仓 库, 食 品 保 存 在 食 品 仓 库 中, 农 用 物 资 保 存 在 农 用 物 资 仓 库 中, 而 办 公 用 品 则 保 存 在 办 公 用 品 仓 库 中, 这 样 就 可 以 解 决 问 题 了 问 了 解 决 同 样 的 问 题,DBMS 也 采 用 了 多 数 据 库 的 方 式 来 保 存 不 同 类 别 的 数 据, 一 个 DBMS 可 以 管 理 多 个 数 据 库, 我 们 将 人 力 资 源 数 据 保 存 在 HR 数 据 库 中, 而 将 核 心 业 务 数 据 保 存 在 BIZ 数 据 库 中, 我 们 将 这 些 不 同 数 据 库 叫 做 Catalog( 在 有 的 DBMS 中 也 称 为 Database, 即 数 据 库 ) 采 用 多 Catalog 以 后 可 以 给 我 们 带 来 如 下 好 处 : 便 于 对 各 个 Catalog 进 行 个 性 化 管 理 DBMS 都 允 许 我 们 指 定 将 不 同 的 Catalog 保 存 在 不 同 的 磁 盘 上, 由 于 人 力 资 源 数 据 相 对 次 要 一 些, 因 此 我 们 可 以 将 HR 保 存 在 普 通 硬 盘 上, 而 将 BIZ 保 存 在 RAID 硬 盘 上 我 们 还 可 以 对 每 个 Catalog 所 能 占 据 的 最 大 磁 盘 空 间 日 志 大 小 甚 至 优 先 级 进 行 指 定, 这 样 就 可 以 针 对 不 同 的 业 务 数 据 进 行 个 性 化 定 制 了 避 免 了 命 名 冲 突 同 一 个 Catalog 中 的 表 名 是 不 允 许 重 复 的, 而 不 同 Catalog 中 的 表 名 则 是 可 以 重 复 的, 这 样 HR 中 可 以 有 Persons 表, 而 BIZ 中 也 可 以 有 Persons 表, 二 者 结 构 可 以 完 全 不 相 同, 保 存 的 数 据 也 不 会 互 相 干 扰 安 全 性 更 高 DBMS 允 许 为 不 同 的 Catalog 指 定 不 同 的 用 户, 并 且 可 以 限 定 用 户 能 访 问 的 Catalog 比 如 用 户 hr123 只 能 访 问 HR, 而 用 户 sales001 只 能 访 问 BIZ 这 就 大 大 加 强 了 系 统 数 据 的 安 全 性 1.2.2 表 (Table) 虽 然 我 们 已 经 将 不 同 用 途 的 物 品 保 存 在 不 同 的 仓 库 中 了, 但 是 在 同 一 个 仓 库 中 数 据 的 保 存 仍 然 存 在 问 题 比 如 食 品 分 为 熟 食 生 肉 大 米 等, 如 果 把 他 们 随 意 的 堆 放 在 一 起, 就 会 造 成 我 们 无 法 很 容 易 的 对 这 些 食 品 进 行 管 理, 当 要 对 大 米 进 行 提 货 的 话 就 必 须 在 一 堆 的 食 品
中 翻 来 翻 去 解 决 这 个 问 题 的 方 法 就 是 将 仓 库 划 分 为 不 同 的 区 域, 熟 食 保 存 在 熟 食 区, 生 肉 保 存 在 生 肉 区, 而 大 米 则 保 存 在 大 米 区 DBMS 中 也 存 在 类 似 的 问 题, 虽 然 我 们 将 核 心 业 务 数 据 保 存 在 BIZ 数 据 库 中 了, 但 是 核 心 业 务 数 据 也 有 很 多 不 同 类 型 的 数 据, 比 如 客 户 资 料 商 品 资 料 销 售 员 资 料 等, 如 果 将 这 些 数 据 混 杂 在 一 起 的 话 将 会 管 理 起 来 非 常 麻 烦, 比 如 我 们 要 查 询 所 有 客 户 资 料 的 话 就 必 须 将 所 有 数 据 查 询 一 遍 解 决 这 个 问 题 的 方 法 就 是 将 不 同 类 型 的 资 料 放 到 不 同 的 区 域 中, 我 们 将 这 种 区 域 叫 做 表 ( Table) 客 户 资 料 保 存 到 Customers 表 中, 将 商 品 资 料 保 存 在 Goods 表 中, 而 将 销 售 员 资 料 保 存 在 SalesMen 表 中, 这 样 当 需 要 查 找 商 品 的 时 候 只 要 到 Goods 表 中 查 找 就 可 以 了 1.2.3 列 (Column) 同 样 是 生 肉, 不 同 的 生 肉 又 有 不 同 的 特 性, 有 的 生 肉 是 里 脊 肉, 有 的 生 肉 是 前 臀 尖, 这 块 生 肉 是 18 公 斤, 而 那 块 生 肉 是 12 公 斤, 这 块 生 肉 是 12.2 元 / 公 斤, 而 那 块 生 肉 是 13.6 元 / 公 斤 每 块 肉 都 有 各 自 的 不 同 的 特 性, 这 些 特 性 包 括 取 肉 部 位 重 量 单 价 如 果 不 对 每 块 肉 标 注 这 些 特 性 数 据 的 话, 当 提 货 人 要 我 们 将 所 有 里 脊 肉 出 库 的 话 我 们 就 非 常 麻 烦 了 解 决 这 个 问 题 的 方 法 就 是 制 作 一 些 标 签, 在 这 个 标 签 上 标 明 取 肉 部 位 重 量 单 价, 这 样 要 提 取 货 物 就 会 非 常 方 便 了 不 仅 如 此, 标 签 的 格 式 也 要 统 一, 如 果 第 一 块 生 肉 的 标 签 内 容 是 : 这 块 肉 是 15.6 公 斤 的 里 脊 肉,13.2 元 / 公 斤 另 一 块 生 肉 的 标 签 内 容 是 : 每 市 斤 8.6 元, 前 臀 尖, 13.6 公 斤 的, 采 用 这 种 标 签 由 于 没 有 统 一 的 格 式, 所 以 阅 读 起 来 非 常 麻 烦, 要 靠 人 工 去 分 辨, 错 误 率 非 常 高 如 果 我 们 规 定 一 个 统 一 的 标 签 格 式, 比 如 下 面 的 标 签 : 取 肉 部 位 重 量 单 价 ( 元 / 公 斤 ) 这 样 每 块 肉 的 标 签 就 可 以 按 照 这 个 格 式 来 填 写 了 : 取 肉 部 位 里 脊 肉 重 量 15.6 单 价 ( 元 / 公 斤 ) 13.2 这 种 格 式 阅 读 起 来 非 常 方 便, 如 果 引 入 自 动 识 别 设 备 的 话, 甚 至 可 以 实 现 自 动 化 的 物 品 分 拣 在 数 据 库 的 表 中 保 存 的 数 据 也 有 类 似 问 题, 如 果 不 规 定 格 式 的 话, 表 中 的 数 据 也 会 非 常 阅 读, 如 果 一 个 员 工 的 资 料 在 表 中 保 存 的 内 容 为 :
2003 年 5 月 入 职, 是 产 品 开 发 部 的, 姓 名 马 小 虎 另 外 一 个 员 工 的 资 料 在 表 中 保 存 的 内 容 为 : 王 二 小, 技 术 支 持 部, 入 职 是 2005 年 7 月 通 常, 以 这 种 不 标 准 的 格 式 保 存 造 成 数 据 十 分 混 乱, 想 要 从 数 据 库 中 取 出 合 适 的 数 据 仍 然 非 常 麻 烦 为 了 解 决 这 个 问 题, 我 们 规 定 下 面 这 种 标 准 的 格 式 : 姓 名 部 门 入 职 时 间 这 里 的 姓 名 部 门 和 入 职 时 间 就 被 称 为 员 工 表 的 列 (Column), 有 时 候 也 叫 做 字 段 (Field), 每 个 列 描 述 了 数 据 的 一 个 特 性 1.2.4 数 据 类 型 (DataType) 上 面 我 们 为 员 工 表 规 定 了 姓 名 部 门 和 入 职 时 间 三 个 列, 这 样 只 要 按 照 这 个 格 式 进 行 数 据 填 写 就 可 以 了, 但 是 这 里 仍 然 有 一 个 问 题, 那 就 是 我 们 没 法 限 定 用 户 向 表 中 填 写 什 么 数 据, 比 如 用 户 填 写 成 下 面 的 格 式 : 姓 名 33 部 门 12.3 入 职 时 间 信 息 中 心 显 然 姓 名 不 应 该 为 一 个 数 字 33; 不 可 能 有 一 个 名 称 为 12.3 的 部 门 ; 入 职 时 间 更 不 可 能 是 信 息 中 心 因 此 我 们 必 须 规 则 每 一 列 中 填 写 的 数 据 的 格 式 : 姓 名 必 须 填 写 汉 字, 最 短 2 个 汉 字, 最 长 5 个 汉 字 ; 部 门 必 须 填 写 产 品 开 发 部 技 术 支 持 部 产 品 实 施 部 人 力 资 源 部 中 的 一 个 ; 入 职 时 间 必 须 填 写 为 正 确 的 时 间 格 式 这 里 就 规 定 了 各 个 列 的 数 据 类 型 (DataType), 数 据 类 型 规 定 了 一 个 列 中 能 填 写 什 么 类 型 的 数 据, 减 少 了 不 规 范 数 据 出 现 的 几 率 除 了 可 以 对 数 据 进 行 规 范 之 外, 数 据 类 型 还 有 下 面 的 作 用 : 提 高 效 率 对 不 同 的 数 据 赋 予 不 同 的 类 型 能 够 使 得 数 据 库 更 好 的 对 数 据 进 行 存 储 和 管 理, 从 而 减 少 空 间 占 用 并 且 提 供 数 据 的 访 问 速 度 比 如, 如 果 将 数 字 123454321 以 文 本 类 型 存 储 的 话 将 会 占 用 9 字 节 的 存 储 空 间, 而 以 整 数 类 型 保 存 的 话 将 只 需 要 占 用 4 字 节 的 存 储 空 间 能 够 确 定 对 数 据 进 行 操 作 所 需 要 的 正 确 处 理 方 式 比 如 如 果 是 整 数 类 型, 那 么 123+234 被 解 释 为 两 个 整 数 的 加 法 运 算, 所 以 其 结 果 是 357; 如 果 是 文 本 类 型, 那 么 123+234 则 会 被 解 释 为 两 个 字 符 串 的 相 连 操 作, 所 以 其 结 果 是 123234 1.2.5 记 录 (Record) 记 录 有 可 以 被 称 为 行 (Row), 可 以 通 俗 的 认 为 它 是 数 据 表 中 的 一 行 数 据 以 员 工 表 为 例, 一 个 公 司 的 员 工 表 中 的 数 据 是 这 样 的 :
姓 名 部 门 入 职 时 间 马 小 虎 产 品 开 发 部 2003 年 5 月 22 日 王 二 小 技 术 支 持 部 2005 年 7 月 17 日 白 展 堂 后 勤 部 1998 年 3 月 27 日 钱 长 贵 销 售 部 2001 年 3 月 3 日 李 达 最 后 勤 部 2005 年 11 月 11 日 这 里 每 一 行 数 据 就 代 表 一 个 员 工 的 资 料, 这 样 的 一 行 数 据 就 叫 做 一 条 记 录 表 是 由 行 和 列 组 成 的 一 张 二 维 表, 这 就 是 关 系 数 据 库 中 最 基 本 的 数 据 模 型 1.2.6 主 键 (PrimaryKey) 员 工 表 中 的 每 一 行 记 录 代 表 了 一 个 员 工, 一 般 员 工 的 名 字 就 能 唯 一 标 识 这 一 个 员 工, 但 是 名 字 也 是 有 可 能 重 复 的, 这 时 我 们 就 要 为 每 一 名 员 工 分 配 一 个 唯 一 的 工 号 : 工 号 姓 名 部 门 入 职 时 间 001 马 小 虎 产 品 开 发 部 2003 年 5 月 22 日 002 王 二 小 技 术 支 持 部 2005 年 7 月 17 日 003 白 展 堂 后 勤 部 1998 年 3 月 27 日 004 钱 长 贵 销 售 部 2001 年 3 月 3 日 005 李 达 最 后 勤 部 2005 年 11 月 11 日 006 王 二 小 产 品 开 发 部 2005 年 3 月 22 日 这 样 就 可 以 通 过 这 个 工 号 来 唯 一 标 识 一 名 员 工 了 当 老 板 下 令 说 把 王 二 小 提 升 为 副 总 的 时 候, 我 们 就 要 问 公 司 有 两 个 王 二 小, 您 要 提 升 哪 一 个?, 老 板 可 以 说 技 术 支 持 部 的 王 二 小, 但 是 更 好 的 方 式, 那 就 是 说 提 升 工 号 为 的 002 员 工 为 副 总, 因 为 只 有 002 这 个 工 号 才 能 唯 一 标 识 一 名 员 工 这 里 的 工 号 被 称 为 员 工 表 的 主 键 ( PrimaryKey), 所 以 我 们 可 以 说 能 唯 一 标 识 一 行 记 录 的 字 段 就 是 此 表 的 主 键 有 的 公 司 比 较 懒 惰, 不 想 为 员 工 分 配 工 号, 只 是 硬 性 规 定 : 一 个 部 门 中 员 工 的 姓 名 不 能 重 复, 有 姓 名 重 复 的 必 须 调 换 到 其 它 部 门 这 样 部 门 和 姓 名 这 两 个 字 段 加 在 一 起 就 能 唯 一 标 识 一 名 员 工 了, 这 里 的 部 门 和 姓 名 两 个 字 段 就 被 称 为 复 合 主 键, 也 就 是 任 何 一 个 字 段 都 不 能 唯 一 标 识 一 行 数 据, 只 有 构 成 复 合 主 键 的 所 有 字 段 组 合 起 来 才 能 唯 一 标 识 这 一 行 数 据 在 大 多 数 DBMS 中 并 没 有 强 制 规 定 一 个 表 必 须 有 主 键, 也 就 是 一 个 表 可 以 没 有 主 键, 但 是 为 一 个 数 据 表 指 定 一 个 主 键 是 一 个 非 常 好 的 习 惯 在 后 边 的 章 节 我 们 将 提 到 用 一 个 无 意 义 的 字 段 做 主 键 将 会 更 加 有 利 于 系 统 的 可 扩 展 性 1.2.7 索 引 (Index) 无 索 引 的 表 就 是 一 个 无 序 的 行 集 比 如 下 面 的 人 员 表 中 有 一 些 数 据 : 编 号 姓 名 年 龄 身 高 001 莫 小 贝 14 1.33 002 佟 湘 玉 23 1.77 003 白 展 堂 17 1.90 004 李 秀 莲 13 1.68 005 郭 芙 蓉 23 1.68 006 邢 育 森 23 1.72 007 吕 秀 才 23 1.72 008 燕 小 六 13 1.44 009 杨 蕙 兰 23 1.69
010 郭 巨 侠 14 1.98 011 娄 之 献 13 1.62 012 邱 小 东 17 1.35 这 个 表 上 没 有 索 引, 因 此 如 果 我 们 查 找 年 龄 等 于 17 的 人 员 时, 必 须 查 看 表 中 的 每 一 行, 看 它 是 否 与 所 需 的 值 匹 配 这 是 一 个 全 表 扫 描, 很 慢, 如 果 表 中 只 有 少 数 几 个 记 录 与 搜 索 条 件 相 匹 配, 则 其 效 率 是 相 当 低 的 如 果 我 们 经 常 要 查 询 某 个 年 龄 的 人 员, 必 须 查 看 表 中 的 每 一 行, 看 它 是 否 与 所 需 的 值 匹 配 这 是 一 个 全 表 扫 描, 很 慢, 如 果 表 中 只 有 少 数 几 个 记 录 与 搜 索 条 件 相 匹 配, 则 其 效 率 是 相 当 低 的 如 果 我 们 为 年 龄 列 创 建 一 个 索 引, 注 意 这 里 的 索 引 所 采 用 的 值 是 排 序 的 : 假 如 我 们 要 查 找 年 龄 为 13 岁 的 所 有 人 员, 那 么 可 以 扫 描 索 引, 结 果 得 出 前 3 行, 当 到 达 年 龄 为 14 的 行 的 时 候, 我 们 发 现 它 是 一 个 比 我 们 正 在 查 找 的 年 龄 要 大 的 人 员 索 引 值 是 排 序 的, 因 此 在 读 到 包 含 14 的 记 录 时, 我 们 知 道 不 会 再 有 匹 配 的 记 录, 可 以 退 出 了 如 果 查 找 一 个 值, 它 在 索 引 表 中 某 个 中 间 点 以 前 不 会 出 现, 那 么 也 有 找 到 其 第 一 个 匹 配 索 引 项 的 定 位 算 法, 而 不 用 进 行 表 的 顺 序 扫 描 ( 如 二 分 查 找 法 ) 这 样, 可 以 快 速 定 位 到 第 一 个 匹 配 的 值, 以 节 省 大 量 搜 索 时 间 可 以 把 索 引 想 像 成 汉 语 字 典 的 的 按 笔 画 查 找 的 目 录 汉 语 字 典 中 的 汉 字 是 按 拼 音 的 顺 序 排 列 在 书 页 中 的, 如 果 要 查 询 笔 画 数 为 18 的 汉 字 的 话 就 必 须 挨 个 查 找 每 个 汉 字 来 比 较 每 个 汉 字 的 笔 画 数, 这 种 速 度 是 让 人 无 法 忍 受 的 而 如 果 我 们 创 建 一 个 按 笔 画 查 找 的 目 录 : 将 笔 画 为 5 的 汉 字 列 出 来, 将 笔 画 为 6 的 汉 字 列 出 来, 这 样 当 我 们 要 查 询 笔 画 数 为 18 的 汉 字 的 话 只 要 来 查 找 这 个 目 录 就 可 以 非 常 快 速 的 查 找 到 需 要 的 数 据 了 虽 然 索 引 可 以 提 高 数 据 查 询 的 速 度, 但 是 任 何 事 物 都 是 双 刃 剑, 它 也 有 一 些 缺 点 : 索 引 占 据 一 定 磁 盘 空 间, 就 像 有 按 笔 画 查 找 的 目 录 的 书 会 比 没 有 这 种 目 录 的 书 页 数 要 多 一 些 索 引 减 慢 了 数 据 插 入 和 删 除 的 速 度 因 为 每 次 插 入 和 删 除 的 时 候 都 需 要 更 新 索 引, 一 个 表 拥 有 的 索 引 越 多, 则 写 操 作 的 平 均 性 能 下 降 就 越 大 1.2.8 表 关 联 我 们 来 为 货 物 建 一 张 表, 其 中 包 含 规 格 名 称 生 产 厂 家 等 等 信 息, 如 下 :
编 号 名 称 规 格 生 产 厂 家 厂 家 地 址 厂 家 电 话 001 生 肉 优 质 七 侠 镇 肉 联 西 凉 河 路 3 5555-123456 厂 号 002 玉 米 肠 简 装 七 侠 镇 肉 联 西 凉 河 路 3 5555-123456 厂 号 003 尿 素 60 公 斤 装 六 扇 门 化 工 汉 中 工 业 区 5555-654321 厂 004 打 印 纸 16 开 钱 氏 纸 业 县 政 府 对 过 5555-123654 005 磷 酸 二 铵 30 公 斤 装 六 扇 门 化 工 汉 中 工 业 区 5555-654321 厂 可 以 看 到 这 里 存 在 大 量 冗 余 信 息, 比 如 厂 家 的 名 称 地 址 电 话 等 就 在 表 中 重 复 多 次, 这 会 带 来 如 下 的 问 题 : 信 息 冗 余 占 据 空 间 数 据 的 存 储 是 占 据 一 定 的 空 间 的, 如 果 存 在 过 多 冗 余 信 息 将 会 使 得 存 储 系 统 的 利 用 率 过 低 信 息 冗 余 使 得 新 数 据 的 加 入 变 得 麻 烦 每 次 录 入 新 的 货 物 的 话 必 须 把 厂 家 地 址 厂 家 电 话 等 信 息 重 新 录 入 一 次 信 息 冗 余 使 得 维 护 数 据 的 正 确 性 变 得 困 难 如 果 七 侠 镇 肉 联 厂 迁 址 了, 那 么 必 须 将 表 中 所 有 七 侠 镇 肉 联 厂 的 厂 家 地 址 都 要 更 新 一 遍 解 决 的 方 法 就 是 即 将 厂 家 的 信 息 在 一 个 新 的 表 中 维 护 我 们 创 建 下 边 的 厂 家 表 : 厂 家 编 号 厂 家 名 称 厂 家 地 址 厂 家 电 话 001 七 侠 镇 肉 联 厂 西 凉 河 路 3 号 5555-123456 002 六 扇 门 化 工 厂 汉 中 工 业 区 5555-654321 003 钱 氏 纸 业 县 政 府 对 过 5555-123654 这 里 我 们 为 每 个 厂 家 指 定 了 一 个 厂 家 编 号 做 为 主 键, 这 个 编 号 就 可 以 唯 一 标 识 一 个 厂 家 有 了 厂 家 信 息 表, 货 物 表 就 可 以 修 改 成 如 下 的 新 的 格 式 了 : 编 号 名 称 规 格 生 产 厂 家 编 号 001 生 肉 优 质 001 002 玉 米 肠 简 装 001 003 尿 素 60 公 斤 装 002 004 打 印 纸 16 开 003 005 磷 酸 二 铵 30 公 斤 装 002 在 货 物 表 中 只 保 留 了 指 向 厂 家 表 的 主 键 的 字 段 生 产 厂 家 编 号, 这 样 就 避 免 了 数 据 冗 余 的 问 题 当 进 行 查 询 的 时 候, 只 要 根 据 生 产 厂 家 编 号 到 厂 家 信 息 表 中 查 询 就 可 以 知 道 厂 家 的 详 细 信 息 了 ; 当 厂 家 迁 址 的 时 候, 只 要 修 改 厂 家 信 息 表 中 的 一 条 数 据 就 可 以 了 这 种 将 两 张 表 通 过 字 段 关 联 起 来 的 方 式 就 被 称 为 表 关 联, 关 联 到 其 他 表 主 键 的 字 段 被 称 为 外 键, 上 边 例 子 中 货 物 表 中 的 生 产 厂 家 编 号 字 段 就 是 外 键 表 关 联 也 是 关 系 数 据 库 的 核 心 理 念, 它 使 得 数 据 库 中 的 数 据 不 再 互 相 孤 立, 通 过 表 关 联 我 们 可 以 表 达 非 常 复 杂 的 数 据 关 系 1.2.9 数 据 库 的 语 言 SQL DBMS 是 一 种 系 统 软 件, 我 们 要 与 它 交 互 的 时 候 就 必 须 使 用 某 种 语 言, 在 数 据 库 发 展 初 期 每 一 种 DBMS 都 有 自 己 的 特 有 的 语 言, 不 过 逐 渐 的 SQL 成 为 了 所 有 DBMS 都 支 持 的 主 流 语 言 SQL 是 专 为 数 据 库 而 建 立 的 操 作 命 令 集, 是 一 种 功 能 齐 全 的 数 据 库 语 言 在 使 用 它 时, 只 需 要 发 出 做 什 么 的 命 令, 怎 么 做 是 不 用 使 用 者 考 虑 的 SQL 功 能 强 大 简 单 易 学 使
用 方 便, 已 经 成 为 了 数 据 库 操 作 的 基 础, 并 且 现 在 几 乎 所 有 的 数 据 库 均 支 持 SQL SQL 的 英 文 全 称 是 Structured Query Language, 它 是 1974 年 由 Boyce 和 Chamberlin 提 出 的, 并 且 首 先 在 IBM 的 关 系 数 据 库 原 型 产 品 R 系 统 (SYSTEM R) 上 实 现 它 的 前 身 是 1972 提 出 的 SQUARE(Specifying Queries As Rela onal Expressesion ) 语 言, 在 1974 年 做 了 修 改, 并 且 改 名 为 SEQUEL(Structured English Query Language) 语 言, 后 来 SEQUEL 简 化 为 SQL SQL 是 高 级 的 非 过 程 化 编 程 语 言, 允 许 用 户 在 高 层 数 据 结 构 上 工 作 使 用 它, 用 户 无 需 指 定 对 数 据 的 存 放 方 法, 也 不 需 要 用 户 了 解 具 体 的 数 据 存 放 方 式, 所 以 具 有 完 全 不 同 底 层 结 构 的 不 同 数 据 库 系 统 可 以 使 用 相 同 的 SQL 语 言 作 为 数 据 输 入 与 管 理 的 接 口 它 以 记 录 集 合 作 为 操 纵 对 象, 所 有 SQL 语 句 接 受 集 合 作 为 输 入, 返 回 集 合 作 为 输 出, 这 种 集 合 特 性 允 许 一 条 SQL 语 句 的 输 出 作 为 另 一 条 SQL 语 句 的 输 入, 所 以 SQL 语 言 可 以 嵌 套, 这 使 它 具 有 极 大 的 灵 活 性 和 强 大 的 功 能, 在 多 数 情 况 下, 在 其 他 语 言 中 需 要 一 大 段 程 序 实 现 的 一 个 单 独 事 件 只 需 要 一 个 SQL 语 句 就 可 以 达 到 目 的, 这 也 意 味 着 用 SQL 语 言 可 以 写 出 非 常 复 杂 的 语 句 SQL 具 有 下 面 4 个 主 要 的 功 能 : 创 建 数 据 库 并 定 义 表 的 结 构 ; 查 询 需 要 的 数 据 ; 更 新 或 者 删 除 指 定 的 数 据 ; 控 制 数 据 库 的 安 全 使 用 SQL 我 们 可 以 完 成 和 DBMS 的 几 乎 所 有 交 互 任 务 比 如 我 们 要 查 找 年 龄 小 于 18 岁 的 员 工 信 息, 那 么 我 们 只 要 执 行 下 面 的 SQL 就 可 以 : SELECT * from Employees where age<18 比 如 我 们 要 将 所 有 职 位 为 名 誉 总 裁 的 员 工 删 除, 那 么 就 可 以 执 行 下 面 的 SQL: DELETE from Employees where posi on= 名 誉 总 裁 可 以 看 到 我 们 只 是 描 述 了 我 们 要 做 什 么, 至 于 怎 么 去 做 则 由 DBMS 来 决 定 可 以 想 想 如 果 要 是 自 己 编 程 去 实 现 类 似 的 功 能, 则 需 要 编 写 非 常 复 杂 的 算 法 才 能 完 成, 而 且 性 能 也 不 一 定 会 非 常 好 我 们 可 以 通 过 三 种 方 式 执 行 SQL: 在 工 具 中 执 行 各 个 DBMS 几 乎 都 提 供 了 工 具 用 于 执 行 SQL 语 句, 比 如 Microso SQL Server 的 Management Studio DB2 的 命 令 中 心 Oracle 的 SqlPlus 或 者 MySQL 的 Query Browser 在 这 些 工 具 中 我 们 只 要 输 入 要 执 行 的 SQL 然 后 点 击 执 行 按 钮 就 可 以 得 到 执 行 结 果 以 编 译 的 方 式 嵌 入 到 语 言 中 在 这 种 方 式 中 我 们 可 以 把 SQL 直 接 写 到 代 码 中, 在 编 译 的 时 候 由 编 译 器 来 决 定 和 数 据 库 的 交 互 方 式 比 如 PowerBuild C 等 就 采 用 这 种 方 式 以 字 符 串 的 形 式 嵌 入 到 语 言 中 在 这 种 方 式 中 SQL 语 句 只 是 以 字 符 串 的 形 式 写 到 代 码 中, 然 后 由 代 码 将 其 提 交 到 DBMS, 并 且 分 析 返 回 的 结 果 目 前 这 是 大 部 分 支 持 数 据 库 操 作 的 语 言 采 用 的 方 式, 比 如 C# Java Python Delphi 和 VB 等 由 于 嵌 入 到 语 言 中 的 执 行 方 式 是 严 重 依 赖 宿 主 语 言 的, 而 本 书 不 假 定 用 户 使 用 任 何 编 程 语 言, 为 了 能 够 使 得 使 用 任 何 语 言 的 读 者 都 能 学 习 本 书 中 的 知 识 点, 本 书 将 主 要 以 在 工 具 中 执 行 的 方 式 来 执 行 SQL 语 句, 读 者 可 以 根 据 自 己 使 用 的 编 程 语 言 来 灵 活 运 用 这 些 知 识 点 不 熟 悉 用 工 具 执 行 SQL 的 读 者 可 以 参 考 附 录 A 中 的 介 绍 IBM 是 SQL 语 言 的 发 明 者, 但 是 其 他 的 数 据 库 厂 商 都 在 IBM 的 SQL 基 础 上 提 出 了 自 己 的 扩 展 语 法, 因 此 形 成 了 不 同 的 SQL 语 法, 对 于 开 发 人 员 来 说, 使 用 这 些 有 差 异 的 语 法 是 非 常 头 疼 的 时 候 因 此 在 1986 年 美 国 国 家 标 准 化 协 会 (ANSI) 为 SQL 制 定 了 标 准, 并 且 在 1987 年 国 际 标 准 化 组 织 (ISO) 也 为 SQL 指 定 了 标 准, 迄 今 为 止 已 经 推 出 SQL-86 SQL-89 SQL-92 SQL-99 SQL-2003 等 版 本 的 标 准 虽 然 已 经 有 了 国 际 标 准, 但 是 由 于 种 种 原 因, 各 个 数 据 库 产 品 的 SQL 语 法 仍 然 有 着 很 大 差 异, 在 数 据 库 A 上 能 成 功 执 行 的 SQL 放 到 数 据 库 B 上 就 会 执 行 失 败 为 了 方 便 使 用 不
同 数 据 库 产 品 的 读 者 都 能 成 功 运 行 本 书 中 的 例 子, 我 们 会 介 绍 各 种 数 据 库 SQL 的 差 异 性, 并 且 给 出 解 决 方 案, 而 且 本 书 将 会 安 排 专 门 章 节 讲 解 跨 数 据 库 程 序 开 发 的 技 术 1.2.10 DBA 与 程 序 员 如 果 你 是 一 个 数 据 库 开 发 技 术 的 初 学 者 的 话, 你 会 发 现 到 了 书 店 里 有 很 多 数 据 库 相 关 的 书 你 看 不 懂, 你 会 发 现 互 联 网 有 一 些 搞 数 据 库 的 人 的 Blog 上 说 的 东 西 你 感 觉 很 陌 生, 他 们 都 是 在 谈 论 数 据 库 的 恢 复 数 据 库 的 调 优 调 整 数 据 库 的 安 全 性, 难 道 他 们 搞 的 是 更 深 层 次 的 东 西 吗? 不 是 的, 他 们 就 是 数 据 库 系 统 管 理 员 (Database Administrator,DBA) 围 绕 在 DBMS 周 围 的 技 术 人 员 有 两 类 : 数 据 库 系 统 管 理 员 和 开 发 人 员 使 用 数 据 库 进 行 程 序 开 发 的 人 员 是 程 序 员, 而 对 数 据 库 系 统 进 行 管 理 维 护 调 优 的 则 是 数 据 库 系 统 管 理 员 作 为 一 名 开 发 人 员, 我 们 不 必 知 道 如 何 安 装 和 配 置 数 据 库 系 统, 这 应 该 是 DBA 的 任 务 ; 当 规 划 数 据 库 的 备 份 策 略 的 时 候, 不 要 去 问 开 发 人 员, 这 也 是 DBA 的 任 务 ; 当 数 据 库 系 统 崩 溃 的 时 候, 请 立 即 给 DBA 打 电 话, 如 果 打 给 开 发 人 员 的 话, 你 得 到 的 回 答 通 常 是 怎 么 会 呢? 天 知 道 怎 么 恢 复! 正 如 一 个 公 司 的 网 络 系 统 是 由 网 管 来 负 责 的 一 样, 一 个 公 司 的 数 据 库 系 统 也 是 由 DBA 来 进 行 管 理 的, 它 们 的 主 要 工 作 如 下 : 安 装 和 配 置 数 据 库, 创 建 数 据 库 以 及 帐 户 ; 监 视 数 据 库 系 统, 保 证 数 据 库 不 宕 机 ; 收 集 系 统 统 计 和 性 能 信 息 以 便 进 行 调 整 ; 发 现 性 能 糟 糕 的 SQL, 并 给 开 发 人 员 提 出 调 优 建 议 ; 管 理 数 据 库 安 全 性 ; 备 份 数 据 库, 当 发 生 故 障 时 要 及 时 恢 复 ; 升 级 DBMS 并 且 在 必 要 时 为 系 统 安 装 补 丁 ; 执 行 存 储 和 物 理 设 计, 均 衡 设 计 问 题 以 完 成 性 能 优 化 ; DBA 大 部 分 时 间 是 在 监 视 系 统 备 份 / 恢 复 系 统 优 化 系 统, 而 开 发 人 员 则 无 需 精 通 这 些 技 能 ; 开 发 人 员 大 部 分 时 间 是 在 用 SQL 实 现 业 务 逻 辑 二 者 知 识 的 重 合 点 就 是 SQL, 一 个 开 发 人 员 如 果 不 熟 悉 SQL 的 话 就 无 法 很 好 的 实 现 业 务 逻 辑, 而 一 个 DBA 如 果 不 熟 悉 SQL 的 话 就 无 法 完 成 数 据 库 的 调 优 工 作 所 以 无 论 你 是 想 成 为 开 发 人 员 还 是 成 为 DBA, 那 么 都 首 先 来 学 好 SQL 吧! 进 行 数 据 库 的 备 份 / 恢 复 权 限 管 理 等 操 作 也 经 常 需 要 使 用 SQL 命 令 来 完 成, 不 过 这 些 SQL 命 令 都 是 与 特 定 的 DBMS 产 品 相 关 的, 而 且 不 同 产 品 的 使 用 方 式 也 是 差 别 很 大 的, 所 以 本 书 不 会 讲 解 数 据 库 的 备 份 / 恢 复 权 限 管 理 相 关 的 SQL, 有 兴 趣 的 读 者 可 以 去 参 考 相 关 的 资 料 第 三 章 数 据 的 增 删 改 上 一 章 中 介 绍 了 创 建 和 管 理 数 据 表 的 方 法, 数 据 表 只 是 数 据 的 容 器, 没 有 任 何 数 据 的 表 是 没 有 任 何 意 义 的 主 流 的 数 据 库 系 统 都 提 供 了 管 理 数 据 库 的 工 具, 使 用 这 些 工 具 可 以 查 看 表 中 的 数 据, 还 可 以 添 加 修 改 和 删 除 表 中 的 数 据, 但 是 使 用 工 具 进 行 数 据 的 增 删 改 通 常 只 限 于 测 试 数 据 库 时 使 用, 更 常 见 的 方 式 时 通 过 程 序 或 者 Web 页 面 来 向 数 据 库 发 出 SQL 语 句 指 令 来 进 行 这 些 操 作, 因 此 本 章 将 介 绍 通 过 SQL 语 句 增 删 改 表 中 数 据 的 方 法 本 章 中 我 们 将 使 用 一 些 数 据 表, 为 了 更 容 易 的 运 行 本 章 中 的 例 子, 必 须 首 先 创 建 所 需 要 的 数 据 表, 因 此 下 面 列 出 本 章 中 要 用 到 数 据 表 的 创 建 SQL 语 句 : MYSQL: CREATE TABLE T_Person (FName VARCHAR(20),FAge INT,FRemark VARCHAR(20),PRIMARY KEY (FName));
CREATE TABLE T_Debt (FNumber VARCHAR(20),FAmount DECIMAL(10,2) NOT NULL, MSSQLServer: FPerson VARCHAR(20),PRIMARY KEY (FNumber), FOREIGN KEY (FPerson) REFERENCES T_Person(FName)) ; CREATE TABLE T_Person (FName VARCHAR(20),FAge INT,FRemark VARCHAR(20),PRIMARY KEY (FName)); Oracle: CREATE TABLE T_Debt (FNumber VARCHAR(20),FAmount NUMERIC(10,2) NOT NULL, FPerson VARCHAR(20),PRIMARY KEY (FNumber), FOREIGN KEY (FPerson) REFERENCES T_Person(FName)) ; CREATE TABLE T_Person (FName VARCHAR2(20),FAge NUMBER (10),FRemark VARCHAR2(20),PRIMARY KEY (FName)) ; DB2: CREATE TABLE T_Debt (FNumber VARCHAR2(20),FAmount NUMERIC(10,2) NOT NULL, FPerson VARCHAR2(20),PRIMARY KEY (FNumber), FOREIGN KEY (FPerson) REFERENCES T_Person(FName)) ; CREATE TABLE T_Person (FName VARCHAR(20) NOT NULL,FAge INT,FRemark VARCHAR(20),PRIMARY KEY (FName)); NULL, CREATE TABLE T_Debt (FNumber VARCHAR(20) NOT NULL,FAmount DECIMAL(10,2) NOT FPerson VARCHAR(20),PRIMARY KEY (FNumber), FOREIGN KEY (FPerson) REFERENCES T_Person(FName)) ; 请 在 不 同 的 数 据 库 系 统 中 运 行 相 应 的 SQL 语 句 T_Person 为 记 录 人 员 信 息 的 数 据 表, 其 中 主 键 字 段 FName 为 人 员 姓 名,FAge 为 年 龄, 而 FRemark 则 为 备 注 信 息 ;T_Debt 记 录 了 债 务 信 息, 其 中 主 键 字 段 FNumber 为 债 务 编 号,FAmount 为 欠 债 金 额,FPerson 字 段 为 欠 债 人 姓 名,FPerson 字 段 与 T_Person 中 的 FName 字 段 建 立 了 外 键 关 联 关 系 3.1 数 据 的 插 入 数 据 表 是 数 据 的 容 器, 没 有 任 何 数 据 的 数 据 表 是 没 有 意 义 的, 数 据 表 创 建 完 成 以 后 比 如 向 其 中 插 入 有 用 的 数 据 才 能 使 得 系 统 运 转 起 来 3.1.1 简 单 的 INSERT 语 句 INSERT INTO 语 句 用 来 向 数 据 表 中 插 入 数 据, 比 如 执 行 下 面 的 语 句 就 可 以 向 T_Person 表 中 插 入 一 条 数 据 : INSERT INTO T_Person(FName,FAge,FRemark) VALUES('Tom',18,'USA') 1 这 句 SQL 向 T_Person 表 中 插 入 了 一 条 数 据, 其 中 FName 字 段 的 值 为 'Tom',FAge 字 段 的 值 为 18, 而 FRemark 字 段 的 值 为 'USA' VALUES 前 边 的 括 号 中 列 出 的 是 要 设 置 字 段 的 字 段 名, 字 段 名 之 间 用 逗 号 隔 开 ;VALUES 后 边 的 括 号 中 列 出 的 是 要 设 置 字 段 的 值, 各 个 值 同 样 用 逗 号 隔 开 需 要 注 意 的 是 VALUES 前 列 出 的 字 段 名 和 VALUES 后 边 列 出 的 字 段 值 是 按 顺 序 一 一 对 应 的, 也 就 是 第 一 个 值 'Tom' 设 置 的 是 字 段 FName 的 值, 第 二 个 值 18 设 置 的 是 字 段 FAge 的 值, 第 三 个 值 'USA' 设 置 的 是 字 段 FRemark 的 值, 不 能 打 乱 它 们 之 间 的 对 应 关 系, 而 且 要 保 证 两 边 的 条 数 是 一 致 的 由 于 FName 和 FRemark 字 段 是 字 符 串 类 型 的, 所 以 需 要 用 单 引 2 号 将 值 包 围 起 来, 而 整 数 类 型 的 FAge 字 段 的 值 则 不 需 要 用 单 引 号 包 围 起 来 1 需 要 注 意, 这 里 的 单 引 号 是 半 角 字 符, 如 果 使 用 全 角 字 符 将 会 导 致 执 行 错 误 2 有 的 数 据 库 系 统 也 支 持 用 双 引 号 来 包 围, 不 过 为 了 使 得 我 们 编 写 的 SQL 更 容 易 的 在 主 流 数 据 库 系 统 中 运 行, 本 书 将 一 律 采 用 单 引 号 来 包 围 字 符 串 类 型 数 据
我 们 来 检 验 一 下 数 据 是 否 真 的 插 入 数 据 表 中 了, 执 行 下 面 的 SQL 语 句 : SELECT * FROM T_Person 3 执 行 完 毕 我 们 将 会 看 到 如 下 的 输 出 结 果 ( 在 不 同 的 数 据 库 系 统 以 及 管 理 工 具 下 的 显 示 效 果 会 略 有 不 同 ): FName FAge FRemark Tom 18 USA 可 以 看 到 插 入 的 数 据 已 经 保 存 在 T_Person 表 中 了, 我 们 还 可 以 运 行 多 条 SQL 语 句 来 插 入 多 条 数 据 : INSERT INTO T_Person(FName,FAge,FRemark) VALUES('Jim',20,'USA'); INSERT INTO T_Person(FName,FAge,FRemark) VALUES('Lili',22,'China') ; INSERT INTO T_Person(FName,FAge,FRemark) VALUES('XiaoWang',17,' China ') ; 再 次 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 : FNAME FAGE FREMARK Tom 18 USA Jim 20 USA Lili 22 China XiaoWang 17 China INSERT 语 句 中 列 的 顺 序 可 以 是 任 意 的, 比 如 我 们 也 可 以 用 下 面 的 SQL 来 插 入 数 据 : INSERT INTO T_Person(FAge,FName,FRemark) VALUES(21,'Kimisushi','Korea') 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 : FNAME FAGE FREMARK Tom 18 USA Jim 20 USA Lili 22 China XiaoWang 17 China Kimisushi 21 Korea 可 见 INSET 语 句 中 列 的 顺 序 不 会 影 响 数 据 插 入 的 结 果 3.1.2 简 化 的 INSERT 语 句 INSERT 语 句 中 也 并 不 需 要 我 们 指 定 表 中 的 所 有 列, 比 如 在 插 入 数 据 的 时 候 某 些 字 段 没 有 值, 我 们 可 以 忽 略 这 些 字 段 下 面 我 们 插 入 一 条 没 有 备 注 信 息 的 数 据 : INSERT INTO T_Person(FAge,FName) VALUES(22,'LXF') 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 : FName FAge FRemark Tom 18 USA Jim 20 USA Lili 22 China XiaoWang 17 China Kimisushi 21 Korea LXF 22 <NULL> INSERT 语 句 还 有 另 一 种 用 法, 可 以 不 用 指 定 要 插 入 的 表 列, 这 种 情 况 下 将 按 照 定 义 表 中 字 段 顺 序 来 进 行 插 入, 我 们 执 行 下 面 的 SQL: INSERT INTO T_Person VALUES('luren1',23,'China') 3 先 不 用 管 这 句 SQL 语 句 的 具 体 语 法, 只 要 知 道 它 是 用 来 查 看 表 T_Person 中 的 数 据 即 可
这 里 省 略 了 VALUES 前 面 的 字 段 定 义,VALUES 后 面 的 值 列 表 中 按 照 CREATE TABLE 语 句 中 的 顺 序 排 列 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 : FNAME FAGE FREMARK Tom 18 USA Jim 20 USA Lili 22 China XiaoWang 17 China Kimisushi 21 Korea LXF 22 <NULL> luren1 23 China 这 种 省 略 字 段 列 表 的 方 法 可 以 简 化 输 入, 不 过 我 们 推 荐 这 种 用 法, 因 为 省 略 字 段 列 表 之 后 就 无 法 很 容 易 的 弄 清 楚 值 列 表 中 各 个 值 到 底 对 应 哪 个 字 段 了, 非 常 容 易 导 致 程 序 出 现 BUG 并 且 给 程 序 的 调 试 带 来 非 常 大 的 麻 烦 3.1.3 非 空 约 束 对 数 据 插 入 的 影 响 正 如 非 空 约 束 表 达 的 意 思, 如 果 对 一 个 字 段 添 加 了 非 空 约 束, 那 么 我 们 是 不 能 向 这 个 字 段 中 插 入 NULL 值 的 T_Debt 表 的 FAmount 字 段 是 有 非 空 约 束 的, 如 果 我 们 执 行 下 面 SQL: INSERT INTO T_Debt (FNumber, FPerson) VALUES ('1', 'Jim') 这 句 SQL 中 没 有 为 字 段 FAmount 赋 值, 也 就 是 说 FAmount 为 空 值 我 们 执 行 这 句 SQL 以 后 数 据 库 系 统 会 报 出 类 似 如 下 的 错 误 信 息 : 败 不 能 将 值 NULL 插 入 列 'FAmount', 表 'demo.dbo.t_debt'; 列 不 允 许 有 空 值 INSERT 失 如 果 我 们 为 FAmount 设 置 非 空 值 的 话, 则 会 插 入 成 功, 执 行 下 面 的 SQL: INSERT INTO T_Debt (FNumber,FAmount, FPerson) VALUES ('1',200, 'Jim') 此 句 SQL 则 可 以 正 常 的 执 行 成 功 执 行 SELECT * FROM T_Debt 来 查 看 表 中 的 数 据 : FNumber FAmount FPerson 1 200.00 Jim 可 以 看 到 数 据 已 经 被 正 确 的 插 入 到 表 中 了 3.1.3 主 键 对 数 据 插 入 的 影 响 主 键 是 在 同 一 张 表 中 必 须 是 唯 一 的, 如 果 在 进 行 数 据 插 入 的 时 候 指 定 的 主 键 与 表 中 已 有 的 数 据 重 复 的 话 则 会 导 致 违 反 主 键 约 束 的 异 常 T_Debt 表 中 FNumber 字 段 是 主 键, 如 果 我 们 执 行 下 面 SQL: INSERT INTOT_Debt (FNumber,FAmount,FPerson) VALUES ('1',300, 'Jim') 由 于 在 上 一 节 中 我 们 已 经 向 表 中 插 入 了 一 条 FNumber 字 段 为 1 的 记 录, 所 以 运 行 这 句 SQL 的 时 候 会 报 出 类 似 如 下 的 错 误 信 息 : 不 能 在 对 象 'dbo.t_debt' 中 插 入 重 复 键 而 如 果 我 们 为 FNumber 设 置 一 个 不 重 复 值 的 话, 则 会 插 入 成 功, 执 行 下 面 的 SQL: INSERT INTOT_Debt (FNumber,FAmount,FPerson) VALUES ('2',300, 'Jim') 此 句 SQL 则 可 以 正 常 的 执 行 成 功 执 行 SELECT * FROM T_Debt 来 查 看 表 中 的 数 据 : FNumber FAmount FPerson 1 200.00 Jim 2 300.00 Jim 可 以 看 到 数 据 已 经 被 正 确 的 插 入 到 表 中 了 3.1.4 外 键 对 数 据 插 入 的 影 响
外 键 是 指 向 另 一 个 表 中 已 有 数 据 的 约 束, 因 此 外 键 值 必 须 是 在 目 标 表 中 存 在 的 如 果 插 入 的 数 据 在 目 标 表 中 不 存 在 的 话 则 会 导 致 违 反 外 键 约 束 异 常 T_Debt 表 中 FPerson 字 段 是 指 向 表 T_Person 的 FName 字 段 的 外 键, 如 果 我 们 执 行 下 面 SQL: INSERT INTO T_Debt (FNumber,FAmount, FPerson) VALUES ('3',100, 'Jerry') 由 于 在 T_Person 表 中 不 存 在 FName 字 段 等 于 Jerry 的 数 据 行, 所 以 会 数 据 库 系 统 会 报 出 类 似 如 下 的 错 误 信 息 : INSERT 语 句 与 FOREIGN KEY 约 束 "FK T_Debt FPerson 1A14E395" 冲 突 该 冲 突 发 生 于 数 据 库 "demo", 表 "dbo.t_person", column 'FName' 而 如 果 我 们 为 FPerson 字 段 设 置 已 经 在 T_Person 表 中 存 在 的 FName 字 段 值 的 话 则 会 插 入 成 功, 执 行 下 面 的 SQL: INSERT INTO T_Debt (FNumber,FAmount, FPerson) VALUES ('3',100, 'Tom') 此 句 SQL 则 可 以 正 常 的 执 行 成 功 执 行 SELECT * FROM T_Debt 来 查 看 表 中 的 数 据 : FNumber FAmount FPerson 1 200.00 Jim 2 300.00 Jim 3 100.00 Tom 可 以 看 到 数 据 已 经 被 正 确 的 插 入 到 表 中 了 3.2 数 据 的 更 新 录 入 到 数 据 表 中 的 数 据 很 少 有 一 成 不 变 的, 随 着 系 统 的 运 行 经 常 需 要 更 新 表 中 的 某 些 数 据, 比 如 Tom 的 家 庭 住 址 变 化 了 我 们 就 要 在 数 据 库 中 将 他 的 家 庭 住 址 更 新 新 年 度 到 来 的 时 候 我 们 就 要 将 所 有 人 员 的 年 龄 增 加 一 岁, 类 似 需 求 都 要 求 对 数 据 库 中 现 有 的 数 据 进 行 更 新 3.2.1 简 单 的 数 据 更 新 UPDATE 语 句 用 来 对 数 据 表 中 的 数 据 进 行 更 新 下 边 的 语 句 用 来 将 表 T_Person 中 所 有 人 员 的 FREMARK 字 段 值 更 新 为 SuperMan : UPDATE T_Person SET FRemark = 'SuperMan' 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 : FName FAge FRemark Jim 20 SuperMan Kimisushi 21 SuperMan Lili 22 SuperMan luren1 23 SuperMan LXF 22 SuperMan Tom 18 SuperMan XiaoWang 17 SuperMan 可 以 看 到 所 有 行 的 FRemark 字 段 值 都 被 设 置 成 了 SuperMan 来 看 一 下 刚 才 执 行 的 SQL 语 句, 首 先 它 声 明 了 要 更 新 的 表 为 T_Person: UPDATE T_Person 在 SET 子 句 中, 我 们 指 定 将 FRemark 字 段 更 新 为 新 值 'SuperMan': SET FRemark = 'SuperMan' 我 们 还 可 以 在 SET 语 句 中 定 义 多 个 列, 这 样 就 可 以 实 现 多 列 同 时 更 新 了, 比 如 下 面 的 UPDATE 语 句 用 来 将 所 有 人 员 的 FRemark 字 段 更 新 为 Sonic, 并 且 将 年 龄 更 新 为 25: UPDATE T_Person SET FRemark = 'Sonic',
FAge=25 多 个 列 之 间 需 要 使 用 逗 号 分 隔 开 执 行 完 此 SQL 语 句 后 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 的 变 化 : FName FAge FRemark Jim 25 Sonic Kimisushi 25 Sonic Lili 25 Sonic luren1 25 Sonic LXF 25 Sonic Tom 25 Sonic XiaoWang 25 Sonic 3.2.2 带 WHERE 子 句 的 UPDATE 语 句 目 前 演 示 的 几 个 UPDATE 语 句 都 是 一 次 性 更 新 所 有 行 的 数 据, 这 无 法 满 足 只 更 新 符 合 特 定 条 件 的 行 的 需 求, 比 如 将 Tom 的 年 龄 修 改 为 12 岁 要 实 现 这 样 的 功 能 只 要 使 用 WHERE 子 句 就 可 以 了, 在 WHERE 语 句 中 我 们 设 定 适 当 的 过 滤 条 件, 这 样 UPDATE 语 句 只 会 更 新 符 合 WHERE 子 句 中 过 滤 条 件 的 行, 而 其 他 行 的 数 据 则 不 被 修 改 执 行 下 边 的 UPDATE 语 句 : UPDATE T_Person SET FAge = 12 WHERE FNAME='Tom' 执 行 完 此 SQL 语 句 后 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 的 变 化 : FName FAge FRemark Jim 25 Sonic Kimisushi 25 Sonic Lili 25 Sonic luren1 25 Sonic LXF 25 Sonic Tom 12 Sonic XiaoWang 25 Sonic 可 以 看 到 只 有 第 一 行 中 的 FAGE 被 更 新 了 WHERE 子 句 WHERE FNAME='Tom' 表 示 我 们 只 更 新 FNAME 字 段 等 于 'Tom' 的 行 由 于 FNAME 字 段 等 于 'Tom' 的 只 有 一 行, 所 以 仅 有 一 行 记 录 被 更 新, 但 是 如 果 有 多 个 符 合 条 件 的 行 的 话 将 会 有 多 行 被 更 新, 比 如 下 面 UPDATE 语 句 将 所 有 年 龄 为 25 的 人 员 的 备 注 信 息 修 改 为 BlaBla : UPDATE T_Person SET FRemark = 'BlaBla' WHERE FAge =25 执 行 完 此 SQL 语 句 后 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 的 变 化 : FName FAge FRemark Jim 25 BlaBla Kimisushi 25 BlaBla Lili 25 BlaBla luren1 25 BlaBla LXF 25 BlaBla
Tom 12 Sonic XiaoWang 25 BlaBla 目 前 为 止 我 们 演 示 的 都 是 非 常 简 单 的 WHERE 子 句, 我 们 可 以 使 用 复 杂 的 WHERE 语 句 来 满 足 更 加 复 杂 的 需 求, 比 如 下 面 的 UPDATE 语 句 就 用 来 将 FNAME 等 于 Jim 或 者 LXF 的 行 的 FAge 字 段 更 新 为 22: UPDATE T_Person SET FAge = 22 WHERE FName ='jim' OR FName='LXF' 执 行 完 此 SQL 语 句 后 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 的 变 化 : FName FAge FRemark Jim 22 BlaBla Kimisushi 25 BlaBla Lili 25 BlaBla luren1 25 BlaBla LXF 22 BlaBla Tom 12 Sonic XiaoWang 25 BlaBla 这 里 我 们 使 用 OR 逻 辑 运 算 符 来 组 合 两 个 条 件 来 实 现 复 杂 的 过 滤 逻 辑, 我 们 还 可 以 使 用 OR NOT 等 运 算 符 实 现 更 加 复 杂 的 逻 辑, 甚 至 能 够 使 用 模 糊 查 询 子 查 询 等 实 现 高 级 的 数 据 过 滤, 关 于 这 些 知 识 我 们 将 在 后 面 的 章 节 专 门 介 绍 3.2.3 非 空 约 束 对 数 据 更 新 的 影 响 正 如 非 空 约 束 表 达 的 意 思, 如 果 对 一 个 字 段 添 加 了 非 空 约 束, 那 么 我 们 是 不 能 将 这 个 字 段 中 的 值 更 新 为 NULL 的 T_Debt 表 的 FAmount 字 段 是 有 非 空 约 束 的, 如 果 我 们 执 行 下 面 SQL: UPDATE T_Debt set FAmount = NULL WHERE FPerson='Tom' 这 句 SQL 为 FAmount 设 置 空 值 我 们 执 行 这 句 SQL 以 后 数 据 库 系 统 会 报 出 类 似 如 下 的 错 误 信 息 : 败 不 能 将 值 NULL 插 入 列 'FAmount', 表 'demo.dbo.t_debt'; 列 不 允 许 有 空 值 UPDATE 失 如 果 我 们 为 FAmount 设 置 非 空 值 的 话, 则 会 插 入 成 功, 执 行 下 面 的 SQL: UPDATE T_Debt set FAmount =123 WHERE FPerson='Tom' 此 句 SQL 则 可 以 正 常 的 执 行 成 功 执 行 SELECT * FROM T_Debt 来 查 看 表 中 的 数 据 : FNumber FAmount FPerson 1 200.00 Jim 2 300.00 Jim 3 123.00 Tom 可 以 看 到 数 据 已 经 被 正 确 的 更 新 到 表 中 了 3.2.3 主 键 对 数 据 更 新 的 影 响 主 键 是 在 同 一 张 表 中 必 须 是 唯 一 的, 如 果 在 进 行 数 据 更 新 的 时 候 指 定 的 主 键 与 表 中 已 有 的 数 据 重 复 的 话 则 会 导 致 违 反 主 键 约 束 的 异 常 T_Debt 表 中 FNumber 字 段 是 主 键, 如 果 我 们 执 行 下 面 SQL: UPDATE T_Debt set FNumber = '2' WHERE FPerson='Tom' 由 于 表 中 已 经 存 在 一 条 FNumber 字 段 为 2 的 记 录, 所 以 运 行 这 句 SQL 的 时 候 会 报 出 类 似 如 下 的 错 误 信 息 :
违 反 了 PRIMARY KEY 约 束 'PK T_Debt 1920BF5C' 不 能 在 对 象 'dbo.t_debt' 中 插 入 重 复 键 而 如 果 我 们 为 FNumber 设 置 一 个 不 重 复 值 的 话, 则 会 插 入 成 功, 执 行 下 面 的 SQL: UPDATE T_Debt set FNumber = '8' WHERE FPerson='Tom' 此 句 SQL 则 可 以 正 常 的 执 行 成 功 执 行 SELECT * FROM T_Debt 来 查 看 表 中 的 数 据 : FNumber FAmount FPerson 1 200.00 Jim 2 300.00 Jim 8 123.00 Tom 可 以 看 到 数 据 已 经 被 正 确 的 更 新 到 表 中 了 3.2.4 外 键 对 数 据 更 新 的 影 响 外 键 是 指 向 另 一 个 表 中 已 有 数 据 的 约 束, 因 此 外 键 值 必 须 是 在 目 标 表 中 存 在 的 如 果 更 新 后 的 数 据 在 目 标 表 中 不 存 在 的 话 则 会 导 致 违 反 外 键 约 束 异 常 T_Debt 表 中 FPerson 字 段 是 指 向 表 T_Person 的 FName 字 段 的 外 键, 如 果 我 们 执 行 下 面 SQL: UPDATE T_Debt set FPerson = 'Merry' WHERE FNumber='1' 由 于 在 T_Person 表 中 不 存 在 FName 字 段 等 于 Merry 的 数 据 行, 所 以 会 数 据 库 系 统 会 报 出 类 似 如 下 的 错 误 信 息 : UPDATE 语 句 与 FOREIGN KEY 约 束 "FK T_Debt FPerson 1A14E395" 冲 突 该 冲 突 发 生 于 数 据 库 "demo", 表 "dbo.t_person", column 'FName' 而 如 果 我 们 为 FPerson 字 段 设 置 已 经 在 T_Person 表 中 存 在 的 FName 字 段 值 的 话 则 会 插 入 成 功, 执 行 下 面 的 SQL: UPDATE T_Debt set FPerson = 'Lili' WHERE FNumber='1' 此 句 SQL 则 可 以 正 常 的 执 行 成 功 执 行 SELECT * FROM T_Debt 来 查 看 表 中 的 数 据 : FNumber FAmount FPerson 1 200.00 Lili 2 300.00 Jim 8 123.00 Tom 可 以 看 到 数 据 已 经 被 正 确 的 更 新 到 表 中 了 3.3 数 据 的 删 除 数 据 库 中 的 数 据 一 般 都 有 一 定 的 生 命 周 期, 当 数 据 不 再 需 要 的 时 候 我 们 就 要 将 其 删 除, 执 行 DELETE 语 句 就 可 以 将 数 据 从 表 中 删 除 不 过 需 要 注 意 的 就 是 如 果 被 删 除 的 数 据 行 是 某 个 外 键 关 联 关 系 中 的 被 引 用 数 据 的 话, 则 进 行 删 除 的 时 候 会 失 败, 如 果 要 删 除 成 功 则 必 须 首 先 删 除 引 用 者 才 可 以 3.3.1 简 单 的 数 据 删 除 删 除 数 据 的 SQL 语 句 非 常 简 单, 我 们 只 要 指 定 要 删 除 的 表 就 可 以 了, 比 如 我 们 要 将 T_Debt 和 T_Person 表 中 的 数 据 删 除, 那 么 执 行 下 面 的 SQL 语 句 即 可 : DELETE FROM T_Debt; DELETE FROM T_Person; 由 于 T_Debt 表 中 FPerson 字 段 是 指 向 表 T_Person 的 FName 字 段 的 外 键, 所 以 必 须 首 先 删 除 T_Debt 表 中 的 数 据 后 才 能 删 除 T_Person 中 的 数 据 执 行 SELECT * FROM T_Debt 查 看 T_Debt 表 中 的 数 据 变 化 : FNumber FAmount FPerson 执 行 完 此 SQL 语 句 后 执 行 SELECT * FROM T_Person 来 查 看 T_Person 表 中 的 数 据 变 化 : FName FAge FRemark 可 以 见 表 中 所 有 的 数 据 行 都 被 删 除 了,T_Debt 和 T_Person 中 没 有 任 何 数 据 初 学 者 往 往 容 易 把 DROP TABLE 语 句 和 DELETE 混 淆, 虽 然 二 者 名 字 中 都 有 删 除 两 个
字, 不 过 DELETE 语 句 仅 仅 是 删 除 表 中 的 数 据 行, 而 表 的 结 构 还 存 在, 而 DROP TABLE 语 句 则 不 仅 将 表 中 的 数 据 行 全 部 删 除, 而 且 还 将 表 的 结 构 也 删 除 可 以 形 象 的 比 喻 成 DELETE 语 句 仅 仅 是 吃 光 碗 里 的 饭, 而 DROP TABLE 语 句 则 是 吃 光 碗 里 的 饭 还 将 碗 砸 碎 如 果 我 们 执 行 DROP TABLE T_Person 的 话, 那 么 再 次 执 行 SELECT * FROM T_Person 的 时 候 数 据 库 系 统 就 会 报 告 数 据 表 T_Person 不 存 在 上 边 介 绍 的 DELETE 语 句 将 表 中 的 所 有 数 据 都 删 除 了, 如 果 我 们 只 想 删 除 我 们 指 定 的 数 据 行 怎 么 办 呢? 和 UPDATE 语 句 类 似,DELETE 语 句 也 提 供 了 WHERE 语 句 进 行 数 据 的 过 滤, 这 样 只 有 符 合 过 滤 条 件 的 数 据 行 才 会 被 删 除 3.3.2 带 WHERE 子 句 的 DELETE 语 句 由 于 前 面 我 们 执 行 DELETE FROM T_Person 语 句 将 数 据 表 T_Person 中 的 数 据 全 部 删 除 了, 为 了 演 示 带 WHERE 子 句 的 DELETE 语 句, 我 们 需 要 重 新 插 入 一 些 数 据 到 T_Person 中 请 执 行 下 面 的 SQL 语 句 : INSERT INTO T_Person(FName,FAge,FRemark) VALUES('Jim',20,'USA'); INSERT INTO T_Person(FName,FAge,FRemark) VALUES('Lili',22,'China') ; INSERT INTO T_Person(FName,FAge,FRemark) VALUES('XiaoWang',17,' China ') ; INSERT INTO T_Person(FName,FAge,FRemark) VALUES('Sam',16,'China') ; INSERT INTO T_Person(FName,FAge,FRemark) VALUES('BlueFin',12,'Mars') ; 执 行 完 此 SQL 语 句 后 执 行 SELECT * FROM T_Person 来 查 看 T_Person 表 中 新 插 入 的 数 据 : FNAME FAGE FREMARK Jim 20 USA Lili 22 China XiaoWang 17 China Sam 16 China BlueFin 12 Mars 我 们 要 删 除 年 龄 大 于 20 岁 或 者 来 自 火 星 (Mars) 的 人 员, 因 此 使 用 带 复 合 逻 辑 WHERE 子 句, 如 下 : DELETE FROM T_Person WHERE FAge > 20 or FRemark = 'Mars' 执 行 完 此 SQL 语 句 后 执 行 SELECT * FROM T_Person 来 查 看 表 中 的 数 据 的 变 化 : FNAME FAGE FREMARK Jim 20 USA XiaoWang 17 China Sam 16 China 可 以 看 到 年 龄 为 22 岁 的 Lili 和 来 自 火 星 的 BlueFin 被 删 除 了 本 章 已 经 结 束, 我 们 不 再 需 要 T_Person T_Debt 这 两 张 表, 因 此 需 要 将 它 们 删 除, 执 行 下 面 的 SQL 即 可 : DROP TABLE T_Debt; DROP TABLE T_Person; 第 四 章 数 据 的 检 索 到 目 前 为 止, 我 们 已 经 学 习 了 如 何 创 建 数 据 表 如 何 修 改 数 据 表 以 及 如 何 删 除 数 据 表, 我 们 还 学 习 了 如 何 将 数 据 插 入 数 据 表 如 何 更 新 数 据 表 中 的 数 据 以 及 如 何 数 据 删 除 创 建 数 据 表 是 在 创 建 存 放 数 据 的 容 器, 修 改 和 删 除 数 据 表 是 在 维 护 数 据 模 型 的 正 确 性, 将 数 据 插 入
数 据 表 更 新 数 据 表 以 及 删 除 数 据 表 中 的 数 据 则 是 在 维 护 数 据 库 中 数 据 与 真 实 业 务 数 据 之 间 的 同 步, 这 些 操 作 都 不 是 经 常 发 生 的, 它 们 只 占 据 数 据 库 操 作 中 很 小 的 一 部 分, 我 们 大 部 分 时 间 都 是 在 对 数 据 库 中 的 数 据 进 行 检 索, 并 且 基 于 检 索 结 果 进 行 响 应 的 分 析, 可 以 说 数 据 的 检 索 是 数 据 库 中 最 重 要 的 功 能 与 数 据 表 结 构 的 管 理 以 及 数 据 表 中 数 据 的 管 理 不 同, 数 据 检 索 所 需 要 面 对 的 问 题 是 非 常 复 杂 的, 不 仅 要 求 能 够 完 成 检 索 出 所 有 年 龄 小 于 12 岁 的 学 生 检 索 出 所 有 旷 工 时 间 超 过 3 天 的 职 工 等 简 单 的 检 索 任 务, 而 且 还 要 完 成 检 索 出 本 季 度 每 种 商 品 的 出 库 入 库 详 细 情 况 检 索 出 所 有 学 生 家 长 的 工 作 单 位 信 息 等 复 杂 的 任 务, 甚 至 还 需 要 完 成 其 他 更 加 复 杂 的 检 索 任 务 数 据 检 索 面 对 的 场 景 是 异 常 复 杂 的, 因 此 数 据 检 索 的 语 法 也 是 其 他 功 能 所 不 能 比 的, 不 仅 语 法 规 则 非 常 复 杂, 而 且 使 用 方 式 也 非 常 灵 活 本 书 中 大 部 分 内 容 都 是 讲 解 数 据 检 索 相 关 知 识 的, 为 了 降 低 学 习 的 梯 度, 本 章 我 们 将 讲 解 基 本 的 数 据 检 索 语 法, 这 些 语 法 是 数 据 检 索 功 能 中 最 基 础 也 是 最 核 心 的 部 分, 因 此 只 有 掌 握 我 们 才 能 继 续 学 习 更 加 复 杂 的 应 用 本 章 中 我 们 将 使 用 一 些 数 据 表, 为 了 更 容 易 的 运 行 本 章 中 的 例 子, 必 须 首 先 创 建 所 需 要 的 数 据 表, 因 此 下 面 列 出 本 章 中 要 用 到 数 据 表 的 创 建 SQL 语 句 : MYSQL: CREATE TABLE T_Employee (FNumber VARCHAR(20),FName VARCHAR(20),FAge INT,FSalary DECIMAL(10,2),PRIMARY KEY (FNumber)) MSSQLServer: CREATE TABLE T_Employee (FNumber VARCHAR(20),FName VARCHAR(20),FAge INT,FSalary NUMERIC(10,2),PRIMARY KEY (FNumber)) Oracle: CREATE TABLE T_Employee (FNumber VARCHAR2(20),FName VARCHAR2(20),FAge NUMBER (10),FSalary NUMERIC(10,2),PRIMARY KEY (FNumber)) DB2: CREATE TABLE T_Employee (FNumber VARCHAR(20) NOT NULL,FName VARCHAR(20),FAge INT,FSalary DECIMAL(10,2),PRIMARY KEY (FNumber)) 请 在 不 同 的 数 据 库 系 统 中 运 行 相 应 的 SQL 语 句 T_Employee 为 记 录 员 工 信 息 的 数 据 表, 其 中 主 键 字 段 FNumber 为 员 工 工 号,FName 为 人 员 姓 名,FAge 为 年 龄,FSalary 为 员 工 月 工 资 为 了 更 加 直 观 的 验 证 本 章 中 检 索 语 句 的 正 确 性, 我 们 需 要 在 T_Employee 表 中 预 置 一 些 初 始 数 据, 请 在 数 据 库 中 执 行 下 面 的 数 据 插 入 SQL 语 句 : INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('DEV001','Tom',25,8300); INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('DEV002','Jerry',28,2300.80); INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('SALES001','John',23,5000); INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('SALES002','Kerry',28,6200); INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('SALES003','Stone',22,1200); INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('HR001','Jane',23,2200.88); INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('HR002','Tina',25,5200.36); INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('IT001','Smith',28,3900); 4.1 SELECT 基 本 用 法 SELECT 是 实 现 数 据 检 索 的 SQL 语 句, 本 节 我 们 学 习 SELECT 语 句 最 基 本 的 用 法 4.1.1 简 单 的 数 据 检 索 取 出 一 张 表 中 所 有 的 数 据 是 最 简 单 的 数 据 检 索 任 务, 完 成 这 个 最 简 单 任 务 的 SQL
语 句 也 是 最 简 单 的, 我 们 只 要 执 行 SELECT * FROM 表 名 即 可 比 如 我 们 执 行 下 面 的 SQL 语 句 : SELECT * FROM T_Employee FNumber FName FAge FSalary DEV001 Tom 25 8300.00 DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 IT001 Smith 28 3900.00 SALES001 John 23 5000.00 SALES002 Kerry 28 6200.00 SALES003 Stone 22 1200.00 执 行 结 果 中 列 出 了 表 中 的 所 有 行, 而 且 包 含 了 表 中 每 一 列 的 数 据 4.1.2 检 索 出 需 要 的 列 上 面 的 SQL 语 句 执 行 的 结 果 中 包 含 了 表 中 每 一 列 的 数 据, 有 的 时 候 并 不 需 要 所 有 列 的 数 据 比 如 我 们 只 需 要 检 索 所 有 员 工 的 工 号, 如 果 我 们 采 用 SELECT * FROMT_Employee 进 行 检 索 的 话, 数 据 库 系 统 会 将 所 有 列 的 数 据 从 数 据 库 中 取 出 来, 然 后 通 过 网 络 发 送 给 我 们, 这 不 仅 会 占 用 不 必 要 的 CPU 资 源 和 内 存 资 源, 而 且 会 占 用 一 定 的 网 络 带 宽, 这 在 我 们 这 种 测 试 模 式 下 不 会 有 影 响, 但 是 如 果 是 在 真 实 的 生 产 环 境 中 的 话 就 会 大 大 降 低 系 统 的 吞 吐 量, 因 此 最 好 在 检 索 的 之 后 只 检 索 需 要 的 列 那 么 如 何 只 检 索 出 需 要 的 列 呢? 检 索 出 所 有 的 列 的 SQL 语 句 为 SELECT * FROM T_Employee, 其 中 的 星 号 * 就 意 味 着 所 有 列, 那 么 我 们 只 要 将 星 号 * 替 换 成 我 们 要 检 索 的 列 名 就 可 以 了 比 如 我 们 执 行 下 面 的 SQL 语 句 : SELECT FNumber FROM T_Employee 这 就 表 示 我 们 要 检 索 出 表 T_Employee 中 的 所 有 数 据, 并 且 只 取 出 FNumber 列 执 行 完 毕 我 们 就 能 在 输 出 结 果 中 看 到 下 面 的 执 行 结 果 : FNumber DEV001 DEV002 HR001 HR002 IT001 SALES001 SALES002 SALES003 可 以 看 到 只 有 FNumber 列 中 的 数 据 被 检 索 出 来 了 上 面 的 SQL 语 句 列 出 了 FNumber 列 中 的 数 据, 那 么 如 果 想 列 出 不 止 一 个 列 中 的 数 据 呢? 非 常 简 单, 只 要 在 SELECT 语 句 后 列 出 各 个 列 的 列 名 就 可 以 了, 需 要 注 意 的 就 是 各 个 列 之 间 要 用 半 角 的 逗 号, 分 隔 开 比 如 我 们 执 行 下 面 的 SQL 语 句 : SELECT FName,FAge FROM T_Employee 这 就 表 示 我 们 要 检 索 出 表 T_Employee 中 的 所 有 数 据, 并 且 只 取 出 FName 和 FAge 两 列 的 内 容
FName FAge Tom 25 Jerry 28 Jane 23 Tina 25 Smith 28 John 23 Kerry 28 Stone 22 可 以 看 到, 执 行 结 果 中 列 出 了 所 有 员 工 的 姓 名 和 他 们 的 年 龄 如 果 要 用 这 种 显 式 指 定 数 据 列 的 方 式 取 出 所 有 列, 我 们 就 可 以 编 写 下 面 的 SQL: SELECT FNumber,FName,FAge,FSalary FROM T_Employee FNumber FName FAge FSalary DEV001 Tom 25 8300.00 DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 IT001 Smith 28 3900.00 SALES001 John 23 5000.00 SALES002 Kerry 28 6200.00 SALES003 Stone 22 1200.00 这 和 SELECT * FROM T_Employee 的 执 行 结 果 是 一 致 的, 也 就 是 说 SELECT FNumber,FName,FAge,FSalary FROMT_Employee 和 SELECT * FROMT_Employee 是 等 价 的 4.1.3 列 别 名 由 于 编 码 命 名 规 范 编 程 框 架 要 求 等 的 限 制, 数 据 表 的 列 名 有 的 时 候 意 思 并 不 是 非 常 易 读, 比 如 T_Employee 中 的 姓 名 字 段 名 称 为 FName, 而 如 果 我 们 能 用 Name 甚 至 姓 名 来 代 表 这 个 字 段 就 更 清 晰 易 懂 了, 可 是 字 段 名 已 经 不 能 更 改 了, 那 么 难 道 就 不 能 用 别 的 名 字 来 使 用 已 有 字 段 了 吗? 当 然 不 是! 就 像 可 以 为 每 个 人 取 一 个 外 号 一 样, 我 们 可 以 为 字 段 取 一 个 别 名, 这 样 就 可 以 使 用 这 个 别 名 来 引 用 这 个 列 了 别 名 的 定 义 格 式 为 列 名 AS 别 名, 比 如 我 们 要 为 FNumber 字 段 取 别 名 为 Number1 4,FName 字 段 取 别 名 为 Name FAge 字 段 取 别 名 为 Age 为 FSalary 字 段 取 别 名 为 Salary, 那 么 编 写 下 面 的 SQL 即 可 : SELECTFNumber ASNumber1,FName ASName,FAge ASAge,FSalary ASSalary FROM T_Employee Number1 Name Age Salary DEV001 Tom 25 8300.00 DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 4 由 于 Number 在 Oracle 中 为 关 键 字, 所 以 如 果 在 为 FNumber 字 段 取 别 名 为 Number, 那 么 将 会 在 Oracle 中 运 行 失 败, 所 以 这 里 取 别 名 为 Number1
HR002 Tina 25 5200.36 IT001 Smith 28 3900.00 SALES001 John 23 5000.00 SALES002 Kerry 28 6200.00 SALES003 Stone 22 1200.00 这 里 的 执 行 结 果 和 SELECT FNumber,FName,FAge,FSalary FROM T_Employee 执 行 结 果 一 样, 唯 一 不 同 的 地 方 就 是 表 头 中 的 列 名, 这 里 的 表 头 的 列 名 就 是 我 们 为 各 列 设 定 的 别 名 定 义 别 名 的 时 候 AS 不 是 必 须 的, 是 可 以 省 略 的, 比 如 下 面 的 SQL 也 是 正 确 的 : SELECTFNumberNumber1,FNameName,FAgeAge,FSalarySalary FROMT_Employee 如 果 数 据 库 系 统 支 持 中 文 列 名, 那 么 还 可 以 用 中 文 来 为 列 设 定 别 名, 这 样 可 读 性 就 更 好 了, 比 如 在 MSSQLServer 中 文 版 上 执 行 下 面 的 SQL: SELECT FNumber 工 号,FName 姓 名,FAge 年 龄,FSalary 工 资 FROM T_Employee 工 号 姓 名 年 龄 工 资 DEV001 Tom 25 8300.00 DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 IT001 Smith 28 3900.00 SALES001 John 23 5000.00 SALES002 Kerry 28 6200.00 SALES003 Stone 22 1200.00 4.1.4 按 条 件 过 滤 前 面 演 示 的 例 子 都 是 检 索 出 表 中 所 有 的 数 据, 不 过 在 很 多 情 况 下 我 们 需 要 按 照 一 定 的 过 滤 条 件 来 检 索 表 中 的 部 分 数 据, 这 个 时 候 可 以 先 检 索 出 表 中 所 有 的 数 据, 然 后 检 查 每 一 行 看 是 否 符 合 指 定 的 过 滤 条 件 比 如 我 们 要 检 索 出 所 有 工 资 少 于 5000 元 的 员 工 的 姓 名, 那 么 可 以 编 写 下 面 的 代 码 来 处 理 5 : result = executequery( SELECT FName, FSalary FROM T_Employee ); for(i=0;i<result.count;i++) { salary = result[i].get( FSalary ); if(salary<5000) { name = result[i].get( FName ); print(name+ 的 工 资 少 于 5000 元, 为 : +salary); } } 这 种 处 理 方 式 非 常 清 晰 简 单, 在 处 理 小 数 据 量 以 及 简 单 的 过 滤 条 件 的 时 候 没 有 什 么 不 妥 的 地 方, 但 是 如 果 数 据 表 中 有 大 量 的 数 据 ( 数 以 万 计 甚 至 百 万 千 万 数 量 级 ) 或 者 过 滤 条 件 非 常 复 杂 的 话 就 会 带 来 很 多 问 题 : 5 为 了 不 涉 及 具 体 宿 主 语 言 的 细 节, 这 里 采 用 的 是 实 例 性 的 类 C 伪 代 码, 如 果 需 要 您 可 以 将 其 翻 译 成 对 应 宿 主 语 言 的 代 码 本 书 其 他 部 分 也 将 采 用 相 同 的 伪 代 码 来 表 示 宿 主 语 言 无 关 的 一 些 算 法
由 于 将 表 中 所 有 的 数 据 都 从 数 据 库 中 检 索 出 来, 所 以 会 有 非 常 大 的 内 存 消 耗 以 及 网 络 资 源 消 耗 需 要 逐 条 检 索 每 条 数 据 是 否 符 合 过 滤 条 件, 所 以 检 索 速 度 非 常 慢, 当 数 据 量 大 的 时 候 这 种 速 度 是 让 人 无 法 忍 受 的 无 法 实 现 复 杂 的 过 滤 条 件 如 果 要 实 现 检 索 工 资 小 于 5000 或 者 年 龄 介 于 23 岁 与 28 岁 之 间 的 员 工 姓 名 这 样 的 逻 辑 的 话 就 要 编 写 复 杂 的 判 断 语 句, 而 如 果 要 关 联 其 他 表 进 行 查 询 的 话 则 会 更 加 复 杂 数 据 检 索 是 数 据 库 系 统 的 一 个 非 常 重 要 的 任 务, 它 内 置 了 对 按 条 件 过 滤 数 据 的 支 持, 只 要 为 SELECT 语 句 指 定 WHERE 语 句 即 可, 其 语 法 与 上 一 章 中 讲 的 数 据 更 新 数 据 删 除 的 WHERE 语 句 非 常 类 似, 比 如 完 成 检 索 出 所 有 工 资 少 于 5000 元 的 员 工 的 姓 名 这 样 的 功 能 可 以 使 用 下 面 的 SQL 语 句 : SELECT FName FROM T_Employee WHERE FSalary<5000 FName Jerry Jane Smith Stone WHERE 子 句 还 支 持 复 杂 的 过 滤 条 件, 下 面 的 SQL 语 句 用 来 检 索 出 所 有 工 资 少 于 5000 元 或 者 年 龄 大 于 25 岁 的 员 工 的 所 有 信 息 : SELECT * FROM T_Employee WHERE FSalary<5000 OR FAge>25 FNumber FName FAge FSalary DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 IT001 Smith 28 3900.00 SALES002 Kerry 28 6200.00 SALES003 Stone 22 1200.00 使 用 WHERE 子 句 只 需 指 定 过 滤 条 件 就 可 以, 我 们 无 需 关 心 数 据 库 系 统 是 如 果 进 行 查 找 的, 数 据 库 会 采 用 适 当 的 优 化 算 法 进 行 查 询, 大 大 降 低 了 CPU 资 源 的 占 用 4.1.5 数 据 汇 总 有 时 需 要 对 数 据 库 中 的 数 据 进 行 一 些 统 计, 比 如 统 计 员 工 总 数 统 计 年 龄 大 于 25 岁 的 员 工 中 的 最 低 工 资 统 计 工 资 大 于 3800 元 的 员 工 的 平 均 年 龄 SQL 中 提 供 了 聚 合 函 数 来 完 成 计 算 统 计 结 果 集 条 数 某 个 字 段 的 最 大 值 某 个 字 段 的 最 小 值 某 个 字 段 的 平 均 值 以 及 某 个 字 段 的 合 计 值 等 数 据 统 计 的 功 能,SQL 标 准 中 规 定 了 下 面 几 种 聚 合 函 数 : 函 数 名 MAX MIN AVG SUM COUNT 说 明 计 算 字 段 最 大 值 计 算 字 段 最 小 值 计 算 字 段 平 均 值 计 算 字 段 合 计 值 统 计 数 据 条 数
这 几 个 聚 合 函 数 都 有 一 个 参 数, 这 个 参 数 表 示 要 统 计 的 字 段 名, 比 如 要 统 计 工 资 总 额, 那 么 就 需 要 把 FSalary 做 为 SUM 函 数 的 参 数 通 过 例 子 来 看 一 下 聚 合 函 数 的 用 法 第 一 个 例 子 是 查 询 年 龄 大 于 25 岁 的 员 工 的 最 高 工 资, 执 行 下 面 的 SQL: SELECT MAX(FSalary) FROM T_Employee WHERE FAge>25 6200.00 为 了 方 面 的 引 用 查 询 的 结 果, 也 可 以 为 聚 合 函 数 的 计 算 结 果 指 定 一 个 别 名, 执 行 下 面 的 SQL: SELECT MAX(FSalary) as MAX_SALARY FROM T_Employee WHERE FAge>25 MAX_SALARY 6200.00 第 二 个 例 子 我 们 来 统 计 一 下 工 资 大 于 3800 元 的 员 工 的 平 均 年 龄, 执 行 下 面 的 SQL: SELECT AVG(FAge) FROM T_Employee WHERE FSalary>3800 25 第 三 个 例 子 我 们 来 统 计 一 下 公 司 每 个 月 应 支 出 工 资 总 额, 执 行 下 面 的 SQL: SELECT SUM(FSalary) FROM T_Employee 34302.04 我 们 还 可 以 多 次 使 用 聚 合 函 数, 比 如 下 面 的 SQL 用 来 统 计 公 司 的 最 低 工 资 和 最 高 工 资 : SELECT MIN(FSalary),MAX(FSalary) FROM T_Employee 1200.00 8300.00 最 后 一 个 介 绍 的 函 数 就 是 统 计 记 录 数 量 的 COUNT, 这 个 函 数 有 一 点 特 别, 因 为 它 的 即 可 以 像 其 他 聚 合 函 数 一 样 使 用 字 段 名 做 参 数, 也 可 以 使 用 星 号 * 做 为 参 数 我 们 执 行 下 面 的 SQL: SELECT COUNT(*),COUNT(FNumber) FROM T_Employee 8 8 可 以 看 到 COUNT(*) COUNT(FNumber) 两 种 方 式 都 能 统 计 出 记 录 的 条 数, 据 此 为 数 不 少 的 开 发 人 员 都 认 为 COUNT(*) COUNT( 字 段 名 ) 这 两 种 使 用 方 式 是 等 价 的 下 面 通 过 例 子 来 说 明, 为 了 看 到 两 种 使 用 方 式 的 区 别 需 要 首 先 向 表 T_Employee 中 插 入 一 条 新 的 数 据, 执 行 下 面 的 SQL: INSERT INTO T_Employee(FNumber,FAge,FSalary) VALUES('IT002',27,2800) 需 要 注 意 的 就 是 这 句 INSERT 语 句 没 有 为 FName 字 段 赋 值, 也 就 是 说 新 插 入 的 这 条 数 据 的 FName 字 段 值 为 空, 可 以 执 行 SELECT * FROM T_Employee 来 查 看 表 T_Employee 中 的 内 容 : FNumber FName FAge FSalary DEV001 Tom 25 8300.00 DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36
IT001 Smith 28 3900.00 IT002 <NULL> 27 2800.00 SALES001 John 23 5000.00 SALES002 Kerry 28 6200.00 SALES003 Stone 22 1200.00 可 以 看 到 FNumber 为 IT002 的 行 的 FName 字 段 是 空 值 接 着 执 行 下 面 的 SQL: SELECT COUNT(*),COUNT(FNumber),COUNT(FName) FROM T_Employee 9 9 8 可 以 看 到 COUNT(*) COUNT(FNumber) 两 个 表 达 式 的 计 算 结 果 都 是 9, 而 COUNT(FName) 的 计 算 结 果 是 8 也 就 反 应 出 了 两 种 使 用 方 式 的 区 别 :COUNT(*) 统 计 的 是 结 果 集 的 总 条 数, 而 COUNT(FName) 统 计 的 则 是 除 了 结 果 集 中 FName 不 为 空 值 ( 也 就 是 不 等 于 NULL) 的 记 录 的 总 条 数 由 于 FNumber 为 IT002 的 行 的 FName 字 段 是 空 值, 所 以 COUNT(FName) 的 计 算 结 果 是 8 因 此 在 使 用 聚 合 函 数 COUNT 的 时 候 一 定 要 区 分 两 种 使 用 方 式 的 区 别, 以 防 止 出 现 数 据 错 误 4.1.6 排 序 到 目 前 为 止, 数 据 检 索 结 果 的 排 列 顺 序 取 决 于 数 据 库 系 统 所 决 定 的 排 序 机 制, 这 种 排 序 机 制 可 能 是 按 照 数 据 的 输 入 顺 序 决 定 的, 也 有 可 能 是 按 照 其 他 的 算 法 来 决 定 的 在 有 的 情 况 下 我 们 需 要 按 照 某 种 排 序 规 则 来 排 列 检 索 结 果, 比 如 按 照 工 资 从 高 到 低 的 顺 序 排 列 或 者 按 照 姓 名 的 字 符 顺 序 排 列 等 SELECT 语 句 允 许 使 用 ORDER BY 子 句 来 执 行 结 果 集 的 排 序 方 式 ORDER BY 子 句 位 于 SELECT 语 句 的 末 尾, 它 允 许 指 定 按 照 一 个 列 或 者 多 个 列 进 行 排 序, 还 可 以 指 定 排 序 方 式 是 升 序 ( 从 小 到 大 排 列 ) 还 是 降 序 ( 从 大 到 小 排 列 ) 比 如 下 面 的 SQL 语 句 演 示 了 按 照 年 龄 排 序 所 有 员 工 信 息 的 列 表 : SELECT * FROM T_Employee ORDER BY FAge ASC 执 行 完 毕 我 们 就 能 在 输 出 结 果 中 看 到 下 面 的 执 行 结 果, 可 以 看 到 输 出 结 果 已 经 按 照 FAge 字 段 进 行 升 序 排 列 了 : FNumber FName FAge FSalary SALES003 Stone 22 1200.00 SALES001 John 23 5000.00 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 DEV001 Tom 25 8300.00 IT002 <NULL> 27 2800.00 SALES002 Kerry 28 6200.00 DEV002 Jerry 28 2300.80 IT001 Smith 28 3900.00 这 句 SQL 中 的 ORDER BY FAge ASC 指 定 了 按 照 FAge 字 段 的 顺 序 进 行 升 序 排 列, 其 中 ASC 代 表 升 序 因 为 对 于 ORDER BY 子 句 来 说, 升 序 是 默 认 的 排 序 方 式, 所 以 如 果 要 采 用 升 序 的 话 可 以 不 指 定 排 序 方 式, 也 就 是 ASC 是 可 以 省 略 的, 比 如 下 面 的 SQL 语 句 具 有 和 上 面 的 SQL 语 句 等 效 的 执 行 效 果 : SELECT * FROM T_Employee ORDER BY FAge 执 行 完 毕 我 们 就 能 在 输 出 结 果 中 看 到 下 面 的 执 行 结 果, 可 以 看 到 输 出 结 果 同 样 按 照
FAge 字 段 进 行 升 序 排 列 了 : FNumber FName FAge FSalary SALES003 Stone 22 1200.00 SALES001 John 23 5000.00 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 DEV001 Tom 25 8300.00 IT002 <NULL> 27 2800.00 SALES002 Kerry 28 6200.00 DEV002 Jerry 28 2300.80 IT001 Smith 28 3900.00 如 果 需 要 按 照 降 序 排 列, 那 么 只 要 将 ASC 替 换 为 DESC 即 可, 其 中 DESC 代 表 降 序 执 行 下 面 的 SQL 语 句 : SELECT * FROM T_Employee ORDER BY FAge DESC 执 行 完 毕 我 们 就 能 在 输 出 结 果 中 看 到 下 面 的 执 行 结 果, 可 以 看 到 输 出 结 果 已 经 按 照 FAge 字 段 进 行 降 序 排 序 了 : FNumber FName FAge FSalary DEV002 Jerry 28 2300.80 IT001 Smith 28 3900.00 SALES002 Kerry 28 6200.00 IT002 <NULL> 27 2800.00 DEV001 Tom 25 8300.00 HR002 Tina 25 5200.36 HR001 Jane 23 2200.88 SALES001 John 23 5000.00 SALES003 Stone 22 1200.00 可 以 看 到 上 面 的 检 索 结 果 中 有 几 组 年 龄 相 同 的 记 录, 这 些 年 龄 相 同 的 记 录 之 间 的 顺 序 是 由 数 据 库 系 统 决 定 的, 但 是 有 时 可 能 需 要 需 要 完 成 按 照 年 龄 从 大 到 小 排 序, 如 果 年 龄 相 同 则 按 照 工 资 从 大 到 小 排 序 之 类 的 排 序 功 能 这 可 以 通 过 指 定 多 个 排 序 规 则 来 完 成, 因 为 ORDER BY 语 句 允 许 指 定 多 个 排 序 列, 各 个 列 之 间 使 用 逗 号 隔 开 即 可 执 行 下 面 的 SQL 语 句 : SELECT * FROM T_Employee ORDER BY FAge DESC,FSalary DESC FNumber FName FAge FSalary SALES002 Kerry 28 6200.00 IT001 Smith 28 3900.00 DEV002 Jerry 28 2300.80 IT002 <NULL> 27 2800.00 DEV001 Tom 25 8300.00 HR002 Tina 25 5200.36 SALES001 John 23 5000.00 HR001 Jane 23 2200.88 SALES003 Stone 22 1200.00
可 以 看 到 年 龄 相 同 的 记 录 按 照 工 资 从 高 到 低 的 顺 序 排 列 了 对 于 多 个 排 序 规 则, 数 据 库 系 统 会 按 照 优 先 级 进 行 处 理 数 据 库 系 统 首 先 按 照 第 一 个 排 序 规 则 进 行 排 序 ; 如 果 按 照 第 一 个 排 序 规 则 无 法 区 分 两 条 记 录 的 顺 序, 则 按 照 第 二 个 排 序 规 则 进 行 排 序 ; 如 果 按 照 第 二 个 排 序 规 则 无 法 区 分 两 条 记 录 的 顺 序, 则 按 照 第 三 个 排 序 规 则 进 行 排 序 ; 以 此 类 推 以 上 面 的 SQL 语 句 为 例, 数 据 库 系 统 首 先 按 照 FAge 字 段 的 降 序 进 行 排 列, 如 果 按 照 个 排 序 规 则 无 法 区 分 两 条 记 录 的 顺 序, 则 按 照 FSalary 字 段 的 降 序 进 行 排 列 ORDER BY 子 句 完 全 可 以 与 WHERE 子 句 一 起 使 用, 唯 一 需 要 注 意 的 就 是 ORDER BY 子 句 要 放 到 WHERE 子 句 之 后, 不 能 颠 倒 它 们 的 顺 序 比 如 我 们 尝 试 执 行 下 面 的 SQL 语 句 : SELECT * FROM T_Employee ORDER BY FAge DESC,FSalary DESC WHERE FAge>23 执 行 以 后 数 据 库 系 统 会 报 错 提 示 此 语 句 有 语 法 错 误, 如 果 我 们 颠 倒 ORDERBY 和 WHERE 子 句 的 位 置 则 可 以 执 行 通 过 : SELECT * FROM T_Employee WHERE FAge>23 ORDER BY FAge DESC,FSalary DESC FNumber FName FAge FSalary SALES002 Kerry 28 6200.00 IT001 Smith 28 3900.00 DEV002 Jerry 28 2300.80 IT002 <NULL> 27 2800.00 DEV001 Tom 25 8300.00 HR002 Tina 25 5200.36 前 面 我 们 提 到, 如 果 没 有 为 SELECT 语 句 指 定 ORDER BY 子 句, 数 据 库 系 统 会 按 照 某 种 内 置 的 规 则 对 检 索 结 果 进 行 排 序 如 果 您 对 检 索 结 果 的 前 后 排 列 顺 序 有 要 求, 那 么 即 使 数 据 库 系 统 返 回 的 检 索 结 果 符 合 要 求 也 最 好 显 式 的 指 定 ORDER BY 子 句, 因 为 这 种 系 统 提 供 的 排 序 方 式 是 不 稳 定 的, 不 仅 在 不 同 数 据 库 系 统 之 间 存 在 差 异, 而 且 即 使 对 同 一 种 数 据 库 系 统 来 说 在 不 同 的 条 件 下 这 种 排 序 方 式 也 是 有 可 能 发 生 改 变 的 4.2 高 级 数 据 过 滤 数 据 检 索 是 数 据 库 系 统 中 最 复 杂 的 功 能, 而 数 据 过 滤 则 是 数 据 检 索 中 最 核 心 的 部 分, 到 目 前 为 止 我 们 讲 解 的 数 据 过 滤 都 是 过 滤 某 字 段 等 于 某 个 值 的 所 有 记 录 过 滤 某 字 段 小 于 某 个 值 或 者 大 于 某 个 值 的 所 有 记 录 等 简 单 的 数 据 过 滤 方 式, 这 显 然 是 无 法 满 足 真 实 业 务 系 统 中 的 各 种 数 据 过 滤 条 件 的, 因 此 本 节 我 们 将 介 绍 一 些 单 表 查 询 时 的 高 级 数 据 过 滤 技 术 需 要 注 意 的 是, 本 节 讲 解 的 高 级 数 据 过 滤 技 巧 几 乎 同 样 适 用 于 Update 语 句 和 Delete 语 句 中 的 Where 子 句 4.2.1 通 配 符 过 滤 到 目 前 为 止, 我 们 讲 解 的 数 据 过 滤 方 式 都 是 针 对 特 定 值 的 过 滤, 比 如 检 索 所 有 年 龄 为 25 的 所 有 员 工 信 息 检 索 所 有 工 资 介 于 2500 元 至 3800 元 之 间 的 所 有 记 录, 但 是 这 种 过 滤 方 式 并 不 能 满 足 一 些 模 糊 的 过 滤 方 式 比 如, 检 索 所 有 姓 名 中 含 有 th 的 员 工 或 者 检 索 所 有 姓 王 的 员 工, 实 现 这 样 的 检 索 操 作 必 须 使 用 通 配 符 进 行 过 滤 SQL 中 的 通 配 符 过 滤 使 用 LIKE 关 键 字, 可 以 像 使 用 OR AND 等 操 作 符 一 样 使 用 它, 它 是 一 个 二 元 操 作 符, 左 表 达 式 为 待 匹 配 的 字 段, 而 右 表 达 式 为 待 匹 配 的 通 配 符 表 达 式 通 配 符 表 达 式 由 通 配 符 和 普 通 字 符 组 成, 主 流 数 据 库 系 统 支 持 的 通 配 符 有 单 字 符 匹 配 和 多 字 符 匹
配, 有 的 数 据 库 系 统 还 支 持 集 合 匹 配 4.2.1.1 单 字 符 匹 配 进 行 单 字 符 匹 配 的 通 配 符 为 半 角 下 划 线 _, 它 匹 配 单 个 出 现 的 字 符 比 如 通 配 符 表 达 式 b_d 匹 配 第 一 个 字 符 为 b 第 二 个 字 符 为 任 意 字 符 第 三 个 字 符 为 d 的 字 符 串, bed bad 都 能 匹 配 这 个 表 达 式, 而 bd abc build 等 则 不 能 匹 配 这 个 表 达 式 ; 通 配 符 表 达 式 _oo_ 匹 配 第 一 个 字 符 为 任 意 字 符 第 二 个 字 符 为 o 第 三 个 字 符 为 o 第 四 个 字 符 为 任 意 字 符 的 字 符 串, look took cool 都 能 匹 配 这 个 表 达 式, 而 rom todo 等 则 不 能 匹 配 这 个 表 达 式 下 面 来 演 示 一 下 单 字 符 匹 配 的 用 法 我 们 来 检 索 T_Employee 表 中 FName 字 段 匹 配 如 下 规 则 的 数 据 行 : 以 任 意 字 符 开 头, 剩 余 部 分 为 erry 根 据 通 配 符 表 达 式 语 法, 我 们 得 知 这 个 匹 配 规 则 对 应 的 通 配 符 表 达 式 为 _erry, 因 此 编 写 如 下 的 SQL: SELECT * FROM T_Employee WHERE FName LIKE '_erry' FNumber FName FAge FSalary DEV002 Jerry 28 2300.80 SALES002 Kerry 28 6200.00 Jerry Kerry 两 个 字 符 串 能 够 匹 配 通 配 符 表 达 式 _erry, 所 以 被 显 示 到 了 结 果 集 中, 而 其 他 数 据 行 则 由 于 不 匹 配 此 通 配 符 表 达 式, 所 以 被 过 滤 掉 了 单 字 符 匹 配 在 通 配 符 表 达 式 中 可 以 出 现 多 次, 比 如 我 们 要 检 索 长 度 为 4 第 三 个 字 符 为 n 其 它 字 符 为 任 意 字 符 的 姓 名 根 据 通 配 符 表 达 式 语 法, 我 们 得 知 这 个 匹 配 规 则 对 应 的 通 配 符 表 达 式 为 n_ ( 注 意 前 两 个 字 符 为 连 续 的 两 个 下 划 线 ), 那 么 需 要 编 写 如 下 的 SQL: SELECT * FROM T_Employee WHERE FName LIKE ' n_' FNumber FName FAge FSalary HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 4.2.1.2 多 字 符 匹 配 使 用 下 划 线 可 以 实 现 匹 配 长 度 为 5 以 ab 开 头 剩 余 字 符 任 意 的 功 能, 而 对 于 匹 配 以 k 开 头, 长 度 不 限, 剩 余 字 符 任 意 这 样 的 需 求 则 无 法 满 足, 这 时 就 需 要 使 用 多 字 符 匹 配 了 进 行 多 字 符 匹 配 的 通 配 符 为 半 角 百 分 号 %, 它 匹 配 任 意 次 数 ( 零 或 多 个 ) 出 现 的 任 意 字 符 比 如 通 配 符 表 达 式 k% 匹 配 以 k 开 头 任 意 长 度 的 字 符 串, k kerry kb 都 能 匹 配 这 个 表 达 式, 而 ark luck 3kd 等 则 不 能 匹 配 这 个 表 达 式 ; 配 符 表 达 式 b%t 匹 配 以 b 开 头 以 t 结 尾 任 意 长 度 的 字 符 串, but bt belt 都 能 匹 配 这 个 表 达 式, 而 turbo tube tb 等 则 不 能 匹 配 这 个 表 达 式 下 面 来 演 示 一 下 多 字 符 匹 配 的 用 法 我 们 来 检 索 T_Employee 表 中 FName 字 段 匹 配 如 下 规 则 的 数 据 行 : 以 T 开 头 长 度, 长 度 任 意 根 据 通 配 符 表 达 式 语 法, 我 们 得 知 这 个 匹 配 规 则 对 应 的 通 配 符 表 达 式 为 T%, 因 此 编 写 如 下 的 SQL: SELECT * FROM T_Employee WHERE FName LIKE 'T%' FNumber FName FAge FSalary DEV001 Tom 25 8300.00
HR002 Tina 25 5200.36 接 着 我 们 来 检 索 姓 名 中 包 含 字 母 n 的 员 工 信 息, 编 写 如 下 SQL: SELECT * FROM T_Employee WHERE FName LIKE '%n%' FNumber FName FAge FSalary HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 SALES001 John 23 5000.00 SALES003 Stone 22 1200.00 单 字 符 匹 配 和 多 字 符 匹 配 还 可 以 一 起 使 用 我 们 来 检 索 T_Employee 表 中 FName 字 段 匹 配 如 下 规 则 的 数 据 行 : 最 后 一 个 字 符 为 任 意 字 符 倒 数 第 二 个 字 符 为 n 长 度 任 意 的 字 符 串 根 据 通 配 符 表 达 式 语 法, 我 们 得 知 这 个 匹 配 规 则 对 应 的 通 配 符 表 达 式 为 %n_, 因 此 编 写 如 下 的 SQL: SELECT * FROM T_Employee WHERE FName LIKE '%n_' FNumber FName FAge FSalary HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 SALES003 Stone 22 1200.00 4.2.1.3 集 合 匹 配 集 合 匹 配 只 在 MSSQLServer 上 提 供 支 持, 在 MYSQL Oracle DB2 等 数 据 库 中 不 支 持, 必 须 采 用 变 通 的 手 段 来 实 现 进 行 集 合 匹 配 的 通 配 符 为 [], 方 括 号 中 包 含 一 个 字 符 集, 它 匹 配 与 字 符 集 中 任 意 一 个 字 符 相 匹 配 的 字 符 比 如 通 配 符 表 达 式 [bt]% 匹 配 第 一 个 字 符 为 b 或 者 t 长 度 不 限 的 字 符 串, bed token t 都 能 匹 配 这 个 表 达 式, 而 at lab lot 等 则 不 能 匹 配 这 个 表 达 式 下 面 来 演 示 一 下 多 字 符 匹 配 的 用 法 我 们 来 检 索 T_Employee 表 中 FName 字 段 匹 配 如 下 规 则 的 数 据 行 : 以 S 或 者 J 开 头 长 度, 长 度 任 意 根 据 通 配 符 表 达 式 语 法, 我 们 得 知 这 个 匹 配 规 则 对 应 的 通 配 符 表 达 式 为 [SJ]%, 因 此 编 写 如 下 的 SQL: SELECT * FROM T_Employee WHERE FName LIKE '[SJ]%' FNumber FName FAge FSalary DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 IT001 Smith 28 3900.00 SALES001 John 23 5000.00 SALES003 Stone 22 1200.00 还 可 以 使 用 否 定 符 ^ 来 对 集 合 取 反, 它 匹 配 不 与 字 符 集 中 任 意 一 个 字 符 相 匹 配 的 字 符 比 如 通 配 符 表 达 式 [^bt]% 匹 配 第 一 个 字 符 不 为 b 或 者 t 长 度 不 限 的 字 符 串, at lab lot 都 能 匹 配 这 个 表 达 式, 而 bed token t 等 则 不 能 匹 配 这 个 表 达 式 我 们 来 检 索 T_Employee 表 中 FName 字 段 匹 配 如 下 规 则 的 数 据 行 : 不 以 S 或 者 J 开
头 长 度, 长 度 任 意 根 据 通 配 符 表 达 式 语 法, 我 们 得 知 这 个 匹 配 规 则 对 应 的 通 配 符 表 达 式 为 [^SJ]%, 因 此 编 写 如 下 的 SQL: SELECT * FROM T_Employee WHERE FName LIKE '[^SJ]%' FNumber FName FAge FSalary DEV001 Tom 25 8300.00 HR002 Tina 25 5200.36 SALES002 Kerry 28 6200.00 集 合 匹 配 只 在 MSSQLServer 上 提 供 支 持, 不 过 在 其 他 数 据 库 中 我 们 可 以 通 过 变 通 手 段 来 实 现 相 同 的 效 果 比 如 下 面 的 SQL 可 以 实 现 和 本 节 第 一 个 例 子 相 同 的 效 果 : SELECT * FROM T_Employee WHERE FName LIKE 'S%' OR FName LIKE 'J%' 而 下 面 的 SQL 可 以 实 现 和 本 节 第 二 个 例 子 相 同 的 效 果 : SELECT * FROM T_Employee WHERE NOT(FName LIKE 'S%') AND NOT(FName LIKE 'J%') 通 配 符 过 滤 一 个 非 常 强 大 的 功 能, 不 过 在 使 用 通 配 符 过 滤 进 行 检 索 的 时 候, 数 据 库 系 统 会 对 全 表 进 行 扫 描, 所 以 执 行 速 度 非 常 慢 因 此 不 要 过 分 使 用 通 配 符 过 滤, 在 使 用 其 他 方 式 可 以 实 现 的 效 果 的 时 候 就 应 该 避 免 使 用 通 配 符 过 滤 4.2.2 空 值 检 测 没 有 添 加 非 空 约 束 列 是 可 以 为 空 值 的 ( 也 就 是 NULL), 有 时 我 们 需 要 对 空 值 进 行 检 测, 比 如 要 查 询 所 有 姓 名 未 知 的 员 工 信 息 既 然 NULL 代 表 空 值, 有 的 开 发 人 员 试 图 通 过 下 面 的 SQL 语 句 来 实 现 : SELECT * FROM T_Employee WHERE FNAME=null 这 个 语 句 是 可 以 执 行 的, 不 过 执 行 以 后 我 们 看 不 到 任 何 的 执 行 结 果, 那 个 Fnumber 为 IT002 的 数 据 行 中 Fname 字 段 为 空, 但 是 没 有 被 查 询 出 来 这 是 因 为 在 SQL 语 句 中 对 空 值 的 处 理 有 些 特 别, 不 能 使 用 普 通 的 等 于 运 算 符 进 行 判 断, 而 要 使 用 IS NULL 关 键 字, 使 用 方 法 为 待 检 测 字 段 名 IS NULL, 比 如 要 查 询 所 有 姓 名 未 知 的 员 工 信 息, 则 运 行 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE FNAME IS NULL FNumber FName FAge FSalary IT002 <NULL> 27 2800.00 如 果 要 检 测 字 段 不 为 空, 则 要 使 用 ISNOTNULL, 使 用 方 法 为 待 检 测 字 段 名 ISNOT NULL, 比 如 要 查 询 所 有 姓 名 已 知 的 员 工 信 息, 则 运 行 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE FNAME IS NOT NULL FNumber FName FAge FSalary DEV001 Tom 25 8300.00 DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36
IT001 Smith 28 3900.00 SALES001 John 23 5000.00 SALES002 Kerry 28 6200.00 SALES003 Stone 22 1200.00 IS NULL/IS NOT NULL 可 以 和 其 他 的 过 滤 条 件 一 起 使 用 比 如 要 查 询 所 有 姓 名 已 知 且 工 资 小 于 5000 的 员 工 信 息, 则 运 行 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE FNAME IS NOT NULL AND FSalary <5000 FNumber FName FAge FSalary DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 IT001 Smith 28 3900.00 SALES003 Stone 22 1200.00 4.2.3 反 义 运 算 符 = < > 等 运 算 符 都 是 用 来 进 行 数 值 判 断 的, 有 的 时 候 则 会 想 使 用 这 些 运 算 符 的 反 义, 比 如 不 等 于 不 小 于 或 者 不 大 于,MSSQLServer DB2 提 供 了! 运 算 符 来 对 运 算 符 求 反 义, 也 就 是!= 表 示 不 等 于!< 表 示 不 小 于, 而!> 表 示 不 大 于 比 如 要 完 成 下 面 的 功 能 检 索 所 有 年 龄 不 等 于 22 岁 并 且 工 资 不 小 于 2000 元, 我 们 可 以 编 写 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE FAge!=22 AND FSALARY!<2000 FNUMBER FNAME FAGE FSALARY DEV001 Tom 25 8300.00 DEV002 Jerry 28 2300.80 SALES001 John 23 5000.00 SALES002 Kerry 28 6200.00 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 IT001 Smith 28 3900.00! 运 算 符 能 够 把 不 等 于 不 大 于 不 小 于 这 样 的 语 义 直 接 翻 译 成 SQL 运 算 符, 不 过 这 个 运 算 符 只 在 MSSQLServer 和 DB2 两 种 数 据 库 系 统 上 提 供 支 持, 如 果 在 其 他 数 据 库 系 统 上 则 可 以 用 其 他 的 变 通 的 方 式 实 现, 最 常 用 的 变 通 实 现 方 式 有 两 种 : 使 用 同 义 运 算 符 使 用 NOT 运 算 符 否 定 的 语 义 都 有 对 应 的 同 义 运 算 符, 比 如 不 大 于 的 同 义 词 是 小 于 等 于 而 不 小 于 的 同 义 词 是 大 于 等 于, 同 时 SQL 提 供 了 通 用 的 表 示 不 等 于 的 运 算 符 <>, 这 样 不 等 于 不 大 于 和 不 小 于 就 分 别 可 以 表 示 成 <> <= 和 >= 因 此 要 完 成 下 面 的 功 能 检 索 所 有 年 龄 不 等 于 22 岁 并 且 工 资 不 小 于 2000 元, 我 们 可 以 编 写 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE FAge<>22 AND FSALARY>=2000 NOT 运 算 符 用 来 将 一 个 表 达 式 的 值 取 反, 也 就 是 将 值 为 真 的 表 达 式 结 果 变 为 假 将
值 为 假 的 表 达 式 结 果 变 为 真, 使 用 方 式 也 非 常 简 单 NOT ( 表 达 式 ), 比 如 要 表 达 年 龄 不 小 于 20, 那 么 可 以 如 下 使 用 NOT(Fage<20) 因 此 要 完 成 下 面 的 功 能 检 索 所 有 年 龄 不 等 于 22 岁 并 且 工 资 不 小 于 2000 元, 我 们 可 以 编 写 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE NOT(FAge=22) AND NOT(FSALARY<2000) 使 用! 运 算 符 的 方 式 由 于 只 能 运 行 在 MSSQLServer 和 DB2 两 种 数 据 库 系 统 上, 所 以 如 果 应 用 程 序 有 移 植 到 其 他 数 据 库 系 统 上 的 需 求 的 话, 就 应 该 避 免 使 用 这 种 方 式 ; 使 用 同 义 运 算 符 的 方 式 能 够 运 行 在 所 有 主 流 数 据 库 系 统 上, 不 过 由 于 粗 心 等 原 因, 很 容 易 将 不 大 于 表 示 成 <, 而 忘 记 了 不 大 于 是 包 含 小 于 和 等 于 这 两 个 意 思 的, 这 样 就 会 造 成 检 索 数 据 的 错 误, 造 成 应 用 程 序 的 Bug; 而 采 用 NOT 运 算 符 的 方 式 能 比 较 容 易 的 表 达 要 实 现 的 需 求, 而 且 能 够 实 现 复 杂 的 嵌 套, 最 重 要 的 是 避 免 了 潜 在 的 应 用 程 序 的 Bug, 所 以 除 了 <> 这 种 方 式 之 外, 我 们 推 荐 使 用 NOT 运 算 符 的 方 式 来 表 示 非 的 语 义 4.2.4 多 值 检 测 公 司 要 为 年 龄 为 23 岁 25 岁 和 28 岁 的 员 工 发 福 利, 请 将 他 们 的 年 龄 工 号 和 姓 名 检 索 出 来, 要 完 成 这 样 的 功 能, 我 们 可 以 使 用 OR 语 句 来 连 接 多 个 等 于 判 断 SQL 语 句 如 下 : SELECT FAge,FNumber,FName FROM T_Employee WHERE FAge=23 OR FAge=25 OR FAge=28 FAge FNumber FName 25 DEV001 Tom 28 DEV002 Jerry 23 HR001 Jane 25 HR002 Tina 28 IT001 Smith 23 SALES001 John 28 SALES002 Kerry 这 里 要 检 索 的 年 龄 值 是 很 少 的, 只 有 3 个, 如 果 要 求 我 们 检 索 年 龄 为 21 岁 22 岁 25 岁 28 岁 30 岁 33 岁 35 岁 38 岁 46 岁 的 员 工 信 息, 那 么 我 们 就 要 用 OR 连 接 九 个 等 于 判 断 : SELECT FAge,FNumber,FName FROM T_Employee WHERE FAge=21 OR FAge=22 OR FAge=25 OR FAge=28 OR FAge=30 OR FAge=33 OR FAge=35 OR FAge=38 OR FAge=46 这 不 仅 写 起 来 是 非 常 麻 烦 的, 而 且 维 护 的 难 度 也 相 当 大, 一 不 小 心 就 会 造 成 数 据 错 误 为 了 解 决 进 行 多 个 离 散 值 的 匹 配 问 题,SQL 提 供 了 IN 语 句, 使 用 IN 我 们 只 要 指 定 要 匹 配 的 数 据 集 合 就 可 以 了, 使 用 方 法 为 IN ( 值 1, 值 2, 值 3 ) 要 完 成 公 司 要 为 年 龄 为 23 岁 25 岁 和 28 岁 的 员 工 发 福 利, 请 将 他 们 的 年 龄 工 号 和 姓 名 检 索 出 来 这 样 功 能 的 话, 可 以 使 用 下 面 的 SQL 语 句 : SELECT FAge,FNumber,FName FROM T_Employee WHERE FAge IN (23,25,28) FAge FNumber FName 25 DEV001 Tom 28 DEV002 Jerry 23 HR001 Jane
25 HR002 Tina 28 IT001 Smith 23 SALES001 John 28 SALES002 Kerry 可 以 看 到 执 行 结 果 和 使 用 OR 语 句 来 连 接 多 个 等 于 判 断 的 方 式 是 一 样 的 使 用 IN 我 们 还 可 以 让 字 段 与 其 他 表 中 的 值 进 行 匹 配, 比 如 查 找 所 有 姓 名 在 迟 到 记 录 表 中 的 员 工 信 息, 要 实 现 这 样 的 功 能 就 需 要 IN 来 搭 配 子 查 询 来 使 用, 关 于 这 一 点 我 们 将 在 后 面 的 章 节 介 绍 4.2.5 范 围 值 检 测 使 用 IN 语 句 只 能 进 行 多 个 离 散 值 的 检 测, 如 果 要 实 现 范 围 值 的 检 测 就 非 常 麻 烦 甚 至 不 可 能 了 比 如 我 们 要 完 成 下 面 的 功 能 检 索 所 有 年 龄 介 于 23 岁 到 27 岁 之 间 的 员 工 信 息, 如 果 用 IN 语 句 来 实 现 的 话 就 必 须 列 出 此 范 围 内 的 所 有 可 能 的 值,SQL 如 下 : SELECT * FROM T_Employee WHERE FAGE IN(23,24,25,26,27) FNumber FName FAge FSalary DEV001 Tom 25 8300.00 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 IT002 <NULL> 27 2800.00 SALES001 John 23 5000.00 当 范 围 内 的 值 比 较 多 的 时 候 使 用 这 种 方 式 非 常 麻 烦, 比 如 检 索 所 有 年 龄 介 于 20 岁 到 60 岁 之 间 的 员 工 信 息 就 要 列 出 20 到 60 之 间 的 每 一 个 值, 这 个 工 作 量 是 非 常 大 的 而 且 这 种 方 式 也 无 法 表 达 非 离 散 的 范 围 值, 比 如 要 实 现 检 索 所 有 工 资 介 于 3000 元 到 5000 元 之 间 的 员 工 信 息 的 话 就 是 不 可 能 的, 因 为 介 于 3000 到 5000 之 间 的 值 是 无 数 的 这 种 情 况 下 我 们 可 以 使 用 普 通 的 大 于 等 于 和 小 于 等 于 来 实 现 范 围 值 检 测, 比 如 完 成 下 面 的 功 能 检 索 所 有 年 龄 介 于 23 岁 到 27 岁 之 间 的 员 工 信 息, 可 以 使 用 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE FAGE>=23 AND FAGE <=27 FNumber FName FAge FSalary DEV001 Tom 25 8300.00 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 IT002 <NULL> 27 2800.00 SALES001 John 23 5000.00 这 种 方 式 能 够 实 现 几 乎 所 有 的 范 围 值 检 测 的 功 能, 不 过 SQL 提 供 了 一 个 专 门 用 语 范 围 值 检 测 的 语 句 BETTWEEN AND, 它 可 以 用 来 检 测 一 个 值 是 否 处 于 某 个 范 围 中 ( 包 括 范 围 的 边 界 值, 也 就 是 闭 区 间 ) 使 用 方 法 如 下 字 段 名 BETTWEEN 左 范 围 值 AND 右 范 围 值, 其 等 价 于 字 段 名 >= 左 范 围 值 AND 字 段 名 <= 右 范 围 值 比 如 完 成 下 面 的 功 能 检 索 所 有 年 龄 介 于 23 岁 到 27 岁 之 间 的 员 工 信 息, 可 以 使 用 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE FAGE BETWEEN 23 AND 27
程 序 员 的 SQL 金 典 FNumber FName FAge FSalary DEV001 Tom 25 8300.00 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 IT002 <NULL> 27 2800.00 SALES001 John 23 5000.00 使 用 BETTWEEN AND 我 们 还 能 够 进 行 多 个 不 连 续 范 围 值 的 检 测, 比 如 要 实 现 检 索 所 有 工 资 介 于 2000 元 到 3000 元 之 间 以 及 5000 元 到 8000 元 的 员 工 信 息, 可 以 使 用 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE (FSalary BETWEEN 2000 AND 3000) OR (FSalary BETWEEN 5000 AND 8000) FNumber FName FAge FSalary DEV002 Jerry 28 2300.80 HR001 Jane 23 2200.88 HR002 Tina 25 5200.36 IT002 <NULL> 27 2800.00 SALES001 John 23 5000.00 SALES002 Kerry 28 6200.00 数 据 库 系 统 对 BETTWEEN AND 进 行 了 查 询 优 化, 使 用 它 进 行 范 围 值 检 测 将 会 得 到 比 其 他 方 式 更 好 的 性 能, 因 此 在 进 行 范 围 值 检 测 的 时 候 应 该 优 先 使 用 BETTWEEN AND 需 要 注 意 的 就 是 BETTWEEN AND 在 进 行 检 测 的 时 候 是 包 括 了 范 围 的 边 界 值 的 ( 也 就 是 闭 区 间 ), 如 果 需 要 进 行 开 区 间 或 者 半 开 半 闭 区 间 的 范 围 值 检 测 的 话 就 必 须 使 用 其 他 的 解 决 方 案 了 4.2.6 低 效 的 WHERE 1=1 网 上 有 不 少 人 提 出 过 类 似 的 问 题 : 看 到 有 人 写 了 WHERE 1=1 这 样 的 SQL, 到 底 是 什 么 意 思? 其 实 使 用 这 种 用 法 的 开 发 人 员 一 般 都 是 在 使 用 动 态 组 装 的 SQL 让 我 们 想 像 如 下 的 场 景 : 用 户 要 求 提 供 一 个 灵 活 的 查 询 界 面 来 根 据 各 种 复 杂 的 条 件 来 查 询 员 工 信 息, 界 面 如 下 图 : 界 面 中 列 出 了 四 个 查 询 条 件, 包 括 按 工 号 查 询 按 姓 名 查 询 按 年 龄 查 询 以 及 按 工 资 查 询,
每 个 查 询 条 件 前 都 有 一 个 复 选 框, 如 果 复 选 框 被 选 中, 则 表 示 将 其 做 为 一 个 过 滤 条 件 比 如 上 图 就 表 示 检 索 工 号 介 于 DEV001 和 DEV008 之 间 姓 名 中 含 有 J 并 且 工 资 介 于 3000 元 到 6000 元 的 员 工 信 息 如 果 不 选 中 姓 名 前 的 复 选 框, 比 如 下 图 表 示 检 索 工 号 介 于 DEV001 和 DEV008 之 间 并 且 工 资 介 于 3000 元 到 6000 元 的 员 工 信 息 : 如 果 将 所 有 的 复 选 框 都 不 选 中, 则 表 示 表 示 检 索 所 有 员 工 信 息, 比 如 下 图 : 这 里 的 数 据 检 索 与 前 面 的 数 据 检 索 都 不 一 样, 因 为 前 边 例 子 中 的 数 据 检 索 的 过 滤 条 件 都 是 确 定 的, 而 这 里 的 过 滤 条 件 则 随 着 用 户 设 置 的 不 同 而 有 变 化, 这 时 就 要 根 据 用 户 的 设 置 来 动 态 组 装 SQL 了 当 不 选 中 年 龄 前 的 复 选 框 的 时 候 要 使 用 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE FNumber BETWEEN 'DEV001' AND 'DEV008' AND FName LIKE '%J%' AND FSalary BETWEEN 3000 AND 6000 而 如 果 不 选 中 姓 名 和 年 龄 前 的 复 选 框 的 时 候 就 要 使 用 下 面 的 SQL 语 句 : SELECT * FROM T_Employee WHERE FNumber BETWEEN 'DEV001' AND 'DEV008' AND FSalary BETWEEN 3000 AND 6000 而 如 果 将 所 有 的 复 选 框 都 不 选 中 的 时 候 就 要 使 用 下 面 的 SQL 语 句 : SELECT * FROM T_Employee