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

PostgreSQL中是否有处理无序数组(集合)的标准方法?,sql,postgresql,set,Sql,Postgresql,Set,我有一个表,它包含两列中的成对单词。单词的顺序通常很重要,但有时我只想根据这两个单词进行聚合,而不考虑顺序。有没有一种简单的方法可以将两行具有相同单词但顺序不同(一行与另一行相反)的行视为相同的“集合”?换句话说,对待: apple orange orange apple 苹果橙 桔子苹果 作为: (苹果,橙色) (苹果,橙色) 现在没有内置的方式 作为数组 如果在保存时始终对其进行规范化,则可以将数组视为集合,方法是始终对其进行排序和消除重复。如果PostgreSQL有一个内置的C函数来实现这

我有一个表,它包含两列中的成对单词。单词的顺序通常很重要,但有时我只想根据这两个单词进行聚合,而不考虑顺序。有没有一种简单的方法可以将两行具有相同单词但顺序不同(一行与另一行相反)的行视为相同的“集合”?换句话说,对待:

apple orange orange apple 苹果橙 桔子苹果 作为:

(苹果,橙色) (苹果,橙色)
现在没有内置的方式

作为数组 如果在保存时始终对其进行规范化,则可以将数组视为集合,方法是始终对其进行排序和消除重复。如果PostgreSQL有一个内置的C函数来实现这一点,那就太好了,但是它没有。我考虑过写一个,但是C数组API很糟糕,所以尽管我写了很多扩展,我还是小心地避开了这个

如果您不介意适度糟糕的性能,可以在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\u uniq\u sort
时包装所有保存,或使用触发器强制执行。然后,您可以比较数组是否相等。如果您只是在应用程序端执行排序/唯一,则可以避免对应用程序中的数据进行
array\u uniq\u sort
调用

如果这样做,请将“集合”存储为数组列,如
text[]
,而不是逗号或空格分隔的文本。请参阅,了解一些原因

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

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\u agg
对它们进行排序和比较,因为使用SQL集操作可能会很麻烦(特别是在缺少XOR/双面集差操作的情况下)

这通常称为EAV(实体属性值)。我自己不是一个歌迷,但它偶尔也有自己的位置。除非在没有
值的情况下使用它

您可以创建一个表:

CREATE TABLE item_attributes (
    item_id integer references items(id),
    attribute_name text,
    primary key(item_id, attribute_name)
);
并为每个项的每个集合项插入一行,而不是让每个项都有一个数组值列。由主键强制执行的唯一约束可确保任何项都不能具有给定属性的重复项。属性顺序不相关/未定义

可以使用SQL集运算符(如
EXCEPT
)进行比较,或者使用
array\u agg(attribute\u name ORDER BY attribute\u name)
形成一致排序的数组进行比较

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

就我个人而言,我会在这种方法中使用数组

商店 您还可以使用具有空值的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)
不过,它只对文本类型有用。e、 g:

regress=# SELECT hstore('"1.0" => 1, "2.0" => 1') = hstore('"1.00" => 1, "1.000" => 1, "2.0" => 1');
 ?column? 
----------
 f
(1 row)
我觉得很难看。所以我还是喜欢数组

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

您的单词实际存储在数组中吗?这个问题似乎暗示着它们被存储为单独的列,但标题谈到了ArrayShanks,因为它能如此清晰地展示各种可能性。db本质上是只读的,所以数组方法应该是好的。使用hstore是我见过其他人做的事情,因此如果我需要在服务器端做一些更复杂的事情,我可能会在某个时候尝试。我想说,contains操作符也可以让你达到你想要的位置。这不是一个集合,但它可以在无序的where子句上获取您的真理<代码>从testarray中选择aids,其中aids@>数组[1,2,3,11,33,22]
返回
{1,2,3,11,22,33}
regress=# SELECT hstore('"1.0" => 1, "2.0" => 1') = hstore('"1.00" => 1, "1.000" => 1, "2.0" => 1');
 ?column? 
----------
 f
(1 row)