我使用MS SQL Server。
我已经交了一些没有约束的大桌子,没有钥匙也没有。
我知道有些列具有唯一值。是否有一种聪明的方法可以让给定的表找到具有唯一值的cols?
现在,我通过计算DISTINCT值是否与表中的行数一样,为每列手动完成。
SELECT COUNT(DISTINCT col) FROM table
可能会让cusor循环遍历所有列,但想知道是否有人知道更智能或内置函数。
感谢。
答案 0 :(得分:8)
这是一种与@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
表示没有重复值且没有NULL(可以是PK或具有唯一约束/索引);
UNIQUE WITH SINGLE NULL
- 可以猜到,没有重复,但是有一个NULL(不能是PK,但可以有唯一约束/索引);
UNIQUE with NULLs
- 没有重复项,两个或多个NULL(如果您使用的是SQL Server 2008,则只能为非NULL值设置条件唯一索引);
空字符串 - 有重复项,也可能是NULL。
答案 1 :(得分:2)
我觉得这可能是最干净的方式。只需使用动态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
答案 2 :(得分:1)
如果您使用的是2008,则可以使用SSIS中的数据概要分析任务返回每个表的候选密钥。
此博客文章逐步完成,非常简单:
答案 3 :(得分:1)
我的代码所做的几句话:
阅读所有表格和列
创建临时表以保存具有重复键的表/列
对于每个表/列,它运行一个查询。如果它找到至少一个值的计数(*)> 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
答案 4 :(得分:0)
简单的一行代码怎么样:
CREATE UNIQUE INDEX index_name ON table_name (column_name);
如果创建了索引,则column_name只包含唯一值。如果您的column_name中存在欺骗,则会收到错误消息。