【问题标题】:Oracle - distinct values of every columnOracle - 每列的不同值
【发布时间】:2012-12-13 12:44:40
【问题描述】:

我知道有一些关于类似主题的讨论,但这有点不同

我需要在 Oracle 中进行查询以获取给定表的值对(列名、不同值的计数)。

示例:来自此表

|   ID     |    NAME    |    AGE   |
____________________________________
|   01     |    MARY    |    10    |
|   02     |    MAX     |    30    |
|   03     |    ALICE   |    30    |
|   04     |    MARY    |    20    |
|   05     |    JOE     |    10    |
____________________________________

我需要得到

|   COLUNL |    DIST. VALUES    |
________________________________
|   ID     |    5       |
|   NAME   |    4       | 
|   AGE    |    3       |
________________________________

问题是我不知道表的结构。我将只有表名,并且需要为每个表名生成此信息。 有什么想法吗????

【问题讨论】:

  • 您希望动态生成列名吗?
  • 我觉得你第 5 行的 ID 04 应该是 05。
  • 是的!!,我需要动态生成它们

标签: oracle distinct


【解决方案1】:

每列的不同值的数量存储在系统表USER_TAB_COL_STATISTICS 中。通过调用过程DBMS_STATS.GATHER_TABLE_STATS 收集统计信息。询问您的 DBA,它应该已经设置好了。

CREATE TABLE mytable (id NUMBER, name VARCHAR2(10), age NUMBER);
INSERT INTO mytable VALUES (01, 'MARY',  10);
INSERT INTO mytable VALUES (02, 'MAX',   30);
INSERT INTO mytable VALUES (03, 'ALICE', 30);
INSERT INTO mytable VALUES (04, 'MARY',  20);
INSERT INTO mytable VALUES (04, 'JOE',   10);
COMMIT;
EXECUTE dbms_stats.gather_table_stats(user, 'MYTABLE');

SELECT table_name, column_name, num_distinct
  FROM user_tab_col_statistics
 WHERE table_name = 'MYTABLE';

TABLE_NAME COLUMN_NAME NUM_DISTINCT
MYTABLE    ID          4
MYTABLE    NAME        4
MYTABLE    AGE         3  

【讨论】:

    【解决方案2】:

    您可以使用UNION ALL 查询UNPIVOT,然后统计数据:

    select col col_name,
      count(distinct value)
    from
    (
      select cast(id as varchar(10)) value, 'id' col
      from yourtable
      union all
      select name value, 'name' col
      from yourtable
      union all
      select cast(age as varchar(10)) value, 'age' col
      from yourtable
    ) 
    group by col
    

    SQL Fiddle with Demo

    如果您使用的是 Oracle 11g+,那么您可以使用 UNPIVOT 函数来执行此操作:

    select col, count(distinct value) CountofValue
    from
    (
      select cast(id as varchar(10)) id, 
        name, 
        cast(age as varchar(10)) age
      from yourtable
    ) 
    unpivot
    (
      value
      for col in (id, name, age)
    ) 
    group by col
    

    SQL Fiddle with Demo

    【讨论】:

    • 对不起,bluefeet,我忘了提到我想在不知道表格结构的情况下执行此操作。我将拥有的只是表名。
    【解决方案3】:

    您可以使用UNION 来执行此操作,例如...

     SELECT 'ID', Count(Distinct ID) As ValueCount From TableName
     UNION
     SELECT 'NAME', Count(Distinct NAME) From TableName
     UNION
     SELECT 'AGE', Count(Distinct AGE) From TableName
    

    [编辑]
    另一种方法是分析表格,例如...

    ANALYZE TABLE TABLENAME COMPUTE STATISTICS;
    

    然后……

    SELECT COLUMN_NAME, NUM_DISTINCT FROM USER_TAB_COLUMNS WHERE TABLE_NAME = 'TABLENAME'
    

    【讨论】:

    • 对不起 lynamc,我忘了说我想在不知道表结构的情况下执行此操作。我将拥有的只是表名。
    • 啊。那么你可以问Oracle。请参阅上面的编辑。如果它是一张大桌子并且你想这样做很多,这不是很实用。
    • @Ciarán:特别是对于大型表,为优化器提供良好的统计数据非常实用。但是ANALYZE TABLE 已经过时了,应该使用DBMS_STATS
    • 我本来打算经常这样做只是为了收集不同的统计数据,但你当然绝对正确,ANALYZE TABLE 已过时,谢谢 Wolfgang。
    【解决方案4】:

    在ideea之下,你应该稍微努力一下:

    create table stats_on_tables(
        date_id date, 
        table_name varchar2(32), 
        col_name varchar2(32), 
        cnt_distinct number
    );
    

    然后使用参数 p_table_name 创建一个过程:

    for n in (select column_name from user_tab_columns where table_name = p_table_name)
    loop
      execute immediate 
        'insert into stats_on_table (date_id, table_name, col_name, cnt_distinct)
         values (sysdate, '||p_table_name||','||n.column_name||', (
         select count(distinct '||n.column_name||') from '||p_table_name||' ))';
    end loop;
    commit;
    

    【讨论】:

    • 谢谢!当您没有时间/空间/权限来生成统计数据时非常有用:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-13
    • 1970-01-01
    相关资源
    最近更新 更多