数据库基础

本讲稿(ORACLE8i 数据库基础)是作者在多年的工作和授课中的总结,主要包括两个部分,第一部分是ORACLE SQL*PLUS基础,主要讲述ORACLE 应用系统设计的基本知识和给出一些有用的实例;第二部分是介绍ORACLE PL/SQL知识,主要讲述ORACLE数据库PL/SQL程序设计所用到基本知识,这部分给出进行应用设计所必需的基础知识。这两部分的内容都尽可能做到内容简洁而全面。特点是,1.用简单明了的语句对解释各个部分的内容,省去一些理论性的解释;2.给出作者在应用设计和开发中的一些具体的例子,为软件人员提供一些借鉴,省去查阅大量资料的时间。3.给出了许多资料所没有提供的一些使用技巧,如导出触发器等。总之,内容基本上包括当前Oracle8I的最新内容。同时也覆盖了最新的ORACLE8iOCP培训大纲的内容。不仅包含ORACLE 程序设计人员、DBA所必须掌握的知识,而且还含盖了系统分析员所要求的内容。与本书(讲稿)相伴的还有《Oracle8i/9i初级数据库管理》和《Oracle8i/9i高级数据库管理》。

      全书内容简练实用,可作为ORACLE 数据库管理人员参考,也可作为应用开发人员和系统分析与设计人员以及大学计算机专业教学的参考资料。由于作者水平所限,加之ORACLE的产品与内容的浩瀚,在资料的整理与收集中可能有不少错误和不妥之处,希望读者给予批评制正。

 

 

 


                                      目            录

第一部分  Oracle SQL*PLUS基础... 23

第一章  Oracle数据库基础... 23

§1.1   理解关系数据库系统(RDBMS)... 23

§1.1.1  关系模型... 23

§1.1.2  Codd十二法则... 24

§1.2   关系数据库系统(RDBMS)的组成... 24

§1.2.1  RDBMS 内核... 24

§1.2.2  数据字典概念... 25

§1.3   SQL、SQL*Plus及 PL/SQL. 25

§1.3.1  SQL和SQL*PLUS的差别... 25

§1.3.2  PL/SQL语言... 27

§1.4  登录到SQL*PLUS. 27

§1.4.1  UNIX环境... 27

§1.4.2  Windows NT和WINDOWS/2000环境... 29

§1.5  常用SQL*PLUS 附加命令简介... 32

§1.5.1  登录到SQL*PLUS. 32

§1.5.2  EXIT和QUIT. 32

§1.5.3  DESCRIBE(显示表、视图结构)33

§1.5.4  LIST(列出)命令... 33

§1.5.5  Change(替换字符串)命令... 34

§1.5.6  Append(追加字符串)命令... 34

§1.5.7  Save保存当前缓冲区命令到文件... 35

§1.5.8  GET将命令文件读到缓冲区... 35

§1.5.9  SPOOL将信息记录到文件中... 36

§1.5.10  再运行当前缓冲区的命令... 36

§1.6  常用数据字典简介... 37

§1.7  ORACLE数据类型... 38

§1.8  SQL 语句基础... 44

§1.8.1   SQL语句所用符号... 44

§1.8.2   简单select 查询... 45

§1.9   伪列及伪表... 46

§1.10  使用SQL Worksheet工作... 46

第二章 查询基础... 50

§2.1   SELECT语句... 50

§2.2   SQL中的单记录函数... 50

§2.2.1   单记录字符函数... 50

§2.2.2   单记录数字函数... 56

§2.2.3   单记录日期函数... 62

§2.2.4   单记录转换函数... 65

§2.2.5   其它的单记录函数... 68

§2.3   SQL中的组函数... 73

§2.3.1   多记录组函数... 73

§2.3.2   带 GROUP  BY 的计算... 75

§2.3.3   用 HAVING  来限制分组的计算... 75

§2.4   控制和格式化输出... 76

§2.4.1   用 ORDER BY 子句来对结果进行排序... 76

§2.4.2   用 BREAK 命令 来对结果进行排列... 76

§2.4.3   用 COMPUTE 命令对结果进行格式化... 79

§2.5   配置会话环境... 82

§2.5.1   ARRAYSIZE(取回的行数)... 82

§2.5.2   AUTOCOMMIT(自动提交)83

§2.5.3   LINESIZE(行显示宽度)83

§2.5.4   LONG(长类型显示字节数)83

§2.5.5   PAGESIZE(页行数)83

§2.5.6   PAUSE(暂停)84

§2.5.7   SPACE(列间空格)84

§2.5.8   Termout (启/停屏幕显示)84

§2.5.9   ECHO (启/停命令显示)84

§2.5.10  TRANSACTION (启动事务)85

§2.5.11  SHOW ALL(列出所有参数)85

§2.6   格式化输出... 87

§2.6.1   一般数据的格式化输出... 87

§2.6.2   日期的格式化输出... 88

§2.7  加标题... 89

§2.8  建立简单报告... 90

§2.9  输入变量... 91

第三章  表及索引的定义操作... 94

§3.1  建立表结构... 94

§3.1.1  建立表结构命令... 94

§3.1.2  建立表结构例子... 96

§3.1.3  建立临时表结构... 97

§3.3  修改表结构... 98

§3.3.1  修改表结构命令... 98

§3.3.2  修改表结构例子... 99

§3.3.3  删除表结构... 101

§3.3.4  使用CHECK作限制约束... 101

§3.3.5  使用UNRECOVERABLE创建表... 102

§3.3.6  将表移动到新的数据段或新的表空间... 102

§3.3.7  手工分配表的存储空间... 104

§3.3.8  标记不使用的列和删除不使用的列... 104

§3.3  主键... 106

§3.3.1  创建主键... 106

§3.3.2  改变主键... 109

§3.3.3  删除主键... 109

§3.4  外部键... 110

§3.4.1  建立外部键... 110

§3.4.2  修改外部键... 112

§3.4.3  删除外部键... 112

§3.5   索引... 112

§3.5.1  建立索引... 112

§3.5.2  修改索引... 114

§3.5.3  删除索引... 115

§3.6  新索引类型... 115

§3.6.1  基于函数的索引... 115

§3.6.2  反向键索引... 117

§3.6.3  索引组织表... 117

§3.7  抽象数据类型的使用... 118

§3.8  大数据类型的使用... 119

§3.8.1  可用数据类型... 119

§3.8.2  为LOB数据类型指定存储... 120

§3.8.3  操作和检索LOB数据... 121

§3.9  表和索引有关的数据字典... 124

§3.9.1  表和索引数据字典... 124

§3.9.2  数据字典查询例子... 125

第四章 视图、同义词和序列... 128

§4.1  视图... 128

§4.1.1  使用视图来修改表中数据... 128

§4.1.2  创建一个新视图... 128

§4.1.3  删除一个视图... 130

§4.1.4  改变视图... 131

§4.2  实体视图(MATERIALIZED VIEW)131

§4.2.1  创建实体视图... 131

§4.2.2  创建实体视图日志... 137

§4.2.3  修改实体视图... 139

§4.2.4  修改实体视图日志... 141

§4.2.45  实体视图完整例子... 142

§4.3  序号(sequence)146

§4.3.1  建立序号... 146

§4.3.2  修改序号... 147

§4.3.3  使用序号... 147

§4.3.4  删除序号... 147

§4.4  同义词... 148

§4.4.1  建立同义词... 148

§4.4.2  删除同义词... 149

§4.5  视图、同义词和序列有关的数据字典... 149

第五章 簇与分区... 150

§5.1  簇( cluster )150

§5.1.0  簇概念... 150

§5.1.1  建立簇... 152

§5.1.2  改变簇... 155

§5.1.3  删除簇... 155

§5.1.4  删除簇索引... 156

§5.1.5  收集簇信息... 156

§5.2  分区... 158

§5.2.1  分区的优点... 158

§5.2.2  分区的方法... 159

§5.2.3  创建表的分区... 159

§5.2.3  创建索引的分区... 164

§5.2.4  维护表分区和索引分区... 167

§5.3  簇与分区有关的数据字典... 169

§5.3.1  分区、簇数据字典列表... 169

§5.3.2  基本的分区、簇信息查询... 169

第六章  使用SQL 进行数据操作... 170

§6.1  INSERT操作... 170

§6.1.1  用文字插入操作... 171

§6.1.2  用子查询插入操作... 171

§6.2  UPDATE操作... 172

§6.2.1  用文字更新操作... 173

§6.2.2  用查询更新操作... 173

§6.2.3  用相关子查询更新操作... 174

§6.3  DETELE操作... 174

§6.3.1  用delete删除全部记录的操作... 174

§6.3.2  用delete有条件删除部分记录... 175

§6.3.3  用delete分段删除大量记录... 175

§6.4  insert、delete及update 的提交和撤消... 176

§6.4.1  自动提交的设置... 176

§6.4.2  保留点和撤消... 177

第七章  复杂查询语句的使用... 180

§7.1   复杂查询语句的使用... 180

§7.1.1  相关子查询... 180

§7.1.2  外连接... 180

§7.1.3  自我连接... 181

§7.1.4  UNION,INTERSECT及MINUS. 182

§7.2  创建复杂的视图... 183

§7.2.1  分组视图... 183

§7.2.2  合计视图... 183

§7.2.3  组合视图... 184

§7.3  家族树... 184

§7.3.1  排除单一体和分枝... 184

§7.3.2  遍历至根... 185

§7.4  在from 中使用视图... 187

第八章  一些高级的用法... 188

§8.1  关于DECODE. 188

§8.1.1  DECODE 中的if-then-else逻辑... 188

§8.1.2  DECODE 的简单例子... 188

§8.1.3  DECODE实现表的转置... 189

§8.2  关于访问远程数据库... 192

§8.2.1  数据库链接... 192

§8.2.2  使用同义词获得本地透明... 193

§8.2.3  在视图中使用user伪列... 194

§8.2.4  使用COPY功能... 195

§8.2.5  管理Oracle名称服务器... 196

§8.3  关于上下文的使用... 196

§8.3.1  设置上下文选项... 196

§8.3.2  为上下文查询设置表... 197

§8.3.3  优化文本索引... 199

§8.4  关于维数(DIMENSION)... 199

§8.4.1  CREATE DIMENSION语法... 200

§8.4.2  创建维的例子... 201

第九章  安全管理... 203

§9.1  CREATE USER 命令... 203

§9.2  建立用户... 204

§9.2.1  外部验证(Authenticated )用户... 204

§9.2.2  全局(Globally)验证用户-企业验证... 204

§9.3  ALTER USER 命令... 205

§9.4  DROP USER 命令... 205

§9.5  GRANT 命令与REVOKE 命令... 206

§9.5.1  GRANT 命令... 206

§9.5.2  REVOKE 命令... 206

§9.6  权限和角色... 207

§9.6.1  建立角色... 207

§9.6.2  给角色授权... 208

§9.6.3  授权角色给用户... 209

§9.7  有关的数据字典... 209

§9.7.1  与用户、角色与权限有关的数据字典... 209

§9.7.2  查询数据字典信息... 209

第十章 其它一些常见问题及技巧... 212

§10.1  一些常见问题... 212

§10.1.1  Oracle与2000年问题... 212

§10.1.2  如何正确插入日期数据... 213

§10.1.3  在查询中只返回满足条件的部分记录... 214

§10.1.4  快速大量删除数据Truncate. 215

§10.1.5  Rowid的使用... 215

§10.1.6  在查询中不让记录被更新... 217

§10.1.7  EXCEPTIONS(违反完整性)问题... 217

§10.1.8  Not  in和Not Exists218

§10.1.9  关于 COPY命令... 218

§10.1.10  列值为NULL情形的处理... 219

§10.1.11  使用 product_user_file来限制用户使用产品... 220

§10.2  常用技巧... 221

§10.2.1  long 类型的查询... 222

§10.2.2  如何确定执行时间... 222

§10.2.3  如何终止用户会话... 222

§10.2.4  用TRANSLATE对数据加密和解密... 224

§10.2.5  如何用查询来修改数据... 225

§10.2.6  如何产生创建用户的脚本... 226

§10.2.7  如何产生创建表结构的脚本... 227

§10.2.8  如何产生创建视图的脚本... 229

§10.2.9  如何产生创建序号的脚本... 229

§10.2.10  如何为用户创建公共同义词... 229

第二部分  Oracle PL/SQL基础... 231

第十一章  PL/SQL 程序设计简介... 231

§11.1  概述... 231

§11.2  SQL与PL/SQL. 231

§11.2.1   什么是PL/SQL?. 231

§11.2.1   PL/SQL的好处... 232

§11.2.1.1  有利于客户/服务器环境应用的运行... 232

§11.2.1.2  适合于客户环境... 232

§11.2.1.3  客户及服务器端的好处... 232

§11.2.2  PL/SQL 可用的SQL语句... 233

§11.3   运行PL/SQL程序... 233

§11.4   PL/SQL内置包... 234

第十二章PL/SQL 块结构和组成元素... 235

§12.1   PL/SQL结构... 235

§12.2   PL/SQL块... 236

§12.3   标识符... 236

§12.4   PL/SQL 变量类型... 237

§12.4.1  变量类型... 237

§12.4.2  复合类型(记录和表)... 238

§12.4.3  使用%ROWTYPE. 240

§12.4.4  LOB类型... 240

§12.4.5  用户定义的子类型... 241

§12.4.6  数据类型的转换... 243

§12.5   运算符和表达式(数据定义)243

§12.5.1  关系运算符... 243

§12.5.2  一般运算符... 244

§12.5.3  逻辑运算符... 244

§12.6   变量赋值... 245

§12.6.1  字符及数字运算特点... 245

§12.6.2  Boolean 赋值... 245

§12.6.3  数据库赋值... 245

§12.6.4  可转换的类型赋值... 246

§12.7  变量作用范围以可见性... 248

§12.8  注释... 248

§12.9  简单例子... 249

§12.9.1   简单数据插入例子... 249

§12.9.2   简单数据删除例子... 249

第十三章PL/SQL 处理流程... 250

§13.1  条件语句... 250

§13.2  循环... 251

§13.3  标号和GOTO.. 254

§13.4  NULL 语句... 255

第十四章 光标的使用... 255

§14.1 光标概念... 255

§14.1.1 处理显式光标... 255

§14.1.2 处理隐式光标... 257

§14.2 光标循环... 258

§14.2.1 简单循环... 258

§14.2.2 WHILE循环... 259

§14.2.3 光标 FOR  循环... 260

§14.2.4 关于NO_DATA_FOUND和%NOTFOUND.. 260

§14.2.5SELECT  FOR  UPDATE 光标... 261

§14.3 光标变量... 262

§14.3.1 声明光标变量... 262

§14.3.2 为光标变量分配存储空间... 262

§14.3.3 打开光标变量... 262

§14.3.4 关闭光标变量... 262

§14.3.5 光标变量例子... 263

§14.3.6 光标变量... 265

第十五章 错误处理... 267

§15.1 异常处理概念... 267

§15.1.1 预定义的异常处理... 267

§15.1.2 触发异常情态... 268

§15.1.3 处理异常情态... 269

§15.1.4  用户定义的异常处理... 270

§15.2 异常情态传播... 271

§15.2.1 在执行部分引发异常情态... 271

§15.2.2 在声明部分引发异常情态... 272

§15.3 异常处理编程... 273

§15.4  在 PL/SQL 中使用 sqlcode,sqlerrm.. 273

第十六章 存储过程和函数... 276

§16.1  引言... 276

§16.2  存储过程... 276

§16.2.1  创建过程... 276

§16.2.2  使用过程... 278

§16.2.3  开发存储过程步骤... 279

§16.2.3.1  编辑存储过程源码... 279

§16.2.3.2  对存储过程程序进行解释... 279

§16.2.3.3  调试源码直到正确... 279

§16.2.3.4  授权执行权给相关的用户或角色... 279

§16.2.4  与存储过程相关数据字典... 280

§16.3  创建函数... 281

§16.4  过程和函数中的例外处理... 282

§16.4.1  使用系统定义的例外处理... 282

§16.4.1.1  没有例外处理的缺点... 283

§16.4.1.2  使用预定义的例外处理... 283

§16.4.2  使用用户定义的例外处理+. 286

§16.4.2.1  定义的用户例外处理... 286

§16.4.2.2  使用户EXCEPTION_INIT处理... 286

§16.4.2.3  使用户raise_application_error处理... 286

第十七章 创建包和使用包... 287

§17.1  引言... 287

§17.2  包的定义... 288

§17.3  包的开发步骤... 289

§17.4  包的头部说明... 289

§17.5  包体的说明... 290

§17.6  删除过程、函数和包... 293

§17.7  包的管理... 293

§17.7.1  包有关的数据字典... 293

§17.7.2  包中无效对象的查询和编译... 294

§17.7.3  包源代码的导出... 296

第十八章 触发器... 297

§18.1  触发器类型... 297

§18.1.1 DML触发器... 297

§18.1.2 替代触发器... 298

§18.1.3 系统触发器... 298

§18.2  创建触发器... 298

§18.2.1 创建DML触发器... 299

§18.2.2 创建替代(Instead_of)触发器... 300

§18.2.3 创建系统触发器... 300

§18.2.4 触发器触发次序... 302

§18.2.5 使用触发器谓词... 302

§18.3  删除和使能触发器... 303

§18.4  创建触发器的限制... 304

§18.5 变异表... 305

§18.5.1 变异表典型例子... 307

§18.5.2 变异表错误的处理... 308

§18.6  触发器数据字典与管理... 309

§18.6.1  触发器数据字典... 309

§18.6.2  无效触发器的编译... 310

第十九章 外部存储过程... 311

§19.1 什么是外部例程... 311

§19.2  C外部例程... 311

§19.2.1  调用步骤... 312

§19.2.2  参数映射( 转换)317

第二十章 会话间通信... 319

§20.1  DBMS_PIPE. 319

§20.1.1 发送消息... 319

§20.1.2 接收消息... 320

§20.1.3 示例... 321

§20.2  DBMS_ALERT. 340

§20.2.1  使用警告... 341

§20.2.2  警告所用的各个过程... 341

§20.2.3  警告例子... 342

§20.3  DBMS_PIPE 和 DBMS_ALERT. 343

第二十一章 数据库作业和文件I/O.. 344

§21.1  数据库作业... 344

§21.1.1后台进程... 344

§21.1.2运行作业... 344

§21.1.3失效作业... 346

§21.1.4删除作业... 347

§21.1.5修改作业参数... 348

§21.1.6与作业参数有关数据字典... 350

§21.2  文件I/O.. 350

§21.2.1 安全性... 351

§21.2.2 打开和关闭文件... 351

§21.2.3文件输出... 353

§21.2.3文件输入... 354

§21.2.4文件操作例子... 354

第二十二章 在PL/SQL 使用SQL语句... 355

§22.1在PL/SQL 使用DML语句... 355

§22.2 伪列... 357

§22.3 GRANT、REVOKE 和权限... 358

§22.3.1  对象和系统权限... 358

§22.3.2  GRANT和REVOKE命令语法... 358

§22.4 事务控制... 359

§22.4.1 COMMIT 和 ROLLBACK.. 359

§22.4.2 保留点 SAVEPOINT. 360

§22.5 在PL/SQL中使用SQL函数... 361

§22.5.1 错误处理函数... 362

§22.5.2 数字函数... 362

第二十三章 PL/SQL程序的测试和调试... 363

§23.1 问题诊断... 363

§23.1.1  调试指南... 363

§23.1.2  显示在编译产生的错误... 363

§23.2 插入测试表... 364

§23.3 DBMS_OUTPUT的使用... 364

§23.4 PL/SQL调试器... 365

§23.4.1 ProcedureBuilder调试器... 365

§23.4.2SQL-Station调试器... 366

§23.5  程序设计方法... 366

§23.5.1  模块化程序设计... 366

§23.5.2  自顶向下设计... 366

§23.5.3  数据抽象... 366

第二十四章 性能及其它问题... 367

§24.1共享池... 367

§24.1.1  共享池工作原理... 367

§24.1.2  估计共享池大小... 368

§24.1.3  将PL/SQL 驻留在共享池中... 369

§24.2  SQL 语句调整... 370

§24.3  网络问题... 373

§24.4  PL/SQL wrap(转换器)373

§24.4.1  运行 wrap实用程序... 373

§24.4.2  输入和输出文件... 374

§24.5   DBMS_OUTPUT的使用... 374

第二十五章 对象类型... 376

§25.1   对象类型定义... 376

§25.1.1   定义对象类型头... 376

§25.1.2   定义对象类型体... 376

§25.1.3   定义对象类型例子... 377

§25.1.4   初始化对象类型... 378

§25.1.5   使用对象类型... 379

§25.2   对象类型修改... 381

§25.3   对象类型删除... 381

第二十六章 动态PL/SQL简介... 383

§26.1 概述... 383

§26.1.1 静态SQL和动态SQL. 383

§26.1.2 用DBMS_SQL 包实现动态... 383

§26.1.3 用本地动态SQL实现动态... 385

§26.2 使用DBMS_SQL进行动态编程... 385

§26.2.1 执行DML、DDL及Alter session语句... 385

§26.2.2 示例... 388

§26.2.3 执行DDL 语句... 389

§26.2.4 执行PL/SQL 块... 390

§26.4  本地动态SQL. 391

§26.4.1使用EXECUTE IMMEDIATE语句... 391

§26.4.2向后兼容情况... 392

§26.4.3指定参数模式... 393

第二十七章 LOB和DBMS_LOB包简介... 394

§27.1 LOB类型一般使用... 394

§27.1.1  LOB类型存储... 395

§27.1.2  临时LOB类型... 395

§27.1.3  LOB类型的接口... 396

§27.2 一般LOB表与数据加载... 396

§27.2.1  建立包含LOB的表... 396

§27.2.2  用EMPTY_CLOB或EMPTY_BLOB插入LOB. 398

§27.2.3  一般的LOB插入... 399

§27.3 内部LOB和DBMS_LOB的使用... 399

§27.3.1  APPEND过程... 400

§27.3.2  CLOSE过程... 401

§27.3.3  COMPARE函数... 401

§27.3.4  COPY过程... 403

§27.3.5  ERASE过程... 405

§27.3.6  GETCHUNKSIZE函数... 406

§27.3.7  GETLENGTH函数... 407

§27.3.8  INSTR函数... 408

§27.3.9  READ过程... 409

§27.3.10  SUBSTR函数... 410

§27.3.11  WRITE过程... 411

§27.3.12  WRITEAPPEND过程... 412

§27.4临时LOB. 413

§27.4.1  建立临时LOB. 413

§27.4.2  查看临时LOB. 414

§27.4.3  释放临时LOB. 414

§27.4.4  从BFILE中加载临时LOB. 415

§27.4.5  查看临时LOB是否打开... 415

§27.4.6  显示临时LOB数据... 416

§27.4.7  从临时LOB读数据... 417

§27.4.8  从临时LOB读部分数据... 418

§27.4.9  比较两个临时LOB数据... 419

§27.4.10  查看临时LOB模式的存在... 420

§27.4.11  得到临时LOB的长度... 421

§27.4.12  拷贝部分临时LOB数据... 421

§27.4.13  为临时LOB拷贝位置... 422

§27.4.14  加临时LOB到另外的LOB. 423

§27.4.15  写追加到临时LOB. 424

§27.4.16  写数据到临时LOB. 424

§27.4.17  修理临时LOB数据... 425

§27.4.18  删除临时LOB数据... 426

§27.5外部LOB (BFILE)426

§27.5.1  BFILE目录指定... 426

§27.5.2  建立包括BFILE列的表... 427

§27.5.3  用BFILENAME()插入数据... 428

§27.5.4  从另外表选择BFILE插入数据... 429

§27.5.5  用初始化BFILE位置来插入数据BFILE行... 429

§27.5.6  动态加载数据BFILE的表... 429

§27.5.7  用BFILE数据来加载LOB数据... 430

§27.5.8  用FILEOPEN打开BFILE. 431

§27.5.9  用OPEN打开BFILE. 431

§27.5.10  用FILEISOPEN看BFILE是否打开... 431

§27.5.11  用ISOPEN看BFILE是否打开... 432

§27.5.12  显示BFILE. 432

§27.5.13  从BFILE中读数据... 433

§27.5.14  读部分BFILE. 433

§27.5.15  比较BFILE. 434

§27.5.16  判断BFILE是否存在模式... 434

§27.5.17  判断BFILE是否存在... 435

§27.5.18  得到BFILE长度... 435

§27.5.19  拷贝BFILE的LOB位置... 436

§27.5.20  得到目录别名和文件名字... 436

§27.5.21  用初始化BFILE位置更新BFILE.. 437

§27.5.22  用FILECLOSE关闭BFILE. 437

§27.5.23  用CLOSE关闭BFILE. 437

§27.5.24  用CLOSEALL关闭所有BFILE. 438

§27.5.25  用DELETE等删除BFILE数据... 438

§27.6  使用SQL*loader加载LOB. 438

§27.6.1  加载图象和文本文件... 438

§27.6.2  加载文本文件... 439

第二十八章 PL/SQL编程技巧... 442

§28.1用触发器实现日期格式的自动设置... 442

§28.2如何避免TOO_MANY_ROWS错误... 443

§28.3如何解决TOO_MANY_ROWS问题... 446

§28.4如何在PL/SQL中使用数组... 447

§28.5如何使用触发器完成数据复制... 448

§28.6在PL/SQL中实现Truncate. 449

§28.7如何导出存储过程、触发器的代码... 450

附录A:SQL及SQL*PLUS 命令参考... 459

%FOUND.. 460

%ISOPEN.. 460

%NOTFOUND.. 461

%ROWCOUNT. 462

%ROWTYPE. 463

%TYPE. 463

(+)464

@ (“at” 号)464

@@.. 465

ABS. 465

ACCEPT. 466

ACOS. 466

ADD_MONTHS. 467

ALTER CLUSTER. 467

ALTER DATABASE. 468

ALTER FUNCTION.. 469

ALTER INDEX.. 469

ALTER PACKAGE. 470

ALTER PROCEDURE. 470

ALTER PROFILE. 471

ALTER RESOURCECOST. 471

ALTER ROLE. 472

ALTER ROLLBACKSEGMENT. 472

ALTER SEQUENCE. 473

ALTER SESSION.. 473

ALTER SNAPSHOT. 474

ALTER SNAPSHOT LOG.. 475

ALTER SYSTEM.. 475

ALTER TABLE. 476

ALTER TABLESPACE. 477

ALTER TRIGGER. 478

ALTER TYPE. 478

ALTER USER. 479

ALTER VIEW.. 480

ANALYZE. 480

APPEND.. 481

ASCII481

ASIN.. 482

ATAN.. 482

ATAN2. 483

AUDIT. 483

AVG.. 484

BFILENAME. 484

BLOCK.. 485

BTITLE. 486

CEIL. 487

CHANGE. 488

CHARTOROWID.. 488

CHR. 489

CLEAR. 489

CLOSE. 490

COLUMN.. 490

COMMENT. 491

COMMIT. 492

COMPUTE. 492

CONCAT. 493

CONCATENATE. 493

CONNECT BY.. 494

CONVERT. 494

COPY.. 495

COS. 496

COSH.. 496

COUNT. 497

CREATE CLUSTER. 497

CREATE CONTROLFILE. 498

CREATE DATABASE. 499

CREATE DATABASELINK.. 500

CREATE PROFILE. 500

CREATE DIRECTORY.. 501

CREATE FUNCTION.. 501

CREATE INDEX.. 502

CREATE LIBRARY.. 503

CREATE PACKAGE. 503

CREATE PACKAGE BODY.. 504

CREATE PROCEDURE. 506

CREATE ROLE. 507

CREATE ROLLBACKSEGMENT. 507

CREATE SCHEMA.. 508

CREATE SEQUENCE. 509

CREATE SNAPSHOT. 509

CREATE SNAPSHOTLOG.. 510

CREATE SYNONYM.. 511

CREATE TABLE. 511

CREATE TABLESPACE. 513

CREATE TRIGGER. 514

CREATE TYPE. 515

CREATE TYPE BODY.. 516

CREATE USER. 516

CREATE VIEW.. 517

CURRVAL. 518

CURSOR_ALREADY_OPEN.. 518

DATATYPE. 519

DATATYPE —CHAR. 519

DATATYPE —DATE. 520

DATATYPE —FLOAT. 520

DATATYPE —LONG.. 520

DATATYPE —LONGRAW.. 521

DATATYPE —MLSLABEL. 521

DATATYPE —NUMBER. 521

DATATYPE —RAW.. 522

DATATYPE —ROWID.. 522

DATATYPE —VARCHAR. 522

DATATYPE —VARCHAR2. 522

DECLARE. 523

DECODE. 523

DEFINE. 524

DEL. 524

DELETE. 525

DEREF. 526

DESCRIBE. 526

DROP CLUSTER. 527

DROP DATABASE LINK.. 527

DROP DIRECTORY.. 528

DROP FUNCTION.. 528

DROP INDEX.. 528

DROP LIBRARY.. 529

DROP PACKAGE. 529

DROP PROCEDURE. 530

DROP PROFILE. 530

DROP ROLE. 531

DROP ROLLBACKSEGMENT. 531

DROP SEQUENCE. 532

DROP SNAPSHOT. 532

DROP SNAPSHOT LOG.. 532

DROP SYNONYM.. 533

DROP TABLE. 533

DROP TABLESPACE. 534

DROP TRIGGER. 534

DROP TYPE. 535

DROP TYPE BODY.. 535

DROP USER. 536

DROP VIEW.. 536

DUMP. 537

DUP_VAL_ON_INDEX.. 537

EDIT. 538

EMPTY_BLOB. 538

EMPTY_CLOB. 539

EXCEPTION INITPragma. 539

EXECUTE. 540

EXISTS. 540

EXIT. 541

EXIT. 542

EXIT-WHEN.. 542

EXP. 543

EXPLAIN PLAN.. 543

FETCH.. 544

FLOOR. 545

FOR-LOOP. 545

FORMAT. 546

FORMAT —DATE. 546

FORMAT —NUMBER. 547

GET. 547

GLB. 548

GOTO.. 548

GRANT. 549

GREATEST. 550

GREATEST_LB. 550

HEXTORAW.. 551

HOST. 551

IF-THEN.. 552

IF-THEN-ELSE. 552

IF-THEN-ELSEIF. 553

INITCAP. 554

INPUT. 554

INSERT. 555

INSTR. 555

INSTRB. 556

INTERSECT. 557

INVALID_CURSOR. 557

INVALID_NUMBER. 558

KEYWORDS. 559

LABELS. 560

LAST_DAY.. 561

LEAST. 561

LEAST_LB. 562

LENGTH.. 562

LENGTHB. 562

LIKE. 563

LIST. 564

LN.. 565

LOCK TABLE. 565

LOG.. 566

LOGIN_DENIED.. 566

LOOP. 567

LOWER. 568

LPAD.. 568

LTRIM.. 569

LUB. 569

MAKE_REF. 570

MAX.. 570

MIN.. 571

MINUS. 571

MOD.. 572

MONTHS_BETWEEN.. 572

NEW_TIME. 573

NEXT_DAY.. 574

NEXTVAL. 574

NLS_CHARSET_DECL_LEN.. 575

NLS_CHARSET_ID.. 575

NLS_CHARSET_NAME. 576

NLS_INITCAP. 576

NLS_LOWER. 577

NLS_UPPER. 577

NO_DATA_FOUND.. 578

NOAUDIT. 579

NOT_LOGGED_ON.. 579

NULL. 580

NVL. 581

OPEN.. 581

OPEN-FOR. 582

运算符... 582

运算符— < >. 583

运算符—>. 583

运算符—> =. 584

运算符—! =. 584

运算符—*. 585

运算符—+. 586

运算符—-*. 586

运算符—/587

运算符—<=. 587

运算符—=. 588

运算符—AND.. 589

运算符—BETWEEN.. 589

运算符—IN.. 590

运算符—IS NOT NULL. 590

运算符—IS NULL. 591

运算符—NOT. 591

运算符—NOT BETWEEN.. 592

运算符—NOT IN.. 592

运算符—OR. 593

PRIOR. 593

PROGRAM_ERROR. 594

PROMPT. 595

PSEUDOCOLUMN.. 595

RAISE. 595

RAWTOHEX.. 596

RECORD.. 596

REFTOHEX.. 597

REMARK.. 598

RENAME. 598

REPFOOTER. 599

REPHEADER. 599

REPLACE. 600

REPLACE. 601

RETURN.. 601

REVOKE. 602

ROLLBACK.. 603

ROUND.. 603

ROWIDTOCHAR. 604

ROWTYPE_MISMATCH.. 605

RPAD.. 606

RTRIM.. 606

SAVE. 607

SAVEPOINT. 607

SELECT. 608

SELECT INTO.. 608

SET. 609

SET ROLE. 611

SET TRANSACTION.. 612

SHOW.. 612

SIGN.. 613

SIN.. 614

SINH.. 614

SOUNDEX.. 615

SPOOL. 615

SQLERRM.. 616

SQLPLUS. 616

SQRT. 617

START. 617

STDDEV.. 618

STORAGE. 618

STORAGE_ERROR. 619

STORE. 619

SUBSTR. 620

SUBSTRB. 620

SUM.. 621

SYSDATE. 622

TABLE. 622

TAN.. 623

TANH.. 623

TIMEOUT_ON_RESOURCE. 624

TIMING.. 624

TO_CHAR (date)625

TO_CHAR (label)625

TO_CHAR (number)626

TO_DATE (char)626

TO_LABEL (char)627

TO_MULTI_BYTE(char)627

TO_NUMBER (char)628

TO_SINGLE_BYTE(char)628

TOO_MANY_ROWS. 629

TRANSLATE. 629

TRUNC (date)630

TRUNC (number)631

TRUNCATERUNCATE. 631

TTITLE. 632

UID.. 633

UNDEFINE. 633

UNION.. 634

UNION ALL. 634

UPDATE. 635

UPPER. 636

USER. 636

USERENV.. 637

VALUE_ERROR. 638

VARIABLE. 638

VARIABLEASSIGNMENT. 639

VARIANCE. 639

VSIZE. 640

RESERVED WORDS. 640

WHENEVER OSERROR. 641

WHENEVER SQLERROR. 642

WHILE-LOOP. 642

ZERO_DIVIDE. 643

 

 

 


 

第一部分  OracleSQL*PLUS基础

 

第一章  Oracle数据库基础

Oracle的SQL*PLUS是设计所有应用系统的基础工具。要想将应用系统设计成一个健壮的、性能优越的系统。最关键的是要理解RDBMS的真正含义和结构,理解OracleSQL*PLUS 的特点和核心,弄清关系数据库与桌面数据库的差别。比如理解数据的完整性、一致性、索引、视图等。只有这样才能设计出符合Oracle特点的应用系统。从而保证系统在提供使用后不会出现一致性、性能等问题。

§1.1   理解关系数据库系统(RDBMS)

CODASYL(数据系统语言协会)是数据库任务组(Database Task Group,DBTG)创建的一种数据库标准,这是一种基于COBOL的网络数据库标准。

 

§1.1.1  关系模型

一个描述两个集合的元素如何相互联系或如何一一对应的数学概念,对于数据库来说,关系只是一个带有一些特殊属性的表。所以有:

 

l  数据的基础项是关系

l  在这些表上的操作只产生关系

一个关系表必须符合某些特定条件,才能成为关系模型的一部分

l  储存在单元中的数据必须是原子的。每个单元只能存储一条数据,叫信息原则(Information Principle)。如果存储多条则违反信息原则。特舒情况下可能需要违反信息原则。

l  储存在列下的数据必须具有相同的数据类型。

l  每一行是唯一的(没有完全相同的行)。

l  列没有顺序。

l  行没有顺序

l  列有一个唯一性的名称。

 

关系模型的另一个是完整性原则。它包括实体完整性原则(Entity integrity rule)和引用完整性原则( Referential integrity rule ),如:

l  主键(Primary key )是能唯一标识行的一列或一组列的集合。

l  由多个列构成的主键称为连接键(Concatenated key)、组合键(Compound key ),或称作为复合键(Composity key )。

 

另外就是外部键(Foreign key )是一个表中的一列或一组列,它们在其它表中作为主键而存在。一个表中的外部键被认为是对另外一个表中主键的引用。实体完整性原则简洁地表明主键不能全部或部分地空缺或为空,引用完整性原则简洁地表明一个外键必须为空或者它所引用的主键当前存在值相一致。

 

§1.1.2  Codd十二法则

Oracle数据库系统是一个完美的完全符合数据库技术的关系数据库系统。要想你的应用设计按照数据库原理来进行,最重要的就是理解Oracle的结构、语句和命令。Codd提出的十二条法则在Oracle系统中都可以找到:

 

1)信息法则。

2)授权存储法则,每一个数据项都通过“表名+行主键+列名”的组合形成访问。

3)必须以一致的方法使用空值。

4)一个活跃的、在线数据字典应作为关系型表被储存

5)必须提供数据存取语言进行存取访问。

6)所有能被更新的视图应当是可被更新的。

7)必须有集合级的插入、更新和删除。

8)物理数据的独立性。即应用不依赖物理结构。

9)逻辑数据的独立性。如果一个表被分成两个部分,则应用视图连接在一起,以便不会对应用产生影响。

10)    完整性的独立性。完整性规则应该储存在数据字典中。

11)    分布独立性。一个数据库即使被分布,也应该能工作。

12)    非破坏性原则。如果允许低级存取,一定不能绕过安全性和完整性原则。

 

§1.2   关系数据库系统(RDBMS)的组成

RDBMS由两部分组成,即数据库系统内核(软件)和数据字典(内核用于管理数据库系统的数据结构)两部分。

 

§1.2.1  RDBMS 内核

RDBMS就是用来控制数据访问的操作系统。它的任务是按照一定的规则存储数据、检索数据及保护数据。

 

§1.2.2  数据字典概念

数据自动存放数据库中所有对象(如表,索引,视图等)所需的信息。Oracle 8i 的数据字典是存放数据库系统信息的一组表,从数据字典中的信息可以确认数据库中数据对象的基本信息及存放位置。

 

§1.3   SQL、SQL*Plus及PL/SQL

下面用简单的语言解释Oracle的常用产品所包含的SQL*PLUS和PL/SQL的关系。

§1.3.1  SQL和SQL*PLUS的差别

SQL是标准结构查询语言,而SQL*PLUS实际是包括标准的SQL和Oracle公司的一些命令组成的产品,因而Oracle公司将其取名为SQL*PLUS。下面是它们的解释。

 

1. SQL(StructuredQuery Language)

 

SQL有许多关键字,以下语句是常用于开头的语句:

Alter                       Insert 

Audit                       Lock 

Commit                      Noaudit

Comment                     Rename

Create                      Revoke

Delete                      Select

Drop                        Update

Grant                       Validate

 

注:

1.Oracle的SQL缓冲区一次只能存放一条SQL命令;

2.Validate(使生效) 在 oracle 中跟 Enable 一起用,但可以省去 Validate,所以许多资料都不介绍Validate 的用法。其语法如:

Enable{[Validate][Novalidate]}{ [UNIQUE][PRIMARY KEY]... } ...

 

2. SQL*PLUS

 

除SQL外,SQL*PLUS还包括称为SQL*PLUS命令的附加命令,这些命令主要用于形成复杂报表,编辑SQL命令,提供帮助信息,维护系统等。SQL*PLUS包括的命令如下:

 

@                    Connect

Host                  Set

#                     Copy

Input                 Show

$                     Define

List                  Spool

/                     Del 

Newpage               Sqlplus

Accept                Describe

Pause                 Start

Append                Disconnect

Quit                  Timing

Break                 Document 

Remark                Ttitle

Btitle                Edit   

Prompt                Undefine

Chang                 Execute

Print                 Save

Clear                 Exit

Run                   Column

Get                   Runform

Compute               Help

 

 

3. DDL(Data  Define Language)

 

对于结构查询语言(有时称SQL命令),可以将它们分成两组,一组是数据定义语言(DDL);另一组是数据操纵语言(DML)。其中用于数据定义的语言如下:

 

     Alter  procedure                     重编译过程

     Alter  table                         修改表的属性

     Analyze                               统计数据库对象性能值

    Alter  table  add Constraint         对已有的表加约束

     Create table                         建立表结构

     Create index                         建立索引

     Drop table                           删除表实体及相关的索引

     Drop index                           删除索引

     Grant                                 授权给用户或角色

     Truncate                              删除表中的所有行

     Revoke                                从用户或角色收回权限

 

4.DML(Data  Manipulation  Language)

 

对于结构查询语言的另一组是数据操纵语言(DML)。DML其中用于数据操纵的命令如下:

 

     Insert

     Delete

     Update

     Select

     Commit work

     Rollback

 

§1.3.2  PL/SQL语言

PL/SQL是OracleRDBMS (Oracle 6 之后版本)的一个组成部分,PL 是“过程化语言(ProcedureLanguage )”的缩写。PL/SQL语言是在SQL语言中结合了结构化过程语言成分的准第四代语言

 

使用PL/SQL的目的:

由于大多数PL/SQL是在服务端来运行,这样可减少由客户端运行程序时所需的网络数据流量。

可以使用PL/SQL的地方:

l  PL/SQL可以单独进行程序的编写,完成一般的处理功能;

l  在高级语言中可嵌入PL/SQL 块;

l  在4GL中可以嵌入PL/SQL块;

l  在PL/SQL程序中可以嵌入 HTML和XML。

 

§1.4  登录到SQL*PLUS

我们创建任何对象,如创建表、索引等都需要连接到Oracle中,这里用“登录”主要是Oracle的界面提供的是Login 这样的叫法。其实就是连接的意思。在Client/Server结构下,Oracle提供两种方式连接SQL*PLUS,其中SQL*NET  V2.x  版本(目前版本不再使用SQL*NET V2.x)提供在字符方式下连接到  SQL*PLUS,SQL*NET  V2. x版本提供在图形方式(Window)使用,目前版本的 ORACLE8/8i 都使用 NET8 连接.(NET8 不再支持字符终端)

 

§1.4.1  UNIX环境

在UNIX下,要确保客户端或服务器端与Oracle服务器系统进行连接,必须保证tnsnames.ora和listener.ora两个参数文件的正确配置。详细的配置解释在DBA章节里解释。下面是tnsnames.ora和listener.ora两个参数文件的内容显示。

 

1. tnsnames.ora参数文件:

INST1_HTTP =

  (DESCRIPTION =

    (ADDRESS_LIST =

      (ADDRESS = (PROTOCOL = TCP)(HOST =dbsvr)(PORT = 1521))

    )

    (CONNECT_DATA =

      (SERVER = SHARED)

      (SERVICE_NAME = s450)

      (PRESENTATION = http://admin)

    )

  )

 

EXTPROC_CONNECTION_DATA=

  (DESCRIPTION =

    (ADDRESS_LIST =

      (ADDRESS = (PROTOCOL = IPC)(KEY =EXTPROC))

    )

    (CONNECT_DATA =

      (SID = PLSExtProc)

      (PRESENTATION = RO)

    )

  )

 

S450 =

  (DESCRIPTION =

    (ADDRESS_LIST =

      (ADDRESS = (PROTOCOL = TCP)(HOST = dbsvr)(PORT = 1521))

    )

    (CONNECT_DATA =

      (SERVICE_NAME = s450)

    )

  )

 

2. listener.ora参数文件:

LISTENER =

  (DESCRIPTION_LIST =

    (DESCRIPTION =

      (ADDRESS_LIST =

        (ADDRESS = (PROTOCOL = TCP)(HOST = dbsvr)(PORT = 1521))

      )

      (ADDRESS_LIST =

        (ADDRESS = (PROTOCOL = IPC)(KEY =EXTPROC))

      )

    )

  )

 

SID_LIST_LISTENER =

  (SID_LIST =

    (SID_DESC =

      (SID_NAME = PLSExtProc)

      (ORACLE_HOME =/home/oracle/app/oracle/product/8.1.7)

      (PROGRAM = extproc)

    )

    (SID_DESC =

      (GLOBAL_DBNAME = s450)

      (ORACLE_HOME = /home/oracle/app/oracle/product/8.1.7)

      (SID_NAME = s450)

    )

  )

 

如果安装后已经正确地对上面的两个参数文件进行配置,则可以按照下面步骤进行登录:

 

1)先启动服务器端监听器:

lsnrctl start

2)用下面命令显式登录到 SQL*PLUS:

$sqlplususername/password

$SQLPLUS  username/password@connect_string

3)用下面命令隐式登录到 SQL*PLUS:

$sqlplus [enter]

Enter username:scott

Enterpassword:******

 

§1.4.2  WindowsNT和WINDOWS/2000环境

在NT/2000环境下,要使客户端能与Oracle服务器进行连接,tnsnames.ora和listener.ora参数文件的配置如下:

 

1. tnsnames.ora参数文件:

 ORA816.TAIJI.COM.CN =

  (DESCRIPTION =

    (ADDRESS_LIST =

      (ADDRESS = (PROTOCOL = TCP)(HOST =zhao)(PORT = 1521))

    )

    (CONNECT_DATA =

      (SERVICE_NAME = ora816)

    )

  )

 

EXTPROC_CONNECTION_DATA.TAIJI.COM.CN=

  (DESCRIPTION =

    (ADDRESS_LIST =

      (ADDRESS = (PROTOCOL = IPC)(KEY =EXTPROC1))

    )

    (CONNECT_DATA =

      (SID = PLSExtProc)

      (PRESENTATION = RO)

    )

  )

S450 =

  (DESCRIPTION =

    (ADDRESS_LIST =

    (ADDRESS = (PROTOCOL = TCP)(HOST =dbsvr)(PORT = 1521))

    )

    (CONNECT_DATA =

      (SERVICE_NAME = s450)

    )

  )

 

2. listener.ora参数文件:

 

LISTENER =

  (DESCRIPTION_LIST =

    (DESCRIPTION =

      (ADDRESS_LIST =

        (ADDRESS = (PROTOCOL = IPC)(KEY =EXTPROC1))

      )

      (ADDRESS_LIST =

        (ADDRESS = (PROTOCOL = TCP)(HOST =zhao)(PORT = 1521))

      )

    )

    (DESCRIPTION =

      (PROTOCOL_STACK =

        (PRESENTATION = GIOP)

        (SESSION = RAW)

      )

      (ADDRESS = (PROTOCOL = TCP)(HOST =zhao)(PORT = 2481))

    )

  )

 

SID_LIST_LISTENER =

  (SID_LIST =

    (SID_DESC =

      (SID_NAME = PLSExtProc)

      (ORACLE_HOME = D:\oracle)

      (PROGRAM = extproc)

    )

    (SID_DESC =

      (GLOBAL_DBNAME = ora816)

      (ORACLE_HOME = D:\oracle)

      (SID_NAME = ora816)

    )

  )

 

Windows NT/2000字符方式登录步骤:

1)先启动服务器端监听器:

lsnrctl start

2)用下面命令显式登录到 SQL*PLUS:

$sqlplususername/password

$SQLPLUS  username/password@connect_string

Windows NT/2000图形方式登录步骤:

1)点击“开始”=》“程序”=》“Oracle –OraHome81”=》“Application on Development”=》“SQL Plus”进入如下屏幕:

 

                 在WINDOWSNT/98/2000上的登录界面(sqlplus图)

 

 

可以在用户名框内输入用户、口令及主机字串;也可以分别进行输入。

 

§1.5  常用SQL*PLUS 附加命令简介

Oracle公司提供的附加语句(或称命令),可以满足程序人员和管理员的一些特殊操作要求。比如,在显示超过上百行记录信息时,可以采用每屏“暂停”来实现。要达到这样的目的,就要在SQL>下发 set pause on 命令。由于SQL*PLUS命令较多,下面仅给出最常用的几个命令的说明,详细的请参考附录。

§1.5.1  登录到SQL*PLUS

 

可以用下面命令登录到 SQL*PLUS,SQL*PLUS命令的简单语法如下:

 

SQLPLUS  [  [logon] | [start]  ]

 

logon可以是:

{username[/password][@connect_identifier]|/} [AS {SYSOPER|SYSDBA}]

|/NOLOG

 

注1:SQLPLUS主要是在命令方式下使用,在NT、WINDOWS/2000、UNIX的用法都一样。

注2:如果在UNIX下,SQLPLUS命令不被识别(不存在),则问题在环境变量PATH没有设置正确或者没有设置。SQLPLUS 可执行程序在$ORACLE_HOME/bin 目录下。

 

§1.5.2  EXIT和QUIT

 

可以用 exit 或quit 来终止SQL*PLUS的操作(会话)。语法如下:

 

{EXIT|QUIT} [SUCCESS|FAILURE|WARNING ]  

 

{EXIT|QUIT} 可以用exit 或quit ,目前它们的功能一样。

 

SUCCESS  正常退出

 

FAILURE 带提示错误代码的退出

 

WARNING  带提示警告代码的退出

 

COMMIT  退出前将未提交进行保存

 

例如:

SQL>exit

 

 

§1.5.3 DESCRIBE(显示表、视图结构)

DESCRIBE可以用(只要用DESC即可)来显示表、视图的列的定义,也可以显示同义词、函数或存储过程的说明。语法如下:

 

DESC[RIBE] {[schema.]object[@connect_identifier]}

 

 

Schema:用户名,如果省去,则为对象的所有者。

 

object

可以是表(table), 视图(view),类型( type), 存储过程(procedure),函数( function), 包(package)或同义词( synonym)

 

@connect_identifier

数据库连接字串

 

例:显示emp 表的结构:
 
SQL>desc emp

 

§1.5.4  LIST(列出)命令

可以用 LIST 命令来列出当前SQL缓冲区中的一行或多行命令语句。        

 

L[IST] [n|n m|n *|n LAST|*|* n|* LAST|LAST]

 

n 列出第n行

nm 列出n到m行

n * 列出第n行到当前行

n LAST 列出第n行到最末行

*  列出所有行

* n  列出当前行到第n行

*LAST列出当前行到最末行

LAST 列出最末行

 

例:

SQL> LIST

1 SELECT ENAME, DEPTNO, JOB

2 FROM EMP

3 WHERE JOB = ’CLERK’

4* ORDER BY DEPTNO

 

§1.5.5  Change(替换字符串)命令

 

可以用Change命令来改变字符串(即替换字符串)。语法如下:

 

C[HANGE] sepchar old [sepchar [new[sepchar]]]

 

Sepchar 为分隔符,可以是”/” 或”!”  -- 请使用者特别注意

 

 

Old 旧字串

 

New 新字串

 

例:将 除号(/)改为 乘号( * ),则需要命令为c!/!*! 。即:

SQL> l

  1* select sal,sal/100 from emp

SQL> c !/!*!

 

提醒:对于修改 / 字符的只能用 ! 来作分隔符(上例)。

 

例:将乘号( * )改为 加号( + ),则需要命令为c !/!*!   。即:

SQL> l

  1* select sal,sal*100 from emp

SQL> c/*/+/

  1* select sal,sal+100 from emp

SQL>

 

§1.5.6  Append(追加字符串)命令

 

可以用 Append命令来完成在当前行的末尾追加字符串。语法如下:

 

A[PPEND] text

 

Text  所要求追加的字符串

 

例:在当前行selectsal,sal+100 from emp 后加 where sal>=2000,则:

 

SQL> l

  1* select sal,sal+100 from emp

SQL> a  where sal>=2000

  1* select sal,sal+100 from emp wheresal>=2000

SQL>

 

§1.5.7 Save保存当前缓冲区命令到文件

 

可以用SAVE命令将当前的命令行保存到操作系统的文件中。语法如下:

 

SAV[E] filename[.ext][CRE[ATE]|REP[LACE]|APP[END]]

 

其中:

filename:你将把缓冲区中的内容存入到操作系统目录的文件名。

ext:若使用文件后缀,缺省的文件后缀为SQL。

 

例:

SQL>select  table_namefrom dict where  table_name like ‘%ROLE%’;

SQL>save c:\get_role

 

§1.5.8  GET将命令文件读到缓冲区

可以用GET 命令将操作系统的目录下的命令文件读到缓冲区(但不执行)。语法如下:

 

GET filename [.ext][LIS[T]|NOL[IST]]

其中:

filename: 希望加载到SQL缓冲区的文件名

ext: 文件的扩展名,缺省为 SQL.

 

例:

 

SQL>get c:\get_role

 

§1.5.9 SPOOL将信息记录到文件中

Oracle的SPOOL 命令可以实现将屏幕所出现的一切信息记录到操作系统的文件中直到SPOOL OFF为止。语法如下:

 

SPO[OL] [filename[.ext] |OFF | OUT]

其中:

filename:你想输出(spool)的文件名。

ext:文件的后缀。缺省的后缀是LST(或LIS)。

 

SQL>coltable_name for a20

SQL>col commentsfor a80

SQL>set linesize110

SQL>SPOOlc:\all_dict

SQL>selecttable_name,comments from dict;

 . . .  .. . (系统查询信息)

 

SQL>SPOOL OFF

 

§1.5.10  再运行当前缓冲区的命令

在SQL>方式下,如果希望在运行当前的命令,可用Run(或R)或用 / 来实现,如:

 

SQL> set lin 120

SQL> select  table_name from dict where  table_name like '%ROLE%';

 

TABLE_NAME

------------------------------

DBA_ROLES

DBA_ROLE_PRIVS

USER_ROLE_PRIVS

ROLE_ROLE_PRIVS

ROLE_SYS_PRIVS

ROLE_TAB_PRIVS

SESSION_ROLES

 

已选择7行。

 

SQL> l

  1* select table_name from dict where table_name like '%ROLE%'

SQL> /

 

TABLE_NAME

------------------------------

DBA_ROLES

DBA_ROLE_PRIVS

USER_ROLE_PRIVS

ROLE_ROLE_PRIVS

ROLE_SYS_PRIVS

ROLE_TAB_PRIVS

SESSION_ROLES

 

已选择7行。

 

§1.6  常用数据字典简介

ORACLE 提供许多内部数据字典, 用以管理系统的各种信息和参数(即数据库对象),下面列出几个常用的数据字典供初学者参考,其它方面的数据字典将在DBA管理中介绍。

ORACLE  数据字典的命名说明:

USER   为前缀----记录用户的所有对象信息

ALL    为前缀----记录包括 USER 记录和授权给PUBLIC或该用

       户的所有对象的信息。

DBA    为前缀----记录关于数据库对象(非用户对象)的信息。

V$     公共系统动态视图,用于系统优化和调整参考.

V_$    动态性能视图,你可用 CATALOG.SQL 脚本建立动态视图建立同义词。

GV$    新(oracle 8)的附加的固定视图(Global V$).在并行环境下反应的是

       V$视图的信息。如:

SELECT * FROMGV$LOCK WHERE INST_ID = 2 OR INST_ID = 5 ;

返回的是instances2 和5的V$的信息。所以GV$反应一组Instances的参数.GV$视图的限制是参数PARALLEL_MAX_SERVERS必须大于0 。

详见 OracleEnterprise Manager Administrator's Guide.

 

注:请注意下面的总结:

l 一般DBA_的视图内容都包含USER_和ALL_为前缀的视图;

l DBA_为前缀的视图的内容基本上是大写;

l 以V$_为前缀的视图的内容基本上是小写。

 

 

1.USER_TABLEs(=TABS)   用户的所有表的信息。

2.USER_TAB_COLUMNS(=COLS)有关各表的列(字段)的信息

3.USER_VIEWS   用户的所有视图

4.USER_SYNONYMS(=SYN)  用户同义词

5.USER_SEQUENCES(=SEQ)   用户序列

6.USER_CONSTRAINTS       记录创建表结构时建立的限制。

7.USER_TAB_COMMENTS      表的注释。如:

 

    Comment on table emp is '职工表';

 

8. USER_COL_COMMENTS   列(字段)注释。如:

 

    Comment on column emp.ename  is '姓名';

 

9. USER_INDEXES(=IND)  用户索引的简要信息

10. USER_IND_COLUMNS    用户索引的列信息

11. USER_TRIGGERS       用户触发器信息

12. USER_SOURCE         用户存储过程

13. USER_TABLESPACE     用户可以使用的表空间信息

14. USER_TS_QUOTAS      用户使用系统资源的信息

15. USER_SEGMENTS       用户对象所使用空间信息

16. USER_EXTENTS        用户的扩展段信息

17. USER_OBJECTS        用户对象

=USER_TABLES+USER_VIEWS+USER_INDEXES+

 USER_SOURCE+USER_TRIGGERS+USER_JAVA

 

18. USER_PART_TABLES     用户分区信息

19. USER_TAB_PARTITIONS

20. USER_PART_COL_STATISTICS

21. USER_IND_PARTITIONS

22. USER_FREE_SPACE

23. CAT(=USER_CATALOG)  用户可以访问的所有的基表。

24. TAB                 用户创建的所有基表,视图,同义词等。

25. DICT(=DICTIONARY)构成数据字典的所有表的信息。

 

提示:虽然Oracle提供可以用Comment on column tablename.column is 'xxxx'; 等来实现对表或列进行注释,但不建议设计者采用这样的工作方式。而建议将注释写到脚本中更为直观。

 

§1.7  ORACLE数据类型

Oracle数据库的数据类型与其它的数据库系统相比,它的数据类型不多,Oracle在表示数据方面比其他数据库系统来说要省去许多关键字。Oracle只用NUMBER(m,n)就可以表示任何复杂的数字数据。其它如日期类型等也简单得多,只DATE就表示日期和时间。下面以列表形式给出各个版本的Oracle系统数据类型的表示方法。下面给出Oracle旧版本的数据类型的目的是让读者了解Oracle的变化,另外就是你在对旧版本进行升级或数据转换时要注意各个版本的差别。

 

ORACLE5、ORACLE6数据类型

 

数据类型

说明

Char

可变长字符型,≤254

Varchar2

可变长字符型,≤2000

Number(m,n)

数字类型,含整数、小数等

Date

日期型,含时间,缺省格式为mmm-dd-yyyy hh:mi:ss(占7字节)

Long

存储大型可变长字符串,≤2GB

Raw

存储短二进制串,≤2GB

Long  raw

存储长二进制串,≤2GB

                               ORACLE7数据类型

数据类型

说明

Char

定长字符,≤255个字符

Varchar

变长字符,≤2000个字符

Varchar2

变长字符,≤2000个字符

Number(m,n)

数字类型,含整数、浮点、双精度等

Long

存储大型可变长字符串,≤2GB

Raw

存储可变短二进制数,≤2000

Long  raw

存储大型可变长二进制数,≤2GB

 

                      ORACLE8/8i  数据类型

 

数据类型

说明

Char

定长字符,≤2000个字符

Varchar

(同Varchar2)可变字符,≤4000个字符

Varchar2

变长字符,≤4000个字符

Date

固定长度(7字节)的日期型

Number

数字型,可存放实型和整型

Long

可变字符,≤2GB个字符

Raw

可变二进制数据,≤4000字节

Long  raw

可变二进制数据,≤2GB

MLSLABEL

仅Trusted Oracle 用长度在2~5字节间

Blob

大二进制对象,≤4GB

Clob

大字符串对象,≤4GB

Nclob

多字节字符集的Clob,≤4GB

Bfile

外部二进制文件,大小由OS决定

 

 

CHAR()

定长字符型(在Oracle5、Oracle6 是变长),字符长度不够自动在右边加空格符号。当字符长度超出2000个则错误。不指定大小缺省为 1。

 

VARCHAR()

可变字符型,当前与VARCHAR2()相同。

 

VARCHAR2()

可变字符型,当前与VARCHAR()相同。VARCHAR2 类型的字段(列)可存放4000个字符;但是VARCHAR2 变量可以存放32,767 个字符。大小必须指定。

 

NCHAR()和NVARCHAR2()

NCHAR 和NVARCHAR2 分别与CHAR和VARCHAR2 有相同的大小。并用于于存放National Language Support (NLS)数据,Oracle 允许以本地语言存放数据和查询数据。

如果将列名声明成NCHAR、NVARCHAR2这样的类型,则insert和 select 等语句中的具体值前加N,不能直接按照普通字符类型进行操作。看下面例子:

 

SQL> create tablenchar_tst(name nchar(6),addr nvarchar2(16),sal number(9,2));

 

表已创建。

 

SQL> insert intonchar_tst values(N'赵元杰',N'北京市海淀区',9999.99);

 

已创建 1 行。

 

SQL> select * fromnchar_tst where name like N'赵%';

 

NAME   ADDR                    SAL

---------------------- ----------

赵元杰 北京市海淀区       9999.99

 

SQL> select *from nchar_tst where name like '赵%';

select * fromnchar_tst where name like '赵%'

                                        *

ERROR 位于第 1 行:

ORA-12704: 字符集不匹配.

 

提示:虽然Oracle可以使用nchar, nvarchar2 类型来存放字符数据,但建议设计者不要使用NCHAR和NVARCHAR2。因为CHAR和VARCHAR2就能存放汉字。

 

NUMBER(

,)

 

 

是数据的整数部分,是数据的精度(即小数)部分,注意,部分可以表示负的精度。用可以表示从小数点往右或往左保留多少位。如下表:

 

实际值

数据类型

存储值

1234567.89

Number

1234567.89

1234567.89

Number(8)

1234568

1234567.89

Number(6)

出错

1234567.89

Number(9,1)

1234567.9

1234567.89

Number(9,3)

出错

1234567.89

Number(7,2)

出错

1234567.89

Number(5,-2)

1234600

1234511.89

Number(5,-2)

1234500

1234567.89

Number(5,-4)

1230000

1234567.89

Number(*,1)

1234567.9

 

 

Sal  number(7,2), --表示5位整数,2位小数.

 

DATE

Oracle 的日期型用7个字节表示,每个日期型包含如下内容:

l Century (世纪)

l Year (年)

l Month(月)

l Day (天)

l Hour (小时)

l Minute (分)

l Second (秒)

 

日期型字段有下面特点:

 

l 日期型字段的插入和更新可以数据型或字符并带to_date 函数说明即可。

l 缺省的日期格式有NLS_DATE_FORMAT参数控制,它的缺省格式为DD-MON-YY。

l 缺省的时间是夜里 00:00:00 (即0点 0分0秒)。

l sysdate返回的是服务器的时间,见下面例子。

l 日期格式的显示可以设置,见下面例子。

l 日期型可以运算,见下面例子。见下面例子。

l 世纪用cc 表示;年用yyyy表示,月用mm表示,日用dd表示,小时用hh24表示,分用mi表示,秒用ss表示。

例子:

SQL> create tablesave_info(per_id varchar2(20),name varchar2(20),tran_date date,

  2 tran_val number(12,2));

 

表已创建。

 

SQL>  insert into save_info values ('110105540609811','赵元杰',

  2 to_date('2001.06.18','yyyy.mm.dd'),12345.66);

 

已创建 1 行。

 

SQL> select *from save_info;

 

PER_ID               NAME                 TRAN_DATE    TRAN_VAL

---------------------------------------- ---------- ----------

110105540609811      赵元杰               18-6月 -01   1234.66

 

SQL> selectper_id,name,to_char(tran_date,'yyyy/mm/dd'),tran_val from save_info;

 

PER_ID               NAME                 TO_CHAR(TR   TRAN_VAL

---------------------------------------- ---------- ----------

110105540609811      赵元杰               2001/06/18   12345.66

 

 

SQL> showparameter nls_date_format

 

NAME                                 TYPE    VALUE

------------------------------------------- ------------------------------

nls_date_format                      string

 

 

SQL> altersession set nls_date_format=

  2 '"公元"yyyy"年"mm"月"dd"日"';

 

会话已更改。

 

SQL> selectsysdate from dual;

 

SYSDATE

------------------

公元2001年05月18日

 

 

SQL> selectto_char(sysdate,'cc yyyy.mm.dd') from dual;

 

TO_CHAR(SYSDA

-------------

21 2001.05.18

 

关于日期型的使用方法详细请参考《Oracle8i National Language Support Guide》。

 

 

BLOB

大二进制对象,每条记录可存储达4GB的数据,详细见后面章节。

 

CLOB

大字符对象,每条记录可存储达4GB的数据,详细见后面章节。

 

BFILE

外部二进制文件,每条记录可存储达4GB的数据(与OS有关),详细见后面章节。

 

RAW

非结构的二进制数据,这些数据不被数据库系统解释。RAW可以存储达2,000字节。

 

LONGRAW

大的二进制类型数据,LONGRAW是非结构的二进制数据,这些数据不被数据库系统解释。LONGRAW可以存储达2GB字节。LONGRAW不能被索引,而RAW可以被索引。

 

ROWID

ROWID在Oracle数据库中是一个虚的列,即系统用的特殊的列,不是我们建立的列。用于对数据库中的每条记录进行定位。详细见“Rowid的使用”章节。

 

UROWID

UROWID 是Universal ROWID 的意思。即全球ROWID,它支持逻辑和物理ROWID,也作为外部表的(通过getway 访问的非Oracle 表)的ROWID。UROWID类型可以存储所有的ROWID类型的数据。

 

 

%TYPE类型的匹配:

             books_printed         number(6);

             books_sold             books_printed%TYPE;

             books_sold的数据类型与book_printed的类型一致;

( %TYPE类型 在 PL/SQL中介绍 )。

 

 

空值与字符型、数字型的运算:

        null + <数字>=null            (空值+数字仍是空值)

        null > <数字>=null            (空值与数字比较结果为空值)

        null || '字符串' = 字符串

 

number类型与以下类型具有同等的值域:

       DEC

       Decimal

       Double  PREcision

       Float

       Integer

       Int

       Numeric

       Real

       Smallint

 

提示:虽然Oracle可以使用上面的子数据类型,但建议还是采用NUMBER(n,m)为好。因为如果使用子数据类型定义字段类型不当,可能引起数据在运算方面的问题。

 

Long数据类型的限制:

l select中可以用long;

l update中可以用select子句;

l insert中可以用Valus子句;

l 每个表只能允许一个long列;

l long列不能列出完整性约束(null、not   null除外);

l long列不能被索引;

l 过程或存储函数不能接收long型函数;

l 存储函数不能返回long型值。

 

 

long  目前不能出现在以下情况中:

l select中的Where,Group  by,order  by,Connect  by,distinct;

l 不能对long列作substr,instr;

l 表达式或条件;

l 子查询或集合中不能用long;

l Create   table  ...as   select   中不能用long;

 

§1.8  SQL 语句基础

下面给出SQL语句的基本介绍,更详细的描述见后面的章节。

§1.8.1   SQL语句所用符号

 

操作符

用途

例子

+ -

 表示正数或负数,正数可省去 +

-1234.56

+

将两个数或表达式进行相加

A=c+b

-

将两个数或表达式进行相减

34-12

*

将两个数或表达式进行相乘

12*34

/

除以一个数或表达式

18*11

NULL

空值判断

Where name is null;

||

字符串连接

‘101-’||tel_num

=

等于测试

Select * from emp

where name=’赵元杰’;

!= 或<>或^=

不等于测试

Select * from emp

where name !=’赵元杰’;

小于测试

Select * from emp

Where sal < 5000;

大于测试

Select * from emp

Where sal > 5000;

<=

小于等于测试

Select * from emp

Where sal <= 5000;

>=

大于等于测试

Select * from emp

Where sal >= 5000;

Not  in

测试某值是否在一个指定的结果集中

Select name,addr from expert

where local not in(‘北京’,’上海’);

ANY

将一个值与一组值进行比较,返回满足条件的结果。必须跟!=,<,>,<=,>=

select ename,sal from emp where sal<= any(select sal from

 emp where deptno=10)

SOME

同ANY,必须跟!=,<,>,<=,>=

 

ALL

将一个值与一组值比较,返回满足条件的所有列值。必须跟!=,<,>,<=,>=

Select name,sal from emp

Where sal<=

 all ( 500,800,1200);

Not between

A and B

判断某个值是否界于两者之间。

Select name,sal from emp Where

sal between  500 and 1200;

[not]exists

判断某个列是否存在于一组值中。

select dname,deptno from dept where exists

(select * from emp where dept.deptno=emp.deptno)

A[not]like b

[Escape ‘char’]

比较两个模式是否相似,当使用like 语句时Oracle不去访问索引。

Select * from emp

Where ename like ‘TH%’;

Is [not] null

 测试值是否为空。

Select ename,deptno from emp

Where comm. Is null or comm.=0;

Not

对结果的否定。

Select * from emp

Where sal not(sal<1000); 等价于

select ename,sal from emp where sal>=1000;

AND

用于判断两个条件十分都满足。

Select * from  emp where

Ename=’SIMTH’ and sal>=1000;

OR

用于判断两个条件中是否有一个满足。

Select * from emp where

Ename=’SIMTH’ or ename=’SCOTT’;

UNION

用于返回(组合)两个查询中所有唯一的行。

Select ename from emp union

Select ename from emp;

UNION ALL

用于返回(组合)两个查询中所有所有的行。

 

INTERSECT

用于返回两个查询中相同的行。

Select ename from emp1 intersect select ename from emp2;

MINUS

用于返回两个查询中的不同的行。

 

 

§1.8.2   简单select查询

当我们可以用SQL*PLUS登录到SQL>下后,我们可以用DESC 显示某表的结构,也可以用select 语句简单查询表中的一些列的内容。

 

例:要查询EMP表中员工的姓名、工资及出生日期,则:

 

SQL>select ename, sal, hiredate  from emp;

 

§1.9   伪列及伪表

Oracle系统为了实现完整的关系数据库功能,系统专门提供了一组称为伪列(Pseudocolumn)的数据库列,这些列不是在建立对象(如建表)时由我们完成的,而是在我们建立对象时由自动Oracle完成的。Oracle目前有以下的伪列:

 

l  CURRVALand NEXTVAL  使用序列号的保留字

l  LEVEL                  查询数据所对应的级

l  ROWID                  记录的唯一标识

l  ROWNUM               限制查询结果集的数量

 

有关伪列的详细解释和使用见相关章节。

 

Oracle 还提供了一个DUAL 的伪表,该表主要目的是保证在使用SELECT 语句中语句的完整性而提供的,如:我们要查询当前的系统日期及时间,而系统的日期和时间并是放在一个指定的表里。所以在 from 语句后就没有表名给出。为了使用 from  后有个表名,我们就用DUAL代替。如:

 

例1:查询Oracle系统日期及时间:

SQL> select  to_char(sysdate,'yyyy.mm.dd hh24:mi:ss')  fromDUAL;

 

TO_CHAR(SYSDATE,'YY

-------------------

2001.06.02 07:28:09

 

例2:计算一下 5000+5000*0.1 的结果是多少,则:

SQL> select 5000+5000*0.1  from  DUAL;

 

5000+5000*0.1

-------------------

         5500

 

§1.10  使用SQLWorksheet工作

在新的Oracle版本里,系统提供了一个叫SQLWorksheet 的图形SQL工作环境,它是ORACLEEnterprise Manager 的一部分。使用它可以免去在SQL>下编辑行命令的不便。它完全是在图形方式进行。它的启动有以下几种方法:

l  从ORACLEEnterprise Manager中启动

l  从Administrtor工具中启动

l  从操作系统中启动

 

下面给出在操作系统下启动SQL Worksheet 工具工作的步骤:

1)     点击 SQL Worksheet 图标,即选择 开始->程序->Oracle-OraHome81->databaseAdministration->SQLPLUS Worksheet。选中SQLPLUS Worksheet后出现如下画面:

 

 

             图 1.10-1 使用SQL Worksheet 的登录画面

 

在用户名、口令及服务输入ORACLE的有效用户名、口令及连接字串再点击确定后进入如图1.10-2所示的画面。

 

2)当进入图1.10-2 所示的画面后。你就可以工作了。目前的版本是在屏幕的上方输入命令,屏幕的下方是系统显示结果。

 

3)我们将光标点击到屏幕上方,输入SQL命令,如输入:

 select  ename, sal from scott.emp;

输入完成命令后,用光标点击 左边的执行图标,Oracle 会结果显示在屏幕的下方:

 

 

 

图  1。10-2 登录成功后的画面

 

                  图1.10-3 查询命令及显示结果画面

 

从SQL Worksheet 工具中可以看出,该工具提供了相当丰富的功能。下面给出个功能的简要说明:

 

1.文件:

l  改变数据库连接:可以连接到另外的用户和数据库上去;

l  打开:可以打开现有文件;

l  将输入另存为:将当前命令存为一个文件;

l  将下方显示的结果存为一个文件。

2.编辑:

l  剪切:将当前选中字符进行剪切;

l  复制:将选中字符进行剪切;

l  粘贴:将缓冲区字符进行粘贴;

l  全选:对当前画面所有字符全选;

l  全部清除:清除目前的所有内容。

 

3.工作单:

l  执行:执行当前的命令;

l  运行本地脚本:运行操作系统下某个.SQL文件(点击后提示输入文件名);

l  命令历史记录:查看命令历史记录;

l  上一条命令:显示上一条命令。

 

 

提示:如果你的SQLWorksheet显示的不是汉字(出现乱字符),请你将你的NT/2000/98环境下的汉字变量设置与服务器的一样就好了。在WINDOWS NT环境设置汉字变量步骤:

 

用regedit修改注册表中的所有ORACLE字符集项,如:

1)点击:开始=》运行=》输入regedit;

2)点击“HEY_LOCAL_MACHINE”左边的“+”以展开目录;

3)点击“SOFTWARE”左边的“+”以展开目录;

4)点击“ORACLE”项;

5)修改ORACLE树下所有“NLS”变量与props$中的一致。

 

关于汉字环境变量的设置,请参阅《Oracle8i/9I初级数据库管理》。

 


 

第二章 查询基础

下面给出查询的一些基本的操作描述,如果你是位Oracle老手则可以跳这一章。

§2.1  SELECT语句

在关系数据库中,使用频率最高要算SELECT语句了。尽管SELECT 语句的使用非常简单,但确很有学问。下面简单介绍有关SELECT 语句的常用方法。

 

1.命令语法:

 

SELECT 的简单语法:

 

SELECT [DISTINCT | ALL] {* | column1[,column2]...}

FROM {table_1 | (subquery)} [alias]

[, {table_2 | (subquery)} [alias]]...

[WHERE condition]

[CONNECT BY condition [START WITH condition]

[GROUP BY expn] [HAVING expn]

[{ UNION [ALL] | INTERSECT | MINUS } SELECT . .. ]

[ ORDER BY [expn ] [ ASC | DESC]

[ FOR UPDATE [OF [user.]table | view] column ]

[NOWAIT]

 

详细语法结构需查阅最新ORACLE 原版《ORACLE8iSQL REFERENCE MANUAL》或《ORACLE9i SQL  REFERENCE  MANUAL》

 

§2.2   SQL中的单记录函数

许多资料(包括Oracle 的资料)把Oracle的SQL语句中用到的函数分为单值函数和多值函数,单值函数又分为字符函数和数字函数。下面分别介绍它们。

 

§2.2.1   单记录字符函数

函    数

          说               明

  ASCII

返回对应字符的十进制值

  CHR

给出十进制返回字符

  CONCAT

拼接两个字符串,与 || 相同

  INITCAT

将字符串的第一个字母变为大写

  INSTR

找出某个字符串的位置

  INSTRB

找出某个字符串的位置和字节数

  LENGTH

字符给出字符串的长度

  LENGTHB

字节给出字符串的长度

  LOWER

将字符串转换成小写

  LPAD

使用指定的字符在字符的左边填充

  LTRIM

左边裁剪掉指定的字符

  RPAD

使用指定的字符在字符的边填充

  RTRIM

右边裁剪掉指定的字符

  REPLACE

执行字符串搜索和替换

  SUBSTR

取字符串的子串

  SUBSTRB

取字符串的子串(以字节)

  SOUNDEX

返回一个同音字符串

  TRANSLATE

执行字符串搜索和替换

  TRIM

裁剪掉前面或后面的字符串

  UPPER

将字符串变为大写

  NVL

以一个值来替换空值

 

 

ASCII()

是字符串。返回与指定的字符对应的十进制数。

SQL> selectascii('A') A,ascii('a') a,ascii('0') zero,ascii(' ') space from dual;

 

     A     a  ZERO  SPACE

---------- -------------------- ----------

65     97     48    32

 

SQL> select ascii('赵')zhao,length('赵') leng from dual;

 

      ZHAO      LENG

----------      ----------

     54740          1

 

CHR([NCHAR])

给出整数,返回对应字符。如:

 

SQL> selectchr(54740) zhao,chr(65) chr65 from dual;

 

ZH  C

--   -

赵  A

 

CONCAT(,)

 

SQL> selectconcat('010-','8801 8159')||'转23' 赵元杰电话 from dual;

 

赵元杰电话

-----------------

010-8801 8159转23

 

 

INITCAP()

 

返回字符串c1 并第一个字母变为大写。例如:

 

SQL> selectinitcap('simth') upp from dual;

 

UPP

-----

Simth

 

 

INSTR(,[,[,] ] )

在一个字符串中搜索指定的字符,返回发现指定的字符的位置。

C1: 被搜索的字符串

C2: 希望搜索的字符串

I: 搜索的开始位置,缺省是1

J: 出现的位置,缺省是1。

 

SQL> SELECT INSTR('Oracle Training', 'ra', 1, 2) "Instring" FROM DUAL;

 

  Instring

----------

        9

 

INSTRB(,[,[,] ] )

 

除了返回的字节外 ,与INSTR 相同,

 

 

LENGTH( )

 

 

返回字符串 c 的长度。

 

SQL> l

  1 select name,length(name),addr,length(addr),sal,length(to_char(sal))

  2* from nchar_tst

SQL> /

 

NAME  LENGTH(NAME) ADDR      LENGTH(ADDR)SAL LENGTH(TO_CHAR(SAL))

------  ------------  ----------------  ------------  ----------  ----------------

赵元杰     3        北京市海淀区         6         99999.99    8

 

 

LENGTHB( )

 

以字节返回字符串的字节数。

 

SQL> selectname,lengthb(name),length(name) from nchar_tst;

 

NAME   LENGTHB(NAME)  LENGTH(NAME)

------  ------------- ------------

赵元杰            6            3

 

 

LOWER ( )

返回字符串并将所有字符变为小写。

 

SQL> selectlower('AaBbCcDd') AaBbCcDd from dual;

 

AABBCCDD

--------

aabbccdd

 

 

UPPER( )

与 LOWER 相反,将给出字符串变为大写。如:

 

SQL>  select upper('AaBbCcDd') AaBbCcDd from dual;

 

AABBCCDD

--------

AABBCCDD

 

 

RPAD和LPAD(粘贴字符)

 

RPAD(string,Length[,'set'])

LPAD(string,Length[,'set'])

      RPAD在列的右边粘贴字符;

      LPAD在列的左边粘贴字符。

 

例1:

SQL>select   RPAD(City,35,'.'),temperature    from weather;

 

        RPAD(City,35,'.')            temperature

        ------------------------------------------

           CLEVELAND......                    85

           LOS ANGELES..                     81

          .........................

 

        (即不够35个字符用'.'填满)

 

LTRIM(左截断)RTRIM(右截断) 函数

 

LTRIM (string  [,’set’])

Left TRIM (左截断)删去左边出现的任何set 字符。

RTRIM (string  [,’set’])

Right TRIM (右截断)删去右边出现的任何set 字符。

 

例1:

SELECT RTRIM (‘Mother Theresa, The’, ‘The’) “Example of Right

Trimming” FROM DUAL;

Example of Right

----------------

Mother Theresa,

 

SUBSTR Substr(string,start[,Count])

 

取子字符串中函数

对字串(或字段),从start字符 开始,连续取 count 个字符并返回结果,如果没有指count则一直取到尾。

 

select phone,substr(phone,1,3) || ‘0’ || substr(phone,4)

from telecommunication where master=’中国电信’;

 

 

SUBSTRB(string,start[,Count])

 

对字串(或字段),从start字节 开始,连续取 count 个字节并返回结果,如果没有指count则一直取到尾。

 

 

REPLACE (‘string’ [,’string_in’,’string_out’])

 

String:希望被替换的字符串或变量。

String_in:被替换字符串。

String_out:要替换字符串。

 

SQL> selectreplace('Informaix中国公司','Informaix','IBM Informix')

  2  IBM数据库from dual;

 

IBM数据库

--------------------

IBM Informix中国公司

 

 

SOUNDEX( )

 

返回一个与给定的字符串读音相同的字符串(不管拼写是否一样)。

 

SELECT DPL_NAME FROMDENIED_PARTIES_LIST WHERE

SOUNDEX(DPL_NAME) =SOUNDEX(‘Saddam Hussain’) ;

DPL_NAME

----------------------------------------------

Al Husseni

Sadda Al Sada.

 

 

REPLACE (‘string’ [,’string_in’,’string_out’])

 

String:希望被替换的字符串或变量。

String_in:被替换字符串。

String_out:要替换字符串。

 

SELECTREPLACE (‘Oracle’, ‘Or’, ‘Mir’) “Example“ FROM DUAL;

Example

-------

Miracle

 

 

TRIM( [] FROM

 

TRIM可以使你对给定的字符串进行裁剪(前面,后面或前后)。

 

l  如果指定 LEADING, Oracle 从trim_char 中裁剪掉前面的字符;

l  如果指定TRAILING, Oracle 从trim_char 中裁剪掉尾面的字符;

l  如果指定两个都指定或一个都没有给出,Oracle从trim_char 中裁剪掉前面及尾面的字符;

l  如果不指定 trim_character, 缺省为空格符;

l  如果只指定trim_source, Oracle Oracle从trim_char 中裁剪掉前面及尾面的字符。

 

例子:将下面字符串中的前面和后面的‘0‘字符都去掉:

SELECT TRIM (0FROM 0009872348900) "TRIM Example" FROM DUAL;

 

TRIM example

--------------------------------

98723489

 

 

§2.2.2   单记录数字函数

 

函数

说明

Value1 + value2

Value1 - value2

Value1 * value2

Value1 / value2

ABS(value)

CEIL(value)

COS(value)

COSH(value)

EXP(value)

FLOOR(value)

LN(value)

LOG(value)

MOD(value,divisor)

NVL(value,substitute)

POWER(value,exponent)

ROUND(value,precision)

SIGN(value)

SIN(value)

SINH(value)

SQRT(value)

TAN(value)

TANH(value)

TRUNC(value,按precision)

VSIZE(value)

绝对值

大于或等于value的最小整数

余弦

反余弦

e的value次幂

小于或等于value的最大整数

value的自然对数

value的以10为底的对数

求模

value为空时以substitute代替

value的exponent次幂

按precision 精度4舍5入

value为正返回1;为负返回-1;为0返回 0.

余弦

反余弦

value 的平方根

正切

反正切

按照precision 截取value

返回value在ORACLE的存储空间大小

 

 

ABS( )

返回指定值的绝对值。如:

 

SQL> selectabs(100),abs(-100) from dual;

 

  ABS(100) ABS(-100)

---------- ----------

       100        100

 

ACOS( )

给出反余弦的值。如:

SQL> Select acos(-1)acos from dual;

 

      ACOS

----------

3.14159265

 

ASIN( )

给出反正弦的值。如:

 

SQL> select asin(-1)"arc sine" from dual;

 

  arc sine

----------

-1.5707963

 

 

 

 

ATAN (

 

返回一个数字的反正切值。如:

 

SQL> select atan(-1)"arc tangent" from dual;

 

arc tangent

-----------

 -.78539816

 

 

CEIL( )

 

返回大于或等于给出数字的最小整数。如:

 

SQL> selectceil(3.14159) from dual;

 

CEIL(3.14159)

-------------

4

 

COS ( )

返回一个数字余弦值。如:

 

SQL> selectcos(-3.1415926) from   dual;

 

COS(-3.1415926)

---------------

-1

 

COSH ( )

 

返回一个数字双曲余弦值。如:

 

SQL> select cosh(20)cosh from dual;

 

     COSH

----------

 242582598

 

 

EXP ( )

 

返回一个数字 e 的 n 次方的值。如:

 

SQL> selectexp(2),exp(1) from dual;

 

EXP(2)      EXP(1)

----------       ----------

 7.3890561  2.71828183

 

 

FLOOR ( )

 

对给定的数字取整数,如:

 

SQL> selectfloor(123.45),floor(45.56) from dual;

 

FLOOR(123.45)  FLOOR(45.56)

-------------    ------------

123                                      45

 

 

LN( )

 

返回一个数字的对数值,n 是大于 0 的数字,如:

 

SQL> selectln(1),ln(2),ln(3) from dual;

 

     LN(1)     LN(2)      LN(3)

----------   ----------   ----------

         0   .693147181  1.09861229

 

 

LOG( , )

 

返回一个以n1为底的n2的对数,n1不是0或1的正数。如:

 

SQL> selectlog(2,1),log(2,2) from dual;

 

  LOG(2,1)    LOG(2,2)

----------     ----------

0                                  1

 

MOD( , )

 

SQL> Selectmod(10,3), mod(10,2), mod(10,4)  from  dual;

 

 MOD(10,3) MOD(10,2)  MOD(10,4)

----------    ----------     ----------

         1          0          2

 

POWER ( , )

 

返回 n1 的 n2 次方值,如:

 

SQL> selectpower(2,10),power(3,3) from dual;

 

POWER(2,10)   POWER(3,3)

-----------      ----------

1024                               27

 

ROUND(value,precision)

 

  按照指定的精度进行舍入;

 

selectround(55.5),round(-55.5),trunc(55.5),trunc(-55.5)

from dual;

 

round(55.5)round(-55.5) trunc(55.5) trunc(-55.5)

----------------------- ----------- -------------

       56             -56         55         -55

 

 

SIGN()

取数字n 的符号,大于0 返回 1;小于0 返回-1; 等于0 返回0。 如:

 

例:

select sign(123),sign(-100),sign(0) from dual;

 

sign(123)  sign(-100) sign(0)

-------------------- ----------

      1           -1         0

 

 

SIN ( )

 

返回一个数字的正弦值。如:

 

SQL> selectsin(1.57079) from dual;

 

SIN(1.57079)

------------

        1

 

SINH( )

 

返回双曲余弦的值,如:

 

SQL> selectsin(20),sinh(20) from dual;

 

   SIN(20)  SINH(20)

----------     ----------

.912945251   242582598

 

 

SQRT( )

 

返回 数字 n 的根,如:

 

SQL> selectsqrt(64),sqrt(10) from dual;

 

  SQRT(64)  SQRT(10)

----------   ----------

         8  3.16227766

 

 

TAN( )

 

返回数字 n的正切值,如:

 

SQL> selecttan(20),tan(10) from dual;

 

TAN(20)       TAN(10)

----------        ----------

2.23716094 .648360827

 

 

 

TANH( )

 

返回数字 n的双曲正切值,如:

 

SQL> selecttanh(20),tan(20) from dual;

 

  TANH(20)    TAN(20)

----------      ----------

         1    2.23716094

 

 

TRUNC(value,precision)  

 按照指定的截取一个数。如:

 

SQL> SELECT TRUNC(124.16666, -2) trunc1, trunc(124.16666,2) from dual;

 

    TRUNC1 TRUNC(124.16666,2)

----------------------------

100                  124.16

 

§2.2.3   单记录日期函数

 

Oracle 用到的日期函是:

 

   函   数

     描      述

ADD_MONTH

在日期date上增加count个月

GREATEST(date1,date2,. . .)

从日期列表中选出最晚的日期

LAST_DAY( date )

返回日期date 所在月的最后一天

LEAST( date1, date2, . . .)

从日期列表中选出最早的日期

MONTHS_BETWEEN(date2,date1)

给出 Date2 - date1 的月数(可以是小数)

NEXT_DAY( date,’day’)

给出日期date之后下一天的日期,这里的day为星期,如: MONDAY,Tuesday等。

NEW_TIME(date,’this’,’other’)

给出在this 时区=Other时区的日期和时间

ROUND(date,’format’)

未指定format时,如果日期中的时间在中午之前,则将日期中的时间截断为12 A.M.(午夜,一天的开始),否则进到第二天。时间截断为12 A.M.(午夜,一天的开始),否则进到第二天。

TRUNC(date,’format’)

未指定format时,将日期截为12 A.M.( 午夜,一天的开始).

 

 

 

 

ADD_MONTHS( , )

 

增加月份和减去月份,如:

 

SQL> selectto_char( add_months(to_date('199712','yyyymm'), 1),'yyyymm') add_month

  2  fromdual;

 

ADD_MO

------

199801

 

 

SQL> selectto_char(add_months(to_date('199712','yyyymm'), -1 ),'yyyymm') add_mo

  2  fromdual;

 

ADD_MO

------

199711

 

 

LAST_DAY( date) 

 

返回日期date 所在月的最后一天,如:

 

SQL> selectto_char(sysdate,'yyyy.mm.dd'),to_char((sysdate)+1,'yyyy.mm.dd')

  2  fromdual;

 

TO_CHAR(SYTO_CHAR((S

--------------------

2001.05.182001.05.19

 

MONTHS_BETWEEN(date2,date1)

给出 Date2 -date1 的月数(可以是小数);

 

SQL> select months_between('19-12月-1999','19-3月-2000')mon_betw from dual;

 

  MON_BETW

----------

        -3

 

 

SQL> selectmonths_between(to_date('2000.05.20','yyyy.mm.dd'),

  2 to_date('2005.05.20','yyyy.mm.dd') ) mon_bet from dual;

 

   MON_BET

----------

-60

 

NEW_TIME(date,’this’,’other’)

 

给出在this 时区=Other时区的日期和时间

This和other 是时区,它们可以是下面的值:

 

时区缩写

代表的时区

AST/ADT

大西洋标准/日期时间

BST/BDT

白令海标准/日期时间

CST/CDT

中部标准/日期时间

GMT

格林威治时间

HST/HDT

阿拉斯加-夏威夷标准/日期时间

MST/MDT

山区标准/日期时间

NST

新大陆标准时间

PST/PDT

太平洋标准/日期时间

YST/YDT

Yukon标准/日期时间

 

 

SQL> selectto_char(sysdate,'yyyy.mm.dd hh24:mi:ss') bj_time,

  2  to_char(new_time(sysdate,'PDT','GMT'),'yyyy.mm.dd hh24:mi:ss')los_angles

  3   from dual;

 

BJ_TIME             LOS_ANGLES

--------------------------------------

2001.05.19 06:25:252001.05.19 13:25:25

 

NEXT_DAY( date,’day’)

给出日期date和星期x之后计算下一星期x的日期,这里的day为星期,如: MONDAY,Tuesday等。但在中文环境下,要写成’星期x’这样的格式,如:

 

例:比如今天是5月18日星期五,计算下一个星期五是几号:

SQL>  select next_day('18-5月-2001','星期五')nxt_day from dual;

 

NXT_DAY

----------

25-5月 -01

 

 

SYSDATE

用来得到系统的当前日期,如:

 

SQL> selectto_char(sysdate,'dd-mon-yyyy day') from dual;

 

TO_CHAR(SYSDATE,'DD

-------------------

18-5月 -2001 星期五

 

 

TRUNC(,[,])

按照 给出的 fmt 的要求将日期截断。如果 fmt=’mi’ 则表示截断掉秒保留至分。如:

 

SQL> selectto_char(trunc(sysdate,'hh'),'yyyy.mm.dd hh24:mi:ss') hh,

  2 to_char(trunc(sysdate,'mi'),'yyyy.mm.dd hh24:mi:ss') hhmm from dual;

 

HH                  HHMM

--------------------------------------

2001.05.18 22:00:002001.05.18 22:27:00

 

 

 

§2.2.4   单记录转换函数

 

   函   数

     描      述

CHARTOROWID

将 字符转换到 rowid类型

CONVERT

转换一个字符节到另外一个字符节

HEXTORAW

转换十六进制到raw 类型

RAWTOHEX

转换raw 到十六进制

ROWIDTOCHAR

转换 ROWID到字符

TO_CHAR

转换日期格式到字符串

TO_DATE

按照指定的格式将字符串转换到日期型

TO_MULTIBYTE

把单字节字符转换到多字节

TO_NUMBER

将数字字串转换到数字

TO_SINGLE_BYTE

转换多字节到单字节

 

 

CHARTOROWID()

 

将字符数据类型转换为ROWID类型,如:

 

  1* select rowid,rowidtochar(rowid),ename fromscott.emp

SQL> /

 

ROWID                  ROWIDTOCHAR(ROWID)     ENAME

-----------------------------------  --------------------------------------------------

AAAFXDAABAAAHVaAAA  AAAFXDAABAAAHVaAAA  SMITH

AAAFXDAABAAAHVaAAB  AAAFXDAABAAAHVaAAB  ALLEN

AAAFXDAABAAAHVaAAC  AAAFXDAABAAAHVaAAC  WARD

 

 

CONVERT( ,[,] )

 

将源字符串sset从一个语言字符集转换到另一个目的dset字符集。

 

SELECT CONVERT (‘strutz’, ‘ WE8HP’, ‘ F7DEC ‘) “Conversion”

FROM DUAL;

 

Conversion

---------------

Strutz.

 

HEXTORAW( )

 

将一个十六进制构成的字符串转化为二进制。如:

 

 

Insert into printers(printer_nbr,manufacturer,model,init_string)

Values ( 12,’HP’,’Laserjet’,”HEXTORAW(‘1B45’));

 

RAWTOHEX( )

 

将一个二进制构成的字符串转化为十六进制。如:

select rawtohex (init_string)  hext  from printers

where model=LaserJet’and manufacturer=’HP’;

 

hext

-----------

1B45

 

 

ROWIDTOCHAR( )

 

将ROWID数据类型转换为字符类型,见 CHARTOROWID。

 

 

TO_CHAR(date,’format’)

 

根据format 重新格式日期date的格式。如:

 

SQL> selectto_char(sysdate,'yyyy/mm/dd hh24:mi:ss') from dual;

 

TO_CHAR(SYSDATE,'YY

-------------------

2001/05/18 23:05:36

 

日期格式比较多,详细内容请参考原版资料。下面给出常用的日期格式代码:

日期格式代码表

日期代码

格式说明

例子

AD 或 BC

AD=Anno Domini公元,BC=Before Christ公元前。不带点的公元或公元前

‘YYYY AD’=1999 AD

A.D. 或B.C.

带点的公元或公元前

‘YYYY A.D.’=1999 A.D.

AM或PM

AM= ante meridiem 上午,PM=post meridiem下午。不带点的上午或下午

‘HH12AM’=09AM

A.M.或P.M.

带点的上午或下午

‘HH12A.M.’=09A.M.

DY

星期几的缩写

Mon,Tue,...

DAY

星期几的全拼

Monday,Tuesday,...

D

一周的星期几,星期天=1,星期六=7

1,2,3,4,5,6,7

DD

一月的第几天,1à31

1,2,... 31

DDD

一年的第几天,1à366

1,2,3,...366

J

公元前的第几天(从公元前4712起 ?)

2451514,2451515,...

W

一个月的第几周,1à 5

1,2,3,4,5

WW,IW

一年的第几周,一年的ISO的第几周

1,2,3,4,... 52

MM

两为数的月

01,02,03,...12

MON

月份的缩写

Jan,Feb,Mar ,...Dec

MONTH

月份的全拼

January,February,...

RM

罗马数字的月份,I à XII

I,II,III,IV,...XII

YYYY,YYY,YY,Y

四位数的年,三位数的年

1999,999,99,9

YEAR

年的全拼

Nineteen Ninety-nine

SYYYY

如果是公元前(BC),年份前负号

-1250

RR

当前年份的后两位数字

01代表2001年

HH,HH12

12小时制,1à12

1,2,3,...12

HH24

24小时制,0à23

0,1,2,3,...23

MI

一小时中的第几分,0à59

0,1,2,3...59

SS

一分中的第几秒,0à59

0,1,2,3,...59

SSSSS

一天中的第几秒,0à86399

0,1,2,3,...86399

../-;:

标点符号表示法

文字显示

‘text’

引号表示法

文字显示

 

 

 

TO_DATE(string,’format’)

 

将一和字串转换为ORACLE的日期。如:

 

Insert  into demo(demo_key,date_col)

Values(1 , to_date(’04-Oct-1999’,‘DD-Mon-yyyy’) );

 

TO_MULTI_BYTE()

 

将字符串中的单字节字符转换为多字节字符, 如:

 

 

TO_NUMBER()

 

将给出的字符转换为数字,如:

 

SELECT TO_NUMBER (‘1947’) “FISCAL_YEAR” FROM DUAL;

FISCAL_YEAR

-----------

1947

 

TO_MULTI_BYTE()及TO_SINGLE_BYTE

 

将单字节转换为多字节或从多字节转换为单字节。

 

 

§2.2.5   其它的单记录函数

 

BFILENAME(

, )

 

指定一个外部二进制文件。如:

 

INSERT INTOfile_tbl

VALUES (BFILENAME(’lob_dir1’, ’image1.gif’));

 

CONVERT(‘x’,’desc_set’ [, ‘source_set’])

 

将x 字段或变量的源 source 转换为 desc,如:

 

selectsid,serial#,username,

DECODE(command,

0,’None’,

2,’Insert’,

3,’Select’,

6,’Update’,

7,’Delete’,

8,’Drop’,

‘Other’) cmd

from  v$session wheretype != ‘BACKGROUND’;

 

 

关于DECODE 在优化方面的内容在《Oracle8i/9i 高级数据库管理》中查阅。

 

 

DUMP( s,[,fmt [,start [, length ] ] ] )

DUMP 函数以fmt指定的内部数字格式返回一个VARCHAR2类型的值。如:

 

SQL> col global_namefor a30

SQL> col DUMP_STRINGfor a50

SQL> set lin 200

SQL>  select global_name,dump(global_name,1017,8,5)dump_string

  2  from global_name;

 

GLOBAL_NAME                    DUMP_STRING

-----------------------------------------------------------------------------------------------------

ORA816.US.ORACLE.COM  Typ=1 Len=20 CharacterSet=ZHS16GBK: U,S,.,O,R

 

 

 

EMPTY_BLOB() 和EMPTY_CLOB() 函数

 

这两个函数都是用来对大数据类型字段进行初始化操作的函数,一般有:

 

BLOB数据类型 --- EMPTY_BLOB()

CLOB数据类型 --- EMPTY_CLOB()

NCLOB数据类型 --- EMPTY_CLOB()

 

 

Insert into proposal

( proposal_id,recipient_name,proposal_name,short_description,

proposal_text,budget, cover_letter )

values(2,’BRAD OHMONT’,’REBUILD FENCE’,NULL,

EMPTY_CLOB(),EMPTY_BLOB(),

BFILENAME(‘proposal_dir’,’P2.DOC’) );

 

GREATEST( )

返回一组表达式中的最大值,即比较字符的编码大小。如:

SQL> selectgreatest('AA','AB','AC') from dual;

 

GR

--

AC

 

SQL> selectgreatest('啊','安','天') from dual;

 

GR

--

 

即 “天”的编码比“安”和“啊”都大。

 

LEAST ( )

 

返回一组表达式中的最小值,即比较字符的编码大小。如:

 

SQL> select least('啊','安','天')from dual;

 

LE

--

 

UID 函数

返回标识当前用户的唯一整数,如:

 

SQL> show user

USER 为"SYSTEM"

SQL> l

  1* select username,user_id from dba_userswhere user_id=UID

SQL> /

 

USERNAME           USER_ID

------------------------------   ----------

SYSTEM                     5

 

 

USER 函数

 

返回当前用户的名字,如:

 

SQL> select userfrom dual;

 

USER

------------------------------

SYSTEM

 

USERENV( )

返回当前用户环境的信息,opt 选项可以是:

ENTRYID  返回当前用户会话的入口ID

SESSIONID 返回当前用户会话的ID

TERMINAL  返回当前系统会话的操作系统标识

OSDBA      如果当前用户有DBA权限,则返回TRUE

LABLE       返回当前用户会话的标号

LANGUAGE   返回当前用户的语言和区域

CLIENT_INFO  为当前用户会话返回 client-info 域的值,这个值由

              dbms_application_info,set_client_info 过程来设置。

LANG   以ISO 的三个字符表示当前用户会话所使用的语言。

VSIZE   返回表达式的字节大小。

 

ISDBA 函数

 

查看当前用户是否是 DBA ,当SYSDBA 角色有效是才返回 TRUE,如:

 

SQL> show user

USER is"SYSTEM"

SQL> selectuserenv('ISDBA') from dual;

 

USEREN

------

FALSE

 

SQL> connectsys/sys@ora816

Connected.

SQL> selectuserenv('ISDBA') from dual;

 

USEREN

------

FALSE

 

SQL> connectinternal

Connected.

SQL> selectuserenv('ISDBA') from dual;

 

USEREN

------

TRUE

 

SESSIONID函数

 

返回审计会话标识,如:

 

select userenv(‘SESSIONID’)  aud_id from dual;

 

aud_id

---------

47343

 

ENTRYID 函数

 

返回审计会话入口标识,当initsid.ora 文件中的 audit_trail=TRUE 时可以用,如:

 

select userenv(‘ENTRYID’)from dual;

 

USERENV(‘ENTRYID’)

-------------

835641

 

INSTANCE函数

 

返回当前INSTANCE 的标识,如:

 

SQL> selectuserenv('INSTANCE') from dual;

 

USERENV('INSTANCE')

-------------------

           1

 

LANGUAGE函数

 

返回当前环境的语言,如:

 

SQL> selectuserenv('LANGUAGE') from dual;

 

USERENV('LANGUAGE')

----------------------------------------------------

SIMPLIFIEDCHINESE_CHINA.ZHS16GBK

 

LANG函数

返回当前环境的语言的缩写,如:

 

SQL> l

  1* select userenv('LANG') from dual

SQL> /

 

USERENV('LANG')

----------------------------------------------------

ZHS

 

TERMINAL函数

 

返回用户的终端或机器的标识,如:

 

SQL> selectuserenv('TERMINAL') from dual;

 

USERENV('TERMINA

----------------

ZHAOYUANJIE

 

 

VSIZE( )

 

返回 x 的大小(字节)数,如:

 

SQL> selectvsize(user),user from dual;

 

VSIZE(USER)   USER

-----------      -----------------------------

          6   SYSTEM

 

 

§2.3   SQL中的组函数

§2.3.1   多记录组函数

 

AVG( [ { DISTINCT | ALL}] )

 

求平均值,ALL表示对所有求平均值,DISTINCT 只对不 同的求平均值,相同只取一个。

 

SQL> l

  1* select avg(sal) from emp

SQL> /

 

  AVG(SAL)

----------

2073.21429

 

MAX( [ { DISTINCT | ALL}] )

 

求最大值,ALL表示对所有求最大值,DISTINCT 只对不 同的求最大值,相同只取一个。

 

SQL> select max(sal)from emp;

 

  MAX(SAL)

----------

      5000

 

MIN( [ { DISTINCT | ALL}] )

 

求最小值,ALL表示对所有求最小值,DISTINCT 只对不同的求最小值,相同只取一个。

 

SQL> select min(sal)from emp;

 

  MIN(SAL)

----------

800

 

STDDEV( [ { DISTINCT | ALL}] )

 

求标准差,ALL表示对所有求标准差,DISTINCT 只对不同的求标准差,相同只取一个。

 

SQL> selectstddev(sal) from emp;

 

STDDEV(SAL)

-----------------

 1182.50322

 

VARIANCE( [ { DISTINCT | ALL}] )

 

求协方差,ALL表示对所有求协方差,DISTINCT 只对不同的求协方差,相同只取一个。

 

SQL> selectvariance(sal) from emp;

 

VARIANCE(SAL)

------------------------

   1398313.87

 

 

§2.3.2   带 GROUP  BY 的计算

 

可以用 GROUP By 来实现对一组数进行分组统计(如SUM,count(*)等),如:

 

要列出部门代码、部门人数,部门工资总和,则用到GROUP BY :

 

SQL> selectdeptno,count(*) ,sum(sal) from emp group by deptno;

 

    DEPTNO  COUNT(*)   SUM(SAL)

----------   ---------     ----------

        10          3       8750

        20          5     10875

        30          6       9400

 

 

§2.3.3   用HAVING  来限制分组的计算

 

在分组GROUP BY 中,一般都不管 统计的结果是多少都要全显示,我们可以在GROUP BY 前或后加 HAVING 子句来限制结果的统计,比如要求被统计的人数有5个人以上,则有两方法可以实现:

 

SQL> selectdeptno,count(*) ,sum(sal) from emp group by deptno

  2   having count(*)>=5;

 

    DEPTNO  COUNT(*)   SUM(SAL)

----------    ----------    ---------

        20          5     10875

        30          6       9400

 

SQL> selectdeptno,count(*) ,sum(sal) from emp having count(*)>=5

  2  groupby deptno;

 

    DEPTNO  COUNT(*)   SUM(SAL)

----------   ----------    ----------

        20          5     10875

        30          6       9400

 

 

§2.4   控制和格式化输出

§2.4.1   用 ORDER BY 子句来对结果进行排序

 

Oracle 提供ORDERBY 子句,可用于对查询到的结果进行排序输出。这样的操作是在内存中进行的。比如按照部门代码顺序和员工的工资多少顺序进行输出,需要命令:

SQL> selectdeptno,ename,sal from emp order by deptno,sal desc;

 

    DEPTNO  ENAME       SAL

---------   ----------    ----------

        10 KING             5000

        10 CLARK            2450

        10 MILLER           1300

        20 SCOTT            3000

        20 FORD             3000

        20 JONES            2975

        20 ADAMS            1100

        20 SMITH             800

        30 BLAKE            2850

        30 ALLEN            1600

        30 TURNER           1500

        30 WARD             1250

        30 MARTIN           1250

        30 JAMES             950

 

这里的 DESC 表sal(工资) 按照降序排列。

 

§2.4.2   用 BREAK 命令 来对结果进行排列

 

一般可以用 BREAK ON column SKIP xx 来对查询结果进行排列,BREAK ON 命令的参数如下:

 

clear    breaks     清除所有的 break 定义

break   on  column     在该列上中断

break   on  row        在每一行上中断

break   on   Page      在每一页上中断

break   on   report    在每一报告上中断

skip     n               跳过n行

skip     page            跳过未用完的页

 

 

 

使用方法请看下面例子:

SQL> break ondeptno

SQL> set pagesize100

SQL> selectdeptno,ename,sal from emp order by deptno;

 

    DEPTNO ENAME             SAL

---------- --------------------

        10 CLARK            2450

           KING             5000

           MILLER           1300

        20 SMITH             800

           ADAMS            1100

           FORD             3000

           SCOTT            3000

           JONES            2975

        30 ALLEN            1600

           BLAKE            2850

           MARTIN           1250

           JAMES             950

           TURNER           1500

           WARD             1250

 

已选择14行。

 

SQL> break ondeptno skip 2

SQL> selectdeptno,ename,sal from emp order by deptno;

 

    DEPTNO ENAME             SAL

-------------------- ----------

        10 CLARK            2450

           KING             5000

           MILLER           1300

 

 

        20 SMITH             800

           ADAMS            1100

           FORD             3000

           SCOTT            3000

           JONES            2975

 

 

        30 ALLEN            1600

           BLAKE            2850

           MARTIN           1250

           JAMES             950

           TURNER           1500

           WARD             1250

 

SQL> break ondeptno skip page

SQL> select deptno,ename,sal from emp order by deptno;

 

    DEPTNO ENAME             SAL

-------------------- ----------

        10 CLARK            2450

           KING             5000

           MILLER           1300

 

    DEPTNO ENAME             SAL

-------------------- ----------

        20 SMITH             800

           ADAMS            1100

           FORD             3000

           SCOTT            3000

           JONES            2975

 

    DEPTNO ENAME             SAL

-------------------- ----------

        30 ALLEN            1600

           BLAKE            2850

           MARTIN           1250

           JAMES             950

           TURNER           1500

           WARD             1250

 

已选择14行。

 

§2.4.3   用 COMPUTE 命令对结果进行格式化

 

COMPUTE 命令 的语法如下:

 

COMP[UTE] [function[LAB[EL] text] ...

OF {expr|column|alias} ...

ON {expr|column|alias|REPORT|ROW} ...]

 

function 可以是下面参数之一

AVG          数字类型平均值

COU[NT]     所有类型的个数

MIN[IMUM]  NUMBER,CHAR,NCHAR, VARCHAR2(VARCHAR),

NVARCHAR2 (NCHARVARYI NG) 类型的最小值

MAX[IMUM]  NUMBER,CHAR,NCHAR, VARCHAR2(VARCHAR),

NVARCHAR2 (NCHARVARYI NG) 类型的最大值

NUM[BER]     计算所有类型的行数

SUM           计算所有非空数字类型的总和

STD            计算数字类型的标准差

DEV[IANCE]    计算数字类型的协方差

 

LAB[EL] text

显示的字符串。用它可以替换掉字段的显示。

 

OF {expr|column|alias} ...

OF子串或表达式或别名

 

ON {expr|column|alias|REPORT|ROW} ...

ON子串或表达式或别名或REPORT或ROW

 

 

例子:

按照员工是 "clerk"、"analyst"、"analyst"及 "salesman"进行工资小计 ,并加标记"TOTAL", 则:

SQL> BREAK ON JOB SKIP 1

SQL> COMPUTE SUM LABEL ’TOTAL’ OF SAL ON JOB

SQL> SELECT JOB, ENAME, SAL

2 FROM EMP

3 WHERE JOB IN (’CLERK’, ’ANALYST’, ’SALESMAN’)

4 ORDER BY JOB, SAL;

The following output results:

JOB ENAME SAL

--------- ---------- ----------

ANALYST SCOTT 3000

FORD 3000

********* ----------

TOTAL 6000

 

CLERK SMITH 800

JAMES 950

ADAMS 1100

MILLER 1300

********* ----------

TOTAL 4150

SALESMAN WARD 1250

MARTIN 1250

TURNER 1500

ALLEN 1600

********* ----------

TOTAL 5600

 

计算工资小于 1,000 的总和:

 

SQL> COMPUTE SUM OF SAL ON REPORT

SQL> BREAK ON REPORT

SQL> COLUMN DUMMY HEADING ’’

SQL> SELECT ’ ’ DUMMY, SAL, EMPNO

2 FROM EMP

3 WHERE SAL < 1000

4 ORDER BY SAL;

 

SAL EMPNO

--- ---------- -----------

800 7369

950 7900

----------

sum 1750

 

计算平均和最大工资、部门:

 

SQL> BREAK ON DNAME SKIP 1

SQL> COMPUTE AVG LABEL ’Dept Average’ ->

MAX LABEL ’Dept Maximum’ ->

OF SAL ON DNAME

 

SQL> SELECT DNAME, ENAME, SAL

2 FROM DEPT, EMP

3 WHERE DEPT.DEPTNO = EMP.DEPTNO

4 AND DNAME IN (’ACCOUNTING’, ’SALES’)

5 ORDER BY DNAME;

 

 

DNAME ENAME SAL

-------------- ---------- ----------ACCOUNTING

CLARK 2450

KING 5000

MILLER 1300

************** ----------Dept

Average 2916.66667

 

Dept Maximum 5000

SALES ALLEN 1600

BLAKE 2850

MARTIN 1250

JAMES 950

TURNER 1500

WARD 1250

************** ----------Dept

Average 1566.66667

Dept Maximum 2850

9 rows selected.

 

计算部门10和20 的工资总和,不打印:

 

SQL> COLUMN DUMMY NOPRINT

SQL> COMPUTE SUM OF SAL ON DUMMY

SQL> BREAK ON DUMMY SKIP 1

SQL> SELECT DEPTNO DUMMY, DEPTNO, ENAME, SAL

2 FROM EMP

3 WHERE DEPTNO <= 20

4 ORDER BY DEPTNO;

 

DEPTNO ENAME SAL

---------- ---------- ----------

10 CLARK 2450

10 KING 5000

10 MILLER 1300

----------

8750

20 SMITH 800

20 ADAMS 1100

20 FORD 3000

20 SCOTT 3000

20 JONES 2975

----------

10875

8 rows selected.

 

在报告结束不打印计算工资总和:

 

SQL> COLUMN DUMMY NOPRINT

SQL> COMPUTE SUM OF SAL ON DUMMY

SQL> BREAK ON DUMMY

SQL> SELECT NULL DUMMY, DEPTNO, ENAME, SAL

2 FROM EMP

3 WHERE DEPTNO <= 20

4 ORDER BY DEPTNO;

 

DEPTNO ENAME SAL

---------- ---------- ----------

10 CLARK 2450

10 KING 5000

10 MILLER 1300

20 SMITH 800

20 ADAMS 1100

20 FORD 3000

20 SCOTT 3000

20 JONES 2975

----------

19625

8 rows selected.

 

 

 

§2.5   配置会话环境

一般在SQL>下进行SQLPLUS 操作,都需要进行必要的环境设置才能完成我们所需要的输出。所有环境的设置由 SET命令加相应的环境变量来完成。下面是常用的环境设置:

 

§2.5.1   ARRAYSIZE(取回的行数)

SET  ARRAY[SIZE]{integer}

 

一次可以提取(Fetch)的行的数目,1->5000,当有较长字段时应设小些。

 

 

§2.5.2   AUTOCOMMIT(自动提交)

SET  AUTO [COMMIT] {[ OFF | ON | IMM | n] }

用于在操作中是自动提交或是部分提交或是不自动提交。

1)  ON或IMM使得在完成每条SQL语句时将未提交的改变立刻提交给数据库系统。

2)  N 允许在用户发出COMMIT后,可以执行命令的数量(将n条SQL语句所做的改变进行提交)。

3)  OFF 停止自动提交,用户必须用COMMIT命令才能被提交。

 

§2.5.3   LINESIZE(行显示宽度)

可以设置 LINESIZE 环境变量来控制行的显示宽度,缺省是80个字符。

SET    Lin[esize]{80|integer}

Integer = 设置行宽度(字符个数),最大值999,如:

SQL>set linesize160

 

§2.5.4   LONG(长类型显示字节数)

在缺省的SQL> 状态下,SQL>缓冲区用于显示LONG 的字节数只有80个字符。如果我们需要查询的列中含有 LONG类型的字段的话,就需要将LONG缓冲区设置大些。

SET  LONG{80|integer}

Integer 是 显示或拷贝long值的最大宽度,n=1->32767(但必须小于Maxdata值)

SQL>show  Maxdata (最大行宽)

SQL>set long 2000

 

§2.5.5   PAGESIZE(页行数)

在缺省的SQL> 状态下,SQL>缓冲区显示页的行数是24行,其中22行显示数据,2行显示标题和横线。我们将pagesize 设置大些以减少提示标题和横线。

SET  pag[esize]   {24|integer}

SQL>SET pagesize66

 

§2.5.6   PAUSE(暂停)

可以设置 PAUSE 为ON 或OFF来控制屏幕显示。当设置为ON时,在select 语句发出后需要按Enter键才能显示一屏。

SET PAUSE [ ON | OFF]

SQL> set pause on

 

提示:在发出select 语句并按Enter键后 还要再按Enter键才能显示结果.

 

§2.5.7   SPACE(列间空格)

可用 set space 来设置各列间的空格数,语法为:

SET   SPA[CE]   {1|n}

N为设置输出行列间的空格数,最大为10。

SQL>set space 2

 

建议:在一般情况下,不用设置space参数。

 

§2.5.8  Termout (启/停屏幕显示)

TERMOUT用于设置在屏幕上显示或不显示所输出的信息。

SET TERMOUT { ON | OFF }

 

set    termout off

set    termout on

 

set   termout off   常用SPOOL XXX时,即关闭报表在屏幕上的显示(节省时间)

set   termout on    常用SPOOL  off之后,即恢复报表在屏幕上的显示

 

§2.5.9   ECHO (启/停命令显示)

可以用ECHO命令来显示或不显示所执行的SQL命令。语法如:

SET   ECHO{OFF|ON}

显示执行当中的各命令( 即用start  时)

set   echo   受到   set  termout  的影响

 

set pagesize 100

set echo on

select table_namefrom dict where rownum<20;

select * from catwhere rownum<30;

set echo off

--下面只显示结果不显示命令:

select table_namefrom dict where rownum<20;

select * from catwhere rownum<30;

 

§2.5.10  TRANSACTION(启动事务)

一个很重要的事务环境设置是TRANSACTION。它包括两个部分的内容:

SET TRANSACTION { READ ONLY | USE ROLLBACK SEGMENTsegment_name }

READ ONLY 是用于保证读的一致性。即其他用户的修改不影响当前查询结果。

USE ROLLBACK SEGMENT segment_name 是为当前所处理的事务指定专门的回滚段。这主要是在进行大量的Insert 或Delete 或Update时,需要一个大的回滚段以保证事务正常完成。详细见数据库管理员。

 

§2.5.11 SHOW ALL(列出所有参数)

可以用SHOW ALL 来显示当前的所有参数情况。它的用法很简单。比如:

 

SQL> show all

appinfo为ON并且已设置为"SQL*Plus"

arraysize 15

autocommit OFF

autoprint OFF

autorecovery OFF

autotrace OFF

blockterminator "."(hex 2e)

btitle OFF and 为下一条SELECT 语句的前几个字符

cmdsep OFF

colsep ""

compatibilityversion NATIVE

concat"." (hex 2e)

copycommit 0

COPYTYPECHECK 为 ON

define"&" (hex 26)

describe DEPTH 1LINENUM OFF INDENT ON

markup HTML OFFSPOOL OFF ENTMAP ON PREFORMAT OFF

echo OFF

editfile"afiedt.buf"

embedded OFF

escape OFF

flagger OFF

flush ON

heading ON

headsep"|" (hex 7c)

instance"local"

linesize 80

lno 14

loboffset 1

logsource""

long 80

longchunksize 80

newpage 1

null ""

numformat""

numwidth 10

pagesize 14

PAUSE 为OFF

pno 0

recsep WRAP

recsepchar "" (hex 20)

release 801070000

repfooter OFF and为 NULL

repheader OFF and为 NULL

serveroutput OFF

shiftinoutINVISIBLE

showmode OFF

spool OFF

sqlblanklines OFF

sqlcase MIXED

sqlcode 0

sqlcontinue"> "

sqlnumber ON

sqlprefix"#" (hex 23)

sqlprompt"SQL> "

sqlterminator";" (hex 3b)

suffix"sql"

tab ON

termout ON

time OFF

timing OFF

trimout ON

trimspool OFF

ttitle OFF and 为下一条SELECT 语句的前几个字符

underline"-" (hex 2d)

USER 为"SYS"

verify ON

wrap : 行将为已换行

SQL>

你可以从上面的参数中看到其当前值,也可以修改某些参数的值。

 

§2.6   格式化输出

§2.6.1   一般数据的格式化输出

 

在Oracle的SQL> 下,经常用COLUMN命令来对所输出的列进行格式化,即按照一定的格式进行显示。COLMUN命令语法如下:

 

COL[UMN] [{ column | expr } [ option_1 ... option_n ] ]

 

column :列名

expr :有效的 SQL 表达式

option_1... option_n:可以是下列之一:

ALI[AS] alias

CLE[AR]

FOLD_A[FTER]

FOLD_B[EFORE]

FOR[MAT] format

HEA[DING] text

JUS[TIFY] {L[EFT]|C[ENTER]|C[ENTRE]|R[IGHT]}

LIKE {expr|alias}

NEWL[INE]

NEW_V[ALUE] variable

NOPRI[NT]|PRI[NT]

NUL[L] text

OLD_V[ALUE] variable

ON|OFF

WRA[PPED]|WOR[D_WRAPPED]|TRU[NCATED]

 

下面给出常用的关键字的解释:

Alias     给出列的别名,BREAK和COUMN可以引用所定义的别名。

CLEAR  取消列的定义。

FORMAT 列显示格式,format为:

9999990     9或0的个数决定最多显示多少位

9,999,999.99 按照逗号和小数点来 显示数据,若是0以空格显示

099999      显示前面补0

$999,999.99  数字前加美圆号

B99999      若为0 ,则结果为空白

99999Mi     若数字为负,则负号放在数字后(右边),缺省放在左边

99999PR     负号将以括号括起

9.999EEEE   以科学记数法表示(必须有4个E)

999V99      数字乘以 10n ,如 1234变为 123400

DATE       采用日期数字格式(MM/DD/YY)

 

 

Heading 重新标记列的显示标题,如:

 

SQL> col  ename heading  姓名 format a10

SQL> selectename,sal  from emp;

 

 

例子:

SQL

COLUMN  SALARY  FOR  $9,999,999.99

COLUMN  LAST_NAME  FOR  A35.

 

§2.6.2   日期的格式化输出

Oracle系统提供了一个 NLS_DATE_FORMAT的环境变量来设置日期的显示格式。用它可以完成按照不同格式要求的显示,比如按照中国的习惯为 yyyy年mm月dd日等。

 

1.系统日期sysdate 的显示

用sysdate 可以显示ORACLE RDBMS 所在机器的日期及时间,如:

SQL> altersession set nls_date_format ='"公元"yyyy"年"mm"月"dd"日"';

 

会话已更改。

 

SQL> selectsysdate from dual;

 

SYSDATE

------------------

公元2001年05月30日

 

 

2.日期类型的显示

 

selectsysdate,to_char(sysdate,’yyyy.mm.dd hh24:mi;ss’)from dual;

 

SQL>connect scott/tiger

已连接。

SQL>alter session set nls_date_format ='yyyy"年"mm"月"dd"日生"';

 

会话已更改。

SQL>col HIREDATE heading 生日

SQL>col sal heading 工资

SQL>col sal ename 姓名

SQL>select ename,sal,hiredate from emp;

 

姓名             工资             生日

---------- ---------- -----------------

SMITH            800 1980年12月17日生

ALLEN           1600 1981年02月20日生

WARD            1250 1981年02月22日生

JONES           2975 1981年04月02日生

MARTIN          1250 1981年09月28日生

BLAKE           2850 1981年05月01日生

CLARK           2450 1981年06月09日生

SCOTT           3000 1987年04月19日生

KING            5000 1981年11月17日生

TURNER           1500 1981年09月08日生

ADAMS           1100 1987年05月23日生

JAMES            950 1981年12月03日生

FORD            3000 1981年12月03日生

MILLER          1300 1982年01月23日生

 

已选择14行。

§2.7  加标题

有时在输出一些结果时,可能需要加一些标题,如表上面的顶标题,落款等。这样的要求可由Ttitle和Btitle来完成。

ttitle和btitle

 

ttitle   [center|left|right]string    顶标题

btitle   [center|left|right]string    底标题

ttitle   center  'XX公司人员情况表'

btitle   left     '制表人:xxxx'   right    '日期:xxxx年xx月'

Clear    ttitle

 

§2.8  建立简单报告

我们可以用TTITLE、BTITLE、COLUMN、BREAKON、COMPUTE SUM及SET LINESIZE、SET PAGESIZE、SETNEWPAGE来设置查询结果的显示格式;在用 SPOOL 命令将显示结果输出到一个操作系统文件中去,一般输出文件的类型为.LST。

 

建立简单报告主要使用下面命令来实现:

 

1. SPOOL命令

 

SPOOL   filename     将缓冲区的内容写到文件中

SPOOL   off          终止写命令

 

2. COLUMN   命令

column    col_name[,heading]    format     format_spe

把字段的结果指定为一种输出格式

COL   name  heading   '姓名'  for    a10

COL    sal     heading   '工资'   for    9,999.99

 

3.ttitle、btitle

 

ttitle   [center|left|right]string    顶标题

btitle   [center|left|right]string    底标题

ttitle   center  'XX公司人员情况表'

btitle   left    '制表人:赵元杰'   right   '日期:1998.11月'

Clear    ttitle

 

4.break、compute

 

clear    breaks,clear    computes

break   on  column     在该列上中断

break   on  row        在每一行上中断

break   on   Page

break   on   report

skip     n               跳过n行

skip     page            跳过未用完的页

compute       avg

compute      count

compute       max

compute       min

compute       std

compute       sum

compute       var

compute       num    计算所有行

compute       sum  of   sal   on  deptno

 

5.set   在报表中的设置

l set    termout   off、set   termout  on 命令

l set   termout   off   常用SPOOL   XXX前,即关闭报表在屏幕上的显示(节省时间)

l set   termout   on    常用SPOOL  off之后,即恢复报表在屏幕上的显示

l set   ECHO{OFF|ON} 显示执行当中的各命令(即用start    时),set   echo   受到  set   termout    的影响

l set    Lin[esize]{80|integer}    设置行宽度,最大值999

l set  pag[esize]  {24|integer}   设置页的大小

 

例子:

SQL>COL enameheading ‘姓名’ for a12

SQL>COL sal heading ‘工资’for a999,999.99

SQL>COLhiredate  heading ‘出生’

SQL>SET LINESIZE 200

SQL>SET PAGESIZE 60

SQL>SPOOL c:\all_emp

SQL>selectename,sal,deptno,hiredate from emp order by deptno;

SQL>SPOOL OFF

 

§2.9  输入变量

Oracle提供一种在处理SQL语句时可以将参数作为变量来对待的技术,即在条件句中可以是变量而不是具体的值,这样的处理就是输入变量。这样做的目的就是可以重复使用同样的语句,每次只要输入相应的值即可。要实现将参数写成为变量,只要在变量前加一个&号即可。看下面语句:

 

Select  sid, serial#,username, command from v$session

Where   USERNAME = upper(‘&usr’);

 

这样的语句在运行中,系统会自动提示你回答变量的具体值,上面语句运行时提示和回答时显示的信息如下:

 

SQL> Select  sid, serial#,username, command from v$session

 2  Where   USERNAME = upper('&usr');

输入 usr 的值:  sys

原值    2: Where   USERNAME = upper('&usr')

新值    2: Where   USERNAME = upper('sys')

 

  SID  SERIAL# USERNAME      COMMAND

---------- ---------------------------------------- ----------

         7     26 SYS                       3

 

 

在变量说明中,可以使用多个变量,比如:

 

Alter systemkill session ‘&sid,&ser’;

Alter systemkill session ‘&会话号,&序列号’;

 

它的运行情况如下:

 

SQL> Select  sid,serial#,username, command from v$session;

 

   SID  SERIAL# USERNAME       COMMAND

---------- ---------- ------------------------------ ----------

         1          1                 0

         2          1                 0

         3          1                 0

         4          1                 0

         5          1                 0

         6          1                 0

         7         26 SYS             3

         8         16 ZHAO           0

 

已选择8行。

 

SQL> Alter system kill session '&sid,&ser';

输入 sid 的值:  8

输入 ser 的值:  16

原值    1: Alter system kill session'&sid,&ser'

新值    1: Alter system kill session '8,16'

 

系统已更改。

 

一般系统缺省下是使用 “&”符号来定义变量,你也可以使用另外的符号来代替,比如不喜欢用 & 而要用 ?,则有:

 

SQL> set define ?

SQL> selectsid,serial#,username from v$session where username='?usr';

输入 usr 的值:  SYS

原值    1: select sid,serial#,username fromv$session where username='?usr'

新值    1: select sid,serial#,username fromv$session where username='SYS'

 

       SID   SERIAL# USERNAME

-------------------- ------------------------------

7            26 SYS

 

次时由于我们修改了会话环境的参数值,可以用下面命令查看:

 

SQL> show define

define "?"(hex 3f)

 

 


 

第三章  表及索引的定义操作

在ORACLE数据库系统中,表是数据库的基本对象,与桌面数据库中的文件类似,我们可以把所有的基本实体都看成为表,不管应用中的表有多复杂,都可以使用(拆成)一个或多个表来表示。用以存放实体的数据。下面针对建表所需要的知识作简单的介绍。

§3.1  建立表结构

建立表结构是每个应用系统都必须进行的工作。由于建立表结构是一项统一规划和统一设计的工作。应该是由总设计师根据用户的具体应用需要来定。表的设计是否合理关系到应用系统将来的成败与性能问题。因此,任何担当总设计师角色的人都不要轻视这项工作。

§3.1.1  建立表结构命令

由于创建表的命令非常长,这里仅给出一些主要的部分,详细的请参考《ORACLE8i SQL REFERENCE》 。

 

CREATE TABLE  命令简要语法如下:

 

CREATE TABLE [USER.]table_name

( { COLUMN1 DATATYPE

[DEFAULT EXPN][COLUMN_CONSTRAINT] |TABLE_CONSTRAINT }

[, { COLUMN1DATATYPE

[DEFAULT EXPN][COLUMN_CONSTRAINT] |

TABLE_CONSTRAINT }]... )

[CLUSTER CLUSTER(COLUMN1 [,COLUMN2] ...) ]

[PCTFREE N]

[PCTUSED N]

[INITRANS N]

[MAXTRANS N]

[STORAGE N]

[TABLESPACETABLESPACE]

[ ENABLE | DISABLE]

[ AS QUERY]

 

其中:

schema     包括基表的模式(缺省:当前用户的帐号)

table_name 表名

column     列名(字段名),ORACLE7最多254列,ORACLE8可达1000个列。

datatype   列数据类型

DEFAULT              当前列的缺省值(常数)

Columnconstraint    列约束

Table_constraint     表约束

PCTFREE    用于更新(update)的空间百分比(1-99)

           0表示在插入时完全填满数据块,缺省为10

PCTUSED    为表的每个数据块保留的可用空间的最小百分比. 取值1-99,缺省为40。

PCTFREE和PCTUSED的组合决定了将插入的数据放入已存在的数据块还是放入一个新的块中。

INITRANS  指定一个在每一个数据块中分配的事务入口的初始数1-255,

                  缺省为1,每一个更新块的事务都需要在块中有一个事务入口

                  (大小依OS),一般不需要指此参。

MAXTRANS    指定用于更新分配给表的数据块的并发事务的最大数,1-

                        255,用户一般不应改此参。

TABLESPACE    表空间。如果缺省则表建在用户缺省的表空间(如果建立用户不指定表空间

              则该用户的缺省表空间为system)。

STORAGE          存储分配参数

                 INITIAL      integer   初始大小

                 NEXT         integer    下一次的大小

                 MINEXTENTS   integer   最小分配次数

                 MAXEXTENTS   integer   最大分配次数

                 PCTINCREASE  integer   增长百分比(>=0)

ENABLE         激活完整性约束

DISABLE        取消完整性约束

As  subquery      建表中查出数据给新表,此语句如果使用,则表的数据类型不需指定,

                   而是继承原表的类型。

FREELIST   GROUP  在并行服务器中指定表或分类、索引组的列表数目。

FREEUST      在并行服务器中指定表、簇、索引的列表数。

 

提示1:

一般情况下,如果表含有long字段,这样势必需大量的空间,系统会在每次插入新记录时,经常分配空间给表,不久就会出现:

 

"ORA-01547:Failed   to  allocate   extent   of  size   xxxxx   in  

tablespace    'xxxx' "

 

     此种情况如果表空间还剩较多的连续空间的话。则可能是该表分配的空间次数已达最大值。为了对该表能插入新数据,需对该表的存储参数作修改,比如:

     SQL>alter   table  xxx   storage(MAXEXTENTS    999 );

 

 

提示2:建议不要对表结构或索引使用 pctincrease大于0的参数以避免将来在运行中产生空间超支问题.

提示3:建立表结构最重要的部分是存储参数(STORAGE)的说明。设置者要特别重视存储参数的估计,设置合理的大小。详细见〈Oracle8i/9i 初级数据库管理〉

 

§3.1.2  建立表结构例子

例1:在SCOTT模式下建立表emp,并指定表空间和存储参数:

Create   table  scott.emp

(

         Empno  number(5)   primary   key,

         Ename  varchar2(15)   not   null,

         Job    varchar2(10),

         Mgr    number(5),

         Hiredate   date  default   sysdate,

         Sal    number(7,2)   CHECK(sal>100),

         Comm   number(3)   default 0.0 ,

         Dept   number   constraint  

         dept_fkey     References   scott.dept

)

Tablespace   users

PCTFREE   10

PCTUSED   70

STORAGE

      (

      INITIAL   50K

      NEXT       50k

      MAXEXTENTS   10

      );

 

例2:在建立表过程中对有限制的列使用NOTNULL:

 

CREATE TABLECHECKUP_HISTORY

(CHECKUP_NONUMBER(10,0) NOT NULL,

ID_NO NUMBER(10,0),

CHECKUP_TYPEVARCHAR2(30),

CHECKUP_DATE DATE,

DOCTOR_NAMEVARCHAR2(50));

 

本例除了要求CHECKUP_NO非空外,其它无任何限制.

 

例3:在建立表时指定列CHECKUP_TYPE为外部列:

 

CREATE TABLESEAPARK.CHECKUP_HISTORY

(

CHECKUP_NONUMBER(10) NOT NULL,

ID_NO NUMBER(10,0),

CHECKUP_TYPEVARCHAR2(30),

CHECKUP_DATE DATE,

DOCTOR_NAMEVARCHAR2(50),

FOREIGN KEY(CHECKUP_TYPE) REFERENCES

SEAPARK.CHECKUP(CHECKUP_TYPE),

PRIMARY KEY(CHECKUP_NO)

)

PCTFREE 20

PCTUSED 60

INITRANS 2

MAXTRANS 255

STORAGE ( INITIAL1250K

NEXT 2K

MINEXTENTS 1

MAXEXTENTS 121

Pctincrease 0)

TABLESPACE  user_data;

 

 

例子指定了所有者,主键,外部键,表空间及存储参数等,主键和外部键在后面章节介绍。

 

§3.1.3  建立临时表结构

Oracle现在可以使用 CREATE GLOBAL TEMPORARY TABLE命令来实现建立临时表结构。这样的表它的数据只在用户会话期间存在,当会话完成后就自动清除。看下面例子:

 

SQL> create  global temporary table myemp as select * fromemp;

 

表已创建。

 

SQL> desc myemp

 名称                                      空?      类型

 ------------------------------------------------- --------------

 ENAME                                             VARCHAR2(20)

 SAL                                               NUMBER(9,2)

 DEPTNO                                             NUMBER(4)

 TEL                                               VARCHAR2(20)

 

SQL> select *from myemp;

 

未选定行

 

SQL> insert intomyemp values('赵元杰',32456.99,10,'12');

 

已创建 1 行。

 

SQL> select *from myemp;

 

ENAME                       SAL    DEPTNO TEL

------------------------------ ---------- ------------------

赵元杰                 32456.99         10 12

 

SQL> connectsys/sys

已连接。

SQL> connectzhao/zhao

已连接。

SQL> l

  1* select * from myemp

SQL> /

 

未选定行

 

从上面可看出当连接到SYS在连接回来后数据就不存在了。对于临时表,可以用DROP TABLE来删除其结构。如:

 

SQL> drop tablemyemp;

 

表已丢弃。

 

 

§3.3  修改表结构

修改表结构是对已经创建完成(实际是存放在数据库字典里)的表的结构进行修改。不同的Oracle版本允许对表的修改也不一样。新版的Oracle8i可以对表中的列进行删除。

§3.3.1  修改表结构命令

修改表结构的命令由ALTERTABLE来完成。该命令的参数较多,下面仅给出一些基本的部分。详细请参考《ORACLE8i SQLREFERENCE》 。

 

ALTER   TABLE  [user.]   table

[ADD   ({colum_element|table_constraint}

       [,{column_element|table_constraint}]...)]

[MODIFY(column_element[,column_element]...)]

[DROP   CONSTRAINT  constraint]...

[PCTFREE   integer][PCTUSED   integer]

[INITRANS   integer][MAXTRANS   integer]

[STORAGE   storage]

[BACKUP]

 

ALTER TABLE 可以作的操作有:

 

l 增加一个列(字段)宽度;

l 减少一个列(字段)宽度(该列必须无数据);

l 增加一个列(字段);

l  修改列的定义 ;

l 或一个限制;(如数据类型,NOT NULL);仅当某列的值为空时才能修改其类型;

l 去掉限制;

l 修改存储分配;

l 记录表已作过BACKUP;

l 删除已存在的列(仅Oracle8i及以后版本);

l 重新定位和组织表(仅Oracle8i及以后版本);

l 将表标识为不可用(仅Oracle8i及以后版本)。

 

 

§3.3.2  修改表结构例子

 

例1:对已经存在的表增加一新的列:

 

SQL>alter   table  dept   add   ( headcount  number(3) );

 

例2:对表的列修改其大小:

 

SQL>alter   table  dept   modify( Dname   char(20) );

 

如果被修改的列没有空(已有数据),则被提示:

ORA-01439: Column tobe modified must be  empty to change

datatype

ORA-01441: Column tobe modified must be  empty to decrease

column length

 

例3:复制一个表:

 

CREATE  TABLE HOLD_TANK  AS  SELECT TANK_NO, CHIEF_CARETAKER_NAME

FROM TANK;

 

 

例4:参照某个已存在的表建立一个表结构(不需要数据)

 

create table emp2 asselect * from emp where rownum<1;

 

 

 

例5:修改已存在表存储参数:

 

Alter  table emp2 storage( next 256k pctincrease 0 );

 

例6:删除表中的列:

 

这是Oracle8i的新功能,它的基本语法为:

 

ALTER TABLE . ..  . . . DROP COLUMN [ CASCADECONSTRAINTS ];

 

如:

Alter  table emp  drop column comm ;

 

例7:重新定位和组织表:

 

这是Oracle8i的新功能,可以实现:

l 将未分区的 表从一个表空间移到另一个表空间;

l 重新组织一个未分区表的存储。

它的基本语法为:

 

ALTER TABLE . ..  . . . MOVE TABLESPACE ;

 

如:

Alter  table emp  move  tablespace  users;

 

例8:将表标识为不可用:

 

这是Oracle8i的新功能,可以实现对空间的收回等。

 

基本语法为:

 

ALTER TABLE . ..  . . . SET  UNUSED COLUMN;

 

如:

Alter  table emp  set  UNUSED COLUMN xyz;

 

提示:虽然Oracle允许用户对表的结构进行修改。但建议你在工作中不要采用方式。因为表结构被多次修改会影响应用系统的性能。

 

§3.3.3  删除表结构

Oracle提供DROP TABLE命令可以实现删除表数据和结构。提醒初学者,不要轻易使用DROP TABLE命令。DROP TABLE 命令语法:

 

DROP TABLE[user.]table_name[CASCADE CONSTRAINTS]

 

CASCADE CONSTRAINTS表示所有指向本表的主键,外部键被删掉。当删除一个表时,下面的对象也随之被删掉。

 

l 表的索引;

l 指向本表的外部键;

l 本表的触发器;

l 本表中的分区;

l  本表的快照;

l 本表的角色和用户权限;

l 加在本表的所有限制。

 

提示:如果你在定义表结构时,采用了主键、外部键来定义了一序列表。则在删除表结构时要小心。不要轻易用CASCADE子句。

 

§3.3.4  使用CHECK作限制约束

Oracle提供了一个很有用的子句CHECK,它可以实现对数据的自动检查。它的用法是在创建表结构时使用。如:

 

     Create  table    worker

     (     empno        number(4)    primary  key,

            name         varchar2(10),

            age          number(2)   CHECK(age  between  18   and  65 ),

            /* age          number(2)   CHECK( age >=18 and age<=65 ) */

            lodging      char(15)    References    LODGING(lodging)

     );

 

     Create  table    emp3

       (  empno         number(4)  constraint abc   primary    key,

           ename         varchar2(10),

           job           varchar2(10),

           sex           char(2) check ( sex=‘男’ or sex= ’女’),

           mgr           number(4),

           hiredate      date,

           sal           number(7,2), /* 工资 */

           comm          number(7,2), /* 奖金 */

           deptno        number(2),

           CHECK      ( sal+comm >0  and  sal+comm<=5000)

      );

 

建议:在设计数据库表结构时,建议你分析用户的数据的取值范围,从而将那些取值范围一定的字段用CHECK进行描述。以保证以后数据的正确性。

 

§3.3.5  使用UNRECOVERABLE创建表

 

对于特殊的需要,可以考虑将表创建成为不需恢复(UNRECOVERABLE)的表。如复制一个已存在的表就可以采用这种方法以减少系统的开销。如:

 

例:参考emp表创建一个新的emp_new 表:

 

SQL> create table new_emp  as select * from emp  UNRECOVERABLE;

 

表已创建。

 

CREATE  TABLEnew_emp  AS select  * from emp  NOLOGGING;

 

注:虽然上面提到UNRECOVERABLE,但是Oracle推荐你使用NOLOGGING或LOGGING;

 

§3.3.6  将表移动到新的数据段或新的表空间

最新的Oracle8i 版本可以用Alter table  … MOVE语句将表移动到一个新的段或新表空间上,这样可以实现对不合理存储参数进行修改,包括用一般的ALTER TABLE 不能修改的参数。如:

 

例1:通过移动来实现存储参数的修改:

 

Alter table emp MOVE

STORAGE(INITIAL 1m next 512k minextents 1 maxextents 999 pctincrease 0 );

 

例2:将那些使用system表空间 的对象移动到合适的表空间中:

1)移动前表所使用的表空间情况:

SQL> selecttablespace_name,table_name,initial_extent from user_tables;

 

TABLESPACE_N    TABLE_NAME      INITIAL_EXTENT

---------------------- ----------------------- ----------------------------

SYSTEM            ABC                       65536

SYSTEM           BONUS                     65536

SYSTEM           DEPT                      65536

SYSTEM           EMP                       65536

SYSTEM           EMP2                      65536

SYSTEM           EMP3                     65536

SYSTEM           EMP4                     65536

USERS              PAY_LST_DET          1048576

SYSTEM           PLAN_TABLE              65536

SYSTEM           SALGRADE                65536

USERS              UNIT_INF               1048576

 

11 rows selected.

 

2)用Alter table . . .  MOVE 语句对表进行移动,下面例子对表进行移动并重新指定存储参数。

 

SQL> altertable emp move tablespace user_data

  2 storage(initial 128k next 128k minextents 1 pctincrease 0);

 

Table altered.

 

SQL> altertable dept move tablespace user_data

  2 storage(initial 128k next 128k minextents 1 pctincrease 0);

 

Table altered.

 

SQL> alter tableBONUS  move tablespace user_data

  2 storage(initial 128k next 128k minextents 1 pctincrease 0);

 

Table altered.

 

3)移动后的表及表空间的情况:

 

SQL> selecttablespace_name,table_name,initial_extent from user_tables;

 

TABLESPACE_N   TABLE_NAME  INITIAL_EXTENT

------------------------------------------------ ---------------------------

SYSTEM          ABC                    65536

USER_DATA       BONUS               131072

USER_DATA       DEPT                  131072

USER_DATA       EMP                    131072

SYSTEM          EMP2                   65536

SYSTEM          EMP3                   65536

SYSTEM          EMP4                   65536

USERS           PAY_LST_DET          1048576

SYSTEM         PLAN_TABLE        65536

SYSTEM         SALGRADE          65536

USERS          UNIT_INF             1048576

 

11 rows selected.

 

 

§3.3.7  手工分配表的存储空间

 

使用ALTER TABLE 加ALLOCATEEXTENT 选项来实现分配一个指定的空间。如:

 

ALTERTABLE emp

ALLOCATE EXTENT (SIZE 5K INSTANCE4);

 

§3.3.8  标记不使用的列和删除不使用的列

前面介绍过,新版的Oracle8I可以删除某个 列。如:

 

例:从LONG_TAB表中将LONG_PICS列删除掉:

ALTER TABLE LONG_TAB DROP COLUMN LONG_PICS;

 

可以使用 ALTER TABLE  . . . SET UNUSED 语句实现将表中的列设置为不用的状态以达到快速处理的目的。其结果是:

 

1)在显示结果时看不到该列;

2)不删除该列的数据(但可以将该列删掉);

 

例:

SQL> select *from emp;

 

     EMPNOENAME      JOB           MGR HIREDATE         SAL       COMM  DEPTNO

  ---------- ------------ ----------------------------- ---------------- ------------ ----------- ----------

      7369 SMITH      CLERK                7902 17-DEC-80        800                       20

      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30

      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30

      7566 JONES      MANAGER          7839 02-APR-81       2975                   20

      7654 MARTIN     SALESMAN      7698 28-SEP-81       1250       1400         30

      7698 BLAKE      MANAGER         7839 01-MAY-81     2850                       30

      7782 CLARK      MANAGER         7839 09-JUN-81       2450                      10

      7788 SCOTT     ANALYST           7566 19-APR-87       3000                      20

      7839 KING   PRESIDENT          17-NOV-81                5000                     10

      7844 TURNER     SALESMAN      7698 08-SEP-81       1500          0          30

 

10 rows selected.

 

SQL> altertable emp2 set unused(comm);

 

Table altered.

 

SQL> select *from emp;

 

     EMPNO ENAME      JOB            MGR HIREDATE         SAL    DEPTNO

   ------------ ----------- ------------------------- --------------- ---------- ----------

      7369 SMITH      CLERK           7902   17-DEC-80        800         20

      7499 ALLEN      SALESMAN    7698  20-FEB-81      1600         30

      7521 WARD       SALESMAN    7698 22-FEB-81       1250         30

      7566 JONES      MANAGER      7839  02-APR-81      2975         20

      7654 MARTIN     SALESMAN  7698  28-SEP-81       1250         30

      7698 BLAKE      MANAGER     7839  01-MAY-81      2850        30

      7782 CLARK      MANAGER     7839  09-JUN-81      2450         10

      7788 SCOTT      ANALYST         7566 19-APR-87       3000         20

     7839 KING       PRESIDENT                17-NOV-81       5000         10

      7844 TURNER   SALESMAN   7698  08-SEP-81        1500         30

 

10 rows selected.

 

SQL> desc emp

 Name                                                             Null?    Type

 ------------------------------------------------------------------------- ------------

 EMPNO                                                                     NUMBER(4)

 ENAME                                                                     VARCHAR2(10)

 JOB                                                                             VARCHAR2(9)

 MGR                                                                            NUMBER(4)

 HIREDATE                                                                 DATE

 SAL                                                     NUMBER(7,2)

 DEPTNO                                                                    NUMBER(2)

 

 

可以用ALTER TABLE . . .DROP UNUSED COLUMNS 来删除不使用的列。它可以在物理上删除表的未使用的列,并重新声明磁盘空间。在使用该语句时可以在后面加上checkpoint 检查点关键字。它可以产生一个检查点。使用检查点可以在删除数据列的操作过程中减少恢复日志的容量积累,从而避免回滚段的空间消耗。

如:

 

SQL> altertable emp drop unused columns checkpoint;

 

Table altered.

 

注意:删除表中未使用列时不需要指定列名,它是根据alter table emp  set unused(comm); 语句来删除未使用的列。

 

 

§3.3  主键

ORACLE 系统提供一个关键字 primary key 来建立一个主键。所谓主键,就是在一个表内该列具有唯一的值。一旦你为一个表的一列或几个列建立了主键,则ORACLE就自动为该表建立一个唯一索引。

 

§3.3.1  创建主键

要想为表的某个列建立主键,可以用Alter table 或 CREATE TABLE 命令完成。

 

1在建表结构中创建主键

 

CREATE TABLE[schema.]table_name  …

   [SCOPE IS[user.]scope_table_name][column_constraint]…

. . .  . . .

 

例1:

 

CREATE TABLE dept

  (deptno number(2),

dname  varchar2(20),

loc         varchar2(20),

CONSTRAINT pk_deptPRIMARY KEY (deptno)

);

 

 

2  用alter table 创建主键

 

ALTER TABLE[schema.]tablename

ADD (constraint_name PRIMARY KEY (column1 [,column2,...])

 

 

例2:

 

ALTER TABLEPARK_REVENUE

 ADD(park_rev_pk  PRIMARY KEY ( ACCOUNT_NO));

 

 

例3:

create table  dept

(deptno  number(5) primary key,

dname    varchar2(20),

loc      varchar2(30))

disable  primary key;

 

注:当主键被说明为 disable primary key 时,不能建立相应的外部键。一定先用:

altertable dept enable primary key 后方可使用:

 deptno  constraint  fk_deptnoReferences  dept(deptno)

 

 

3唯一索引和主键区别

 

唯一索引:唯一索引使用CREATE UNIQUE INDEX命令完成,能标识数据库表中一行的关键字。在数据字典中建立了唯一索引名字。

主   键:主键使用primary  key来指定,能标识数据库表中一行的关键字。在数据字典中也建立了唯一索引名字。

差   别:被定义为唯一索引的列可以空,而被定义为主键的列不能空。

 

 

4建立索引、主键的方法:

 

在建表命令中用Constraint说明详见《oracle8i  sever SQL Reference》或者  Help  constraint得到语法说明。

 

  Create  table   dept

       (deptno  number(2),

         dname  varchar2(40)  constraint  unq_dname unique,

         loc   varchar2(50)

       );

 

constraint  unq_dname unique可以允许dname没有值,这样未指定空间分配参数的语句,oracle 采用缺省参数为 unq_dname 分配空间.

 

同样可以用下面命令达到如上的效果:

 

   Create  table   dept

        (deptno   number(2),

         dname    varchar2(20),

         loc      varchar2(20),

         constraint  unq_dname   unique(dnam)

            using  index  pctfree   20

            tablespace   users_x

        STORAGE(initial  8K  next   6k)

       );

 

constraint  unq_dname unique可以允许dname没有值,并指定空间分配参数的语句,oracle将根据参数为 unq_dname 分配空间.

 

 

   Create  table   dept

         (dept  number(2)  constraint  pk_dept primary  key,

          dname varchar2(20),

          loc   varchar2(20)

         );

 

   同样可以用下面命令完成上面的说明:

   Create  table   dept

         (deptno   number(2),

          dname    varchar2(20),

          loc      varchar2(20),

          constraint   pk_dept  primary   key (deptno)

         );

 

建立完表结构后再建索引、主键:

优点:索引可以放在另一表空间中,如果在表中直接写,则必须用using index  说明分配大小、表空间等。

   Alter  table   ship_cont

     Add primary  key(ship_no,container_no)   Disable

 

 

一般声明主键时,可以让其有效(缺省),也可以使其无效(Disable)

 

建议:在程序开发调试中,经常先将主键设为Disable,上面的ship_no,container_no一起组成主键,这种两个以上的字段组成的叫组合键(最多16个字段),不要指定过多的组合键以避免出现性能下降.

 

 

§3.3.2  改变主键

 

命令语法详见 altertable 命令

 

限制: 不许修改作为主键的列;

       不许修改作为主键的名字

可以: 可以定义一主键;或使主键无效

 

 

ALTER TABLE[schema.]tablename

DISABLEconstraint_name

 

例1:

   Alter  table   dept

       Disable scott.pk_dept;

 

这样,如果有一外部键依赖于该主键,则系统给出下列错误:

 

 ORA-02297: Cannot disable constraint (scott.pk_dept)-

Depentencies exist.

 

在这种情况下,必须先删掉依赖于该主键的外部键并使该外部键无效,然后查才能使主键无效。

 

§3.3.3  删除主键

 

ALTER TABLE[schema.]tablename

DROP CONSTRAINTconstraint_name [CASCADE]

 

删除顺序:

1) 使该外部键无效,删掉依赖于该主键的外部键;

2) 使该主键无效,删掉该主键

或:

当在删掉主键命令后加参数CASCADE , 则在删掉主键的同时把依赖于该主键的外部键一起删掉。

 

DROP INDEX  index_name ;

 

 

§3.4  外部键

建立外部键是保证完整性约束的一种唯一方法,也是关系数据库的精髓所在。许多曾使用过桌面数据库(如Dbase, Foxpro )的软件人员不太习惯或不使用关系数据库的主键与外部键的方法来设计自己的数据库结构,这是很不好的方法。应该在使用关系数据库中将习惯改过来。否则设计的应用结构和效率就不可能达到用户的要求。

§3.4.1  建立外部键

外部键的建立与主键的建立类似,都可以在 CREATE TABLE命令或ALTER TABLE命令中来说明,详细语法见《Oracle SQL reference 》Create table 命令9和Altertable 命令。

 

1.在 CREATE TABLE 命令语句中建立外部键

 

2.用 ALTER TABLE 命令语句建立外部键

 

ALTER TABLE [schema.]table_name

ADD ( CONSTRAINT_NAME FOREIGN KEY (Column1 [,column2,. . .])

REFERENCES [schema.]table_name (Column1 [,column2,. . .]);

 

CREATE TABLE dept

(deptno NUMBER(2),

dname VARCHAR2(9),

loc VARCHAR2(10),

CONSTRAINT pk_dept PRIMARY KEY (deptno) );

 

 

   Create  table   emp

   (  empno      number(4),

       ename      varchar2(10),

       job        varchar2(10),

       mgr        number(4),

       hiredate   date,

       sal        number(7,2),

       comm       number(7,2),

       deptno     constraint fk_deptno References  dept(deptno)

);

 

同样下面语句的效果与上面一样:

     Create  table   emp

       ( empno         number(4),

          ename         varchar2(10),

          job           varchar2(10),

          mgr           number(4),

          hiredate      date,

          sal           number(7,2),

         comm          number(7,2),

          deptno,

               constraint    fk_deptno

               Foreign   key(deptno)  References   dept(deptno)

      );

 

 

使用Delete   cascade管理引用完整性

 

Create   table  emp

       (  empno         number(4),

           ename         varchar2(10),

           job           varchar2(10),

           mgr           number(4),

           hiredate      date,

           sal           number(7,2),

           comm          number(7,2),

           deptno        number(2)  constraint fk_deptno

                         References   dept(deptno)

                         On   Delete  CASCADE

      );

 

 

常用组合键的完整性约束:

      Alter  table   phone_calls

        ADD  constraint   fk_areaco_phoneno

                  Foreign   key(areaco,phoneno)

                  References   austomers(areano,phoneno)

                  Exceptions   into  wrong_numbers

 

     Create  table   TROUBLE

     (     City               varchar2(10),

            Sampledate         date,

            Noon               number(4,1),

            Midnight           number(4,1),

            Precipitation      number,

            Constraint   TROUBLE.PK   PRIMARY   KEY(city,Sampledate)

     );

 

§3.4.2  修改外部键

由于ORACLE不允许改变已被定义的外部键的列,也不允许改变外部键的名字,所以你只能用ALTER  TABLE 定义一个新的外部键或者使一个已存在的外部键无效:

 

ALTER TABLE[schema.]table_name

DISABLECONSTRAINT_NAME;

 

§3.4.3  删除外部键

要删除已定义的外部键,要用Alter table 命令中的 DROP 关键字来实现,命令语法见Alter table 命令。

 

ALTER TABLE [schema.]table_name

DROP CONSTRAINTconstraint_name;

 

提示:关系数据库的核心主要体现在主键和外部键上。在进行数据库结构设计时,建议要采用主键和外部键来定义那些有关系的表。这样可以保证应用系统数据的完整性和一致性。

 

§3.5   索引

索引是关系数据库中用于存放每一条记录的一种对象,主要目的是加快数据的读取速度和完整性检查。建立索引是一项技术性要求高的工作。一般在数据库设计阶段的与数据库结构一道考虑。应用系统的性能直接与索引的合理直接有关。下面给出建立索引的方法和要点。

§3.5.1  建立索引

1. CREATE INDEX命令语法:

 

CREATE INDEX

CREATE [unique]INDEX [user.]index

ON [user.]table(column [ASC | DESC] [,column

[ASC | DESC] ] ... )

[CLUSTER[scheam.]cluster]

[INITRANS n]

[MAXTRANS n]

[PCTFREE n]

[STORAGE storage]

[TABLESPACEtablespace]

[NO SORT]

Advanced

 

其中:

   schema    ORACLE模式,缺省即为当前帐户

   index     索引名

   table     创建索引的基表名

   column    基表中的列名,一个索引最多有16列,long列、long raw

              列不能建索引列

   DESC、ASC  缺省为ASC即升序排序

   CLUSTER   指定一个聚簇(Hash  cluster不能建索引)

   INITRANS、MAXTRANS   指定初始和最大事务入口数

   Tablespace   表空间名

   STORAGE      存储参数,同create table 中的storage.

   PCTFREE       索引数据块空闲空间的百分比(不能指定pctused)

   NOSORT       不(能)排序(存储时就已按升序,所以指出不再排序)

 

 

2.建立索引的目的:

 

建立索引的目的是:

l 提高对表的查询速度;

l 对表有关列的取值进行检查。

 

但是,对表进行insert,update,delete处理时,由于要表的存放位置记录到索引项中而会降低一些速度。

注意:一个基表不能建太多的索引;

      空值不能被索引

      只有唯一索引才真正提高速度,一般的索引只能提高30%左右。

 

   Create index  ename_in  on  emp  (ename,sal);

 

例1:商场的商品库表结构如下,我们为该表的商品代码建立一唯一索引,使得在前台POS收款时提高查询速度。

Create  table good(good_id    number(8)  not null,/* 商品条码 */

                   Good_desc   varchar2(40),  /* 商品描述 */

                   Unit_cost   number(10,2)   /* 单价 */

                   Good_unit   varchar2(6),   /* 单位 */

                   Unit_pric   number(10,2)   /* 零售价 */

                   );

 

注:提高查询速度的方法还有在表上建立主键,主键与唯一索引的差别

在于唯一索引可以空,主键为非空,比如:

 

Create  table good(good_id  number(8)primary  key,

                    Good_desc   Varchar2(40),

                    Unit_cost   number(10,2),

                    Good_unit   char(6),

                    Unit_pric   number(10,2)

                   );

 

§3.5.2  修改索引

对于较早的Oracle版本,修改索引的主要任务是修改已存在索引的存储参数适应增长的需要或者重新建立索引。而Oracle8I及以后的版本,可以对无用的空间进行合并。这些的工作主要是由管理员来完成。

 

简要语法结构如下,更详细的语法图见电子文档《Oracle8i Reference 》 中的 Alter index.

 

ALTER [UNIQUE] INDEX[user.]index

[INITRANS n]

[MAXTRANS n] 

REBUILD

[STORAGE n]

 

其中:

REBUILD 是 根据原来的索引结构重新建立索引,实际是删除原来的索引后再重新建立。

 

提示:DBA经常用 REBUILD 来重建索引可以减少硬盘碎片和提高应用系统的性能。

 

例:

alter index pk_detnorebuild storage(initial  1m next 512k);

 

ALTER INDEX emp_ixREBUILD REVERSE;

 

 

Oracle8i  的新功能可以对索引的无用空间进行合并,它由下面命令完成:

 

ALTER INDEX . . . COALESCE;

 

例如:

 

ALTER INDEX   ename_idx  COALESCE;

 

§3.5.3  删除索引

当不需要时可以将索引删除以释放出硬盘空间。命令如下:

 

DROP INDEX[schema.]indexname

 

例如:

 

sql> drop indexpk_dept;

 

注:当表结构被删除时,有其相关的所有索引也随之被删除。

 

§3.6  新索引类型

Oracle8i为了性能优化而提供新的创建新类型的索引。这些新索引在下面介绍:

 

§3.6.1  基于函数的索引

基于函数的索引就是存储预先计算好的函数或表达式值的索引。这些表达式可以是算术运算表达式、SQL或PL/SQL函数、C调用等。值得注意的是,一般用户要创建函数索引,必须具有GLOBAL QUERY REWRITE和CREATE ANY INDEX权限。否则不能创建函数索引,看下面例子:

 

例1:为EMP表的ename 列建立大写转换函数的索引idx :

 

CREATE INDEX idx ON emp ( UPPER(ename));

 

这样就可以在查询语句来使用:

 

SELECT  * FROM EMPWHERE UPPER(ename)  LIKE ‘JOH%’;

 

例2:为emp的工资和奖金之和建立索引:

1) 查看emp 的表结构:

SQL> desc emp

 Name                         Null?    Type

 ------------------------------------------------- ------------------

 EMPNO                      NOT NULL NUMBER(4)

 ENAME                                VARCHAR2(10)

 JOB                                    VARCHAR2(9)

 MGR                                   NUMBER(4)

 HIREDATE                              DATE

 SAL                                   NUMBER(7,2)

 COMM                                 NUMBER(7,2)

 DEPTNO                               NUMBER(2)

 

2)没有授权就创建函数索引的提示:

 

SQL> createindex sal_comm on emp ( (sal+comm)*12, sal,comm)

  2 tablespace users storage(initial 64k next 64k pctincrease 0);

create indexsal_comm on emp ( (sal+comm)*12, sal,comm)

                                          *

ERROR at line 1:

ORA-01031:insufficient privileges

 

3) 连接到DBA帐户并授权:

 

SQL> connectsys/sys@ora816

Connected.

SQL> grantGLOBAL QUERY REWRITE to scott;

 

Grant succeeded.

 

SQL> grantCREATE ANY INDEX to scott;

 

Grant succeeded.

 

 

4)在连接到scott帐户,创建基于函数的索引:

 

SQL> connectscott/tiger@ora816

Connected.

SQL> createindex sal_comm on emp ( (sal+comm)*12, sal,comm)

  2 tablespace users storage(initial 64k next 64k pctincrease 0);

 

Index created.

 

1)在查询中使用函数索引:

 

SQL> selectename,sal,comm from emp where (sal+comm)*12 >5000;

 

ENAME             SAL       COMM

-------------------------------------- ----------------

ALLEN            1600        300

WARD             1250        500

MARTIN           1250       1400

TURNER           1500          0

    赵元杰           1234.5      54321

 

§3.6.2  反向键索引

反向键索引通过反向键保持索引的所有叶子键上的插入分布。有时,可用反向键索引来避免不平衡的索引。对于反向键索引可以进行下面操作:

l 通过在ALTERINDEX命令后加REBUILD NOREVERSE或REBUILDREVERSE子句来使索引边为反向键索引或普通索引;

l 采用范围扫描的查询不能使用反向键索引;

l 位图索引不能反向;

l 索引编排表不能反向。

 

例1:创建一个反向键索引:

CREATE INDEX i ON t (a,b,c) REVERSE;

 

例2:使一个索引变为反向键索引:

ALTER INDEX i REBUILD NOREVERSE;

 

 

§3.6.3  索引组织表

与普通的索引不一样,索引组织表(Index_Organized Table)是根据表来存储数据,即将索引和表存储在一起。这样的索引结构表(Index_organizedtable—IOT)的特点是:对表数据的改变,如插入一新行、删除某行都引起索引的更新。

索引组织表就象带一个或多个列所有的普通表一样,但索引组织表在B-树索引结构的叶节点上存储行数据。通过在索引结构中存储数据,索引组织表减少了总的存储量,此外,索引组织表也改善访问性能。

由于表中的行与B_树索引存放在一起,每个行都没有ROWID,而是用主键来标识。但是Oracle会“猜”这些行的位置并为每个行分配逻辑的ROWID。此外,你可以为这样的表建立第二个索引。

 

创建索引结构表也是用CREATE TABLE  命令加ORGANIZATIONINDEX关键字来实现。但是,这样的表在创建完后,你还必须为该表建立一个主键。

 

例子:

CREATE TABLE IOT_EXPAMPLE

(

Pk_col1 number(4),

Pk_col2  varchar2(10),

Non_pk_col1 varchar2(40),

Non_pk_col2 date,

CONSTRAINT pk_iot  PRIMARY KEY

                ( pk_col1, pk_col2)

)

ORGANIZATION INDEX

TABLESPACE INDEX

STORAGE( INITIAL 1M   NEXT 512K   PCTINCREASE 0 );

 

 

 

索引组织表有些限制:

l  不能使用唯一约束;

l  必须具有一个主键;

l  不能建立簇;

l  不能包含LONG类型列;

l  不支持分布和复制。

提示:如果建立了索引组织表,则会在DBA_TABLES中的IOT_TYPE和IOT_NAME列上记录有索引组织表的信息。

 

例1.修改索引结构表 docindex 的索引段的INITRANS参数:

 

ALTER TABLE docindex INITRANS 4;

 

例2.下面语句加一个的溢出数据段到索引组织表 docindex中:

 

ALTER TABLE docindex ADD OVERFLOW;

 

例3.下面语句为索引组织表 docindex的溢出数据段修改INITRANS参数:

 

ALTER TABLE docindex OVERFLOW INITRANS 4;

 

 

§3.7  抽象数据类型的使用

Oracle 提供了一种新的类型结构,叫做抽象数据类型。用于定义许多复杂的对象。

 

1.创建抽象类型的命令语法:

 

CREATE OR REPLACETYPE [schema.]type_name [IS|AS] OBJECT ( element_list );

 

详细命令语法见《ORACLE8i SQL REFERENCE》

 

2.例子:

 

例:为地址建立一个抽象数据类型 add_type

 

create type add_typeas object

(

 street varchar2(10),--街道名

 city   varchar2(20), -- 城市名

 state  char(2),      --州代码

 zip    number --邮编

);

 

 

在建立表时使用add_type 数据类型

 

create tablecustomer

(

 name varchar2(20),

 address add_type

);

 

向具有抽象数据类型的表插入数据

insert  into customer  values

(‘1’,add_type('mystaree','some city','st',10001));

 

 

§3.8  大数据类型的使用

 

除了 long 能在一行上存储多达2GB的字符和long raw 能存储多达2GB的二进制数据外,ORACLE还提供四种大的数据类型来完善大数据的存储。

 

§3.8.1  可用数据类型

下表列出在ORACLE8中可用的数据类型:

 

LOB数据类型

描述

BLOB

二进制LOB,最多为4GB

CLOB

字符LOB, 最多为4GB

BFILE

二进制文件,存储在数据库之外的只读二进制文件,大小与OS有关

NCLOB

支持多字符集(Multibyte Characters)的CLOB列

 

 

与LONG数据类型不同,在一个表内可以建立多个 LOB列,如:

 

Create tableproposal

(

proposal         number(10) promary key,

recipient_name   varchar2(25),

proposal_name    varchar2(25),

short_description  varchar2(1000),

proposal_text      clob, /* 提议内容 */

budget             blob, /* 预算电子数据报表 */

cover_letter       bfile /* 与提议有关的封面函件 */

);

 

§3.8.2  为LOB数据类型指定存储

由于LOB占用空间较大,所以应该为LOB所在的表制定存储空间。如:

 

Create tableproposal

(

proposal     number(10) promary key,

recipient_name   varchar2(25),

proposal_name    varchar2(25),

short_description  varchar2(1000),

proposal_text      clob, /* 提议内容 */

budget             blob, /* 预算电子数据报表 */

cover_letter       bfile /* 与提议有关的封面函件 */

)

storage( initial1m  next 500k  pctincrease 0 )

tablespacePROPOSALS;

 

上面例子是将整个表存储在一个表空间中,为了达到高效目的,可以将LOB列存储在另外的表空间中,如:

 

Create tableproposal

(

proposal     number(10) promary key,

recipient_name   varchar2(25),

proposal_name    varchar2(25),

short_description  varchar2(1000),

proposal_text      clob, /* 提议内容 */

budget             blob, /* 预算电子数据报表 */

cover_letter       bfile /* 与提议有关的封面函件 */

)

storage( initial1m  next 500k  pctincrease 0 )

tablespace PROPOSALS

LOB(proposal_text,budget) STORE AS

( TABLESPACEproposal_lobs

   STORAGE( initial 2m  next 1m pctincrease 0 )

   CHUNK 16k PCTVERSION 10  NOCACHE  LOGGING

);

 

其中:

LOB(proposal_text,budget) STORE AS  是将 LOB列出并指定存储在proposal_lobs中。

CHUNK  16k    指出分配给LOB的空间,它的取值范围最小为1k;最大为32k。

PCTVERSION 10  创建新版本的百分比。缺省时老版本的数据不被覆盖,直到有10%的可用LOB存储空间被使用。

NOCACHE   在读、写操作中数据不被存储在内存中,否则为 CACHE。

LOGGING   对于LOB的所有操作都被记录在重做日志文件(REDO)中,否则为 NOLOGGING。

 

§3.8.3  操作和检索LOB数据

可以有多种方法来检索和操作LOB数据,主要有:

1)通过DBMS_LOB包;

2)使用API(ApplicationProgramming Interfaces);

3)OCI(Oracle Call Interfaces)。

 

1.初始化值:

对于每个表中的LOB列,ORACLE都有一个定位器(Locator Value)来告诉数据库在哪里可以找到对于每个记录任意分开存储的数据。当在包括LOB的表插入一个记录时,可以使用DBMS_LOB包来告诉Oracle 对于内部存储的LOB列,生成一个空的定位器值。

例如我们要向PROPOSAL表插入一个记录,但还没有Budget 电子表格和信函封面,则可以使用下面命令:

 

Insert into proposal

( proposal_id,recipient_name,proposal_name,short_description,

proposal_text,budget, cover_letter )

values(1,’DOT PHILLIPS’,’CLEAR PHILLIPS FIELD’,NULL,

‘This is the text of a proposal to clear Phillipsfield.’,

EMPTY_BLOB(), NULL);

 

为了将budget 设置为一个空的定位器值,使用了EMPTY_BLOB函数,如果希望将CLOB数据类型设置为一个空的定位器,则可使用EMPTY_CLOB函数。由于cover_letter 是一个外部存储的BFILE值,所以设置为NULL。

 

BLOB 数据类型 --- EMPTY_BLOB()

CLOB 数据类型 --- EMPTY_CLOB()

NCLOB数据类型 --- EMPTY_CLOB()

 

可以使用BFILENAME来指向目录和文件(需要有 DBA角色或 CREATE DIRECTORY 权限)。为了创建一个目录,要使用Create directory命令。如:

 

Create directory ‘proposal_dir’ for ‘/u01/proposal/letters’;

 

当插入数据项时可以使用proposal_dir 逻辑目录(而不使用/u01/proposal/letters)。

现在可以向 proposal表输入第二条带有cover_letter的记录:

 

Insert into proposal

( proposal_id,recipient_name,proposal_name,short_description,

proposal_text,budget, cover_letter )

values(2,’BRAD OHMONT’,’REBUILD FENCE’,NULL,

EMPTY_CLOB(),EMPTY_BLOB(),

BFILENAME(‘proposal_dir’,’P2.DOC’) );

 

 

2.带子查询的数据插入

 

与LONG类型不一样,LOB数据类型可以使用 select 语句来进行数据的插入。如:

 

Insert into proposal

( proposal_id,recipient_name,proposal_name,short_description,

proposal_text,budget, cover_letter )

select 3,’SKIP GATES’,’CLEAR GATES FIELD’,NULL,

proposal_text,buaget,cover_letter

from proposal

where proposal_id =1;

 

3.更新LOB值

 

update proposal

   set proposal_text=’Thisis the new proposal text.’

Where proposal_id=3;

 

Update proposal

  Set cover_letter=BFILENAME(‘proposal_dir’,’P3.DOC’)

Where proposal_id =3;

 

4.使用DBMS_LOB来操作LOB值

 

可以用DBMS_LOB来改变或检索LOB列值。在DBMS_LOB包中可以使用下面过程或函数来对LOB进行操作:

 

过程或函数

描述

READ

用来读入一个LOB值的过程

SUBSTR

用来在LOB值上执行SQL语句的SUBSTR函数

INSTR

用来在LOB值上执行SQL语句的INSTR函数

GETLENGTH

用来在LOB值上执行SQL语句的GETLENGTH函数

COMPARE

比较两个LOB值的函数

WRITE

用于将一个LOB值的指定点写入数据到表的LOB列值中

APPEND

用来将LOB值添加到表的LOB中(追加在后面)

ERASE

用来删除所有的LOB值

TRIM

用来在一个LOB值中执行TRIM(裁剪)函数

COPY

用来将一个LOB值从一个列拷贝到另一个LOB列

 

 

BFILE使用的附加函数:

在使用BFILE类型时还要另外一些附加的函数。并且要在INITsid.ora 参数文件中修改:

SESSION_MAX_OPEN_FILES  xxx

缺省时,只允许打开10个BFILE文件。

 

BFILE用的函数和过程如下:

 

过程或函数

描述

FILEOPEN

用于打开所需读入的文件的过程

FILECLOSE

用于关闭所需读入的文件的过程

FILECLOSEALL

用于关闭所有打开的文件的过程

FILEEXISTS

用来确认所打开的文件是否存在的函数

FILEGETNAME

用来得到一个BFILE定位器值所引用的外部文件名的过程

FILEISOPEN

用来确认一个外部文件是否已打开

 

 

用DBMS_LOB包来读入 LOB的PL/SQL例子:

先看PL/SQL读入LOB的结构:

 

declare

     locator value 变量;

     amount        总字节变量;

offset        偏移量变量;

output       输出变量;

begin

set  amount :=…;

set offset := . . .;

select  locator_value into locator from table;

DBMS_LOB.READ(locator_value,amount,offset,output );

DBMS_OUTPUT.PUT_LINE(‘output:’||output );

end;

 

例子:

declare

locator_var  CLOB;

amount_var  integter;

offset_var  integer;

output_var  varchar2(10);

begin

amunt_var :=10;

offset_var := 1;

select proposal_textinto locator_var  from PROPOSAL

where proposal_id=1;

DBMS_LOB.READ(locator_var,amount_var,offset_var,output_var);

DBMS_OUTPUT.PUT_LINE(‘Start of proposal text:’||output_var);

End;

/

 

 

§3.9  表和索引有关的数据字典

当我们创建了表、主键、外部键和索引后,相关的信息就被记录到Oracle的数据字典中,应用系统设计人员、程序人员和数据库管理员,应该了解有关数据字典的基本查询方法.下面给出表和索引有关的数据字典的简单介绍,更详细的内容请参考《Oracle8i/9I数据库管理》。

§3.9.1  表和索引数据字典

l DBA_TABLES,ALL_TABLES,USER_TABLES存放表的基本信息,主要包括创建表结构时描述的信息,如表名,表空间,存储参数等;此外,还有一些信息是在分析表时由系统自动写进去的,比如,表的行数量、行平均字节等。

l DBA_INDEXES,ALL_INDEXES,USER_INDEXES存放索引的基本信息,主要包括创建索引时描述的信息和用ANALYZE分析索引由系统自动写进去的信息。

l DBA_IND_COLUMNS  存放有索引的列的信息,因为Oracle在分析创建索引的命令正确后就将表名、索引名等存放到DBA_INDEXES数据字典中,而将索引的列名存放到DBA_IND_COLUMNS数据字典中。所以,查询者需要了解两个数据字典才能查到索引的详细信息。

l ALL_CONSTRAINTS 存放表的限制信息。

l ALL_CONS_COLUMNS 存放表的列的限制信息。

 

§3.9.2  数据字典查询例子

了解数据字典的目的就是查询有关表和索引的信息,下面是简单的查询例子。

 

例1.查询当前用户的表的基本信息,包括表名、存放的表空间、存储参数:

 

SQL> selecttable_name ,tablespace_name,initial_extent,next_extent

 2* from user_tables

SQL>

 

TABLE_NAME         TABLESPACE_NAME    INITIAL_EXTENT NEXT_EXTENT

------------------------------------ -------------- -----------

ACCESS$            SYSTEM                      16384      106496

AQ$_MESSAGE_TYPES  SYSTEM                      65536       65536

AQ$_PENDING_MESSAGESSYSTEM                      65536       65536

.  . .   .  .  .

 

例2.查询当前用户的索引的基本信息,包括表名、索引名及表空间、存储参数:

 

 

SQL> selectindex_name,tablespace_name,initial_extent,next_extent

  2  fromall_indexes where owner=user;

 

INDEX_NAME                     TABLESPACE_NAME    INITIAL_EXTENT NEXT_EXTENT

------------------------------------------------ -------------- -----------

AQ$_MSGTYPES_PRIMARY           SYSTEM                      65536       65536

AQ$_PROPAGATION_STATUS_PRIMARYSYSTEM                      65536       65536

AQ$_QTABLE_AFFINITIES_PK       SYSTEM                      65536      65536

AQ$_QUEUE_STATITICS_PK         SYSTEM                      65536       65536

AQ$_SCHEDULES_PRIMARY          SYSTEM                      65536       65536

ASSOC1                         SYSTEM                      16384       16384

ASSOC2                         SYSTEM                      16384       16384

 

.  . .    .  .  .

 

这里的whereowner=user 表示只查当前用户的索引.

 

 

 

 

 

例3.查询当前用户的索引及索引的列名:

 

SQL> colcolumn_name for a40

SQL> colindex_name for a18

SQL> selectindex_name,table_name,column_name from all_ind_columns

  2* where table_owner=user;

 

INDEX_NAME         TABLE_NAME         COLUMN_NAME

------------------------------------ -----------------------------

I_ACCESS1          ACCESS$            D_OBJ#

I_ACCESS1          ACCESS$            ORDER#

AQ$_MSGTYPES_PRIMARYAQ$_MESSAGE_TYPES  QUEUE_OID

.  . .    .  .  .

 

 

例4.查询当前用户的限制信息,当我们创建表结构时,如果描述了限制,则这些限制就被存放到DBA_CONSTRAINTS数据字典中,看下面例子:

 

创建下面表结构:

     Create  table    worker

     (     empno        number(4)    primary  key,

            name         varchar2(10),

            age          number(2)   CHECK(age  between  18   and  65 ),

            /* age          number(2)   CHECK( age >=18 and age<=65 ) */

            lodging      char(15)    References    LODGING(lodging)

     );

 

查询数据字典信息可以得到:

 

SQL> selectowner,constraint_name,table_name from user_constraints;

 

OWNER                CONSTRAINT_NAME                TABLE_NAME

-------------------------------------------------- -----------------

ZHAO                 SYS_C001009                    WORKER

ZHAO                 SYS_C001010                    WORKER

 

SQL> set long1000

SQL> selectSEARCH_CONDITION  from user_constraints;

 

SEARCH_CONDITION

--------------------------------------------------------

age   between 18   and   65

 

 

 

 

 

 

例5.创建表结构时描述了限制,则这些限制就被存放到DBA_CONSTRAINTS数据字典中,再看下面例子:

 

 CREATE TABLE dept

     (deptno number(2),

   dname varchar2(20),

    loc        varchar2(20),

  CONSTRAINT pk_dept PRIMARY KEY (deptno)

   );

 

Create   table   empl

(

         Empno  number(5)   primary   key,

         Ename  varchar2(15)   not   null,

         Job    varchar2(10),

         Mgr    number(5),

         Hiredate   date  default   sysdate,

         Sal    number(7,2)   CHECK(sal>100),

         Comm   number(3)   default 0.0 ,

         Dept   number   constraint  

         dept_fkey    References   zhao.dept

);

 

SQL> colCONSTRAINT_NAME for a12

SQL> selectconstraint_name,table_name,SEARCH_CONDITION

  2* from user_constraints;

 

CONSTRAINT_NTABLE_NAME         SEARCH_CONDITION

------------------------------ -------------------------

PK_DEPT      DEPT

SYS_C001013  EMPL               "ENAME" IS NOT NULL

SYS_C001014  EMPL               sal>100

SYS_C001015  EMPL

DEPT_FKEY    EMPL

SYS_C001009  WORKER             age   between 18   and   65

SYS_C001010  WORKER

 

已选择7行。

 


 

第四章 视图、同义词和序列

视图、同义词和序列是Oracle的常用对象,在Oracle系统安装完成后,就已经建立许多Oracle系统所用的视图、同义词和序列。此外,在应用系统设计中,也经常需要创建视图、同义词和序列来满足应用的需要。下面给出简要介绍。

§4.1  视图

视图的一个主要目的就是简化用于查询所使用的语句,另外就是可以实现安全和保密的目的。利用视图,我们可以在查询处理中完成复杂的操作。

§4.1.1  使用视图来修改表中数据

可以用视图修改表中数据:

l 带有集合操作,如  intersect,union和minus的视图;

l 带有  groupby,connect by,或 start with子句的视图;

l 带有组合功能,如 avg , sum 或 max  功能的视图;

l 使用 distinct 功能的视图。

 

 

§4.1.2  创建一个新视图

1   建立视图命令语法:

 

CREATE [OR REPLACE][FORCE/NO FORCE] VIEW [schema.]view

[column_name1,column_name2] AS query

[WITH OBJECT OID |DEFAULT]

[WITH CHECK OPTION]

[CONSTRAINTconstraint]

[WITH READ ONLY]

 

OR REPLACE  替换掉原来的视图(不需删除)

FORCE       强行创建一视图,无论视图的基表是否存在或拥有者是

            否有权限,但作select、insert、update、delete前条件

            必须为真。

Schema      帐户、缺省为当前登录的帐户。

VIEW        视图名

Alias       视图的列名(唯一),缺省为列名

As   subquery  查询表达式(不含order  by, For update)

WITH   CHECK  OPTION   在视图上作insert,update时必须是视图,

                       查询所得到的结果,有子查询时可能不正确。

Constraint     约束名称,缺省为sys_Cn.   N为整数(唯一)。

 

注:视图只是一个逻辑表,它自己不包含任何数据,目的在于:

 

l 通过限制存取基表中预定的一组行或列,提供安全的附加功能;

l 隐藏数据的复杂性,例如,经常对几个表的数据作某种运算后查询

     时,可以使用视图使得操作仿佛是在单表上进行;

l 省去一些复杂的连接操作

 

==============================================================================

注意:下面情况在视图中受到限制:

 

视图查询不能选取Currval,nextval伪列;

只有加别名才能使用rowid,rownum,level

如果在子查询中使用 * 代替选择的表的所有列,则后来该表新加的列不会自动被加到视图中,只有重新创建视图后该新增的列才能被加到视图中;

如果视图建立(即查询)时包括任何以下结构之一,则该视图不能作insert,update,delete(目前的新版可以,需作特别的说明限制):

连接运算;

集合运算符;

组函数;

GROUP BY,CONNECTBY,START WITH

DISTINCT

 

==============================================================================

 

提示:不要在视图中再建视图,理论上虽可以对视图再建视图,但这样在查询时影响速度。

 

Create  view emp_vi  as  select *  from  emp;

 

例1:为表emp建立视图dept20,此视图可以显示部门20的雇员和他们

的年薪。

     Create view  dept10  As select  ename,deptno,job,sal*12  sal12

             From  emp where  deptno=10;

例2:

     Create view  clerk  (id_number, person, depart, position )

       As select  empno,ename,deptno,job

       From emp  where  job='clerk'

       With check  option  constraint wco;

 

用户不能往clerk视图中作insert(或update)非'clerk'的记录。

 

 

§4.1.3  删除一个视图

1.用命令删除视图

语法:

DROP VIEW [SCHEMA.]view_name;

 

drop view  view_data;

 

建议:一般视图不占用多少空间,可以不必删除。

 

2.用SchemaManager 删除视图

 

1)启动Schema Manager ,以DBA登录;

2)双击 View 文件夹,出现包含视图的模式列表;

3)双击包含要改变的视图的名字;

4)点击要被删除的视图名;

5)点红X;

6)在确定是否要删除中回答 Yes;

 

 

有关的数据字典user_views(dba_views,all_views) 视图:

 

Column      Datatype       NULL          说明

------------ ------------- ---------- ------------------

OWNER        VARCHAR2(30)   NOT NULL     视图创建者

VIEW_NAME    VARCHAR2(30)   NOT NULL     视图名

TEXT_LENGTH  NUMBER                       视图主体长度

TEXT         LONG                         视图内容

TYPE_TEXT_LENGTH  NUMBER                  类型文本长度

TYPE_TEXT         VARCHAR2(4000)          视图的类型

OID_TEXT_LENGTH   NUMBER                  OID 视图类型的长度

OID_TEXT          VARCHAR2(4000)          视图类型的OID

VIEW_TYPE_OWNER    VARCHAR2(30)           视图类型的所以者

VIEW_TYPE          VARCHAR2(30)           视图类型

 

§4.1.4  改变视图

当视图的状态不可用('INVALID')时,需要用ALTER VIEW . . . COMPILE 对视图进行编译。如:

 

 

SQL>ALTER VIEW SCHEMA.view COMPILE;

 

你可以用下面语句查询那些无效的视图,然后有针对性地进行编译:

SQL> SELECT OWNER,OBJECT_NAME,OBJECT_TYPE,STATUS FROM DBA_OBJECTS

WHERE object_type=’VIEW’ and STATUS='INVALID';

 

 

§4.2  实体视图(MATERIALIZED VIEW)

Oracle8i版本提供可以创建实体视图(MATERIALIZED VIEW),它确实存放有物理数据。实体视图包含定义视图的查询时所选择的基表中的行。在普通的视图中,Oracle在执行查询时临时进行查询操作来返回结果;而对实体视图的查询是直接从该视图中取出行。

在Oracle9i版本里,对实体视图进行了增强,如提供快速刷新等。下面简单介绍实体视图的使用。

§4.2.1  创建实体视图

1.关键内容:

 

使用实体视图需要了解下面几个关键点:

 

l 实体视图存放有物理数据;

l 实体视图背后的查询只在视图建立或刷新时执行,即如果创建后不进行刷新则只得到创建时的数据;

l 实体视图使用DBMS_MVIEW 程序包中含有刷新和管理实体视图的过程来进行管理;

l 在导出和导入(EXP、IMP)中使用MVDATA参数来实现实体视图数据的导出和导入;

l 使用CREATEMATERIALIZED VIEW 语句创建实体视图;

l 实体视图中的查询表叫主表(master tables)(复制项)或详细表(数据仓库项)。为一致起见,这些主表叫主数据库(master databases.);

l 为了复制目的,实体视图允许你在本地管理远程拷贝;

l 所复制的数据可以使用高级复制特性进行更新;

l 在复制环境下,通常创建的实体视图都是主键、ROWID和子查询实体视图。

 

2.创建实体视图前提:

 

l  要有授权创建实体视图的权限(CREATE MATERIALIZED VIEW 或CREATE SNAPSHOT);

l  必须有访问各个主表的权限,即 有SELECT ANY TABLE 的系统权限。

如果在另外的用户模式下创建实体视图,则:

l  需要有CREATE ANY MATERIALIZED VIEW或CREATE ANY SNAPSHOT、SELECTANY TABLE 权限;

l  必须有CREATETABLE、SELECT ANY TABLE系统权限。

 

如果带查询重写有效来创建实体视图,则:

 

l  主表的主人必须有QUERY REWRITE系统权限;

l  如果你不是主表主人,则必须有GLOBAL QUERY REWRITE系统权限;

l  如果模式主人没有主表,则该模式主人必须有GLOBAL QUERY REWRITE权限。

 

3.创建实体视图语法:

 

下面给出Oracle9i版本的实体视图的创建语法:

 

CREATE MATERIALIZEDVIEW   [schema.]  materializede_view 

[ OF [schema .]object_type ]| [(scoped_table_ref_constraint)] |

ORGANIZATION_INDEXindex_org_table_clause |

[

[

[[segment_attribute_cluase|column_properties ] | [CACHE|NOCACHE ] ] |

[ CLUSTER cluster(column,) ]

]|

[partitioning_clause|parllel_cluse|build_clause]|

[

ON PREBUILT TABLE [[WITH|WITHOUT] | REDUCED PRECISION ]

]|

[

[ USING INDEX[physical_attribute_clause |TABLESPACE tablespace] ] |

[ USING NO INDEX]

] refresh_cluse

[ [ FOR UPDATE ] | [ DISABLE | ENABLE ] QUERYREWRITE ] ]

AS subquery;

 

其中:

 

scoped_table_ref_constraint为:

SCOPE FOR ([ref_column|ref_attribute] ) IS [schema.] scpe_table_name

 

Index_org_table_clause为:

[(mapping_table_clause) | PCTTHRESHOLD integer | [COMPRESS integer|NOCOMPRESS] ]

[ INCLUDINGcolumn_name ] OVERFLOW [ segment_attribute_clause]

 

refresh_clause 为:

 

  [ NEVER REFRESH |

  [ REFRESH | [ USING [ DEFAULT [LOCAL | MASTER] ROLLBACK SEGMENT ] |

                      [LOCAL | MASTER] ROLLBACK SEGMENT ] rollback_segment ]

            | WITH [ PRIMARY KEY | ROWID ]

            | NEXT [ START WITH ] date

            | ON [ DEMAND | COMMIT ]

            | [ FAST | COMPLETE|FORCE ]

   ]

 

参数说明:

 

schema  模式名

materialized_view 实体视图名

segment_attributes_clause 建立PCTFREE、PCTUSED、INITRANS和MAXTRANS参数。

TABLESPACE  表空间

LOB_storage_clause 大对象存储参数

LOGGING | NOLOGGING 指定创建实体视图时是否需要建立日志

CACHE | NOCACHE   实体视图的数据是否被缓存

CLUSTER  cluster

partitioning_clauses 用于指定实体视图的分区范围或一个HASH函数。实体视图分区与表分区类似。

parallel_clause指定实体视图的并行操作和设置查询并行度。

build_clause   当移植实体视图时使用。

NOPARALLEL    指定顺序执行(缺省值),

PARALLEL      如果选择并行度时可指定并行。

THREADS_PER_CPU 初始参数

PARALLEL integer 指定并行度。

Build_clause 指定重建实体视图时的选项:

IMMEDIATE   指定为IMMEDIATE 表示实体视图是立即移植(缺省值)。

DEFERRED    指定为DEFERRED 表示实体视图是在下次刷新时移植。第一次延期总是一个完全的刷新。一直到被刷新为止该实体视图的值都是旧的值,所以它是不可查询重写的。

 

ON PREBUILTTABLE 此项可以使你以原初始化实体视图(preinitializedmaterialized view)来注册一个存在的表。这对于大表来说非常有用。它有下面限制:

l  每个列的别名必须与表的列名一样;

l  如果使用ONPREBULT TABLE,则不能对列再指定 NOT NULL。

 

WITH REDUCED PRECISION 允许指定表或实体视图精度可以丢失。实体视图的列不能与子查询所返回的精度一致。

 

WITHOUT REDUCED PRECISION 表示不允许指定表或实体视图精度可以丢失。实体视图的列要与子查询所返回的精度一致。这是缺省值。

 

USING INDEX 用此项可以为索引建立INITRANS、MAXTRANS及STORAGE参数。如果不指定本参数,则系统使用原索引。

 

限制:不能在USING INDEX字句里指定PCTUSEDPCTFREE参数。

 

refresh_clause   用于指定缺省方法、模式及Oracle刷新实体视图的次数。如果一个实体视图的主表被修改。则实体视图必须被更新才能反映当前的数据。这项可以实现指定时间表和刷新方法。

 

FAST 指定增量刷新方法,该刷新是根据主表的改变来进行。这种改变存储在任何一个实体视图的日志里或加载日志里。

即使还没有在主表下建立实体视图日志,也可以建立一个总和的实体视图。然而,如果你建立其它类型的实体视图时,CREATE 语句就会失败。除非实体视图日志已经存在。

如果在创建实体视图时存在适合的实体视图日志,Oracle将执行快速的刷新。

为了使DML改变和直接的加载都能有效,就要适当限制实体视图的刷新。

 

 

COMPLETE 指定刷新方法,如果指定了完全刷新,即使已经指定了快速刷新,Oracle也执行完全刷新。

 

FORCE 表示强行刷新。它是FAST、COMPLETE、FORCE三种刷新的缺省值。

 

 

4.创建实体例子:

 

例1.创建实体汇总视图:

 

下面语句建立一个移植的实体视图,并指定缺省的刷新方法、模式及时间:

 

CREATE MATERIALIZED VIEW mv1 REFRESH FAST ONCOMMIT

BUILD IMMEDIATE

AS SELECT t.month, p.prod_name, SUM(f.sales) ASsum_sales

FROM time t, product p, fact f

WHERE f.curDate = t.curDate AND f.item = p.item

GROUP BY t.month, p.prod_name;

 

例2.创建实体汇总视图:

下面语句建立和移植一个实体视图sales_by_month_by_state,这个实体视图根据数据语句一旦执行成功就进行移植。接着就完成实体视图的查询:

 

CREATE MATERIALIZED VIEW sales_by_month_by_state

TABLESPACE my_ts PARALLEL (10)

ENABLE QUERY REWRITE

BUILD IMMEDIATE

REFRESH COMPLETE

AS SELECT t.month, g.state, SUM(f.sales) ASsum_sales

FROM fact f, time t, geog g

WHERE f.cur_date = t.cur_date AND f.city_id =g.city_id

GROUP BY month, state;

 

 

例3.原实体视图(即视图的名字与原来表名一样):

 

下面语句为先前存在的总结表sales_sum_table  建立汇总视图 sales_sum_table:

 

CREATE TABLE sales_sum_table

(month DATE, state VARCHAR2(25), sales NUMBER);

 

CREATE MATERIALIZED VIEW sales_sum_table

ON PREBUILT TABLE

ENABLE QUERY REWRITE

AS SELECT t.month, g.state, SUM(f.sales) ASsum_sales

FROM fact f, time t, geog g

WHERE f.cur_date = t.cur_date AND f.city_id =g.city_id

GROUP BY month, state;

 

 

在这个例子中,实体视图与先前建立的实体表 有相同的名字、相同的列和数据类型。

 

例4.实体连接视图:

声明语句建立一个连接实体视图:

 

CREATE MATERIALIZED VIEW mjv

REFRESH FAST

AS SELECT l.rowid as l_rid, l.pk, l.ofk, l.c1,l.c2,

o.rowid as o_rid, o.pk, o.cfk, o.c1, o.c2,

c.rowid as c_rid, c.pd, c.c1, c.c2

FROM l, o, c

WHERE l.ofk = o.pk(+) AND o.ofk = c.pk(+);

 

 

例5.子查询实体视图:

 

下面语句创建一个基于Order和 Customers 表的视图:

 

CREATEMATERIALIZED VIEW sales.orders FOR UPDATE

ASSELECT * FROM [email protected] o

WHEREEXISTS

(SELECT* FROM [email protected] c

WHEREo.c_id = c.c_id);

 

 

例6.主键的实体视图:

 

下面语句创建一个主键实体视图human_genome:

 

CREATE MATERIALIZED VIEW human_genome

REFRESH FAST START WITHSYSDATE NEXT SYSDATE + 1/4096

WITH PRIMARY KEY

AS SELECT * FROM genome_catalog;

 

 

例7.ROWID实体视图:

下面语句创建一个ROWID实体视图emp_data:

 

CREATEMATERIALIZED VIEW emp_data REFRESH WITH ROWID

ASSELECT * FROM emp_table73;

 

 

例8.周期性刷新的实体视图:

下面语句创建一个主键实体视图emp_sf并根据在纽约的scott的职工表来移植数据:

 

CREATE MATERIALIZED VIEW emp_sf

PCTFREE 5 PCTUSED 60

TABLESPACE users

STORAGE (INITIAL 50K NEXT 50K)

REFRESH FAST NEXT sysdate + 7

AS SELECT * FROM scott.emp@ny;

 

此语句没有START WITH参数,所以Oracle使用SYSDATE来估计下次的自动刷新时间。Oracle执行首次刷新为7天后。

 

 

例9.自动刷新的实体视图:

下面语句创建一个复杂的实体视图all_emps,它查询DALLAS和BALTIMORE中的职工表:

 

CREATEMATERIALIZED VIEW all_emps

PCTFREE5 PCTUSED 60

TABLESPACEusers

STORAGEINITIAL 50K NEXT 50K

USINGINDEX STORAGE (INITIAL 25K NEXT 25K)

REFRESHSTART WITH ROUND(SYSDATE + 1) + 11/24

NEXTNEXT_DAY(TRUNC(SYSDATE, ’MONDAY’) )+15/24

ASSELECT * FROM fran.emp@dallas

UNION

SELECT* FROM marco.emp@balt;

 

Oracle在早上11点自动刷新,接着就在周一的3点进行刷新。缺省刷新方法是FORCE,all_emps视图包含一个UNION,它是不支持快速刷新的,所以Oracle只能用完全(complete)刷新。

上面语句同样为实体视图建立存储特性:

l 第一个存储参数建立初始大小为50KB,下次大小也为50KB.

l 第二个存储参数(使用USING INDEX)建立初始大小为25KB,下次大小也为25KB.

 

 

例10.自回滚段的实体视图:

 

下面语句在远程建立带master_seg 回滚段的主键实体视图sales_emp,并用本地回滚段snap_seg来刷新实体视图:

 

CREATEMATERIALIZED VIEW sales_emp

REFRESHFAST START WITH SYSDATE NEXT SYSDATE + 7

USINGMASTER ROLLBACK SEGMENT master_seg

LOCALROLLBACK SEGMENT snap_seg

ASSELECT * FROM bar;

 

 

§4.2.2  创建实体视图日志

1.创建实体视图日志的目的

 

使用CREATEMATERIALIZED VIEW LOG语句可以创建实体视图日志。实体视图日志是一个包含有主表和实体视图的表。这些快照(snapshot)和实体视图(materializedview)其实都是同义词。它们都引用一个或多个包含查询结果的表,这些表可以是本地数据库或远程数据库的表。

 

DML的改变是由主表的数据组成的,Oracle在实体视图日志里存储那些改变行的描述,然后使用实体视图日志去刷新基于主表的实体视图,这个过程叫快速刷新。如果没有实体视图日志,Oracle必须重新执行实体视图查询,这个过程叫完全刷新。通常快速刷新要比完全刷新用的时间少。

一般,实体视图日志与模式中的主表放在一起。你需要为每个主表建立实体视图日志。因为Oracle 要使用这个实体视图日志来进行快速刷新。

 

2.要求

 

l  如果你拥有主表,则可以建立实体视图日志。

l  如果你为其他人建立实体视图日志,则必须有CREATE ANY TABLE 和 COMMENT ANY TABLE权限。

 

3. CREATE MATERIALIZED VIEW LOG语法

 

( 创建实体视图日志命令语法 见《Oracle9i SQL Reference 》 )p982

 

 

4.实体视图日志例子

 

 

例1.主键的例子:

下面语句在雇员表上建立实体视图日志:

 

CREATE MATERIALIZED VIEW LOG ON emp WITH PRIMARYKEY;

 

例2.建立仅包含更新行主键的实体视图日志

 

Oracle可以用实体视图日志在任何简单主键的实体视图中来执行一个快速刷新。下面语句建立一个只包含更新行主键的实体视图日志:

 

CREATE MATERIALIZED VIEW LOG ON emp

PCTFREE 5

TABLESPACE users

STORAGE (INITIAL 10K NEXT 10K);

 

下面语句建立一个只包含更新行主键的实体视图日志:

 

CREATE MATERIALIZED VIEW LOG ON sales WITHROWID, PRIMARY KEY;

 

下面语句建立一个包含更新行主键和更新列ZIP的实体视图日志:

 

CREATE MATERIALIZED VIEW LOG ON address WITH(zip);

 

 

下面语句建立一个主表,然后建立一个带INCLUDING NEW VALUES的实体视图日志:

 

CREATE TABLE agg

(u NUMBER, a NUMBER, b NUMBER, c NUMBER, dNUMBER);

CREATE MATERIALIZED VIEW LOG ON agg

WITH ROWID (u,a,b,c,d)

INCLUDING NEW VALUES;

 

下面语句使用agg日志来建立实体视图:

 

CREATE MATERIALIZED VIEW sn0

REFRESH FAST ON COMMIT

AS SELECT SUM(b+c), COUNT(*), a, d, COUNT(b+c)

FROM agg

GROUP BY a,d;

 

§4.2.3  修改实体视图

1.修改实体视图目的

实体视图是Oracle的一个数据库对象。它包含有一个或多个表的查询结果。使用

 ALTER MATERIALIZED VIEW 可以对已经存在的实体视图进行修改。修改方法如下:

l  修改存储特性;

l  修改刷新方法、模式及时间

l  改变实体视图的结构以使它有不同类型;

l  使查询重写有效。

 

 

2.修改实体视图命令语法

 

ALTER MATERIALIZEDVIEW   [schema.]  materializede_view 

[

[physical_attributes_clause|

LOB_storage_clause[,...] |

Modify_LOB_storage_clause [,...]|

Partition_clause |

Parallel_clause |

[LOGGING|NOLOGGING] |

allocate_extent_clause |

[CACHE|NOCACHE ]

]|

[

alter_iot_cluse |

USING INDEXphysical_attribute_clause |

MODIFYscoped_table_ref_constraint |

REBUILD |

Refresh_cluse

]|

[

[ DISABLE | ENABLE ]QUERY REWRITE |

COMPILE |

CONSIDER FRESH

]

 

详细见《Oracle9iSQL Reference》p502

 

 

 

3.修改实体视图例子

 

例1:

CREATE MATERIALIZED VIEW hq_emp

REFRESH COMPLETE

START WTIH SYSDATE NEXT SYSDATE +1/4096

AS SELECT * FROM hq_emp;

 

ALTER MATERIALIZED VIEW hq_emp

REFRESH FAST;

 

例2:修改下次刷新:

 

ALTER MATERIALIZED VIEW branch_emp

REFRESH NEXT SYSDATE+7;

 

例3:修改完全刷新:

 

ALTER MATERIALIZED VIEW sf_emp

REFRESH COMPLETE

START WITH TRUNC(SYSDATE+1) + 9/24

NEXT SYSDATE+7;

 

例4:使查询重写有效:

 

ALTER MATERIALIZED VIEW mv1

ENABLE QUERY REWRITE;

 

例5:使用回滚段:

 

ALTER MATERIALIZED VIEW inventory

REFRESH USING MASTER ROLLBACK SEGMENTmaster_seg;

 

ALTER MATERIALIZED VIEW sales

REFRESH USING DEFAULT MASTER ROLLBACK SEGMENT;

 

例6:使用主键:

 

ALTER MATERIALIZED VIEW emp_rs

REFRESH WITH PRIMARY KEY;

 

例7:使用完全刷新:

 

ALTER MATERIALIZED VIEW store_mv COMPILE;

 

例8:修改刷新方法:

 

ALTER MATERIALIZED VIEW store_mv REFRESH FAST;

 

例9:修改考虑刷新(CONSIDER FRESH)方法:

 

ALTER MATERIALIZED VIEW mv1 CONSIDER FRESH;

 

§4.2.4  修改实体视图日志

ALTER MATERIALIZED VIEW LOG

1.修改实体视图日志目的

使用 ALTER MATERIALIZEDVIEW LOG 可以对已经存在的实体视图日志进行修改。可以修改存储特性、刷新模式、时间或已经存在实体视图日志的类型。

 

 

2.修改实体视图日志命令语法

 

( 创建实体视图日志命令语法 见《Oracle9iSQL Reference 》 )

 

3.修改实体视图日志命令例子

 

例1:修改扩展次数:

 

ALTER MATERIALIZED VIEW LOG ON dept

STORAGE MAXEXTENTS 50;

 

 

例2:修改已经存在的ROWID:

 

ALTER MATERIALIZED VIEW LOG ON sales

ADD PRIMARY KEY;

 

 

§4.2.5  实体视图完整例子

要在应用中使用实体视图,除了要实体视图的语句外,还需要进行数据库实例的初始化参数。并重新启动数据库实例才能使所写的实体视图有效。下面是操作步骤:

 

1.修改实例初始化参数initsid.ora 有关参数

 

与实体视图有关的参数与数据库作业一样,都是job_queue_processes和job_queue_interval 。第1个参数是队列的进程数,一般要设大于 0 ;第2个参数是刷新间隔秒数。Oracle9i可以是小于1000的整数。例如在initora817.ora初始化中将该二参数设置为:

 

job_queue_processes = 2

job_queue_interval = 5

 

2.关闭实例和重启动实例

 

在Oracle8i版本,可用svrmgrl服务器实用程序来关闭和启动数据库实例;在Oracle9i版本可用SQL>CONNECT AS SYSDBA实现关闭和启动数据库实例。

 

3.运行实体视图

 

CREATE MATERIALIZED VIEW emp_stat

TABLESPACE users

STORAGE (INITIAL 8K NEXT 5K)

 REFRESH FAST START WITHSYSDATE NEXT round(SYSDATE + 16/24)

 AS SELECT deptno,sum(sal)

from emp   group by deptno;

 

实体化视图已创建。

 

22:29:28 SQL> create materialized viewlog on emp pctfree 5 tablespace users;

 

实体化视图日志已创建。

 

SQL> select * from emp_stat;

 

   DEPTNO   SUM(SAL)

---------- ----------

       10      14116

       20      54537

       30       9400

 

SQL> altermaterialized view emp_stat

  2 refresh complete

  3 start with trunc(sysdate)+15/24 next sysdate+30/24*60*60;

 

实体化视图已更改。

 

SQL>

 

SQL> select * from emp_stat;

 

   DEPTNO   SUM(SAL)

---------- ----------

       10      14116

        20     64536

30                        9400

 

修改下次刷新时间为下午3点半(startwith trunc(sysdate)+15.5/24),则:

SQL> set time on

15:23:34 SQL>alter materialized view emp_stat

15:23:50   2 refresh complete

15:23:50   3 start with trunc(sysdate)+15.5/24 next sysdate+30/24*60*60;

 

实体化视图已更改。

现在虽然视图已更改,但由于没到时间。所以视图数据还是原来的旧数据:

15:27:05 SQL> /

 

   DEPTNO   SUM(SAL)

---------- ----------

       10      14116

       20      64536

       30       9400

 

15:27:07 SQL>

15:27:07 SQL>

由于时间到了3点刷新点,可查出新的统计结果:

15:30:06 SQL> /

 

   DEPTNO   SUM(SAL)

---------- ----------

        10     24115

       20      64536

       30       9400

 

15:30:09 SQL>

 

15:36:09 SQL> insert into emp values(555,'zhaojie','enginner',null,null,20000,5000,20);

 

已创建 1 行。

 

15:36:39 SQL> commit;

 

15:38:08 SQL> select * from emp_stat;

 

   DEPTNO   SUM(SAL)

---------- ----------

       10      24115

       20      64536

       30       9400

 

15:38:34 SQL>

 

每一小时一次next 表达式为 sysdate+1*60*60/24 *60* 60=next sysdate+1/24

每半小时一次 next sysdate + 30*60/60*60*24 = sysdate+1/48

15分钟一次 next sysdate+1/96

 

希望刷新是4点半,接着是15分一次:

 

alter materializedview emp_stat

refresh complete

start withtrunc(sysdate)+16.5/24 next sysdate+1/96;

 

16:10:49 SQL>alter materialized view emp_stat

16:13:29   2 refresh complete

16:13:29   3 start with trunc(sysdate)+16.5/24 next sysdate+1/96;

 

实体化视图已更改。

 

16:13:31 SQL>select * from emp_stat;

 

    DEPTNO  SUM(SAL)

---------- ----------

        10     24115

        20     64536

        30      9400

 

16:13:43 SQL>

 

16:30:20 SQL>/

 

    DEPTNO  SUM(SAL)

---------- ----------

        10     24115

        20     64536

        30     19399

 

16:30:27 SQL>

 

16:30:27 SQL>

16:31:03 SQL>  insert into empvalues(555,'zhaojie','enginner',null,null,20000,5000,20);

 

已创建 1 行。

 

16:32:04 SQL> commit;

 

提交完成。

 

16:32:15 SQL>

 

希望在16:45时重新刷新。得到新结果,在时间到后,视图自动刷新,deptno=20的总和已改变:

 

16:46:22 SQL> select * from emp_stat;

 

   DEPTNO   SUM(SAL)

---------- ----------

       10      24115

        20     84536

       30      19399

 

与实际表查出一样:

 

16:46:29 SQL> select deptno,sum(sal)from emp group by deptno;

 

   DEPTNO   SUM(SAL)

---------- ----------

       10      24115

        20     84536

       30      19399

 

4.停止实体视图的自动运行

 

 

 

§4.3  序号(sequence)

序号是一个发布唯一数字的ORACLE 对象,在需要时,每次按1或一定增量增加。序号通常用于产生表中的唯一主键或唯一索引等。

§4.3.1  建立序号

建立序号可以在SQL*PLUS 中用命令来完成,也可以使用SchemaManager 工具来完成。

 

1. 命令语法:

 

CREATE SEQUENCE[user.]sequence

[INCREMENT BY{1|integer}]

[START WITH integer]

[MAXVALUEinteger|NOMAXVALUE]

[MINVALUEinteger|NOMINVALUE]

[CYCLE|NOCYCLE]

[CACHE{20|integer}|NOCACHE]

[ORDER|NOORDER]

 

 

2. 建立序号

 

例1:建立Sequence

Create   sequence  emp_sequence

Increment     by 1

Start    with   1

No   maxvalue

No   cycle

Cache    10;

 

Create   sequence  order_seq

   Start  with   1

   Incremant   by   1

   Nomaxvalue

   Nocycle

   Cache  20;

 

§4.3.2  修改序号

 

3. 修改序号

有时需要对已建立的序号进行修改,比如在系统移植或升级时可能有的序号已经增长到某个值。现在需要从原先停止的地方开始等。

 

例2:修改sequence

Alter   sequence  emp_sequence

Increment    by  1

Maxvalue        10000

Cycle

Cache    20;

 

§4.3.3  使用序号

建立序号的目的就是使用序号,使用序号主要是在插入和查询时使用。

 

 

例3:使用sequence

     insert  into   orders(orderno,custno)

                values(order_seq.nextval,1032);

update   orders  set orderno-orderno=order_seq.nextval

           where orderno=10112;

每使用一次,nextval自动增1,currval是多次使用的值,如果一开始就

用,则其值为0,一般情况下是在nextval使用之后才能使用currval,可以用它来产生同样的号,比如有一定货号有多种商品和数量:

insert   into  line  items(orderno,partno,quantity)

           values(order_seq.currval,20231,3);

insert   into  line_items(orderno,partno,quantity)

          values(order_seq.currval,29374,1);

 

提示:在ORACLE8 中,如果在建立序列的语句中未加上NOCACHE,则有可能在关闭系统再启动后产生跳号现象。如果你的系统要求不许跳号,请在创建序列时在后面加 NOCACHE 。

 

§4.3.4  删除序号

当不再使用时就可以删除序号,删除序号有两种方法:

 

1.  DROP SEQUENCE [Schema.]seguence_name;

2.  使用 Schema Manager 工具;

 

§4.4  同义词

同义词可以使多个用户使用同一个对象而不用将模式(Schema )作为前缀加在对象的前面,从而简化授权方面的操作。同义词有公有和私有两种。

§4.4.1  建立同义词

要建立同义词,首先要有Create  any   synonym和drop   any  synonym权限方可建立和撤消,如果某个用户不能建立同义词,则应给其授该权限。

 

 

CRAETE [PUBLIC]SYNONYM [user.]synonym

FOR [user.]table[@database_link];

 

 

例1:

   Create  public   synonym   emp

         For  scott.emp@sales;

 

例2:为当前用户的所有对象建立公共同义词,可用下面各命令来完成创建一个脚本:

 

set echo off

set head off

set verify off

set linesize 200

set pages 0

set feedback off

set term on

undefine p_user

def p_user =&&p_user

Prompt GeneratingScript To Drop User

set term off

SPOOL  create_syn.sql

 

select 'drop publicsynonym '||object_name||' ;' from user_objects;

 

select ' createpublic synonym '||object_name||

 ' for sale.'||object_name||' ;' fromuser_objects;

 

SPOOL  OFF

 

Start  create_syn.sql

 

注意:当创建同义词后,还要将该同义词授权给public ,才能使其他的Oracle用户可以访问该同义词。

 

同义词数据字典:

DBA_SYNONYMS实例中所有同义词

USER_SYNONYMS(=SYN)用户的同义词

 

 

§4.4.2  删除同义词

DROP PUBLIC synonym[schema.]synonym ;

 

   Drop  synonym   emp;

 

例1:为当前所有对象建立同义词。为了省去编辑,可用下面个命令来完成:

* 需具有 dba, -- create any synonym,drop anysynonym 权限

 

select 'drop publicsynonym '||object_name||' ;' from user_objects;

 

 

select ' createpublic synonym '||object_name||

 ' for sale.'||object_name||' ;' fromuser_objects;

 

§4.5  视图、同义词和序列有关的数据字典

当我们创建了视图、同义词和序列后,相关的信息就被记录到Oracle的数据字典中,作为程序人员和数据库管理员,应该了解有关数据字典的基本查询方法.

 

与视图、同义词和序列有关的数据字典有:

 

l DBA_VIEWS –实例中所有的视图的基本信息;

l DBA_SYNONYMS–实例中所有的同义词;

l DBA_SEQUENCES–实例中所有的序列。

 

 


 

第五章 簇与分区

Oracle公司在Oracle7以后的版本提供了许多数据库厂商不能具备的分区和簇的存储管理技术。使用这些技术,可以实现将大的表和索引进行拆分,使得处理速度提高和便于管理。

§5.1  簇( cluster )

簇(Cluster)是一组表,如果应用程序中的SQL 语句经常联结两个或多个表,可以把这些表以簇方式进行创建以改善性能。只要我们创建了簇并在创建表时指定到已经创建好的簇中,ORACLE 就把簇中的表存储在相同的数据块中,并且各个表中的相同的列值只存储一个。

§5.1.0  簇概念

簇(Cluster)就是将一组有机联系的表在物理上存放在一起并且相同的关键列的值只存储一份,用于提高处理效率的一项技术。如下图所示( 见Oracle8i concept ):

 

 

 

 


1.何时建立簇

 

如果通过引用完整性把两个或多个表联系起来并经常使用联结,则为这些表创建一个索引簇。如果一个表的多行经常与一个非唯一的列一起查询,则为该列创建一个单表簇,该列作为簇关键字,以提高性能。

 

2.有时簇会损害性能

 

对频繁更新或删除的表使用簇对性能有不利的影响。

 

3.限制:

 

l 簇中的每个表必须有一列与簇中指定的列的 大小和类型匹配;

l 簇码中可用列的最大数目是16,即一个簇最多有16列作为簇码;

l 列的最大长度为239字节;

l LONG 和LONG RAW 不能作为簇列码。

§5.1.1  建立簇

1.创建簇语法

 

CREATE CLUSTER cluster

       ( columndatatype[,colmn datatype]…)

[PCTUSED 40|intger] [ PCTFREE 10| intger]

[ SIZE intger ]

[INITRANS 1|intger] [MAXTRANS 255|intger]

[TABLESPACE tablespace]

[STORAGE storage]

 

 

2.创建簇及其表的步骤:

 

1) 用 CREATE CLUSTER创建簇

2) 用CREATE INDEX创建簇索引

3) 用CREATE TABLE 创建表,并指定簇

4) 插入数据并进行DML 操作

 

 

例1: 住房公积金实例

 

/******************************************************************/

/*  创建单位信息和单位职工汇缴信息所用的簇emp_unit               */

/*  并为簇emp_unit 创建相应索引  unit_inf_ind                    */

/*  为创建单位信息和单位职工汇缴信息表作准备                      */

/******************************************************************/

 

prompt  建立单位代码及职工 cluster

drop clusteremp_unit;

 

create clusteremp_unit(acc_no  varchar2(15))

tablespace user_data

storage(initial 1mnext 1m maxextents 121 pctincrease 0 );

/

 

create indexunit_inf_ind on cluster emp_unit

tablespaceuser_indx;

/

 

 

 

/******************************************************************/

/*  创建单位信息表unit_inf,并指定表属于cluster  emp_unit簇     */

/*  并为表unit_inf的acc_no列创建相应索引unit_inf_in            */

/******************************************************************/

 

prompt  建立单位开户登记表(unit_inf) 

 

drop table unit_inf;

 

create table  unit_inf

(

bank_code   varchar2(6) ,  -- 经办行代码  

acc_no      varchar2(15) , -- 公积金代号(帐号)

proc_date   date        , -- 处理时间   

unit_name   varchar2(50) , -- 单位名称   

Area        varchar2(20) , -- 所在区、县 

Address     varchar2(50) , -- 单位地址   

Zip         varchar2(6)  , -- 邮政编码   

Master      varchar2(20) , -- 主管部门   

Belong      varchar2(20) , -- 隶属关系   

economic    varchar2(20) , -- 经济性质   

tot_emp     number(6)    , -- 职工人数   

sal_bank    varchar2(40) , -- 发薪银行   

sal_acc_no  varchar2(20) , -- 发薪户帐户 

sal_date    number(2)   , -- 发薪日 

pay_tot     number(6)    , -- 汇缴人数   

pay_money   number(13,2) , -- 汇缴总金额 

pro_depart  varchar2(40) , -- 经办部门  

pro_master  varchar2(10) , -- 负责人 

pro_cotact  varchar2(10) , -- 联系人 

pro_tel     varchar2(15) , -- 电话   

save_bank   varchar2(40) , -- 公积金经办行名称   

bank_add    varchar2(40) , -- 经办行地址 

bank_cotectvarchar2(10) , -- 经办行联系人   

bank_tel    varchar2(15) , -- 经办行电话 

enter_stampvarchar2(40) , -- 填报单位章

enter_date  date        , -- 填报日期   

center_datedate         , -- 中心盖章日期

status_code   char(1)   , -- "0未缴存","1缴存","2封存","3销户"

oper_no       varchar2(10),-- 操作员

unit_pay_ratenumber(7,4) ,-- 单位缴交率

per_pay_rate  number(7,4) -- 个人缴交率

)

cluster emp_unit  ( acc_no ) ;

/

 

prompt  建立 单位开户登记 唯一键: acc_no_in

create unique indexunit_inf_in on unit_inf ( acc_no )

storage ( initial 1Mnext 512k maxextents 121 pctincrease 0 )

/

 

 

/******************************************************************/

/*  创建单位职工汇缴信息表pay_lst_det,并指定到  emp_unit  簇    */

/*  并为表pay_lst_det创建相应唯一索引pay_det_in1                 */

/******************************************************************/

 

prompt   建立开户单位汇缴清册(  pay_lst_det )

 

drop tablepay_lst_det;

 

create tablepay_lst_det

(

bank_code     varchar2(6)NOT NULL,   -- 经办行代码

acc_no       varchar2(15) not null, -- 公积金代码

emp_acc_no    varchar2(20) not null, -- 职工帐号

table_date    date ,          -- 编报日期

Name             Varchar2(10), -- 姓名

Sex            varchar2(2)check(sex='男' or sex='女'),  -- 性别

Birth            date,         -- 出生年月

Per_id           varchar2(20), -- 身份证号

Sal           Number(7,2) not null,  --月工资

Per_pay_rate  Number(7,4), --个人缴交率

Per_pay       Number(7,2),  --个人交缴金额

Unit_pay_rateNumber(7,4),  --单位交缴金率

Unit_pay      Number(7,2),  --单位交缴额

pay_money     number(13,2) check(pay_money>=5.0), --月应缴额

status_code   char(1)   ,  -- "0未缴存","1缴存","2封存","3销户"

Oper_no       Varchar2(10)  --操作员代码

)

cluster emp_unit  ( acc_no )

/

 

create unique index pay_det_in1 on pay_lst_det( per_id )

storage ( initial10M next 2m maxextents 121 pctincrease 0 )

/

 

create unique indexpay_det_in2 on pay_lst_det( emp_acc_no )

storage ( initial 1Mnext 512k maxextents 121 pctincrease 0 )

/

 

§5.1.2  改变簇

在用户具有 ALTER ANY CLUSTER 的权限情况下,可以对已建好的簇(CLUSTER )改变其设置,如:

 

l 物理属性:PCTFREE,PCTUSED,INITRANS,MAXTRANS和STORAGE;

l 为CLUSTER关键字值存储所有行所需的一般空间容量;

l 缺省平行度。

 

命令语法:

ALTER CLUSTERCluster_name

{ PCTUSED  integer

  | PCTFREE integer

  | SIZE integer

  | INITRANS integer

  | MAXTRANS integer

  | STORAGE Cluase

}

 

 

例:ALTERCLUSTER emp_dept

PCTFREE 30

PCTUSED 60;

 

对于用ALTER TABLE语句只能改变表中非簇列的设置,不能对簇列进行任何的修改。

 

§5.1.3  删除簇

只要用户具有 DROP ANY CLUSTER权限均可以对所有的CLUSTER进行删除。

 

语法如下:

DROP CLUSTER[user.]cluster [INCLUDING TABLES]

 

如果使用INCLUDING TABLES 则删除 CLUSTER 的同时也删除所包含的表。簇表可以被单个删除而不影响该表所属的簇、其他簇表或者簇索引。删除一个簇表如同删除一个普通的表一样都可以用DROP TABLE 来完成。

注意:当用户从簇中删除单个表时,ORACLE单独删除表中的每一行。删除整个簇的最有效的方法是使用带有 INCLUDING TABLE 选项的DROP CLUSTER语句删除包含所有表的簇。只有当用户仍想保留簇中其它表时才会使用DROP TABLE从簇中删除单个表。

 

§5.1.4  删除簇索引

一个簇的索引可以被删除而不影响表的数据,但是当簇的索引被删除后,属于该簇的表就变为不可用,所以当删除簇的索引后还须再建立该簇的索引才行。有时为了消除盘空间的碎片我们常进行删除簇索引操作。删除索引命令见 DROP INDEX 命令。

 

§5.1.5  收集簇信息

当应用在设计时使用了簇,则用户或数据库管理员都可以通过查询簇的信息来了解簇的情况,从而进行必要的管理。使用下面命令可以收集属于用户本人的簇信息:

 

l DBA_CLU_COLUMNS或USER_CLU_COLUMNS

l DBA_CLUSTERS或USER_CLUSTER

 

DBA_CLU_COLUMNS  存放有系统实例中所有簇的数据情况。它的结构如下:

 

SQL> descdba_clu_columns

 名称                                     空?      类型

 ------------------------------------------------- ---------------

 OWNER                                     NOT NULLVARCHAR2(30)

 CLUSTER_NAME                              NOT NULLVARCHAR2(30)

 CLU_COLUMN_NAME                           NOT NULLVARCHAR2(30)

 TABLE_NAME                                NOT NULLVARCHAR2(30)

 TAB_COLUMN_NAME                                   VARCHAR2(4000)

 

其中:

OWNER            创建簇的主人

CLUSTER_NAME     簇的名字

CLU_COLUMN_NAME   簇中的列名

TABLE_NAME        与之相关的表名

TAB_COLUMN_NAME   表中的列名

 

 

DBA_CLUSTERS 数据字典存放有簇的详细数据情况,包括存储参数等。结构如下:

SQL> descdba_clusters

 名称                                     空?      类型

 ------------------------------------------------- --------------

 OWNER                                     NOT NULLVARCHAR2(30)

 CLUSTER_NAME                              NOT NULLVARCHAR2(30)

 TABLESPACE_NAME                           NOT NULLVARCHAR2(30)

 PCT_FREE                                          NUMBER

 PCT_USED                                  NOT NULLNUMBER

 KEY_SIZE                                          NUMBER

 INI_TRANS                                 NOT NULLNUMBER

 MAX_TRANS                                 NOT NULL NUMBER

 INITIAL_EXTENT                                     NUMBER

 NEXT_EXTENT                                        NUMBER

 MIN_EXTENTS                               NOT NULL NUMBER

 MAX_EXTENTS                               NOT NULL NUMBER

 PCT_INCREASE                                       NUMBER

 FREELISTS                                         NUMBER

 FREELIST_GROUPS                                    NUMBER

 AVG_BLOCKS_PER_KEY                                 NUMBER

 CLUSTER_TYPE                                      VARCHAR2(5)

 FUNCTION                                          VARCHAR2(15)

 HASHKEYS                                          NUMBER

 DEGREE                                            VARCHAR2(21)

 INSTANCES                                         VARCHAR2(21)

 CACHE                                             VARCHAR2(11)

 BUFFER_POOL                                       VARCHAR2(7)

 SINGLE_TABLE                                      VARCHAR2(11)

 

关于列的解释见《Oracle8i/9Ireference》。

 

此外,你还可以用ANALYZE命令来分析某个簇的数据情况,ANALYZE 命令语法如下:

 

ANALYZE CLUSTERCluster_name

{ COMPUTE STATISTICS

| ESTIMATESTATISTICS

| DELETE STATISTICS

| VALIDATE REFUPDATE

| VALIDATE STRUCTURE

| LIST Chained ROWINTO table_name

}

 

例:ANALYZECLUSTER students COMPUTE STATISTICS;

 

当然我们可以从数据字典中查询所统计的结果,如:

SELECTAVG-BLOCKS_PER_KEY,INSTANCES,CACHE,BUFFER_POOL

FROM USER_CLUSTER

WHERE CLUSTER_NAME=’STUDENT_DEPT’;

 

小结:

l ORACLE8 可以对表及其各自的索引建立簇;

l 可以对基于主键的簇和基于哈希函数建立簇;

l 簇码只能存储一次;

l 簇如果正确使用可以涉及复杂的操作和降低磁盘I/O;

l 簇索引必须在任何簇表装入数据之前创建;

l 只对使用等号操作符的查询表和表的大小相对静态使用哈希簇;

l 建立簇时,可以用 STORAGE 参数分配来优化簇的性能。

 

 

§5.2  分区

现代企业运行的数据库一般都达几个 GB数据量。我们把这写数据库称为超大型数据库(VLDB=Vary LargeDatabase)。ORACLE 公司从 ORACLE7 开始就提出了分区的方法。到ORACLE8后,分区技术已经提供了非常完善的功能。为大型应用系统提供了可能。

§5.2.1  分区的优点

oracle8i分区选项可以对超大规模数据库(VLDB=Vary large databast)进行分区、使之可以达到下面目的:

l 增强可用性,如果表的一个分区由于系统故障或者维护而得不到使用时,表的其余部分仍是可用的

l 减少关闭时间,如果系统故障只影响表的某部分,那么只有这部分需要修复,因此修复工作量减少,所以更快地完成

l 维护轻松,如果需重新连表,那么独立地管理而不是单个大型表的操作要轻松得多。

l 均衡的I/O,可以把不同分区映射到磁盘以平衡I/O并显著改善性能。

l 改善性能,对已分区对象的某些查询可以运行更快,因为搜索仅限于关心的分区。

 A部分

 

B部分

 

C部分

 

D部分

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


                               表和索引分区的示意图

 

不是所有表都可以被分区,下面是不可分区的情况:

l 存在于oracle8簇(cluster)中的表不能被分区

l

l 如果一个表包含非结构性数据,则这个表不能被分区,下面的数据类型就不能进行分区:

l      1)LOBS

l      2)LONG  RAW

         3)对象类型

 

l 索引组织的表不能被分区。

 

§5.2.2  分区的方法

ORACLE 提供了对表或索引的三种分区方法:

l 范围分区;

l 散列(hash)分区;

l 复合分区。

 

1.范围分区方法

 

根据表中列值的范围进行分区,如一年中的月份,当数据在范围内均匀分布时,性能最好,否则应考虑其它的分区方法。

当创建范围分区时,要考虑:

l 分区方法;范围

l 分区列

l 分区中说明指定分区边界

 

2.使用散列分区

 

如果数据不容易进行范围分区,而出现性能原因时就要进行散列分区。

 

3.复合分区法

 

复合分区的分区数据使用范围分区法,而在每个分区或子分区内使用散列分区。

 

§5.2.3  创建表的分区

1.范围分区法

 

1)表的单列分区

create tablestudents

(

student_id  integer not  null,

student_first_name  varchar2(25),

student_last_name   varchar2(25),

student_dept_id     integer,

student_address     varchar2(50),

student_city  varchar2(25),

)constraint  Dept_id_pk primary  key (student_dept_id)

 

partition  By Range (student_dept_id)

(partition  Dept_id_1 values  less  than(100) tablespace  om1,

partition  Dept_id_2 values  less   than (250) tablespace om2,

partition  Dept_id_3 values  less   than (500) tablespace om3

partition  Dept_id_4 values  less   than (750) tablespace om4

partition  Dept_id_5 values  less   than (max value)table space om5);

 

 

Student 表根据students_Dept_id到值进行分区创建的五个分区的名字和范围值如下:

Dept_id_1-范围0-99

Dept_id_2-范围100-249

Dept_id_3-范围250-499

Dept_id_4-范围500-749

Dept_id_5-范围750-MAXVALUE

可以用oracleschema Manager工具查看表的分区结果。

 

注:如果划分有空值,应指定MAXVALUE,这样oracle8i将具有空值的列排到大于其它分区值之后,但此MAXVALUE小。

 

2)表的多列分区

 

oracle8i把多列分区码值作为向量来决定一行应放在哪个分区,如:

例1:

create tablestudents

(

student_id  integer not  null,

student_first_name  varchar2(25),

student_last_name  varchar2(25),

student_dept_id  integer,

student_address  varchar2(50),

student_city  varchar2(25),

)constraint  Dept_id_pk primary  key (student_dept_id)

partition By Range(student_id,student_Dept_id)

partitionDept_id_1  values lessthan(1000,100)tablespace om1,

partitionDept_id_2  values lessthan(2000,250)tablespace om2,

partitionDept_id_3  values lessthan(3000,500)tablespace om3,

partitionDept_id_1  values lessthan(4000,750)tablespace om4,

partition Dept_id_1values less than(MAXVALUE,MAXVALUE)tablespace om5);

 

如果一行码值是(2500,150),则该行插入Dept_id_2分区中,因为码(2500,x)小于(300,x)且比(1000,100)大。

 

例2:

 

CREATE TABLE sales

(invoice_no NUMBER,

sale_year INT NOTNULL,

sale_month INT NOTNULL,

sale_day   INT NOT NULL )

PARTITION BY RANGE(sale_year,sale_month,sale_day)

  (

   PARTITION sales_ql VALUES LESS THAN (1999,04,01)

   TABLESPACE tsa,

   PARTITION sales_q2 VALUES LESS THAN (1999,07,01)

   TABLESPACE tsb,

   PARTITION sales_q3 VALUES LESS THAN (1999,10,01)

   TABLESPACE tsc,

   PARTITION sales_q4 VALUES LESS THAN (2000,01,01)

   TABLESPACE tsd

  )

 

3)等同分区

 

     把表对应的索引按照表的分区确定索引的分区称等同分区,如students表使用

student_id和student_Dept_id来分区,则该表的索引也使用这二列来分区.优点有:

 

l oracle8i在复杂的连接,排序操作中改善分区表的执行计划。

l 由于相关表和索引可同时恢复,减少介质恢复时间。

 

2.使用散列分区法

 

散列分区提供了一种通过指定分区编号来均匀地分布数据的方法。基于分区键的散列将被映射到分区上。为创建和使用散列分区给用户提供了高度灵活的放置数据的方法,因为通过在I/O设备上进行散列分区,使得这些分区在大小上一致。

建立散列分区,需要指定下面信息:

l 分区方法:散列;

l 分区列;

l 分区编号或各个分区的说明。

 

使用  CREATE TABLE 语句加PARTITIONBY HASH 子句可以指定所建的表被散列分区。

 

下面例子创建一个散列分区。分区列为ID,创建了四个分区并分配了由系统生成的分区名,它们被放置在四个被命名的表空间gear1,gear2,gear3,gear4上。

例1:

CREATE TABLEscubagear

( id NUMBER,

  name VARCHAR2(60)

)

PARTITION BYHASH(id)

PARTITIONS 4

STORE IN (gear1,gear2,gear3,gear4);

 

散列分区表的每个分区内保存在不同的节中,且散列数据被放在缺省表空间中。

 

例2:

CREATE TABLE (deptno NUMBER,deptname VARCHAR2(32))

STORAGE( INITIAL 10k)

PARTITION BYHASH(deptno)

(

PARTITION p1TABLESPACE ts1,

PARTITION p2TABLESPACE ts2,

PARTITION p3TABLESPACE ts1,

PARTITION p4TABLESPACE ts3

);

 

指定了各个分区的名字及它们所存放的表空间。所有分区都继承表空间的初始分配 INITIAL 10k 参数。

 

3.复合分区方法

复合分区的分区方法数据使用范围分区,而在每个分区或子分区内使用散列分区法。复合分区对历史数据和带状数据都很理想,并提供范围分区和数据放置的改进的管理性能和散列分区的并行优点。

建立复合分区,须进行:

l 分区方法:范围分区;

l 分区列;

l 指定分区边界的分区说明;

l 子分区方法;散列;

l 子分区列;

l 每个分区的子分区数量或子分区说明。

 

例:下面例子创建了三个范围分区,每个分区又包含八个子分区,子分区没有名字,所以赋予它们系统生成的名字,“STORE IN”子句将它们分布在四个指定的表空间 ts1,ts2,ts3,ts4中。

CREATE TABLEscubager(equipno NUMBER,equipname VARCHAR(32),price NUMBER)

PARTITION BYRANGE(equipno)SUBPARTITION BY HASH(equipname)

SUBPARTITIONS 8STORE IN ( ts1,ts2,ts3,ts4)

(

PARTITION p1 VALUESLESS THAN(1000),

PARTITION p2 VALUESLESS THAN(2000),

PARTITION p3 VALUESLESS THAN(MAXVALUE)

);

 

 

4. 对表分区小结

 

把表的数据范围(range)进行分区存储;

只需在Createtable或Alter table命令中指定即可;

分区名在Createtable或Alter table中指定(给出)即可,不需在任何另外的地方预先说明。

l 建立表结构时指定区

 

   Create table emp

   (emp_no number(5),

   dept   varchar2(2),

   name  varchar2(30))

   storage(initial 100k next 50k) logging

   PARTITION BY  RANAE  (enp_no)

   (PARTITION acct values less than (1000) tablespace ts1,

   PARTITION sales values less than (2000) tablespace ts2,

   PARTITION edue values less than (3000));

Insent into empvalues (1226, ′sa′,′smith′);

Insent into empvalues (2100, ′ed′,′jones′);

 

对具有分区的表更新,有以下不足:

 

1) 不能进行的更新

up date emp set emp_no=1500 where name= ′JONES′;

此条语句将不能运行(引起错误),原因是′Jones′原来是(emp_no=2100)对应的分区为educ,而现要将其从educ分区移至sales中,所以不能垮分区修改。

2) 不指定分区的更新(影响效率)

update  emp set  emp_no=1356  where name = ′SMITH′;

3) 指定分区的更新(提高效率)

update  sale  partition(feb96)

set  s.account_name=upper(s.account_name);

 

对具有分区的表进行删除(指定分区效率更高)

 

Delete  From sales  Partition (nov96)

Where  amount_of_sale !=0;

 

对具有分区的表进行查询

 

Select * from  emp partition  acct

Where  emp_no=999;

 

用日期字段作分区条件(详细见《oracle8 sql Reference》)

 

Create  table stock_xaction

(stock_symbot  CHAR(5),

stock_series  CHAR(1),

num_shares  Number(10)

price       Number(5,2)

trade_date   Date

Storage  (inltial 100k  next  50k)logging

PARTITION  By range (trade_date)

(PARTITION  sx1992 values  less  than (to_date(′01-JAN-1993′,

′DD-MON-YYYY′))Tablespace  tso  Nologging,

PARTITION  sx1993 values  less  than(To-date(′01-JAN-1994′,

′DD-MON-YYYY′))Tablespace  ts1,

PARTITION  sx1994 values  less  than (To-date(‘01-JAN-1995′,

′DD-MON-YYYY′))Tablespace  ts2);

 

用Alter对表进行分区

 

可以用下面语句实现分区指定:

MODIFY  PARTITION partition-name [phsical-attributes-clause]

 

 

§5.2.3  创建索引的分区

 

可以创建两种类型的索引分区:

l 局部索引

l 全部索引

 

这两种均遵从下列原则:

 

l 分区的索引表不能应用聚类表

l 位图索引必须为局部索引

l 分区和未分区的索引可以应用于分区或未分区的表

 

 

1. 局部索引

 

  根据表的分区个数来建立同样的索引分区叫局部索引,如:

 

      ( create index  Dept_id_1  tablespace om1,

         create index  Dept_id_2  tablespace om2,

         create index  Dept_id_3  tablespace om3,

         create index  Dept_id_4  tablespace om4

         create index  Dept_id_5  tablespace om5

       );

 

每个局部索引都与其基于的表等同分区。局部索引有下列优点:

 

l 如果只一个分区需要维护,则只有一个局部索引受影响

l 支持分区独立性

l 只有局部索引能支持单一分区的装入和卸出

l oracle8更好的查询

l 表分区和各自的局部索引可同时恢复

l 局部索引可以单独重建

l 位图索引仅由局部索引支持

 

根据前面STUDENTS表被划分为5个区DEPT_ID_1,... DEPT_ID_5 。按照上面对各个分区的进行局部索引的创建,则形象如下图:

 

 

 

                  STUDENTS表

 
 

 

 

 


                      局部索引DEPT_IDX ( Dept_idx图)

 

2. 全局索引分区

 

对表的多个分区建立索引分区叫全局索引(分区)一般可以这样认为,未作分区的索引被认为是全局索引如:

create  index Dept_idx on students(student_dept_id)

GLOBAL  partition By  range (student_dept_id)

(partition  Dept_id_1 values less than (1000,100)tablespace om1,

partition  Dept_id_2 values less than (2000,250)tablespace om2,

partition  Dept_id_3 values less than (3000,500)tablespace om3,

partition  Dept_id_4 values less than (4000,750)tablespace om4,

partition  Dept_id_5 values less than(MAXVALUE,MAXVALUE) tablespace om5;

 

 

下面图表示全局索引Dept_idx的情况

 

 

 

 

 

 

 

 

 

 

                  STUDENTS表

 
 

 

 

 


                        全局索引Dept_idx(Dept_idx2图)

 

3. 相关的数据字典

 

DBA_IND_PARTITIONS

DBA_TAB_PARTITIONS

DBA_PART_COL_STATISTICS

USER_TAB_PARTITONS

USER_PART_COL_STATISTICS

USER_IND_PARTITIONS

ALL_TAB_PARTITIONS

ALL_IND_PARTITIONS

ALL_PART_COL_STATISTICS

 

 

§5.2.4  维护表分区和索引分区

在了解如何建立表分区和索引分区后,在应用设计中还经常进行分区的维护。下面是维护分区的简要介绍。

1.用 ALTER TABLE 语句来维护表分区

 

维护操作

范围

散列

复合

加入分区

ADD PARTITION

 ADD PARTITION

ADD PARTITION

MODIFY PARTITION

…ADD SUBPARTITION

合并分区

N/a

COALESCE PARTITION

MODIFY PARTITION

…ADD COALESCE

SUBPARTITION

删除分区

DROP PARTITION

N/a

DROP PARTITION

互换分区

EXCHANGE PARTITION

EXCHANGE PARTITION

.EXCHANGE PARTITION

.EXCHANGE UBPARTITION

合并(merge)分区

MERGE PARTITION

N/a

MERGE PARTITION

修改分区缺省属性

MODIFY DEFAULT

 ATTRIBUTES

MODIFY DEFAULT

 ATTRIBUTES

.MODIFY DEFAULT

 ATTRIBUTES

.MODIFY DEFAULT

 ATTRIBUTES FOR

PARTITION

修改分区实际属性

MODIFY PARTITION

MODIFY PARTITION

.MODIFY PARTITION

.MODIFY SUBPARTITION

移动分区

MOVE PARTITION

MOVE PARTITION

MOVE SUBPARTITION

重命名分区

RENAME PARTITION

RENAME PARTITION

. RENAME PARTITION

. RENAME SUBPARTITION

拆分分区

SPLIT PARTITION

N/a

SPLIT PARTITION

截短分区

TRUNCATE PARTITION

TRUNCATE PARTITION

.TRUNCATE PARTITION

. TRUNCATE SUBPARTITION

 

2.用 ALTER INDEX 语句来维护索引分区

 

维护操作

索引

类型

                 索  引  分  区  类  型

      范围               散列             复合

删除索引

分区

全局

本地

DROP PARTITION

N/a

 

N/a

 

N/a

修改索引

分区的缺

省值

全局

本地

.MODIFY DEFAULT

ATTRIBUTES

.MODIFY DEFAULT

ATTRIBUTES

.MODIFY

DEFAULT

ATTRIBUTES

.MODIFY DEFAULT

ATTRIBUTES

.MODIFY DEFAULT

ATTRIBUTES FOR

 PARTITION

修改索引分区的实际属性

全局

本地

.MODIFY PARTITION

.MODIFY PARTITION

 

MODIFY PARTITION

 

MODIFY SUBPARTITION

重建索引分区

全局

本地

REBILD PARTITION

 

REBILD PARTITION

 

REBILD PARTITION

重新命名

索引分区

全局

本地

RENAME PARTITION

RENAME PARTITION

 

RENAME PARTITION

 

RENAME PARTITION

拆分索引分区

全局

本地

SPLIT PARTITION

N/a

 

N/a

 

N/a

 

§5.3  簇与分区有关的数据字典

如果你在应用系统设计时采用了分区和簇技术,则你最好要了解与簇和分区有关的数据字典。这样对管理有好处。

 

§5.3.1  分区、簇数据字典列表

下面给出的数据字典有三类,分别以DBA、ALL和USER开头,如果你具有DBA权限,你只要了解DBA开头即可。下面仅给相关数据字典的名字,具体的列名及介绍请见《Oracle8i/9i数据库管理》。

 

l  ALL_CLUSTERS、DBA_CLUSTER、USER_CLUSTER 存放簇的基本信息。

l  DBA_TABLES   存放索引表的信息,其中cluster_name 表示该表所对应的Cluster名字。

l ALL_TAB_PARTITIONS、DBA_TAB_PARTITIONS、USER_TAB_PARTITIONS 存放有关分区的基本信息,如表名,分区名等。

l ALL_IND_PARTITIONS、DBA_IND_PARTITIONS、USER_IND_PARTITIONS有关索引分区的信息。

l ALL_PART_INDEXES、DBA_PART_INDEXES、USER_PART_INDEXES可访问的分区的索引。

l ALL_PART_TABLES、DBA_PART_TABLES、USER_PART_TABLES存放可访问的分区表的信息。

l  ALL_PART_LOBS、DBA_PART_LOBS、USER_PART_LOBS存放大对象类型的分区信息。

 

§5.3.2  基本的分区、簇信息查询

了解数据字典的目的是查询它们的信息和管理。下面给出几个常用查询例子。

 

例1.查询与簇有关的表的信息:

 

SQL> col owner fora20

SQL> coltable_name for a20

SQL> coltablespace_name for a20

SQL> selectOWNER,table_name,TABLESPACE_NAME,CLUSTER_NAME from dba_tables

  2* where CLUSTER_NAME is not null;

 

OWNER                TABLE_NAME           TABLESPACE_NAME      CLUSTER_NAME

---------------------------------------- -------------------- --------------

SYS                  IND$                 SYSTEM               C_OBJ#

SYS                  CLU$                 SYSTEM               C_OBJ#

SYS                  ICOL$                SYSTEM               C_OBJ#

SYS                  FET$                 SYSTEM               C_TS#

SYS                  CDEF$                SYSTEM               C_COBJ#

 

. . .  . . .

 

已选择33行。

 

 

例2.查询进行过分区的表的信息:

 

SQL> selectTABLE_OWNER,TABLE_NAME,PARTITION_NAME,TABLESPACE_NAME

  2  fromDBA_TAB_PARTITIONS;

 

未选定行

 

SQL>

 

 

第六章  使用SQL进行数据操作

大家都知道,关系数据库中使用最频繁的SQL语句可以是SELECT 、INSERT、UPDATE及DELETE语句了,尽管它们使用简单,但也是变化最多和最能衡量一个编程人员水平的语句了。下面就增、删、改作简要介绍。

§6.1  INSERT操作

INSERT 语句可以完成对表、视图及快照(snapshot)进行数据插入。插入的数据依不同的版本而允许插入的数据类型也不同,最新版本可以在子查询中使用 LOB数据类型。现在最新的版本仍有下面限制:

l  不能在语句中使用并行,也不允许从远程进行插入;

l  在子查询中不允许使用带有long 类型的字段。

 

 

1.INSERT命令语法:

 

INSERT INTO[user.]table[@db_link][(column1[,column2]...)]

VALUES (express1[,express2]...|subquery...);

 

2 . 日期的插入

  INSERT into emp_house_fund(name,emp_acc_no,tran_date,tran_val)

VALUES('赵元杰','123456',to_date('06/09/2000','dd/mm/yyyy'),99.9);

 

  INSERT intoemp_house_fund(name,emp_acc_no,tran_date,tran_val)

VALUES('赵元杰','123456',to_date('2000.06.09','yyyy.mm.dd'),99.9);

 

  INSERT into emp_house_fund(name,emp_acc_no,tran_date,tran_val)

VALUES('赵元杰','123456',to_date('06092000','ddmmyyyy'),99.9);

 

3.带select 的插入

SQL> create tableemp_house_fund_sum( per_id verchar2(20), tran_val number(9,2));

 

SQL> insert intoemp_house_fund_sum 

select per_id,sum(tran_val)

From emp_house_fundgrou by per_id;

 

SQL>selecta.name, b.per_id,b.tran_val

from emp_house_funda,emp_house_fund_sum b

wherea.per_id=b.per_id;

 

§6.1.1  用文字插入操作

INSERTINTO dept

VALUES(50, ‘PRODUCTION’,’SANFRANCISCO’);

 

INSERTINTO emp (empno, ename, job, sal, comm, deptno)

VALUES(7890, ‘LINKS’,’CLERK’,1.2E3,NULL, 40);

 

下面语句完成同样的功能,只是用了子查询:

INSERTINTO (SELECT empno, ename, job, sal, comm, deptno FROM emp)

VALUES(7890, ‘LINKS’,’CLERK’,1.2E3,NULL, 40);

 

§6.1.2  用子查询插入操作

INSERTINTO bonus

SELECTename, job, sal, comm

FROMemp

WHEREcomm > 0.25 * sal

ORjob IN (‘PRESIDENT’,’MANAGER’);

 

分区的例子:

插入到 SALES表的 OCT98 分区中:

INSERTINTO sales PARTITION (oct98)

SELECT* FROM latest_data;

 

绑定变量的例子:下面例子将插入结果返回到变量:

INSERTINTO emp VALUES (empseq.nextval, ‘LEWIS’ ‘CLARK’

7902,SYSDATE, 1200, NULL, 20)

RETURNINGsal*12, job INTO :bnd1, :bnd2;

 

插入 LOB 数据类型的例子:

1)插入一个带 long raw 的表:

CREATETABLE long_tab (long_pics LONG RAW);

2)建立一个带 LOB的表:

CREATETABLE lob_tab (lob_pics BLOB);

3)用下面预计完成将 long raw 插入到 LOB 中:

INSERTINTO lob_tab (lob_pics)

SELECTTO_LOB(long_pics) FROM long_tab;

4)可以将带有long raw 的列删除掉:

ALTERTABLE long_tab DROP COLUMN long_pics;

 

插入BFILE 的例子:

INSERTINTO emp

VALUES (1, BFILENAME (‘a_dir_alias’, ‘a_filename’);

 

§6.2 UPDATE操作

1. UPDATE语法

 

UPDATE[user.]table[@db_link][alias]

SET {column1=express1[,column2=experss2]...|

(column1[,column2]...)=(subquery)}

[WHEREcondition|current of cursor];

 

2.一般的修改

如果起息日为空时以处理日作为该记录的起息日:

SQL>update  emp_house_fund set tran_date=sysdate

Whereproc_date=sysdate and tran_date is null;

 

3. 带null 的修改

SQL>update empset per_id=null where length(per_id)<15 or

Substr(per_id,15,1)> 1;

 

 

§6.2.1  用文字更新操作

在一般情况下,我们经常使用文字更新操作,即在UPDATE 语句中直接将要更新的数值写在语句中,如:

 

UPDATE emp

SET job = ’MANAGER’, sal = sal + 1000, deptno = 20

WHERE ename = ’JONES’;

 

UPDATE accounts@boston

SET balance = balance + 500

WHERE acc_no = 5001;

 

限制:

l  不能在并行语句中使用或在远程进行更新;

l   不能在更新子句中对LONG类型进行更新。

 

 

§6.2.2  用查询更新操作

在Oracle中,可以根据查询结果来更新表的数据。比如,在申请基金项目时,不允许一个人在大学申请项目又在大学的研究所中申请项目,则可使用下面例1的语句来实现检查。

 

例1:

SQL>update colle_subjectsset app_flag='0'

Where per_id in (select per_id from univ_subjects );

 

例2:

SQL>updatecomfort set ( noon, midnigt )=

(selecthumiddity,temperature from weather

  where city='MANCHESTER')

where City='WALPOLE'and

Sampledate=to_date('22-dec-2000','DD-MON-YYYY');

 

例3:

UPDATE sales PARTITION(feb96) s

SET s.account_name =UPPER(s.account_name);

 

§6.2.3  用相关子查询更新操作

同样可以在更新中使用相关的查询操作,如:

 

例1.复杂UPDATE语句:

UPDATE emp a

SET deptno =

(SELECT deptno

FROM dept

WHERE loc = ’BOSTON’),

 

(sal, comm) =

(SELECT 1.1*AVG(sal),1.5*AVG(comm)

FROM emp b

WHERE a.deptno = b.deptno)

 

WHERE deptno IN

(SELECT deptno

FROM dept

WHERE loc = ’DALLAS’

OR loc = ’DETROIT’);

 

 

例2:相互更新的例子:

 

UPDATE TABLE(SELECT projs

FROM dept d WHERE d.dno =123) p

SETp.budgets = p.budgets + 1;

 

§6.3 DETELE操作

在应用中,可以使用delete 语句实现将不需要的记录进行删除。值得注意的是,经常使用DELETE 语句对表的记录进行有条件的删除。而无条件的全表删除需要一定的技巧。请看下面的例子。

§6.3.1  用delete删除全部记录的操作

1. DELETE 语法

DELETE [ FROM ][user.]table [@db_link][Alias] [WHERE condition];

这里的condition 可以复杂的表达式或子查询。

 

2.例子:

SQL> delete fromhouse.emp_house_fund;

 

SQL>delete fromcolle_subjects

Where per_id  in ( select per_id from univ_subjects );

 

 

§6.3.2  用delete有条件删除部分记录

删除语句用的最多应该是有条件的删除记录。如果我们不是有条件的删除的话,我们应该采用直接建立一个新表、DROP 旧表的方法来达到我们的目的。

 

例1:

 

DELETE FROM temp_assign;

 

例2:

 

DELETE FROM emp

WHERE JOB = ’SALESMAN’

AND COMM < 100;

 

例3:

 

DELETE FROM (select * from emp)

WHERE JOB = ’SALESMAN’

AND COMM < 100;

 

限制:

不能使用并行或带远程对象

不能用LONG类型

 

 

§6.3.3  用delete分段删除大量记录

有时我们需要删除大块的数据,在环境比较差的情况下,往往由于回滚段不够大而出现删除失败。这样我们可以采用以下两种方法来达到删除大量数据的目的。

 

例1:用rownum来限制每次删除的记录数目:

DELETE from emp where deptno=9999 and   rownum < 1000;

 

例2:编写一个简单的存储过程,如:

SQL>get del_rec

DECLARE TMP VARCHAR2(1);

BEGIN

   LOOP

   BEGIN

   /* 下面语句确定是否还有可删的记录,如果没有就直接到EXCEPTION */

   SELECT  ‘X’ INTO TMP  FROM  SAMPLE

   WHERE ROWNUM = 1;

   /* 如果SAMPLE还有数据就执行删除一组操作,即使不够20条也不会出错 */

   DELETE FROM SAMPLE

   WHEREROWNUM<20;

   COMMIT;

  EXCEPTION

  WHEN NO_DATA_FOUNDTHEN

  EXIT;

  END;

END LOOP;

END;

 

 

§6.4 insert、delete及update 的提交和撤消

与桌面数据库最大的区别是,所有的关系数据库在事务处理操作中,可以对每个事务进行提交或撤消。当我们在进行insert、update、delete时,都可以根据当前的处理情况来确定目前的操作是提交或撤消。

§6.4.1  自动提交的设置

    为了保证在SQL>方式下进行INSERT、DELETE和UPDATE操作达到安全的目的,一般在SQL>下进行INSERT、DELETE和UPDATE操作前,建议将环境设置成为非自动提交的方式。

我们可以在SQL>下用 show autocommit 命令查看当前该参数的状态。如果状态是ON,则建议用下面命令将其设置为 OFF状态,这样做主要目的是:即使误删除某些记录也可以用ROLLBACK命令进行恢复。

 

l 查看当前的提交状态:

SQL>show    autocommit

autocommit    OFF

 

l 设置是否自动提交的命令:

             SET   AUTO[commit]{ON|OFF|IMM{[EDIATE]|n}(oracle8

             SET   AUTO[commit]{ON|OFF|IMM{[EDIATE]}(oracle7

             当设为imm时,每作一个修改操作均自动提交。

             当设n(n为一个整数),当作过n个修改时自动提交。

 

l 设置为非自动提交:

SQL>setautocommit off

 

l 设置为自动提交:

SQL>setautocommit on

 

l Commit

Commit     Complete

(这样的命令表示以前的操作到目前为止都进行提交,不是仅提交当前的操作)

 

l rollback

rollback    complete

(只回滚那些未被提交的且最近一次的那些事务)

 

l 隐含提交

虽然有的操作并不发出commit,但我们用exit 退出后系统会自动提交,目前exit等价于quit,以前oracle v5如果用quit退出,则所作修改不提交。

 

l 自动回滚

oracle在遇到异外情况下,如断电,系统故障时,自动采取回滚。

 

 

例。

 

SQL>show user

User为“SCOTT”

SQL>show autocommit

Autocommit off

SQL>

SQL> update emp set sal = sal*1.2 wheredeptno=10;

 

已更新2行。

 

SQL> rollback;

 

重算已完成。

 

§6.4.2  保留点和撤消

    我们可以使用 ROLLBACK 命令撤消最近一次所做的操作,要想实现对前面的所有各个操作也要撤消的话,就必须在每个操作命令前设置相应的保留点。当对每个操作都设置了相应的保留点,我们就可以根据需要用ROLLBACK TO xx 来实现撤消到某一步。

 

l SAVEPOINT命令

SAVEPOINTsavepoint_work;

 

其中:savepoint_work 是要设置的保留点标识。

 

l ROLLBACK命令

ROLLBACK [WORK ] [TO[SAVEPOINT] savepoint_work]

 

其中:savepoint_work 是要设置的保留点标识。

 

例子:

-- 看当前用户的名字

SQL> show user

USER 为"ZHAO"

 

-- 先查看emp表的记录数

SQL> select * from emp;

 

 

ENAME          SAL  DEPTNO   TEL

-------------------- ------------ ------------ -----------------

赵元杰        99999.12     10    1360 136 5681

张x           8888.88      10    12345

 

-- 设置第1个保留点a

SQL> savepoint a;

保存点已创建。

 

--插入第1条记录

SQL> insert into empvalues('John',123.45,20,'56789');

 

已创建 1 行。

 

-- 设置第2个保留点b

SQL> savepoint b;

 

保存点已创建。

 

--插入第2条记录

SQL> insert into empvalues('Scott',456.78,20,'13601361234');

 

已创建 1 行。

-- 设置第3个保留点c

SQL> savepoint c;

 

保存点已创建。

 

-- 插入第3条记录

SQL> insert into empvalues('赵x',3210.1,20,'62348901');

 

已创建 1 行。

 

-- 查询到目前为止的emp表记录数

SQL> select * from emp;

 

ENAME          SAL   DEPTNO  TEL

-------------------- ---------- ---------- --------------------

赵元杰          99999.12        10 1360 136 5681

张x             8898.88         10 12345

John             123.45         20 56789

Scott            456.78         20 13601361234

赵x              3210.1         20 62348901

 

-- 要求撤消到第2步,即撤消到保留点b

SQL> rollback to b;

 

重算已完成。

 

-- 再查询撤消后的emp 表记录情况

SQL> select * from emp;

 

ENAME          SAL   DEPTNO  TEL

-------------------- ---------------- ----------------------------

赵元杰           99999.12   10 1360 136 5681

张x              8898.88    10 12345

John              123.45    20 56789

 

SQL>

 

 

注意:撤消的处理必须是在没有发出COMMIT命令的前提下才能有效。

 


 

第七章  复杂查询语句的使用

在关系数据库中,select 语句是使用最频繁的语句。它的处理复杂程度可依据业务的要求的不同而不同。它是程序员和管理员必需的语句。前面已经进行过介绍,但下面从较为复杂的程度来介绍它的使用情况。

§7.1   复杂查询语句的使用

使用SELECT语句和子查询(SUBQUERY)可以从一个或多个表、视图、实体视图中返回数据。

§7.1.1  相关子查询

    可以将子查询(前面提到的 as subquery )或In 或exists当成 where 的一个条件的一部分,这样的查询称作子查询。

 

l where中可以包含一个select语句子查询;

l where中可以包含IN, EXISTS 语句;

l 最多可嵌套16层;

l 层数过多会影响性能。

 

例:比如一个查询是否有专家既以研究所的名义申请基金项目又以大学系为单位申请项目(按规定只能以一个单位来申请):

 

SQL>select name,per_id,dept_namefrom univ_subjects

Where per_id in  ( select per_id  from colle_subjects );

 

§7.1.2  外连接

    招生中,如果所有学生的信息放在 students 表中,而部分有特长的学生在另一个表student_skill 中同样有该学生信息。现在要全部列出所有学生,如果某个学生在表student_skill 中有其特长信息,就显示特长内容,如果某个学生没有特长(在表student_skill中无其特长信息)就显示特长为空:

SQL>selecta.st_id, name, age,skill from students a, student_skill b

Wherea.st_id=b.st_id(+)

Order by a.name;

 

Students 结构为:

St_id  varchar(20),

Name varchar2(10),

Age   number(2),

Tot_score   number(3),

... ...

 

Student_skill 结构为:

St_id  varchar(20),

Skill   varchar2(20),

... ...

Students 的记录,Student_skill的记录少。上面的“+”跟在记录少的表后面,它表示当没有与a.st_id 匹配时就为 b.st_id增加一空行。

 

St_id          name          tot_score    skill

----------  ----------   -------------  ------------------

1111     aaaa       600               足球

2222     bbbb       590               篮球

3333     cccc       620                    

4444     dddd       610               跳高

...  ...

 

§7.1.3  自我连接

自我连接是在同一个表或视图内进行条件连接。下面语句返回的是每个雇员的名字及该雇员的经理的名字:

 

SELECT e1.ename||’ works for ’||e2.ename

"Employees and their Managers"

FROM emp e1, emp e2 WHERE e1.mgr = e2.empno;

 

Employees and their Managers

-------------------------------

BLAKE works for KING

CLARK works for KING

JONES works for KING

FORD works for JONES

SMITH works for FORD

ALLEN works for BLAKE

WARD works for BLAKE

MARTIN works for BLAKE

SCOTT works for JONES

TURNER works for BLAKE

ADAMS works for SCOTT

JAMES works for BLAKE

MILLERworks for CLARK

 

连接条件是 e1.mgr =e2.empno

 

 

§7.1.4  UNION,INTERSECT及MINUS

有时需要从多个表中组合具有一种相似类型的信息。Union 可以完成将两个以上的表的相类似的查询结果合并在一起,并且相同的只取其一;如果unionall 则表示返回所有行(不管是否重复)。Intersect返回在两个表中都有相同内容的信息。Minus 则返回只在一个表中出现的信息。

 

1. 语法:

select ...

union[all]

select ...

 

select ...

intersect

select ...

 

select ...

minus

select ...

 

例:

sql>

   select sum(balance) into lf_return from

     (

selectsum(nvl(tran_val,0)*decode(db_cr_flag,'1',1,'0',-1,0) ) balance

         from per_fix_det

         where acc_no=as_acc_no

       union all

selectsum(nvl(tran_val,0)*decode(db_cr_flag,'1',1,'0',-1,0) ) balance

          from per_detail

          where acc_no=as_acc_no

     );

 

列出有特长的考生(在表students,student_skill同时出现):

sql>select namefrom sutdents

      intersect

     select name from  student_skill;

 

列出没有特长的考生(仅在表students出现):

sql>select namefrom sutdents

      minus

     select name from  student_skill;

 

 

 

§7.2  创建复杂的视图

许多应用系统都可能有统计等功能,没有经验的开发者可能在开发工具端来写这些语句。比如在POWER BUILDER 中加上复杂的统计与排序等处理。其实,这样很不好。建议把这些复杂语句写成视图更好。下面就介绍几个常用的视图。

§7.2.1  分组视图

例1:

CREATE OR REPLACEVIEW dept_tot as

select a.dname dept,sum(b.sal)total_sal from dept a,emp b

wherea.deptno=b.deptno group by a.dname

 

例2:

CRATE OR REPLACEITEMTOT AS

SELECTPERSION,SUM(AMOUNT) ITEMTOT

FROM LEDGER

WHERE ACTIONDATEBETWEEN

TO_DATE(‘01-MAR-1901’,’DD-MON-YYYY’) and

TO_DATE(‘31-MAR-1901’,’DD-MON-YYYY’)

And ACTION IN ( ‘BOUGHT’,’RAID’)

GROUP BY PERSION;

 

§7.2.2  合计视图

例:

CREATE VIEW empvi AS

SELECT  DEPTNO,SUM(SAL),SUM(COMM)

FROM  EMP GROUP BY DEPTNO;

 

§7.2.3  组合视图

例:

CREATE OR REPLACEVIEW BYITEM AS

SELECTL.persion  persion.item,

Amount,

100*amount/itemtotalbypersion, 100*amount/total  bytotal

from ledgerl L,iteamtotal I, total

whereL.persion=I.persion

and actiondatebetween

to_date(‘01-MAR-1901’,’DD-MON-YYYY’) and

TO_date(‘31-MAR-1901’,’DD-MON-YYYY’)

And ACTION IN(‘BOUGHT’,’PAID’);

 

§7.3  家族树

ORACLE 提供了一个有趣的功能 connect by 子句,它可以对具有家族树结构的分枝进行排序。它的用途有 机构或公司的各层结构,财务的科目代码等。

要使用查询遍历,需要在将数据在基表中按照层次结构进行存储。比如一个组织机构就是这样的典型例子。

 

实现语句:

 

SELECT column

FROM  table_name

START WITH column=value

CONNECT  BY  PRIOR  父主键=子外键

 

§7.3.1  排除单一体和分枝

例1:在ORACLE的EMP 表中,每一条记录都有一个唯一标识当前雇员的empno和标识这个雇员的经理的mgr列。如果mgr 为空,则该雇员是该机构的最顶级。现在要列出每个雇员的层次结构(从顶到底):

 

select lpad(' ',4*(level-1))||ename name ,empno,mgr fromemp

  start with mgr isnull

  connect by prior empno=mgr;

 

NAME                    EMPNO      MGR

--------------------             ---------      ---------

KING                      7839

    JONES                 7566      7839

        SCOTT             7788      7566

            ADAMS        7876     7788

        FORD              7902      7566

            SMITH         7369      7902

    BLAKE                 7698      7839

        ALLEN             7499      7698

        WARD              7521      7698

        MARTIN            7654      7698

        TURNER            7844      7698

        JAMES             7900       7698

    CLARK                 7782      7839

        MILLER            7934       7782

 

14 rows selected.

 

SQL>

 

从查询结果中可以看出,由于JONES、BLAKE、CLARK的上司是KING,所以JONES等MGR(经理编号)=KING的empno号,即KING的直接下级是JONES、BLAKE、CLARK,因为他们的MGR与KING的EMPNO一样。

 

§7.3.2  遍历至根

例2:现在要从某个雇员往他的上级列出该雇员的层次结构(从顶到底):

SQL> col enamefor a30

SQL> l

select lpad('',4*(level-1))||ename ename,mgr,empno from emp

start withmgr=7788

connect by priormgr= empno

SQL> /

 

ENAME                       MGR   EMPNO

------------------------------          -----    ---------

ADAMS                       7788      7876

    SCOTT                    7566      7788

        JONES                7839      7566

            KING                       7839

 

 

例3:现在要列出所有雇员的层次结构(从顶到底):

 

  select lpad('',4*(level-1))||ename name ,empno,mgr from emp

  start with mgr isnot null

  connect by  empno=prior mgr

 

 

NAME                   EMPNO   MGR

--------------------           ---------   -----

SMITH                     7369  7902

    FORD                  7902  7566

        JONES             7566  7839

            KING          7839

ALLEN                     7499  7698

    BLAKE                 7698  7839

        KING              7839

WARD                      7521  7698

    BLAKE                 7698  7839

        KING              7839

JONES                     7566  7839

    KING                  7839

MARTIN                    7654  7698

    BLAKE                 7698  7839

        KING              7839

BLAKE                     7698  7839

    KING                  7839

CLARK                     7782  7839

    KING                  7839

SCOTT                     7788  7566

    JONES                 7566  7839

        KING              7839

TURNER                    7844  7698

    BLAKE                 7698  7839

        KING               7839

ADAMS                    7876  7788

    SCOTT                 7788  7566

        JONES             7566  7839

            KING          7839

JAMES                     7900  7698

    BLAKE                 7698  7839

        KING              7839

FORD                      7902  7566

    JONES                 7566  7839

        KING              7839

MILLER                    7934  7782

    CLARK                 7782  7839

        KING              7839

 

38 rows selected.

§7.4  在from 中使用视图

在SELECT 语句中,当对一个表或视图查询时,语句要求视图是必须存在的。在ORACLE7.2版以后。当该视图不存在时,我们可以在 FROM子句后写上该视图即可。

 

详细例子如下:

1.假设有下面视图:

CREATE OR REPLACEVIEW TOTAL AS

Select SUM(amount)TOTAL

From ledger

Where actiondatebetween

To_date(‘01-MAR-1901’,’DD-MON-YYYY’) and

To_date(‘31-MAR-1901’,’DD-MON-YYYY’)

And action in(‘BOUGHT’,’PAID’);

 

2.我们可以像下面来使用视图( FROM 之后的TOTAL是视图):

SELECTPERSON,AMOUNT,100*AMOUNT/TOTAL

From LEDGER,TOTAL

Where actiondatebetween

To_date(‘01-MAR-1901’,’DD-MON-YYYY’) and

To_date(‘31-MAR-1901’,’DD-MON-YYYY’)

And action in(‘BOUGHT’,’PAID’);

 

3.如果不建立 TOTAL视图,也可以使用下面语句来完成同样的工作:

 

SELECTPERSON,AMOUNT,100*AMOUNT/TOTAL

From LEDGER,

( select SUM(Amount) TOTAL

 from Ledger

  Where actiondatebetween

  To_date(‘01-MAR-1901’,’DD-MON-YYYY’) and

  To_date(‘31-MAR-1901’,’DD-MON-YYYY’)

  And action in(‘BOUGHT’,’PAID’)

)

Where actiondatebetween

To_date(‘01-MAR-1901’,’DD-MON-YYYY’) and

To_date(‘31-MAR-1901’,’DD-MON-YYYY’)

And action in(‘BOUGHT’,’PAID’);

 


 

第八章  一些高级的用法

这里给出一点不作为一般要求的内容,它虽然不是必需的,但对于应用开发来说很重要。希望Oracle应用设计者把它应用到系统的设计中。

§8.1  关于DECODE

DECODE是Oracle公司独家提供的功能,它是一个功能很强的函数。它虽然不是SQL的标准,但对于性能非常有用。到目前,其他的数据库供应商还不能提供类似DECODE的功能,甚至有的数据库的供应商批评Oracle的SQL不标准。实际上,这种批评有些片面或不够水平。就象有些马车制造商抱怨亨利。福特的“马车”不标准一样。

 

§8.1.1  DECODE 中的if-then-else逻辑

在逻辑编程中,经常用到If – Then –Else 进行逻辑判断。在DECODE的语法中,实际上就是这样的逻辑处理过程。它的语法如下:

 

DECODE(value, if1, then1, if2,then2, if3,then3,  . . .  else )

 

Value 代表某个表的任何类型的任意列或一个通过计算所得的任何结果。当每个value值被测试,如果value的值为if1,Decode函数的结果是then1;如果value等于if2,Decode函数结果是then2;等等。事实上,可以给出多个if/then 配对。如果value结果不等于给出的任何配对时,Decode 结果就返回else。

需要注意的是,这里的if、then及else都可以是函数或计算表达式。

 

§8.1.2  DECODE 的简单例子

Oracle系统中就有许多数据字典是使用decode 思想设计的,比如记录会话信息的V$SESSION数据字典视图就是这样。我们从《Oracle8i Reference》资料中了解到,当用户登录成功后在V$SESSION中就有该用户的相应记录,但用户所进行的命令操作在该视图中只记录命令的代码(0—没有任何操作,2—Insert…),而不是具体的命令关键字。因此,我们需要了解当前各个用户的名字及他们所进行的操作时,要用下面命令才能得到详细的结果:

 

selectsid,serial#,username,

DECODE(command,

0,’None’,

2,’Insert’,

3,’Select’,

6,’Update’,

7,’Delete’,

8,’Drop’,

‘Other’) cmmand

from  v$session whereusername is not null;

 

§8.1.3  DECODE实现表的转置

数据库中的表是由列和行构成的一个二维表。一般列在任何数据库中都是有限的数量,而行的变化较大,如果表很大,行的数量可能大上千万行。同一列的不同行可能有不同的值,而且不是预先定义的。

除上面描述表具有的一些特点外,有一些表可以看成是不变的或者是较稳定的,比如住房公积金系统是各个单位按照职工的工资数的比例交到本地的经办行中,它的处理流程如下:

 

例1.住房公积金报表置换实例:

 

1.各个单位在本地经办行进行开户,开户就是将单位的基本信息和职工信息的进行登记;

2.每月各个单位的会计到经办行交缴本单位的所有职工的住房公积金,系统记录有每个职工的交缴明细并在每条记录上记录有经办行的代码;

3.每月、季、半年及年终都要求将经办行 变为“列”给出个月的明细报表:

 

     经办行:城西区        城东区  。 。 。

月份:

2001.01     xxxx1.xx         xxxxx2.xx

2001.02     xxxx3.xx         xxxxx4.xx 

。 。 。   。 。 。

 

原来的数据顺序是:

城西区2001.01  xxxxx1.xx

城东区2001.01  xxxxx2.xx

城西区2001.02  xxxxx3.xx

城东区2001.02  xxxxx4.xx

 

 

住房公积金系统记录职工的每月交缴名细的pay_lst表结构是:

 

bank_code    varchar2(6)NOT NULL,   -- 经办行代码

acc_no        varchar2(15) not null, -- 单位代码(单位帐号)

emp_acc_no    varchar2(20) not null, -- 职工帐号

tran_date     date not null,         -- 交缴日期

tran_val      Number(7,2) not null,  -- 交缴额

sys_date      date default sysdate,  --系统日期

oper_id       varchar2(10)            --操作员代码

 

 

这样的表结构,一般按照将经办行作为行进行统计是很容易的,但是如果希望将经办行变为列这样的格式来输出就有困难。如果用DECODE函数来处理则变得很简单:

 

我们创建一个视图来对目前的pay_lst表进行查询。将经办行代码变为一些具体的经办行名称即可:

 

CREATE OR REPLACEVIEW  bank_date_lst  AS

Select  to_char(tran_date,’yyyy.mm’),

SUM( DECODE (bank_code,’001’, tran_val,0 )) 城西区,

SUM( DECODE (bank_code,’002’, tran_val,0 )) 城南区,

SUM( DECODE (bank_code,’003’, tran_val,0 )) 城东区

FROM pay_lst

GROUP BYto_char(tran_date,’yyyy.mm’);

 

 

 

 

 

 

例2.希望将下面的列结果按照列的方式来显示JOB内容:

 

SQL> selectempno,ename,job,sal,deptno from emp

  2 order by deptno,job;

 

     EMPNO ENAME      JOB              SAL     DEPTNO

-------------------- --------- ---------- ----------

      7934 MILLER     CLERK           1300         10

      7782 CLARK      MANAGER         2450         10

      7839 KING       PRESIDENT       5000         10

      7788 SCOTT      ANALYST         3000         20

      7369 SMITH      CLERK            800         20

      7876 ADAMS      CLERK           1100         20

      7566 JONES      MANAGER         2975         20

      7938 赵元杰     软件           12345         20

      7698 BLAKE      MANAGER         2850         30

      7499 ALLEN      SALESMAN        1600         30

      7654 MARTIN     SALESMAN        1250         30

      7844 TURNER     SALESMAN        1500         30

      7521 WARD       SALESMAN        1250         30

 

18 rows selected.

 

再看下面的查询结果:

 

SQL> selectdeptno,job,sum(sal) from emp group by deptno,job;

 

    DEPTNO JOB         SUM(SAL)

---------- -------------------

        10 CLERK           1300

        10 MANAGER         2450

        10 PRESIDENT       5000

        20 ANALYST         3000

        20 CLERK           1900

        20 MANAGER         2975

        20 软件           74070

        30 MANAGER         2850

        30 SALESMAN        5600

 

9 rows selected.

 

 

从上面的结果看,如果希望将JOB置换成列的方式,则只要用DECODE将JOB列进行描述即可。创建的视图如下:

 

create or replaceview empv as

select deptno,

sum( decode(job,’ANALYST’, sal,0)) ANALYST,

sum( decode(job,’CLERK’, sal,0)) CLERK,

sum( decode(job,’MANAGER’, sal,0)) MANAGER,

sum( decode(job,’PRESIDENT’, sal,0)) PRESIDENT,

sum( decode(job,’SALESMAN’, sal,0)) SALESMAN,

sum( decode(job,’软件’, sal,0)) 软件

from emp  group by deptno;

 

具体运行的显示样本如下:

SQL> create orreplace view empv as

  2 select deptno,

  3  sum(decode(job,'ANALYST', sal,0)) ANALYST,

  4  sum(decode(job,'CLERK', sal,0)) CLERK,

  5  sum(decode(job,'MANAGER', sal,0)) MANAGER,

  6  sum(decode(job,'PRESIDENT', sal,0)) PRESIDENT,

  7  sum(decode(job,'SALESMAN', sal,0)) SALESMAN,

  8  sum(decode(job,'软件', sal,0)) 软件

  9  fromemp  group by deptno;

 

View created.

 

SQL> select *from empv;

 

    DEPTNO   ANALYST      CLERK    MANAGER PRESIDENT   SALESMAN       软件

-------------------- ---------- ---------- ---------- ---------- ----------

        10          0       1300       2450       5000          0          0

        20      3000       1900       2975          0          0     74070

        30          0          0       2850          0       5600          0

 

§8.2  关于访问远程数据库

在许多环境中,都可能需要访问远程数据库。现在的Oracle8i/9I的NET都支持远程访问技术。只要环境网络具备和在参数文件中进行相应的配置就能在SQL语句中进行访问。关于环境的安装和配置另见DBA资料。

 

§8.2.1  数据库链接

Oracle本地要与远程进行连接,要通过数据库链接。

 

1.使用数据库链接进行查询和更新:

 

SELECT * fromworker;

 

这样的语句表示在本地进行查询。而对于远程,则需要在语句后加相应的数据库链接。如:

 

SELECT * FROM worker@remote_connect;

 

如果想省去@号后面的字串,可以采用建立一个本地的同义词来实现。如:

 

CREATE SYNONYMWORKER_SYN for WORKER@remote_connect;

 

如果希望进行远程更新的话,类似可以在UPDATE语句中加上远程连接符。如:

 

UPDATE worker@remote_connect

SET lodging=’CRANMER’ where lodging=’ROSEHILL’;

 

2.创建数据库链接的语法:

 

创建数据库链接的语法如下:

 

CREATE [PUBLIC]DATABASE LINK remote_connect

CONNECT TO usernameidentified by password using ‘connect string’;

 

一般PUBLIC有DBA来创建。个人用户可以不加PUBLIC就是私有的数据库链接。

Oracle系统可以创建链接,但是连接的数量有限制。缺省的并发数是4(由init.ora文件中的OP_LINKS来限制)。

 

为了建立数据库链接,需要有CREATEDATABASE LINKS 系统权限;要与远程的帐号进行连接还需要有CREATE SESSION普通权限。

 

CREATE database linkzhao connect to zhaoyuanjie identified by zhao_yuan_jie

Using ‘sun450’;

 

这样创建后,可以用下面语句来使用:

 

SELECT * from tst@sun450;

 

需要注意的是,在创建数据库链接时是根据Oracle的Tnsnames.ora参数文件中的连接字符串来填写连接字串。比如上面的连接字串是sun450 。则在tnsmaes.ora中的要有下面的数据项:

 

SUN450 =

  (DESCRIPTION =

    (ADDRESS_LIST =

      (ADDRESS = (PROTOCOL = TCP)(HOST =dbsvr)(PORT = 1521))

    )

    (CONNECT_DATA =

      (SERVICE_NAME = s450)

    )

  )

 

 

§8.2.2  使用同义词获得本地透明

在应用系统的生命周期内,为了方便和维护简便,经常采用建立同义词来实现透明的访问。

 

例1. 没有建立本地透明时的访问:

 

SELECT * FROMnorth.worker;

 

例2.建立一个同义词,然后进行访问:

 

CREATE SYNONYMWORKER FOR NORTH.WORKER;

 

SELECT * FROMWORKER;

 

 

在实际应用中,为了达到隐藏表的所有权,还可以通过使用数据库链接和同义词来隐藏数据的物理位置。通过使用对应远程端的本地表同义词,可以把另一个逻辑层从应用转移到数据库中。

 

例3.建立一个本地同义词的远程表:

 

CREATE SYNONYMWORKERSKILL

For  WORKERSKILL@remote_connect;

 

§8.2.3  在视图中使用user伪列

Oracle提供一个伪列user, 它可以在创建视图中使用,从而实现对结果的返回的限制。如:

 

CREATE OR REPLACEVIEW emp_lst

AS select * from emp

Where ename=user;

 

这样的视图表示,只有使用者的用户名与ename中的名字一样,才能返回相关的记录。看下面的结果就会明白:

 

SQL> CREATE ORREPLACE VIEW emp_lst

  2  ASselect * from emp

  3 Where ename=user;

 

View created.

 

SQL> select *from emp;

 

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM    DEPTN

---------- ---------- --------- ---------- ------------------- ---------- ---------

      7369 SMITH      CLERK           7902 17-DEC-80        800                    2

      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         3

      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         3

      7566 JONES      MANAGER         7839 02-APR-81       2975                    2

      7654 MARTIN    SALESMAN        769828-SEP-81       1250       1400         3

      7698 BLAKE      MANAGER         7839 01-MAY-81       2850                    3

      7782 CLARK      MANAGER         7839 09-JUN-81       2450                    1

      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    2

      7839 KING       PRESIDENT            17-NOV-81       5000                    1

      7844TURNER     SALESMAN        7698 08-SEP-81       1500          0         3

      7876 ADAMS      CLERK           7788 23-MAY-87       1100                    2

      7934MILLER     CLERK           7782 23-JAN-82       1300                    1

      7938 赵元杰     软件                23-SEP-01      12345      54321         2

      7939 赵元杰     软件                23-SEP-01      12345      54321         2

 

14 rows selected.

 

SQL> select * from emp_lst;

 

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM    DEPTN

---------- ---------- --------- ---------- --------- -------------------- ---------

      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    2

 

SQL>

 

上面结果显示,由于本用户的名字是scott,所以只显示ename=scott的记录。

 

 

§8.2.4  使用COPY功能

如果我们用 CREATETABLE xxx AS select * from tablename@remote_connect;  不能完成带Long等列的操作时,请你使用Oracle提供的COPY命令。COPY可以实现在CREATE TABLE复制表时所不能实现的功能。

 

COPY命令的语法如下:

 

COPY { FROMusername[/password]@database | TO

                        username[/password]@database |

              FROM username[/password]@databaseTO

                        username[/password]@database }

           { APPEND|CREATE|INSERT|REPLACE }

           destination_table[(col1,col2,...) ]USING query

 

参数说明:

APPEND  如果目标表已存在,将查询的记录插入该表中,

                 如果目标表不存在,则创建再插入所查询的记录。

CREATE  先创建目标表再插入所查询的记录,

                 如果目标表不存在,则提示错误。

INSERT    将查询(必须用 using query 查)的记录插入到目标表中,

                 如果目标表不存在,则提示错误。

REPLACE  将查询的记录替换到目标表中的内容,

                 如果目标表存在,则先删旧表内容再用拷贝表替换,

                 如果目标表不存在,则创建表。

使用copy 命令还需设置以下变量:

SQL>set  long n; /* 数据长度 */

SQL>setcopycommit  m;/* m行提交一次 */

SQL>setarraysize  n; /* 批操作的大小 */

 

 

 

例:

 

COPY from zhao/zhaoyuan@sun450

CREATE WORKER usingselect * from  WORKER;

 

 

§8.2.5  管理Oracle名称服务器

要保证与远程进程连接,DBA必须确保名称服务器配置的正确。另见DBA资料的“NET8 名称服务器”章节。

 

 

§8.3  关于上下文的使用

在Oracle系统中,可以支持对文本进行处理。要想对文本进行搜索,则需要对数据库环境进行设置。

 

§8.3.1  设置上下文选项

为了在数据库中使用上下文功能,先要设置上下文选项。用以启动数据库上下文处理进程。可以用CTXCTL实用程序来启动上下文服务器:

 

$CTXCTL

…  …

>help

 

The follwing commands are available:

Help[command]  -- 命令信息

Status          -- 正在运行的服务器情况

Start n [line |query | ddl | dml ] … --启动n服务进程

Stop  pid… |  all    --停止ctxctl

Quit                  -- 结束ctxctl

Exit                   --结束ctxctl

 

为了支持文本搜索,用户至少启动一个query上下文服务器。到底启动多少个服务器,要根据用户的要求决定。比如:

start 1 ddl dml query

start 1  query

服务器的当前情况可以从CTS_ALL_SERVERS数据字典来查询,如:

 

SQL>col ser_name for a30

Select ser_name,ser_status,set_started_at fromCTX-ALL_SERVERS;

 

从结果可看出已经启动的服务器,DBA可以在SQL>下用下面命令来停止服务的运行:

 

SQL>exec CTX_ADM.SHUTDOWN;

 

 

1.在init.ora参数文件中设置启动参数:

 

要使上下文有效,必须在Init.ora文件中设置下面参数:

 

text_enable= TRUE

 

也可以在SQL>下进行设置:

 

ALTER SESSION set text_enable = TRUE;

 

 

2.必要的角色:

 

在Oracle数据库中,上下文的数据字典属于CTXSYS用户所有。所以CTXSYS是唯一具有CTXADMIN角色的用户。此外,还有CTXAPP(应用程序所有)和CTXUSER(应用程序用户)角色。一般需要将CTXAPP授予开发上下文的用户。如:

 

grant  CTXAPP toscott;

 

§8.3.2  为上下文查询设置表

为了实现上下文的查询,需要在基表的某列建立主关键字和为表中的文本列设置相应的查询策略。比如有下面的求职表:

 

1.基本的设置:

 

1)创建基本表:

CREATE TABLE prospect( name  varchar2(20),

Address varchar2(40),

Resume  long )tablespace user_data

storage(initial  5mnext 1m pctincrease 0);

 

2)为prospect表建立一个主关键字:

ALTER table prospect add constraint prospect_pk  primary key ( name );

 

 

 

3)为prospect表建立定义策略:

 

为了在prospect 表上进行上下文的查询,需要用 Oracle提供的CREATE_POLICY过程来创建一个策略。CREATE_POLICY过程需要两个参数:策略名称 和 被索引列的名称。如:

 

exec CTX_DDL.CREATE_POLICY(‘prospect’,’ prospect.resome’);

 

2.显示和修改选项:

 

可以从CTX_PREFERENCE_USAGE数据字典视图中查出有关当前已经建立的策略信息。

 

1)显示策略信息:

例1.查询数据字典视图中的PROSPECT策略的信息:

 

SELECT PRE_NAME from CTX_PREFERENCE_USAGE

Where pol_name=’ PROSPECT’;

 

2)修改策略信息:

可以通过执行CTX_DDL_UPDATE_POLICY过程来对策略进行修改,如希望加SOUNDEX来对prospect进行查询:

 

EXEC CTX_DDL_UPDATE_POLICY( policy_name=>’ PROSPECT’,

Worldist_pref=>’CTXSYS.SOUNDEX’);

 

3)删除策略信息:

可以通过执行CTX_DDL_DROP_POLICY过程来实现删除某个策略。如:

 

EXEC CTX_DDL_DROP_POLICY( ’ PROSPECT’ );

 

 

3.建立文本索引:

 

要实现对文本的查询,除了设置参数外,还要用CTX_DDL包中CREATE_INDEX过程为表建立文本索引。要建立文本索引,要求具有CTXAPP角色。

1)建立文本索引:

EXEC CTX_DDL.CREATE_INDEX(‘prospect’);

 

如果出现错误,可能还没有启动DDL服务器,则要用CTXCTL来启动上下文服务器,在运行上面的建立索引命令。

 

2)生成数据库对象:

当创建文本索引完成后,系统就数据库中建立一些表,这些表存放支持策略的信息。可以从CTX_USER_POLICY数据字典中查到各个表及其策略。要查询策略信息,还需要与user_tables和user_indexes数据字典进行相关查询。

 

3)删除文本索引:

当不能修改文本策略索引或不再需要时,可以通过CTX_DDL.DROP_INDEX过程来删除文本索引。

 

例。删除一个索引:

 

EXEC CTX_DDL.DROP_INDEX(‘prospect’);

 

再查看数据字典的信息:

 

select pol_status from CTX_USER_POLICIES

where pol_name=’PROSPECT’;

 

§8.3.3  优化文本索引

在CTX_DDL包中提供了一个OPTIMIZE_INDEX过程来重建所有的文本索引。OPTIMIZE_INDEX过程可以对压缩索引中的碎片,并且去掉或删除文本数据项中的引用和其他相关的数据项。OPTIMIZE_INDEX过程的用法如下:

 

EXEC CTX_DDL .OPTIMIZE_INDEX(‘prospect’);

 

§8.4  关于维数(DIMENSION)

Oracle8i提供一种新功能叫维(DIMENSION),用于在一对列之间定义一个“父-子”关系,这些列的全部列必须来自同一个表。但是,对于一个列(或层)可以来自不同的表。优化器可以在实体化视图中利用这种“父-子”关系来进行查询改写。

要建立维,你必须有CREATE DIMENSION 系统权限。如果你要在其他的模式下建立维,则需要具有CREATE ANY DIMENSION 系统权限。

注意,在建立完成维后,Oracle系统会自动有效这些维,如果希望对建立的维有效,则需要指定hierarchy_clause和join_clause, 你必须用DBMS_OLAP.validate_dimension存储过程。

 

§8.4.1 CREATE DIMENSION语法

创建维的语法如下:

 

CREATE DIMENSION [schema.]dimension

LEVEL level IS (level_table.level_column )

 {

HIERARCHY hierarchy  ( child_level CHILD OF parent_level

                    JOIN KEY (child_key_column)

                    REFERENCES parent_level

                  ) |

ATTRIBUTE level  DEFERENCES ( dependent_column )

 }

 

schema

模式名字,如果没有指定模式名,则Oracle将你的用户名作为模式名。

 

dimension

维的名字,在模式下的维名字必须唯一。

 

level_clause

level_clause定义维的级,一个级定义一个层和属性

level  层的名字

level_table.level_column 级的列名,最多32级。有下面限制:

l  在级中的所有列必须来自同一个表;

l  不同级的列可以来自不同的表,但是必须指定join_clause;

l  所指定的一组列在该级中必须是唯一的;

l  所指定的列不能在另外的地方指定;

l  每个level_column必须是非空的(不是原来意义上的NOT NULL)。

 

 

hierarchy_clause

层在维数中定义一个线性的层,每个层概括一个父-子关系的链。在维中的层与其他层有关系,它们可以有一些列。

hierarchy 指定相同的级,这些级在维中必须是唯一的。

child_level 指定级中的名字。

 

join_clause

join_clause 可以为一个包括多个表的维指定一个内部的等价连接。

 

 

 

 

attribute_clause

attribute_clause可以指定唯一确定的列。在level中的列必须来自同一个dependent_columns所指的表。在level_clause 中,dependent_columns不需指定。

例如,层次级为:city、state和 country,则city是可以作为市长(mayor),而state可以确定为 州长(governor),而country确定为总统(president)。

 

§8.4.2  创建维的例子

 

下面例子在time_tab表中创建一个维 time 和在CITY、STATE、COUNTRY表中创建维geog

 

CREATEDIMENSION time

LEVELcurDate IS time_tab.curDate

LEVELmonth IS time_tab.month

LEVELqtr IS time_tab.qtr

LEVELyear IS time_tab.year

LEVELfiscal_week IS time_tab.fiscal_week

LEVELfiscal_qtr IS time_tab.fiscal_qtr

LEVELfiscal_year IS time_tab.fiscal_year

HIERARCHYmonth_rollup (

curDateCHILD OF

monthCHILD OF

qtrCHILD OF

year)

 

HIERARCHYfiscal_year_rollup (

curDateCHILD OF

fiscal_weekCHILD OF

fiscal_qtrCHILD OF

fiscal_year)

ATTRIBUTEcurDate DETERMINES (holiday, dayOfWeek)

ATTRIBUTEmonth DETERMINES (yr_ago_month, qtr_ago_month)

ATTRIBUTEfiscal_qtr DETERMINES yr_ago_qtr

ATTRIBUTEyear DETERMINES yr_ago ;

CREATEDIMENSION geog

LEVELcityID IS (city.city, city.state)

LEVELstateID IS state.state

LEVELcountryID IS country.country

HIERARCHYpolitical_rollup (

cityIDCHILD OF

stateIDCHILD OF

countryID

JOINKEY city.state REFERENCES stateID

JOIN KEY state.country REFERENCES countryID);

 

 

 


 

第九章  安全管理

在建立应用系统的各种对象(包括表、视图、索引等)前,就得先确定各个对象与用户的关系。也就是说,哪些用户需要建立,哪些用户都充当什么样的角色,他们应该有多大权限等。下面介绍基本的安全管理方面的内容,更详细的内容在DBA资料里介绍。

 

§9.1  CREATEUSER 命令

CREATE USER usernameIDENTIFIED BY password

  Or IDENTIFIEDEXETERNALLY

  Or IDENTIFIEDGLOBALLY AS ‘CN=user’

[DEAFULT TABLESPACEtablespace ]

[TEMPORARYTABLESPACE tablespace]

[QUOTA [integerK[M]][UNLIMITED] ON tablespace

[,QUOTA [integer K[M]][UNLIMITED] ONtablespace

[PROFILESprofile_name]

[PASSWORD EXPIRE]

[ACCOUNT LOCK orACCOUNT UNLOCK]

 

 

CREATE USER username用户名

IDENTIFIED BYpassword  用户口令

IDENTIFIED BYEXETERNALLY 用户名在操作系统下验证,这个用户名必须与操作

                        系统中所 定义的用户相同。

IDENTIFIED GLOBALLYAS ‘CN=user’ 用户名是ORACLE 安全域中心服务器来验证

                                 ,CN 名字标识用户的外部名。

[DEAFULT TABLESPACEtablespace ]  缺省的表空间

[TEMPORARYTABLESPACE tablespace] 缺省的临时表空间

[QUOTA [integerK[M]][UNLIMITED] ON tablespace 允许使用k[m]字节

[,QUOTA [integer K[M]][UNLIMITED] ONtablespace

[PROFILESprofile_name]  资源文件的名字

[PASSWORDEXPIRE]        立即将口令设成过期状态,用户在登录进入前必须

                         修改口令。

[ACCOUNT LOCK orACCOUNT UNLOCK]  用户不被加锁。


 

§9.2  建立用户

建立用户虽然不是经常的工作,但却是比不可少的工作。如果你的环境是一个较复杂的应用系统,你还是应该重视用户的建立和管理的事。下面是建立不同类型用户的方法。

§9.2.1  外部验证(Authenticated )用户

 外部识别的Oracle用户可以被客户端的操作系统验证,即在Oracle外放置了用于口令管理和用户验证的控制。此类登录不再需要Oracle 口令。操作系统验证的实现需要进行下面步骤:

 

1.  在INITsid.ORA文件中设置OS_AUTHENT_PREFIX 参数,在Oracle6里必须设置用户的前缀为OPS$。Oracle8可以不需要前缀OPS$。如在INITsid.ORA文件上加:

. . .

OS_AUTHENT_PREFIX=”OPS$”

. . .

 

2.  用CREATEUSER 建立外部用户:

 

CREATE USER ops$zhao IDENTIFIED BY EXTERNALLY;

 

如果在INITsid.ORA文件的OS_AUTHENT_PREFIX=””(即没有设置为OPS$),则:

 

CREATE USER zhao IDENTIFIED BY EXTERNALLY;

 

CREATE USER ops$zhaoyj IDENTIFIED BY EXTERNALLY

DEFAULT TABLESPACE users

TEMPORARY TABLESPACE temp

QUOTS UNLIMITED ON users

QUOTS UNLIMITED ON temp;

 

§9.2.2  全局(Globally)验证用户-企业验证

在Oracle数据库里,可以将用户配置成不需要验证口令的方式,用以替代来自X.509企业目录服务的口令检查。这种类型的用户一般都是在大的企业里的登录使用。一般企业验证启用Oracle安全服务(OSS)来实现单独的注册。建立全局验证的用户需要带 GLOABLLY AS 。如:

 

CREATE USER SCOTT IDENTIFIED GLOABLLY AS ‘CN=scott,

OU=division1, O=sybex, C=US’;

 

§9.3  ALTERUSER 命令

ALTER USER命令用于修改用户的资源限制和口令等。ALTER USER 命令语法如下:

 

ALTER USER usernameIDENTIFIED BY password

  Or IDENTIFIED EXETERNALLY

  Or IDENTIFIED GLOBALLY AS ‘CN=user’

[DEAFULT TABLESPACEtablespace ]

[TEMPORARYTABLESPACE tablespace]

[QUOTA [integerK[M]][UNLIMITED] ON tablespace

[,QUOTA [integer K[M]][UNLIMITED] ONtablespace

[PROFILESprofile_name]

[PASSWORD EXPIRE]

[ACCOUNT LOCK orACCOUNT UNLOCK]

[DEFAULT ROLE role[,role]

  or [DEFAULT ROLE ALL [EXEPT role[,role]]]or[DEFAULT ROLE NOTE]

 

 

例:比如用户使用的资源超出限额的话,就如下提示:

ORA-01536:SPACE QUOTA EXCEEDED FOR TABLESPACE ‘USERS’

这时需要对该用户增加资源限额:

 

SQLPLUSSYSTEM/MANAGER

SQL>ALTER USERsideny QUOTA 10M ON SYSTEM;

 

§9.4  DROP USER 命令

对于不再需要的用户,可以用DROPUSER 来将不要的用户从数据库系统中删除。以释放出磁盘空间。DROP USER语句的语法如下:

 

DROP USER user [CASCADE]

 

如果加CASCADE 则连同用户的 对象一起删除。

 

SQL>drop user zhao cascade;

 

提示:不要轻易使用 DROP USER 命令。只有在确认某个用户没有保留时才使用该命令。

 

§9.5  GRANT命令与REVOKE 命令

Oracle提供两个命令(grant和revoke)用于给用户(或角色)进行授权和从用户(或角色)中收回某些权限。GRANT可以给用户(或角色)授予对象的权限和系统权限。

 

§9.5.1  GRANT 命令

可以使用GRANT语句将权限或角色授予某个用户或角色。GRANT的语法如下:

 

GRANT system_privilege |role TO user | role | PUBLIC

[WITH ADMIN OPTION]

GRANT object_privilege |ALL column ON schema.object

FROM user | role | PUBLICWITH GRANT OPTION

 

system_privilege: 系统权限或角色

role: 角色

user: 被授予的用户或角色

object_privilege:对象的权限,可以是:

 

l   ALTER

l   DELETE

l   EXECUTE

l   INDEX

l   INSERT

l   REFERENCES

l   SELECT

l   UPDATE

 

例子:

SQL

GRANT CREATE TABLE TO gavaskar;

GRANT team_leader TO crystal;

GRANT  INSERT,  UPDATE ON sales  TO  larry WITH  GRANT  OPTION;

GRANT ALL TO PUBLIC;.

 

§9.5.2 REVOKE 命令

可以使用REVOKE语句从用户或角色中撤消某些权限。REVOKE的语法如下:

 

REVOKE system_privilege |role FROM user | role | PUBLIC

REVOKE system_privilege |role FROM user | role | PUBLIC

REVOKE object_privilege |ALL ON schema.object FROM user

| role | PUBLIC CASCADECONSTRAINTS

 

system_privilege: 系统权限或角色

object_privilege:对象的权限,可以是:

l  ALTER

l  DELETE

l  EXECUTE

l  INDEX

l  INSERT

l  REFERENCES

l  SELECT

l  UPDATE

 

例:

REVOKE ALTER TABLESPACEFROM john;

REVOKE GRANT ANY ROLE FROMtodd;

REVOKE manager FROM imran;

REVOKE INSERT ON sales FROMjaved;

REVOKE ALL ON marketingFROM terry;.

 

 

§9.6  权限和角色

为了管理复杂系统的不同用户,Oracle系统提供了角色和权限。权限可以使用户能访问对象或执行程序。而角色是一组权限的集合,同样,角色被授予用户后,用户也具有某些权限。Oracle有三种类型的权限:

 

l  对象权限(Object)

l  系统权限(System)

l  角色(Role)

 

§9.6.1  建立角色

角色是一组权限的集合。角色包含一个或多个权限;角色可以再包含角色。关于角色的详细描述参考另外的《Oracle8i初级数据库管理》--赵元杰著。

 

1.建立角色的命令语法如下:

 

CREATE ROLE role_name

 [ NOT INDENTIFIED |

  [ INDENTIFIED [BYpassword | EXTERNALLY|GLOABALLY] ]

 ];

 

 

role 指定角色名;

NOT IDENTIFIED 不需口令有数据库验证;

IDENTIFIED 需要口令,分别为三种情况:

l  BY password 指定本地用户口令,如果在建立角色时用口令,则用户在使用时也要给出口令。

l  EXTERNALLY 指定为外部用户,该用户用外部服务进行验证。

 

CREATEROLE role

NOTIDENTIFIED

IDENTIFIED

BYpassword

EXTERNALLY

GLOBALLY;

 

例:

 

CREATE ROLE vendor IDENTIFIED GLOBALLY;

 

2.三种标准角色:

 

自从Oracle6版本以后,Oracle系统一直有三种缺省的角色,即:

 

l  CONNECT ( 连接角色)

 

具有CONNECT角色用户,可以进行 SELECT ,INSERT,UPDATE和DELETE操作。

l  RESOURCE (资源角色)

具有RESOURCE角色的用户可以进行CONNECT所做的工作,此外,还可以进行CREATE TABLE、CREATESEQUENCE、CREATE PROCEDURE、CREATETRIGGER、CREATE INDEX及CREATECLUSTER等。

l  DBA(数据库管理员角色)

具有DBA角色的用户可以进行除 RESOURCE外,还可以进行数据库的管理操作。

 

§9.6.2  给角色授权

    一旦创建完角色,用户就可以给角色授权。给角色授权的GRANT语句在前面介绍。通过GRANT语句可以对角色授各种权限,如用户对象的访问权,系统权限等。如果用户具有DBA权限的话,则用户有GRANT ANYPRIVILEGE系统权限。可以对角色授予各种权限。如:

 

GRANT CREATE SESSION  TO clerk;

 

GRANT CREATE SESSION,CREATE Database link tomamager;

 

§9.6.3  授权角色给用户

如果角色创建完毕并且已经给角色授了相应的权限,用户就可以将角色授权给用户了。这样的操作完成后,被授角色的用户就有了相应的权限。要完成这样的操作,只要操作者具有GRANT ANY PRIVILEGE系统权限就可通过GRANT语句对用户授各种权限。如:

 

例。假设clerk是一个角色,则可以将它授予用户:

GRANT clerk TO  ZHAO;

 

§9.7 有关的数据字典

无论对数据库管理员或是一般的用户,对Oracle有关数据字典的了解程度是衡量是否真正掌握Oracle核心的关键。如果你了解基本的Oracle数据字典,对于各种系统的信息查询将大有好处。下面给出与安全管理有关的数据字典简单介绍。

 

§9.7.1  与用户、角色与权限有关的数据字典

与用户、角色、权限有关的数据字典主要有:

 

DBA_USERS            实例中有效的用户及相应信息。

V$SESSION            实例中会话的信息。

DBA_ROLES            实例中已经创建的角色的信息。

ROLE_TAB_PRIVS       授予角色的对象权限。

ROLE_ROLE_PRIVS      授予另一角色的角色。

ROLE_SYS_PRIVS       授予角色的系统权限。

DBA_ROLE_PRIVS       授予用户和角色的角色。

SESSION_ROLES        用户可用的角色的信息。

§9.7.2  查询数据字典信息

对于一般的软件人员来说,应该掌握对数据字典的基本查询,如:

 

例1。查看当前已经创建了多少用户和用户缺省的表空间:

 

SQL> set line 120

SQL> col usernamefor a26

SQL> coldefault_tablespace for a20

SQL> selectusername,DEFAULT_TABLESPACE,created from dba_users;

 

USERNAME                   DEFAULT_TABLESPACE   CREATED

---------------------------------------------- ----------

SYS                        SYSTEM               05-12月-01

SYSTEM                     TOOLS                05-12月-01

OUTLN                      SYSTEM               05-12月-01

DBSNMP                     SYSTEM               05-12月-01

AURORA$JIS$UTILITY$        SYSTEM               05-12月-01

OSE$HTTP$ADMIN             SYSTEM              05-12月-01

AURORA$ORB$UNAUTHENTICATEDSYSTEM         05-12月-01

ORDSYS                     SYSTEM               05-12月-01

ORDPLUGINS                 SYSTEM               05-12月-01

MDSYS                      SYSTEM               05-12月-01

ZHAO                       USERS                07-12月-01

SCOTT                      USERS                08-2月-02

 

已选择12行。

 

例2。查看当前已经创建了多少角色:

 

SQL> select *from dba_roles;

 

ROLE                           PASSWORD

--------------------------------------

CONNECT                        NO

RESOURCE                       NO

DBA                            NO

SELECT_CATALOG_ROLE            NO

EXECUTE_CATALOG_ROLE           NO

DELETE_CATALOG_ROLE            NO

EXP_FULL_DATABASE              NO

IMP_FULL_DATABASE              NO

RECOVERY_CATALOG_OWNER         NO

AQ_ADMINISTRATOR_ROLE          NO

AQ_USER_ROLE                   NO

 

ROLE                           PASSWORD

--------------------------------------

SNMPAGENT                      NO

OEM_MONITOR                    NO

HS_ADMIN_ROLE                  NO

JAVAUSERPRIV                   NO

JAVAIDPRIV                     NO

JAVASYSPRIV                    NO

JAVADEBUGPRIV                  NO

JAVA_ADMIN                     NO

JAVA_DEPLOY                    NO

TIMESERIES_DEVELOPER           NO

TIMESERIES_DBA                 NO

 

已选择22行。

 

SQL>

 

 


 

第十章 其它一些常见问题及技巧

下面给出一些对于初学者来是常见问题的一点描述,目的是使那些使用Oracle系统时间不长的人员能尽快适应在Oracle环境下的开发。

§10.1  一些常见问题

下面是一些初学者常遇到的问题的解释。如果你是一位Oracle的老手可以不阅读本章的内容。

§10.1.1 Oracle与2000年问题

l oracle 约定

l oracle在系统中一直用YYYY:MM:DD  HH24:MI:SS表示日期和时间

l ORACLE7   server和ORACLE8   server提供一种年格式掩码RR

 

规则转换如下表:

当前年度(最后两位数)    指定的两位数年

     (机器设置为)

       RR返回的年

      0~49                                0~49

      50~99                              0~49

      0~49                                50~99

      50~99                              50~99

 当前世纪(19XX)

 下个世纪(20XX)

 上个世纪(18XX)

 当前世纪(19XX)

 

l 当前年是在50~99后半世纪

 

1)如果输入00和99之间,oracle将被记为下个世纪,如在1996年输02,则被记为2002年。

2)如果输入50和99之间,oracle将被记为当前世纪,如在1996年输97,则被记为1997年。

l 当前年是在00~49前半世纪

 

1)如果输入00和49之间,oracle将被记为当前世纪,如在2001年时输02,则被记为2002年。

2)如果输入的两位年在50和99之间,oracle将被记为上个世纪,如在2001年输97,则被记为1997年。

 

l 例子

 

   Create  table   abc(datefld   date)

   Insert   into   abc   Value('01-JAN-11');

   Insert   into   abc   Value('01-JAN-90');

 

转换成1911年和1990年

Update    abc

Set  Datefld(d=To_date(To_datefld,'DD-MON-YY  HH24:MI:SS'),

       'DD_MON_RR   HH24:MI:SS');

SelectTo_char(Datefld,'DD-MON-YYYY')  Datefld    from abc;

           01-JAN-2011

           01-JAN-1990

 

 

建议:2000年问题在开发中的建议任何时应采用4位年表示如果用两位一定用YY或RR表示输入界面最好作判断和提示。

 

§10.1.2  如何正确插入日期数据

许多初学者都可能遇到这样的问题,就是往DATE类型的列插入日期数据时,经常被提示错误。

 

比如有下面的ABC表结构:

 

SQL> desc abc

 名称                          空?      类型

 ------------------------------------------------- ------------

 RQ                                DATE

 NAME                            VARCHAR2(20)

 

当用下面命令插入数据到ABC表时,系统提示如下信息:

 

SQL> insert intoabc values('02-JAN-2002','赵元杰');

insert into abcvalues('02-JAN-2002','赵元杰')

                       *

ERROR 位于第 1 行:

ORA-01843: 无效的月份

 

这是由于系统安装时的默认字符集引起的。虽然上面语句看上去没有错误,但是它不符合当前系统的日期格式要求。那么当前系统的日期格式是什么呢?我们可以用下面语句来查询:

 

SQL> selectsysdate from dual;

 

SYSDATE

----------

01-2月 -02

 

既然系统的日期格式是中文的月份,则将上面语句改为中文的月即可:

 

SQL> insert intoabc values('02-2月-2002','赵元杰');

 

已创建 1 行。

 

当然,你可以用altersession命令修改当前系统的日期格式为你喜欢的格式,如:

 

SQL> altersession set nls_date_format='yyyy/mm/dd';

 

会话已更改。

 

SQL> insert intoabc values('2002/02/02','赵元杰');

 

已创建 1 行。

 

SQL> select *from abc;

 

RQ         NAME

------------------------------

2002/02/02 赵元杰

2002/02/02 赵元杰

 

关于日期格式的有关资料,请参见《Oracle8I数据库管理员》--赵元杰著

 

§10.1.3  在查询中只返回满足条件的部分记录

有时,我们关心的查询结果不是所有的记录,而是关心所查询的内容的存在性。如果我们不加特别的限制,满足条件的所有记录会源源不断地显示在屏幕上。为了只显示少量的内容,oracle提供rownum伪列来限制在查询时返回的记录数。例如:

 

Select   *  from   dict   where  rownum < 10

 

Rownum是要显示的记录数

 

注意:

l 该用法在PL/SQL和Pro*C中常常不能用 ;

l 在条件中可以用 <= ,但不能用 = 或> 作判断。

 

 

§10.1.4  快速大量删除数据Truncate

在数据库管理操作中,经常需要将某个表的所有记录都删除而只保留表结构,这样的要求如果用delete 进行删除的话,Oracle系统会自动为该操作分配回滚段。如果回滚段较小,则可能导致操作失败。即使回滚段足够大,删除操作也需要较长的时间才能完成。为了加快删除操作,Oracle提供了一个特别的命令TRUNCATE,可以快速地完成对某个表的所有记录的删除。TRUNCATE的语法如下:

 

TRUNCATE [TABLE | CLUSTER]

schema.[table][cluster] [DROP | REUSE STORAGE]

 

删除表中或簇中的所有行,REUSE   STORAGE保留被删除的空间作为该表的新行使用:缺省为DROP   storge     即收回被删除的空间给系统。

特点:不可恢复。即不需rollback     segment,不在日志文件中记录信息。

 

§10.1.5 Rowid的使用

l oracle为每个表的每一条记录赋予一个唯一的标识号rowid;

l 它是一个伪列,虽然在定义表结构时并不声明它,但它自动地建立;

l 用desc查看表结构时并不显示该字段;

l ROWID 在进行UPDATE或DELETE操作中速度最快;

l Oracle7和Oracle8的ROWID不同。

 

SQL>select   name,sex,sal,rowid   from emp;

SQL>delete   from   emp   where   rowid='...XXXX.XX.XXXX';

 

l Oracle7的Rowid 由三个部分组成,结构为:

 

         block.row.file

格式为:

BBBBBBBB.RRRR.FFFF

 

BBBBBBBB 是文件的块号;RRRR 块中的行号;FFFF是文件的绝对号。

 

例0000000F.0000.00002

   第15数据块.第1行.第二个数据文件

 

 

l Oracle8和Oracle8i/9i的Rowid由四个部分组成,结构为:

 

OOOOOOFFFBBBBBBRRR

 

格式为:

 

l OOOOOO代表数据对象号,它表示数据库段的编号;

l FFF 代表在表空间中的相对文件号;

l BBBBBB代表在一个文件中的块号,块号与数据文件有关,与表空间无关;

l RRR代表块中行的位置号。

 

例1:查询记录中的ROWID列的值:

SQL> select *from emp;

 

ENAME                       SAL     DEPTNO TEL

------------------------------ ---------- -------------

赵元杰                 9999.12         10 1360 136 5681

赵元杰                 9999.12         10 1360 136 5681

 

 

例2:使用ROWID删除重复的记录。由于记录每个列的值完全一样,where 条件无法辨别,但是两条记录的ROWID号是不一样的。所以可以用ROWID作为条件。详细操作如下:

 

1)先查出记录:

 

SQL> selectename,sal,deptno,tel,rowid from emp;

 

ENAME               SAL     DEPTNO TEL                  ROWID

---------------------- ---------- -------------------- ------------------

赵元杰         9999.12         10 1360 136 5681        AAAFyUAADAAAAADAAA

赵元杰         9999.12         10 1360 136 5681        AAAFyUAADAAAAADAAB

 

2)看到两条记录的rowid不一样,可以使用chartorowid函数和rowid值完成删除操作:

 

SQL> delete fromemp where rowid = chartorowid('AAAFyUAADAAAAADAAB');

 

已删除 1 行。

 

3)删除操作完成,再查看emp表的数据:

 

SQL> selectename,sal,deptno,tel,rowid from emp;

 

ENAME               SAL     DEPTNO TEL                  ROWID

---------------------- ---------- -------------------- ------------------

赵元杰         9999.12         10 1360 136 5681        AAAFyUAADAAAAADAAA

 

从例子中可以看出,rowid的优势,建议在PL/SQL中的循环操作使用ROWID来提高处理速度。

 

§10.1.6  在查询中不让记录被更新

要保证在统计(查询)执行过程中,记录不被其他用户更新,则可以使用For   update子句进行加锁。这样在这个锁释放前其他用户不能对这些记录作update、delete和加锁。

 

SQL>Select   daptno  from    dept

         Where  deptno=25   For update;

 

如果你使用了FORUPDATE来对表进行加锁,组必须用commit来释放加锁的记录。

 

§10.1.7 EXCEPTIONS(违反完整性)问题

前面介绍的主键的创建方法,如果我们对表创建了主键后,那么在查入记录时,Oracle会自动对插入数据进行唯一性检查,当出现有数据违反唯一性限定的情况时,一般用户可能只看到ORA-0001  Dup_val_on_index ( 试图破坏一个唯一性限制 ) 类似的提示,而没有看是哪条记录违反唯一性限定。为了使用户有针对性地修改违反唯一性限定的记录,Oracle提供了一种方法可以容许用户捕获那些导致限定产生失败的行的信息。方法是:

 

l 用户生成一个列为EXCEPTION的表,创建该表的脚本是UTLEXCPT.SQL,你可以从oracle.../rdbms/admin目录中找。如:

 

SQL> startc:\oracle\ora81\rdbms\admin\utlexcpt

 

表已创建。

 

l 在建表时声明EXCEPTIONS。

 

l 激活EXCEPTIONS,如:

 

Alter   table   newspaper   enable   primary key

       Exceptions  into   EXCEPTIONS;

 

     EXCEPTIONS   表有四个列:

     Row_ID       违反限定的各行

     Ower         违反限定的拥有者

     Table_name   违反限定所在的表

     Constraint   行所在的限定

 

l 查看违反完整性的记录:

 

  Select  *   form   Newspaper

  Where   Rowid    in  (select  Row_id   from   EXCEPTIONS);

 

注:可能原版资料上将例外的表拼写成为 except_table ,其实脚本并不是这样。下面是原版资料的例子:

 

ALTER TABLE emp

ENABLE VALIDATE CONSTRAINT fk_deptno

EXCEPTIONS INTO except_table;

 

SELECT emp.*

FROM emp e, except_table ex

WHERE e.row_id = ex.row_id

AND ex.table_name = ’EMP’

AND ex.constraint = ’FK_DEPTNO’;

 

§10.1.8 Not  in和Not Exists

一般来说,在处理存在性检查中,用户都会看到Not  in 和Not  Exists 两个判断语句,但是它们在处理速度上有些不同。

 

Not  in 速度慢

Not  Exists 速度较快。

SQL>select  name,depart,zip

             From   export

          Where name  not  in (select  name  from xxx not  exists

           Item_application  where …)  and  rownum<6

           Order  by score;

 

§10.1.9  关于 COPY命令

可以弥补 createtable ... as  select ... from ...的和imp,exp 的不足,主要功能有:

1) 从一个本地数据库将一个或多个表拷贝到一个远程数据库;

2) 将一个表的一些记录拷贝到远程或本地库的其它表中;

3) 将包含 long 类型的表的一些列拷贝到其他表中;

4) 从一个oracle 数据库向一个非oracle数据库的拷贝表。

 

语法如下:

COPY { FROMusername[/password]@database | TO

                        username[/password]@database |

              FROM username[/password]@databaseTO

                         username[/password]@database}

           { APPEND|CREATE|INSERT|REPLACE }

           destination_table[(col1,col2,...) ]USING query

 

参数说明:

APPEND  如果目标表已存在,将查询的记录插入该表中,

                 如果目标表不存在,则创建再插入所查询的记录。

CREATE  先创建目标表再插入所查询的记录,

                 如果目标表不存在,则提示错误。

INSERT    将查询(必须用 using query 查)的记录插入到目标表中,

                 如果目标表不存在,则提示错误。

REPLACE  将查询的记录替换到目标表中的内容,

                 如果目标表存在,则先删旧表内容再用拷贝表替换,

                 如果目标表不存在,则创建表。

使用copy 命令还需设置以下变量:

SQL>set  long n; /* 数据长度 */

SQL>setcopycommit  m;/* m行提交一次 */

SQL>setarraysize  n; /* 批操作的大小 */

 

§10.1.10  列值为NULL情形的处理

对于编程人员来说,如果对列的空值(NULL)不注意而使处理结果不正确的情况还比较多。这主要是由于数学上的问题引起的,数学的数字运算是:null + 数字 = null 。这样的法则使我们在处理表中的列的值为空时会出现不正确的结果。请看下面操作:

 

例子:假设EMP表有下面的记录:

 

SQL> select *from emp;

 

ENAME               SAL     DEPTNO TEL                        COMM

---------------------- ---------- -------------------- ----------

赵元杰             9000         10 1360 136 5681              1000

张三               8898         10 123456                     1200

李四               7000         10 654321

 

从查询结果来看,李四的comm(奖金)没有值。当我们将sal+comm(工资+奖金)来列出结果时,则看到下面的结果:

 

SQL> selectename,sal,comm,sal+comm from emp;

 

ENAME               SAL       COMM  SAL+COMM

---------------------- ---------- ----------

赵元杰             9000       1000     10000

张三               8888       1200     10088

李四               7000

 

由于李四没有奖金(comm 列值为空),所以“工资”加“奖金”也变为“空”了。

 

对于这样的情形,请你务必记住使用 NVL 函数来解决。NVL函数的格式为:

 

NVL ( value,substitute)

 

即value为空时以substitute代替,可以将上面语句改为下面语句就正确了:

 

SQL> selectename,sal,comm,nvl(sal,0)+nvl(comm,0) from emp;

 

ENAME               SAL       COMM NVL(SAL,0)+NVL(COMM,0)

---------------------- ---------- ----------------------

赵元杰             9000       1000                  10000

张三               8888       1200                  10088

李四               7000                              7000

 

§10.1.11  使用 product_user_file来限制用户使用产品

缺省情况下,该表在oraclerdbms 中是不建立的,需要时可以system帐户下运行...\dbs\pupbld.sql即可建立该表,product_user_file表的结构如下:

product                产品名,sql*plus

userid                 被禁止的用户(大写)

attribute              被禁止的属性(具体命令)

scope                  用于非oracle 产品,用null替换

numeric_value      用于非oracle 产品, 用null替换

char_value         必需含'DISABLED'

date_value         用于非oracle 产品,用null替换

long_value         用于非oracle 产品,用null替换

 

例1:禁止scott用户使用sql*plus ,则

insert intoproduct_user_profile

  (product,userid,attribute,scope,numeric_value,

char_value,date_value,long_value)

values

('SQL*PLUS','SCOTT','HOST',NULL,NULL,'DISABLE',NULL,NULL);

 

例2:重新让scott用户使用sql*plus ,则

SQL>delete fromproduct_user_profile

Where userid='SCOTT'and attribute='HOST';

 

Attribute 可能的命令如下:

  COPY

  EDIT

  EXECUTE

  EXIT

  GET

  HOST

  QUIT

  PASSWORD

  RUN

  SAVE

  SET

  SPOOL

  START

  ALTER

  ANALYZE

  AUDIT

  CONNECT

  CREATE

  DELETE

  DROP

  GRANT

  INSERT

  LOCK

  NOAUDIT

  RENAME

  REVOKE

  SELECT

  SET ROLE

  SET TRANSACTION

  TRUNCATE

  UPDATE

  BEGIN

  DECLARE

 

§10.2  常用技巧

下面给出开发人员在工作中经常遇到的问题的解决方法。这里的所有例子都经过作者的精心调试通过。希望能对那些新手的读者有点帮助。

§10.2.1 long 类型的查询

由于在SQLPLUS 下的缓冲区有限,并且LONG的缺省长度为80 个字符。所以要查询LONG类型的字段时,需要设置 LONG的值为一个合适的值。如:

SQL>set  long  3000

SQL>col text for a90

SQL>select text from user_source;

 

§10.2.2  如何确定执行时间

在程序调试过程中,经常需要了解某个语句的执行时间。以选择较好的语句。用下面的设置可以显示每个语句所用去的时间(毫秒,毫秒/1000=秒)。

SQL> settiming on

SQL> selectcount(*) from emp;

 

 COUNT(*)

--------------

       14

 

 real: 190

SQL>

实际需要 190/1000=0.19秒

 

§10.2.3  如何终止用户会话

有时由于系统资源紧张或需要进行系统的整理时,都希望将与系统处于连接的用户会话进行终止。可以用下面命令分两步实现:

 

1)先查询出所有用户的信息:

SQL> selectsid,serial#,username,terminal from v$session;

 

      SID  SERIAL# USERNAME      TERMINAL

--------- --------------------------------------- ----------------

        1         1                ZHAOYUANJIE

        2         1                ZHAOYUANJIE

        3         1               ZHAOYUANJIE

        4         1               ZHAOYUANJIE

        5        1                ZHAOYUANJIE

        6         1               ZHAOYUANJIE

        7      505

        8      505

       11      370 SYS           ZHAOYUANJIE

 

9 rows selected.

 

 real: 190

SQL>

 

2)用ALTER system  kill  session ‘sid,serial#’ ;   来终止:

 

SQL>Alter system kill session ’11,370’;

 

如果希望一次终止多个会话,可以采用变量的方式更为快捷,如:

 

SQL> selectsid,serial#,username,terminal from v$session;

 

      SID  SERIAL# USERNAME                  TERMINAL

--------- --------------------------------------- ----------------

        1         1                                ZHAOYUANJIE

        2         1                                ZHAOYUANJIE

        3         1                                ZHAOYUANJIE

        4        1                                ZHAOYUANJIE

        5         1                                ZHAOYUANJIE

        6         1                                ZHAOYUANJIE

        7      833

        8      833

       11      370 SYS                            ZHAOYUANJIE

       13      370 SCOTT                        ZHAOYUANJIE

 

10 rows selected.

 

 

SQL> altersystem kill session '&sid,&ser';

Enter value forsid: 13

Enter value forser: 370

old   1: alter system kill session'&sid,&ser'

new   1: alter system kill session '13,370'

 

System altered.

 

 real: 100

 

§10.2.4  用TRANSLATE对数据加密和解密

TRANSLATE函数是一个变换函数,用它可以实现对存入表中数据进行加密和解密处理。函数语法如下:

 

REPLACE (‘string’ [,’string_in’,’string_out’])

 

String:希望被替换的字符串或变量。

String_in: 被替换字符串。

String_out: 要替换字符串。

 

例1:

PL/SQL

Var1:= REPLACE (‘Oracle’, ‘Or’, ‘Mir’,);

 

SQL

SELECT REPLACE (‘Oracle’, ‘Or’, ‘Mir’) “Example “ FROM DUAL;

Example

-------

Miracle

 

下面给出较复杂的例子,例1是一个 加密的存储过程,例2是用该过程进行加密的过程;例3是密的过程,例4是使用解密的过程:

 

例1:加密过程可以写成如下:

CREATE OR REPLACE FUNCTION ENCRYPT(INPASS IN VARCHAR2)

RETURN VARCHAR2 AS

STRING_IN VARCHAR(78);

STRING_OUT  VARCHAR2(39);

OFFSET NUMBER(2);

OUTPASS VARCHAR2(30);

BEGIN

OFFSET := TO_NUMBER(TO_CHAR(SYSDATE,’SS’))MOD 39;

STRING_IN := ‘YN8K1JOZVURB3MDETS5GPL27AXWIHQ94C6F0#$_’;

STRING_OUT :=’_$#ABCDEFGHIJKMNOPQRSTUVWXYZ0123456789’;

OUTPASS := SUBSTR(STRING_IN,OFFSET,1);

STRING_IN := STRING_IN||STRING_IN;

STRING_IN := SUBSTR(STRING_IN,OFFSET,39);

OUTPASS :=OUTPASS||TRANSATE(UPPER(INPASS),STRING_IN,STRING_OUT);

RETURN OUTPASS;

END;

 

例2:编写下面过程以调用ENCRYPT来加密:

DECLARE

X VARCHAR2(40);

BEGIN

X := ENCRYPT(‘HELLO’);

DBMS_OUTPUT.PUT_LINE(‘Encrypted:’|| X );

END;

 

SQL>set serveroutput on

SQL>/

Encrypted:#2PVV9

 

例3:编写一个针对例1的加密函数程序:

CREATE OR REPLACE FUNCTION DECRYPT(OUTPASS IN VARCHAR2)

  RETURN  VARCHAR2 AS

STRING-IN VARCHAR2(780;

STRING_OUT VARCHAR2(39);

OFFSET  NUMBER(2);

INPASS  VARCHAR2(30);

BEGIN

STRING_IN :=‘YN8K1JOZVURB3MDETS5GPL27AXWIHQ94C6F0#$_’;

STRING_OUT :=’_$#ABCDEFGHIJKMNOPQRSTUVWXYZ0123456789’;

OFFSET := INSTR(STRING_IN,SUBSTR(OUTPASS,1,1));

STRING_IN := STRING_IN||STRING_IN;

STRING-IN := SUBSTR(STRING_IN,OFFSET,39);

INPASS :=TRANSLATE(UPPER(SUBSTR(OUTPASS,2)),STRING_OUT,STRING_IN);

RETURN  INPASS;

END;

 

例4:编写一个调用解密的简单过程:

DECLARE

X  VARCHAR2(30);

BEGIN

  X := DECRYPT(‘#2PVV9’);

 DBMS_OUTPUT.PUT_LINE(X);

END;

 

§10.2.5  如何用查询来修改数据

有时需要用另外表的数据或本表的数据来修改某些记录。这样的应用在实际中经常使用。以下例子具有代表性:

 

例1:更新一个字段的情况:

 

UPDATE  DEPT SETDEPT_NAME=(SELECT DEPART_NAME FROM DEPART

   WHERE  DEPART.DEPTNO = DEPT.DEPTNO );

 

例2:更新多个字段的情况:

 

UPDATE  CHP8A

SET (DEPT_NAME,MGR_ID)=(SELECT

DEPART_NAME,MANAGER_ID FROM CHP8B

WHERE CHP8B.DEPART_NUMBER=CHP8A.DEPT_NO

AND ROWNUM=1)

WHERE EXIST(SELECT ‘X’ FROM CHP8B whereCHP8B.depart_number=CHP8a.dept_no);

 

 

§10.2.6  如何产生创建用户的脚本

有时,我们需要在新的环境创建用户,这些用户来自一个已经存在的应用环境中。比如希望重新创建用户的命令如何来产生。下面的例子从数据字典中查询数据自动完成创建用户、创建角色、授权角色给用户操作。

 

accept uname prompt'输入希望的用户名: '

spool c:\gen_user

 

SELECT username,'CREATE USER '||username||' '||

       DECODE(password, 'EXTERNAL', 'IDENTIFIEDEXTERNALLY',

              'IDENTIFIED BY '''||password||'''') lne,

       'DEFAULT TABLESPACE'||default_tablespace lne,

       'TEMPORARY TABLESPACE'||temporary_tablespace||';' lne

  FROM DBA_USERS

 WHERE USERNAME LIKE UPPER('%&&uname%')

    OR UPPER('&&uname') IS NULL

 ORDER BY USERNAME;

 

SELECT username,'ALTER USER '||username||' QUOTA '||

       DECODE(MAX_BYTES, -1, 'UNLIMITED',TO_CHAR(ROUND(MAX_BYTES/1024))||'K')

       ||' ON TABLESPACE'||tablespace_name||';' lne

  FROM DBA_TS_QUOTAS

 WHERE USERNAME LIKE UPPER('%&&uname%')

    OR UPPER('&&uname') IS NULL

 ORDER BY USERNAME;

 

spool off

 

 

§10.2.7  如何产生创建表结构的脚本

可以通过查询Oracle的数据字典USER_TABLES和USER_TAB_COLUMNS来产生创建表的脚本。这样的要求,其实主要是decode 函数的使用。下面给出两个例子。

 

例1.从USER_TAB_COLUMNS来产生创建表的脚本:

 

/************************************************************/

/*  功能:自动产生创建表的脚本                            */

/*  文件名:gen_cre_tab1.sql                                */

/*  作者:赵元杰                                            */

/*  日期:2001.12.10                                        */

/************************************************************/

set linesize 500

set pagesize 1000

set arraysize 8

set feedback off

set heading off

 

selectdecode(t1.column_id,1,'CREATE TABLE '||t1.table_name|| ' (', '   ') a,

   t1.column_name b,

   t1.data_type||decode(t1.data_type,'DATE',

                                    decode(t1.NULLABLE,'N',' not null'),

                      'VARCHAR2','('||to_char(t1.data_length)||')'||

                                     decode(t1.NULLABLE,'N','not null'),

                      'NUMBER',decode(t1.data_precision,null,‘ ‘ ,

                      '('||to_char(t1.data_precision)||

                    ','||to_char(t1.data_scale)||')' )

                     ||decode(t1.NULLABLE,'N','not null'),

                  'CHAR','('||to_char(t1.data_length)||')'||

                      decode(t1.NULLABLE,'N','not null'))||

         decode(t1.column_id,max(t2.column_id),');',',') c

FROMuser_tab_columns t1,user_tab_columns t2

WHERE    t1.table_name = t2.table_name and

   t1.table_name in (select distinctobject_name from user_objects

   where object_type='TABLE')

group byt1.column_id,t1.table_name,t1.data_type,t1.nullable,

   t1.data_length,t1.data_scale,t1.column_name,

    t1.data_precision

order byt1.table_name,t1.column_id;

 

例2.从USER_TABLES和USER_TAB_COLUMNS来产生创建表的脚本:

 

/************************************************************/

/*  功能:自动产生创建表的脚本和相应的存储参数              */

/*  文件名:gen_cre_tab2.sql                                */

/*  作者:赵元杰                                           */

/*  日期:2001.12.10                                        */

/************************************************************/

 

set linesize 500

set pagesize 1000

set arraysize 8

set feedback off

set heading off

selectdecode(t1.column_id,1,'CRE

你可能感兴趣的:(oracle)