zoukankan      html  css  js  c++  java
  • oracle 優化

    ORACLE SQL优化

    1 选择最有效率的表名顺序(只在基于规则的优化器中有效)
    ORACLE
    的解析器按照从右到左的顺序处理FROM 子句中的表名,FROM 子句中写在最后的表
    (
    基础表driving table)将被最先处理,在FROM 子句中包含多个表的情况下,你必须选择记
    录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersec
    tion table)
    作为基础表, 交叉表是指那个被其他表所引用的表.
    2 WHERE 子句中的连接顺序.:
    ORACLE
    采用自下而上的顺序解析WHERE 子句,根据这个原理,表之间的连接必须写在其他WHE
    RE
    条件之前, 那些可以过滤掉最大数量记录的条件必须写在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 , 回滚段不再存放任何可被恢复的信息.
    当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短. (译者按: TRU
    NCATE
    只在删除全表适用,TRUNCATE DDL 不是DML)
    10 尽量多使用COMMIT
    只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT
    所释放的资源而减少:
    COMMIT
    所释放的资源:
    a.
    回滚段上用于恢复数据的信息.
    b.
    被程序语句获得的锁
    c. redo log buffer
    中的空间
    d. ORACLE
    为管理上述3种资源中的内部花费
    11 Where 子句替换HAVING 子句:
    避免使用HAVING 子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处
    理需要排序,总计等操作. 如果能通过WHERE 子句限制记录的数目,那就能减少这方面的开
    . (oracle )onwherehaving 这三个都可以加条件的子句中,on 是最先执行,whe
    re
    次之,having 最后,因为on 是先把不符合条件的记录过滤后才进行统计,它就可以减少
    中间运算要处理的数据,按理说应该速度是最快的, where 也应该比having 快点的,因为
    它过滤数据后才进行sum,在两个表联接时才用on 的,所以在一个表的时候,就剩下where
    having 比较了。在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,
    那它们的结果是一样的,只是where 可以使用rushmore 技术,而having 就不能,在速度上
    后者要慢如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,根据
    上篇写的工作流程,where 的作用时间是在计算之前就完成的,而having 就是在计算后才
    起作用的,所以在这种情况下,两者的结果会不同。在多表联接查询时, on where 更早
    起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where
    进行过滤,然后再计算,计算完后再由having 进行过滤。由此可见,要想过滤条件起到正
    确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里
    12 减少对表的查询:
    在含有子查询的SQL 语句中,要特别注意减少对表的查询.例子:
    SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
    TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
    13 通过内部函数提高SQL 效率.
    复杂的SQL 往往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中
    是非常有意义的
    14 使用表的别名(Alias)
    当在SQL 语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column .这样一来,
    就可以减少解析的时间并减少那些由Column 歧义引起的语法错误.
    15 EXISTS 替代IN、用NOT EXISTS 替代NOT IN
    在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况
    , 使用EXISTS(NOT EXISTS)通常将提高查询的效率. 在子查询中,NOT IN 子句将执行
    一个内部的排序和合并. 无论在哪种情况下,NOT IN 都是最低效的(因为它对子查询中的
    表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Join
    s)
    NOT EXISTS.
    例子:
    (高效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X'
    FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB')
    (
    低效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEP
    TNO FROM DEPT WHERE LOC = ‘MELB')
    16 识别'低效执行'SQL 语句:
    虽然目前各种关于SQL 优化的图形化工具层出不穷,但是写出自己的SQL 工具来解决问题始
    终是一个最好的方法:
    SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,
    ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,
    ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,
    SQL_TEXT
    FROM V$SQLAREA
    WHERE EXECUTIONS>0
    AND BUFFER_GETS > 0
    AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
    ORDER BY 4 DESC;
    17
    用索引提高效率:
    索引是表的一个概念部分,用来提高检索数据的效率,ORACLE 使用了一个复杂的自平衡B-tr
    ee
    结构. 通常,通过索引查询数据比全表扫描要快. ORACLE 找出执行查询和Update 语句
    的最佳路径时, ORACLE 优化器将使用索引. 同样在联结多个表时使用索引也可以提高效率.
    另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证.那些LONG LONG
    RAW
    数据类型, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特别有效. 当然,
    你也会发现, 在扫描小表时,使用索引同样能提高效率. 虽然使用索引能得到查询效率的提
    ,但是我们也必须注意到它的代价. 索引需要空间来存储,也需要定期维护, 每当有记录
    在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的INSERT , DEL
    ETE , UPDATE
    将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,
    那些不必要的索引反而会使查询反应时间变慢.。定期的重构索引是有必要的.
    ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
    18
    EXISTS 替换DISTINCT
    当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT 子句中使用D
    ISTINCT.
    一般可以考虑用EXIST 替换, EXISTS 使查询更为迅速,因为RDBMS 核心模块将在
    子查询的条件一旦满足后,立刻返回结果. 例子:
    (
    低效):
    SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E
    WHERE D.DEPT_NO = E.DEPT_NO
    (
    高效):
    SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X'
    FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);
    19 sql 语句用大写的;因为oracle 总是先解析sql 语句,把小写的字母转换成大写的
    再执行
    20 java 代码中尽量少用连接符连接字符串!
    21 避免在索引列上使用NOT 通常,
    我们要避免在索引列上使用NOT, NOT 会产生在和在索引列上使用函数相同的影响. ORAC
    LE”
    遇到”NOT,他就会停止使用索引转而执行全表扫描.
    22 避免在索引列上使用计算.
    WHERE
    子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描.
    举例:
    低效:
    SELECT … FROM DEPT WHERE SAL * 12 > 25000;
    高效:
    SELECT … FROM DEPT WHERE SAL > 25000/12;
    23 >=替代>
    高效:
    SELECT * FROM EMP WHERE DEPTNO >=4
    低效:
    SELECT * FROM EMP WHERE DEPTNO >3
    两者的区别在于, 前者DBMS 将直接跳到第一个DEPT 等于4的记录而后者将首先定位到DEPT
    NO=3
    的记录并且向前扫描到第一个DEPT 大于3的记录.
    24 UNION 替换OR (适用于索引列)
    通常情况下, UNION 替换WHERE 子句中的OR 将会起到较好的效果. 对索引列使用OR 将造
    成全表扫描. 注意, 以上规则只针对多个索引列有效. 如果有column 没有被索引, 查询效
    率可能会因为你没有选择OR 而降低. 在下面的例子中, LOC_ID REGION 上都建有索引.
    高效:
    SELECT LOC_ID , LOC_DESC , REGION
    FROM LOCATION
    WHERE LOC_ID = 10
    UNION
    SELECT LOC_ID , LOC_DESC , REGION
    FROM LOCATION
    WHERE REGION = “MELBOURNE”
    低效:
    SELECT LOC_ID , LOC_DESC , REGION
    FROM LOCATION
    WHERE LOC_ID = 10 OR REGION = “MELBOURNE”
    如果你坚持要用OR, 那就需要返回记录最少的索引列写在最前面.
    25 IN 来替换OR
    这是一条简单易记的规则,但是实际的执行效果还须检验,在ORACLE8i 下,两者的执行路
    径似乎是相同的.
    低效:
    SELECT…. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30
    高效
    SELECT… FROM LOCATION WHERE LOC_IN IN (10,20,30);
    26 避免在索引列上使用IS NULL IS NOT NULL
    避免在索引中使用任何可以为空的列,ORACLE 将无法使用该索引.对于单列索引,如果列
    包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在
    此记录. 如果至少有一个列不为空,则记录存在于索引中.举例: 如果唯一性索引建立在
    表的A 列和B 列上, 并且表中存在一条记录的A,B 值为(123,null) , ORACLE 将不接受下一
    条具有相同A,B 值(123,null)的记录(插入). 然而如果所有的索引列都为空,ORACLE
    认为整个键值为空而空不等于空. 因此你可以插入1000 条具有相同键值的记录,当然它们
    都是空! 因为空值不存在于索引列中,所以WHERE 子句中对索引列进行空值比较将使ORACLE
    停用该索引.
    低效: (索引失效)
    SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL;
    高效: (索引有效)
    SELECT … FROM DEPARTMENT WHERE DEPT_CODE >=0;
    27 总是使用索引的第一个列:
    如果索引是建立在多个列上, 只有在它的第一个列(leading column)where 子句引用时,
    优化器才会选择使用该索引. 这也是一条简单而重要的规则,当仅引用索引的第二个列时,
    优化器使用了全表扫描而忽略了索引
    28
    UNION-ALL 替换UNION ( 如果有可能的话)
    SQL 语句需要UNION 两个查询结果集合时,这两个结果集合会以UNION-ALL 的方式被合
    , 然后在输出最终结果前进行排序. 如果用UNION ALL 替代UNION, 这样排序就不是必要
    . 效率就会因此得到提高. 需要注意的是,UNION ALL 将重复输出两个结果集合中相同记
    . 因此各位还是要从业务需求分析使用UNION ALL 的可行性. UNION 将对结果集合排序,
    这个操作会使用到SORT_AREA_SIZE 这块内存. 对于这块内存的优化也是相当重要的. 下面
    SQL 可以用来查询排序的消耗量
    低效:
    SELECT ACCT_NUM, BALANCE_AMT
    FROM DEBIT_TRANSACTIONS
    WHERE TRAN_DATE = '31-DEC-95'
    UNION
    SELECT ACCT_NUM, BALANCE_AMT
    FROM DEBIT_TRANSACTIONS
    WHERE TRAN_DATE = '31-DEC-95'
    高效:
    SELECT ACCT_NUM, BALANCE_AMT
    FROM DEBIT_TRANSACTIONS
    WHERE TRAN_DATE = '31-DEC-95'
    UNION ALL
    SELECT ACCT_NUM, BALANCE_AMT
    FROM DEBIT_TRANSACTIONS
    WHERE TRAN_DATE = '31-DEC-95'
    29 WHERE 替代ORDER BY
    ORDER BY
    子句只在两种严格的条件下使用索引.
    ORDER BY
    中所有的列必须包含在相同的索引中并保持在索引中的排列顺序.
    ORDER BY
    中所有的列必须定义为非空.
    WHERE
    子句使用的索引和ORDER BY 子句中所使用的索引不能并列.
    例如:
    DEPT 包含以下列:
    DEPT_CODE PK NOT NULL
    DEPT_DESC NOT NULL
    DEPT_TYPE NULL
    低效: (索引不被使用)
    SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_TYPE
    高效: (使用索引)
    SELECT DEPT_CODE FROM DEPT WHERE DEPT_TYPE > 0
    30 避免改变索引列的类型.:
    当比较不同数据类型的数据时, ORACLE 自动对列进行简单的类型转换.
    假设EMPNO 是一个数值类型的索引列.
    SELECT … FROM EMP WHERE EMPNO = ‘123'
    实际上,经过ORACLE 类型转换, 语句转化为:
    SELECT … FROM EMP WHERE EMPNO = TO_NUMBER(‘123')
    幸运的是,类型转换没有发生在索引列上,索引的用途没有被改变.
    现在,假设EMP_TYPE 是一个字符类型的索引列.
    SELECT … FROM EMP WHERE EMP_TYPE = 123
    这个语句被ORACLE 转换为:
    SELECT … FROM EMP WHERETO_NUMBER(EMP_TYPE)=123
    因为内部发生的类型转换, 这个索引将不会被用到! 为了避免ORACLE 对你的SQL 进行隐式
    的类型转换, 最好把类型转换用显式表现出来. 注意当字符和数值比较时, ORACLE 会优先
    转换数值类型到字符类型
    31 需要当心的WHERE 子句:
    某些SELECT 语句中的WHERE 子句不使用索引. 这里有一些例子.
    在下面的例子里, (1)‘!=' 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不
    能告诉你什么不存在于表中. (2) ‘||'是字符连接函数. 就象其他函数那样, 停用了索引.
    (3) ‘+'
    是数学函数. 就象其他数学函数那样, 停用了索引. (4)相同的索引列不能互相
    比较,这将会启用全表扫描.
    32 a. 如果检索数据量超过30%的表中记录数.使用索引将没有显著的效率提高.
    b.
    在特定情况下, 使用索引也许会比全表扫描慢, 但这是同一个数量级上的区别. 而通常
    情况下,使用索引比全表扫描要块几倍乃至几千倍!
    33 避免使用耗费资源的操作:
    带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY SQL 语句会启动SQL 引擎
    执行耗费资源的排序(SORT)功能. DISTINCT 需要一次排序操作, 而其他的至少需要执行两
    次排序. 通常, 带有UNION, MINUS , INTERSECT SQL 语句都可以用其他方式重写. 如果
    你的数据库的SORT_AREA_SIZE 调配得好, 使用UNION , MINUS, INTERSECT 也是可以考虑
    , 毕竟它们的可读性很强
    34 优化GROUP BY:
    提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉.下面两个
    查询返回相同结果但第二个明显就快了许多.
    低效:
    SELECT JOB , AVG(SAL)
    FROM EMP
    GROUP by JOB
    HAVING JOB = ‘PRESIDENT'
    OR JOB = ‘MANAGER'
    高效:
    SELECT JOB , AVG(SAL)
    FROM EMP
    WHERE JOB = ‘PRESIDENT'
    OR JOB = ‘MANAGER'
    GROUP by JOB

    下面是Oracle支持的字符函数和它们的Microsoft SQL Server等价函数。

    函数 Oracle Microsoft SQL Server
    把字符转换为ASCII :ASCII ASCII
    字串连接: CONCAT --------------(expression + expression)
    ASCII转换为字符 CHR, CHAR
    返回字符串中的开始字符(左起) INSTR ,---------------CHARINDEX
    把字符转换为小写 LOWER ---------------------LOWER
    把字符转换为大写 UPPER-------------------- UPPER
    填充字符串的左边 LPAD --------------------N/A
    清除开始的空白 LTRIM--------------------LTRIM
    清除尾部的空白 RTRIM --------------------RTRIM
    字符串中的起始模式(pattern INSTR --------------------PATINDEX
    多次重复字符串 RPAD --------------------REPLICATE
    字符串的语音表示 SOUNDEX --------------------SOUNDEX
    重复空格的字串 RPAD --------------------SPACE
    从数字数据转换为字符数据 TO_CHAR --------------------STR
    子串 SUBSTR --------------------SUBSTRING
    替换字符 REPLACE --------------------STUFF
    将字串中的每个词首字母大写 INITCAP --------------------N/A
    翻译字符串 TRANSLATE --------------------N/A
    字符串长度 LENGTH-------------------- DATELENGTH or LEN
    列表中最大的字符串 GREATEST-------------------- N/A
    列表中最小的字符串 LEAST --------------------N/A
    如果为NULL则转换字串 NVL-------------------- ISNULL

     

    日期函数

    下面是Oracle支持的日期函数和它们的Microsoft SQL Server等价函数。

    函数 Oracle --------------------Microsoft SQL Server
    日期相加 (date column +/- value) or ADD_MONTHS  --------------------DATEADD

    两个日期的差 (date column +/- value) or MONTHS_BETWEEN  --------------------DATEDIFF
    当前日期和时间 SYSDATE --------------------GETDATE()
    一个月的最后一天 LAST_DAY  --------------------N/A
    时区转换 NEW_TIME  --------------------N/A
    日期后的第一个周日 NEXT_DAY  --------------------N/A
    代表日期的字符串 TO_CHAR --------------------DATENAME
    代表日期的整数 TO_NUMBER (TO_CHAR))  --------------------DATEPART
    日期舍入 ROUND  --------------------CONVERT
    日期截断 TRUNC  --------------------CONVERT
    字符串转换为日期 TO_DATE  --------------------CONVERT
    如果为NULL则转换日期 NVL -------------------- ISNULL

     

    转换函数

    下面是Oracle支持的转换函数和它们的Microsoft SQL Server等价函数。

    函数 Oracle  --------------------Microsoft SQL Server
    数字转换为字符 TO_CHAR  --------------------CONVERT
    字符转换为数字 TO_NUMBER  --------------------CONVERT
    日期转换为字符 TO_CHAR  --------------------CONVERT
    字符转换为日期 TO_DATE CONVERT
    16
    进制转换为2进制 HEX_TO_RAW  --------------------CONVERT
    2
    进制转换为16进制 RAW_TO_HEX  --------------------CONVERT

     

    其它行级别的函数

    下面是Oracle支持的其它行级别的函数以及它们的Microsoft SQL Server等价函数。

    函数 Oracle  --------------------Microsoft SQL Server
    返回第一个非空表达式 DECODE -------------------------------------COALESCE
    当前序列值 CURRVAL  --------------------N/A
    下一个序列值 NEXTVAL  --------------------N/A

    用户登录账号ID数字 UID --------------------SUSER_ID
    用户登录名 USER  --------------------SUSER_NAME
    用户数据库ID数字 UID  --------------------USER_ID
    用户数据库名 USER  --------------------USER_NAME
    当前用户 CURRENT_USER -------------------- CURRENT_USER
    用户环境(audit trail) USERENV  --------------------N/A
    CONNECT BY子句中的级别 LEVEL  --------------------N/A

     

    合计函数

    下面是Oracle支持的合计函数和它们的Microsoft SQL Server等价函数。

    函数 Oracle  --------------------Microsoft SQL Server
    Average AVG -------------------- AVG
    Count COUNT  --------------------COUNT
    Maximum MAX -------------------- MAX
    Minimum MIN  --------------------MIN
    Standard deviation STDDEV  --------------------STDEV or STDEVP
    Summation SUM -------------------- SUM
    Variance VARIANCE  --------------------VAR or VARP

     

    条件测试

    OracleDECODE语句和Microsoft SQL ServerCASE表达式都执行条件测试。
    test_value中的值和后面的任何表达式匹配的时候,相关的值就返回。如果没有找到任何匹配的值,就返回default_value
    如果没有指定default_value,在没有匹配的时候,DECODECASE都返回一个NULL下表显示了该语句的语法,
    同时给出了转换DECODE命令的示例。

    Oracle Microsoft SQL 
    DECODE (test_value,
    expression1, value1
    <,expression2, value2] […>
    [,default_value]
    )
    CREATE VIEW STUDENT_ADMIN.STUDENT_GPA
    (SSN, GPA)
    AS SELECT SSN, ROUND(AVG(DECODE(grade
    ,'A', 4
    ,'A+', 4.3
    ,'A-', 3.7
    ,'B', 3
    ,'B+', 3.3
    ,'B-', 2.7
    ,'C', 2
    ,'C+', 2.3
    ,'C-', 1.7
    ,'D', 1
    ,'D+', 1.3
    ,'D-', 0.7
    ,0)),2)
    FROM STUDENT_ADMIN.GRADE
    GROUP BY SSN
    CASE input_expression
    WHEN when_expression THEN
       result_expression

    [ELSE else_result_expression]
    END
    CREATE VIEW STUDENT_ADMIN.STUDENT_GPA
    (SSN, GPA)
    AS SELECT SSN, ROUND(AVG(CASE grade
    WHEN 'A' THEN 4
    WHEN 'A+' THEN 4.3
    WHEN 'A-' THEN 3.7
    WHEN 'B' THEN 3
    WHEN 'B+' THEN 3.3
    WHEN 'B-' THEN 2.7
    WHEN 'C' THEN 2
    WHEN 'C+' THEN 2.3
    WHEN 'C-' THEN 1.7
    WHEN 'D' THEN 1
    WHEN 'D+' THEN 1.3
    WHEN 'D-' THEN 0.7
    ELSE 0
    END),2)
    FROM STUDENT_ADMIN.GRADE
    GROUP BY SSN


     

    CASE表达式可以支持用SELECT语句执行布尔测试,这是DECODE命令所不允许的。欲了解关于CASE表达式的详细信息,
    请参阅SQL Server联机手册。

     

    把值转换为不同的数据类型

    Microsoft SQL ServerCONVERTCAST函数都是多目标转换函数。它们提供了相似的功能,
    把一种数据类型的表达式转换为另一种数据类型的表达式,并且支持多种专门数据的格式。

    CAST(expression AS data_type)
    CONVERT (data type[(length)], expression [, style])
    CAST
    是一个SQL-92标准的函数。这些函数执行同OracleTO_CHARTO_NUMBERTO_DATEHEXTORAW以及RAWTOTEXT函数相同的功能。

    这里所指的数据类型是任何表达式将被转换成为的系统数据类型。不能使用用户定义的数据类型。长度参数是可选的,
    该参数用于charvarcharbinary以及varbinary数据类型。允许的最大长度是8000

    转换 Oracle Microsoft SQL Server
    字符到数字 TO_NUMBER(')  --------------------CONVERT(numeric, ')
    数字到字符 TO_CHAR(10)  --------------------CONVERT(char, 10)
    字符到日期 TO_DATE(-JUL-97')
    TO_DATE(
    -JUL-1997','dd-mon-yyyy')

    TO_DATE('July 4, 1997', 'Month dd, yyyy') --------------------CONVERT(datetime, -JUL-97')

    CONVERT(datetime, -JUL-1997')
    CONVERT(datetime, 'July 4, 1997')
    日期到字符 TO_CHAR(sysdate)
    TO_CHAR(sysdate, 'dd mon yyyy')
    TO_CHAR(sysdate, 'mm/dd/yyyy') --------------------CONVERT(char, GETDATE())
    CONVERT(char, GETDATE(), 106)
    CONVERT(char, GETDATE(), 101)
    16
    进制到2进制 HEXTORAW(ƇF')-------------------- CONVERT(binary, ƇF')
    2
    进制到16进制 RAWTOHEX(binary_column) --------------------CONVERT(char, binary_column)


     

    请注意字符串是怎样转换为日期的。在Oracle中,缺省的日期格式模型是“DD-MON-YY”如果你使用任何其它格式,
    你必须提供一个合适的日期格式模型。CONVERT函数自动转换标准日期格式,不需要任何格式模型。

    从日期转换到字符串时,CONVERT函数的缺省输出是“dd mon yyyy hh:mm:ss:mmm(24h)”
    用一个数字风格代码来格式化输出,使它能输出为其它类型的日期格式模型。欲了解CONVERT函数的详细信息,请参阅SQL Server联机手册。

    下表显示了Microsoft SQL Server日期的缺省输出。

    Without Century With Century Standard Output
    - 0 or 100 (*) Default mon dd yyyy hh:miAM (or PM)
    1 101 USA mm/dd/yy
    2 102 ANSI yy.mm.dd
    3 103 British/French dd/mm/yy
    4 104 German dd.mm.yy
    5 105 Italian dd-mm-yy
    6 106 - dd mon yy
    7 107 - mon dd, yy
    8 108 - hh:mm:ss
    - 9 or 109 (*) Default milliseconds mon dd yyyy hh:mi:ss:mmm (AM or PM)
    10 110 USA mm-dd-yy
    11 111 Japan yy/mm/dd
    12 112 ISO yymmdd
    - 13 or 113 (*) Europe default dd mon yyyy hh:mm:ss:mmm(24h)
    14 114 - hh:mi:ss:mmm(24h)

     

    用户定义函数

    Oracle PL/SQL函数可以在Oracle SQL语句中使用。在Microsoft SQL Server中一般可以通过其它方式来实现同样的功能。

    SQL Server中可以用表中给出的查询来代替。

    Oracle Microsoft SQL Server
    SELECT SSN, FNAME, LNAME, )
       TUITION_PAID,
       TUITION_PAID/GET_SUM_
       MAJOR(MAJOR)
       AS PERCENT_MAJOR
    FROM STUDENT_ADMIN.STUDENT SELECT SSN, FNAME, LNAME, TUITION_PAID, TUITION_PAID/SUM_MAJOR AS PERCENT_MAJOR
    FROM STUDENT_ADMIN.STUDENT,
      (SELECT MAJOR,      SUM(TUITION_PAID) SUM_MAJOR
      FROM STUDENT_ADMIN.STUDENT
      GROUP BY MAJOR) SUM_STUDENT
    WHERE STUDENT.MAJOR =
         SUM_STUDENT.MAJOR
    CREATE OR REPLACE FUNCTION GET_SUM_MAJOR
    (INMAJOR VARCHAR2) RETURN NUMBER
    AS SUM_PAID NUMBER;
    BEGIN
    SELECT SUM(TUITION_PAID) INTO
       SUM_PAID
    FROM STUDENT_ADMIN.STUDENT
    WHERE MAJOR = INMAJOR;
    RETURN(SUM_PAID);
    END GET_SUM_MAJOR; No CREATE FUNCTION syntax is required; use CREATE PROCEDURE syntax.

     

    比较操作符

    OracleMicrosoft SQL Server的比较操作符几乎是一样的。

    算符 Oracle Microsoft SQL Server
    等于 (=) (=)
    大于 (>) (>)
    小于 (<) (<)
    大于或等于 (>=) (>=)
    小于或等于 (<=) (<=)
    不等于 (!=, <>, ^=) (!=, <>, ^=)
    不大于,不小于 N/A !> , !<
    在集合中任意成员中 IN IN
    不在集合中的任何成员中 NOT IN NOT IN
    集合中的任意值 ANY, SOME ANY, SOME
    提交集合中的所有值 != ALL, <> ALL, < ALL,
    > ALL, <= ALL, >= ALL, !=
     SOME, <> SOME,
    <
     SOME, > SOME,
    <=
     SOME, >= SOME != ALL, <> ALL, < ALL,
    > ALL, <= ALL, >= ALL, !=
     SOME, <> SOME,
    <
     SOME, > SOME,
    <=
     SOME, >= SOME
    像模式(Like pattern LIKE LIKE
    不像模式(Not like pattern NOT LIKE NOT LIKE
    X
    y之间的值 BETWEEN x AND y BETWEEN x AND y
    不在xy之间的值 NOT BETWEEN NOT BETWEEN
    值存在 EXISTS EXISTS
    值不存在 NOT EXISTS NOT EXISTS
    {|不为} IS NULL, IS NOT NULL Same. Also = NULL,
    !=
     NULL for backward compatibility (not recommended).

     

    模式匹配

    SQL ServerLIKE关键字提供了有用的通配符搜索功能,这个功能在Oracle中不支持
    除了所有的RDBMS都支持的(%)和(_)通配符以外,SQL Server还支持([ ])和([^])通配符。

    [ ])字符用来查询在一个范围内的所有单个字符。例如,如果你需要查询包含一个从af的字符的数据,
    你可以这样写:“LIKE '[a-f]'”或者“LIKE '[abcdef]'”。这些附加的通配符的有效性在下表中给出。

    Oracle Microsoft SQL 
    SELECT * FROM STUDENT_ADMIN.STUDENT
    WHERE LNAME LIKE 'A%'
    OR LNAME LIKE 'B%'
    OR LNAME LIKE 'C%' SELECT * FROM STUDENT_ADMIN.STUDENT
    WHERE LNAME LIKE '[ABC]%'

     

    [^]通配符用来标记那些不在特定范围内的字符。例如,如果除了af以外的所有字符都是可以接受的,你可以这样书写:
    LIKE '[^a - f]'
    或者LIKE '[^abcdef]'

    欲了解关于LIKE关键字的详细信息,请参阅SQL Server联机手册。

     

    在比较中使用NULL

    尽管Microsoft SQL Server传统上支持SQL-92标准的和一些非标准的NULL行为,但是它还是支持Oracle中的NULL的用法。

    为了支持分布式查询,SET ANSI_NULLS必须设定为ON

    在进行连接的时候,SQL ServerSQL Server ODBC驱动程序和OLE DB提供者自动把SET ANSI_NULLS设定为ON
    这个设置可以在ODBC数据源、ODBC连接属性、或者是在连接到SQL Server之前在应用程序中设置的OLE DB连接属性中进行配置。
    在从DB-Library应用程序中连接时,SET ANSI_NULLS缺省为OFF

    SET ANSI_DEFAULTSON时,SET ANSI_NULLS被允许。

    欲了解关于NULL用法的详细信息,请参阅SQL Server联机手册。

     

    字串连接

    Oracle使用两个管道符号(||)来作为字串连接操作符,SQL Server则使用加号(+)。这个差别要求你在应用程序中做小小的修改。

    Oracle Microsoft SQL 
    SELECT FNAME||' '||LNAME AS NAME
    FROM STUDENT_ADMIN.STUDENT
    -----------------------------------------------
     SELECT FNAME +' '+ LNAME AS
       NAME
    FROM STUDENT_ADMIN.STUDENT

     

    流控制(Control-of-Flow)语言

    流控制语言控制SQL语句执行流,语句块以及存储过程。PL/SQLTransact-SQL提供了多数相同的结构,但是还是有一些语法差别。

     

    关键字

    这是两个RDBMS支持的关键字。

    语句 Oracle PL/SQL ---------------------Microsoft SQL Server Transact-SQL

    声明变量 DECLARE DECLARE
    语句块 BEGIN...END; BEGIN...END
    条件处理 IF…THEN,
    ELSIF…THEN,
    ELSE
    ENDIF;
    --------------------------------------------------------
    IF…[BEGIN…END]
    ELSE <condition>
    [BEGIN…END]
    ELSE IF <condition>
    CASE expression
    无条件结束 RETURN------------ RETURN
    无条件结束当前程序块后面的语句 EXIT BREAK
    重新开始一个WHILE循环 N/A CONTINUE
    等待指定间隔 N/A (dbms_lock.sleep) WAITFOR
    循环控制 WHILE LOOP…END LOOP;
    ------------
    LABEL…GOTO LABEL;
    FOR…END LOOP;
    LOOP…END LOOP;
    WHILE <condition>
    BEGIN… END
    LABEL…GOTO LABEL

    程序注释 /* … */, -- /* … */, --
    打印输出 RDBMS_OUTPUT.PUT_LINE PRINT

    引发程序错误(Raise program error RAISE_APPLICATION_ERROR --------------------RAISERROR

    执行程序 EXECUTE----------------------EXECUTE
    语句终止符 Semicolon (;) ------------------N/A

     

    声明变量

    Transact-SQLPL/SQL的变量是用DECLARE关键字创建的。Transact-SQL变量用@标记,
    并且就像PL/SQL一样,在第一次创建时,用空值初始化。

    Oracle Microsoft SQL 
    DECLARE
    VSSN CHAR(9);
    VFNAME VARCHAR2(12);
    VLNAME VARCHAR2(20);
    VBIRTH_DATE DATE;
    VLOAN_AMOUNT NUMBER(12,2);
    -----------------------------------------
    DECLARE
    @VSSN CHAR(9),
    @VFNAME VARCHAR2(12),
    @VLNAME VARCHAR2(20),
    @VBIRTH_DATE DATETIME,
    @VLOAN_AMOUNT NUMERIC(12,2)

     

    Transact-SQL不支持%TYPE%ROWTYPE变量数据类型定义。一个Transact-SQL变量不能在DECLARE命令中初始化。
    Microsoft SQL Server数据类型定义中也不能使用OracleNOT NULLCONSTANT关键字。

    OracleLONGLONG RAW数据类型一样。文本和图形数据类型不能被用做变量定义。
    此外,Transact-SQL不支持PL/SQL风格的记录和表的定义。

     

    给变量赋值

    OracleMicrosoft SQL Server提供了下列方法来为本地变量赋值。

    Oracle Microsoft SQL 
    Assignment operator (:=) ---------------------SET @local_variable = value
    SELECT...INTO syntax for selecting column values from a single row
    -------------------------
    SELECT @local_variable = expression [FROM…] for assigning a literal value,
     an expression involving other local variables, or a column value from a single row

    FETCH…INTO syntax------------------------------- FETCH…INTO syntax

     

    这里有一些语法示例

    Oracle Microsoft SQL 
    DECLARE VSSN CHAR(9);
    VFNAME VARCHAR2(12);
    VLNAME VARCHAR2(20);
    BEGIN
    VSSN := ?'
    SELECT FNAME, LNAME INTO VFNAME, VLNAME FROM STUDENTS WHERE SSN=VSSN;
    END;
    ------------------------------------------------------------------------------
    DECLARE @VSSN CHAR(9),
    @VFNAME VARCHAR(12),
    @VLNAME VARCHAR(20)
    SET @VSSN = ?'
    SELECT @VFNAME=FNAME, @VLNAME=LNAME FROM STUDENTS WHERE SSN = @VSSN

     

    语句块

    Oracle PL/SQLMicrosoft SQL Server Transact-SQL都支持用BEGIN…END术语来标记语句块。
    Transact-SQL
    不需要在DECLARE语句后使用一个语句块。
    ---------------------------------------------------------------------------------
    -
    如果在Microsoft SQL Server
    中的IF语句和WHILE循环中有多于一个语句被执行,则需要使用BEGIN…END语句块。

    Oracle Microsoft SQL 
    DECLARE
    DECLARE VARIABLES ...
    BEGIN -- THIS IS REQUIRED SYNTAX
    PROGRAM_STATEMENTS ...
    IF ...THEN
    STATEMENT1;
    STATEMENT2;
    STATEMENTN;
    END IF;
    WHILE ... LOOP
    STATEMENT1;
    STATEMENT2;
    STATEMENTN;
    END LOOP;
    END; -- THIS IS REQUIRED SYNTAX DECLARE
    DECLARE VARIABLES ...
    BEGIN -- THIS IS OPTIONAL SYNTAX
    PROGRAM_STATEMENTS ...
    IF ...
    BEGIN
    STATEMENT1
    STATEMENT2
    STATEMENTN
    END
    WHILE ...
    BEGIN
    STATEMENT1
    STATEMENT2
    STATEMENTN
    END
    END -- THIS IS REQUIRED SYNTAX

     

    条件处理

    Microsoft SQL Server Transact-SQL的条件语句包括IFELSE,但不包括Oracle PL/SQL中的ELSEIF语句。
    可以用嵌套多重IF语句来到达同样的效果。对于广泛的条件测试,用CASE表达式也许更容易和可读一些。

    Oracle Microsoft SQL 
    DECLARE
    VDEGREE_PROGRAM CHAR(1);
    VDEGREE_PROGRAM_NAME VARCHAR2(20);
    BEGIN
    VDEGREE_PROGRAM := 'U'
    IF VDEGREE_PROGRAM = 'U' THEN
    VDEGREE_PROGRAM_NAME := 'Undergraduate'

    ELSIF VDEGREE_PROGRAM = 'M'         THEN VDEGREE_PROGRAM_
               NAME := 'Masters'
    ELSIF VDEGREE_PROGRAM = 'P'
               THEN VDEGREE_PROGRAM_
                  NAME := 'PhD'
    ELSE VDEGREE_PROGRAM_
                  NAME := 'Unknown'
    END IF;
    END;
    -----------------------------------------------------
    DECLARE
    @VDEGREE_PROGRAM CHAR(1),
    @VDEGREE_PROGRAM_NAME VARCHAR(20)
    SELECT @VDEGREE_PROGRAM = 'U'
    SELECT @VDEGREE_PROGRAM_
       NAME = CASE @VDEGREE_PROGRAM
       WHEN 'U' THEN 'Undergraduate'
       WHEN 'M' THEN 'Masters'
       WHEN 'P' THEN 'PhD'.
       ELSE 'Unknown'
    END

     

    重复执行语句(循环)

    Oracle PL/SQL提供了无条件的LOOPFOR LOOPTransact-SQL则提供了WHILE循环和GOTO语句。

    WHILE Boolean_expression
    {sql_statement | statement_block}

    [BREAK] [CONTINUE]


     

    WHILE循环需要测试一个布尔表达式来决定一个或者多个语句的重复执行。
    只要给定的表达式结果为真,这个(些)语句就一直重复执行下去。如果有多个语句需要执行,则这些语句必须放在一个BEGIN…END块中。

    Oracle Microsoft SQL 
    DECLARE
    COUNTER NUMBER;
    BEGIN
    COUNTER := 0
    WHILE (COUNTER <5) LOOP
    COUNTER := COUNTER + 1;
    END LOOP;
    END;
    ------------------------------------------------------
    DECLARE
    @COUNTER NUMERIC
    SELECT@COUNTER = 1
    WHILE (@COUNTER <5)
    BEGIN
       SELECT @COUNTER =
       @COUNTER +1
    END

     

    语句的执行可以在循环的内部用BREAKCONTINUE关键字控制。BREAK关键字使WHILE循环无条件的结束,
    CONTINUE关键字使WHILE循环跳过后面的语句重新开始。BREAK关键字同Oracle PL/SQL中的EXIT关键字是等价的。
    而在Oracle中没有和CONTINUE等价的关键字

    GOTO语句

    OracleMicrosoft SQL Server都有GOTO语句,但是语法不同。GOTO语句使Transact-SQL跳到指定的标号处运行,
    GOTO语句后指定标号之间的任何语句都不会被执行。

    Oracle Microsoft SQL 
    GOTO label;
    <<label name here>> GOTO label

     

    PRINT语句

    Transact-SQLPRINT语句执行同PL/SQLRDBMS_OUTPUT.put_line过程同样的操作。该语句用来打印用户给定的消息。

    PRINT语句打印的消息上限是8,000个字符。定义为char或者varchar数据类型的变量可以嵌入打印语句。
    如果使用其它数据类型的变量,则必须使用CONVERT或者CAST函数。本地变量、全局变量可以被打印。可以用单引号或者双引号来封闭文本。

     

    从存储过程返回

    Microsoft SQL ServerOracle都有RETURN语句。RETURN使你的程序从查询或者过程中无条件的跳出。RETURN是立即的、
    完全的、并且可以用于从过程、批处理或者语句块的任意部分跳出。在REUTRN后面的语句将不会被执行。

    Oracle Microsoft SQL 
    RETURN expression: RETURN [integer_expression]

     

    引发程序错误(Raising program errors

    Transact-SQLRAISERROR返回一个用户定义的错误消息,并且设置一个系统标志来记录发生了一个错误。
    这个功能同PL/SQLraise_application_error异常处理器的功能是相似的。

    RAISERROR语句允许客户重新取得sysmessages表的一个入口,或者用用户指定的严重性和状态信息动态的建立一条消息。
    在被定义后,消息被送回客户端作为系统错误消息。

    RAISERROR ({msg_id | msg_str}, severity, state
    [, argument1 [, argument2>)

    [WITH options]


     

    在转换你的PL/SQL程序时,也许用不着使用RAISERROR语句。在下面的示例代码中。
    PL/SQL程序使用raise_application_error异常处理器,但是Transact-SQL程序则什么也没用。
    包括raise_application_error异常处理器是为了防止PL/SQL返回不明确的未经处理的异常错误消息。
    作为代替,当一个不可预见的问题发生的时候,异常处理器总是返回Oracle错误消息。

    当一个Transact-SQL失败时,它总是返回一个详细的错误消息给客户程序。因此,除非需要某些特定的错误处理,
    一般是不需要RAISERROR语句的。

    Oracle Microsoft SQL 
    CREATE OR REPLACE FUNCTION
    DEPT_ADMIN.DELETE_DEPT
    (VDEPT IN VARCHAR2) RETURN NUMBER AS
    BEGIN
    DELETE FROM DEPT_ADMIN.DEPT
    WHERE DEPT = VDEPT;
    RETURN(SQL%ROWCOUNT);
    EXCEPTION
    WHEN OTHER THEN
    RAISE_APPLICATION_ERROR
    (-20001,SQLERRM);
    END DELETE_DEPT;
    ------------------------------------------------------
    / CREATE PROCEDURE
    DEPT_ADMIN.DELETE_DEPT
    @VDEPT VARCHAR(4) AS
    DELETE FROM DEPT_DB.DBO.DEPT
    WHERE DEPT = @VDEPT
    RETURN @@ROWCOUNT
    GO

     

    实现游标

    Oracle在使用SELECT语句时总是需要游标,不管从数据库中请求多少行。在Microsoft SQL Server
    SELECT
    语句并不把在返回客户的行上附加游标作为缺省的结果集合。这是一种返回数据给客户应用程序的有效的方法。

    SQL Server为游标函数提供了两种接口。当在Transact-SQL批处理或者存储过程中使用游标的时候,SQL语句可用来声明、
    打开、和从游标中抽取,就像定位更新和删除一样。当使用来自DB-LibraryODBC、或者OLEDB程序的游标时,SQL Server
    显式的调用内建的服务器函数来更有效的处理游标。

    当从Oracle输入一个PL/SQL过程时,首先判断是否需要在Transact-SQL中采用游标来实现同样的功能。如果游标仅仅返回一
    组行给客户程序,就使用非游标的SELECT语句来返回缺省的结果集合。如果游标用来从行中一次取得一个数据给本地过程变量,
    你就必须在Transact-SQL中使用游标。

     

    语法

    下表显示了使用游标的语法。

    操作 Oracle Microsoft SQL Server
    声明一个游标 CURSOR cursor_name [(cursor_parameter(s))]
    IS select_statement;
    ----------------------------------------------------
    DECLARE cursor_name CURSOR
    [LOCAL | GLOBAL]
    [FORWARD_ONLY | SCROLL]
    [STATIC | KEYSET | DYNAMIC | FAST_FORWARD]
    [READ_ONLY | SCROLL_LOCKS | OPTIMISTIC]
    [TYPE_WARNING]
    FOR select_statement
    [FOR UPDATE [OF column_name [,…n>]
    打开一个游标 OPEN cursor_name [(cursor_parameter(s))];
    ----------------
    OPEN cursor_name
    从游标中提取(Fetching FETCH cursor_name INTO variable(s)
    -------------------------------------------------------------------------------------------
    FETCH FROM] cursor_name
    [INTO @variable(s)]
    更新提取行 UPDATE table_name
    SET statement(s)…
    WHERE CURRENT OF cursor_name; UPDATE table_name
    SET statement(s)…
    WHERE CURRENT OF cursor_name
    删除提取行 DELETE FROM table_name
    WHERE CURRENT OF cursor_name; DELETE FROM table_name
    WHERE CURRENT OF cursor_name
    关闭游标 CLOSE cursor_name; CLOSE cursor_name
    清除游标数据结构 N/A DEALLOCATE cursor_name

     

    声明一个游标

    尽管Transact-SQL DECLARE CURSOR语句不支持游标参数的使用,但它确实支持本地变量。当游标打开的时候,
    它就使用这些本地变量的值。Microsoft SQL Server在其DECLARE CURSOR中提供了许多附加的功能。

    INSENSITIVE选项用来定义一个创建数据的临时拷贝以被游标使用的游标。游标的所有请求都由这个临时表来应答。因此
    对原表的修改不会反映到那些由fetch返回的用于该游标的数据上。这种类型的游标访问的数据是不能被修改的。

    应用程序可以请求一个游标类型然后执行一个不被所请求的服务器游标类型支持的Transact-SQL语句。SQL Server返回一个错误,
    指出该游标类型被改变了,或者给出一组参数,隐式的转换游标。欲取得一个触发SQL Server 7.0隐式的把游标从一种类型转换为
    另一种类型的参数的完整列表,请参阅SQL Server联机手册。

    SCROLL选项允许除了前向的抽取以外,向后的、绝对的和相对的数据抽取。一个滚动游标使用一种键集合的游标模型,在该模型中,
    任何用户提交的对表的删除和更新都将影响后来的数据抽取。只有在游标没有用INSENSITIVE选项声明时,上面的特性才起作用。

    如果选择了READ ONLY选项,对游标中的行的更新就被禁止。该选项将覆盖游标的缺省选项棗允许更新。

    UPDATE [OF column_list]语句用来在游标中定义一个可更新的列。如果提供了[OF column_list],那么仅仅是那些列出的列可以被修改。
    如果没有指定任何列。则所有的列都是可以更新的,除非游标被定义为READ ONLY

    重要的是,注意到一个SQL Server游标的名字范围就是连接自己。这和本地变量的名字范围是不同的。
    不能声明一个与同一个用户连接上的已有的游标相同名字的游标,除非第一个游标被释放。

     

    打开一个游标

    Transact-SQL不支持向一个打开的游标传递参数,这一点和PL/SQL是不一样的。当一个Transact-SQL游标被打开以后,
    结果集的成员和顺序就固定下来了。其它用户提交的对原表的游标的更新和删除将反映到对所有未加INSENSITIVE选项定义
    的游标的数据抽取上。对一个INSENSITIVE游标,将生成一个临时表。

     

    抽取数据

    Oracle游标只能向前移动棗没有向后或者相对滚动的能力。SQL Server游标可以向前或者向后滚动,具体怎么滚动,
    要由下表给出的数据抽取选项来决定。只有在游标是用SCROLL选项声明的前提下,这些选项才能使用。

    卷动选项 描述
    NEXT
    如果这是对游标的第一次提取,则返回结果集合的第一行;否则,在结果结合内移动游标到下一行。
    NEXT
    是在结果集合中移动的基本方法 NEXT是缺省的游标提取(fetch)。
    PRIOR
    返回结果集合的前一行。
    FIRST
    把游标移动到结果集合的第一行,同时返回第一行。
    LAST
    把游标移动到结果集合的最后一行,同时返回最后一行。
    ABSOLUTE n
    返回结果集合的第n行。如果n为负数,则返回倒数第n
    RELATIVE n
    返回当前提取行后的第n行,如果n是负数,则返回从游标相对位置起的倒数第n行。

     

    Transact-SQLFETCH语句不需要INTO子句。如果没有指定返回变量,行就自动作为一个单行结果集合返回给客户。但是,
    如果你的过程必须把行给客户,一个不带游标的SELECT语句更有效一些。

    在每一个FETCH后面,@@FETCH_STATUS函数被更新。这和在PL/SQL中使用CURSOR_NAME%FOUNDCURSOR_NAME%NOTFOUND变量是相似的
    @@FETCH_STATUS函数在每一次成功的数据抽取以后被设定为0。如果数据抽取试图读取一个超过游标末尾的数据,则返回一个为-1的值。
    如果请求的行在游标打开以后从表上被删除了,@@FETCH_STATUS函数就返回一个为-2的值。只有游标是用SCROLL选项定义的情况下,
    才会返回-2值。在每一次数据抽取之后都必须检查该变量,以确保数据的有效性。

    SQL Server不支持Oracle的游标FOR循环语法。

    CURRENT OF子句

    更新和删除的CURRENT OF子句语法和函数在PL/SQLTransact-SQL中是一样的。在给定游标中,在当前行上执行定位的UPDATEDELETE

     

    关闭一个游标

    Transact-SQLCLOSE CURSOR语句关闭游标,但是保留数据结构以备重新打开。PL/SQL CLOSE CURSOR语句关闭并且释放所有的数据结构。

    Transact-SQL需要用DEALLOCATE CURSOR语句来清除游标数据结构。DEALLOCATE CURSOR语句同CLOSE CURSOR是不一样的,
    后者保留数据结构以备重新打开。DEALLOCATE CURSOR释放所有与游标相关的数据结构并且清除游标的定义。

     

    游标示例

    下面的例子显示了在PL/SQLTransact-SQL等价的游标语句。

    Oracle Microsoft SQL 
    -----------------------------------------------------------------------------------------------------------
    DECLARE
    VSSN CHAR(9);
    VFNAME VARCHAR(12);
    VLNAME VARCHAR(20);
    -----------------------------------------------------------------------------------------------------------
    DECLARE
    @VSSN CHAR(9),
    @VFNAME VARCHAR(12),
    @VLNAME VARCHAR(20)
    CURSOR CUR1
    IS
    SELECT SSN, FNAME, LNAME
    FROM STUDENT ORDER BY LNAME;

    BEGIN
        OPEN CUR1;
        FETCH CUR1 INTO VSSN,     VFNAME, VLNAME;
        WHILE (CUR1%FOUND) LOOP
        FETCH CUR1 INTO VSSN,     VFNAME, VLNAME;
    END LOOP;
    CLOSE CUR1;
    END;
    -----------------------------------------------------------------------------------------------------------
    DECLARE curl CURSOR FOR
       SELECT SSN, FNAME, LNAME
       FROM STUDENT ORDER BY SSN
    OPEN CUR1
    FETCH NEXT FROM CUR1
       INTO @VSSN, @VFNAME, @VLNAME
    WHILE (@@FETCH_STATUS <> -1)
       BEGIN
      FETCH NEXT FROM CUR1 INTO       @VSSN, @VFNAME, @VLNAME
       END
    CLOSE CUR1
    DEALLOCATE CUR1

  • 相关阅读:
    Chrome使用指南
    Vue2.x-踩坑记
    C# WinForm listView 多行删除 操作
    Winform中DataGridView多行删除
    20211026_阿里云服务器引流限制ssl的问题
    docker commit
    docker build
    docker build与docker commit
    阿里云Docker镜像仓库(Docker Registry)
    Docker Nginx安装(centos7)
  • 原文地址:https://www.cnblogs.com/Mayvar/p/wanghonghua201107150516.html
Copyright © 2011-2022 走看看