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

Posted

技术标签:

【中文标题】如何根据条件从每列中获取唯一值?【英文标题】:How to get unique values from each column based on a condition? 【发布时间】:2014-05-19 19:24:57 【问题描述】:

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

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, ...

然后我会使用 返回的 列名称来获取 每列 中的 唯一/不同 值,而不仅仅是 不同的行强>。

我知道一种最简单但很糟糕的方法是为每一列(大约 20-50 次)从 table where column_name = 'something' 中编写 select distict column_name ,这也非常耗时。由于每个 column_name 不能使用多个不同的值,因此我坚持使用这种老派的解决方案。

我确信会有一种更快、更优雅的方式来实现这一点,但我只是不知道怎么做。我将非常感谢您对此提供的任何帮助。

【问题讨论】:

由于每一列的行数都不同,并且唯一的列值不会再组合在一起,您希望得到怎样的结果?显示示例输出。另外,我们在谈论什么数据类型? 恐怕没有“更快、更优雅的方式来实现这一点”,但如果有的话我很感兴趣;) 如果您需要优化性能,请在您的问题中提供所有基本要素:示例表定义(包括索引)、基数(多少行?)、多少写入/时间单位 - 还是只读?定义并描述您在标题中提到的“条件”。它的选择性如何?可以采取哪些形式?结果中有多少个值?用例是什么?检查我添加的标签的信息:[postgresql-performance]。 【参考方案1】:

您不能只返回行,因为不同的值不再一起出现。

可以返回数组,这可能比您预期的要简单:

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

【讨论】:

谢谢欧文。我认为以数组/字符串的形式返回就可以了。我相信我可以在我的代码中使用它。实际上我知道它不能是基于行的解决方案,所以看起来与您提供的类似。再次,非常感谢!!! 谢谢,但我不相信它比最初的提议更快......实际上,无论如何你必须为每个字段选择不同的,所以这个解决方案更“专家”(=复杂在我看来),但我不确定它是否更有效。请让我知道上述解决方案的执行时间是否明显更快(或没有)。 @CedricSimon:我不相信执行时间会比单独的SELECT DISTINCT 快得多——或者如果这可能的话。中小型表可能会有所收获,以节省开销。我理解这个问题是为了找到更快的方法来为大量列编写查询。至于复杂性,它足够简单,也不那么冗长。 @CedricSimon 我对执行时间进行了比较,它(在数组中返回结果)花费了一半的执行时间(5 秒对 9.5 秒之前)。所以仍然很快,但在实时环境中使用 5 秒仍然较慢。我仍在寻找任何更快的选择,我希望会有一个:)。 @Dev Patel 和 Erwin Brandstetter:哇!我很佩服。我没想到会有显着的性能提升。对我来说好惊喜。谢谢。【参考方案2】:

如果您“实时”需要它,您将无法使用需要执行全表扫描以存档它的 SQL 来存档它。

我建议您创建一个单独的表,其中包含每列的不同值(使用来自 @Erwin Brandstetter 的 SQL 初始化;)并使用原始表上的触发器对其进行维护。

您的新表格每个字段将有一列。行数将等于一个字段的不同值的最大数量。

插入时:为每个字段维护检查该值是否已经存在。如果没有,请添加它。

对于更新:对于每个要维护的具有旧值的字段!= 来自新值,检查新值是否已经存在。如果没有,请添加它。关于旧值,检查是否有其他行具有该值,如果没有,则将其从列表中删除(将字段设置为 null)。

对于删除:对于要维护的每个字段,检查是否有任何其他行具有该值,如果没有,则将其从列表中删除(将值设置为 null)。

这样负载主要转移到触发器上,值列表的SQL会超快。

P.S.:确保将所有 SQL 从触发器传递到解释计划,以确保它们尽可能使用最佳索引和执行计划。对于更新/删除,只需检查旧值是否存在(限制 1)。

【讨论】:

感谢您的建议。由于我正在使用的表具有不同的行,其中包含许多列值组合(>30)。而且我有大约 20 多个这样的表。所以不确定具有不同值的表是什么意思。您的意思是每列的不同值都有一个表吗?我的主要挑战是从预先存在的表中检索信息 (SELECT)。 我的意思是一列将保存一个字段的每个不同值。每个字段一列。然后从所需列中选择非空值。 是的,同意。但是我必须根据条件选择值,因此根据条件,结果将是 1000 行的唯一组合。所以我仍然想知道如何为一个字段保留每个不同的值。 ......我将尝试提供一个sn-p /数据示例,这可能会更好地解释它。 嗯...去商店,买一些 GB 的内存,然后把你所有的表放在内存中:D。哈哈

以上是关于如何根据条件从每列中获取唯一值?的主要内容,如果未能解决你的问题,请参考以下文章

获取二维数组中每列的第二个最小值

如何计算每列中唯一的重复值

如何将熊猫数据框中每列中唯一值的数量绘制为条形图?

Pyspark - 从每列中选择不同的值

MySQL - 如何根据另一列中的唯一值转置一列中的单元格?

如何获取列中多个最小值的索引?