|
#1
|
|||
|
|||
вычисляемые поля
Помогите пожалуйста. есть две таблицы ostatki, potrebnost
таблицы ostatki, potrebnost имеют поля (diametr, gost , ves). Нужно если diametr и gost в одной таблице равны diametr и gost в другой то ves из одной таблице должен вычитаться из другой и записыватся в поле itog. Вот текст. Подскажите ,что не так Код:
procedure TForm1.Button2Click(Sender: TObject); begin form1.ADOtable1.first; while form1.ADOtable1.Eof do begin if (ADOtable1diametr.Value=form1.ADOtable2diametr1.Value)and (ADOtable1gost.Value= ADOtable2gost1.Value) then // ADOtable1rezult.Value:=ADOtable2ves1.Value-ADOtable1ves.Value ; ADOtable1itog.Value:=ADOtable2ves1.Value - ADOtable1ves.Value; form1.ADOtable1.next; end;end; Спасибо за помощь Последний раз редактировалось Admin, 26.10.2011 в 18:52. |
#2
|
|||
|
|||
А на уровне SQL это нельзя сделать?
Код:
select o.diametr, o.gost, (o.ves - p.ves) as itog from ostatki o left join potrebnost p on o.gost=p.gost and o.diametr = з.diametr |
#3
|
|||
|
|||
есть 2 подхода
1. на уровне SQL- пишешь SQL процедуру 2. на уровне пользовательской подключаемой библиотеки вечером покажу. |
#4
|
|||
|
|||
/*---вот объявление функций пользователя.
Это оформляется в виде DLL. Я привожу этот пример только как рыбу. Обрати внимание на способ передачи параметров- cdecl. Это обязательное условие. Этот текст надо оформить в виде DLL- библиотеки и поместить ее в каталог C:\Interbase\Udf *'/ Код:
library UdfMetrolog; uses SysUtils, DateUtils; function GetYear(var Dt:double):smallint;cdecl; begin try GetYear:=YearOf(Dt); except GetYear:=9999 end end; function GetMonth(var Dt:double):smallint;cdecl; begin try Result:=MonthOf(Dt); except Result:=-1 end end; function AddMonth(var Dt:double;var NumbOfMonth:integer):double;cdecl; begin try Result:=IncMonth(Dt,NumbOfMonth); except Result:=-1 end end; exports AddMonth, GetMonth, GetYear; begin end. После того как ты изготовил DLL с твоими функциями пользователя на них можно ссылаться в тексте описания БД. Для этого надо сделать внешние ссылки на эти функции, как это указано ниже. Теперь твои функции можно применять также как и стандартные. Надо сказать что такую возможность предоставляют не все базы данныз. Лично я использую InterBase/FireBird, где все это есть. */ Код:
DECLARE EXTERNAL FUNCTION ADDMONTH DOUBLE PRECISION, INTEGER RETURNS DOUBLE PRECISION BY VALUE ENTRY_POINT 'AddMonth' MODULE_NAME 'UdfMetrolog'; DECLARE EXTERNAL FUNCTION GETMONTH DOUBLE PRECISION RETURNS SMALLINT BY VALUE ENTRY_POINT 'GetMonth' MODULE_NAME 'UdfMetrolog'; DECLARE EXTERNAL FUNCTION GETYEAR DOUBLE PRECISION RETURNS SMALLINT BY VALUE ENTRY_POINT 'GetYear' MODULE_NAME 'UdfMetrolog'; Теперь о втором способе. Можно в самой БД создать некое свойство, которое позволяет прямо по ходу дела анализировать ситуацию и соответственно ее обрабатывать. Это триггеры- специальные процедуры, внедренные в базу данных и запускающиеся автомтически при наступлении определенных событий в БД. Например, процедура Workks_trig_ins (см ниже) автоматически запустится ПЕРЕД вставкой новой строки в таблицу Works. Код:
*-------------------------------------------------------------------------------------------------- генератор номеров свидетельств в пределах 1 года для таблицы Works VidDocum IN (' - ','Сертифик. о калибр.','Свидет. о повер.','Извещ. о непригодн.','Акт на спис.')), ---------------------------------------------------------------------------------------------------*/ CREATE TRIGGER Works_trig_ins FOR Works ACTIVE BEFORE INSERT AS DECLARE VARIABLE Yr SMALLINT; DECLARE VARIABLE Yr2 SMALLINT; BEGIN Yr2=extract(year from CURRENT_DATE); /* свидетельство */ IF (NOT(NEW.Svidet IS NULL)) THEN BEGIN SELECT GETYEAR(Dat) FROM Works WHERE (Dat=(SELECT MAX(Dat) FROM Works WHERE (VidDocum = NEW.VidDocum))) INTO :Yr; IF (NEW.VidDocum='Сертифик. о калибр.') then BEGIN NEW.NumSvidet_Yr = GEN_ID(Works_Kal_Yr_GEN,1); IF (:Yr <> :Yr2) THEN NEW.NumSvidet_Yr = GEN_ID(Works_Kal_Yr_GEN,1-NEW.NumSvidet_Yr); END IF (NEW.VidDocum='Свидет. о повер.') then BEGIN NEW.NumSvidet_Yr = GEN_ID(Works_Pov_Yr_GEN,1); IF (:Yr <> :Yr2) THEN NEW.NumSvidet_Yr = GEN_ID(Works_Pov_Yr_GEN,1-NEW.NumSvidet_Yr); END IF (NEW.VidDocum='Извещ. о непригодн.') then BEGIN NEW.NumSvidet_Yr = GEN_ID(Works_Negodn_Yr_GEN,1); IF (:Yr <> :Yr2) THEN NEW.NumSvidet_Yr = GEN_ID(Works_Negodn_Yr_GEN,1-NEW.NumSvidet_Yr); END IF (NEW.VidDocum='Акт на спис.') then BEGIN NEW.NumSvidet_Yr = GEN_ID(Works_Spisan_Yr_GEN,1); IF (:Yr <> :Yr2) THEN NEW.NumSvidet_Yr = GEN_ID(Works_Spisan_Yr_GEN,1-NEW.NumSvidet_Yr); END END END! Итак, после всего этого база данных перестает быть просто хранилищем, а приобретает определенный интеллект, чем программист должен уметь пользоваться. После того как программист заложил в БД функции, она приобретает способность производить первичную обработку информации и уже находится в состоянии, когда может по требованию пользователя выдать нужную информацию (перед тем ее обработав и представив в нужном виде!). Несколько советов Эти 2 способа в какой- то мере конкурируют между собой. Какой из них избрать для достижения заданной цели- решает программист. Мой совет В DLL следует помещать функции сложные. Они пишутся на языках высокого уровня и потому просты в отладке. Оформмять твои специфические функции как триггеры следует тогда, когда они достаточно просты и кроме того предвидится необходимость их изменять. Это так называемые Бизнес-правила. Например, как триггер следует оформить функцию вычета подоходного налогга. Если правила исчисления подоходного налога изменились- ты просто в твоей БД изменяешь эту функцию- и она автоматически действует для всех пользователей. */ |
#5
|
|||
|
|||
Тов, Чайник, а вам не кажется, что вас нетуда понесло???
|