【问题标题】:Get top three most common values from every column in a table从表中的每一列中获取前三个最常见的值
【发布时间】:2015-05-14 20:58:32
【问题描述】:

我正在尝试编写一个查询,该查询将从表的每一列中生成非常小的数据样本,其中样本由前 3 个最常见的值组成。这个特殊问题是一项更大任务的一部分,即编写可以表征数据库及其表、数据完整性的脚本,并且还可以在每列的基础上快速调查表中的常见值。将此视为对表格的自动“分析”。

在单列的基础上,我已经通过简单地计算值的频率然后按频率排序来做到这一点。如果我有一个名为“颜色”的列并且所有颜色都在其中,并且恰好颜色“蓝色”出现在大多数行中,那么最常出现的前 1 个值将是“蓝色”。在易于计算的 SQL 中。

但是,我不确定如何在多个列上执行此操作。

目前,当我对表的所有列进行计算时,我会执行以下类型的查询:

USE database;

DECLARE @t nvarchar(max)
SET @t = N'SELECT '

SELECT @t = @t + 'count(DISTINCT CAST(' + c.name + ' as varchar(max))) "' + c.name + '",'
FROM sys.columns c 
WHERE c.object_id = object_id('table');

SET @t = SUBSTRING(@t, 1, LEN(@t) - 1) + ' FROM table;'

EXEC sp_executesql @t

但是,我并不完全清楚我将如何在这里做到这一点。

(旁注:text、ntext 和 image 类型的列,因为这些列在计算不同值时会导致错误,但我不太关心解决这个问题)

但是每列获得前三个最常见值的问题让我非常难过。

理想情况下,我希望得到这样的结果:

Col1     Col2              Col3       Col4     Col5
---------------------------------------------------------------------
1,2,3    red,blue,green    29,17,0    c,d,j    nevada,california,utah

【问题讨论】:

  • 我不完全确定您要在这里做什么,但如果您想排除某些数据类型的列,您可以使用 system_type_id 列。如果您想要文字说明,请从 sys.columns 加入 sys.types。
  • @SeanLange 我更关心从表的所有列(任何表)中递归计算最频繁出现的值的问题
  • 对...这就是我说的部分我不明白你在做什么。
  • OP 可能只是为数据分析或建模构建样本集。我过去做过。
  • @RajMore 确实如此。谢谢你!

标签: sql sql-server


【解决方案1】:

我一起破解了这个,但它似乎工作:

我忍不住想我应该使用 RANK()。

USE <DB>;

DECLARE @query nvarchar(max)
DECLARE @column nvarchar(max)
DECLARE @table nvarchar(max)
DECLARE @i INT = 1
DECLARE @maxi INT = 10
DECLARE @target NVARCHAR(MAX) = <table>

declare @stage TABLE (i int IDENTITY(1,1), col nvarchar(max), tbl nvarchar(max))
declare @results table (ColumnName nvarchar(max), ColumnValue nvarchar(max), ColumnCount int, TableName NVARCHAR(MAX))

insert into @stage

select c.name, o.name
    from sys.columns c
    join sys.objects o on o.object_id=c.object_id and o.type = 'u'
    and c.system_type_id IN (select system_type_id from sys.types where [name] not in ('text','ntext','image'))
    and o.name like @target



SET @maxi = (select max(i) from @stage)

while @i <= @maxi

BEGIN

set @column = (select col from @stage where i = @i)
set @table = (select tbl from @stage where i = @i)


SET @query = N'SELECT ' +''''+@column+''''+' , '+ @column

SELECT @query = @query + ', COUNT(  ' + @column + ' ) as count' + @column + ' , ''' + @table + ''' as tablename'
select @query = @query + ' from ' + @table + ' group by ' + @column

--Select @query
insert into @results
EXEC sp_executesql @query

SET @i = @i + 1
END

select * from @results
; with cte as (
                select *, ROW_NUMBER() over (partition by Columnname order by ColumnCount desc) as rn from @results
                )


select * from cte where rn <=3

【讨论】:

  • 谢谢!它似乎非常接近工作,但是,我确实收到了类型冲突错误:timestamp is incompatible with nvarchar(max),有什么建议吗?
  • 我会排除时间戳以及文本、ntext 和图像。除非你特别需要。
【解决方案2】:

从这个 SQL 语句构建器开始,然后根据自己的喜好对其进行修改:

EDIT 按描述添加顺序

With ColumnSet As
(
    Select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME
    From INFORMATION_SCHEMA.COLUMNS
    Where 1=1
        And TABLE_NAME IN ('Table1')
        And COLUMN_NAME IN ('Column1', 'Column2')
)
Select 'Select Top 3 ' + COLUMN_NAME + ', Count (*) NumInstances From ' + TABLE_SCHEMA + '.'+ TABLE_NAME + ' Group By ' + COLUMN_NAME + ' Order by Count (*) Desc'
From ColumnSet

【讨论】:

  • 您需要在此处添加订单。如果我了解 OP 正在寻找什么,这只是一个开始。这将需要使用动态交叉表或动态数据透视表将值放回列中。
  • 我会使用按 count(*) 排序而不是序数位置。出错的可能性要小得多。 :)
猜你喜欢
  • 2010-09-25
  • 2017-11-08
  • 1970-01-01
  • 1970-01-01
  • 2017-01-06
  • 2023-04-10
  • 1970-01-01
  • 2021-05-21
  • 1970-01-01
相关资源
最近更新 更多