PostgreSQL 中是否有处理无序数组(集)的标准方法?

2024-02-19

我有一个表,其中包含两个单独列中的单词对。单词的顺序通常很重要,但有时我只想根据两个单词进行聚合,而不管顺序如何。是否有一种简单的方法将具有相同单词但顺序不同(一行与另一行相反)的两行视为相同的“集合”?换句话说,治疗:



apple orange
orange apple
  

as:



(apple,orange)
(apple,orange)
  

目前没有内置方法。

作为数组

如果您在保存时始终对它们进行规范化,则可以将数组视为集合,方法是始终对它们进行排序和去重存储。如果 PostgreSQL 有一个内置的 C 函数来执行此操作,那就太好了,但事实并非如此。我看了一下写一个,但 C 数组 API 是horrible,所以尽管我已经写了一堆扩展,但我只是小心翼翼地放弃了这个。

如果你不介意性能稍差,你可以用 SQL 来实现:

CREATE OR REPLACE FUNCTION array_uniq_sort(anyarray) RETURNS anyarray AS $$
SELECT array_agg(DISTINCT f ORDER BY f) FROM unnest($1) f;
$$ LANGUAGE sql IMMUTABLE;

然后将所有保存包装在调用中array_uniq_sort或使用触发器强制执行。然后您可以比较数组是否相等。你可以避免array_uniq_sort如果您只是在应用程序端进行排序/唯一,则需要从应用程序获取数据。

如果你这样做please将您的“集”存储为数组列,例如text[],不是逗号或空格分隔的文本。看这个问题 https://dba.stackexchange.com/q/55871/7788由于某些原因。

您需要注意一些事情,例如数组之间的转换比其基本类型之间的转换更严格。例如。:

regress=> SELECT 'a' = 'a'::varchar, 'b' = 'b'::varchar;
 ?column? | ?column? 
----------+----------
 t        | t
(1 row)

regress=> SELECT ARRAY['a','b'] = ARRAY['a','b']::varchar[];
ERROR:  operator does not exist: text[] = character varying[]
LINE 1: SELECT ARRAY['a','b'] = ARRAY['a','b']::varchar[];
                              ^
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
regress=> SELECT ARRAY['a','b']::varchar[] = ARRAY['a','b']::varchar[];
 ?column? 
----------
 t
(1 row)

此类列对于数组包含或数组重叠等操作是可索引的;请参阅有关数组索引的 PostgreSQL 文档。

作为标准化行

另一种选择是仅使用合适的键存储规范化的行。我还是会用array_agg用于对它们进行排序和比较,因为 SQL 集合操作使用起来可能很笨拙(特别是考虑到缺乏 XOR / 双面集合差异操作)。

这通常称为 EAV(实体-属性-值)。我自己不是粉丝,但它偶尔也有它的一席之地。除非你在没有value成分。

您创建一个表:

CREATE TABLE item_attributes (
    item_id integer references items(id),
    attribute_name text,
    primary key(item_id, attribute_name)
);

并为每个项目的每个集合条目插入一行,而不是让每个项目都有一个数组值列。主键强制执行的唯一约束确保没有项目可以具有给定属性的重复项。属性顺序不相关/未定义。

可以使用 SQL 集合运算符进行比较,例如EXCEPT,或使用array_agg(attribute_name ORDER BY attribute_name)形成一致排序的数组以进行比较。

索引仅限于确定给定项目是否具有给定属性。

就我个人而言,我会使用数组而不是这种方法。

hstore

您还可以使用带有空值的 hstore 来存储集合,因为 hstore 可以删除重复的键。 9.4的jsonb也将为此努力。

regress=# create extension hstore;
CREATE EXTENSION
regress=# SELECT hstore('a => 1, b => 1') = hstore('b => 1, a => 1, b => 1');
 ?column? 
----------
 t
(1 row)

不过,它只对文本类型真正有用。例如。:

regress=# SELECT hstore('"1.0" => 1, "2.0" => 1') = hstore('"1.00" => 1, "1.000" => 1, "2.0" => 1');
 ?column? 
----------
 f
(1 row)

我觉得这很丑。再说一遍,我更喜欢数组。

仅适用于整数数组

The intarray扩展提供了有用、快速的函数来将数组视为集合。它们仅适用于整数数组,但它们确实很有用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PostgreSQL 中是否有处理无序数组(集)的标准方法? 的相关文章

随机推荐