当操作在更新中获得 0 或更少时,Postgresql 引发异常

Postgresql RAISE EXCEPTION when operation get 0 or less in Update

我有三个表:

    CREATE TABLE public.art_movimientos
    (
      cmovimiento bigint NOT NULL DEFAULT nextval('art_movimientos_cmovimiento_seq'::regclass),
      tipo character varying(3) NOT NULL, -- Tipos de Valores:...
      fecha_mov timestamp without time zone NOT NULL,
      documento integer NOT NULL,
      control integer,
      fecha_doc timestamp without time zone NOT NULL,
      corden integer NOT NULL DEFAULT 0,
      calmacen integer NOT NULL,
      calmacen2 integer,
      status character varying(13) NOT NULL DEFAULT 'PENDIENTE'::bpchar, -- PENDIENTE...
      donado integer NOT NULL DEFAULT 0,
      monto_mov numeric(11,2) NOT NULL DEFAULT 0.00,
      monto_desc numeric(11,2) NOT NULL DEFAULT 0.00,
      monto_total numeric(11,2) NOT NULL DEFAULT 0.00,
      observacion text,
      casiento integer,
      crea_user character varying(25),
      crea_date timestamp without time zone,
      mod_user character varying(25),
      mod_date timestamp without time zone,
      cproveedor integer NOT NULL DEFAULT 0
    )
CREATE TABLE public.art_movimientos_det
(
  cmovimiento_det bigint NOT NULL DEFAULT nextval('art_movimientos_det_cmovimiento_det_seq'::regclass),
  cmovimiento integer NOT NULL,
  cart_generico integer NOT NULL,
  cunidad integer NOT NULL DEFAULT 1,
  cant numeric(11,2) NOT NULL DEFAULT 0.00,
  iva numeric(11,2) NOT NULL DEFAULT 0.00,
  costou numeric(11,2) NOT NULL DEFAULT 0.00,
  crea_user character varying(25),
  crea_date timestamp without time zone,
  mod_user character varying(25),
  mod_date timestamp without time zone,
  cart_comercial integer NOT NULL,
  costot numeric(11,2) NOT NULL DEFAULT 0.00
)
CREATE TABLE public.ordencompra_det
(
  corden_det bigint NOT NULL DEFAULT nextval('ordencompra_det_corden_det_seq'::regclass),
  corden integer NOT NULL,
  cart_comercial integer NOT NULL,
  cunidad integer NOT NULL DEFAULT 1,
  cant numeric(11,2) NOT NULL DEFAULT 0.00,
  costou numeric(11,2) NOT NULL DEFAULT 0.00,
  iva numeric(11,0) NOT NULL DEFAULT 0.00,
  costot numeric(11,2) NOT NULL DEFAULT 0.00,
  crea_user character varying(25),
  crea_date timestamp without time zone,
  mod_user character varying(25),
  mod_date timestamp without time zone,
  cant_restante numeric(11,2) NOT NULL DEFAULT 0
)

我有一个程序可以减少 ordencompra_det 中的 cant_restante:

UPDATE ordencompra_det AS od
        SET cant_restante = cant_restante - s.cant_real
        FROM (SELECT am.corden, md.cart_comercial,(md.cant*u.multiplicador)cant_real FROM art_movimientos am INNER JOIN art_movimientos_det md ON am.cmovimiento=md.cmovimiento INNER JOIN art_und u ON md.cunidad=u.cunidad WHERE md.cmovimiento=cmov) AS s
        WHERE od.corden=s.corden and od.cart_comercial=s.cart_comercial

但有时我在 cant_restante 中得到 0 或更少,如果更新结果低于 0,我该如何检查?我不想有负值“/,如果我得到负值,回滚更新并引发异常?

我正在为此使用 postgresql 函数(过程)(因为我在数据库中做了很多事情)

还有更多的可能性:

  • 使用table约束:

    CREATE TABLE ordencompra_det(
      ...
      cant_restante numeric(11,2) NOT NULL DEFAULT 0 CHECK(can_restante >= 0),
      ...
    )
    
  • 使用校验函数:

    CREATE OR REPLACE FUNCTION only_positive(numeric)
    RETURNS numeric AS $$
    BEGIN
      IF  < 0 THEN
        RAISE EXCEPTION '%s is not positive', ;
      END IF;
      RETURN ;
    END;
    $$ LANGUAGE plpgsql IMMUTABLE STRICT;
    

    更新ordencompra_det SET cant_restante = only_positive(cant_restante - s.cant_real) ...

首选第一种方式