2011-06-18 18 views
3

私はデータベースの多くのテーブルのコードを生成したいので、私の3番目の実装である "テーブルXのコードを取得する"を書く準備ができたら、複数のテーブルのコードを動的に生成するPostgreSQLのトリガー

私のコードはこれです:私はNEW.tenant_code、NEW.user_codeまたはNEW.table_whatever_codeに割り当てるにはどうすればよい

-- Tenants receive a code that's composed of a portion of their subdomain and a unique number. 
-- This number comes from this sequence. 
CREATE SEQUENCE tenant_codes_seq MAXVALUE 9999 NO CYCLE; 

CREATE TABLE tenants (
    subdomain varchar(36) NOT NULL UNIQUE 
    , tenant_code char(8)  NOT NULL UNIQUE 
    , PRIMARY KEY (tenant_code) 
); 

-- This function expects four parameters: 
-- 1. The column that's receiving the generated code (RECEIVING_COLUMN_NAME) 
-- 2. The column that's used to salt the code (SALT_COLUMN_NAME) 
-- 3. The number of characters to use from the salt column (SALT_LENGTH) 
-- 4. The sequence name, but defaults to RECEIVING_COLUMN_NAME || 's' 
CREATE OR REPLACE FUNCTION generate_table_code() RETURNS trigger AS $$ 
DECLARE 
    receiving_column_name text; 
    salt_column_name  text; 
    salt_length   text; 
    sequence_name   text; 
BEGIN 
    receiving_column_name := TG_ARGV[0]; 
    salt_column_name  := TG_ARGV[1]; 
    salt_length   := TG_ARGV[2]; 

    CASE 
    WHEN TG_NARGS = 3 THEN 
    sequence_name := receiving_column_name || 's'; 
    WHEN TG_NARGS = 4 THEN 
    sequence_name := TG_ARGV[3]; 
    ELSE 
    RAISE EXCEPTION '3 or 4 arguments expected, received %', TG_NARGS; 
    END CASE; 

    -- The intent is to return ABC-0001 when salt_column contains 'ABC' 
    EXECUTE 'rpad(substr('    || 
      quote_ident(salt_column_name) || 
      ', 1, 4), 4, '    || 
      quote_literal('-')   || 
      ') || lpad(nextval('   || 
      quote_literal(sequence_name) || 
      ')::text, '     || 
      quote_literal(salt_length) || 
      ', '       || 
      quote_literal('0')   || 
      ')' 
    INTO STRICT NEW; 
    RETURN NEW; 
END 
$$ LANGUAGE plpgsql; 

CREATE TRIGGER generate_tenant_code_trig 
    BEFORE INSERT ON tenants FOR EACH ROW 
    EXECUTE PROCEDURE generate_table_code('tenant_code', 'subdomain', 4); 

? 、

INSERT INTO tenants(subdomain) VALUES ('abc') 


CREATE TABLE 
ERROR: syntax error at or near "NEW" 
LINE 1: NEW.tenant_code := rpad(substr(subdomain, 1, 4), 4, '-') || ... 
     ^
QUERY: NEW.tenant_code := rpad(substr(subdomain, 1, 4), 4, '-') || lpad(nextval('tenant_codes')::text, '4', '0'::text) 
CONTEXT: PL/pgSQL function "generate_table_code" line 20 at EXECUTE statement 

答えて

4

私が間違って表示されるのは非常に熱心になるだろう(私は時々あまりにもこれを自分自身を必要とする):いくつかのテストを実行する

は正しい「文」を得たが、私は正しく割り当てるように見えることはできませんただし、変数を使用して列名を参照することは、PL/PgSQLトリガーではなくPL/Cトリガーを実際に使用する必要があるケースの1つです。このようなトリガーの例は、contrib/spiおよびPGXNにあります。

また、列に一貫して名前を付けて、列を直接参照できるようにすることもできます。 NEW.tenant_code

個人的に、私は一般的にトリガを作成する関数を書いて終わる:

create function create_tg_stuff(_table regclass, _args[] text[]) 
    returns void as $$ 
begin 
    -- explore pg_catalog a bit 
    execute $x$ 
    create function $x$ || quote_ident(_table || '_tg_stuff') || $x$() 
    returns trigger as $t$ 
    begin 
    -- more stuff 
    return new; 
    end; 
    $t$ language plpgsql; 
    $x$; 
end; 
$$ language plpgsql; 
+0

ありがとう、それはPostgreSQL自体ではなくRuby/ERBを除いて私がやっていることです。 –

0

NEWあなたはその私の知る限りに割り当てることができませんので、RECORDを入力しています。

は、たとえば、 NEW.columnに割り当て、列の値を設定するには:
NEW.tenant_code := (SELECT some_calculation); 

はたぶんあなたのデザインがあまりにも複雑である

。 PL/SQLは非常に限定された言語です - できるだけシンプルにコードを作成してください

関連する問題