On Fri, Mar 18, 2016 at 7:08 AM, Sándor Daku <daku.san...@gmail.com> wrote:

>
> On 18 March 2016 at 10:55, Leonardo M. Ramé <l.r...@griensu.com> wrote:
>
>> Hi, I have read and re-read the Partitioning chapter (
>> http://www.postgresql.org/docs/9.1/static/ddl-partitioning.html), but I
>> still don't see how to implement this use case:
>>
>> One table storing current data, let's call it the "master table", then
>> one or more partitions with old data.
>>
>> For example, the master table is this:
>>
>>     create table log(
>>       idlog serial not null,
>>       date_time timestamp not null default now(),
>>       log varchar(255),
>>       primary key(idlog)
>>     );
>>
>> The documentation says the master table should be empty, then a trigger
>> must evaluate a condition, the date_time field for example, and insert the
>> data in the corresponding table. This is a *rare* condition, because in the
>> log example, new content is created without knowing its date and time in
>> advance. For example:
>>
>>     insert into log(log) values('log this please.');
>>
>> The date_time column will set the now() value.
>>
>> Now, by following the example, to create a child table I'll do
>>
>>     create table log_old( ) inherits (log);
>>
>> This raises the 1nst question, how can I define a *dynamic* check,
>> for checking older than X days?. Is this possible?.
>>
>> An idea (didn't test):
>>
>>     check (date_time::date < now()::date - '30 day'::interval)
>>
>> Then, the trigger, after each insert should *move* old data to log_old.
>>
>> The only problem I see here is the master table isn't empty, but contains
>> current data. The question is, will it work as expected?, I mean when I do
>> "select * from log" I'll get an *union* of new and old data?.
>>
>>
> I'm quite(but not completely) sure the dynamic constraint won't work.
> Also the log data - I guess - will be actual so nothing goes to the _old
> table, except you keep nudging the records and use an update trigger to
> move the data around.
> Oh, and you should keep the parent table empty.
> The correct way would be to define fixed date ranges for the child tables
> and keep adding new ones as time advances.(And dropping old ones if you
> want.)
> log ->parent
> log_201603 -> child of log, check date_time>'2016.03.01' and
> date_time<='2016.04.01'
> log_201604 -> child of log, check date_time>'2016.04.01' and
> date_time<='2016.05.01'
>
> Or take a look to the pg_partman extension which promises to do the
> legwork for you
>
> Regards,
> Sándor.
>
>
>
> Ezt az e-mailt egy Avast védelemmel rendelkező, vírusmentes számítógépről
> küldték.
> www.avast.com
> <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
> <#1995191727766771537_DDB4FAA8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
>


It would really be helpful for future reference if you provided the
PostgreSQL version and O/S, but nevertheless:

The best way to do it is to make a new version of the old master
and base the child/partitions off of that.
eg:

CREATE TABLE log_new(
      idlog serial not null,
      date_time timestamp not null default now(),
      log varchar(255),
      primary key(idlog)
    );

CREATE TABLE log1()
  INHERITS (log_new);
ALTER TABLE log1
  ADD CONSTRAINT log1_pk PRIMARY KEY (idlog);
CREATE TABLE log2()
  INHERITS (log_new);
ALTER TABLE log2
  ADD CONSTRAINT log2_pk PRIMARY KEY (idlog);
CREATE TABLE log3()
  INHERITS (log_new);
ALTER TABLE log3
  ADD CONSTRAINT log3_pk PRIMARY KEY (idlog);

  CREATE OR REPLACE FUNCTION log_insert_fn()
   RETURNS TRIGGER AS
   $$
   BEGIN
    IF NEW.date_time < '2015-01-01' THEN
      INSERT INTO log1(idlog, date_time, log)
        VALUES
       ( NEW.idlog, NEW.date_time, NEW.log );
    ELSEIF NEW.date_time >= '2015-01-01' AND NEW.date_time <=
'2015-12-31'THEN
      INSERT INTO log2(idlog, date_time, log)
        VALUES
       ( NEW.idlog, NEW.date_time, NEW.log );
    ELSE
      INSERT INTO log3(idlog, date_time, log)
        VALUES
       ( NEW.idlog, NEW.date_time, NEW.log );
    END IF;
   RETURN NEW;
   END
   $$
   LANGUAGE plpgsql;

CREATE TRIGGER log_insert
  BEFORE INSERT ON log_new
  FOR EACH ROW
  EXECUTE PROCEDURE log_insert_fn();


Then, at a convenient time, split the data:
INSERT INTO log_new SELECT * FROM log;

and finally
ALTER TABLE log RENAME TO log_old;
ALTER TABLE log_new RENAME TO log;

You can then either keep or drop log_old.

-- 
*Melvin Davidson*
I reserve the right to fantasize.  Whether or not you
wish to share my fantasy is entirely up to you.

Reply via email to