Как узнать, есть ли в таблице несколько уникальных столбцов - PullRequest
11 голосов
/ 04 августа 2011

Я использую MS SQL Server.

Мне передали несколько больших таблиц без ограничений на них, без ключей и ничего.

Я знаю, что некоторые столбцы имеют уникальные значения.Есть ли разумный способ для данной таблицы найти столбцы с уникальными значениями?

Сейчас я делаю это вручную для каждого столбца, подсчитывая, сколько значений DISTINCT столько, сколько строк в таблице.

SELECT COUNT(DISTINCT col) FROM table

Может быть, попытается создать кастор для циклического перебора всех столбцов, но захочет узнать, знает ли кто-нибудь более умную или встроенную функцию.

Ответы [ 5 ]

8 голосов
/ 04 августа 2011

Вот подход, который в основном похож на @ JNK, но вместо того, чтобы печатать счетчики, он возвращает готовый ответ для каждого столбца, который говорит вам, состоит ли столбец только из уникальных значений или нет:

DECLARE @table varchar(100), @sql varchar(max);
SET @table = 'some table name';

SELECT
  @sql = COALESCE(@sql + ', ', '') + ColumnExpression
FROM (
  SELECT
    ColumnExpression =
      'CASE COUNT(DISTINCT ' + COLUMN_NAME + ') ' +
      'WHEN COUNT(*) THEN ''UNIQUE'' ' +
      'ELSE '''' ' +
      'END AS ' + COLUMN_NAME
  FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_NAME = @table
) s

SET @sql = 'SELECT ' + @sql + ' FROM ' + @table;
PRINT @sql;  /* in case you want to have a look at the resulting query */
EXEC(@sql);

Он просто сравнивает COUNT(DISTINCT column) с COUNT(*) для каждого столбца. Результатом будет таблица с одной строкой, где каждый столбец будет содержать значение UNIQUE для тех столбцов, у которых нет дубликатов, и пустую строку, если дубликаты присутствуют.

Но приведенное выше решение будет работать корректно только для тех столбцов, которые не имеют NULL. Следует отметить, что SQL Server не игнорирует значения NULL, когда вы хотите создать уникальное ограничение / индекс для столбца. Если столбец содержит только одно значение NULL и все другие значения являются уникальными, вы все равно можете создать уникальное ограничение для столбца (однако нельзя сделать его первичным ключом, что требует как уникальности значений, так и отсутствия NULL).

Поэтому вам может потребоваться более тщательный анализ содержимого, который вы можете получить с помощью следующего скрипта:

DECLARE @table varchar(100), @sql varchar(max);
SET @table = 'some table name';

SELECT
  @sql = COALESCE(@sql + ', ', '') + ColumnExpression
FROM (
  SELECT
    ColumnExpression =
      'CASE COUNT(DISTINCT ' + COLUMN_NAME + ') ' +
      'WHEN COUNT(*) THEN ''UNIQUE'' ' +
      'WHEN COUNT(*) - 1 THEN ' +
        'CASE COUNT(DISTINCT ' + COLUMN_NAME + ') ' +
        'WHEN COUNT(' + COLUMN_NAME + ') THEN ''UNIQUE WITH SINGLE NULL'' ' +
        'ELSE '''' ' +
        'END ' +
      'WHEN COUNT(' + COLUMN_NAME + ') THEN ''UNIQUE with NULLs'' ' +
      'ELSE '''' ' +
      'END AS ' + COLUMN_NAME
  FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_NAME = @table
) s

SET @sql = 'SELECT ' + @sql + ' FROM ' + @table;
PRINT @sql;  /* in case you still want to have a look at the resulting query */
EXEC(@sql);

Это решение учитывает значения NULL, проверяя три значения: COUNT(DISTINCT column), COUNT(column) и COUNT(*). Результаты отображаются аналогично предыдущему решению, но возможные диагнозы для столбцов более разнообразны:

  • UNIQUE означает отсутствие дублирующихся значений и пустых значений (может быть либо PK, либо иметь уникальное ограничение / индекс);

  • UNIQUE WITH SINGLE NULL - как можно догадаться, дубликатов нет, но есть один NULL (не может быть PK, но может иметь уникальное ограничение / индекс);

  • UNIQUE with NULLs - без дубликатов, двух или более NULL (если вы используете SQL Server 2008, вы можете иметь условный уникальный индекс только для значений, отличных от NULL);

  • пустая строка - есть дубликаты, возможно, также NULL.

2 голосов
/ 04 августа 2011

Вот я думаю, наверное, самый чистый путь.Просто используйте динамический sql и один оператор select для создания запроса, который дает вам общее количество строк и количество отдельных значений для каждого поля.

Введите имя БД и имя таблицы вверху.Часть имени БД действительно важна, поскольку OBJECT_NAME работает только в текущем контексте базы данных.

use DatabaseName

DECLARE @Table varchar(100) = 'TableName'

DECLARE @SQL Varchar(max)

SET @SQL = 'SELECT COUNT(*) as ''Total'''

SELECT @SQL = @SQL + ',COUNT(DISTINCT ' + name + ') as ''' + name + ''''
FROM sys.columns c
WHERE OBJECT_NAME(object_id) = @Table

SET @SQL = @SQL + ' FROM ' + @Table

exec @sql
1 голос
/ 04 августа 2011

Несколько слов о том, что делает мой код:

  1. Читать все таблицы и столбцы

  2. Создает временную таблицу для хранения таблицы / столбцов с дублирующимися ключами

  3. Для каждой таблицы / столбца выполняется запрос. Если он находит число (*)> 1 хотя бы для одного значения делает вставку во временную таблицу

  4. Выберите столбец и значения из системных таблиц, которые не соответствуют таблице / столбцам, у которых обнаружены дубликаты

    DECLARE @sql VARCHAR(max)
    DECLARE @table VARCHAR(100)
    DECLARE @column VARCHAR(100)
    
    
    CREATE TABLE #temp (tname VARCHAR(100),cname VARCHAR(100))
    
    DECLARE mycursor CURSOR FOR
    select t.name,c.name
    from sys.tables t
    join sys.columns c on t.object_id = c.object_id
    where system_type_id not in (34,35,99)
    
    OPEN mycursor
    FETCH NEXT FROM mycursor INTO @table,@column
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
    SET @sql = 'INSERT INTO #temp SELECT DISTINCT '''+@table+''','''+@column+ ''' FROM ' + @table + ' GROUP BY ' + @column +' HAVING COUNT(*)>1 '
    EXEC (@sql)
    FETCH NEXT FROM mycursor INTO @table,@column
    END
    
    select t.name,c.name
    from sys.tables t
    join sys.columns c on t.object_id = c.object_id
    left join #temp on t.name = #temp.tname and c.name = #temp.cname
    where system_type_id not in (34,35,99) and #temp.tname IS NULL
    
    DROP TABLE #temp
    
    CLOSE mycursor
    DEALLOCATE mycursor
    
1 голос
/ 04 августа 2011

Если вы используете 2008, вы можете использовать задачу профилирования данных в SSIS, чтобы вернуть ключи-кандидаты для каждой таблицы.

Эта запись в блоге пошагово выполняет процесс, она довольно проста:

http://consultingblogs.emc.com/jamiethomson/archive/2008/03/04/ssis-data-profiling-task-part-8-candidate-key.aspx

0 голосов
/ 04 декабря 2017

А как насчет простой строки кода:

CREATE UNIQUE INDEX index_name ON table_name (column_name);

Если индекс создан, то имя вашего столбца имеет только уникальные значения. Если в вашем column_name есть дубликаты, вы получите сообщение об ошибке.

...