一、引言

部门使用 Oracle 已经有一些时日,最近在工作中遇到了这么一个需求:

我们希望拿到某些数据表的全部索引信息,对索引信息进行检查,检查是否有漏掉没有创建的索引

这个需求,核心的点在于,我需要编写一条 sql 语句,来获取到 Oracle 数据库中的数据表的全部索引信息,并且输出的结果还要能够方便我后续的检查工作。

因此对这条 sql 语句我们有以下的要求:

要能输出数据表的全部索引信息,并且组合为字符串的形式,方便检查

要保证索引输出结果唯一,比如 (A,B,C)、(A,C,B)、(B,C,A) 统一输出为 (A,B,C),这样才能方便后续检查

再把需求翻译成技术语言,那就是:

需要将同一个索引的索引字段组合成一个字符串

需要将同一个索引中的字段进行排序

由于我对数据库的陌生,导致我完成这个工作耗费了不少时间。尽管我花了很长的时间,还是摸索出来了一个解决方案,缺仍然不知道自己的解决方案是不是最佳的。

因此,写下这篇博客,一方面希望给有同样需求的人一条解决问题的思路,另一方面也是希望能够有大佬帮忙参考下有没有更佳的解决方案。

二、解决

我解决这个问题的过程,是一步步开始的:

先想办法获取到数据表的全部索引字段

再将所有的索引字段按照索引名分组

最后再考虑如何将分组后的字段进行排序,最后组合成一个字符串

先上我的最终解决方案代码:

select index_name, max(to_char(index_keys)) from

(

select index_name, wm_concat(column_name)

over(partition by index_name order by column_name) index_keys

from

(

select a.index_name, b.column_name

from all_indexes a, all_ind_columns b

where a.table_name = b.table_name

and a.index_name = b.index_name

and a.tab_owner = upper('WANGYING')

and a.table_name = 'TAB_TEST'

)

) group by index_name;

我写出这条 sql 的过程,也是按照我上面的思路完成的。在按照我的思路编写的过程中,遇到了不少阻碍。

这里假设在 Oracle 数据库下模式名为 WANGYING 的环境下,有个数据库 TAB_TEST,它有 (A,B,C) 和 (D,E) 两个索引,索引名分别为 index_name_1 和 index_name_2。

这里伴随着上面的假设,介绍下这条 sql 的含义:

1. 最内层 sql: 获取到全部索引字段

从 all_indexes、all_ind_columns 两个表中,拿到属于 WANGYING 模式名下的,表名为 TAB_TEST 的全部索引字段信息。这时候的 sql 输出就是一系列的字段信息,此时的输出类似:

a.index_name

b.column_name

index_name_1

A

index_name_2

D

index_name_1

B

index_name_2

E

index_name_1

C

2. 外层 sql: 组合并且排序索引字段

我们拿到了索引字段,接下来看看我们还需要什么:

使用 wm_concat 函数能够组合指定列的信息,这个函数可以用来组合我们想要的索引信息

使用 group by 函数能够帮我们按照索引名分组,这条语句能够帮我们分组索引字段

使用 order by 函数能够帮我们按照某个字段排序,这条语句能够帮我们将索引内的字段排序

按照上面的思路的话,我们写出来的 sql 应该长下面这样:

select index_name, wm_concat(column_name)

from

(

select a.index_name, b.column_name

from all_indexes a, all_ind_columns b

where a.table_name = b.table_name

and a.index_name = b.index_name

and a.tab_owner = upper('WANGYING')

and a.table_name = 'TAB_TEST'

order by a.index_name, b.column_name

)

group by index_name;

看似很简单的需求,先在内部按照索引名 index_name,再索引字段 column_name 排序,最后再 group by 分组,再 wm_concat 组合成字符串不就好了?

当然没有这么简单,你如果执行上面的语句,会发现内层 sql 的排序在 wm_concat 之后,顺序丢失了 T_T

那么怎么办呢,我搜了好久的资料,查找到了 over(partition by order by) 的用法,它可以:

顾名思义,PARTITION 中文是分割的意思,ORDER 是排序的意思,所以翻译一下就是先把一组数据按照制定的字段进行分割成各种组,然后组内按照某个字段排序。

参考自博客 【Orcale】分析函数 OVER(PARTITION BY… ORDER BY…)的讲解

按照这个说法,我只需要让它按照索引名 index_name 分割成多个组,然后组内按照索引字段 column_name 进行排序就可以了,这样就能保有索引字段的排序了。

因此写出 sql 如下:

select index_name, wm_concat(column_name)

over(partition by index_name order by column_name) index_keys

from

(

select a.index_name, b.column_name

from all_indexes a, all_ind_columns b

where a.table_name = b.table_name

and a.index_name = b.index_name

and a.tab_owner = upper('WANGYING')

and a.table_name = 'TAB_TEST'

)

有人可能会说,诶,你这样写不就好了吗,为什么最终方案还多了一层呢?

别急,你先看看执行结果:

index_name

wm_concat(column_name)

index_name_1

A

index_name_1

A,B

index_name_1

A,B,C

index_name_2

D

index_name_2

D,E

3. 最外层 sql:分析函数的特殊性,取最长字符串

正因为 partition by 是分析函数而不是聚合函数,它会在一个分组中返回多条数据,因此你就看到了上述的执行结果:

partition by关键字是分析性函数的一部分,它和聚合函数(如group by)不同的地方在于它能返回一个分组中的多条记录,而聚合函数一般只有一条反映统计值的记录,

参考自博客 分组函数 partition by 的详解,与order by 区别

那么怎么解决这个问题呢?

其实也简单,我们再加一层,按照索引名分组,取最大的一条记录即可,所以最终的解决方案如下:

select index_name, max(to_char(index_keys)) from

(

select index_name, wm_concat(column_name)

over(partition by index_name order by column_name) index_keys

from

(

select a.index_name, b.column_name

from all_indexes a, all_ind_columns b

where a.table_name = b.table_name

and a.index_name = b.index_name

and a.tab_owner = upper('WANGYING')

and a.table_name = 'TAB_TEST'

)

) group by index_name;

这样,我们就写出了最终方案的代码,执行结果:

index_name

index_keys

index_name_1

A,B,C

index_name_2

D,E

三、Oracle 19c 不支持 wm_concat:使用 listagg() within group() 替换

上述所说的 wm_concat 函数只有在 Oracle 11g 支持,如果你的 Oracle 版本是 12c 甚至 19c,那么 wm_concat 函数就不能再使用了。

那么这下怎么办呢?最好能够找到一种方法,能够在 Oracle 11g/12c/19c 都兼容的情况下成功运行。

通过我的探索,发现使用 listagg() within group() 函数可以完美替代掉 wm_concat 函数使用。listagg 函数中可以指定特定的分隔符,并且还能对组合的数据进行排序:

-- 组合 column_name 列的数据,并且按照 , 分割,组合出来的数据按照 column_name 排序

listagg(column_name, ',') within group (order by column_name)

同样的,除了把多列变成一行的需求之外,我们还希望能够按照 index_name 分组多列转行,也就是达到上一节中的效果,index_name_1 的索引字段 ABC 放在一起,index_name_2 的索引字段 DE 放在一起。这时候,我们可以继续使用 over (partition by) 的方式进行分析处理,使其输出多行数据。而此时,我们只需要使用 distinct 即可取到每个 index_name 唯一的数据。

select distinct index_name, listagg(column_name, ',')

within group (order by column_name)

over (partition by index_name) index_keys from (

select a.index_name, b.column_name

from all_indexes a, all_ind_columns b

where a.table_name = b.table_name

and a.index_name = b.index_name

and a.tab_owner = upper('WANGYING')

and a.table_name = 'TAB_TEST'

)

输出结果是一样的:

index_name

index_keys

index_name_1

A,B,C

index_name_2

D,E

使用这种方式的好处就是,代码嵌套层数少,listagg 函数的功能比之 wm_concat 函数更加强大。亲测该代码在 Oracle 11g 以后的版本(Oracle 12c、Oracle 19c)都能正常使用。

四、总结

我相信我写出来的解决方案一定不是最佳的解决方案,这块希望大佬们能够不吝赐教;另外,伴随着我的日后工作学习,应该也会有更多的不一样的体会。

希望本篇博客能够给你们带来一些启发或者帮助~~~

To be Stronger:)

c oracle 多条语句,Oracle 实践:如何编写一条 sql 语句获取数据表的全部索引信息(兼容 Oracle 19c、Oracle 11g)...相关推荐

  1. oracle 把结果加上百分号_用一条sql语句显示数据百分比并加百分号

    求数值所占比重 关键点:(round(t1.cnt/t2.totalCount*100,2))||'%' 例子: 如下表所示,车辆信息注册表carInfo ID CAR_TYPE CAR_ONWER ...

  2. 在Oracle中不通过存储过程一次执行多条SQL语句Oracle PL/SQL

    PL/SQL是ORACLE对标准数据库语言的扩展,ORACLE公司已经将PL/SQL整合到ORACLE 服务器和其他工具中了,近几年中更多的开发人员和DBA开始使用PL/SQL,本文将讲述PL/SQL ...

  3. c#执行多句oracle,C#一次执行多条SQL语句,Oracle11g数据库

    由于经常执行SQL语句,如果一条一条执行效率低下. oarclecmd.CommandText = sqlstr; oraclecmd.ExecuteNonQuery(); sqlstr 可以写成如下 ...

  4. oracle修改表结构的sql命令是什么,sql语句中修改表结构的命令是什么?

    sql语句中修改表结构的命令是:"ALTER TABLE"命令. ALTER TABLE 语句用于在已有的表中添加.删除或修改列. SQL ALTER TABLE 语法 如需在表中 ...

  5. oracle创建表语句_利用FME去拼接SQL语句并创建表

    在之前的工作中,我遇到了这么一个需求,需要将数据库内一千多个旧表按其原来表结构,重新创建对应的新表.然后对旧数据的进行处理后,存储新的数据. 不只是结构需要保持一致,还有用户.表空间.约束.备注等也需 ...

  6. oracle取本月最后一天是星期几_oracle SQL语句取本周本月本年的数据

    --国内从周一到周日 国外是周日到周六 select to_char(sysdate-1,'D') from dual;--取国内的星期几 去掉减一取国外的星期 --取本周时间内的数据 select ...

  7. oracle维护常用SQL语句(查看系统表和视图)

    转:http://www.360doc.com/content/11/1230/15/7489308_176090474.shtml oracle维护常用SQL语句(查看系统表和视图) 1.查看表空间 ...

  8. 关于oracle sql语句查询时表名和字段名要加双引号的问题

    oracle初学者一般会遇到这个问题. 用navicat可视化创建了表,可是就是不能查到! 后来发现②语句可以查询到 ①select * from user; 但是,我们如果给user加上双引号就可以 ...

  9. oracle将千万行查询优化到一秒内,oracle下一条SQL语句的优化过程(比较详细)

    oracle下一条SQL语句的优化过程(比较详细) 更新时间:2010年04月14日 23:56:49   作者: 很简单的一次调整,语句加了适当的索引后性能就有大幅的提升.当时看到这条语句的时候,第 ...

最新文章

  1. python文本挖掘视频课_自动摘要的python实现
  2. 【Android 安装包优化】资源混淆 ( 资源混淆效果 | APK 构建流程简介 | 资源 ID 组成 )
  3. Jmeter(二十二)_jenkins配置gitlab插件与ant插件
  4. SLAM: 图像角点检测的Fast算法(时间阈值实验)
  5. idal 创建springboot 项目_手把手的SpringBoot教程,SpringBoot创建web项目(四)
  6. 2015 ACM/ICPC Asia Regional Changchun Online HDU - 5441 (离线+并查集)
  7. 官网链接下载QT5 Creator
  8. 新科LoRa网关和LoRa节点
  9. 浏览器goback跨域
  10. 读《大型网站技术架构:核心原理与案例分析+李智慧》记一
  11. 如何拿到阿里offer的?面试流程及面试题
  12. 漏刻有时数据可视化Echarts组件开发(2):根据温度阈值显示不同颜色的温度报警动画
  13. 再现地表最强屏幕,三星Note 9破11项纪录称皇
  14. vue项目添加ico(已修改)
  15. js:身份证号码脱敏(对中间11位号码用*号替换)
  16. Task 1 知识图谱介绍
  17. python-线程池的使用
  18. 大数据周会-本周学习内容总结04
  19. Visual Query Interfaces——文献翻译
  20. IE11兼容IE8的设置

热门文章

  1. java使用httpclient封装post请求和get的请求
  2. C#的发展历程第五 - C# 7开始进入快速迭代道路
  3. Visualforce简介
  4. JQuey中 attr('checked', true)设置状态只有第一次有用
  5. C++各个算数类型占用的字节数
  6. DevExpress使用技巧总结
  7. XML类型的SQL参数
  8. 两道挺有意思的思考题
  9. i = i+1 和 i += 1
  10. python小游戏贪吃蛇源码下载