我正在尝试使用MySQL
SET类型PostgreSQL
,但我发现只有数组,它具有非常相似的功能但不符合要求。
是否PostgreSQL
有类似的数据类型?
我正在尝试使用MySQL
SET类型PostgreSQL
,但我发现只有数组,它具有非常相似的功能但不符合要求。
是否PostgreSQL
有类似的数据类型?
您可以使用以下解决方法:
您可以简单地定义一组最大 N 个元素BIT(N)
。填充和检索有点尴尬 - 您必须使用位掩码作为集合成员。但是位串真的很适合集合操作:交集很简单&
,并集很简单|
。
这种类型的存储非常有效 - 每位每位的长度开销很小。
此外,长度不受限制也很好(但您必须提前决定)。
HSTORE
type 是一个扩展,但是很容易安装。简单地执行
CREATE EXTENSION hstore
对于大多数安装 (9.1+) 将使其可用。有传言说 PostgreSQL 9.3 将HSTORE
作为标准类型。
它不是真正的集合类型,而是更像 Perl 哈希或 Python 字典:它保留任意的key
=>value
对集合。
这样,它不是很有效(当然不是 BIT 字符串有效),但它确实提供了集合所必需的函数:||
对于并集,但交集有点尴尬:使用
slice(a,akeys(b)) || slice(b,akeys(a))
您可以在此处阅读有关 HSTORE的更多信息。
基于上面 a_horse_with_no_name 的答案,我建议稍微复杂一点:
CREATE FUNCTION set_check(in_value anyarray, in_check anyarray)
RETURNS BOOL LANGUAGE SQL IMMUTABLE AS
$$
WITH basic_check AS (
select bool_and(v = any($2)) as condition, count(*) as ct
FROM unnest($1) v
GROUP BY v
), length_check AS (
SELECT count(*) = 0 as test FROM unnest($1)
)
SELECT bool_and(condition AND ct = 1)
FROM basic_check
UNION
SELECT test from length_check where test;
$$;
然后你应该能够做类似的事情:
CREATE TABLE set_test (
my_set text[] CHECK (set_check(my_set, array['one'::text,'two']))
);
这有效:
postgres=# insert into set_test values ('{}');
INSERT 0 1
postgres=# insert into set_test values ('{one}');
INSERT 0 1
postgres=# insert into set_test values ('{one,two}');
INSERT 0 1
postgres=# insert into set_test values ('{one,three}');
ERROR: new row for relation "set_test" violates check constraint "set_test_my_set_check"
postgres=# insert into set_test values ('{one,one}');
ERROR: new row for relation "set_test" violates check constraint "set_test_my_set_check"
请注意,这假设对于您的集合,每个值都必须是唯一的(我们在这里讨论集合)。该功能应该执行得非常好并且应该满足您的需求。然而,这具有处理任何尺寸集的优势。
存储方面它与 MySQL 的实现完全不同。它将占用更多磁盘空间,但应该处理具有尽可能多的成员的集合,前提是您没有遇到存储限制......所以与 MySQL 的实现相比,它应该具有超集的功能。但是,一个显着的区别是这不会将数组折叠成不同的值。它只是禁止他们。如果您也需要,请查看触发器。
此解决方案还保持输入数据的序数不变,因此 '{one,two}' 与 '{two,one}' 不同,因此如果您需要确保行为已更改,您可能需要查看 PostgreSQL 9.2 上的排除约束.
带有检查约束的数组怎么样:
create table foobar
(
myset text[] not null,
constraint check_set
check ( array_length(myset,1) <= 2
and (myset = array[''] or 'one'= ANY(myset) or 'two' = ANY(myset))
)
);
这将匹配SET('one', 'two')
MySQL 手册中解释的定义。
唯一不会做的就是“标准化”数组。所以
insert into foobar values (array['one', 'two']);
和
insert into foobar values (array['two', 'one']);
显示方式与 MySQL 不同(两者都显示为'one','two'
)
但是,检查约束会因超过 3 或 4 个元素而变得混乱。
您在寻找枚举数据类型吗?
从阅读问题中引用的页面来看,似乎 SET 是一种在一列中存储多达 64 个命名布尔值的方法。PostgreSQL 没有提供这样做的方法。您可以使用独立的布尔列,或某种大小的整数并直接旋转位。添加两个新表(一个用于有效名称,另一个用于将名称连接到详细信息行)可能是有意义的,尤其是在可能需要将任何其他数据与单个值相关联的情况下。
前段时间我写了一个类似的扩展
https://github.com/okbob/Enumset
但它并不完整
pltoolkit 的一些更完整和更接近 mysql 的功能
http://okbob.blogspot.cz/2010/12/bitmapset-for-plpgsql.html http://pgfoundry.org/frs/download.php/3203/pltoolbox-1.0.2.tar.gz http:// postgres.cz/wiki/PL_toolbox_%28en%29
函数 find_in_set 可以通过数组来模拟
http://okbob.blogspot.cz/2009/08/mysql-functions-for-postgresql.html