编写 Rails 迁移以将布尔值折叠为枚举
Writing a Rails migration to collapse booleans into an enum
我在对数据建模时犯了一个错误,创建了一个包含 4 个布尔值的模型,一次只有一个处于活动状态。我想创建一个 Postgres 枚举类型的列,然后根据先前设置的布尔标志设置值。
我知道我想从这样的事情开始:
class ChangePositionTypeToBeEnumInPosition < ActiveRecord::Migration[6.0]
def change
reversible do |change|
change.up do
execute <<-SQL
CREATE TYPE position_type AS ENUM ('chair', 'jboard', 'eboard', 'aboard');
SQL
# TODO: Execute code to create a new column and set values based off of existing values in the same row
# TODO: Drop the 4 boolean columns
end
change.down do
# TODO: Create the 4 boolean columns
# TODO: Set one to true depending on the enum state
execute <<-SQL
DROP TYPE position_type;
SQL
end
end
end
end
我的问题是:在我的 TODO 注释所在的位置我可以做什么?之前我在我的用户模型中编写了一个从整数到 Postgres 枚举的迁移,我的 change_column
代码如下所示:
change_column :users, :member_type, <<-SQL.strip
member_status USING
CASE member_type
WHEN '0' THEN 'inactive'::member_status
WHEN '1' THEN 'active'::member_status
WHEN '2' THEN 'suspended'::member_status
END
SQL
我想我正在尝试编写的代码是它的一些变体,带有一系列 if 语句。如有任何意见,我们将不胜感激。
虽然你自己提出了问题的方法,但无论如何这里是解决方案。
基于this article。您可以尝试以下操作:
class ChangePositionTypeToBeEnumInPosition < ActiveRecord::Migration[6.0]
def change
reversible do |change|
change.up do
execute <<-SQL
CREATE TYPE position_type_enum AS ENUM ('chair', 'jboard', 'eboard', 'aboard');
SQL
add_column :positions, :position_type, :position_type_enum
# You may also want to add index on this column
# If this table's size is huge(10m-20m+), this is not a good idea in that case.
execute <<-SQL
WITH cte AS
(
SELECT id,
CASE
WHEN chair = true THEN 'chair'::position_type_enum
WHEN jboard = true THEN 'jboard'::position_type_enum
WHEN eboard = true THEN 'eboard'::position_type_enum
ELSE 'aboard'::position_type_enum
END AS position_type
FROM positions
)
UPDATE positions p
SET position_type = c.position_type
FROM cte c
WHERE p.id = c.id;
SQL
remove_column :positions, :chair, :boolean
remove_column :positions, :jboard, :boolean
remove_column :positions, :eboard, :boolean
remove_column :positions, :aboard, :boolean
end
change.down do
add_column :positions, :chair, :boolean
add_column :positions, :jboard, :boolean
add_column :positions, :eboard, :boolean
add_column :positions, :aboard, :boolean
execute <<-SQL
UPDATE positions
SET chair = CASE WHEN position_type = 'chair' THEN true ELSE false END,
jboard = CASE WHEN position_type = 'jboard' THEN true ELSE false END,
eboard = CASE WHEN position_type = 'eboard' THEN true ELSE false END,
aboard = CASE WHEN position_type = 'aboard' THEN true ELSE false END
SQL
remove_column :positions, :position_type
execute <<-SQL
DROP TYPE position_type_enum;
SQL
end
end
end
end
我还没有尝试 运行 此代码,您应该更正您可能发现的任何拼写错误(并在此处发表评论,以便我更新答案)。
另请阅读我在上面链接的文章,了解如何在模型上正确使用 postgres 枚举。
我在对数据建模时犯了一个错误,创建了一个包含 4 个布尔值的模型,一次只有一个处于活动状态。我想创建一个 Postgres 枚举类型的列,然后根据先前设置的布尔标志设置值。
我知道我想从这样的事情开始:
class ChangePositionTypeToBeEnumInPosition < ActiveRecord::Migration[6.0]
def change
reversible do |change|
change.up do
execute <<-SQL
CREATE TYPE position_type AS ENUM ('chair', 'jboard', 'eboard', 'aboard');
SQL
# TODO: Execute code to create a new column and set values based off of existing values in the same row
# TODO: Drop the 4 boolean columns
end
change.down do
# TODO: Create the 4 boolean columns
# TODO: Set one to true depending on the enum state
execute <<-SQL
DROP TYPE position_type;
SQL
end
end
end
end
我的问题是:在我的 TODO 注释所在的位置我可以做什么?之前我在我的用户模型中编写了一个从整数到 Postgres 枚举的迁移,我的 change_column
代码如下所示:
change_column :users, :member_type, <<-SQL.strip
member_status USING
CASE member_type
WHEN '0' THEN 'inactive'::member_status
WHEN '1' THEN 'active'::member_status
WHEN '2' THEN 'suspended'::member_status
END
SQL
我想我正在尝试编写的代码是它的一些变体,带有一系列 if 语句。如有任何意见,我们将不胜感激。
虽然你自己提出了问题的方法,但无论如何这里是解决方案。
基于this article。您可以尝试以下操作:
class ChangePositionTypeToBeEnumInPosition < ActiveRecord::Migration[6.0]
def change
reversible do |change|
change.up do
execute <<-SQL
CREATE TYPE position_type_enum AS ENUM ('chair', 'jboard', 'eboard', 'aboard');
SQL
add_column :positions, :position_type, :position_type_enum
# You may also want to add index on this column
# If this table's size is huge(10m-20m+), this is not a good idea in that case.
execute <<-SQL
WITH cte AS
(
SELECT id,
CASE
WHEN chair = true THEN 'chair'::position_type_enum
WHEN jboard = true THEN 'jboard'::position_type_enum
WHEN eboard = true THEN 'eboard'::position_type_enum
ELSE 'aboard'::position_type_enum
END AS position_type
FROM positions
)
UPDATE positions p
SET position_type = c.position_type
FROM cte c
WHERE p.id = c.id;
SQL
remove_column :positions, :chair, :boolean
remove_column :positions, :jboard, :boolean
remove_column :positions, :eboard, :boolean
remove_column :positions, :aboard, :boolean
end
change.down do
add_column :positions, :chair, :boolean
add_column :positions, :jboard, :boolean
add_column :positions, :eboard, :boolean
add_column :positions, :aboard, :boolean
execute <<-SQL
UPDATE positions
SET chair = CASE WHEN position_type = 'chair' THEN true ELSE false END,
jboard = CASE WHEN position_type = 'jboard' THEN true ELSE false END,
eboard = CASE WHEN position_type = 'eboard' THEN true ELSE false END,
aboard = CASE WHEN position_type = 'aboard' THEN true ELSE false END
SQL
remove_column :positions, :position_type
execute <<-SQL
DROP TYPE position_type_enum;
SQL
end
end
end
end
我还没有尝试 运行 此代码,您应该更正您可能发现的任何拼写错误(并在此处发表评论,以便我更新答案)。
另请阅读我在上面链接的文章,了解如何在模型上正确使用 postgres 枚举。