我一直在尝试找到一个最佳解决方案,从每列中选择唯一值。我的问题是我不提前知道列名,因为不同的表有不同的列数。首先,我必须找到列名,我可以使用下面的查询来执行此操作:
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 distict column_name,其中column_name =' 39> 为每一列(约20-50次)及其非常也很耗时。由于我不能使用多个不同的每列名称,因此我坚持使用这个旧的学校解决方案。
我相信会有更快更优雅的方式实现这一目标,而我无法理解如何做到这一点。我真的很感激你的帮助。
答案 0 :(得分:3)
您不能只返回行,因为不同的值不再相继。
你可以返回数组,这可能比你预期的更简单:
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
。在这个相关答案中有更多解释:
PLpgSQL function to find columns with only NULL values in a given table
答案 1 :(得分:3)
如果您需要“实时”,则无法使用需要执行全表扫描的SQL来存档它。
我建议你创建一个包含每列不同值的分隔表(用@Erwin Brandstetter中的SQL初始化;)并使用原始表上的触发器维护它。
您的新表格每个字段会有一列。行的数量将等于一个字段的不同值的最大数量。
对于插入:对于每个字段,以维持检查该值是否已存在。如果没有,请添加它。
对于on update:对于要维护旧值的每个字段!=从新值,检查新值是否已经存在。如果没有,请添加它。关于旧值,检查是否有任何其他行具有该值,如果没有,则从列表中删除它(将字段设置为null)。
对于删除:对于要维护的每个字段,检查是否有任何其他行具有该值,如果没有,则将其从列表中删除(将值设置为null)。
这样负载主要移动到触发器,值列表表上的SQL将超快。
P.S。:确保将所有SQL从触发器传递到解释计划,以确保它们尽可能使用最佳索引和执行计划。对于更新/删除,只需检查是否存在旧值(限制1)。