Как выбрать имя столбца, который содержит максимальное количество различных значений? - Oracle SQL - PullRequest
1 голос
/ 17 января 2020

Вот мой текущий запрос:

SELECT c.COLUMN_NAME, t.NUM_ROWS
FROM ALL_TAB_COLUMNS c
INNER JOIN ALL_TABLES t ON t.OWNER = c.OWNER AND t.TABLE_NAME = c.TABLE_NAME
WHERE c.TABLE_NAME='MY_TABLE_NAME'
AND c.OWNER = 'MY_SCHEMA_NAME' 

Для этого нужно получить как имя каждого столбца в моей таблице, так и количество строк в каждом столбце.

Что мне нужно сделать, это получить количество различных значений, присутствующих в каждом столбце, а затем в конечном итоге определить, какой столбец имеет максимальное количество различных записей. Как бы я go сделал это, учитывая мой текущий запрос?

Есть ли лучший способ достичь того, что я хочу сделать? Нужен ли Dynami c SQL?

Ответы [ 3 ]

3 голосов
/ 17 января 2020

Вы можете использовать XMLQUERY для получения желаемого результата.

Oracle настройка данных:

SQL> CREATE TABLE TEST_SO (COL1 NUMBER, COL2 VARCHAR(20));

Table created.

SQL>
SQL> INSERT INTO TEST_SO (COL1,COL2) VALUES (1, 'TEJASH');

1 row created.

SQL> INSERT INTO TEST_SO (COL1,COL2) VALUES (2, 'TEJASH1');

1 row created.

SQL> INSERT INTO TEST_SO (COL1,COL2) VALUES (3, 'TEJASH2');

1 row created.

SQL> INSERT INTO TEST_SO (COL1,COL2) VALUES (2, 'TEJASH3');

1 row created.

SQL> INSERT INTO TEST_SO (COL1,COL2) VALUES (2, 'TEJASH');

1 row created.

SQL>

Теперь, COL2 имеет 4 различных значения, а COL1 имеет 3 различных значения. Используйте следующий запрос, чтобы извлечь COL2 и 4 (так как они больше 3 (различные значения в COL1)) как отдельные значения в нем.

Ваш запрос:

SQL> SELECT
  2      C.COLUMN_NAME,
  3      TO_NUMBER(XMLQUERY('/ROWSET/ROW/C/text()'
  4                  PASSING XMLTYPE(DBMS_XMLGEN.GETXML(
  5                  'select count(distinct "'
  6                   || C.COLUMN_NAME
  7                   || '") as c '
  8                   || 'from "'
  9                   || C.TABLE_NAME
 10                   || '"')) RETURNING CONTENT)) AS DISTINCT_VALS
 11  FROM USER_TAB_COLUMNS C
 12  WHERE C.TABLE_NAME = 'TEST_SO'
 13  ORDER BY DISTINCT_VALS DESC NULLS LAST
 14  FETCH FIRST ROW WITH TIES;

COLUMN_NAME     DISTINCT_VALS
--------------- -------------
COL2                        4

SQL>

Ура !!

2 голосов
/ 17 января 2020

Начиная с

  • вы готовы использовать num_rows из представления all_% и
  • Если у вас есть собранная статистика и
  • допустимо возможное расхождение, вы может использовать базу данных статистики, собранную из all_tab_col_statistics.

Как это.

select num_distinct, column_name 
  from all_tab_col_statistics
 where table_name = 'TABLE_NAME_UPPERCASE'
 order by num_distinct desc
 fetch first row with ties;

Опять же, используйте это, пожалуйста, когда допустимый допуск. Хотя статистика таблиц обычно собирается на регулярной основе (зависит от администратора баз данных), между собранной и реальной стоимостью может существовать некоторый разрыв.

0 голосов
/ 17 января 2020

Для отдельной таблицы вы также можете выполнить такую ​​процедуру:

DECLARE

    CURSOR Cols IS
    SELECT COLUMN_NAME 
    FROM USER_TAB_COLUMNS 
    WHERE TABLE_NAME = 'MY_TABLE_NAME' 
    ORDER BY COLUMN_ID;

    cur INTEGER := DBMS_SQL.OPEN_CURSOR;
    columnCount INTEGER := 0;
    describeColumns DBMS_SQL.DESC_TAB2;
    res INTEGER;
    distinctValues NUMBER;
    m NUMBER := -1;
    c INTEGER := 0;

    sqlstr VARCHAR2(30000);

BEGIN

    FOR aCol IN Cols LOOP
        sqlstr := sqlstr || ',COUNT(DISTINCT '||aCol.COLUMN_NAME||') AS '||aCol.COLUMN_NAME;
    END LOOP;
    sqlstr := REGEXP_REPLACE(sqlstr, '^,', 'SELECT ')||' FROM MY_TABLE_NAME';

    DBMS_SQL.PARSE(cur, sqlStr, DBMS_SQL.NATIVE);
    DBMS_SQL.DESCRIBE_COLUMNS2(cur, columnCount, describeColumns);

    FOR i IN 1..columnCount LOOP
        DBMS_SQL.DEFINE_COLUMN(cur, i, distinctValues);
    END LOOP;
    res := DBMS_SQL.EXECUTE(cur);

    res := DBMS_SQL.FETCH_ROWS(cur); -- no loop required as you get always exactly one row
    FOR i IN 1..columnCount LOOP
        DBMS_SQL.COLUMN_VALUE(cur, i, distinctValues);
        IF distinctValues > m THEN
            m := distinctValues;
            c := i;
        END IF;
        DBMS_OUTPUT.PUT_LINE ( describeColumns(i).col_name ||': '|| distinctValues );
    END LOOP;
    DBMS_OUTPUT.PUT_LINE ( 'Max distinct values at '||describeColumns(c).col_name ||': '|| m );

END;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...