select语句的两种不等于的写法

select *
from emp

where deptno<>30;

或者我们可以用下面的

select *
from emp
where deptno!=30;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
先登陆服务器: telnet 192.168.0.23 公帐号: openlab-open123 tarena-tarena 再进入SQL:sqlplus sd0807/sd0807 帐号:sd0807-密码同样 公帐号:openlab-open123 设置环境变量: ORACLE_SID=oral10g\ --变局部变量 export ORACLE_SID --变全局变量 unset ORACLE_SID --卸载环境变量 ORACLE_HOME=... --安装路径;直接用一句语句也可以,如下 export ORACLE_HOME=/oracledata/.../bin: 一、注意事项: 大小写不敏感,即不区分大小写。提倡关键字大写,便于阅读和调式。 “!”在SQL环境下执行Unix命令。 SQL语句是由简单的英语单词构成;这些英语单词称为关键字/保留字,不做它用。SQL由多个关键字构成。 SQL语句由子句构成,有些子句是必须的,有些是可选的。 在处理SQL语句时,其中所有的空格都被忽略(空格只用来分开单词,连续多个空格当一个用)。 SQL语句可以在一行上写出,建议多行写出,便于阅读和调试。 多条SQL语句必须以分号分隔。多数DBMS不需要在单条SQL语句后加分号,但特定的DBMS可能必须在单条SQL语句后加分号。 SQL语句的最后一句要以 “;”号结束 二、写子句顺序 Select column,group_function From table [Where condition] [Group by group_by_expression] [Having group_condition] …… [Order by column]; --最后 三、常用简单语句: clear screen:清屏 edit:编辑刚才的一句。 desc/describe:(列出所有列名称) 用法: DESCRIBE [schema.]object[@db_link] dual:亚表,临时用。如:desc dual;/from dual; rollback:回溯,回溯到上次操作前的状态,把这次事务操作作废,只有一次(DDL和DCL语句会自动提交,不能回溯)。 可以用commit语句提交,这样就回溯不回了。 set pause on\off :设置分屏(设置不分屏) set pause "please put an enter key" 且 set pause on:设置带有提示的分屏 oerr ora 904 :查看错误 set head off :去掉表头 set feed off :去掉表尾 保存在oracle数据库中的所有操作细节: spool oracleday01.txt :开始记录 spool off :开始保存细节 四、SELECT语句:选择操作、投影操作。 select:从一个或多个表中检索一个或多个数据列。包含信息:想选择什么表,从什么地方选择。必须要有From子句。(最常用) 当从多张表里查询的时候,会产生笛卡尔积;可用条件过滤它。 当两个表有相同字段时必须加前缀,列名前需加表名和“.”,如“s_emp.id”。 1、用法:SELECT columns,prod2,prod3<列> FROM Table1,table2<表名> 分号结束 如: select id from s_emp; select last_name,name from s_emp,s_dept where s_emp.dept_id=s_dept.id;--列表每人所在部门 SELECT * FROM Products; --检索所有列。 数据太多时,最好别使用上句,会使DBMS降低检索和应用程序的性能。(*通配符) 2、对数据类型的列可进行运算(如加减乘除)。 3、对列起别名:有直接起别名,加AS起别名,用双引号起别名等三种方法 (单引号,引起字符串;双引号,引起别名。起别名有符号,或者区分大小写时,必须用双引号) 多表查询时,可给表起别名。(给列起别名,列<空格>列别名;给表起别名,表<空格>表别名;)。 如:Select first_name EMPLOYEES, 12*(salary+100) AS MONEY, manager_id "ID1" From s_emp E; 4、字段的拼接,可用双竖线(双竖线只能用于select语句里)。不同的DBMS可能使用不同的操作符;拼接的字段同样可以起别名。 如:Select first_name ||' '|| last_name || ', '|| title "Employees" From s_emp; 排他锁:Select id,salary From s_emp where id=1 For Update; 可以阻止他人并发的修改,直到你解锁。 如果已有锁则自动退出:Select id,salary From s_emp where id=1 For Update NoWait; FOR UPDATE :可以再加 OF 精确到某格。如: ... For Update OF salary ... 注意要解锁。 五、ORDER BY 子句,排序 Order by:按某排序列表(默认升序 asc,由低到高;可加 desc,改成降序由高到低) 检索返回数据的顺序没有特殊意义,为了明确地排序用 SELECT 语句检索出的数据,可使用 ORDER BY 子句。 ORDER BY 子句取一个或多个列的名字。 对空值,按无穷大处理(升序中,空值排最后;降序中排最前)。 1、用法:Select prod_id,prod_price,prod_name From Products Order By prod_price,prod_name; (从左到右执行排序,先排price) ORDER BY子句中使用的列将是为显示所选择的列,但是实际上并不一定要这样,用非检索的列排序数据是完全合法的。 为了按多个列排序,列名之间用逗号分开。 2、支持按相对列位置进行排序。 输入 SELECT prod_id,prod_price,prod_name FROM Products ORDER BY 2,3 --(2指price,3指name) 3、升序、降序。默认是升序(asc,从小到大排序),想降序时用desc。 如:SELECT prod_id,prod_price,prod_name FROM Products ORDER BY prod_price DESC; 注意:DESC 关键字只应用到直接位于其前面的列名。如果想在多个列上进行排序,必须对每个列指定DESC关键字。 升序是默认的,可不写,但降序必须写。 六、WHERE子句,选择、过滤 其后只能跟逻辑语句,返回值只有ture或false 如: select last_name,salary from s_emp where salary=1000;--找出工资1000的人 WHERE子句操作符: 1、逻辑比较运算符 = 等于 != 不等于,还有(<> ^= 这两个同样表示不等于) > 大于 >= 大于等于 < 小于 <= 小于等于 2、SQL 比较运算符 between…and… :在两者之间。(BETWEEN 小值 AND 大值) 如:select last_name,salary from s_emp where salary between 1000 and 1500; --工资1000到1500的人,包括1000和1500。 in(列表):在列表里面的。 如:select last_name,dept_id from s_emp where dept_id in(41,42);第41、42部门的人 like : 包含某内容的。模糊查询 可以利用通配符创建比较特定数据的搜索模式,通配符只能用于文本,非文本数据类型不能使用通配符。 通配符在搜索模式中任意位置使用,并且可以使用多个通配符。 通配符%表示任何字符出现任意次数;还能代表搜索模式中给定位置的0个或多个字符。下划线匹配单个任意字符。 如:select table_name from user_tables where table_name like 'S\_%' escape'\'; ' 找出“S_“开头的,由于下划线有任意字符的含义,故需另外定义转移符。 但习惯用“\”,为方便其他程序员阅读和检测,一般不改用其他的。 like 'M%':M开头的 like '_a%':第二个字符是a的 like '%a%'所有含a的 (“_”表示一个任意字符;“%”表示任意多个任意字符。) 单引号里面的内容,大小写敏感。单引号用来限定字符串, 如果将值与串类型的列进行比较,则需要限定引号;用来与数值列进行比较时,不用引号。 is null:是空。(NULL表示不包含值。与空格、0是不同的。) 如:SELECT prod_name,prod_price FROM Products WHERE prod_price IS NULL; 七、高级检索(逻辑运算符): 通常我们需要根据多个条件检索数据。可以使用AND或OR、NOT等连接相关的条件 计算次序可以通过圆括号()来明确地分组。不要过分依赖默认计算次序,使用圆括号()没有坏处,它能消除二义性。 and:条件与 如 SELECT prod_id,prod_price,prod_name FROM Products WHERE prod_price<4 AND vend_id=‘DELL’ or:条件或 (注: and 的优先级比 or 更高,改变优先级可用括号) 如 SELECT prod_id,prod_price,prod_name FROM Products WHERE prod_price<4 OR vend_id=‘DELL’ not:条件非。否定它之后所跟的任何条件 否定的SQL 比较运算符: NOT BETWEEN; NOT IN; NOT LIKE; IS NOT NULL: (注意,按英语习惯用 is not,而不是 not is) NOT 与 IN 在一起使用时,NOT 是找出与条件列表不匹配的行。 IN 列表里有 NULL 时不处理,不影响结果;用 NOT IN 时,有 NULL 则出错,必须排除空值再运算。 in :选择列表的条件 使用IN操作符的优点: 在长的选项清单时,语法直观; 计算的次序容易管理; 比 OR 操作符清单执行更快;最大优点是可以包含其他 SELECT 语句,使用能够动态地建立 WHERE 子句。 如 SELECT prod_id,prod_price,prod_name FROM Products WHERE vend_id IN(‘DELL’,’RBER’,’TTSR’); 八、单行函数: 函数一般在数据上执行,它给数据的转换和处理提供了方便。不同的DBMS提供的函数不同。 函数可能会带来系统的不可移植性(可移植性:所编写的代码可以在多个系统上运行)。 加入注释是一个使用函数的好习惯。 大多数SQL实现支持以下类型的函数: 文本处理, 算术运算, 日期和时间, 数值处理。 Null:空值 空值当成无穷大处理,所有空值参与的运算皆为空。 空值与空值并不相等,因为空值不能直接运算。 如:prod_price="" 这种写法是错的(不要受到corejava的影响) prod_price=NULL 这种写法是错的(不要受到corejava的影响) prod_price IS NULL 这种写法才是对的 NVL:处理空值,把空值转化为指定值。可转化为日期、字符、数值等三种(注意:转化时,两参数必须要同类型) 如:NVL(date, '01-JAN-95') NVL(title,'NO Title Yet') NVL(salary,0) 错误写法Select last_name,title,salary*commission_pct/100 COMM From s_emp;--没提成的人没法显示工资 正确写法Select last_name,title,salary*NVL(commission_pct,0)/100 COMM From s_emp;--把提成是空值的转化为0 DISTINCT:过滤重复 把重复的行过滤掉;多个字段组合时,只排除组合重复的。 DISTINCT必须使用列名,不能使用计算或者表达式。 所有的聚合函数都可以使用。如果指定列名,则DISTINCT只能用于COUNT(列名),DISTINCT不能用于COUNT(*)。 如:Select Distinct name From s_dept; Select Distinct dept_id,title From s_emp; 文本处理: TRIM()/LTRIM()/RTIRM():去空格。只能去掉头和尾的空格,中间的不理。 trim(' heo Are fdou ') --> heo Are fdou 输入:select trim(' heo Are fdou ') from dual; -->:heo Are fdou LOWER:转小写 lower('SQL Course') --> sql course UPPER:转大写 upper(' SQL Course') --->SQL COURSE INITCAP:首字母转大写,其余转小写 initcap(SQL Course') '--> Sql Course CONCAT:合成。双竖线只能在select语句里面用,这个可用于任何语句。 Concat('Good','String') --> GoodString SUBSTR:截取。 Substr('String', 1 ,3) --> Str 第一个数字“1”,表示从第几个开始截取;若要从倒数第几个开始,用负数,如“-2”表示倒数第2个。 上式中第2个数字“3”表示截取多少个。 LENGTH:统计长度。 Length('String') --> 6 NVL:转换空值 日期和时间处理: Oracle日期格式:DD-MMM-YYYY (D代表日期date,M代表月month,Y代表年year) 如:SELECT prod_name (DAY表示完整的星期几,DY显示星期的前三个字母) FROM Products WHERE prod_time BETWEEN to_date(’01-JAN-2008’) AND to_date(’31-DEC-2008’); 日期可以进行加减,默认单位是1天。日期与日期可以相减,得出天数;日期与日期但不能相加。 sysdate -> 系统的当天 Months_Between('01-Sep-95','11-Jan-94') --> 19.774194 相差多少个月,Between里面也可以填函数。 Add_months('11-Jan-94',6) --> 11-Jul-94 增加多少个月 Next_day('01-Sep-95','Friday') --> '08-Sep-95' 下一个星期五。其中的'Friday'可用6替代,因为星期日=1 Last_day('01-Sep-95') --> '30-Sep-95' 这个月的最后一天 数值处理:可以运用于代数,三角,几何 ROUND:四舍五入 Round(45.925,2) -> 45.93 Round(45.925,0) -> 46 Round(45.925,-1) -> 50 逗号前一个数是要处理的数据源,后一个参数表示保留多少位小数。 后一参数是负数时,表示舍去小数点前的几位,例3是舍去个位及其后的。不写后一参数时,默认不保留小数。 TRUNC:舍去末位。直接舍去,不会进位。 Trung(45.925,2) -> 45.92 Trung(45.925,2) -> 45.92 Trung(45.925,2) -> 45.92 日期的舍取: 常用的数值处理函数有: ABS() 绝对值 ABS(-5741.5854) --> 5741.5854 PI() 圆周率 注意:oracle中不支持 PI()函数;MYSql 支持PI()函数。 SIN() 正统值 Oracle还支持COS()、ASIN()、ACOS()函数 SQRT() 平方根 转化: TO_CHAR(number,'fmt'):把数值转换成字符串 显示数字的命令 9:正常显示数字; 0:显示包括0的数值形式,空位强制补0; $:以美元符号显示货币; L:按当前环境显示相关的货币符号; . 和,:在固定位置出现“.”点 和“,”逗号;不够位时,四舍五入。 例题:SQL> select 'Order'||To_char(id)|| 2 'was filled for a total of' 3 ||To_char(total,'fm$9,999,999') 4 from s_ord 5 where ship_date ='21-SEP-92'; TO_NUMBER(char):把字符转换成数字 九、链接 内链接:严格匹配两表的记录。 外链接分左链接和右链接: 会使用一方表中的所有记录去和另一格表中的记录按条件匹配,空值也会匹配,这个表中的所有记录都会显示, 数据库会模拟出记录去和那些不匹配的记录匹配。 左链接 加号在右面 如:有 TABLE1 TABLE2 1的一条记录在2里面没有匹配上,那么1里面的记录保留 2的一条记录在1里面没有匹配上 ,那么2丢弃 右链接正好相反 --例题:哪些人是领导。 select distinct b.id,b.last_name manager from s_emp a,s_emp b where a.manager_id=b.id(+); 左右顺序有区别,这是另外新建一个表,要显示的是第二个表格的内容。 +放在没有匹配行的表一侧,令表格能完整显示出来。 标准写法:内连接用INNER,左连接用LEFT,右连接用RIGHT。 select distinct b.id,b.last_name manager from s_emp a LEFT join s_emp b ON a.manager_id=b.id; 十、组函数: 分组允许将数据分为多个逻辑组,以便能对每个组进行聚集计算。 Group:分组 Group by:分组。(默认按升序对所分的组排序;想要降序要用 order by)可以包括任意数目的列。 如果嵌入了分组,数据将在最后规定的分组上进行汇总。 GROUP BY 子句中列出的每个列都必须是检索列或有效的表达式,但不能是聚集函数。 *如果在SELECT 中使用表达式,则必须在GROUP BY子句中指定相同的表达式,不能使用别名。 除聚合计算语句外,SELECT语句中的每个列都必须在GROUP BY子句中给出。 如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL,它们将分为一组。 Having:过滤。分组之后,不能再用where,要用having 选择过滤。Having不能单独存在,必须跟在group by后面。 WHERE在数据分组前进行过滤,HAVING在数据分组后过滤。 可以在SQL中同时使用 WHERE和HAVING,先执行WHERE,再执行HAVING。 聚合函数: AVG:平均值 (忽略值为NULL的行,但不能用 AVG(*)) COUNT:计数 (Count(列)不计算空值;但 COUNT(*)表示统计表中所有行数,包含空值) MAX:最大值 (忽略列值为 NULL 的行。但有些DBMS还允许返回文本列中的最大值, 在作用于文本数据时,如果数据按照相应的列排序,则 MAX()返回最后一行。) MIN:最小值 (忽略值为 NULL 的行。不能用 MIN(*)。一般是找出数值或者日期值的最小值。 但有些DBMS还允许返回文本列中的最小值,这时返回文本最前一行) SUM:求和 (忽略值为 NULL 的值。SUM 不能作用于字符串类型,而 MAX(),MIN()函数能。也不能 SUM(*)) 子查询:查询语句的嵌套 可以用于任意select 语句里面,但子查询不能出现 order by。 子查询总是从内向外处理。作为子查询的SELECT 语句只能查询单个列,企图检索多个列,将会错误。 如:找出工资最低的人select min(last_name),min(salary) from s_emp; 或者用子查询select last_name,salary from s_emp where salary=(select min(salary) from s_emp); E-R图:属性: E(Entity) -R(Relationship) * (Mandatory marked 强制的) 强制的非空属性 o (Optional marked 可选的) 可选属性(可以有值也可以没有) #* (Primary marked ) 表示此属性唯一且非空 约束:针对表中的字段进行定义的。 PK:primary key (主键约束,PK=UK+NN)保证实体的完整性,保证记录的唯一 主键约束,唯一且非空,并且每一个表中只能有一个主键,有两个字段联合作为主键, 只有两个字段放在一起唯一标识记录,叫做联合主键(Composite Primary Key)。 FK:foreign key (外建约束)保证引用的完整性,外键约束,外键的取值是受另外一张表中的主键或唯一值的约束,不能够取其他值, 只能够引用主键会唯一键的值,被引用的表,叫做parent table(父表),引用方的表叫做child table(子表); child table(子表),要想创建子表,就要先创建父表,后创建子表,记录的插入也是如此,先父表后子表, 删除记录,要先删除子表记录,后删除父表记录, 要修改记录,如果要修改父表的记录要保证没有被子表引用。要删表时,要先删子表,后删除父表。 U:unique key(唯一键 UK),值为唯一,不能重复。 在有唯一性约束的列,可以有多个空值,因为空值不相等。 NN:NOT NULL,不能为空。 index(索引)是数据库特有的一类对象,实际应用中一定要考虑索引,view(示图) 数量关系: 一对一关系 多对一关系 一对多关系 多对多关系 范式: 好处:降低数据冗余;减少完整性问题;标识实体,关系和表 第一范式(First normal form:1Nf),每一个属性说一件事情。所有的属性都必须是单值,也就是属性只表示单一的意义。 (记录可以重复,会有大量冗余,没有任何限制) 第二范式(2N范式),最少有一个属性要求唯一且非空PK,其他跟他有关联(记录不可重复,但是数据可能会出现冗余)。 第三范式(3N范式),非主属性只能依赖于主属性,不能依赖于其他非主属性。(解决数据冗余问题,不能存在推理能得出的数据) 一般情况会做到第三范式。 创建表: Create Table 表名 (字段名1 类型(数据长度)(default ...) 约束条件, 字段名2 类型(数据长度) 约束条件 ); 建表的名称: 必须字母开头;最多30字符;只能使用“A~Z、a~z、0~9、_、$、#”; 同一目录下不能有同名的表;表名不能跟关键字、特殊含意字符同样。 如:create table number_1 (n1 number(2,4), n2 number(3,-1), n3 number); create table t_sd0808(id number(12) primary key,name varchar(30) not null); MySQL的: create table student (oid int primary key, ACTNO varchar(20) not null unique, BALANCE double); --MySQL的number类型分小类了,Oracle只有number,且MySQL的数值型不用定大小 Oracle的: create table t_ad (oid number(15) primary key, ACTNO varchar(20) not null unique,BALANCE number(20)); INSERT:插入(或添加)行到数据库表中的关键字。 插入方式有以下几种:插入完整的行;插入行的一部分;插入某些查询的结果。 对于INSERT操作,可能需要客户机/服务器的DBMS中的特定的安全权限。 插入行(方式一) INSERT INTO products VALUES(2008,’TV’,222.22,’US’); 依赖于表中定义的顺序,不提倡使用。有空值时需要自己补上。 插入行(方式二) INSERT INTO products(id,name,price,vend_name) VALUES(2008,’TV’,222.22,’US’); 依赖于逻辑顺序,会自动补上空值,提倡使用。 插入检索出的数据:可以插入多条行到数据库表中 INSERT INTO products(*,*,*,*) SELECT *,*,*,* FROM products_copy; 如果这个表为空,则没有行被插入,不会产生错误,因为操作是合法的。 可以使用WHERE加以行过滤。 复制表: 将一个表的内容复制到一个全新的表(在运行中创建,开始可以不存在) CREATE TABLE 新表名 AS SELECT * FROM 表名; INSERT INTO 与 CREATE TABLE AS SELECT 不同,前者是导入数据,而后者是导入表。 任何SELECT选项和子句都可以使用,包括WHERE和GROUP BY。 可利用联接从多个表插入数据。不管从多少个表中检索数据,数据都只能插入到单个表中。 更新数据 UPDATE 语句 需要提供以下信息:要更新的表;列名和新值;确定要更新的哪些行的过滤条件。 UPDATE 表名 SET vend_name = ‘HP’, prod_name = ‘NEWCOMPUTER’ WHERE vend_name = ‘IBM’; --UPDATE 语句中可以使用子查询,使得能用SELECT语句检索出的数据更新列数据。也可以将一个列值更新为 NULL。 删除数据 DELETE 语句 DELETE FROM products WHERE prod_name = ‘COMPUTER’; 全行删除,不要省略WHERE,注意安全。 DELETE不需要列名或通配符。删除整行而不是删除列。DELETE是删除表的内容而不是删除表。 如果想从表中删除所有内容,可以使用TRUNCATE TABLE语句(清空表格),它更快。 数字字典表: Sequence:排列。存储物理地址 Index:索引。依附于表,为提高检索速度。 View:视图。看到表的一部分数据。 限制数据访问。简化查询。数据独立性。本质上是一个sql查询语句。 Create[or Relace][Force|noForce] View 视图名 [(alias[,alias]…)] 别名列表 As subquery [With Check Option [Constraint ……]] [With Read Only] 注意:有些DBMS不允许分组或排序视图,不能有 Order by 语句。可以有 Select 语句。 删除视图: DROP VIEW 视图名 Rownum:纬列。内存里排序的前N个。 在where语句中,可以用=1,和<=N 或 <N;但不能用=N 或 >N。 因为这是内存读取,没有1就丢弃再新建1。只能从1开始。需要从中间开始时,需二重子rownum语句需取别名。 经典应用: Top-n Analysis (求前N名或最后N名) Select [查询列表], Rownum From (Select [查询列表(要对应)] From 表 Order by Top-N_字段) Where Rownum <= N 分页显示: --取工资第5~10名的员工(二重子rownum语句,取别名) select rn,id,last_name,salary From ( select id,last_name,salary,Rownum rn From (Select id,last_name,salary from s_emp order by salary desc) where rownum <= 10) where rn between 5 and 10; Union:合并表 Select … Union Select… 把两个Select语句的表合并。 要求两表的字段数目和类型按顺序对应。合并后的表,自动过滤重复的行。 Intersect:交。 同上例,把两个Select表相交。 Minus:减。 把相交的内容减去。 not exists 除运算。 添加字段(列): Alter Table 表名 Add (column dataype [Default expr][Not Null] [,column datatype]…); 添加有非空限制的字段时,要加Default语句 字段名字不可以直接改名,需要添加新字段,再复制旧字段后删除旧字段。 添加约束: Alter Table 表名 Add [CONSTRAINT constraint] type (column); 添加非空约束时,要用Modify语句。 查看约束名时,可以违反约束再看出错提示;或者查看约束字典desc user_constraints 减少字段: Alter Table 表名 Drop (column [,column]…); 删除约束: Alter Table 表名 Drop CONSTRAINT column; 或: Alter Table 表名 Drop Primary Key Cascade; 暂时关闭约束,并非删除: Alter Table 表名 Disable CONSTRAINT column Cascade; 打开刚才关闭的约束: Alter Table 表名 Enable CONSTRAINTcolumn; 修改字段: Alter Table 表名 Modify (column dataype [Default expr][Not Null] [,column datatype]…); 修改字段的类型、大小、约束、非空限制、空值转换。 删除表: 会删除表的所有数据,所有索引也会删除,约束条件也删除,不可以roll back恢复。 Drop Table 表名 [Cascade Constraints]; 加 [Cascade Constraints] 把子表的约束条件也删除;但只加 [Cascade]会把子表也删除。 改表名: Rename 原表名 To 新表名; 清空表格: TRUNCATE TABLE 表名; 相比Delete,Truncate Table清空很快,但不可恢复。清空后释放内存。 Delete 删除后可以roll back。清空后不释放内存。
1 SQL基础 1.1 基本概念 结构化查询语言(Structured Query Language)简称SQL,是一种关系数据库查询语言,用于存取数据以及查询、更新和管理关系数据库系统。 1.2 语句结构 1.2.1 数据查询语言(DQL) 对数据库进行的信息查询,select。 1.2.2 数据操作语言(DML) 用于操作关系型数据库对象内部的数据,insert、update、delete。 1.2.3 数据定义语言(DDL) 用来建立及定义数据表、字段以及索引等数据库结构,create、alter、drop 。 1.2.4 数据控制语言(DCL) 用于控制对数据库里数据的访问,通常用于创建与用户访问相关的对象以及控制用户的权限,grant、revoke(撤销)。 1.2.5 事务控制命令(TPL) 用于管理数据库事务,commit、rollback、savepoint(在一组事务里创建标记点以用于回退)。 1.3 表的构成 1.3.1 字段 字段是表里的一列,用于保持每条记录的特定信息 1.3.2 记录 记录,也被成为一行数据,是表里的每一行 1.4 完整性的约束条件 1.4.1 实体完整性 关系模型的实体完整性在create table中用primary key约束实现,primary key约束用于定义主键,它保证主键的唯一性和非空性。 1.4.2 参照完整性 关系模型的参照完整性可以通过在create table中用foreign key (<外键>) references <被参照表名> (<与外键对应的主键名>)进行约束定义。 1.4.3 用户定义完整心 在create table语句中可以根据应用要求,定义属性以及元组上的约束。 常见的用户定义的完整性约束有: not null或null约束。 unique约束:唯一性约束。 default约束:默认值约束。 check约束:检查约束,check约束通过约束条件表达式设置列值应该满足的条件。 1.5 范式 1.5.1 第一范式 1.5.1.1 规范 无重复的列,确保每列保持原子性,即数据库表中的所有字段值都是不可分解的原子值。 1.5.1.2 举例 姓名 年龄 联系电话 地址 省 市 详细地址 1.5.2 第二范式 1.5.2.1 规范 属性完全依赖于主键,确保表中每列都与主键相关。 1.5.2.2 举例 订单表 订单Id 商品Id 总金额 商品名称 001 1 10 苹果 001 2 10 橘子 联合主键订单Id、商品Id => 商品表 商品Id 商品名称 单价 订单表 订单Id 总金额 1.5.3 第三范式 1.5.3.1 规范 属性不依赖于其它非主属性,确保数据表中的每一列数据都和主键直接相关,而不能间接相关,即要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。 1.5.3.2 举例 党员表 党员Id 党员姓名 组织Code 符合3NF 党员表 党员Id 党员姓名 组织名称 不符合3NF 组织表 组织Code 组织名称 1.6 外连接 1.6.1 准备 create table student_A( uuid varchar2(32), name varchar2(100)); create table student_B( uuid varchar2(32), name varchar2(100)); insert into student_A values('1','小黄'); insert into student_A values('2','小黑'); insert into student_A values('3','小红'); insert into student_B values('1','大黄'); insert into student_B values('2','大黑'); insert into student_B values('4','大红'); insert into student_B values('4','大紫'); 1.6.2 左连接(left join) 1.6.2.1 说明 查询指定的左表的所有行,而不仅仅是联接列所匹配的行;如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。 1.6.2.2 语法 select A.*,B.* from student_A A left join student_B B on A.Uuid = B.Uuid; 1.6.2.3 结果 1.6.2.4 (+)表示 select A.*,B.* from student_A A,student_B B where A.Uuid = B.Uuid(+) 1.6.3 右连接(right join) 1.6.3.1 说明 查询指定的右表的所有行,而不仅仅是联接列所匹配的行;如果右表的某行在左表中没有匹配行,则在相关联的结果集行中左表的所有选择列表列均为空值。 1.6.3.2 语法 select A.*,B.* from student_A A right join student_B B on A.Uuid = B.Uuid; 1.6.3.3 结果 1.6.3.4 (+)表示 select A.*,B.* from student_A A,student_B B where A.Uuid(+) = B.Uuid 1.6.4 全外连接(full outer join) 1.6.4.1 说明 完整外部联接返回左表和右表中的所有行;当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值;如果表之间有匹配行,则整个结果集行包含基表的数据值。 1.6.4.2 语法 select A.*, B.* from student_A A full outer join student_B B on A.Uuid = B.Uuid; 1.6.4.3 结果 1.6.4.4 全外连接不支持(+)写法 1.6.5 (+) + 表示补充,即哪个表有加号,这个表就是匹配表。 1.7 运算符 1.7.1 比较 =、>,<,>=,<=,!=,<>, 1.7.2 确定范围 between and 、not between and 1.7.3 确定集合 in、not in 1.7.4 字符匹配 like(“%”匹配任何长度,“_”匹配一个字符) 1.7.5 转义字符 1.7.5.1 常规转义字符 “\”转义字符,“\%”则表示单纯的字符“%” 1.7.5.2 escape escape关键字经常用于使某些特殊字符,如通配符:'%','_'转义为它们原来的字符的意义,被定义的转义字符通常使用'\',但是也可以使用其他的符号。 select * from Student_a where name like '%$%%' escape '$'; 1.7.6 空值 is null、is not null 1.7.7 集合查询 union(并)、intersect(交)、minus(差) 1.7.8 多重条件 and、or、not 1.7.9 对查询结果分组 <group by 列名> 1.7.10 分组筛选条件 [having <条件表达式>] 1.7.11 字符串拼接 select 'A' || 'B' from dual; // || 拼接 1.8 函数 1.8.1 聚集函数 count、sum、avg、max、min 1.8.2 case when 1.8.2.1 语法 select t.uuid, t.score, case when t.score > 90 then '优秀' when t.score > 60 then '及格' else '不及格' end from exam_user_exam t 1.8.3 decode 1.8.3.1 语法 select decode(x,1,'x is 1', 2 , 'x is 2','others') from dual 1.8.3.2 说明 当x等于1时,则返回‘x is 1’,当x等于2时,则返回‘x is 2’,否则,返回‘others’。 1.8.4 nulls first(nulls last)排序 1.8.4.1 语法 select * from dy_info t order by t.degree nulls first 1.8.4.2 说明 控制null显示行位置 1.8.5 Nvl 1.8.5.1 语法 select nvl(t.sap,'空') from dy_info t; 1.8.5.2 说明 如果sap号为空,则返回‘空’,否则返回sap号。 1.8.6 递归查询 1.8.6.1 语法 select t.* from g_organ t start with t.organcode = '080' connect by prior t.parentcode = t.organcode; //递归查询父节点 select t.* from g_organ t start with t.organcode = '080' connect by t.parentcode = prior t.organcode; //递归查询子节点 1.8.7 union 和 union all 1.8.7.1 语法 select * from dual union all select * from dual 1.8.7.2 说明 union 会对查询数据进行去重并排序,union all只是简单的将两个结果合并。 1.8.8 wm_concat 1.8.8.1 语法 select wm_concat(t.role_name) from g_role t where t.role_name like '%书记%' 1.8.8.2 说明 拼接字符串,结果为:‘党工委副书记,总支副书记,党支部书记,党委书记,党委副书记,党总支书记,党工委书记,党总支副书记,党支部副书记’ 1.8.9 相似度 1.8.9.1 语法 select utl_match.edit_distance_similarity('aaaaa','bbaaaa') from dual; 1.8.10 去格式 1.8.10.1 oracle正则表达式:去除<></>格式 select REGEXP_REPLACE(title,'<[^>]*>','') title from exam_question 1.8.11 rank() over (partition by …) 1.8.11.1 语法 select organcode,score,ranknum from ( select t.organcode, t.score, rank() over (partition by t.organcode order by t.score desc) ranknum from exam_user_exam t) where ranknum < 4 1.8.11.2 说明 获取每个组织,考试成绩前三名。 1.9 存储过程 1.9.1 定义 存储过程是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。 1.9.2 准备 create table t_user ( username varchar2(20), password varchar2(20) ); create table t_user_temp ( username varchar2(20), password varchar2(20) ); insert into t_user(username,password) values('小王','1111'); insert into t_user(username,password) values('小李','1111'); 1.9.3 创建存储过程 create or replace procedure adduser as begin insert into t_user_temp(username,password) select username,password from t_user t where t.username = '小李'; end adduser; 1.9.4 执行 begin adduser; end; 1.9.5 验证 select * from t_user; select * from t_user_temp 2 SQL深入 2.1 常用 2.1.1 表空间 2.1.1.1 创建表空间 create tablespace TS_DJY datafile 'd:/software/oracle/tablespace/ts_djy.dat' size 1024M autoextend on next 100M maxsize 2048M; 2.1.1.2 指定用户表空间 alter user cssdj default tablespace TS_DJY; 2.1.1.3 指定表的表空间 create table t_student( uuid varchar2(32) )tablespace TS_DJY; 2.1.2 自增sequence 2.1.2.1 创建 create sequence seq_student_uuid minvalue 1 maxvalue 999999999999999 start with 1 increment by 1 nocache; 2.1.2.2 使用 select seq_student_uuid.nextval from dual; //获取下一个 select seq_student_uuid.currval from dual; //获取当前 2.1.3 批量插入 2.1.3.1 查询结果批量插入 insert into tablea(cola,colb) select cola,colb from tableb; 2.1.3.2 创建相同的表结构并插入数据(备份表数据) create tab_new as select * from tab_old; 2.1.3.3 创建相同的表结构不插入数据 create tab_new as select * from tab_old where rownum=0; 2.1.4 伪列伪表 2.1.4.1 伪列 伪列不是表的真实列,但是你可以象使用真实列一样使用伪列,常用伪列:rowid行的绝对物理编号,每一行是唯一的。rownum序号,返回查询结果的每行序号。系统时间sysdate,返回系统当前时间。 2.1.4.2 伪表 select * from dual; 2.1.5 系统表 2.1.5.1 user_tables 当前用户表信息 2.1.5.2 user_tab_columns 当前用户表所有列信息,搜索列所在的表: select * from user_tab_columns t where t.column_name like '%ORGANCODE%'; 2.1.5.3 user_tablespaces 当前用户表空间 2.1.5.4 dba_users 数据库所有用户 2.1.5.5 dba_tables 数据库所有表 2.1.5.6 dba_tablespaces 数据库所有表空间 2.1.6 锁表解锁 2.1.6.1 查看锁表信息 select l.OBJECT_ID,s.SID,s.SERIAL#,s.USERNAME, s.MACHINE from V$locked_Object l,V$session s where l.SESSION_ID = s.SID; 2.1.6.2 解锁 alter system kill session 'sid,serial#'; 2.1.7 备份与恢复 2.1.7.1 导出 导出用户: exp cssdj/cssdj@zr owner=(cssdj,cssdj_zsy) file=d:/cssdj.dmp log=d:/cssdj.log 导出用户表: exp cssdj/cssdj@zr tables=(g_dict,g_dict_item) file=d:/cssdj.dmp log=d:/cssdl.log 2.1.7.2 导入 imp cssdj/cssdj@zr fromuser=cssdj_zsy touser=cssdj file=d:/cssdj.cmp log=d:/cssdj.log 2.1.7.3 数据泵 2.1.8 Dblink 2.1.8.1 创建 create database link orcllink connect to cssdj identified by cssdj using '(DESCRIPTION = (ADDRESS_LIST= (ADDRESS=(PROTOCOL = TCP)(HOST = 219.239.110.65)(PORT = 1521))) (CONNECT_DATA=(SID = orcl)))'; 2.1.8.2 删除 drop database link orcllink; 2.1.8.3 使用 select * from dy_info@orcllink; 2.2 Oracle与Mysql差异 2.2.1 Group by 2.2.1.1 Oracle select后面出现的列,如果没有使用集合函数,必须出现在group by 中。 select sno,sname,sum(grade) from student group by sno,sname; //合法写法 select sno,sname,sum(grade) from student group by sno; //非法写法 select sno,min(sname),sum(grade) from student group by sno; //建议用这种写法,效率高些 2.2.1.2 Mysql select sno,sname,sum(grade) from student group by sno,sname; //合法写法 select sno,sname,sum(grade) from student group by sno; //合法写法 2.2.2 分页 2.2.2.1 Oracle 使用rownum来表明分页位置,而且rownum只能小于某值,不能大于某值,故而rownum和where联用才能完成数据范围的控制 2.2.2.2 Mysql mysql的分页可以用limit startNum,pageNum 2.3 了解 2.3.1 事务 2.3.1.1 Rollback start transaction; --开始事务 insert into g_dict values('test','测试','1',''); --执行数据操作语言(DML) select * from g_dict where code = 'test'; --可以查看是否执行正确 rollback; --错误执行rollback操作 commit; --正确执行commit操作 2.3.1.2 Savepoint start transaction; --开始事务 insert into g_dict values('t1','测试','1',''); --执行数据操作语言(DML) savepoint pointA; insert into g_dict values('t2','测试','1',''); --执行数据操作语言(DML) select * from g_dict where code = 'test33'; --可以查看是否执行正确 rollback to savepoint pointA; 2.3.2 利用执行计划评估SQL语句的性能 2.3.2.1 工具 在PL/SQL Developer中写好一段SQL代码后,按F5,PL/SQL Developer会自动打开执行计划窗口,显示该SQL的执行计划。 2.3.2.2 查看总COST,获得资源耗费的总体印象 一般而言,执行计划第一行所对应的COST(即成本耗费)值,反应了运行这段SQL的总体估计成本,单看这个总成本没有实际意义,但可以拿它与相同逻辑不同执行计划的SQL的总体COST进行比较,通常COST低的执行计划要好一些。 2.3.2.3 了解执行计划的执行步骤 按照从左至右,从上至下的方法,了解执行计划的执行步骤; 执行计划按照层次逐步缩进,从左至右看,缩进最多的那一步,最先执行,如果缩进量相同,则按照从上而下的方法判断执行顺序,可粗略认为上面的步骤优先执行。每一个执行步骤都有对应的COST,可从单步COST的高低,以及单步的估计结果集(对应ROWS/基数),来分析表的访问方式,连接顺序以及连接方式是否合理。 2.3.2.4 分析表的访问方式 表的访问方式主要是两种:全表扫描(TABLE ACCESS FULL)和索引扫描(INDEX SCAN),如果表上存在选择性很好的索引,却走了全表扫描,而且是大表的全表扫描,就说明表的访问方式可能存在问题;若大表上没有合适的索引而走了全表扫描,就需要分析能否建立索引,或者是否能选择更合适的表连接方式和连接顺序以提高效率。 2.3.2.5 分析表的连接方式和连接顺序 表的连接顺序:就是以哪张表作为驱动表来连接其他表的先后访问顺序。 表的连接方式:简单来讲,就是两个表获得满足条件的数据时的连接过程。主要有三种表连接方式,嵌套循环(NESTED LOOPS)、哈希连接(HASH JOIN)和排序-合并连接(SORT MERGE JOIN)。我们常见得是嵌套循环和哈希连接。 嵌套循环:最适用也是最简单的连接方式。类似于用两层循环处理两个游标,外层游标称作驱动表,Oracle检索驱动表的数据,一条一条的代入内层游标,查找满足WHERE条件的所有数据,因此内层游标表中可用索引的选择性越好,嵌套循环连接的性能就越高。 哈希连接:先将驱动表的数据按照条件字段以散列的方式放入内存,然后在内存中匹配满足条件的行。哈希连接需要有合适的内存,而且必须在CBO优化模式下,连接两表的WHERE条件有等号的情况下才可以使用。哈希连接在表的数据量较大,表中没有合适的索引可用时比嵌套循环的效率要高。 2.3.3 优化器 Oracle优化器分为基于规则的优化器(RBO)和基于代价的优化器(CBO)。 2.3.3.1 规则的优化器(RBO) RBO的优化方式,依赖于一套严格的语法规则,只要按照规则写出的语句,不管数据表和索引的内容是否发生变化,不会影响PL/SQL语句的"执行计划"。 2.3.3.2 基于代价的优化器(CBO) CBO计算各种可能"执行计划"的"代价",即cost,从中选用cost最低的方案,作为实际运行方案。各"执行计划"的cost的计算根据,依赖于数据表中数据的统计分布,ORACLE数据库本身对该统计分布是不清楚的,须要分析表和相关的索引,才能搜集到CBO所需的数据。 2.3.4 表分析analysis 2.3.4.1 说明 analyze table,一般可以指定分析表、所有字段、所有索引字段、所有索引,若不指定则全部都分析。 2.3.4.2 表分析 analyze table dy_info compute statistics; 2.3.4.3 删除分析数据 analyze table dy_info delete statistics; 2.3.5 oracle添加强制索引 如果使用的是CBO的话,可能SQL不执行索引,则可以添加强制索引执行索引。 2.3.5.1 语法 /*+index(tablename indexname)*/ 2.3.5.2 举例 select /*+index(t INDEX_SAP)*/* from dy_info t where t.sap = 'T6000890'
(转)SQL 优化原则 一、问题的提出  在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用系统提交实际应用后,随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要的问题之一。系统优化中一个很重要的方面就是SQL语句的优化。对于海量数据,劣质SQL语句和优质SQL语句之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就可,而是要写出高质量的SQL语句,提高系统的可用性。   在多数情况下,Oracle使用索引来更快地遍历表,优化器主要根据定义的索引来提高性能。但是,如果在SQL语句的where子句中写的SQL代码不合理,就会造成优化器删去索引而使用全表扫描,一般就这种SQL语句就是所谓的劣质SQL语句。在编写SQL语句时我们应清楚优化器根据何种原则来删除索引,这有助于写出高性能的SQL语句。   二、SQL语句编写注意问题   下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍。在这些where子句中,即使某些列存在索引,但是由于编写了劣质的SQL,系统在运行该SQL语句时也不能使用该索引,而同样使用全表扫描,这就造成了响应速度的极大降低。   1. IS NULL 与 IS NOT NULL   不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。   任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。   2. 联接列   对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。我们一起来看一个例子,假定有一个职工表(employee),对于一个职工的姓和名分成两列存放(FIRST_NAME和LAST_NAME),现在要查询一个叫比尔.克林顿(Bill Cliton)的职工。   下面是一个采用联接查询的SQL语句select * from employss where first_name||''||last_name ='Beill Cliton'; 上面这条语句完全可以查询出是否有Bill Cliton这个员工,但是这里需要注意,系统优化器对基于last_name创建的索引没有使用。   当采用下面这种SQL语句的编写,Oracle系统就可以采用基于last_name创建的索引。 *** where first_name ='Beill' and last_name ='Cliton'; . 带通配符(%)的like语句   同样以上面的例子来看这种情况。目前的需求是这样的,要求在职工表中查询名字中包含cliton的人。可以采用如下的查询SQL语句: select * from employee where last_name like '%cliton%'; 这里由于通配符(%)在搜寻词首出现,所以Oracle系统不使用last_name的索引。在很多情况下可能无法避免这种情况,但是一定要心中有底,通配符如此使用会降低查询速度。然而当通配符出现在字符串其他位置时,优化器就能利用索引。在下面的查询中索引得到了使用: select * from employee where last_name like 'c%'; 4. Order by语句   ORDER BY语句决定了Oracle如何将返回的查询结果排序。Order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。   仔细检查order by语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。 5. NOT   我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。下面是一个NOT子句的例子: ... where not (status ='VALID') 如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。NOT运算符包含在另外一个逻辑运算符中,这就是不等于(<>)运算符。换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,见下例: ... where status <>'INVALID'; 对这个查询,可以改写为不使用NOT: select * from employee where salary<3000 or salary>3000; 虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。 虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。 =============================================================================================== 我们要做到不但会写SQL,还要做到写出性能优良的SQL,以下为笔者学习、摘录、并汇总部分资料与大家分享! (1) 选择最有效率的表名顺序(只在基于规则的优化器中有效): ORACLE 的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表. (2) WHERE子句中的连接顺序.: ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾. (3) SELECT子句中避免使用 ‘ * ‘: ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间 (4) 减少访问数据库的次数: ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量 , 读数据块等; (5) 在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200 (6) 使用DECODE函数来减少处理时间: 使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表. (7) 整合简单,无关联的数据库访问: 如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系) (8) 删除重复记录: 最高效的删除重复记录方法 ( 因为使用了ROWID)例子: DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO); (9) 用TRUNCATE替代DELETE: 当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况) 而当运用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短. (译者按: TRUNCATE只在删除全表适用,TRUNCATE是DDL不是DML) (10) 尽量多使用COMMIT: 只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少: COMMIT所释放的资源: a. 回滚段上用于恢复数据的信息. b. 被程序语句获得的锁 c. redo log buffer 中的空间 d. ORACLE为管理上述3种资源中的内部花费
1、索引 ·什么是索引 ·索引的基本原理 ·索引的基本写法 ·索引的分类 ·索引的作用 ·索引的优缺点 ·索引的建立原则 2、存储过程 ·什么是存储过程 ·存储过程的基本写法 ·存储过程的作用 ·存储过程的优缺点 ·存储过程的应用场景 3、触发器 ·什么是触发器 ·触发器的的基本写法 ·触发器的功能 ·触发器的优缺点 ·触发器的两种形式 ·触发器的应用场景 4、视图 ·什么是视图 ·视图的基本写法 ·视图在哪些情况下不能被增、删、改 ·视图的作用 ·视图的优缺点 ·视图的应用场景 5、游标 ·什么是游标 ·游标的作用 ·游标的分类 ·游标的基本用法 ·使用游标的优缺点 ·什么时候选择使用游标 1、 (1)索引是对数据库表中一列或多列进行排序的一种结构。 (2)Mysql中搜索引擎Innodb(聚簇索引)和Mysiam(非聚簇索引)都采用B+,oracle也采用B+树实现 注:聚簇索引:一张表只能建立一个聚簇索引,以主键建立索引。聚簇索引包括主键索引和二级索引(二级索引是在对非主键字段建立索引后,通过索引找到对应这个非主键字段的主键,再进行主键索引,找到B+树中叶子结点);(聚簇索引B+树中叶子结点存放的是数据和指向下一条数据的指针) 非聚簇索引:对主键和非主键字段建立索引时,直接找到B+树中的叶子结点,B+树中叶子结点存放的是对应数据的地址,并通过地址找到数据。 (3)Create index 索引名 on 表名(字段名) (4)索引分为聚簇索引和非聚簇索引 (5)索引的作用 1.创建唯一性索引,可以保证数据库表中每一行数据的唯一性。 2.可以加大数据的检索速度,这也是创建索引的主要原因。 3.可以加速表与表之间的连接效率。 4.在分组排序时使用索引,可以减少分组排序的时间。 (6)索引的优缺点 索引的优点既索引的作用。 索引的缺点:1.建立索引会产生占据一定的空间。2.对表中的数据进行增、删、改的时候,索引也要动态的维护,这就降低了整数的维护速度。 (7)索引的建立原则 1.主外键 2.经常被查询的列 3.用于连接的字段 4.排序分组的字段 2、存储过程 (1)什么是存储过程? 存储过程(Stored Procedure)是一组为了完成特定功能的SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。 (2)存储过程的基本写法(oracle) Create or replace procedure 名称(参数) Is/as (变量的赋值例如:(a name%type)(a varchar(2))) Begin Sql语句以及判断条件 End 名称; (3)存储过程的作用 1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而 一般SQL 语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速 度。 2.当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query,Delete 时),可将此复杂操作用存储过程封装起来 与数据库提供的事务处理结合一起使用。 3.存储过程可以重复使用,可减少数据库开发人员的工作量。 4.安全性高,可设定只有某此用户才具有对指定存储过程的使用权。 (4)存储过程的优缺点 优点: 作用的四条加上 1.分布式工作。 应用程序和数据库的编码工作可以分别独立进行,而不会相互影响。 缺点:1.如果更改范围大到需要对输入存储过程的参数进行更改,或者要更改由其返回的数据,则您仍需要更新程序集中的代码以添加参数、更新 GetValue() 调用,等等,这时候估计比较繁琐了。 2.可移植性差 由于存储过程将应用程序绑定到数据库,因此使用存储过程封装业务逻辑将限制应用程序的可移植性。 (5)存储过程的应用场景 1.通常,复杂的业务逻辑需要多条  SQL  语句。这些语句要分别地从客户机发送到服务器,当客户机和服务器之间的操作很多时,将产生大量的网络传输。如果将这些操作放在一个存储过程中,那么客户机和服务器之间的网络传输就会大大减少,降低了网络负载。 3、触发器 (1)什么是触发器 在Oracle中,触发器是一种特殊的存储过程,也是由一组sql语句以及一些业务逻辑代码组成的。数据库可以通过增、删、改来触发触发器。 (2)触发器的基本写法 create or replace trigger tri_adddept AFTER INSERT on dept For each row //表级不用加 declare begin dbms_output.put_line('插入了新部门'); end ; (3)触发器的功能 1.配合sequence实现自增(oracle) 2.提供审计和日志记录 3.写复杂的业务逻辑代码 (4)触发器的优缺点 优点: 1.实现级联更改 2.能过实现比check更严格的约束,与CHECK 约束不同,触发器可以引用其它表中的数据。通过其他表中的数据的变化来设置更加复杂的约束。 缺点:滥用触发器会造成数据库及应用程序的维护困难。 (5)触发器的两种形式(行级触发器,表级触发器) 1.在语法上,行级触发器就多了一句话:for each row 2.在表现上,行级触发器,在每一行的数据进行操作的时候都会触发。 语句级触发器,对表的一个完整操作才会触发一次。 简单的说:行级触发器,是对应行操作的;语句级触发器,是对应表操作的。 (6)应用场景 作用+优点 4、视图 (1)什么是视图? 视图(VIEW)也被称作虚表,即虚拟的表,是一组数据的逻辑表示,其本质是对应于一条SELECT语句,结果集被赋予一个名字,即视图名字。 视图本身并不包含任何数据,它只包含映射到基表的一个查询语句,当基表数据发生变化,视图数据也随之变化。 (2)视图的基本写法 Create view 视图名 as select * from emp; (3)视图在哪些情况下不能被增、删、改 (1)若视图的字段是来自字段表达式或常数,则不允许对此视图执行INSERT、UPDATE操作,允许执行DELETE操作; (2)若视图的字段是来自库函数,则此视图不允许更新; (3)若视图的定义中有GROUP BY子句或聚集函数时,则此视图不允许更新; (4)若视图的定义中有DISTINCT任选项,则此视图不允许更新; (5)若视图的定义中有嵌套查询,并且嵌套查询的FROM子句中涉及的表也是导出该视图的基表,则此视图不允许更新; (6)若视图是由两个以上的基表导出的,此视图不允许更新; (7)一个不允许更新的视图上定义的视图也不允许更新; 本表的行列子集视图一般是可更新的。若视图的属性来自集函数、表达式,则该视图肯定是不可以更新的。 (4)视图的作用 1、视图隐藏了底层的表结构,简化了数据访问操作,客户端不再需要知道底层表的结构及其之间的关系。 2、视图提供了一个统一访问数据的接口。(即可以允许用户通过视图访问数据的安全机制,而不授予用户直接访问底层表的权限) 3、从而加强了安全性,使用户只能看到视图所显示的数据。 4、视图还可以被嵌套,一个视图中可以嵌套另一个视图。 (5) 视图的优缺点 优点:1.简单性。视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使用户不必为以后的操作每次都指定全部的条件。 2.安全性。通过视图用户只能查询和修改他们所能见到的数据。数据库中的其他数据则既看不见也取不到。数据库授权命令可以使每个用户对数据库的检索限制到特定的数据库对象上,但不能授权到数据库特定行和特定的列上。通过视图,用户可以被限制在数据的不同子集上。 3. 逻辑数据独立性。视图可以使应用程序和数据库表在一定程度上独立。如果没有视图,应用一定是建立在表上的。有了视图之后,程序可以建立在视图之上,从而程序与数据库表被视图分割开来。 缺点:1.如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,也要花费一定的时间。 2.修改限制:当用户试图修改视图的某些行时,数据库必须把它转化为对基本表的某些行的修改。对于简单视图来说,这是很方便的,但是,对于比较复杂的视图,可能是不可修改的。 (6)视图的应用场景 1.访问频繁,更新少的一组数据 2.需要对一些数据限制访问权限时 5、游标(cursor) (1)什么是游标 游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标充当指针的作用。尽管游标能遍历结果中的所有行,但他一次只指向一行。 (2)游标的作用 游标的一个常见用途就是保存查询结果,以便以后使用。 (3)游标的分类 游标分为显示游标和隐式游标 隐式游标:是用户操作SQL时自动生成的,而显式游标是在声明块中直接定义的游标。 (4)游标的基本用法 通过ROWCOUNT查看游标指向的行:(隐式游标实例) 例: DECLARE v_count NUMBER; BEGIN SELECT COUNT(*) INTO v_count from dept; --返回一个隐式游标 dbms_output.put_line('SQL%ROWCOUNT = '||SQL%COUNT); END; / 执行结果:SQL%ROWCOUNT = 1 (显式游标基本) DECLARE CURSOR mycur IS SELECT * FROM dept; deptinfo dept%ROWTYPE; BEGIN IF mycur%ISOPEN THEN NULL; ELSE OPEN mycur; END IF; LOOP FETCH mycur INTO deptinfo; EXIT WHEN mycur%NOTFOUND; dbms_output.put_line('部门名称:'||deptinfo.dname); END LOOP; END; (配合for) DECLARE CURSOR mycur IS SELECT * FROM dept; deptinfo dept%ROWTYPE; BEGIN For test in mycur loop EXIT WHEN mycur%NOTFOUND; dbms_output.put_line('部门名称:'||test.dname); END LOOP; END; (5)游标的优缺点 优点: 游标允许应用程序对查询语句select 返回的行结果集中每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作; 它还提供对基于游标位置而对表中数据进行删除或更新的能力 缺点: 处理大数据量时,效率低下,占用内存大 (6)什么时候选择使用游标? 一般是在循环处理的时候使用。 比如你判断一个班上的同学数学成绩怎么样,你就可能用游标,先把全部的成绩查询到游标中,之后再循环一条条进行判断处理。
CruiseYoung提供的带有详细书签的电子书籍目录 http://blog.csdn.net/fksec/article/details/7888251 该资料是《Oracle SQL高级编程》的源代码 对应的书籍资料见: Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐) 基本信息 原书名: Pro Oracle SQL 原出版社: Apress 作者: (美)Karen Morton    Kerry Osborne    Robyn Sands    Riyaj Shamsudeen    Jared Still    译者: 朱浩波 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:9787115266149 上架时间:2011-11-9 出版日期:2011 年11月 开本:16开 页码:502 版次:1-1 主编推荐     资深Oracle专家力作,OakTable团队推荐     全面、独到、翔实,题材丰富     Oracle开发人员和DBA必备 内容简介     Oracle 数据库中的SQL是当今市场上功能最强大的SQL实现之一,而本书全面展示了这一工具的威力。如何才能让更多人有效地学习和掌握SQL呢?Karen Morton及其团队在本书中提供了专业的方案:先掌握语言特性,再学习Oracle为提升语言效率而加入的支持特性,进而将两者综合考虑并在工作中加以应用。作者通过总结各自多年的软件开发和教学培训经验,与大家分享了掌握Oracle SQL所独有的丰富功能的技巧所在,内容涵盖SQL执行、联结、集合、分析函数、子句、事务处理等多个方面。读者可以学习到以下几个方面的技巧:     掌握Oracle数据库中独有的SQL强大特征;     读取并理解SQL执行计划;     快速分析并改进表现欠佳的SQL;     通过提示及配置文件等来控制执行计划;     在程序中优化查询而无需改动代码。     作为Oracle SQL经典著作之一,本书为SQL开发人员指明了前行的方向,赋予了他们不断开拓的动力。 作者简介     KAREN MORTON 研究人员、教育家及顾问,Fidelity信息服务公司的资深数据库管理员和性能调优专家。她从20世纪90年代初就开始使用Oracle,从事 Oracle的教学工作也已经超过10年的时间。她是Oracle ACE,也是OakTable(Oracle社区中著名的“Oracle科学家”的非正式组织)的成员,经常在技术会议上演讲。她的著作还包括 Expert Oracle Practices和Beginning Oracle SQL,博客主页是karenmorton.blogspot.com。     KERRY OSBORNE  专注于Oracle咨询的Enkitec公司的创始人之一。从1982年开始使用Oracle(第2版)。他当过开发人员,也做过DBA,目前是 Oracle ACE总监和OakTable成员。最近几年,他专注于研究Oracle内部原理以及解决性能问题。他的博客主页是 kerryosborne.oracle-guy.com。     ROBYN SANDS 思科公司的软件工程师,为思科的客户设计开发嵌入式Oracle数据库产品。从1996年开始使用Oracle,在应用开发、大型系统实现以及性能评估方面具有丰富的经验。她是OakTable的成员,同时是Expert Oracle Practices (2010年 Apress出版)一书的合著者。     RIYAJ SHAMSUDEEN 专注于性能/数据恢复/电子商务的咨询公司OraInternals的首席数据库管理员和董事长。有近20年使用Oracle技术产品以及Oracle数据库管理员/Oracle数据库应用管理员的经验,是真正应用集群、性能调优以及数据库内部属性方面的专家。同时是一位演讲家及Oracle ACE。     JARED STILL 从1994年就开始使用Oracle。他认为对于SQL的学习是永无止境的,相信每一个查询Oracle数据库的人都需要精通SQL语言,才能写出高效的查询。他参与本书的编写就是为了帮助别人实现这一目标。 目录 封面 -11 封底 -10 扉页 -9 版权 -8 版权声明 -7 致谢 -6 目录 -5 第1章 SQL核心 1 1.1 SQL语言 1 1.2 数据库的接口 2 1.3 SQL*Plus 回顾 3 1.3.1 连接到数据库 3 1.3.2 配置SQL*Plus环境 4 1.3.3 执行命令 6 1.4 5 个核心的SQL语句 8 1.5 SELECT语句 8 1.5.1 FROM子句 9 1.5.2 WHERE子句 11 1.5.3 GROUP BY子句 11 1.5.4 HAVING子句 12 1.5.5 SELECT列表 12 1.5.6 ORDERBY子句 13 1.6 INSERT语句 14 1.6.1 单表插入 14 1.6.2 多表插入 15 1.7 UPDATE语句 17 1.8 DELETE语句 20 1.9 MERGE语句 22 1.10 小结 24 第2章 SQL执行 25 2.1 Oracle架构基础 25 2.2 SGA-共享池 27 2.3 库高速缓存 28 2.4 完全相同的语句 29 2.5 SGA-缓冲区缓存 32 2.6 查询转换 35 2.7 视图合并 36 2.8 子查询解嵌套 39 2.9 谓语前推 42 2.10 使用物化视图进行查询重写 44 2.11 确定执行计划 46 2.12 执行计划并取得数据行 50 2.13 SQL执行——总览 52 2.14 小结 53 第3章 访问和联结方法 55 3.1 全扫描访问方法 55 3.1.1 如何选择全扫描操作 56 3.1.2 全扫描与舍弃 59 3.1.3 全扫描与多块读取 60 3.1.4 全扫描与高水位线 60 3.2 索引扫描访问方法 65 3.2.1 索引结构 66 3.2.2 索引扫描类型 68 3.2.3 索引唯一扫描 71 3.2.4 索引范围扫描 72 3.2.5 索引全扫描 74 3.2.6 索引跳跃扫描 77 3.2.7 索引快速全扫描 79 3.3 联结方法 80 3.3.1 嵌套循环联结 81 3.3.2 排序-合并联结 83 3.3.3 散列联结 84 3.3.4 笛卡儿联结 87 3.3.5 外联结 88 3.4 小结 94 第4章 SQL是关于集合的 95 4.1 以面向集合的思维方式来思考 95 4.1.1 从面向过程转变为基于集合的思维方式 96 4.1.2 面向过程vs.基于集合的思维方式:一个例子 100 4.2 集合运算 102 4.2.1 UNION和UNION ALL 103 4.2.2 MINUS 106 4.2.3 INTERSECT 107 4.3 集合与空值 108 4.3.1 空值与非直观结果 108 4.3.2 集合运算中的空值行为 110 4.3.3 空值与GROUP BY和ORDER BY 112 4.3.4 空值与聚合函数 114 4.4 小结 114 第5章 关于问题 116 5.1 问出好的问题 116 5.2 提问的目的 117 5.3 问题的种类 117 5.4 关于问题的问题 119 5.5 关于数据的问题 121 5.6 建立逻辑表达式 126 5.7 小结 136 第6章 SQL执行计划 137 6.1 解释计划 137 6.1.1 使用解释计划 137 6.1.2 理解解释计划可能达不到目的的方式 143 6.1.3 阅读计划 146 6.2 执行计划 148 6.2.1 查看最近生成的SQL语句 149 6.2.2 查看相关执行计划 149 6.2.3 收集执行计划统计信息 151 6.2.4 标识SQL语句以便以后取回计划 153 6.2.5 深入理解DBMS_XPLAN的细节 156 6.2.6 使用计划信息来解决问题 161 6.3 小结 169 第7章 高级分组 170 7.1 基本的GROUP BY用法 171 7.2 HAVING子句 174 7.3 GROUP BY的“新”功能 175 7.4 GROUP BY的CUBE扩展 175 7.5 CUBE的实际应用 179 7.6 通过GROUPING()函数排除空值 185 7.7 用GROUPING()来扩展报告 186 7.8 使用GROUPING_ID()来扩展报告 187 7.9 GROUPING SETS与ROLLUP() 191 7.10 GROUP BY局限性 193 7.11 小结 196 第8章 分析函数 197 8.1 示例数据 197 8.2 分析函数剖析 198 8.3 函数列表 199 8.4 聚合函数 200 8.4.1 跨越整个分区的聚合函数 201 8.4.2 细粒度窗口声明 201 8.4.3 默认窗口声明 202 8.5 Lead和Lag 202 8.5.1 语法和排序 202 8.5.2 例1:从前一行中返回一个值 203 8.5.3 理解数据行的位移 204 8.5.4 例2:从下一行中返回一个值 204 8.6 First_value和Last_value 205 8.6.1 例子:使用First_value来计算最大值 206 8.6.2 例子:使用Last_value来计算最小值 207 8.7 其他分析函数 207 8.7.1 Nth_value(11gR2) 207 8.7.2 Rank 209 8.7.3 Dense_rank 210 8.7.4 Row_number 211 8.7.5 Ratio_to_report 211 8.7.6 Percent_rank 212 8.7.7 Percentile_cont 213 8.7.8 Percentile_disc 215 8.7.9 NTILE 215 8.7.10 Stddev 216 8.7.11 Listagg 217 8.8 性能调优 218 8.8.1 执行计划 218 8.8.2 谓语 219 8.8.3 索引 220 8.9 高级话题 221 8.9.1 动态SQL 221 8.9.2 嵌套分析函数 222 8.9.3 并行 223 8.9.4 PGA大小 224 8.10 组织行为 224 8.11 小结 224 第9章 Model子句 225 9.1 电子表格 225 9.2 通过Model子句进行跨行引用 226 9.2.1 示例数据 226 9.2.2 剖析Model子句 227 9.2.3 规则 228 9.3 位置和符号引用 229 9.3.1 位置标记 229 9.3.2 符号标记 230 9.3.3 FOR循环 231 9.4 返回更新后的行 232 9.5 求解顺序 233 9.5.1 行求解顺序 233 9.5.2 规则求解顺序 235 9.6 聚合 237 9.7 迭代 237 9.7.1 一个例子 238 9.7.2 PRESENTV与空值 239 9.8 查找表 240 9.9 空值 242 9.10 使用Model子句进行性能调优 243 9.10.1 执行计划 243 9.10.2 谓语前推 246 9.10.3 物化视图 247 9.10.4 并行 249 9.10.5 Model子句执行中的分区 250 9.10.6 索引 251 9.11 子查询因子化 252 9.12 小结 253 第10章 子查询因子化 254 10.1 标准用法 254 10.2 SQL优化 257 10.2.1 测试执行计划 257 10.2.2 跨多个执行的测试 260 10.2.3 测试查询改变的影响 263 10.2.4 寻找其他优化机会 266 10.2.5 将子查询因子化应用到PL/SQL中 270 10.3 递归子查询 273 10.3.1 一个CONNECT BY的例子 274 10.3.2 使用RSF的例子 275 10.3.3 RSF的限制条件 276 10.3.4 与CONNECT BY的不同点 276 10.4 复制CONNECT BY的功能 277 10.4.1 LEVEL伪列 278 10.4.2 SYS_CONNECT_BY_PATH函数 279 10.4.3 CONNECT_BY_ROOT运算符 281 10.4.4 CONNECT_BY_ISCYCLE伪列和NOCYCLE参数 284 10.4.5 CONNECT_BY_ISLEAF伪列 287 10.5 小结 291 第11章 半联结和反联结 292 11.1 半联结 292 11.2 半联结执行计划 300 11.3 控制半联结执行计划 305 11.3.1 使用提示控制半联结执行计划 305 11.3.2 在实例级控制半联结执行计划 308 11.4 半联结限制条件 310 11.5 半联结必要条件 312 11.6 反联结 312 11.7 反联结执行计划 317 11.8 控制反联结执行计划 326 11.8.1 使用提示控制反联结执行计划 326 11.8.2 在实例级控制反联结执行计划 327 11.9 反联结限制条件 330 11.10 反联结必要条件 333 11.11 小结 333 第12章 索引 334 12.1 理解索引 335 12.1.1 什么时候使用索引 335 12.1.2 列的选择 337 12.1.3 空值问题 338 12.2 索引结构类型 339 12.2.1 B-树索引 339 12.2.2 位图索引 340 12.2.3 索引组织表 341 12.3 分区索引 343 12.3.1 局部索引 343 12.3.2 全局索引 345 12.3.3 散列分区与范围分区 346 12.4 与应用特点相匹配的解决方案 348 12.4.1 压缩索引 348 12.4.2 基于函数的索引 350 12.4.3 反转键索引 353 12.4.4 降序索引 354 12.5 管理问题的解决方案 355 12.5.1 不可见索引 355 12.5.2 虚拟索引 356 12.5.3 位图联结索引 357 12.6 小结 359 第13章 SELECT以外的内容 360 13.1 INSERT 360 13.1.1 直接路径插入 360 13.1.2 多表插入 363 13.1.3 条件插入 364 13.1.4 DML错误日志 364 13.2 UPDATE 371 13.3 DELETE 376 13.4 MERGE 380 13.4.1 语法和用法 380 13.4.2 性能比较 383 13.5 小结 385 第14章 事务处理 386 14.1 什么是事务 386 14.2 事务的ACID属性 387 14.3 事务隔离级别 388 14.4 多版本读一致性 390 14.5 事务控制语句 391 14.5.1 Commit(提交) 391 14.5.2 Savepoint(保存点) 391 14.5.3 Rollback(回滚) 391 14.5.4 Set Transaction(设置事务) 391 14.5.5 Set Constraints(设置约束) 392 14.6 将运算分组为事务 392 14.7 订单录入模式 393 14.8 活动事务 399 14.9 使用保存点 400 14.10 序列化事务 403 14.11 隔离事务 406 14.12 自治事务 409 14.13 小结 413 第15章 测试与质量保证 415 15.1 测试用例 416 15.2 测试方法 417 15.3 单元测试 418 15.4 回归测试 422 15.5 模式修改 422 15.6 重复单元测试 425 15.7 执行计划比较 426 15.8 性能测量 432 15.9 在代码中加入性能测量 432 15.10 性能测试 436 15.11 破坏性测试 437 15.12 通过性能测量进行系统检修 439 15.13 小结 442 第16章 计划稳定性与控制 443 16.1 计划不稳定性:理解这个问题 443 16.1.1 统计信息的变化 444 16.1.2 运行环境的改变 446 16.1.3 SQL语句的改变 447 16.1.4 绑定变量窥视 448 16.2 识别执行计划的不稳定性 450 16.2.1 抓取当前所运行查询的数据 451 16.2.2 查看一条语句的性能历史 452 16.2.3 按照执行计划聚合统计信息 454 16.2.4 寻找执行计划的统计方差 454 16.2.5 在一个时间点附近检查偏差 456 16.3 执行计划控制:解决问题 458 16.3.1 调整查询结构 459 16.3.2 适当使用常量 459 16.3.3 给优化器一些提示 459 16.4 执行计划控制:不能直接访问代码 466 16.4.1 选项1:改变统计信息 467 16.4.2 选项2:改变数据库参数 469 16.4.3 选项3:增加或移除访问路径 469 16.4.4 选项4:应用基于提示的执行计划控制机制 470 16.4.5 大纲 470 16.4.6 SQL概要文件 481 16.4.7 SQL执行计划基线 496 16.4.8 基于提示的执行计划控制机制总结 502 16.5 结论 502 媒体评论     本书作者全部是OakTable的成员,且具有15~29年丰富的Oracle开发经验。在研究一些被其他专门讨论Oracle SQL语言的参考书直接忽略的问题时,这种对Oracle数据库的长期钻研无疑是一个巨大的优势。     ——亚马逊读者评论 精彩内容     SQL核心     凯伦?莫顿(Karen Morton)     不管你是刚开始写SQL语句还是已经写过很多年了,学会写出“好的”SQL这个过程都需要具有很扎实的SQL核心语法和概念基础知识。本章对SQL语言的核心概念及其性能做了回顾,同时还描述了一些你应该已经很熟悉的常用SQL命令。对于那些以前曾经使用过SQL并且基础知识相当牢靠的读者来说,本章就是一个简要的复习,让你为后面更详细的SQL论述做好准备。如果你是一位SQL新人,你可能想要先阅读Beginning Oracle SQL这本书以确保掌握SQL的基础。不管是哪种情况,第1章的目的就是通过对5个核心SQL语句的快速浏览来衡量一下你的SQL水平,同时还概述了我们用来执行SQL语句的工具:SQL*Plus。     1.1  SQL语言     SQL语言最早是IBM公司于20世纪70年代开发出来的,称为结构化英文查询语言,简称为SEQUEL。该语言是基于E.F.Codd在1969年提出的关系型数据库管理系统(RDBMS)的。后来因为商标的纠纷,其简称又进一步缩写为SQL。1986年和1987年,ANSI(美国国家标准化组织)和ISO(国际标准化组织)先后将SQL语言采纳为标准语言。而人们并不熟悉的是,ANSI官方曾将SQL语言的读音确定为“S-Q-L”。绝大多数人,包括我本人,都还在使用“sequel”的读音,只是因为这样读起来更顺口一些。     SQL的目的就是简单地提供一个到数据库的接口,在本书指的是Oracle数据库。每一条SQL语句对于数据库来说就是一条命令或指令。SQL与其他编程语言(如C或Java)的区别就在于它是要处理数据集合而不是一行一行的数据。语言本身也不需要你提供如何导航到数据的指令——这是在后台透明地进行的。但你将在后面的章节中看到,如果想在Oracle中写出高效的SQL语句,了解数据及其在数据库中的存储方式与存储位置是很重要的。     由于不同的供应商(例如甲骨文、IBM和微软)实现SQL核心功能的机制相差无几,所以基于某一种数据库所学的技巧同样可以应用到其他类型的数据库上。你基本上可以利用同样的SQL语句来进行数据的查询、插入、更新和删除,以及创建、修改和删除对象,而不必管数据库的供应商是哪家。     尽管SQL是各种关系型数据库管理系统的标准语言,但实际上它并不一定是关系型的。在本书后面我将就这一点稍作扩展。如果想要了解更多的细节,我推荐大家阅读C.J.Date的SQL and Relational Theory一书。需要铭记于心的一点是SQL语言并不总是严格遵守关系模型的——它根本就没有实现关系模型的某些要素,同时还不恰当地实现了一些要素。事实上,既然SQL是基于关系模型的,那么要想写出尽可能正确高效的SQL语句,你不仅必须要理解SQL语言,还要理解关系模型。     1.2  数据库的接口     多年以来人们开发出多种途径来传递SQL语句到数据库并获得结果。Oracle数据库的本地接口界面是Oracle调用界面(OCI)。OCI将由Oracle内核传送而来的查询语句发送到数据库。当使用某种Oracle工具如SQL*Plus或者SQL Developer时,你都在使用OCI。其他的Oracle工具如SQL*Loader、数据泵(Data Pump)以及Real Application Testing (RAT)既使用OCI,也可以使用语言特定的接口,如Oracle JDBC-OCI、ODP.Net、Oracle预编译器、Oracle ODBC以及Oracle C++调用接口(OCCI)驱动器。     当使用编程语言(如COBOL或C语言)时,你所写的语句被称为嵌入式的SQL语句并且在应用程序编译之前会由SQL预处理器进行预处理。代码清单1-1是一段可以在C/C++程序块中使用的SQL语句的例子。     代码清单1-1  C/C++程序块中所嵌入的SQL语句     其他工具,例如SQL*Plus和SQL Developer,都是交互式的工具。你输入并执行命令,然后获得相应的输出。交互式工具并不需要在运行代码前先精确编译,你只需要输入想要执行的命令即可。代码清单1-2是一段使用SQL*Plus执行语句的例子。     代码清单1-2  使用SQL*Plus执行SQL语句     在本书中,为了保持一致性我们所用的示例代码清单都使用SQL*Plus工具,但需要记住的是,不管你是用什么方法或工具来输入和执行SQL语句,所有的事情最后都要通过OCI来传递到数据库。这里的主旨就是不管你所使用的是什么工具,其本地接口都是一样的。     1.3  SQL*Plus回顾     SQL*Plus是一个不管采用哪个安装平台(Windows或Unix)都会提供的命令行工具。它是一个用来输入和执行SQL语句并显示输出结果的纯文本环境。用该工具可以直接输入、编辑命令,可以一条条地保存和执行命令或者通过脚本文件来进行,然后将输出结果以很精美格式的报表输出。要启动SQL*Plus你只需要在主机的命令提示符后敲入sqlplus即可。     1.3.1  连接到数据库     有多种方法可以通过SQL*Plus连接数据库。然而在连接之前,你还需要在$ORACLE_HOME/ network/admin/tnsnames.ora这个文件中登记想要连接的数据库。有两种通常使用的方法,或者如代码清单1-3所示那样在启动SQL*Plus时提供连接信息,或者如代码清单1-4所示那样在启动SQL*Plus以后使用connect命令。     代码清单1-3  通过窗口命令提示符连接到SQL*Plus     如果想要启动SQL*Plus而又不显示登录到数据库后的提示,可以在启动SQL*Plus时使用/nolog选项。     代码清单1-4  通过SQL>提示符连接SQL*Plus并登录到数据库     1.3.2  配置SQL*Plus环境     SQL*Plus有很多的命令可以让你来定制工作环境和显示选项。代码清单1-5所示是在SQL>提示符下输入help index命令后显示出来的可用的命令。     代码清单1-5  SQL*Plus命令列表     set命令是用来定制工作环境的最基本的命令。代码清单1-6为set命令的帮助文本。     代码清单1-6  SQL*Plus的SET命令     有了上面这些可用命令,你就能够很轻松地定制最适合你的运行环境了。但有一点要铭记于心的就是当你退出或关闭SQL*Plus的时候,这些设置命令就不再被保留了。为了避免每次使用SQL*Plus时都重新敲入一遍这些设置命令,你可以创建一个login.sql文件。事实上每次启动SQL*Plus的时候它都会默认去读两个文件。第一个是$ORACLE_HOME/sqlplus/admin目录下的glogin.sql文件。如果找到了这个文件,它就会被读进来,文件中的命令语句也会被执行。这样就可以把那些定制你的会话体验的SQL*Plus命令和SQL语句保存起来。     在读取glogin.sql文件以后,SQL*Plus会进一步寻找login.sql文件。这个文件必须在SQL*Plus的启动文件夹中或者包含在环境变量SQLPATH所指向的文件夹路径中。在login.sql文件中的所有命令优先级都比glogin.sql文件中的命令高。从10g开始,Oracle在每次你启动SQL*Plus或者从SQL*Plus里执行connect命令的时候都会同时去读取glogin.sql和login.sql这两个文件。在Oracle 10g之前,login.sql脚本文件只有在SQL*Plus启动的时候才会被执行。代码清单1-7是一个常见的login.sql文件内容。     代码清单1-7  一个常见的login.sql文件     注意这里在SET SQLPROMPT中使用的变量_user和_connect_identifier。它们是预定义变量的两个示例。你可以在login.sql文件中或者任何你创建的脚本文件中使用下面这些预定义变量:     ·_connect_identifier     ·_date     ·_editor(这个变量指定了当你使用edit命令的时候启动哪个编辑器)     ·_o_version     ·_o_release     ·_privilege     ·_sqlplus_release     ·_user     1.3.3  执行命令     有两种命令可以在SQL*Plus中执行:SQL语句和SQL*Plus命令。代码清单1-5和代码清单1-6中所列出的SQL*Plus命令对于SQL*Plus来说是特有的命令,可以用来定制运行环境并且可以运行SQL*Plus特有的命令,例如DESCRIBE和CONNECT。要想执行一个SQL*Plus命令,你只需在命令提示符后输入该命令然后敲回车,命令会自动被执行。另一方面,如果要执行SQL语句,就必须使用一个特定字符来表明你想要执行输入的语句,分号(;)或者斜线(/)都可以。使用分号的话可以直接放在输入命令的后面或者放在接下来的空行中,而斜线则必须放在接下来的空行中才可以被识别。代码清单1-8展示了如何使用这两种符号。     代码清单1-8  执行字符的用法     注意第5个在语句最后面加了一个斜线(/)的例子。光标移动到了下一行而不是立即执行语句命令。接下来,如果你再按一下回车键,语句就会被放入SQL*Plus的缓冲器中,但是也不执行。如果想要查看SQL*Plus缓冲器中的内容,可以使用list命令(也可以简写为l)。接下来如果你想在缓冲器中通过使用斜线(/)来执行语句[尽管斜线(/)命令本来就是这样来用的]在这里也将会返回一个错误。这是因为你最初在SQL语句的结尾敲入了一个斜线(/),而斜线(/)并不是一个有效的SQL命令,从而在语句想要执行的时候报错。     另外一种执行命令的方法是把命令放到一个文件中。你可以在SQL*Plus之外直接用文本编辑器生成这些文件,也可以在SQL*Plus中使用EDIT命令来直接调用编辑器。如果已经有了一个文件,EDIT命令可以打开这个文件,如果没有的话就会创建新的文件。文件必须放在默认文件夹中,否则你必须指定文件的全路径。想要设定所选择的编辑器,你只需要利用命令define_ editor='//myeditor.exe'来设置预定义变量_editor。具有.sql扩展名的文件在执行的时候不必敲入扩展名,通过@或START命令都可以执行。代码清单1-9中列出了这两个命令的用法。     代码清单1-9  执行.sql脚本文件     SQL*Plus具有很多特性和选项,以致于多得在这里不能一一列举。就本书需要而言,这种概述就已经足够了。但是,Oracle文档对SQL*Plus的用法给出了指导,而且很多的书,比如Beginning Oracle SQL,都对SQL*Plus作了更为深入的阐述,如果感兴趣你可以参考。     1.4  5个核心的SQL语句     SQL语言有很多不同的语句,但在整个职业生涯中,你可能只会用到其中很少的一部分。不过你所使用的几乎其他任何产品不也是这样的吗?据说有一个统计结果是,绝大多数人都仅使用了他们常用的软件产品或编程语言所有功能的20%甚至更少。我不知道这个统计真实与否,但以我的经验来看,这似乎是很准确的。我发现同样的基本SQL语句格式在大多数应用中使用了将近20年了。极少数的人使用过SQL提供的所有功能——即使对于那些他们确实经常使用的功能也常常用得不是很恰当。显而易见,我们不可能覆盖SQL语言的所有语句以及它们的选项。本书的目的在于让你能够深入理解那些最常用的SQL语句并帮助你更高效地使用它们。     在本书中,我们将重点讨论5个最常用的SQL语句,它们分别为SELECT、INSERT、UPDATE、DELETE以及MERGE。尽管这些核心语句都将逐个讲解,但重中之重还是SELECT语句。将这5个语句用好了将会为你在日常工作中用好SQL语言打下坚实的基础。     1.5  SELECT语句     SELECT语句用来从一个或多个表中或者其他数据库对象中提取数据。你应该已经很熟悉SELECT语句的基础知识了,所以我将不再从一个初学者的角度来介绍SELECT语句,而是首先回顾一下SELECT语句的执行逻辑。对于如何来写一个基本的SELECT语句你应该已经学习过了,但为了培养基本的思维模式,你要一直写出符合语法规则的高效SQL语句,你需要理解SQL语句是如何执行的。     一个查询语句在逻辑上的处理方式可能会与实际物理处理过程大相径庭。Oracle基于查询成本的优化器(cost-based optimizer , CBO)用来产生实际的执行计划。我们在后面的章节中将会讲解优化器是干什么的,如何来实现其功能的以及为什么要进行优化。目前,我们需要关心的是优化器将会决定如何访问表、按照什么样的顺序来处理它们,以及如何将多个表联结起来及如何使用筛选器。查询的处理在逻辑上是按照特定的顺序进行的,但是,优化器所选择的物理执行计划可能会按照完全不同的顺序来实际执行这些步骤。代码清单1-10是一段包含SELECT语句的主要子句的查询片段,在其中标出了每一个子句的逻辑处理顺序。     代码清单1-10  查询语句的逻辑处理顺序     你应该立刻注意到SQL有别于其他编程语言的一点在于首先处理的并不是写在第一行的语句SELECT语句),而是FROM子句。注意在这个代码清单中我给出了两个不同的FROM子句。标记为1.1的那个FROM子句表示的是当使用ANSI语法时的不同。我们可以把处理过程中的每一个步骤想象为生成一个临时的数据集。随着每个处理步骤的进行,这个数据集被不断地操作直到生成最终的处理结果。查询返回给调用者的就是这个最终结果数据集。     为了更详细地了解SELECT语句的每个部分,你可以参考代码清单1-11所示的查询语句,该语句返回的结果集为下订单超过4次的女顾客的列表。     代码清单1-11  下订单超过4次的女顾客查询语句     1.5.1  FROM子句     FROM子句列出了所查询数据的源对象。这个子句可以包含表、视图、物化视图、分区或子分区,或者你可以建立一个子查询来生成子对象。如果使用了多个源对象,其逻辑处理阶段也将会应用到每一个联结类型以及谓词ON(如步骤1.1所示)。在本书后面的章节中你将会进一步了解联结类型的更多细节,但注意在处理联结语句的时候是按照下面的顺序来进行的:     (1) 交叉联结,也称为笛卡儿乘积;     (2) 内联结;     (3) 外联结。     在代码清单1-11所示的查询例子中,FROM子句列出了两张表:customers和orders,通过customer_id列来联结。因此,当处理这一信息时,FROM子句所生成的初始数据集将会包含这两张表中customer_id相匹配的行。在本例中结果集将会包含105行。为了验证这一点,只要执行例子中的前4行,如代码清单1-12所示。     代码清单1-12  仅通过FROM子句的部分查询语句的执行     注意 为了使之很好地适应页面我手工调整了输出结果,实际输出结果在页面上超过105行。     1.5.2  WHERE子句     WHERE子句提供了一种方法,可以按照条件来限制查询最终返回结果集的行数。每个条件或者谓语都是以两个值或表达式相比较的形式出现的。比较的结果要么是匹配(值为TRUE)要么是不匹配(值为FALSE)。如果比较的结果是FALSE,那么相应的行不会被包含在最终结果集中。     这里我需要稍微偏离一下主题,来谈一谈与这一步相关的SQL中的一个重要方面。事实上,SQL中逻辑比较的可能结果是TRUE、FALSE以及未知。当其中包含空值(null)的时候比较的结果就会是未知。空值与任何值比较或者用在表达式中都会得到空值,或者是未知。一个空值代表一个相应值的缺失,并且可能因为SQL语言中的不同部分对空值的处理不同而令人费解。关于空值是如何影响SQL语句执行的话题将会贯穿本书,但在这里我不得不先提及一下这个话题。我之前所说的还是基本正确的,一个比较的返回值将会是TRUE或者FALSE。你会发现当进行筛选的比较条件中包含空值的时候,将作为FALSE来对待。     在我们的例子中,只有一个将结果限定为下了订单的女性消费者的谓语。如果你查看FROM子句执行之后的中间结果(见代码清单1-12),你会发现105行中仅有31行是由女性消费者所下的订单(gender = 'F')。因此,在应用了WHERE子句以后,中间结果集将从105行减少到31行。     应用WHERE子句以后得到了更精确的结果集。注意,在这里使用的是“精确的结果集”。我的意思是说现在已经得到了能够满足你查询需求的数据行。其他子句(GROUP BY, HAVING)也许可以用来聚合并且进一步限制调用程序会接收到的最终的结果集,但需要注意的很重要的一点是,目前已经得到了查询计算最终结果所需的所有数据。     WHERE子句的目的是限制或者减小结果集。你所使用的限制条件越少,最终返回的结果集中包含的数据就会越多。你需要返回的数据越多,执行查询的时间也就越长。     1.5.3  GROUP BY子句     GROUP BY子句将执行FROM和WHERE子句后得到的经过筛选后的结果集进行聚合。查询出来的结果按照GROUP BY子句中列出的表达式进行分组,来为每一个分组得出一行汇总结果。你可以按照FROM子句中所列出对象的任意字段进行分组,即使你并不想在输出结果列表中显示该列。相反,Select列表中的任何非聚合字段都必须包括在GROUP BY表达式中。     GROUP BY子句中还可以包含两个附加的运算:ROLLUP 和CUBE。ROLLUP运算用来产生部分求和值,CUBE运算用来求得交互分类值。当你使用这两种运算中任意一个的时候,你将会得到不止一行的汇总信息。在第7章中将会对这两个运算进行更详细的讨论。     在示例查询中,需要按照customer_id来进行分组。这就意味着对于每一个唯一的customer_id只会返回一行值。在WHERE子句执行后所得到的代表下订单的女性消费者的31行订单中,有11个独特的customer_id值,如代码清单1-13所示。     代码清单1-13  截至GROUP BY子句的部分查询执行     你会发现查询的结果是经过分组的,但并没有排序。表面上看结果好像是按照order_ct字段排序的,但这仅仅是个巧合而不是确定的行为。需要记住的很重要的一点是:GROUP BY子句并不确定结果数据的排序。如果你需要结果按照特定的顺序排列,则必须指定一个order by子句。     1.5.4  HAVING子句     HAVING子句将分组汇总后的查询结果限定为只有该子句中的条件为真的数据行。除非你使用HAVING子句,否则将返回所有的汇总行。事实上,GROUP BY子句和HAVING子句的位置是可以互换的,谁先谁后都无关紧要。但是,似乎在编码中将GROUP BY子句放在前面更有意义一些,因为GROUP BY子句在逻辑上是先执行的。从本质上来说,HAVING子句是在GROUP BY子句执行后用来筛选汇总值的第二个WHERE子句。     在我们的查询例子中,HAVING子句HAVING COUNT(o.order_id) > 4,将分组数据从11行减少到2行。这一点你可以通过查看GROUP BY子句应用后返回的结果行来确认,如代码清单1-13所示。注意仅有146和147号消费者所下的订单数超过4次。这样就产生了组成最终结果集的两行数据。     1.5.5  SELECT列表     SELECT列表列出查询的返回最终结果集中需要显示哪些列。这些列可以是数据表中一个实际的列、一个表达式,或者甚至是一个SELECT语句的结果,如代码清单1-14所示。     代码清单1-14  展现SELECT列表各种可能情况的查询实例     SQL> select.customer_id, c.cust_first_name||''||c.cust_last_name,     .     当使用另外一个SELECT语句来产生结果中的一列的值的时候,这个查询必须只能返回一行一列的值。这种类型的子查询被称为标量子查询。尽管这可能是一个非常有用的语法,但需要牢记于心的是标量查询在结果集中的每一行结果产生时都要执行一遍。在某些情况下可以进行优化以减少标量子查询的重复执行,但更糟糕的场景是每一行都需要标量子查询执行。你可以想象如果你的结果集中有几千行甚至上百万行数据的时候所需要付出的查询代价!在后面的章节中我们还将回顾标量子查询并讨论如何更好地来使用它们。     在SELECT列表中你还有可能用到的一个选项是DISTINCT子句。在例子中并没有使用它,但我想要简要地提及一下。DISTINCT子句用来在其他子句执行完毕以后从结果集中去除重复的行。     SELECT列表执行完以后,你就得到了最终的查询结果集。所剩的唯一需要做的事情,如果包含了的话,就是将查询结果集按照所需的顺序排序。     1.5.6  ORDER BY子句     ORDER BY子句用来对查询最终返回的结果集进行排序。在本例中,需要按照orders_ct和customer_id进行排序。orders_ct这一列是通过GROUP BY子句中的COUNT聚合函数计算得到的值。如代码清单1-13中所示,有两个消费者的订单超过4个。由于这两个消费者的订单数都是5份,orders_ct这一列的值是相同的,所以要由第二个排序列来确定最终结果的显示顺序。如代码清单1-15中所示,该查询的最终经过排序的输出结果是按照customer_id排序的两行数据集。     代码清单1-15  示例查询的最终输出     当输出结果需要排序的时候,Oracle必须在其他所有子句都执行完之后按照指定的顺序对最终结果集进行排序。需要排序的数据量大小是非常重要的。我这里所说的大小是指结果集中所包含的总字节数。你可以通过用行数乘以每一行的字节数来估计数据集的大小。每行所包含的字节数通过将选择列表中包含的每一列的平均长度相加来确定。     上面的查询实例在选择列表中仅需要列出customer_id 和orders_ct两列的值。我们可以估算每一行输出值的字节数为10。在第6章中我将阐述从哪里能找到优化器所估计的值。因此,如果我们在结果集中只有两行数据,排序的大小实际上是很小的,大约20字节。请记住这仅仅是估算,但这样的估算也是很重要的。     较小的排序会完全在内存中来实现,而较大的排序将不得不使用临时磁盘空间来完成。如你可能推断的那样,在内存中完成的排序比必须使用磁盘的排序要快。因此,当优化器估算排序数据的影响时,它必须要考虑排序数据集的大小,以此来调整如何能够以最有效的方法来获得查询的结果。一般来说,排序是查询过程中开销相当大的一个处理步骤,尤其是当返回结果集很大的时候。     1.6  INSERT语句     INSERT语句用来向表、分区或视图中添加行。可以向单表或者多个表方法中添加数据行。单表插入将会向一个表中插入一行数据,这行数据可以显式地列出插入值也可以通过一个子查询来获取。多表插入将会向一个或多个表中插入行,并且会通过子查询获取值来计算所插入行的值。     1.6.1  单表插入     代码清单1-16中的第一个例子阐明了使用values子句实现的单表插入。每一列的值都显式地输入。如果你要插入表中所定义的所有列的值,那么列的列表是可选的。但是,如果你只想提供部分列的值,则必须在列的列表中指明所需的列名。好的做法是不管是不是需要插入所有列的值,都把所有列的列表列出来。这样做就像该语句的自述文件一样,并且也可以减少将来别人要插入一个新列到表中的时候可能出现的错误。     代码清单1-16  单表插入     第二个例子阐述了通过子查询来实现插入。这是插入数据行的一个非常灵活的选项。所写的子查询可以返回一行或多行数据。返回的每一行都会用来生成需要插入的新行的列值。根据你的需要这个子查询可以很简单也可以很复杂。在本例中,我们使用子查询实现了在现有薪水的基础上为每一位员工发放10%奖金的计算。事实上奖金表包含4列,但在这个插入中我们只列出了3个字段。comm这一列在子查询中并没有占据一列并且我们也没有将它包括在列表中。因为我们没有包含这一列,它的值将会是null。注意如果comm列具有非空约束,那么可能已返回一个约束错误,语句的执行也已失败。     1.6.2  多表插入     代码清单1-17所示的多表插入的例子阐明了一个子查询返回的数据行是如何被用来插入多个表中的。我们从3个表开始:small_customers、medium_customers以及large_customers。我们想要按照每位消费者所下订单的总金额来将数据分别插入这些表。子查询将每一位消费者的order_total列求和来确定该消费者的消费金额是小(所有订单的累加金额小于10 000美元)、中等(介于10 000美元与99 999.99美元之间)还是大(大于等于100 000美元),然后按照条件将这些行插入对应的表中。     代码清单1-17  多表插入     注意INSERT关键字后面ALL子句的使用。当指定了ALL子句的时候,这个语句就会执行无条件的多表插入。也就意味着每一个WHEN子句按照子查询所返回的每一行来确定值而不管前一个条件的输出结果是什么。因此,你需要注意如何来指定每个条件。例如,如果我使用WHEN sum_orders < 100 000这个条件而不是像上面一样列出范围,插入medium_customers表中的行有可能也会插入small_customers表中。     你需要指明FIRST选项来实现每一个WHEN子句按照其出现在语句中的顺序进行评估,并且对于一个给定的子查询行跳过接下来的WHEN子句评估。关键在于要记住哪一个选项能够更好地满足你的需要,ALL还是FIRST,然后使用最适合的选项。     1.7  UPDATE语句     UPDATE语句的作用是改变表中原有行的列值。这个语句的语法由3部分组成:UPDATE、SET和WHERE。UPDATE子句用来指定要更新的表,SET子句用来指明哪些列改变了以及调整的值,WHERE子句用来按条件筛选需要更新的行。WHERE子句是可选的,如果忽略了这个子句的话,更新操作将针对指定表中的所有行进行。     代码清单1-18列出了几种UPDATE语句的不同写法。首先,我建立了一个employees表的副本,名称为employees2,然后我将执行几个完成基本相同任务的不同更新操作:将90部门的员工工资增加10%。在例5中,commission_pct这一列也进行了更新。下面就是采用的不同方法。     例1:使用表达式更新一个单列的值。     例2:通过子查询更新一个单列的值。     例3:通过在WHERE子句中使用子查询确定要更新的数据行来更新单列的值。     例4:通过使用SELECT语句定义表及列的值来更新表。     例5:通过子查询更新多列。     代码清单1-18  UPDATE语句的例子     1.8  DELETE语句     DELETE语句用来从表中移除数据行。该语句的语法结构由3部分组成:DELETE、FROM和WHERE。DELETE关键字是单独列出的。除非你决定使用我们后面将会讨论到的提示(hint),没有其他选项与DELETE关键字相结合。FROM子句用来指定要从哪个表中删除数据行。如代码清单1-19中的例子所示,这个表可以直接指定也可以通过子查询来确定。WHERE子句提供筛选条件有助于确定哪些行是要删除的。如果忽略了WHERE子句,删除操作将删除指定表中的所有数据行。     代码清单1-19展示出了DELETE语句的几种不同写法。注意,在这些例子中我使用了代码清单1-18中创建的employees2表。下面你将看到的就是这些不同的删除方法。     例1:使用WHERE子句中的筛选条件来从指定表中删除行。     例2:使用FROM子句中的子查询来删除行。     例3:使用WHERE子句中的子查询来从指定表中删除行。     代码清单1-19  DELETE语句的例子     1.9  MERGE语句     MERGE语句具有按条件获取要更新或插入到表中的数据行,然后从1个或多个源头对表进行更新或者向表中插入行两方面的能力。它最经常被用在数据仓库中来移动大量的数据,但它的应用不仅限于数据仓库环境下。这个语句提供的一个很大的附加值在于你可以很方便地把多个操作结合成一个。这就使你可以避免使用多个INSERT、UPDATE以及DELETE语句。并且,在本书后面的内容中你将看到,如果你避免去做那些不是必须做的事情,响应时间可能得到相应的改善。     MERGE语句的语法是:     为了说明MERGE语句的用法,代码清单1-20展示出了如何建立一个测试表,然后恰当地利用MERGE条件来向表中插入或更新行。     代码清单1-20  MERGE语句例子     MERGE语句完成了下面这些事情。     ·插入了两行(员工id 106和107)。     ·更新了一行(员工id 105)。     ·删除了一行(员工id 103)。     ·一行保持不变(员工id 104)。     如果没有MERGE语句,你必须最少写3条不同的语句来完成同样的事情。     1.10  小结     正如你可以从到目前为止的例子中看出的,SQL语言提供了很多不同的选择来得到同样的结果集。你可能还注意到了一点就是这5个核心的SQL语句都可以使用类似的构造,例如子查询。关键是需要搞清楚在各种不同的使用场景下哪种构造是最高效的。我们将在本书后面的内容中阐述如何做到这一点。     如果你对本章的例子的理解有任何困难,请一定花点时间复习Beginning Oracle SQL或者Oracle文档中的SQL Reference Guide。在本书中接下来的部分我们假设你已经很好地理解了5个核心SQL语句的基本构造:SELECT、INSERT、UPDATE、DELETE和MERGE。
-- 首先,以超级管理员的身份登录oracle sqlplus sys/bjsxt as sysdba --然后,解除对scott用户的锁 alter user scott account unlock; --那么这个用户名就能使用了。 --(默认全局数据库名orcl) 1、select ename, sal * 12 from emp; --计算年薪 2、select 2*3 from dual; --计算一个比较纯的数据用dual表 3、select sysdate from dual; --查看当前的系统时间 4、select ename, sal*12 anuual_sal from emp; --给搜索字段更改名称(双引号 keepFormat 别名有特殊字符,要加双引号)。 5、--任何含有空值的数学表达式,最后的计算结果都是空值。 6、select ename||sal from emp; --(将sal的查询结果转化为字符串,与ename连接到一起,相当于Java中的字符串连接) 7、select ename||'afasjkj' from emp; --字符串的连接 8、select distinct deptno from emp; --消除deptno字段重复的值 9、select distinct deptno , job from emp; --将与这两个字段都重复的值去掉 10、select * from emp where deptno=10; --(条件过滤查询) 11、select * from emp where empno > 10; --大于 过滤判断 12、select * from emp where empno 10 --不等于 过滤判断 13、select * from emp where ename > 'cba'; --字符串比较,实际上比较的是每个字符的AscII值,与在Java中字符串的比较是一样的 14、select ename, sal from emp where sal between 800 and 1500; --(between and过滤,包含800 1500) 15、select ename, sal, comm from emp where comm is null; --(选择comm字段为null的数据) 16、select ename, sal, comm from emp where comm is not null; --(选择comm字段不为null的数据) 17、select ename, sal, comm from emp where sal in (800, 1500,2000); --(in 表范围) 18、select ename, sal, hiredate from emp where hiredate > '02-2月-1981'; --(只能按照规定的格式写) 19、select ename, sal from emp where deptno =10 or sal >1000; 20、select ename, sal from emp where deptno =10 and sal >1000; 21、select ename, sal, comm from emp where sal not in (800, 1500,2000); --(可以对in指定的条件进行取反) 22、select ename from emp where ename like '%ALL%'; --(模糊查询) 23、select ename from emp where ename like '_A%'; --(取第二个字母是A的所有字段) 24、select ename from emp where ename like '%/%%'; --(用转义字符/查询字段中本身就带%字段的) 25、select ename from emp where ename like '%$%%' escape '$'; --(用转义字符/查询字段中本身就带%字段的) 26、select * from dept order by deptno desc; (使用order by desc字段 对数据进行降序排列 默认为升序asc); 27、sel
### 回答1: SQL 语句判断时间区间有多种写法,下面列举常见的几种: 1. 使用 BETWEEN 运算符: ``` SELECT * FROM table_name WHERE date_column BETWEEN start_date AND end_date; ``` 2. 使用 >= 和 <= 运算符: ``` SELECT * FROM table_name WHERE date_column >= start_date AND date_column <= end_date; ``` 3. 使用 >= 和 < 运算符: ``` SELECT * FROM table_name WHERE date_column >= start_date AND date_column < end_date; ``` 这些都是常用的写法,具体选择哪种方法可以根据实际情况和需求决定。 ### 回答2: SQL语句判断时间区间有几种常见的写法。以下是其中几种常用的写法: 1. 使用BETWEEN运算符: 使用BETWEEN运算符可以判断一个值是否在一个范围内,可以将时间字段和两个具体的时间值进行比较。例如,若要查询2019年1月1日至2019年12月31日之间的数据,可以使用以下语句SELECT * FROM table_name WHERE date_column BETWEEN '2019-01-01' AND '2019-12-31'; 2. 使用大于号和小于号: 可以使用大于号和小于号将时间字段和具体的时间值进行比较。例如,若要查询2019年1月1日至2019年12月31日之间的数据,可以使用以下语句SELECT * FROM table_name WHERE date_column >= '2019-01-01' AND date_column <= '2019-12-31'; 3. 使用DATE_ADD和DATE_SUB函数: 可以使用DATE_ADD和DATE_SUB函数来对时间字段进行加减操作,从而完成时间区间的判断。例如,若要查询最近一个月的数据,可以使用以下语句SELECT * FROM table_name WHERE date_column >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH); 这几种写法都可以用来判断时间区间。根据具体的需求和数据库系统的不同,选择合适的写法即可。需要注意的是,在使用这些方法判断时间区间时,要确保时间字段和比较的时间值的格式一致。 ### 回答3: 在SQL语句中,有多种方法可以判断时间区间。 1. 使用BETWEEN和AND操作符:这是一种常见的方法,在WHERE子句中使用BETWEEN和AND操作符,将开始时间和结束时间作为参数传递。例如: SELECT * FROM 表名 WHERE 时间列名 BETWEEN '开始时间' AND '结束时间'; 2. 使用大于或等于(>=)和小于或等于(<=)操作符:这种方法使用>=和<=操作符来比较时间列和指定的开始和结束时间。例如: SELECT * FROM 表名 WHERE 时间列名 >= '开始时间' AND 时间列名 <= '结束时间'; 3. 使用大于(>)和小于(<)操作符:这种方法将开始时间和结束时间作为参数传递,并使用大于和小于操作符进行比较。例如: SELECT * FROM 表名 WHERE 时间列名 > '开始时间' AND 时间列名 < '结束时间'; 4. 使用DATEPART函数:DATEPART函数可以提取日期和时间的特定部分,如年、月、日等。可以使用DATEPART函数将时间列和指定的开始和结束时间进行比较。例如: SELECT * FROM 表名 WHERE DATEPART(部分, 时间列名) >= DATEPART(部分, '开始时间') AND DATEPART(部分, 时间列名) <= DATEPART(部分, '结束时间'); 5. 使用DATEDIFF函数:DATEDIFF函数可以计算两个日期或时间之间的差值。可以使用DATEDIFF函数计算时间列与指定开始和结束时间的差值,并根据差值判断是否在时间区间内。例如: SELECT * FROM 表名 WHERE DATEDIFF(单位, 开始时间, 时间列名) >= 0 AND DATEDIFF(单位, 结束时间, 时间列名) <= 0; 这些是一些常见的SQL语句判断时间区间的写法。根据具体情况和需求,可以选择最合适的写法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

q1054261752

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值