【问题标题】:MySQL SET Type in PostgreSQL? [duplicate]PostgreSQL 中的 MySQL SET 类型? [复制]
【发布时间】:2013-01-18 10:15:59
【问题描述】:

我正在尝试使用MySQL SET 输入PostgreSQL,但我发现只有数组,它具有非常相似的功能但不符合要求。

PostgreSQL 有类似的数据类型吗?

【问题讨论】:

    标签: mysql database postgresql database-migration sqldatatypes


    【解决方案1】:

    您在寻找枚举数据类型吗?

    PostgreSQL 9.1 Enumerated Types

    【讨论】:

    • 虽然这是 Postgres 中的“最佳”匹配,但两种解决方案(SET 或 ENUM)都不是很好。我认为两者都是正确的 1:n 关系模型的解决方法。
    • 不,我不是在寻找 ENUM。我正在寻找 SET。
    【解决方案2】:

    通过阅读问题中引用的页面,似乎 SET 是一种在一列中存储多达 64 个命名布尔值的方法。 PostgreSQL 没有提供这样做的方法。您可以使用独立的布尔列,或某种大小的整数并直接旋转位。添加两个新表(一个用于有效名称,另一个用于将名称连接到详细信息行)可能有意义,尤其是在可能需要将任何其他数据与单个值关联时。

    【讨论】:

      【解决方案3】:

      【讨论】:

        【解决方案4】:

        您可以使用以下解决方法:

        1。 BIT strings

        您可以将最多 N 个元素的集合定义为简单的BIT(N)。 填充和检索有点尴尬 - 您必须使用位掩码作为集合成员。但是位串真的很适合set operations:交集就是&,联合就是|

        这种类型的存储效率非常高 - 每比特的长度开销很小。

        此外,长度不受限制也很好(但您必须提前决定)。

        2。 HSTORE

        HSTORE 类型是一个扩展,但是很容易安装。简单地执行

        CREATE EXTENSION hstore
        

        对于大多数安装 (9.1+) 将使其可用。有传言说 PostgreSQL 9.3 将有 HSTORE 作为标准类型。

        它并不是真正的集合类型,而更像 Perl 哈希或 Python 字典:它保留任意的 key=>value 对集合。

        这样,它不是很有效(当然不是 BIT 字符串有效),但它确实提供了集合所必需的功能:|| 用于联合,但交集有点尴尬:使用

        slice(a,akeys(b)) || slice(b,akeys(a))
        

        您可以阅读有关 HSTORE 的更多信息here

        【讨论】:

        • 3.选项:规范化模型
        • 总的来说,我完全同意。但是,如果您想存储非常长(如 1000 秒)的位集,位串可以节省您的时间 - 因为它非常有效。
        • 总的来说,我在这里同意@a_horse_with_no_name。具有唯一约束或主键的表是一个集合。当然,如果您要从另一个平台迁移,您通常希望首先启动并运行一些东西....
        • 再一次,如果你想保留 100 万张位图,使用 VARBIT 你将只花费 1000000/8 = 125KB(即使这也会被 Postgres TOAST 压缩,可能会压缩 5x-10x到 20KB)。如果您使用具有唯一约束的表,您将花费1000000*(32+8) = 40 MB(行开销为about 32 bytes + 4-8 字节用于您的唯一键和数据),并且不会被压缩。所以差异可能是 1000 倍或更多。
        【解决方案5】:

        带有检查约束的数组呢:

        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 个元素而变得混乱。

        【讨论】:

          【解决方案6】:

          基于上面 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 上。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多