[翻译]Sequel数据库模式修改方法

原文链接

这是一个对常用的模式修改方法的简要描述:

create_table(创建数据表)

create_table是最常用的模式修改方法,它向模式中添加一个数据表。你提供一个符号类型的参数作为数据表的名字,类似下面的语句块:

create_table(:artists) do
  primary_key :id
  String :name
end

注意如果你想给数据表添加主键,你必须指定一个,Sequel默认是不会创建的。

列类型

method_missing调用column时,create_table语句块中的大部分方法调用会创建数据列。通常情况下用具体的列类型作为方法名可以创建相应的列,方法名后紧跟的是用符号表示的列名,在列名后面还可以有一些选项。如果用Sequel能够识别的ruby类型作为方法名,Sequel会根据给定的数据库将其转换为恰当的类型。因此当你指定String类型时,实际上Sequel会根据底层数据库而使用varchar或text类型。下面给出了所有能被Sequel转换成数据库类型:

许多能在create_table块中调用的方法能创建

create_table(:columns_types) do       # common database type used
  Integer :a0                         # integer
  String :a1                          # varchar(255)
  String :a2, :size=>50               # varchar(50)
  String :a3, :fixed=>true            # char(255)
  String :a4, :fixed=>true, :size=>50 # char(50)
  String :a5, :text=>true             # text
  File :b,                            # blob
  Fixnum :c                           # integer
  Bignum :d                           # bigint
  Float :e                            # double precision
  BigDecimal :f                       # numeric
  BigDecimal :f2, :size=>10           # numeric(10)
  BigDecimal :f3, :size=>[10, 2]      # numeric(10, 2)
  Date :g                             # date
  DateTime :h                         # timestamp
  Time :i                             # timestamp
  Time :i2, :only_time=>true          # time
  Numeric :j                          # numeric
  TrueClass :k                        # boolean
  FalseClass :l                       # boolean
end

注意,除了通过ruby的类型,Sequel还会通过列选项自动推断要使用哪种数据库数据类型。也同样需要注意,由于ruby中并没有Boolean类型,TrueClassFalseClass会被视为boolean类型的列,你可以使用它们两个中的任意一个。

同时还需要注意这种转换只会对被Sequel支持的ruby类型起作用。所有其他的情况,Sequel会按照字面使用指定的类型:

create_table(:columns_types) do  # database type used
  string :a1                     # string
  datetime :a2                   # datetime
  blob :a3                       # blob
  inet :a4                       # inet
end

除了将列类型作为方法名使用,你还可以使用column方法,第二个参数是指定的数据类型,可以是ruby类型、符号或者字符串:

create_table(:columns_types) do  # database type used
  column :a1, :string            # string
  column :a2, String             # varchar(255)
  column :a3, 'string'           # string
  column :a4, :datetime          # datetime
  column :a5, DateTime           # timestamp
  column :a6, 'timestamp(6)'     # timestamp(6)
end

列选项

当使用类型名作为方法名时,第3个参数可以使用一个可选的hash。当使用column方法时,第4个参数是这个可选的hash。以下是被支持的选项:

选项 说明
:default 提供列的默认值
:index 为列创建索引。如果给的是个hash,则使用该hash作为索引
:null 标注该列是否能够使用NULL空值。如果为true则允许NULL,如果为false则不允许NULL。如果为指定,则依照使用的数据库的默认情况
:unique 标注该列是唯一的,通常情况下和对该列创建唯一索引有同样的效果

其他方法

除了column方法和一些其他的创建列的方法,这里还有一些其他的方法可以使用:

primary_key(主键)

前面已经使用过这个方法了。该方法会创建一个integer类型的自增的主键。

create_table(:a0){primary_key :id}

如果想要一个64位integer自增主键,可以这样:

create_table(:a0){primary_key :id, :type=>Bignum}

如果不想创建一个integer自增主键,那就不要用该方法。你应该在column方法或相应类型的方法中使用:primary_key选项:

create_table(:a1){Integer :id, :primary_key=>true} # Non autoincrementing integer primary key
create_table(:a2){String :name, :primary_key=>true} # varchar(255) primary key

如果想创建一个复合主键,那么你应该调用primary_key方法并传递给它一个包含列符号名的数组:

create_table(:items) do
  Integer :group_id
  Integer :position
  primary_key [:group_id, :position]
end

如果给primary_key提供一个数组,它并不会创建一个列,而是设置一个主键约束。

foreign_key(外键)

foreign_key被用来创建一个和另一个(也可以是同一个)数据表中的一个列相关联的外键列。该方法的第1个参数是列名,第2个参数是相关联的数据表,第3个参数是一个hash对,这是可选的。下面给一个简单的例子:

create_table(:albums) do
  primary_key :id
  foreign_key :artist_id, :artists
  String :name
end

foreign_key接受以下给定的选项:

选项 说明
:deferrable 使外键约束能延期校验,因此在事物结束前它不会被检验。
:key 与作为外键的列相关联的关联表中的列。如果这个列引用的是关联表的主键,则这不是必须的,至少在大多数数据库是这样的。
:on_delete 指定与外键列关联的记录的主键被删除时的行为。可以是:restrict:cascade:set_null或者:set_default。你也可以使用一个被逐字地使用的字符串。
:on_update 指定与外键列关联的记录的主键被修改时的行为。和:on_delete有一样的可选值。

primary_key一样,如果给foreign_key提供一个数组,它并不会创建一个列,而是设置一个外键约束:

create_table(:artists) do
  String :name
  String :location
  primary_key [:name, :location]
end
create_table(:albums) do
  String :artist_name
  String :artist_location
  String :name
  foreign_key [:artist_name, :artist_location], :artists
end

index(索引)

index为数据表创建索引。对单一列来说,调用index方法和在创建列时使用:index选项的效果一样:

create_table(:a){Integer :id, :index=>true}
# Same as:
create_table(:a) do
  Integer :id
  index :id
end
create_table(:a){Integer :id, :index=>{:unique=>true}}
# Same as:
create_table(:a) do
  Integer :id
  index :id, :unique=>true
end

primary_keyforeign_key方法类似,调用index方法并提供一个符号数组会创建一个多列索引:

create_table(:albums) do
  primary_key :id
  foreign_key :artist_id, :artists
  Integer :position
  index [:artist_id, :position]
end

index方法同样能接受一些可选项:

选项 说明
:name 索引名(如果未提供则根据表名和列名生成)
:type 索引使用的数据类型(部分数据库支持)
:unique 使索引唯一,不允许出现重复的值。
:where 创建一个局部索引(部分数据库支持)

unique(唯一索引)

unique方法为数据表创建一个唯一约束。通常情况下,唯一约束和唯一索引运行起来是一样的。因此下面三个create_table语句块的效果实际上是一样的:

create_table(:a){Integer :a, :unique=>true}
create_table(:a) do
  Integer :a
  index :a, :unique=>true
end

create_table(:a) do
  Integer :a
  unique :a
end

index类似,unique方法可以设置一个多列唯一索引。多列唯一索引可以确保索引列中每个值组合都是唯一的:

create_table(:a) do
  Integer :a
  Integer :b
  unique [:a, :b]
end

full_text_index and spatial_index(全文索引和局部索引)

只有部分数据库支持这两个能创建特殊索引类型的方法。它们和index有一样的可选项。

constraint(约束)

constraint方法会创建一个命名的表约束:

create_table(:artists) do
  primary_key :id
  String :name
  constraint(:name_min_length){char_length(name) > 2}
end

不使用语句块,你还可以使用类似Dataset#where作为方法的参数达到同样效果:

create_table(:artists) do
  primary_key :id
  String :name
  constraint(:name_length_range, Sequel.function(:char_length, :name)=>3..50)
end

check(check约束)

check运行起来和constraint很像,但是它没有名字,其创建的是一个未命名的约束:

create_table(:artists) do
  primary_key :id
  String :name
  check{char_length(name) > 2}
end

create_join_table(创建连接表)

create_join_table是一种快速地创建简单的多对多关系的连接表的方式:

create_join_table(:artist_id=>:artists, :album_id=>:albums)

上面的语句如果扩展开会是这样:

create_table(:albums_artists) do
  foreign_key :album_id, :albums, :null=>false
  foreign_key :artist_id, :artists, :null=>false
  primary_key [:album_id, :artist_id]
  index [:artist_id, :album_id]
end

create_table :as=>(创建表,带:as=>参数)

SELECT查询的结果创建表时,不给create_table传一个语句块进去,而是提供一个数据集给:as选项:

create_table(:older_items, :as=>DB[:items].where{updated_at < Date.today << 6})

alter_table(修改表)

alter_table被用来修改已存在的表。它能够修改表的列、索引、约束。就像使用create_table一样,它接受一个instance_evaled的语句块,并且有其自己的方法:

add_column(增加列)

最常用的方法之一,add_column用来给表增加列。这个API和create_table的column方法很像。它的第1个参数是列名,第2个参数是列数据类型,第3个参数是一个可选的hash:

alter_table(:albums) do
  add_column :copies_sold, Integer, :default=>0
end

drop_column(丢弃列)

正如你期望的一样,drop_column带一个参数,以此参数为列名的列会被丢弃。这个方法常常用在一个迁移的down块中,用来丢弃在up块中被添加的列:

alter_table(:albums) do
  drop_column :copies_sold
end

rename_column(重命名列)

rename_column用来重命名列。第1个参数是旧列名,第2个参数是新列名:

alter_table(:albums) do
  rename_column :copies_sold, :total_sales
end

add_primary_key(添加主键)

如果你忘了给表添加一个主键,现在想加上,那你可以用add_primary_key方法。这通常用来在真实模型中为关联表添加多对多关系:

alter_table(:albums_artists) do
  add_primary_key :id
end

就像create_tableprimary_key方法一样,如果你提供一个符号数组,Sequel不会添加一列,而是添加一个复合主键约束:

alter_table(:albums_artists) do
  add_primary_key [:album_id, :artist_id]
end

如果仅仅是想把一个已经存在的单列变成主键,那么调用add_primary_key时就给它一个只包含一个符号的数组:

alter_table(:artists) do
  add_primary_key [:id]
end

add_foreign_key(添加外键)

add_foreign_key用来给表添加新的外键列或外键约束。类似add_primary_key,如果用一个符号作为第1个参数,该方法会创建一个新列:

alter_table(:albums) do
  add_foreign_key :artist_id, :artists
end

如果想给一个已经存在的列添加外键约束,就提供给它一个只包含一个元素的数组:

alter_table(:albums) do
  add_foreign_key [:artist_id], :artists
end

提供一个包含多列列名的符号的数组能够设置一个多列外键约束:

alter_table(:albums) do
  add_foreign_key [:artist_name, :artist_location], :artists
end

add_index(添加索引)

create_tableindex方法类似,add_index会给表创建新的索引:

alter_table(:albums) do
  add_index :artist_id
end

该方法接受和create_tableindex方法一样的选项,用数组能创建多列索引:

alter_table(:albums_artists) do
  add_index [:album_id, :artist_id], :unique=>true
end

drop_index(丢弃索引)

drop_index会丢弃一个已存在的索引:

alter_table(:albums) do
  drop_index :artist_id
end

drop_column一样,该方法通常会出现在迁移的down块中。

:name选项能丢弃指定名字的索引:

alter_table(:albums) do
  drop_index :artist_id, :name=>:artists_id_index
end

add_full_text_index, add_spatial_index(添加全文索引/添加局部索引)

create_tablefull_text_indexspatial_index方法一样,这两个方法会为表创建相应的索引。

add_constraint(添加约束)

create_tableconstraint方法类似,这会为表添加一个命名的约束:

alter_table(:albums) do
  add_constraint(:name_min_length){char_length(name) > 2}
end

注意,没有专门用来添加未命名约束的方法,不过你可以将nil作为add_constraint的第1个参数来达到相同的目的。当然,我们并不推荐这么做,因为删除未命名的约束是很困难的。

add_unique_constraint(添加唯一约束)

create_tableunique方法一样,为表添加唯一约束。

alter_table(:albums) do
  add_unique_constraint [:artist_id, :name]
end

drop_constraint(丢弃约束)

丢弃一个已命名的约束:

alter_table(:albums) do
  drop_constraint(:name_min_length)
end

没有单独的丢弃未命名约束的方法。通常,数据库会自动给未命名约束一个名字,你要做的就是找出这个名字。因此你不应该让一个你将来可能会丢弃的约束成为未命名约束。

有些数据库可能还要求你必须指定约束的类型,这可以通过:type选项来完成:

alter_table(:albums) do
  drop_constraint(:albums_pk, :type=>:primary_key)
  drop_constraint(:albums_fk, :type=>:foreign_key)
  drop_constraint(:albums_uk, :type=>:unique)
end

set_column_default(设置列的默认值)

该方法会改变指定列的默认值:

alter_table(:albums) do
  set_column_default :copies_sold, 0
end

set_column_type(设置列的数据类型)

该方法会改变列的数据类型,大多数数据库会尝试自动转换已经存在的数据值到新的类型:

alter_table(:albums) do
  set_column_type :copies_sold, Bignum
end

你可以用字符串或符号指定类型,这时会按字面指定数据类型。或者使用被支持的ruby类型,这是会转为恰当的数据库数据类型。

set_column_allow_null(设置列允许空值)

该方法改变列是否允许空值:

alter_table(:albums) do
  set_column_allow_null :artist_id, true    # NULL
  set_column_allow_null :copies_sold, false # NOT NULL
end

其他修改数据库模式的方法

Sequel::Database有很多关于模式修改的实例方法,其中大多数是与alter_table中的方法作用类似的“快捷方法”。下面列出的Database的实例方法其实只是调用了alter_table中的同名函数,并将表名作为第1个参数,其余参数放在表名之后:

  • add_column
  • drop_column
  • rename_column
  • add_index
  • drop_index
  • set_column_default
  • set_column_type

举例来说,下面两个方法执行效果相同:

alter_table(:artists){add_column :copies_sold, Integer}
add_column :artists, :copies_sold, Integer

还有一些不和alter_table类似的模式修改方法:

drop_table

drop_table可以带很多参数,它将这些参数都视为表名,这些表将被丢弃:

drop_table(:albums_artists, :albums, :artists)

注意,如果你使用了外键,而数据库要确保引用完整性,这时要按特定的顺序丢弃这些表。通常你要先丢弃包含外键的表,然后再丢弃被这些表引用主键的表。

drop_table?

drop_table类似,但仅当表不存在时drop_table?才会丢弃表。有些数据库会使用IF NOT EXISTS检测表是否存在,其他的数据库则使用单独的查询语句来检测。
不要在迁移中使用该方法,如果该表不存在,这样做会破坏迁移。

rename_table

你可以使用rename_table重命名一个表。类似rename_column,第1个参数是当前名,第2个参数是新名:

rename_table(:artist, :artists)

create_table!

create_table!在创建表之前会试图丢弃已存在的同名表,因此:

create_table!(:artists) do
  primary_key :id
end

和下载的代码作用一样:

drop_table?(:artists)
create_table(:artists) do
  primary_key :id
end

不要在迁移中使用该方法,如果该表不存在,这样做会破坏迁移。

create_table?

create_table?仅仅当表不存在时才会将其创建,因此:

create_table?(:artists) do
  primary_key :id
end

和下面的代码作用一样:

unless table_exists?(:artists)
  create_table(:artists) do
    primary_key :id
  end
end

create_table!一样,它不能被用在迁移里。

create_view 和 create_or_replace_view(创建视图/创建或替换视图)

该组方法用来创建视图。两者的区别是create_or_replace_view会无条件地替换已存在的同名视图。而create_view则会抛出一个错误。两个方法接受同样的参数,第1个参数是视图名,第2个参数是一个字符串或者一个数据集:

create_view(:gold_albums, DB[:albums].where{copies_sold > 500000})
create_or_replace_view(:gold_albums, "SELECT * FROM albums WHERE copies_sold > 500000")

drop_view(删除视图)

drop_view删除一个已存在的视图。和drop_table类似,它可以接受多参数:

drop_view(:gold_albums, :platinum_albums)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容