目前没有内置方法。
作为数组
如果您在保存时始终对它们进行规范化,则可以将数组视为集合,方法是始终对它们进行排序和去重存储。如果 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
扩展提供了有用、快速的函数来将数组视为集合。它们仅适用于整数数组,但它们确实很有用。