How can I use Integer Auto Increment Field in DBx4 with BlackFish? - delphi

I am trying to use auto incremental fields in dbx4 with a black fish database
I have a simple table Structure:
CREATE TABLE tblTABname (
ID int AUTOINCREMENT Primary Key,
Description varchar(100) NOT NULL );
Before Open I am doing the :
qryTAB.FieldByName( ‘ID’).AutoGenerateValue := arAutoInc;
cdsTAB.FieldByName( ‘ID’).AutoGenerateValue := arAutoInc;
After Open:
qryTab.FieldByName('ID').ProviderFlags := [pfInWhere, pfInKey];
cdsTab.FieldByName('ID').ProviderFlags := [pfInWhere, pfInKey];
If I do:
cdsTAB.Edit;
cdsTAB.FieldByName(‘Description’).value := ‘Test’;
cdsTAB.Post;
Or if I use this in a DBGRID, it fails with the error :
“Field ‘ID’ must have a value”
Witch should have been generated .
If I run an INSERT Query it works fine, with or without the “AutoGenerateValue := arAutoInc” lines.
How can I overcome this problem?

Instead of calling CDSTab.EDIT, call CDSTab.INSERT to add a new row, only call CDSTab.EDIT when your cursor is on a record already, and to edit the value of that record.

Related

How can i append record to TAdoQuery without clearing its fields?

I am using TAdoQuery with BatchOptimistic lock type. If the select command has some fields that are calculated on database server the returned fields has property ReadOnly = true, so i must change them to false so i can modify them in my query.
I am actually never attempting to post to database, but i must use TAdoQuery.
Its all good to the point I append or insert some record, set its fields, and then call for example TAdoQuery.Last, Next or First.. The appended records fields change to null. Please, is there a way that these records could stay as they were?
I am attaching a simple code here, where the problem is presented:
// .. lockType = Batchoptimistic so TAdoQuery.first or TAdoQuery.last do NOT post do database
ADOQuery1.LockType := ltBatchOptimistic;
ADOQuery1.SQL.Text := 'SELECT 10 AS id, 20 AS sid ';
ADOQuery1.Open;
// .. readOnly = false so i can modify these two fields in appended record
ADOQuery1.FieldByName('id').ReadOnly := false;
ADOQuery1.FieldByName('sid').ReadOnly := false;
ADOQuery1.Append;
ADOQuery1.FieldByName('id').AsInteger := 5;
ADOQuery1.FieldByName('sId').AsInteger := 5;
// if use last, first etc. the appended record fields will change to 0 (null)
ADOQuery1.Last;

Single field , multi-record Data-aware control

I trying to create a data-aware component that is a single field , multi-record control , something like TDBLoookupList , but with the KeyField only.
I cannot figure how to iterate through the dataset correctly .
private
FFieldDataLink:TFieldDataLink;
FDataList:Tlist;
if FFieldDataLink.DataSet.Active and (FFieldDataLink.FieldName<>'' ) then
begin
try
FFieldDataLink.DataSet.GetFieldList(FFDataList,FieldDataLink.FieldName);
except
DatabaseErrorFmt(SFieldNotFound, [Self.Name,FFieldDataLink.FieldName]);
end;
end;
the above code snippet should return a list of the fields in the buffer, but it returns only the first record .
thanks

Getting error using a parameter with anydac (now firedac) script for firebird

I'm unable to get the following script to execute without error.. It's running in delphi against a firebird database.
var
vScript: TADScript;
begin
vScript := TADScript.Create(nil);
vScript.Connection := xConnection;
vScript.Transaction := xTransaction;
with vScript.Params.Add do
begin
Name := 'DEFVAL'; // also tried ':DEFVAL'
AsInteger := 1;
end;
with vScript.SQLScripts.Add do
SQL.Text := 'ALTER TABLE "PERSON" add "AGE" INTEGER DEFAULT :DEFVAL';
vScript.ValidateAll;
vScript.ExecuteAll;
end
It gives an error of 'Token unknown - line 1, column 48', the parameter (:DEFVAL) location
I've tried assigning the sql text first then calling Params.FindParam but it's not in the list. This works for queries.
Not using parameters and just including the default value in the SQL string works but this code is used as part of a bigger frame work and that option is a last resort.
The reason you get a token unknown error is because ALTER TABLE statements do not allow the use of parameters in this way.
You will need to concat the stringified default value to the ALTER TABLE statement. Since your code is unconditionally applying a default value of 1 in this case then this can be simply included in the statement literal:
with vScript.SQLScripts.Add do
SQL.Text := 'ALTER TABLE "PERSON" add "AGE" INTEGER DEFAULT 1';
If you did need to accommodate potentially variable default values then obviously this would need to change to something similar to:
with vScript.SQLScripts.Add do
SQL.Text := Format('ALTER TABLE "PERSON" add "AGE" INTEGER DEFAULT %i', [iDefaultValue]);
Where iDefaultValue is some integer variable holding the default value required.

Monitoring a table attribute with stored procdeure

I am working on a stored procedure that monitors the Last_Extract_Ts value in the table that provides information about Extract Transform Load(ETL). Now I want to check whether the Last_Extract_ts value changed from the last time the procedure ran, but I can't quite figure out how to store the result of the last procedure run so that I can use it in the current one.
Below is my procedure
create or replace PROCEDURE MONITOR AS
v_count number:=0;
v_Last_Extract_Ts VARCHAR2(80) := '';
v_Last_ETL_Run VARCHAR2(80) := '';
BEGIN
select count(*) into v_count from oms_etl_config where ATTR_NM='last_extract_ts' and process_type='upd' and ATTR_VALUE<=to_char(sys_extract_utc(systimestamp)-5/1440,'YYYY-MM-DD HH24:MI:SS');
select Attr_value into v_Last_Extract_Ts from OMS_ETL_CONFIG where PROCESS_TYPE='upd' AND ATTR_NM='last_extract_ts';
Select MAX(START_TS) into v_Last_ETL_Run from OMS_ETL_AUDIT;
dbms_output.put_line(v_count);
dbms_output.put_line(v_Last_Extract_Ts);
dbms_output.put_line(v_Last_ETL_Run);
END;
I came across something like storing the result of the stored procedure in a temp table in Insert results of a stored procedure into a temporary table , Exec stored procedure into dynamic temp table but I can't quite see how it meets my needs.
Is what I am trying to achieve possible or I need to have a different approach.
Thanks in advance.
P.S. I am absolute beginner with PL/SQL and stored procedures so I am
not having any attempt in my post to show for the research I have done. Sorry for that.
The simplest way is to save the last results in a table.
create a table:
Create table monitor_results
(
last_run_date date
, last_Last_Extract_Ts varchar2(80)
, last_ETL_Run varchar2(80)
, last_count NUMBER
);
initialize values:
insert into monitor_results values (NULL, NULL, NULL, NULL);
commit;
in the stored procedure update the values in the table:
...
update monitor_results
set
last_run_date = SYSDATE
, last_Last_Extract_Ts = v_Last_Extract_Ts
, last_ETL_Run = v_Last_ETL_Run
, last_count = v_count
;
commit;
You can do this check using a trigger: See below:
CREATE OR REPLACE TRIGGER reporting_trigger
AFTER UPDATE ON <Table>
FOR EACH ROW
BEGIN
/**Your column which holds the record**/
IF :new.a = :old.a THEN
raise_application_error( -20001, 'This is a custom error' );
END IF;
END;

Insert partly existing data

I need to add extra data to my TEMP table shown at the bottom on button click.
I need all existing occurences of FROM - TO - DAYS in the table duplicated and inserted.
RATE_PRICE would be predetermined & and the same for all new inserts (when inserting).
and also inserted.
Example : I have an extra bed to add and it costs 15 euros.
Now I would like to, when I check a checkbox (and click on a button) to insert that value (15) in the TEMP table but
it must follow the displayed dates values in the grid.
I had in mind adding extra field in the TEMP table called EXTRA which would be invisible unless
checkbox checked. So when I check an option of adding an extra bed, the extra bed would follow the displayed.Rate price would be 15 then ...
dates.
How can I insert desired data ?
UPDATE
I did it on button click :
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
with ABSQuery4 do begin
ABSQuery4.Close;
ABSQuery4.SQL.Clear;
ABSQuery4.SQL.Text := 'INSERT INTO TEMP (extra,Date_From,Date_To,Rate_price,Days,Total) VALUES (:a1,:a2,:a3,:a4,:a5,:a6)';
ABSquery4.Params.ParamByName('a1').asString :='TT';
ABSquery4.Params.ParamByName('a2').value := cxDateEdit1.date;
ABSquery4.Params.ParamByName('a3').value := cxDateEdit2.date;
ABSquery4.Params.ParamByName('a4').value :='1';
ABSquery4.Params.ParamByName('a5').value :=Daysbetween(cxDateEdit1.Date,cxDateEdit2.Date);
ABSquery4.Params.ParamByName('a6').value := (ABSquery4.Params.ParamByName('a4').value)*(ABSquery4.Params.ParamByName('a5').value);
ABSquery4.ExecSQL ;
ABSquery2.Refresh;
end;
end;
Any more elegant way ?
You should new readers to point out to which, previous question (code), you are referring. Without this information, they can not understand your question. Hotel prices spanning multiple dates issue
Now to your Question.
Forget your with absquery4 do begin, there is an easier way.
With only 2 new lines of code added to your existing code.
Expand your price list to all the extras you need.
e.g. DBLMSExtraBed : 'Price:15,00`.
Add a new Button Caption:='Add Extras`.
clickEvent pointing to your CalculationButtonClick.
Test in CalculationButtonClick from wich button the event is fired.
Fill out ROOM_TYPE TEditfield with DBLMSExtraBed.
Add following WITH .. IF .. THEN
...
with sender As TButton do if name='DoCalc' then begin
above
ABSQuery2.Close;
ABSQuery2.SQL.Text:='DELETE from TEMP';
ABSQuery2.ExecSQL;
ABSQuery2.SQL.Text:='SELECT * from TEMP ORDER BY ID ';
ABSQuery2.Open;
and an end;
end;
If the Event is fired from AddExtrasButton . It will not clear your Temp-Table.
So the Table is still open and the new Data will be inserted.
Now you have 3 Rows, last is :
With the AddExtrasButton you can add as much extras you like, as long there are extras in the Pricelist.
Used Table:
CREATE DATABASE IF NOT EXISTS pricelist;
USE pricelist;
DROP TABLE IF EXISTS `room_rates`;
CREATE TABLE `room_rates` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`CENIK_ID` int(10) unsigned NOT NULL,
`ROOM_TYPE` varchar(45) NOT NULL,
`RATE_START_DATE` datetime NOT NULL,
`RATE_END_DATE` datetime NOT NULL,
`RATE_PRICE` decimal(5,2) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
/*!40000 ALTER TABLE `room_rates` DISABLE KEYS */;
INSERT INTO `room_rates` (`ID`,`CENIK_ID`,`ROOM_TYPE`,`RATE_START_DATE`,`RATE_END_DATE`,`RATE_PRICE`) VALUES
(1,1,'DBLMS','2013-01-02 00:00:00','2013-04-26 00:00:00','128.00'),
(2,1,'DBLMS','2013-10-22 00:00:00','2013-12-18 00:00:00','128.00'),
(3,1,'DBLMS','2013-04-26 00:00:00','2013-06-22 00:00:00','146.00'),
(4,1,'DBLMS','2013-09-21 00:00:00','2013-10-20 00:00:00','146.00'),
(5,1,'DBLMSExtraBed','2013-01-02 00:00:00','2013-06-22 00:00:00','15.00');
Update :
Only a Tipp:
Create in your Temp Table a Field EXTRAS.
procedure TForm1.AdvGlowButton1Click(Sender: TObject);
var
isExtra : Boolean;
[...]
with sender As TButton do if name='AdvGlowButton1' then
isExtra := False else
isExtra := True;
if NOT isExtra then begin
ABSQuery2.Close;
ABSQuery2.SQL.Text:='DELETE from TEMP';
ABSQuery2.ExecSQL;
ABSQuery2.SQL.Text:='SELECT * from TEMP ORDER BY ID ';
ABSQuery2.Open;
end;
[...]
if isExtra then
ABSQuery2.FieldByName('EXTRAS').AsString:=mem_ROOM_TYPE
else
ABSQuery2.FieldByName('ROOM_TYPE').AsString:=mem_ROOM_TYPE;

Resources