【问题标题】:Oracle query(PROC) not giving desired resultsOracle 查询(PROC)没有给出想要的结果
【发布时间】:2020-12-31 18:50:43
【问题描述】:

在查询下运行时(在 sproc 内)oracle..

SELECT
    index_name,
    index_description,
    ltrim(sys_connect_by_path(index_keys,','),',') as Index_Keys,
    include_cols,
    index_filter,
    data_compression,
    allow_page_locks,
    table_name,
    index_type
 from
  (
  Select t.*,
    row_number() over (partition by INDEX_NAME order by COLUMN_POSITION) as rn
    from
    (
     SELECT
        di.index_name AS "INDEX_NAME",
        CASE
                WHEN di.index_type = 'IOT - TOP' THEN 'clustered'
                ELSE 'nonclustered'
            END
        ||
            CASE
                WHEN di.uniqueness = 'UNIQUE' AND
                     substr (
                    di.index_name,
                    1,
                    3
                ) = 'PK_' THEN ', unique, primary key'
                WHEN di.uniqueness = 'UNIQUE' THEN ', unique'
            END
        ||
            CASE
                WHEN di.uniqueness = 'NONUNIQUE' THEN ''
                ELSE ''
            END
        ||
        ' located on PRIMARY' AS "INDEX_DESCRIPTION",
        ci.column_name AS "INDEX_KEYS",
        NULL AS "INCLUDE_COLS",
        NULL AS "INDEX_FILTER",
        NULL AS "DATA_COMPRESSION",
        NULL AS "ALLOW_PAGE_LOCKS",
        di.table_name AS "TABLE_NAME",
        CASE
                WHEN di.index_type = 'IOT - TOP' THEN 'CLUSTERED'
                ELSE 'NONCLUSTERED'
            END
        AS "INDEX_TYPE",ci.column_position
                      FROM
        dba_indexes di
        JOIN dba_ind_columns ci
        ON ci.index_owner   = di.owner AND
           ci.index_name    = di.index_name
                      WHERE
       di.table_owner = '****' AND
        di.table_name = '******' AND
        partitioned = 'NO'
    UNION ALL
    SELECT
        di.index_name AS "INDEX_NAME",
        CASE
                WHEN di.index_type = 'IOT - TOP' THEN 'clustered'
                ELSE 'nonclustered'
            END
        ||
            CASE
                WHEN di.uniqueness = 'UNIQUE' AND
                     substr (
                    di.index_name,
                    1,
                    3
                ) = 'PK_' THEN ', unique, primary key'
                WHEN di.uniqueness = 'UNIQUE' THEN ', unique'
            END
        ||
            CASE
                WHEN di.uniqueness = 'NONUNIQUE' THEN ''
                ELSE ''
            END
        ||
        ' located on PRIMARY' AS "INDEX_DESCRIPTION",
        ci.column_name AS "INDEX_KEYS",
        NULL AS "INCLUDE_COLS",
        NULL AS "INDEX_FILTER",
        NULL AS "DATA_COMPRESSION",
        NULL AS "ALLOW_PAGE_LOCKS",
        di.table_name AS "TABLE_NAME",
        CASE
                WHEN di.index_type = 'IOT - TOP' THEN 'CLUSTERED'
                ELSE 'NONCLUSTERED'
            END
        AS "INDEX_TYPE",ci.column_position
    FROM
        dba_indexes di
        JOIN dba_ind_partitions dip
        ON dip.index_owner   = di.owner AND
           dip.index_name    = di.index_name
        JOIN dba_ind_columns ci
        ON ci.index_owner   = di.owner AND
           ci.index_name    = di.index_name
    WHERE
        di.table_owner = '*******' AND
       di.table_name = '******' AND
        di.partitioned = 'YES' AND
        dip.composite != 'YES'
    UNION ALL
    SELECT
        di.index_name AS "INDEX_NAME",
        CASE
                WHEN di.index_type = 'IOT - TOP' THEN 'clustered'
                ELSE 'nonclustered'
            END
        ||
            CASE
                WHEN di.uniqueness = 'UNIQUE' AND
                     substr (
                    di.index_name,
                    1,
                    3
                ) = 'PK_' THEN ', unique, primary key'
                WHEN di.uniqueness = 'UNIQUE' THEN ', unique'
            END
        ||
            CASE
                WHEN di.uniqueness = 'NONUNIQUE' THEN ''
                ELSE ''
            END
        ||
        ' located on PRIMARY' AS "INDEX_DESCRIPTION",
        ci.column_name AS "INDEX_KEYS",
        NULL AS "INCLUDE_COLS",
        NULL AS "INDEX_FILTER",
        NULL AS "DATA_COMPRESSION",
        NULL AS "ALLOW_PAGE_LOCKS",
        di.table_name AS "TABLE_NAME",
        CASE
                WHEN di.index_type = 'IOT - TOP' THEN 'CLUSTERED'
                ELSE 'NONCLUSTERED'
            END
        AS "INDEX_TYPE",ci.column_position
    FROM
        dba_indexes di
        JOIN dba_ind_partitions dip
        ON dip.index_owner   = di.owner AND
           dip.index_name    = di.index_name
        JOIN dba_ind_subpartitions dis
        ON dis.index_owner      = di.owner AND
           dis.index_name       = di.index_name AND
           dis.partition_name   = dip.partition_name
        JOIN dba_ind_columns ci
        ON ci.index_owner   = di.owner AND
           ci.index_name    = di.index_name
    WHERE
      di.table_owner = '***' AND
       di.table_name = '*****' AND
        di.partitioned = 'YES' AND
       dip.composite = 'YES' ) t
)
where connect_by_isleaf = 1
connect by index_name  = prior index_name
and rn = prior rn+1
start with rn =1 ;

它给出以下输出..

![在此处输入图片描述][1]

AI_TESTORACLE_TEMP_27977 和 AI_TESTORACLE_TEMP_27978 的索引键当前显示功能索引的 column_name,即来自 dba_ind_columns 的 SYS_NC00023$ 和 SYS_NC00024$,而我们期望它应该是“TestInt, lower(TestShortString)”和“TestSmallInt, UPPER(TestShortString)”。 ..这是列表达式,可以从 dba_col_expressions 视图中派生出来..

 Name                                                                    Null?    Type
 ----------------------------------------------------------------------- -------- -----------------------------
 INDEX_OWNER                                                             NOT NULL VARCHAR2(128)
 INDEX_NAME                                                              NOT NULL VARCHAR2(128)
 TABLE_OWNER                                                             NOT NULL VARCHAR2(128)
 TABLE_NAME                                                              NOT NULL VARCHAR2(128)
 COLUMN_EXPRESSION                                                                LONG
 COLUMN_POSITION                                                         NOT NULL NUMBER

SQL> desc dba_ind_Columns;
 Name                                                                    Null?    Type
 ----------------------------------------------------------------------- -------- ----------------------
 INDEX_OWNER                                                             NOT NULL VARCHAR2(128)
 INDEX_NAME                                                              NOT NULL VARCHAR2(128)
 TABLE_OWNER                                                             NOT NULL VARCHAR2(128)
 TABLE_NAME                                                              NOT NULL VARCHAR2(128)
 COLUMN_NAME                                                                      VARCHAR2(4000)
 COLUMN_POSITION                                                         NOT NULL NUMBER
 COLUMN_LENGTH                                                           NOT NULL NUMBER
 CHAR_LENGTH                                                                      NUMBER
 DESCEND                                                                          VARCHAR2(4)
 COLLATED_COLUMN_ID                                                               NUMBER

只需要在此查询中进行微小更改即可输出列表达式而不是列名作为 index_keys 仅用于功能索引(这有点棘手).. REST NO CHANGE 在其他列中.. 在这里寻求所有专家的帮助..

INDEX_TYPE 作为基于函数的 NORMAL 或 NORMAL 可以从 DBA_INDEXES 中获取

SQL> select column_Expression from dba_ind_expressions where table_name='TESTORACLE_TEMP' AND TABLE_OWNER='ROLLOUT';

COLUMN_EXPRESSION
--------------------------------------------------------------------------------
LOWER("TESTSHORTSTRING")
UPPER("TESTSHORTSTRING")

SQL> select column_name from dba_ind_columns where table_owner='ROLLOUT' and table_name='TESTORACLE_TEMP';

COLUMN_NAME
----------------------------------------------------------------------------------------------------------------
KEYTESTORACLE
TESTTINYINT
TESTSMALLINT
TESTUNIQUEIDENTIFIER
TESTINT
SYS_NC00023$
TESTSMALLINT
SYS_NC00024$
UPDDATE

9 rows selected.

[![在此处输入图片描述][2]][2]

添加 index_keys 列(当前输出和预期) [1]:https://i.stack.imgur.com/fsg0z.png [2]:https://i.stack.imgur.com/SeewU.jpg

【问题讨论】:

  • 你能提供一个小提琴吗?

标签: sql oracle


【解决方案1】:

使用user_ind_expressions 进行左连接。如果该表不为空,则从该表中取值,否则从user_index_columns 中取值。然后您可以进行分层查询,或者listagg() 会更好。

一个问题。 Column_expression 是 long data_type(至少我看到它是这种形式),所以我做了一个简单的函数来将它转换为 varchar(你可以改进它,请阅读适当的文章,例如 asktom 网站)。

create or replace function 
  get_expr(i_tn in varchar2, i_in in varchar2, i_cp in number) return varchar2 as

  l_data long;
begin
  select column_expression into l_data from user_ind_expressions
    where table_name = i_tn and index_name = i_in and column_position = i_cp;
  return substr(l_data, 1, 4000);
end;

这是我的测试数据和查询:

create table emp(id primary key, fname, lname, dept) as (
  select 707, 'Pete', 'Griffin', 'Sales' from dual);
create index idx_emp1 on emp(lower(dept));
create index idx_emp2 on emp(upper(lname), upper(fname));

和查询:

select index_name,
       ltrim(sys_connect_by_path(index_keys,','),',') as Index_Keys
  from (
    select t.*, row_number() over (partition by index_name order by column_position) as rn
      from (     
        select index_name, column_name, column_position, 
               nvl(get_expr(table_name, index_name, column_position), column_name) as index_keys
          from user_indexes di
          join user_ind_columns ci using (table_name, index_name)
          left join user_ind_expressions using (table_name, index_name, column_position)
          where table_name = 'EMP') t )
  where connect_by_isleaf = 1
  connect by index_name  = prior index_name and rn = prior rn+1
  start with rn = 1

结果:

INDEX_NAME      INDEX_KEYS
--------------- --------------------------------
IDX_EMP1        LOWER("DEPT")
IDX_EMP2        UPPER("LNAME"),UPPER("FNAME")
SYS_C00148175   ID

如您所见,ID 取自 user_ind_columns,其他键取自 user_ind_expressions

【讨论】:

  • 谢谢..你能分享我转换后的完整查询(首先粘贴在表格中)吗?所以我可以测试一下...还有什么办法不使用函数(创建)..我们可以编写这个完整的查询吗?
  • sys_connect_by_pathlistagg 都不适用于 long 数据类型,因此您必须以某种方式将此值转换为 varchar。功能是我知道的唯一方法。其次,我专注于有问题的部分,以使答案尽可能清晰。您的查询很长,您正在使用 DBA 视图,而我不能。像上面一样进行连接,将owner添加到连接条件,同时添加owner作为函数参数。
  • 搜索者要求包含 COLUMN_EXPRESSION 意味着 any solution had to wrestle with a LONG column 是一个很好的地方。
  • @PonderStibbons 不适合我.. 下面是根据您的建议更新的代码.. 它在命令行给出错误:56 列:86 错误报告 - SQL 错误:ORA-00918:列不明确定义 00918. 00000 - “列定义不明确”db-fiddle.com/f/vSs39NTTdDDwwRvKzgvznj/0
  • 将此条件using (table_name, index_name, column_position,table_owner) 扩展为on ri.table = di.table_name and ri.index_name ...。在其他地方的列名之前使用别名。
猜你喜欢
  • 2018-10-17
  • 2019-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-29
  • 1970-01-01
  • 2013-10-26
  • 2021-03-02
相关资源
最近更新 更多