我一直在尝试找到一个最佳解决方案来从每列中选择唯一值。我的问题是我事先不知道列名,因为不同的表有不同的列数。所以首先,我必须找到列名称,我可以使用下面的查询来做到这一点:
select column_name from information_schema.columns
where table_name='m0301010000_ds' and column_name like 'c%'
列名称的示例输出:
c1, c2a, c2b, c2c, c2d, c2e, c2f, c2g, c2h, c2i, c2j, c2k, ...
然后我将使用返回的列名称来获取每列中的唯一/不同值,而不仅仅是不同行。
我知道一个最简单且糟糕的方法是为每个列编写 select distect column_name from table where column_name = 'something'(大约 20-50 次),而且也非常耗时。由于我不能在每个column_name中使用多个不同的值,所以我坚持使用这种老式的解决方案。
我确信会有一种更快、更优雅的方式来实现这一目标,但我只是不知道如何实现。我将非常感谢对此的任何帮助。
您不能只返回行,因为不同的值不再组合在一起。
你可以返回数组,它可以比你想象的更简单:
SELECT array_agg(DISTINCT c1) AS c1_arr
,array_agg(DISTINCT c2a) AS c2a_arr
,array_agg(DISTINCT c2b) AS c2ba_arr
, ...
FROM m0301010000_ds;
这将返回每列不同的值。每列一个数组(可能很大)。列中值之间的所有连接(以前位于同一行中)都将在输出中丢失。
CREATE OR REPLACE FUNCTION f_build_sql_for_dist_vals(_tbl regclass)
RETURNS text AS
$func$
SELECT 'SELECT ' || string_agg(format('array_agg(DISTINCT %1$I) AS %1$I_arr'
, attname)
, E'\n ,' ORDER BY attnum)
|| E'\nFROM ' || _tbl
FROM pg_attribute
WHERE attrelid = _tbl -- valid, visible table name
AND attnum >= 1 -- exclude tableoid & friends
AND NOT attisdropped -- exclude dropped columns
$func$ LANGUAGE sql;
致电:
SELECT f_build_sql_for_dist_vals('public.m0301010000_ds');
返回如上所示的 SQL 字符串。
我使用系统目录
pg_attribute
而不是信息模式。表名称的对象标识符类型为 regclass
。此相关答案中有更多解释:如果您“实时”需要此数据,您将无法使用需要执行全表扫描来归档它的 SQL 来归档它。
我建议您创建一个单独的表,其中包含每列的不同值(使用 @Erwin Brandstetter 的 SQL 初始化;)并使用原始表上的触发器来维护它。
您的新表的每个字段将有一列。行数将等于一个字段的不同值的最大数量。
插入时:对于每个字段要维护检查该值是否已经存在。如果没有,请添加。
对于更新:对于每个要维护的具有旧值!=新值的字段,检查新值是否已经存在。如果没有,请添加。对于旧值,检查是否有任何其他行具有该值,如果没有,则将其从列表中删除(将字段设置为空)。
对于删除:对于要维护的每个字段,检查是否有任何其他行具有该值,如果没有,则将其从列表中删除(将值设置为空)。
这样负载主要转移到触发器上,值列表表上的SQL会超级快。
P.S.:确保将所有 SQL 从触发器传递到解释计划,以确保它们尽可能使用最佳索引和执行计划。对于更新/删除,只需检查旧值是否存在(限制 1)。
DECLARE @TableName NVARCHAR(MAX) = 'table_name'; -- 在此指定您的表名称 声明 @SQLQuery NVARCHAR(MAX) = '';
选择@SQLQuery = @SQLQuery + 'SELECT ''' + COLUMN_NAME + ''' AS Column_Name, COUNT(DISTINCT ' + QUOTENAME(COLUMN_NAME) + ') AS Unique_Values FROM ' + QUOTENAME(@TableName) + ' UNION ALL ' 来自 INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName;
-- 从查询中删除最后一个“UNION ALL” SET @SQLQuery = LEFT(@SQLQuery, LEN(@SQLQuery) - LEN(' UNION ALL '));
-- 追加 order by 子句 SET @SQLQuery = @SQLQuery + ' ORDER BY Unique_Values DESC;';
-- 执行动态查询 EXEC sp_executesql @SQLQuery;
从表名中选择计数(*)作为Total_value