从数据库系统表中选择所有索引,根据Oracle中的索引聚合数据

Posted

技术标签:

【中文标题】从数据库系统表中选择所有索引,根据Oracle中的索引聚合数据【英文标题】:Select all indexes from database system table, aggregate data based on the index in Oracle 【发布时间】:2021-09-11 09:03:32 【问题描述】:

我正在使用 Oracle 作为 CRM 的数据库。

我被要求根据特定条件生成一个完整的索引列表,以便检查表名。

我找到并详细说明了以下查询:

select ind.index_name,
       ind_col.column_name,
       tab_cols.DATA_DEFAULT,
       ind.table_name
from sys.all_indexes ind
         inner join sys.all_ind_columns ind_col on
            ind.owner = ind_col.index_owner and ind.index_name = ind_col.index_name
         left outer join sys.all_TAB_COLS tab_cols on
            ind_col.COLUMN_NAME = tab_cols.COLUMN_NAME and
            INDEX_TYPE='FUNCTION-BASED NORMAL' and
            tab_cols.OWNER = ind.owner and
            ind_col.COLUMN_NAME like 'SYS_NC%' and
            tab_cols.TABLE_NAME = ind.table_name
where  [requested conditions]
order by ind.table_name,INDEX_NAME; 

这个查询生成了大约 1.600 行,其中大部分是重复的 INDEX_NAME 值,因为如果索引有多个参数,我会重复该字段。

我想做的是:

    将 ind_col.column_name 中定义的一个索引的所有值分组到一列中,逗号分隔 (如果可能)具有 tab_cols.DATA_DEFAULT (long) 的值,而不是 ind_col.column_name,以防第一个值不为空。

我可以请你帮忙吗?

非常感谢您的回复!

【问题讨论】:

查看LISTAGG 以获取逗号分隔列表和NVLNVL2 以处理NULL/NOT NULL 值 DATA_DEFAULT 不是 CLOB 而是 LONG 不幸的是,它非常非常难以保存转换为 VARCHAR2。我最终在我的 DBMS(Oracle 19c 企业版)上遇到了数据库故障“SP2-0642:SQL*Plus 内部错误状态 2147,上下文 0:0:0 无法安全继续”。 【参考方案1】:
sys.listagg can be used on the columns you want to aggregate:

''' 
select substr(sys.listagg(ind.index_name||','),1,length(sys.listagg(ind.index_name||',')-1))   as index_name,
       ind_col.column_name,
       tab_cols.DATA_DEFAULT,
       ind.table_name
from sys.all_indexes ind
inner join sys.all_ind_columns ind_col on
    ind.owner = ind_col.index_owner and ind.index_name = ind_col.index_name
left outer join sys.DBA_TAB_COLS tab_cols on
    ind_col.COLUMN_NAME = tab_cols.COLUMN_NAME
    and INDEX_TYPE='FUNCTION-BASED NORMAL'
    and tab_cols.OWNER = ind.owner and ind_col.COLUMN_NAME like 'SYS_NC%'
where [list of custom conditions]
group by 
  ind_col.column_name,`enter code here`
       tab_cols.DATA_DEFAULT,
       ind.table_name
order by INDEX_NAME;
`enter code here`
'''

【讨论】:

你真的试过了吗?你得到了什么结果? 不幸的是,这部分工作,因为我仍然使用 tab_cols.DATA_DEFAULT 得到 ORA-00997,因为它是一个长类型 如果可能,请排除 data_fault 列。如果没有,解决方法是使用:substr(to_char(tab_cols.DATA_DEFAULT),1,4000)。如果 data_default 的值较长,则仅使用前 4000 个字符。 . @little_amb 我已经尝试过了,我目前使用 excel 对数据进行分组......无论如何,我认为不可能排除该字段,如果我希望在查询中显示公式的数据 @little_amb 我已经尝试了建议的转换,但它返回了 Oracle 错误。【参考方案2】:

这就是我得到的。我最终在我的 DBMS(Oracle 19c 企业版)上遇到了数据库故障“SP2-0642:SQL*Plus 内部错误状态 2147,上下文 0:0:0 无法安全继续”。尽管如此,也许它会有所帮助。

with
  function get_data_default(
    p_owner varchar2,
    p_table_name varchar2,
    p_column_name varchar2,
    p_index_type varchar2) return varchar2
  as
    v_long long;
  begin
    select data_default
    into v_long
    from dba_tab_cols
    where owner = p_owner
    and table_name = p_table_name
    and column_name = p_column_name
    and p_index_type = 'FUNCTION-BASED NORMAL'
    and column_name like 'SYS_NC%';
    
    return substr(v_long, 1, 4000);
  end get_data_default;
select 
  ind.owner,
  ind.index_name,
  listagg(
    coalesce(
      get_data_default(ind.table_owner, ind.table_name, ind_col.column_name, ind.index_type),
      ind_col.column_name), ', ') 
    within group (order by ind_col.column_position) as cols,
  ind.table_name
from dba_indexes ind
inner join dba_ind_columns ind_col on ind.owner = ind_col.index_owner
                                  and ind.index_name = ind_col.index_name
where [list of custom conditions]
group by ind.owner, ind.index_name, ind.table_name
order by ind.owner, ind.index_name, ind.table_name;

(如果您想知道为什么 ind.table_name 出现在 GROUP BY 子句中,尽管它已按索引所有者和名称区域分组:Oracle 需要这样做,因为 DBMS 无法检测到 GROUP BY 中的功能依赖关系,还没有。)

【讨论】:

非常感谢!让我们希望有人能从这里开始工作:) 不幸的是,我对 Oracle、SQL 和 sys 表(以及 idex)还很陌生 否则,还有其他地方可以获取 SYS_NC 字段的值吗?

以上是关于从数据库系统表中选择所有索引,根据Oracle中的索引聚合数据的主要内容,如果未能解决你的问题,请参考以下文章

oracle数据库中如何查看已经创建的索引信息?

如何使用oracle程序将数据从多个表中插入一个表中

从动态表中选择到 Datatable Oracle

ORACLE删除表中重复数据

Oracle统计信息

如何通过 JDBC 获取 Oracle 表中的所有索引,即使它们由不同的用户拥有?