2017-01-27 7 views
0

私は記事の使用に関するすべての情報を入れたいテーブルを持っていて、autoincrementを持つ列を作成する必要があります。IDは同じ値フィールド(tipo)に別の値がある場合は、この特定の場合に一意ですID。たとえば:別の列の値に応じて増加する列を作成する方法

ID/TIPO 
1 / AJE -- Is Ok 
1 / AJS -- Is Ok (because this Tipo is AJS, different from AJE) 
1 / SI -- Is Ok 
2 / AJE -- Is Ok (New ID) 
2 / AJE -- Is Wrong, because ID=2, TIPO=AJE already exist. 

は私が独自の文やった:

ALTER TABLE public.art_movimientos 
ADD CONSTRAINT uk_mov UNIQUE (id,tipo) USING INDEX TABLESPACE sistema_index; 

をしかし、どのように、私は2つの列をカバーする自動インクリメントを作成することができますか?

私のテーブルコード:

CREATE TABLE public.art_movimientos 
(
    id integer NOT NULL DEFAULT nextval('seq_art_movimientos'::regclass), 
    tipo character(3) NOT NULL, -- Tipos de Valores:... 
    documento integer, 
    fecha_doc date[] NOT NULL, 
    fecha_mov date[] NOT NULL, 
    calmacen integer NOT NULL, 
    status character(13) NOT NULL DEFAULT 'PENDIENTE'::bpchar, -- PENDIENTE... 
    mes integer NOT NULL, 
    "año" integer NOT NULL, 
    donado integer NOT NULL DEFAULT 0 
) 
WITH (
    OIDS=FALSE 
); 
+1

「しない」と同じですか?シリアル番号は、PKの値がこの場合のテーブルの内容に依存しない場合に便利です。あなたはおそらく 'INSERT INTO art_movimientos SELECT max(id)+ 1、tipo、...よりartmovimientosどこのtipo = '...''より良いでしょう。 – dhke

答えて

1

あなたは行動statedbyの@dhke模倣、挿入トリガー前を使用することによって、この状況を管理することができます

CREATE TABLE art_movimientos 
(
    id integer NOT NULL DEFAULT NULL, -- You don't want a serial, nor a default 
    tipo character(3) NOT NULL, -- Tipos de Valores:... 
    documento integer, 
    fecha_doc date[] NOT NULL, 
    fecha_mov date[] NOT NULL, 
    calmacen integer NOT NULL, 
    status character(13) NOT NULL DEFAULT 'PENDIENTE'::bpchar, -- PENDIENTE... 
    mes integer NOT NULL, 
    "año" integer NOT NULL, 
    donado integer NOT NULL DEFAULT 0, 

    /* You have actually a 2-column Primary Key */ 
    PRIMARY KEY (tipo, id) 

を)。

-- Create a trigger function to generate 'id' 
CREATE FUNCTION art_movimientos_insert_trigger() 
    RETURNS trigger 
AS 
$$ 
BEGIN 
    /* Compute "id", as the following id for a certain "tipo" */ 
    new.id = coalesce( 
        (SELECT max(id) + 1 
        FROM art_movimientos a 
        WHERE a.tipo = new.tipo), 1); 
    return new; 
END 
$$ 
    LANGUAGE 'plpgsql' 
    VOLATILE ; 

-- This trigger will be called whenever a new row is inserted, and "id" is 
-- not specified (i.e.: it defaults to null), or is specified as null 
CREATE TRIGGER art_movimientos_ins_trg 
    BEFORE INSERT 
    ON art_movimientos 
    FOR EACH ROW 
    WHEN (new.id IS NULL) 
    EXECUTE PROCEDURE art_movimientos_insert_trigger(); 

その後、次の行(id列を指定なし)挿入することができます。

INSERT INTO art_movimientos 
    (tipo, documento, fecha_doc, fecha_mov, calmacen, mes, "año") 
VALUES 
    ('AJE', 1, array['20170128'::date], array['20170128'::date], 1, 1, 2017), 
    ('AJS', 2, array['20170128'::date], array['20170128'::date], 1, 1, 2017), 
    ('SI', 3, array['20170128'::date], array['20170128'::date], 1, 1, 2017), 
    ('AJE', 4, array['20170128'::date], array['20170128'::date], 1, 1, 2017), 
    ('AJE', 5, array['20170128'::date], array['20170128'::date], 1, 1, 2017) ; 

を...そして、あなたが意図したものを手に入れることを参照してください。

SELECT 
    id, tipo 
FROM 
    art_movimientos 
ORDER BY 
    documento ; 


| id | tipo | 
|----|------| 
| 1 | AJE | 
| 1 | AJS | 
| 1 | SI | 
| 2 | AJE | 
| 3 | AJE | 

SQLFiddle(PL/pgSQLの機能とセミコロンについて少し気をつけています)をすべて確認できます。


サイドノート:この手順は、トランザクション内で失敗する可能性がありますいくつかのコーナーケースが存在する可能性があるためのデッドロックおよび/またはレースコンディション、他のトランザクションも同じにデータを挿入している場合同時にテーブル。したがって、全体的なコードは、中止されたトランザクションを処理し、再試行したり、エラーをユーザーに表示したりすることができます。

+0

bigserialフィールドを使用し、プライマリキーのみを設定することをお勧めしますか? – JuJoGuAl

+1

通常は簡単ですが、1つの行に1つの*キー*を与えます。ちょうど、AJE123という行があります(これは*最後の*になります)、削除して新しい行を挿入することができます。それは再びAJE123を得るでしょう。 2つの異なるものについて同じ* id * =が問題につながります。 – joanolo

+0

Thxたくさんの男、本当に私を助けてください。 – JuJoGuAl

関連する問題