我正在尝试将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。
建议?
答案 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;