如何根据条件从每列中获取唯一值?

时间:2014-05-19 19:24:58

标签: sql postgresql postgresql-9.1 postgresql-performance

我一直在尝试找到一个最佳解决方案,从每列中选择唯一值。我的问题是我不提前知道列名,因为不同的表有不同的列数。首先,我必须找到列名,我可以使用下面的查询来执行此操作:

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 =' 为每一列(约20-50次)及其非常也很耗时。由于我不能使用多个不同的每列名称,因此我坚持使用这个旧的学校解决方案。

我相信会有更快更优雅的方式实现这一目标,而我无法理解如何做到这一点。我真的很感激你的帮助。

2 个答案:

答案 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;

这会返回每列的不同值。每列一个数组(可能很大)。列中的值之间的所有连接(以前在同一行中的所有连接)都会在输出中丢失。

自动构建SQL

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)。