Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails行为异常wrt Postgres SERIAL NOT NULL列_Ruby On Rails_Postgresql_Ruby On Rails 3_Plpgsql - Fatal编程技术网

Ruby on rails Rails行为异常wrt Postgres SERIAL NOT NULL列

Ruby on rails Rails行为异常wrt Postgres SERIAL NOT NULL列,ruby-on-rails,postgresql,ruby-on-rails-3,plpgsql,Ruby On Rails,Postgresql,Ruby On Rails 3,Plpgsql,我正在开发一个(目前)Rails 2.3.x应用程序,它有一个PostgreSQL 8.4数据库后端。在我的Rails应用程序中,我有一个与数据库表相对应的模型,该数据库表有两列数据类型SERIAL,并设置为NOTNULL。我将其中一列设置为Rails中的主键和PostgreSQL约束 表定义: CREATE TABLE problem_table ( col1 serial NOT NULL, col2 serial NOT NULL, other_col1 character v

我正在开发一个(目前)Rails 2.3.x应用程序,它有一个PostgreSQL 8.4数据库后端。在我的Rails应用程序中,我有一个与数据库表相对应的模型,该数据库表有两列数据类型SERIAL,并设置为NOTNULL。我将其中一列设置为Rails中的主键和PostgreSQL约束

表定义:

CREATE TABLE problem_table
(
  col1 serial NOT NULL,
  col2 serial NOT NULL,
  other_col1 character varying,
  other_col2 character varying,
  ...,
  CONSTRAINT problem_table_pkey PRIMARY KEY (col1)
);
class ModelClass1 < ActiveRecord::Base
  self.table_name = 'problem_table'
  self.primary_key = 'col1'
end
模型类定义:

CREATE TABLE problem_table
(
  col1 serial NOT NULL,
  col2 serial NOT NULL,
  other_col1 character varying,
  other_col2 character varying,
  ...,
  CONSTRAINT problem_table_pkey PRIMARY KEY (col1)
);
class ModelClass1 < ActiveRecord::Base
  self.table_name = 'problem_table'
  self.primary_key = 'col1'
end
Rails告诉PostgreSQL的是:

INSERT INTO problem_table (
  col2, 
  other_col1, 
  other_col2,
  ...
) VALUES (
  NULL,
  'normal',
  'data',
  ...
);
我的问题是,如何让Rails停止为此列传递NULL而不传递任何内容,让默认的nextval(My_seq)接管?或者,如果不可能,我如何告诉PostgreSQL在传递时忽略此空值和/或识别此空值与“设为默认值”相同

我会尝试对Rails 2.3.x ActiveRecord内部进行修补,但我知道如果我这样做了,那么在过渡到Rails 3时,我会被搞砸

我已经研究过如何在插入之前使用PL/pgSQL触发器修复问题,但我不知道如何让带有PL/pgSQL的PostgreSQL“取消定义”NEW.col2值或说NEW.col2:=DEFAULT(这不起作用)


感谢您的回答和/或建议

不确定PL/pgSQL语法的精确性(我的PostgreSQL安装在家里,所以我不能玩弄它),但在Oracle PL/SQL中,我会这样做

CREATE OR REPLACE TRIGGER MYSCHEMA.PROBLEM_TABLE_BI
  BEFORE INSERT ON MYSCHEMA.PROBLEM_TABLE
  REFERENCING NEW AS NEW
  FOR EACH ROW
BEGIN
  IF :NEW.COL2 IS NULL THEN
    :NEW.COL2 := MY_SEQ.NEXT_VAL;
  END IF;
END PROBLEM_TABLE_BI;
PL/pgSQL应该是类似的


希望这有帮助。

找到了一些有效的方法。我可能需要在相当多的表中使用第二个串行列,这些表使用不同的递增序列。下面是一个解决方案,其中包含按唯一序列递增的col1的任意数量的表只需要1个触发器函数

CREATE OR REPLACE FUNCTION fn_set_col1_as_nextval_sequence_if_null()
  RETURNS trigger AS
$BODY$
  BEGIN
    IF NEW.col1 IS NULL THEN
      SELECT nextval(TG_ARGV[0]) INTO NEW.col1;
    END IF;
    RETURN NEW;
  END;
$BODY$
  LANGUAGE 'plpgsql';

CREATE TRIGGER trg_set_col1_as_nextval_sequence_on_problem_table_create
BEFORE INSERT
ON problem_table
FOR EACH ROW
EXECUTE PROCEDURE fn_set_col1_as_nextval_sequence_if_null('problem_table_col1_seq');

如果可能的话,我仍然想弄清楚如何修复2.3.x和3.0的Rails行为,但这将同时起作用。

更简单的方法可能是定义自己的序列,并在ActiveRecord回调中使用Postgres自己的
nextval()
nextval()
在一个原子操作中处理将序列向前推进一步和返回下一个值

在迁移过程中:

def self.up
    execute "CREATE SEQUENCE myseq"
end

def self.down
    execute "DROP SEQUENCE myseq"
end    
在模型中:

before_save :set_column_from_sequence, :on => :create

def set_column_from_sequence
    self.mycolumn = self.class.connection.select_value("SELECT nextval('myseq')")
end

谢谢我现在有了一个基于这个策略的东西@克里斯戈达德——这就是生活。:-}谢谢你!rails 2.3到3.1升级期间的巨大帮助