sql >> データベース >  >> RDS >> PostgreSQL

自己管理型PostgreSQLパーティションテーブル

    double precisionを混合しています date_part() の出力 text '-' 。それはPostgreSQLには意味がありません。 textへの明示的なキャストが必要になります 。しかし、これをすべて行うにはもっと簡単な方法があります:

    startdate:=date_part('year',to_timestamp(NEW.date))
    ||'-'||date_part('month',to_timestamp(NEW.date))
    ||'-'||date_part('day',to_timestamp(NEW.date));

    代わりに使用してください:

    startdate := to_char(NEW.date, 'YYYY-MM-DD');
    

    これも意味がありません:

    EXECUTE 'CREATE TABLE $1 (
            CHECK (date >= DATE $2 AND date < DATE $3 )
        ) INHERITS (pings)' USING quote_ident(tablename),startdate,enddate;

    USINGでのみ値を指定できます 句。 こちらのマニュアルをお読みください> 。代わりに試してください:

    EXECUTE 'CREATE TABLE ' || quote_ident(tablename) || ' (
                CHECK ("date" >= ''' || startdate || ''' AND
                       "date" <  ''' || enddate   || '''))
                INHERITS (ping)';
    

    または、format() 。以下を参照してください。

    また、@a_horse回答 のように :テキスト値は一重引用符で囲む必要があります。

    ここに似ています:

    EXECUTE 'INSERT INTO $1 VALUES (NEW.*)' USING quote_ident(tablename);

    代わりに:

    EXECUTE 'INSERT INTO ' || quote_ident(tablename) || ' VALUES ($1.*)'
    USING NEW;
    

    関連する回答:

    余談ですが、PostgreSQLでは列名に「日付」が許可されていますが、これはすべてのSQL標準で予約語 。列に「日付」という名前を付けないでください。混乱を招く構文エラーが発生します。

    完全な作業デモ

    CREATE TABLE ping (ping_id integer, the_date date);
    
    CREATE OR REPLACE FUNCTION trg_ping_partition()
      RETURNS trigger AS
    $func$
    DECLARE
       _tbl text := to_char(NEW.the_date, '"ping_"YYYY_DDD_') || NEW.ping_id;
    BEGIN
       IF NOT EXISTS (
          SELECT 1
          FROM   pg_catalog.pg_class c
          JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
          WHERE  n.nspname = 'public'  -- your schema
          AND    c.relname = _tbl
          AND    c.relkind = 'r') THEN
    
          EXECUTE format('CREATE TABLE %I (CHECK (the_date >= %L AND
                                                  the_date <  %L)) INHERITS (ping)'
                  , _tbl
                  , to_char(NEW.the_date,     'YYYY-MM-DD')
                  , to_char(NEW.the_date + 1, 'YYYY-MM-DD')
                  );
       END IF;
    
       EXECUTE 'INSERT INTO ' || quote_ident(_tbl) || ' VALUES ($1.*)'
       USING NEW; 
    
       RETURN NULL;
    END
    $func$ LANGUAGE plpgsql SET search_path = public;
    
    CREATE TRIGGER insbef
    BEFORE INSERT ON ping
    FOR EACH ROW EXECUTE PROCEDURE trg_ping_partition();
    
    • 更新: Postgresの新しいバージョンには、テーブルが存在するかどうかを確認するためのより洗練された方法があります。

    • to_char() dateを取ることができます $1として 。これはtimestampに変換されます 自動的に。
      日付/時刻機能に関するマニュアル 。

    • (オプション) SET search_path 変更されたsearch_pathによる不正行為を回避するための関数のスコープ 設定。

    • 他の複数の簡素化と改善。コードを比較してください。

    テスト:

    INSERT INTO ping VALUES (1, now()::date);
    INSERT INTO ping VALUES (2, now()::date);
    INSERT INTO ping VALUES (2, now()::date + 1);
    INSERT INTO ping VALUES (2, now()::date + 1);
    

    SQLフィドル。



    1. Oracle SQL Developerで外部キーを作成する方法は?

    2. 文字列の先頭から数字や特殊文字を削除するにはどうすればよいですか?

    3. Javaを使用するときにMySQLでテーブルを作成する方法

    4. MyISAMをInnoDBに変換します。有益?結果?