Search Postgresql Archives

Re: Restart increment to each year = re-invent the

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> Bruno Baguette said:
>> I have to design a table wich will store some action reports. Each
>> report have an ID like this 1/2004, 2/2004, ... and each years, they
>> restart to 1 (1/2004, 1/2005, 1/2006,...).
>>
>> So, I was thinking to split that in two fields : one with the
>> increment and one with the year. But I don't know how can I manage
>> the sequences since I have to restart to  each year...
>>
>> Do you think I should re-invent the sequences mecanism with a second
>> table and a stored procedure, only to manage theses 'home-made'
>> sequences ?
>>
>> Or should I create some sequences like myseq_2004, myseq_2004,
>> my_seq_2005,... and use a concatenation of the myseq_ string and the
>> current year when calling nextval and curvall ?
>

I use the "re-invent" option for compound sequences, as follows:

Each employee submits expense reports. Expense reports for each employee
are numbered as YYYY-NN, where "YYYY" is the current year, and "NN" is an
integer starting at one for each year for each employee.

CREATE TABLE employee
(
  employee_pk int4 serial,
  ...
  expense_report_seq int4 DEFAULT 0,
  CONSTRAINT employee_pkey PRIMARY KEY (employee_pk),
);


CREATE TABLE expense
(
  employee_pk int4 NOT NULL,
  expense_report_year int4 NOT NULL,
  expense_report_pk int4 NOT NULL,
  ...
  CONSTRAINT expense_report_pkey PRIMARY KEY (employee_pk,
expense_report_year, expense_report_pk),
  CONSTRAINT expense_fkey FOREIGN KEY (employee_pk) REFERENCES
paid.employee (employee_pk)
);


CREATE OR REPLACE FUNCTION expense_report_next(int4)
  RETURNS int4 AS
'
DECLARE
  l_employee_pk ALIAS FOR $1;
BEGIN
  UPDATE employee
    SET expense_report_seq = (expense_report_seq + 1)
    WHERE employee_pk = l_employee_pk;
RETURN (SELECT expense_report_seq FROM employee  WHERE employee_pk =
l_employee_pk) ;
END;'
  LANGUAGE 'plpgsql' VOLATILE;

/*
NOTE: I'm informed by good sources that the stored procedure defined
above handles concurrency issues correctly because 1) the UPDATE
statment locks the record until a COMMIT is invoked, so the subsequent
SELECT will return YOUR incremented value, not someone else's, and
2) since this procedure is called from within an ON INSERT trigger, it
therefore occurs within a transaction block (which is established
implicitly by the trigger).
*/

CREATE OR REPLACE FUNCTION expense_bit()
  RETURNS trigger AS
'
BEGIN
  IF NEW.expense_report_year IS NULL THEN
    SELECT INTO NEW.expense_report_year date_part(\'year\', current_date);
  END IF;
  IF NEW.expense_report_pk IS NULL THEN
    SELECT INTO NEW.expense_report_pk expense_report_next(new.employee_pk);
  END IF;
  RETURN new;
END;
'
  LANGUAGE 'plpgsql' VOLATILE;


CREATE TRIGGER expense_bit
  BEFORE INSERT
  ON expense
  FOR EACH ROW
  EXECUTE PROCEDURE paid.expense_bit();

-- Resetting the report sub-sequence values for each employee
-- at the start of a new year is left as a student exercise.

--Berend Tober




---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
      subscribe-nomail command to majordomo@postgresql.org so that your
      message can get through to the mailing list cleanly

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux