序列“setval”操作与Rails 3.2.16中的Postgres的“nextval”不同

时间:2014-01-15 19:44:24

标签: ruby-on-rails-3 postgresql pg

我有一个模型,可以使用pg gem将数据直接加载到数据库。它通过动态创建CSV文件并通过调用以下内容将值分配给id字段来实现此目的:

self.class.select("nextval('apps_id_seq'::regclass)").first['nextval']

to_csv实例方法中。

这在生产中很有效。但是,我正在填写一些测试,如果这个测试首先运行,或者单独运行,它会失败,因为数据库刚刚被Database Cleaner gem重置,并且序列被重置。但它们没有起始值。

Postgres文档说您可以在相关序列上调用setval来设置它。所以,假设我想将其设置为从1开始,以便下次调用nextval时,它将返回1:

select setval('apps_id_seq'::regclass, 1, false);

但是我不能像上面调用nextval一样调用它,因为它只是简单的不起作用。它返回nil,并且不设置序列。

我尝试的任何迭代都没有:

self.class.select("setval('apps_id_seq'::regclass)").first
App.connection.execute("select setval('apps_id_seq'::regclass,1,false)")
ActiveRecord::Base.connection.execute("select setval('apps_id_seq'::regclass,1)")
ActiveRecord::Base.connection.execute("select setval('apps_id_seq'::regclass,1,false)")
ActiveRecord::Base.connection.execute("select setval('apps_id_seq'::regclass,1,false)")

也没有任何组合起作用,只需refuses即可。我不知道这是否是pg宝石问题。

更新

这些陈述适用于development模式:

App.select("setval('apps_id_seq'::regclass,1)").first

App.select("nextval('apps_id_seq'::regclass)").first

然而,它们都不适用于test

但是,这些陈述在test模式下有效:

ActiveRecord::Base.connection.execute("select setval('apps_id_seq'::regclass,1,false)").first

ActiveRecord::Base.connection.execute("select nextval('apps_id_seq'::regclass)").first

据我所知,两种环境中的唯一区别是,一个人拥有数据,而另一个人没有。我的测试数据库是使用rake db:test:prepare文件中的structure.sql创建的。

1 个答案:

答案 0 :(得分:2)

setvalnextval无论表中是否附有序列附加数据都可以使用。可以创建并递增序列,甚至不与现有表的列相关联。当您使用Model.select执行原始SQL时,ActiveRecord会为您正在使用的模型表生成带有from子句的SQL:

> App.select("setval('apps_id_seq'::regclass,1)").first

  SELECT nextval('apps_id_seq'::regclass)
  FROM "apps" ORDER BY "apps"."id" ASC LIMIT 1'

=> nil

由于apps表中没有记录,因此永远不会执行setval函数。这就是为什么同一个select在直接使用连接时有效,因为select没有多余的from子句:

> ActiveRecord::Base.connection.execute("SELECT setval('apps_id_seq'::regclass, 1)").first

  SELECT setval('apps_id_seq'::regclass, 1)

=> {"setval"=>"1"}

使用此表单执行SQL,以确保始终评估setval函数。