【问题标题】:query to find various combinations search and counts in single query oracle查询以在单个查询 oracle 中查找各种组合搜索和计数
【发布时间】:2021-06-02 12:38:45
【问题描述】:

大家好,我遇到了一个要求,即找出特定模式 (SCHEMA_A) 中列 (col1,col2,col3) 的计数,但这里有一个问题,我必须找出所有列的组合为了计算有多少表使用了VALID_FROM_DATE、VALID_FROM_DATE、TIMESTAMP,下面是更多细节

数据库 - Oracle 11g

表搜索 - DBA_TAB_COLUMNS

col1 - VALID_FROM_DATE

col2 - VALID_TO_DATE

col3 - 时间戳

组合搜索以及所有表的计数

combination 1 
VALID_FROM_DATE + VALID_TO_DATE + TIMESTAMP

combination 2
VALID_FROM_DATE + VALID_TO_DATE 

combination 3 
VALID_FROM_DATE + TIMESTAMP

combination 4 
VALID_TO_DATE + TIMESTAMP

combination 5 
VALID_FROM_DATE

combination 6 
VALID_TO_DATE

combination 7 
TIMESTAMP

查询 - 我正在尝试

select count(distinct table_name) from DBA_TAB_COLUMNS
where owner='SCHEMA_A'
and column_name in ('VALID_FROM_DATE','VALID_TO_DATE','TIMESTAMP')
order by table_name;

但是如何在单个查询中实现上述组合 (1-7) 以捕获计数和总体百分比,是否有可能以最简单的方式实现单个查询块

percentage - round(100*ratio_to_report(count(*)) over (), 2) percentage

有什么建议吗?

【问题讨论】:

  • 嗨 Rakesh,我并不完全清楚你需要达到什么目标。您说“识别列”,但在查询中您正在查找表名(删除不同 n 表名之间的逗号)。能否请您提供您需要得到的测试数据和结果
  • @ekochergin - 现在更新了问题,我需要找出有多少表用户使用上述列,无论所有表都具有 1 到 7 的组合

标签: sql oracle dynamic plsql oracle-sqldeveloper


【解决方案1】:

我相信完整的外部连接在这里可以工作。

这里的子查询用于找出具有该列的表,然后将结果连接起来,为我们提供所有可能的组合。

在最后一步计算组合。

select case when vfd.table_name is not null then 'VALID_FROM_DATE' else null end VALID_FROM_DATE, 
       case when vtd.table_name is not null then 'VALID_TO_DATE' else null end VALID_TO_DATE, 
       case when ts.table_name  is not null then 'TIMESTAMP' else null end TIMESTAMP_col,
       count(1) tables_cnt
  from            (select table_name from dba_tab_cols where column_name = 'VALID_FROM_DATE') vfd -- tables with 'VALID_FROM'
  full outer join (select table_name from dba_tab_cols where column_name = 'VALID_TO_DATE') vtd   -- tables with 'VALID_TO'
    on vfd.table_name = vtd.table_name
  full outer join (select table_name from dba_tab_cols where column_name = 'TIMESTAMP') ts        -- tables with 'TIMESTAMP'
    on vfd.table_name = ts.table_name
 where vfd.table_name is not null 
    or vtd.table_name is not null
    or ts.table_name is not null
 group by case when vfd.table_name is not null then 'VALID_FROM_DATE' else null end, 
          case when vtd.table_name is not null then 'VALID_TO_DATE' else null end, 
          case when ts.table_name  is not null then 'TIMESTAMP' else null end

我在这里使用的子查询只是为了提高可读性。万一有人骂你这里的子查询有问题,你可以使用下面的版本

select case when vfd.table_name is not null then 'VALID_FROM_DATE' else null end VALID_FROM_DATE, 
       case when vtd.table_name is not null then 'VALID_TO_DATE' else null end VALID_TO_DATE, 
       case when ts.table_name  is not null then 'TIMESTAMP' else null end TIMESTAMP_col,
       count(1) tables_cnt
  from user_tab_cols vfd -- tables with 'VALID_FROM'
  full outer join user_tab_cols vtd   -- tables with 'VALID_TO'
    on vfd.table_name = vtd.table_name
    and vfd.column_name = 'VALID_FROM_DATE'
    and vtd.column_name = 'VALID_TO_DATE'
  full outer join user_tab_cols ts        -- tables with 'TIMESTAMP'
    on vfd.table_name = ts.table_name
    and vfd.column_name = 'VALID_FROM_DATE'
    and ts.column_name = 'TIMESTAMP'
 where vfd.column_name = 'VALID_FROM_DATE' 
    or vtd.column_name = 'VALID_TO_DATE' 
    or ts.column_name = 'TIMESTAMP'
 group by case when vfd.table_name is not null then 'VALID_FROM_DATE' else null end, 
          case when vtd.table_name is not null then 'VALID_TO_DATE' else null end, 
          case when ts.table_name  is not null then 'TIMESTAMP' else null end;

如果出现性能问题,在 dba_tab_cols 的 column_name 上添加索引可能会有所帮助。

【讨论】:

    【解决方案2】:

    我认为您正在寻找这样的东西。我正在使用多个 CTE 分步拆分逻辑

    • x_dba_tab_columns cte 只是模拟 dba_tab_columns 的测试数据
    • all_tables cte 是不同的表列表
    • table_w_cols cte 将每个表连接到按列过滤的 x_dba_tab_columns,如果该列存在则返回 1,如果不存在则返回 0

    而最终的选择只是一个计算组合的case语句。

    with x_dba_tab_columns (table_name, column_name)
    AS
    (
      SELECT 'TABLE1','VALID_FROM_DATE' FROM DUAL UNION ALL
      SELECT 'TABLE1','VALID_TO_DATE' FROM DUAL UNION ALL
      SELECT 'TABLE1','TIMESTAMP' FROM DUAL UNION ALL
      SELECT 'TABLE2','VALID_TO_DATE' FROM DUAL
      
    ), all_tables (table_name)
    AS
    (
      SELECT DISTINCT table_name FROM x_dba_tab_columns
    ), table_w_cols (table_name, vfd, vtd, ts)
    AS
    (
    SELECT 
      t.table_name, 
      NVL2(vfd.table_name,1,0) vfd,
      NVL2(vtd.table_name,1,0) vtd,
      NVL2(ts.table_name,1,0) ts
      FROM all_tables t 
           LEFT OUTER JOIN x_dba_tab_columns vfd ON vfd.table_name = t.table_name AND vfd.column_name = 'VALID_FROM_DATE'
           LEFT OUTER JOIN x_dba_tab_columns vtd ON vtd.table_name = t.table_name AND vtd.column_name = 'VALID_TO_DATE'  
           LEFT OUTER JOIN x_dba_tab_columns ts ON ts.table_name = t.table_name AND ts.column_name = 'TIMESTAMP'  
    )
    SELECT 
      table_name,
      CASE 
        WHEN (vfd = 1 AND vtd = 1 AND ts = 1) THEN 'combination 1'
        WHEN (vfd = 1 AND vtd = 1) THEN 'combination 2'
        WHEN (vfd = 1 AND ts = 1) THEN 'combination 3'
        WHEN (vtd = 1 AND ts = 1) THEN 'combination 4'
        WHEN (vfd = 1) THEN 'combination 5'
        WHEN (ts = 1) THEN 'combination 7'
        WHEN (vtd = 1) THEN 'combination 6'
      END as combination 
    FROM table_w_cols;
    
    TABLE1  combination 1
    TABLE2  combination 6
    

    【讨论】:

    • 感谢模板,我想要计数 1 表示和 0 表示?
    • 正如我所说,“table_w_cols cte 将每个表连接到按列过滤的 x_dba_tab_columns,如果该列存在则返回 1,如果不存在则返回 0”。因此,如果列“vfd”=1,那么该表有一个列 VALID_FROM_DATE。
    • 你能把问题标记为已回答吗?
    猜你喜欢
    • 2016-03-28
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 2011-03-20
    • 1970-01-01
    • 2018-03-24
    • 2012-12-24
    • 1970-01-01
    相关资源
    最近更新 更多