我使用SQL Server。
我手头有一些没有任何约束条件的大型表,没有键也没有其他任何东西。
我知道其中一些列具有唯一值。有没有一种聪明的方法可以查找具有唯一值的列?
现在,我为每个列手动执行此操作,通过计算是否有与表中行数相同数量的DISTINCT值。
SELECT COUNT(DISTINCT col) FROM table
或许可以创建一个游标来遍历所有列,但我想听听是否有更聪明或内置的方法。
我使用SQL Server。
我手头有一些没有任何约束条件的大型表,没有键也没有其他任何东西。
我知道其中一些列具有唯一值。有没有一种聪明的方法可以查找具有唯一值的列?
现在,我为每个列手动执行此操作,通过计算是否有与表中行数相同数量的DISTINCT值。
SELECT COUNT(DISTINCT col) FROM table
或许可以创建一个游标来遍历所有列,但我想听听是否有更聪明或内置的方法。
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
,表示没有重复项的列,如果存在重复,则为空字符串。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
表示没有重复值和NULL(可以是PK或具有唯一约束/索引);
UNIQUE WITH SINGLE NULL
- 没有重复值,但有一个NULL(不能是PK,但可以具有唯一约束/索引);
UNIQUE with NULLs
- 没有重复值,有两个或更多NULL(如果您在SQL Server 2008上,则可以为非NULL值设置条件唯一索引);
空字符串 - 存在重复值,可能还有NULL。
这里我认为可能是最简单的方法。只需使用动态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,则将其插入到临时表中
从系统表中选择与发现具有重复项的表/列不匹配的列和值
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);
如果您正在使用2008版本,您可以在SSIS中使用数据分析任务来返回每个表的候选键。
本博客文章将逐步介绍该过程,它非常简单: