将MySQL SET数据类型转换为Postgres

时间:2011-12-07 23:42:02

标签: mysql postgresql

我正在尝试将MySQL数据库转换为Postgres。这令人沮丧,但一直在稳步前进。我难以理解的一个问题是将MySQL SET数据类型转换为Postgres。 MySQL中的SET数据类型与普通的ENUM类型不同,不能使用CHECK约束进行模拟。

据我所知,SET类型允许从列中的集合中存储零个或多个值。所以,像MySQL中的以下内容

CREATE TABLE foo (color SET('red','green','blue'));

将允许以下任何一项作为有效值

''
'red'
'red,blue'
'green,red'

等等。 Postgres中的近似值是

CREATE TABLE foo (
    color VARCHAR(10) NOT NULL, 
    CHECK (color IN ('red','green','blue'))
);

但上面不允许“红色,蓝色”或“绿色,红色”等等。

当然,以上只是一种简化。实际的数据库相当复杂,大约有六个列被定义为SET。

建议?

1 个答案:

答案 0 :(得分:8)

您可以为列使用数组,为CHECK约束使用"is contained by"运算符:

create table pancakes (
    color varchar(10)[] not null,
    check (color <@ ARRAY['red', 'green', 'blue']::varchar[])
);

然后发生这样的事情:

=> insert into pancakes values (ARRAY['red']);
INSERT 0 1
=> insert into pancakes values (ARRAY['red','green','blue']);
INSERT 0 1
=> insert into pancakes values (ARRAY['red','green','blue','black']);
ERROR:  new row for relation "pancakes" violates check constraint "pancakes_color_check"
=> select * from pancakes;
      color       
------------------
 {red}
 {red,green,blue}
(2 rows)

这将允许列中的{red,red};如果禁止{red,red}很重要,那么您可以添加一个函数来检查数组中的唯一颜色值并调整CHECK约束:

create function has_unique_colors(varchar[]) returns boolean as $$
    select (select count(distinct c) from unnest($1) as dt(c)) = array_length($1, 1);
$$ language sql;

create table pancakes (
    color varchar(10)[] not null,
    check (color <@ ARRAY['red', 'green', 'blue']::varchar[] and has_unique_colors(color))
);

另一个选项是一堆关联表,列中包含简单的标量值。但是,如果您有六个列,这可能很麻烦。如果你需要担心“集合”中的NULL,你也可以使用Erwin的函数版本:

create function has_unique_colors(varchar[]) returns boolean as $$
    select not exists(select c from unnest($1) dt(c) group by 1 having count(*) > 1);
$$ language sql;