Как узнать, есть ли в таблице уникальные столбцы

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

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

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

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

SELECT COUNT(DISTINCT col) FROM table

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

спасибо.

5 ответов


вот подход, который в основном похож на @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 для тех столбцов, которые не имеют дубликатов, и пустая строка, если дубликаты подарок.

но описанное выше решение будет работать только для тех столбцов, которые не имеют значения. Следует отметить, что SQL Server не игнорирует нули, когда вы хотите создать уникальное ограничение / индекс для столбца. Если столбец содержит только один 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);

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

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

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

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

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


вот я думаю, наверное, самый чистый способ. Просто используйте динамический 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

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

эта запись в блоге проходит через процесс, это довольно просто:

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


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

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

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

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

  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
    

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

CREATE UNIQUE INDEX index_name ON table_name (column_name);

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