Как узнать, есть ли в таблице уникальные столбцы
Я использую 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 для возврата ключей-кандидатов для каждой таблицы.
эта запись в блоге проходит через процесс, это довольно просто:
несколько слов, что делает мой код:
читать все таблицы и столбцы
создает временную таблицу для хранения таблиц/столбцов с повторяющимися ключами
для каждой таблицы/столбца выполняется запрос. Если он находит count (*)>1 Для хотя бы одного значения он делает вставку в таблицу temp
-
выберите столбец и значения из системных таблиц, которые не соответствуют таблице / столбцам, которые, как установлено, имеют дубликаты
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, вы получите сообщение об ошибке.