MySQL 递归 sql语句 WITH表达式实现

MySQL 递归 sql语句 WITH AS 实现

前言: 这里一般来说需要编一个故事但是我懒

mysql递归CTE: 8.0版本以上才有WITH AS,8.0以下版本的话请绕行----->不是说8.0以下不能写递归只是不是这个文章的写法,所以看了也没用不用浪费时间

文档原话:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mMXet8Yy-1641353366608)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20211228160148075.png)]

文档英文原话:

官方文档链接

先上可以cv的,不着急写需求的可以往下看看或者看不懂的话可以往下看看

sql语句

# n: 迭代次数
# id, name, parentId: 想要查询的字段,根据自己需求进行修改
# cte_test_paths: 储存区名字是自己创建的这个地方需要和最后的SELECT * FROM cte_test_paths WHERE n = 1;中的表名相同
WITH RECURSIVE cte_test_paths (n, id, name, parentId) AS
                   (
                       # 0 AS n的0表示第一次递归从零开始计数,因为一般来说第一次递归会查询最高级,一般情况下的最高级,而不是真正的第一级,可以根据业务变更
                       SELECT 0 AS n,
                              id,
                              name,
                              parentId
                              # cte_test: 你需要取递归的表,这里需要注意的是递归公用表表达式'cte_test_paths'在递归查询块中既不能包含聚合函数也不能包含窗口函数
                       from cte_test
                       # WHERE后接需要查询的条件,比如这里是第一代的id,也就是第一代的标志,
                       WHERE id = 1
                       UNION ALL
                       SELECT n + 1, e.id, e.name, e.parentId
                       FROM cte_test_paths AS etp
                                # 这里联表的条件是递归的上级id和下级id的关系,需要根据自己的实际环境进行修改
                                JOIN cte_test AS e ON etp.id = e.parentId
                       # 这里的 n<1 是为了限制迭代次数避免无限迭代浪费性能,比如说我只需要查询两代了的话,但是不做代数限制,却查了所有代,这是没有必要的浪费
                       WHERE n < 1)
SELECT *
FROM cte_test_paths
# 这里之所以做条件查询的原因是因为,我只想看到第一代(因为我的第一代是不包含根代,这里的根代的意思就是一个第一代都要属于他子节点的最顶级,所以根据上述 0 AS n 第一代并不是0而是1)
WHERE n = 1;

文档翻译的

递归公用表表达式

CTE 可以指代自身或其他 CTE:

  • 自引用 CTE 是递归的。

  • CTE 可以指在同一WITH子句中较早定义的 CTE ,但不能指稍后定义的CTE 。

    此约束排除了相互递归的 CTE,其中 cte1引用cte2cte2引用 cte1。其中一个引用必须是稍后定义的 CTE,这是不允许的。

  • 给定查询块中的 CTE 可以指在更外层的查询块中定义的 CTE,但不能指在更内层的查询块中定义的 CTE。

为了解析对同名对象的引用,派生表隐藏了 CTE;和 CTE 隐藏基表、 TEMPORARY表和视图。名称解析通过在同一查询块中搜索对象,然后在没有找到具有该名称的对象的情况下依次进行外部块来进行。

与派生表一样,CTE 不能包含 MySQL 8.0.14 之前的外部引用。这是 MySQL 8.0.14 中解除的 MySQL 限制,而不是 SQL 标准的限制。有关特定于递归 CTE 的其他语法注意事项,请参阅 递归公用表表达式

递归公用表表达式是具有引用其自身名称的子查询的表达式。例如:

WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte WHERE n < 5
)
SELECT * FROM cte;

执行时,该语句会产生以下结果,即包含简单线性序列的单列:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dgK9IiYK-1641353366609)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20211228160417074.png)]

递归 CTE 具有以下结构:

  • 如果WITH子句中的任何CTE引用自身,则with子句必须以 WITH RECURSIVE开头。(如果没有CTE引用自身,则允许递归,但不是必需的。)

    如果您忘记了递归CTE的RECURSIVE,则可能会导致此错误:

    ERROR 1146 (42S02): Table 'cte_name' doesn't exist
    
  • 递归 CTE 子查询有两个部分,由UNION [ALL\] 或分隔 UNION DISTINCT

    SELECT ...      -- return initial row set
    UNION ALL
    SELECT ...      -- return additional row sets
    

    第一个SELECT生成CTE的初始行或多行,并且不引用CTE名称。第二个SELECT通过引用其FROM子句中的CTE名称来生成其他行和递归。当此部分不生成新行时,递归结束。因此,递归CTE由非递归SELECT部分和递归SELECT部分组成。

    每个SELECT部分本身可以是多个SELECT 语句的联合。

  • CTE结果列的类型SELECT仅从非递归部分的列类型推断出来 ,列都是可以为空的。对于类型确定,递归SELECT部分将被忽略。

  • 如果非递归部分和递归部分由 分隔 UNION DISTINCT,则消除重复行。这对于执行传递闭包的查询很有用,以避免无限循环。

  • 递归部分的每次迭代仅对前一次迭代产生的行进行操作。如果递归部分有多个查询块,则每个查询块的迭代按未指定的顺序进行调度,并且每个查询块对自上次迭代结束后由其上一次迭代或其他查询块生成的行进行操作。

前面显示的递归 CTE 子查询具有此非递归部分,它检索单个行以生成初始行集:

SELECT 1

CTE 子查询也有这个递归部分:

SELECT n + 1 FROM cte WHERE n < 5

在每次迭代中,该SELECT生成一行,其新值大于上一行集中的值n。第一次迭代对初始行集 (1) 进行操作,并产生1 + 1 = 2; 第二次迭代对第一次迭代的行集 (2) 进行操作并产生2 + 1 = 3; 等等。这一直持续到递归结束,当n不小于5时发生。

如果CTE的递归部分比非递归部分产生更宽的列值,则可能需要加宽非递归部分中的列以避免数据截断。考虑以下陈述:

WITH RECURSIVE cte AS
(
  SELECT 1 AS n, 'abc' AS str
  UNION ALL
  SELECT n + 1, CONCAT(str, str) FROM cte WHERE n < 3 
  # 别查了CONCAT拼接字符串函数
)
SELECT * FROM cte;

在非严格 SQL 模式下,该语句产生以下输出:

+------+------+
| n    | str  |
+------+------+
|    1 | abc  |
|    2 | abc  |
|    3 | abc  |
+------+------+

str列值都是 'abc'因为非递归 SELECT确定列宽。因此,str递归产生的更广泛的值SELECT 被截断。

在严格的 SQL 模式下,该语句会产生错误:

ERROR 1406 (22001): Data too long for column 'str' at row 1

要解决此问题,使语句不会产生截断或错误,请CAST() 在非递归中使用SELECT以使str列更宽:

WITH RECURSIVE cte AS
(
  SELECT 1 AS n, CAST('abc' AS CHAR(20)) AS str
  UNION ALL
  SELECT n + 1, CONCAT(str, str) FROM cte WHERE n < 3
)
SELECT * FROM cte;

现在语句产生这个结果,没有截断:

+------+--------------+
| n    | str          |
+------+--------------+
|    1 | abc          |
|    2 | abcabc       |
|    3 | abcabcabcabc |
+------+--------------+

列是按名称而不是位置访问的(具体看一下下方例子就明白了),这意味着递归部分中的列可以访问非递归部分中具有不同位置的列,如本 CTE 所示:

WITH RECURSIVE cte AS
(
  SELECT 1 AS n, 1 AS p, -1 AS q
  UNION ALL
  SELECT n + 1, q * 2, p * 2 FROM cte WHERE n < 5
)
SELECT * FROM cte;

因为p一行是q从前一行派生的 ,反之亦然,正负值在输出的每一行中交换位置:(这里不明白的话自己算一下就知道了)

+------+------+------+
| n    | p    | q    |
+------+------+------+
|    1 |    1 |   -1 |
|    2 |   -2 |    2 |
|    3 |    4 |   -4 |
|    4 |   -8 |    8 |
|    5 |   16 |  -16 |
+------+------+------+

一些语法约束适用于递归 CTE 子查询:

  • 递归SELECT部分不得包含以下结构:

    • 聚合函数,例如 SUM()
    • Window functions
    • GROUP BY
    • ORDER BY
    • DISTINCT

    在MySQL 8.0.19之前,递归CTE的递归选择部分也不能使用LIMIT子句。在MySQL 8.0.19中取消了此限制,现在在这种情况下支持LIMIT以及可选的OFFSET子句。对结果集的影响与在最外层选择中使用限制时相同,但也更有效,由于将其与递归选择一起使用,因此一旦生成了请求的行数,就会停止生成行数。

    这些约束不适用于递归CTE的非递归选择部分。对DISTINCT的禁止仅适用于工会成员; 允许使用UNION DISTINCT。

  • 递归SELECT部分必须仅在其FROM子句中引用 CTE 一次,而不能在任何子查询中引用。它可以引用CTE以外的表,并将它们与CTE连接起来。如果在这样的连接中使用,CTE 不得位于LEFT JOIN的右侧.

这些约束来自 SQL 标准,除了 MySQL 特定的ORDER BYLIMIT(MySQL 8.0.18 及更早版本)和 DISTINCT排除项.

对于递归CTE,EXPLAIN 递归SELECT 部分部分在Extra列中显示Recursive的输出行。

EXPLAIN显示的成本估算表示每次迭代的成本,可能与总成本有很大不同。优化器无法预测迭代次数,因为它无法预测WHERE子句在什么时候变为false。

CTE实际成本也可能受到结果集大小的影响。产生许多行的CTE可能需要足够大的内部临时表才能从内存转换为磁盘格式,并且可能会遭受性能损失。如果是这样,增加允许的内存内临时表大小可能会提高性能; 请参阅第8.4.4节 “MySQL中的内部临时表使用”。

限制公用表表达式递归

对于递归CTE来说,递归选择部分包括终止递归的条件是很重要的。作为防止失控的递归CTE的开发技术,您可以通过限制执行时间来强制终止:

  • cte_max_recursion_depth 系统变量对CTE的递归级别数量进行限制。服务器终止任何递归级别超过此变量值的 CTE 的执行。

  • 所述max_execution_time 系统变量强制用于执行超时 SELECT在当前会话中执行的语句。

  • MAX_EXECUTION_TIME 优化器提示强制为每个查询执行超时SELECT在它出现的语句。

    ps:下面两个时间我也是在没看明白,要是有大佬看见的话麻烦解释一二

假设在没有递归执行终止条件的情况下错误地编写了递归 CTE:

WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte
)
SELECT * FROM cte;

默认情况下, cte_max_recursion_depth值为 1000,导致 CTE 在递归超过 1000 个级别时终止。应用程序可以更改会话值以根据其要求进行调整:

SET SESSION cte_max_recursion_depth = 10;      -- permit only shallow recursion
SET SESSION cte_max_recursion_depth = 1000000; -- permit deeper recursion

您还可以设置全局 cte_max_recursion_depth值以影响随后开始的所有会话。

对于执行并因此缓慢递归或在有理由将cte_max_recursion_depth值设置得非常高的上下文中的查询, 防止深度递归的另一种方法是设置每个会话超时。为此,请在执行 CTE 语句之前执行如下语句:

SET max_execution_time = 1000; -- impose one second timeout

或者,在 CTE 语句本身中包含优化器提示:

WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte
)
SELECT /*+ SET_VAR(cte_max_recursion_depth = 1M) */ * FROM cte;

WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte
)
SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM cte;

从 MySQL 8.0.19 开始,您还可以 LIMIT在递归查询中使用来强加要返回到最外层的最大行数 SELECT,例如:

WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte LIMIT 10000
)
SELECT * FROM cte;

除了或代替设置时间限制,您还可以执行此操作。因此,以下 CTE 在返回一万行或运行一秒(1000 毫秒)后终止,以先发生者为准:

WITH RECURSIVE cte (n) AS
(
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM cte LIMIT 10000
)
SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM cte;

如果没有执行时间限制的递归查询进入无限循环,您可以使用 KILL QUERY. 在会话本身内,用于运行查询的客户端程序可能会提供终止查询的方法。例如,在 mysql 中,输入Control+C 会 中断当前语句。

创建测试单表数据

  • 测试表cte_test创建

    create table cte_test
    (
        id       bigint  not null comment 'ID',
        parentId bigint  not null comment '爹id',
        name     char(3) null comment '名字',
        unique (id)
    )
        comment '递归测试表';
    
  • 插入测试数据

    INSERT INTO cte_test (id, parentId, name) VALUES (1, 0, '用户1');
    INSERT INTO cte_test (id, parentId, name) VALUES (2, 1, '用户2');
    INSERT INTO cte_test (id, parentId, name) VALUES (3, 1, '用户3');
    INSERT INTO cte_test (id, parentId, name) VALUES (4, 1, '用户4');
    INSERT INTO cte_test (id, parentId, name) VALUES (5, 4, '用户5');
    INSERT INTO cte_test (id, parentId, name) VALUES (6, 4, '用户6');
    INSERT INTO cte_test (id, parentId, name) VALUES (7, 6, '用户7');
    INSERT INTO cte_test (id, parentId, name) VALUES (8, 7, '用户8');
    
  1. 查询第一代的所有用户

    • sql

      WITH RECURSIVE cte_test_paths (n, id, name, parentId) AS
                         (
                             SELECT 0 AS n, id, name, parentId
                             from cte_test
                             WHERE id = 1
                             UNION ALL
                             SELECT n + 1, e.id, e.name, e.parentId
                             FROM cte_test_paths AS etp
                                      JOIN cte_test AS e ON etp.id = e.parentId
                             WHERE n < 1)
      SELECT *
      FROM cte_test_paths
      WHERE n = 1;
      
    • 数据

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p6D6nXes-1641353366610)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20220105112734854.png)]

  2. 查询所有用户和代数

    • sql

      WITH RECURSIVE cte_test_paths (n, id, name, parentId) AS
                         (
                             SELECT 0 AS n, id, name, parentId
                             from cte_test
                             WHERE id = 1
                             UNION ALL
                             SELECT n + 1, e.id, e.name, e.parentId
                             FROM cte_test_paths AS etp
                                      JOIN cte_test AS e ON etp.id = e.parentId
                         )
      SELECT *
      FROM cte_test_paths;
      
    • 数据

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QRj6YIkR-1641353366611)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20220105112834419.png)]

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
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'

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

社畜阿藏405

挣点钱不丢人吧?

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

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

打赏作者

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

抵扣说明:

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

余额充值