Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Firebird, Interbase > Помогите написать триггер или UDF


Автор: Urvin 11.2.2008, 19:15
Если честно, даже не знаю в какую сторону смотреть....

Суть: заказы в базе данных помимо собственного ID имеют более гуманный "номер",
составляющийся из цифр текущего года, месяца и порядкового номера заказа
в этом месяце вида ММГГ-ННН.

т.е. Например, за последние два месяца заказы могут выглядеть так:
0108-001 // январь
0108-002
0108-003
0108-004
0208-001 // февраль пошел
0208-002
0208-003
...

Хотелось бы, чтобы при добавлении нового заказа автоматически на стороне СУБД
генерировался не только ID, но и этот номер заказа.

Подскажите, как реализовать данную хотелку?

На дельфях функцию NextNumber(PreviousNumber: string) реализовал.

Автор: Urvin 11.2.2008, 22:19
Я сделал библиотечку на Delphi:
Код

library v_number;

uses
  SysUtils,
  DateUtils,
  Classes;

{$R *.res}
// Добавление ведущих нулей
function AddNill(value: integer; digs: integer): string;
begin
  result:=IntToStr(value);
  while length(result) < digs do begin
    result:= '0' + result;
  end;
end;

// главная функция - возвращает следующий номер в зависимости от предыдущего
procedure Next_Number(OldNumber, NewNumber: PChar); cdecl export;
var
  LfNumber,NewN: string;
begin
  LfNumber:= AddNill(MonthOf(Now),2) + Copy(IntToStr(YearOF(now)),3,2);
  if LfNumber <> Copy(OldNumber,1,4) then
    NewN:='000'
  else
    NewN:=Copy(OldNumber,6,length(OldNumber)-5);

  NewN:=LfNumber + '-' + AddNill(StrToInt(NewN)+1,3);

  NewNumber:=PChar(NewN);
end;


exports
  Next_Number;
begin
  isMultiThread:=True;
end.


Cкомпилировал в v_number.dll, которую кинул её в .../firebird_2_0/UDF

В базу добавил так:
Код

DECLARE EXTERNAL FUNCTION Next_Number
    CSTRING(10), CSTRING(10)
    RETURNS PARAMETER 2
ENTRY_POINT 'Next_Number'  MODULE_NAME 'v_number'


и даже написал триггер:
Код

CREATE OR ALTER trigger bef_ins_ord for orders
active before insert position 0
AS
    declare variable oldn varchar(10);
begin
    if (new.cid is null) then
        new.cid=gen_id(gen_ord,1);
    if (new.cnumber1 is null) then begin
        SELECT cnumber1
        FROM orders
        WHERE cid = (SELECT MAX(cid) from orders)
        into :oldn;

        new.cnumber1=Next_Number(:oldn);

    end
end



К сожалению, оно даже не работает с запросом
Код
select Next_Number(cnumber1) from orders where cid=1;



Где я наврал?

Автор: Urvin 11.2.2008, 23:44
Код

library v_number;

uses
  SysUtils,
  DateUtils,
  Classes,
  ib_util in 'C:\Program Files\Firebird\Firebird_2_0\include\ib_util.pas';

{$R *.res}
// Добавление ведущих нулей
function AddNill(value: integer; digs: integer): string;
begin
  result:=IntToStr(value);
  while length(result) < digs do begin
    result:= '0' + result;
  end;
end;



// главная функция - возвращает следующий номер в зависимости от предыдущего
function Next_Number(OldNumber: PChar):PChar; cdecl export;
var
  LfNumber,NewN: string;
begin
  LfNumber:= AddNill(MonthOf(Now),2) + Copy(IntToStr(YearOF(now)),3,2);
  if LfNumber <> Copy(OldNumber,1,4) then
    NewN:='000'
  else
    NewN:=Copy(OldNumber,6,length(OldNumber)-5);

  NewN:=LfNumber + '-' + AddNill(StrToInt(NewN)+1,3);

  Result := ib_util_malloc(Length(NewN) + 1);
  StrPCopy(Result, NewN);
end;

exports
  Next_Number;
begin
  isMultiThread:=True;
end.


Код

DECLARE EXTERNAL FUNCTION NEXT_NUMBER
    CSTRING(10)
RETURNS CSTRING(10) FREE_IT
ENTRY_POINT 'Next_Number' MODULE_NAME 'v_number';



простите, был напуган

Автор: Akella 12.2.2008, 01:42
почитай про extract и про Copy

Добавлено через 13 минут и 55 секунд
сеглдня лень тебе написать процедуру, напомни завтра в PM, постараюсь дать код  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)