Hotel prices spanning multiple dates issue - sql

Question is somehow related to this one, with the exception that I use parameters.
I have this on my button click :
procedure TForm1.Button1Click(Sender: TObject);
begin
with ABSQuery1 do begin
ABSQuery1.Close;
ABSQuery1.SQL.Clear;
ABSQuery1.SQL.Add('select * from ROOM_RATES where CENIK_ID = :a4 and ROOM_TYPE = :A1');
ABSQuery1.SQL.Add('and rate_Start_DATE < :a3 AND rate_End_DATE > :a2 ORDER BY rate_Start_DATE ASC ');
ABSQuery1.Params.ParamByName('a1').Value:= cxLookupComboBox2.Text;
ABSQuery1.Params.ParamByName('a2').Value:= cxDateEdit1.Date;
ABSQuery1.Params.ParamByName('a3').Value := cxDateEdit2.Date;
ABSQuery1.Params.ParamByName('a4').Value := cxLookupComboBox1.Text;
ABSQuery1.Open;
end;
end;
This kind of works but not what I want actually.Problem is related to this one:
Hotel Booking Rates SQL Problem
Problem is with the overlapping dates like in the mentioned hyperlink.Right now I am getting this :
How can I obtain result similar in the mentioned hyperlink with the above example ?
This is the snapshot of the db table :
Update (NEW):
This is the code on the button click :
procedure TForm1.AdvGlowButton1Click(Sender: TObject);
var
nxt : integer;
mem_from : TDateTime;
mem_to : TDateTime;
mem_RATE_ID : integer;
mem_ROOM_TYPE : string[10];
mem_Start_DATE_1 : TDateTime;
mem_End_DATE_1 : TDateTime;
mem_RATE_Price_1 : Currency;
mem_calc_END : TDateTime;
mem_calc_DAYS : integer;
c_from : TDateTime;
c_to : TDateTime;
c_from_test : TDateTime;
c_to_test : TDateTime;
begin
ABSQuery2.Close;
ABSQuery2.SQL.Text:='DELETE from TEMP';
ABSQuery2.ExecSQL;
ABSQuery2.SQL.Text:='SELECT * from TEMP ORDER BY ID ';
ABSQuery2.Open;
c_from := cxDateEdit1.Date;
c_to := cxDateEdit2.Date;
mem_from := cxDateEdit1.Date;
mem_to := cxDateEdit2.Date;
with ABSQuery1 do begin
ABSQuery1.Close;
ABSQuery1.SQL.Clear;
ABSQuery1.SQL.Add('select * from ROOM_RATES where CENIK_ID = :a4 and ROOM_TYPE = :A1');
ABSQuery1.SQL.Add('and rate_Start_DATE < :a3 AND rate_End_DATE > :a2 ORDER BY rate_Start_DATE ASC ');
ABSQuery1.Params.ParamByName('a1').Value:= cxLookupComboBox2.Text;
ABSQuery1.Params.ParamByName('a2').Value:= cxDateEdit1.Date;
ABSQuery1.Params.ParamByName('a3').Value := cxDateEdit2.Date;
ABSQuery1.Params.ParamByName('a4').Value := cxLookupComboBox1.Text;
ABSQuery1.Open;
nxt := 1;
mem_RATE_ID := ABSQuery1.FieldByName('RATE_ID').AsInteger;
mem_ROOM_TYPE := ABSQuery1.FieldByName('ROOM_TYPE').AsString ;
mem_Start_DATE_1 := ABSQuery1.FieldByName('RATE_START_DATE').AsDateTime;
mem_End_DATE_1 := ABSQuery1.FieldByName('RATE_END_DATE').AsDateTime;
mem_RATE_Price_1 := ABSQuery1.FieldByName('RATE_PRICE').AsCurrency;
if mem_to > mem_End_DATE_1 then begin
mem_calc_END := mem_End_DATE_1;
mem_calc_DAYS := Daysbetween(mem_from,mem_End_DATE_1);
end else begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(mem_from,mem_calc_END);
end;
end;
if ABSQuery1.RecordCount > nxt then ABSQuery1.Next;
with ABSQuery2 do begin
open;
Insert;
ABSQuery2.FieldByName('RATE_ID').AsInteger:=mem_RATE_ID;
ABSQuery2.FieldByName('ROOM_TYPE').AsString:=mem_ROOM_TYPE;
ABSQuery2.FieldByName('DATE_FROM').AsDateTime:=mem_from;
ABSQuery2.FieldByName('DATE_TO').AsDateTime:= mem_to;//mem_calc_END;
ABSQuery2.FieldByName('RATE_PRICE').AsCurrency:=mem_RATE_PRICE_1;
ABSQuery2.FieldByName('DAYS').AsInteger:=mem_calc_DAYS;
ABSQuery2.FieldByName('TOTAL').AsCurrency:=mem_RATE_PRICE_1 * mem_calc_DAYS;
post;
end; ///////////////////////////////////////////////////////////////////
if ABSQuery1.RecordCount > nxt then begin
inc(nxt);
if mem_to < ABSQuery1.FieldByName('rate_End_DATE').AsDateTime then begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(ABSQuery1.FieldByName('rate_Start_DATE').AsDateTime,mem_calc_END);
end else begin
mem_calc_END := ABSQuery1.FieldByName('rate_End_DATE').AsDateTime;
mem_calc_DAYS := Daysbetween(ABSQuery1.FieldByName('rate_Start_DATE').AsDateTime, ABSQuery1.FieldByName('rate_End_DATE').AsDateTime);
end;
mem_RATE_ID := ABSQuery1.FieldByName('RATE_ID').AsInteger;
mem_ROOM_TYPE := ABSQuery1.FieldByName('ROOM_TYPE').AsString;
mem_Start_DATE_1 := ABSQuery1.FieldByName('rate_Start_DATE').AsDateTime;
mem_End_DATE_1 := ABSQuery1.FieldByName('rate_End_DATE').AsDateTime;
mem_Rate_Price_1 := ABSQuery1.FieldByName('RATE_PRICE').AsCurrency;
// calculation : second row.
with ABSQuery2 do begin
Insert;
FieldByName('RATE_ID').AsInteger:=mem_RATE_ID;
FieldByName('ROOM_TYPE').AsString:=mem_ROOM_TYPE;
FieldByName('DATE_FROM').AsDateTime:=mem_Start_DATE_1;
FieldByName('DATE_TO').AsDateTime:= mem_calc_END;
FieldByName('RATE_PRICE').AsCurrency:=mem_RATE_PRICE_1;
FieldByName('DAYS').AsInteger:=mem_calc_DAYS;
FieldByName('TOTAL').AsCurrency:=mem_RATE_PRICE_1 * mem_calc_DAYS;
post;
end;
ABSQuery2.refresh;
end;
end;
The result I get is this :
As you can see from the database snapshot, prices are set OK.

Tested with Delphi 2010.
Your only one DBGrid, are associated with the dataset-table-pricelist
matches two rows of dataset-table-pricelist and so in your ABSQuery1 DBGrid
Row 1 from price list is shown.
Row 3 from price list is shown.
Now for both Rows procedure ABSQuery1CalcFields(DataSet: TDataSet);
is called with the same values !!
Daysbetween(cxDateEdit1.Date,cxDateEdit2.Date) = allways 19
.
procedure TForm1.ABSQuery1CalcFields(DataSet: TDataSet);
begin
ABSQuery1.FieldByName('Days').Value := IntToStr(Daysbetween(cxDateEdit1.Date,cxDateEdit2.Date));
ABSQuery1.FieldByName('TOTAL').AsCurrency :=ABSQuery1.FieldByName('Days').Value * ABSQuery1.FieldByName('RATE_PRICE').Value ;
end;
Therefore you have in your DBGrid twice Days are 19
The two fields From and To come also from the Table Price List.
Therefore, you can not see your own data From and To.
You should have 2 tables
Price list
calculation
With a loop on the table pricelist, fetch the required data of the price list.
clear calculation.
insert the data you get from Table price list.
Because I do not know exactly how your table is set up, you have to adapt the code to the database and your table.
In order to show the necessary steps better, here the following code.
Update : Here, now the complete code.
unit PriceList;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Grids, DBGrids, Db, ZAbstractRODataset, ZAbstractDataset,
ZDataset, ZConnection;
type
TForm1 = class(TForm)
ZConnection1: TZConnection;
ABSQuery1: TZQuery;
calculation: TZQuery;
DataSource1: TDataSource;
DataSource2: TDataSource;
DBGrid1: TDBGrid;
DBGrid2: TDBGrid;
DoCalc: TButton;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
RATE_ID: TLargeintField;
CENIK_ID: TLargeintField;
ROOM_TYPE: TWideStringField;
RATE_START_DATE: TDateTimeField;
RATE_END_DATE: TDateTimeField;
RATE_PRICE: TFloatField;
calculationID: TLargeintField;
calcRATE_ID: TLargeintField;
calcROOM_TYPE: TWideStringField;
calcDFROM: TDateTimeField;
calcDTO: TDateTimeField;
calcRATE_PRICE: TFloatField;
calcDAYS: TLargeintField;
calcTOTAL: TFloatField;
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
uses DateUtils;
procedure TForm1.DoCalcClick(Sender: TObject);
var
nxt : integer;
mem_from : TDateTime;
mem_to : TDateTime;
mem_RATE_ID : integer;
mem_ROOM_TYPE : string[20];
mem_Start_DATE_1 : TDateTime;
mem_End_DATE_1 : TDateTime;
mem_RATE_Price_1 : Currency;
mem_calc_END : TDateTime;
mem_calc_DAYS : integer;
c_from : string[19];
c_to : string[19];
c_from_test : string[19];
c_to_test : string[19];
begin
calculation.Close;
calculation.SQL.Text:='DELETE from calculation';
calculation.ExecSQL;
calculation.SQL.Text:='SELECT * from calculation ORDER BY ID ';
calculation.Open;
c_from := Edit3.Text;
c_to := Edit4.Text;
c_from_test := copy(Edit3.Text,7,4)+'.'+copy(Edit3.Text,4,2)+'.'+copy(Edit3.Text,1,2); // From 01.01.2013
c_to_test := copy(Edit4.Text,7,4)+'.'+copy(Edit4.Text,4,2)+'.'+copy(Edit4.Text,1,2);
mem_from := StrToDateTime(c_from);
mem_to := StrToDateTime(c_to);
with ABSQuery1 do begin
Close;
SQL.Clear;
SQL.Add('select * from ROOM_RATES where CENIK_ID = "'+Edit1.Text+'" and ROOM_TYPE = "'+Edit2.Text+'"');
SQL.Add('and RATE_START_DATE < '''+c_to_test+''' AND RATE_END_DATE > '''+c_from_test+''' ORDER BY RATE_START_DATE ASC ');
Open;
nxt := 1;
mem_RATE_ID := RATE_ID.AsLargeInt;
mem_ROOM_TYPE := ROOM_TYPE.AsString ;
mem_Start_DATE_1 := RATE_START_DATE.AsDateTime;
mem_End_DATE_1 := RATE_END_DATE.AsDateTime;
mem_RATE_Price_1 := RATE_PRICE.AsCurrency;
if mem_to > mem_End_DATE_1 then begin
mem_calc_END := mem_End_DATE_1;
mem_calc_DAYS := Daysbetween(mem_from,mem_End_DATE_1);
end else begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(mem_from,mem_calc_END);
end;
end;
if ABSQuery1.RecordCount > nxt then ABSQuery1.Next;
with calculation do begin
open;
Insert;
calculation.FieldByName('RATE_ID').AsInteger:=mem_RATE_ID;
calculation.FieldByName('ROOM_TYPE').AsString:=mem_ROOM_TYPE;
calculation.FieldByName('DFROM').AsDateTime:=mem_from;
calculation.FieldByName('DTO').AsDateTime:= mem_calc_END;
calculation.FieldByName('RATE_PRICE').AsCurrency:=mem_RATE_PRICE_1;
calculation.FieldByName('DAYS').AsInteger:=mem_calc_DAYS;
calculation.FieldByName('TOTAL').AsCurrency:=mem_RATE_PRICE_1 * mem_calc_DAYS;
post;
end;
if ABSQuery1.RecordCount > nxt then begin
inc(nxt);
if mem_to < rate_End_DATE.AsDateTime then begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(rate_Start_DATE.AsDateTime,mem_calc_END);
end else begin
mem_calc_END := rate_End_DATE.AsDateTime;
mem_calc_DAYS := Daysbetween(rate_Start_DATE.AsDateTime, rate_End_DATE.AsDateTime);
end;
mem_RATE_ID := RATE_ID.AsInteger;
mem_ROOM_TYPE := ROOM_TYPE.AsString;
mem_Start_DATE_1 := rate_Start_DATE.AsDateTime;
mem_End_DATE_1 := rate_End_DATE.AsDateTime;
mem_Rate_Price_1 := RATE_PRICE.AsCurrency;
with calculation do begin
Insert;
FieldByName('RATE_ID').AsInteger:=mem_RATE_ID;
FieldByName('ROOM_TYPE').AsString:=mem_ROOM_TYPE;
FieldByName('DFROM').AsDateTime:=mem_Start_DATE_1;
FieldByName('DTO').AsDateTime:= mem_calc_END;
FieldByName('RATE_PRICE').AsCurrency:=mem_RATE_PRICE_1;
FieldByName('DAYS').AsInteger:=mem_calc_DAYS;
FieldByName('TOTAL').AsCurrency:=mem_RATE_PRICE_1 * mem_calc_DAYS;
post;
end;
end;
calculation.refresh;
end;
end.
Of time constraints the code is not optimized. It is only to show the necessary steps.
TABLE room_rates
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;
TABLE calculation
DROP TABLE IF EXISTS `calculation`;
CREATE TABLE `calculation` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`RATE_ID` int(10) unsigned NOT NULL,
`ROOM_TYPE` varchar(45) NOT NULL,
`DFROM` datetime NOT NULL,
`DTO` datetime NOT NULL,
`RATE_PRICE` decimal(5,2) NOT NULL,
`DAYS` int(10) unsigned NOT NULL,
`TOTAL` decimal(7,2) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
Update :
Search for if mem_to > mem_End_DATE_1
To change Total 0,00€ You have to expand
if mem_to > mem_End_DATE_1 then begin
mem_calc_END := mem_End_DATE_1;
mem_calc_DAYS := Daysbetween(mem_from,mem_End_DATE_1);
end else begin
mem_calc_END := mem_to;
mem_calc_DAYS := Daysbetween(mem_from,mem_calc_END);
end;
Update 2 : above, now the complete code.
Update 3 : but still I get from 14/4/2013 to 26/4/2013 11 DAYS ! user763539
This behavior comes from DaysBetween(..,..) and not from my code.
DaysBetween is a delphi function!
I ask you 3 times .
Did you check what you get from cxDateEdit1.Date and cxDateEdit2.Date.
It must be to accurately 14-04-2013 00:00:00 and 26-04-2013 00:00:00 .
Create a new test programm.
Controlling what you get with.
DateTimeToString(formattedDateTime, 'c', cxDateEdit1.Date);
Memo1.Lines.Add(formattedDateTime);
With a loop over all ROOM_RATES records You should also check all date fields in ROOM_RATES.
DateTimeToString(formattedDateTime, 'c', ABSQuery1.FieldByName('RATE_START_DATE').AsDateTime);
Memo1.Lines.Add(formattedDateTime);
All times should be 00:00:00
For example:
DaysBetween .. 14-04-2013 12:15:10and26-04-2013 12:15:05==11 Days`
more accurately: 11 Days : 23 Hours : 59 minutes : 55 seconds.

Related

In my pl/SQL code there is an error which states that "The number specified in exact fetch is less than the rows returned" any ideas

This is my PL/SQL error:
Error report
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 67
00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
PL/SQL script:
DECLARE
cursor cur is (select distinct sor_ident
from CLEVA_OWNER_BE.f_polices, CLEVA_OWNER_BE.f_sit_objet_risque, CLEVA_OWNER_BE.f_produitass, cleva_owner_be.f_desc_stat_100, CLEVA_OWNER_BE.f_p_c_client, CLEVA_OWNER_BE.f_garantie_dyn
where pol_ident = sor_ptrpolid
and sor_ident = d100_ptrsorid
and bpcl_ident = pol_ptrclid
and pol_ptrpasid = pas_ident
and sor_ident = gad_ptrsorid
and pas_code_produit IN ('BFOV','BFOV2','BFOV5','BFOV6')
and BPCL_LIB24 = '1'
and d100_lib01 IN ('1','2','4','5','6')
and d100_lib09 > '1997'
and ( pol_codetat in ('1', '3', '6') or ( pol_codetat = '0' and pol_datcre > trunc ( sysdate - 183 ) ) )
and gad_code IN('RCVVY','RCLTY','RCVCT','RCHTY')
);
type tt_cur is varray(50) of cur%rowtype;
t_cur tt_cur;
type tt_cld is varray(50) of CLEVA_OWNER_BE.f_clause_dyn%rowtype;
t_cld tt_cld := tt_cld();
cld_key pls_integer;
v_ordre varchar2(3900);
v_desc varchar2(5000);
v_titre varchar2(5000);
BEGIN
t_cld.extend();
t_cld(1).CLD_IDENT := null;
t_cld(1).CLD_PTRSORID := null;
t_cld(1).CLD_TEXTE := null;
t_cld(1).CLD_ORDRE := null;
t_cld(1).CLD_CODE := 'RCVT7';
t_cld(1).CLD_SEQUENTIEL := null;
t_cld(1).CLD_SERVICES := null;
t_cld(1).CLD_INT_LOT_IMP := null;
t_cld(1).CLD_INT_LOT_EXP := null;
t_cld(1).CLD_LIBRE := 0;
t_cld(1).CLD_CHAPITRE := null;
t_cld(1).CLD_S_CHAPITRE := null;
t_cld(1).CLD_SS_CHAPITRE := null;
t_cld(1).CLD_TYPE := 2;
t_cld(1).CLD_TABLE := null;
t_cld(1).CLD_REFECHO := null;
t_cld(1).CLD_PTRSARID := null;
t_cld(1).CLD_TITRE := null;
t_cld.extend(49,1);
Line 67 select nvl( max(CLD_ident), 30000000) into cld_key
from CLEVA_OWNER_BE.f_clause_dyn
where CLD_ident between 30000000 and 49999999;
select TGA_ORDRE, tga_description, tga_titre into v_ordre, v_desc, v_titre
from cleva_owner_be.f_tarif_gar
where TGA_CODE = 'RCVT7';
OPEN cur;
LOOP
FETCH cur BULK COLLECT INTO t_cur LIMIT 50 ;
FOR i IN 1 .. t_cur.COUNT
LOOP
cld_key := cld_key + 1;
t_cld(i).CLD_IDENT := cld_key;
t_cld(i).CLD_PTRSORID := t_cur(i).sor_ident;
t_cld(i).CLD_TEXTE := v_desc;
t_cld(i).CLD_TITRE := v_titre;
t_cld(i).CLD_ORDRE := v_ordre;
END LOOP;
FORALL j IN 1..t_cur.COUNT
INSERT INTO CLEVA_OWNER_BE.f_clause_dyn VALUES t_cld(j);
COMMIT;
EXIT WHEN cur%NOTFOUND ;
END LOOP;
END
;

Bypass the JSON object using PL / SQL, and output all data in key value format in Oracle

I have JSON, I want to bypass it and display all the data that is in it. But the problem is that I can't know what data will be there. I made the code, but it only looks for top-level objects. And the rest are not. I will be grateful for your help.
DECLARE
l_object json_object_t;
l_key_list json_key_list;
v_clob CLOB;
tv apex_json.t_values;
BEGIN
-- JSON_OBJECT can figure out what keys it has...
v_clob := '{"devices":{"id":"d652f632-0835-871b-a140-58701f019000","scale_id":"88348A32BD3D149FE055000000000001"},"data":{"external_id":"40023"},"data_weight":{"weight":"20322","prevWeight":"1000","prevTransaction":"1607680754361","transaction":"1607680754361","on":"false","transactionDataCount":"1","stable":"false","duration":"12","transactionMaxWeight":"2000","perimetr":"true","driverInCar":"false"}}';
apex_json.parse(tv,v_clob);
l_object := json_object_t.parse (v_clob);
l_key_list := l_object.get_keys;
FOR counter IN 1 .. l_key_list.COUNT
LOOP
DBMS_OUTPUT.put_line (
l_key_list (counter)
|| ' : '
|| apex_json.get_varchar2(p_path => l_key_list (counter), p_values => tv));
END LOOP;
END;
If you take into account only the top level objects, then this code works
DECLARE
l_object json_object_t;
l_key_list json_key_list;
v_clob CLOB;
tv apex_json.t_values;
BEGIN
-- JSON_OBJECT can figure out what keys it has...
v_clob := '{"devices":"3423","data":"okwwwe"}';
apex_json.parse(tv,v_clob);
l_object := json_object_t.parse (v_clob);
l_key_list := l_object.get_keys;
FOR counter IN 1 .. l_key_list.COUNT
LOOP
DBMS_OUTPUT.put_line (
l_key_list (counter)
|| ' : '
|| apex_json.get_varchar2(p_path => l_key_list (counter), p_values => tv));
END LOOP;
END;
RESULT :
devices : 3423
data : okwwwe
And how to deduce the data from the first example, I can not understand. These data must correspond to the hierarchy.
If you have access to the native JSON types (JSON_ELEMENT_T, JSON_ARRAY_T, etc.) you should always use them over using the APEX_JSON package ans they will have much better performance. A package similar to the one below can be used to output the full hierarchy of a JSON object or array. Feel free to tweak the package to change the format of the output.
Package Specification
CREATE OR REPLACE PACKAGE output_json
AS
c_padding_char CONSTANT VARCHAR2 (1) := '-';
c_padding_amount CONSTANT PLS_INTEGER := 1;
PROCEDURE output_scalar (p_element json_element_t,
p_padding PLS_INTEGER,
p_json_key VARCHAR2 DEFAULT NULL);
PROCEDURE output_object (p_object json_object_t, p_padding PLS_INTEGER);
PROCEDURE output_array (p_array json_array_t, p_padding PLS_INTEGER);
PROCEDURE output_element (p_element json_element_t,
p_padding PLS_INTEGER,
p_json_key VARCHAR2 DEFAULT NULL);
END;
/
Package Body
CREATE OR REPLACE PACKAGE BODY output_json
AS
PROCEDURE output_scalar (p_element json_element_t,
p_padding PLS_INTEGER,
p_json_key VARCHAR2 DEFAULT NULL)
IS
BEGIN
DBMS_OUTPUT.put_line (
LPAD (c_padding_char, p_padding, c_padding_char)
|| CASE WHEN p_json_key IS NOT NULL THEN p_json_key || ' : ' END
|| CASE
WHEN p_element.is_boolean
THEN
CASE WHEN p_element.to_boolean THEN 'TRUE' ELSE 'FALSE' END || ' (boolean)'
WHEN p_element.is_date
THEN
TO_CHAR (p_element.TO_DATE, 'YYYY-MM-DD') || ' (date)'
WHEN p_element.is_number
THEN
p_element.TO_NUMBER || ' (number)'
WHEN p_element.is_string
THEN
p_element.TO_STRING || ' (string)'
END);
END;
PROCEDURE output_object (p_object json_object_t, p_padding PLS_INTEGER)
IS
l_keys json_key_list;
l_element json_element_t;
BEGIN
l_keys := p_object.get_keys;
FOR i IN 1 .. l_keys.COUNT
LOOP
l_element := p_object.get (l_keys (i));
output_element (l_element, p_padding, l_keys (i));
END LOOP;
END;
PROCEDURE output_array (p_array json_array_t, p_padding PLS_INTEGER)
IS
BEGIN
FOR i IN 0 .. p_array.get_size - 1
LOOP
output_element (p_array.get (i), p_padding);
END LOOP;
END;
PROCEDURE output_element (p_element json_element_t,
p_padding PLS_INTEGER,
p_json_key VARCHAR2 DEFAULT NULL)
IS
BEGIN
DBMS_OUTPUT.put_line (
CASE
WHEN p_json_key IS NOT NULL AND NOT p_element.is_scalar THEN p_json_key || ' : '
END);
IF p_element.is_scalar
THEN
output_scalar (p_element, p_padding, p_json_key);
ELSIF p_element.is_object
THEN
output_object (TREAT (p_element AS json_object_t), p_padding + c_padding_amount);
ELSIF p_element.is_array
THEN
output_array (TREAT (p_element AS json_array_t), p_padding + c_padding_amount);
END IF;
END;
END;
/
Example Call
DECLARE
l_clob CLOB;
BEGIN
l_clob :=
'{"arr":[1,2,3],"devices":{"id":"d652f632-0835-871b-a140-58701f019000","scale_id":"88348A32BD3D149FE055000000000001"},"data":{"external_id":"40023"},"data_weight":{"weight":"20322","prevWeight":"1000","prevTransaction":"1607680754361","transaction":"1607680754361","on":"false","transactionDataCount":"1","stable":"false","duration":"12","transactionMaxWeight":"2000","perimetr":"true","driverInCar":"false"}}';
output_json.output_element (json_element_t.parse (l_clob), 0);
END;
/
Example Output
arr :
--1 (number)
--2 (number)
--3 (number)
devices :
--id : "d652f632-0835-871b-a140-58701f019000" (string)
--scale_id : "88348A32BD3D149FE055000000000001" (string)
data :
--external_id : "40023" (string)
data_weight :
--weight : "20322" (string)
--prevWeight : "1000" (string)
--prevTransaction : "1607680754361" (string)
--transaction : "1607680754361" (string)
--on : "false" (string)
--transactionDataCount : "1" (string)
--stable : "false" (string)
--duration : "12" (string)
--transactionMaxWeight : "2000" (string)
--perimetr : "true" (string)
--driverInCar : "false" (string)
I also made my own version, but it is limited to 2 levels of objects, and does not take into account arrays.
DECLARE
l_object json_object_t;
l_key_obj json_key_list;
v_clob CLOB;
tv apex_json.t_values;
obj_in_obj JSON_OBJECT_T;
l_key_list json_key_list;
BEGIN
v_clob := '{
"devices":{
"id":"d652f632-0835-871b-a140-58701f019000",
"scale_id":"88348A32BD3D149FE055000000000001"
},
"data":{
"external_id":"40023"
},
"data_weight":{
"weight":"20322",
"prevWeight":"1000",
"prevTransaction":"1607680754361",
"transaction":"1607680754361",
"on":"false",
"transactionDataCount":"1",
"stable":"false",
"duration":"12",
"transactionMaxWeight":"2000",
"perimetr":"true",
"driverInCar":"false"
}
}';
apex_json.parse(tv,v_clob);
l_object := json_object_t.parse (v_clob);
l_key_list := l_object.get_keys;
FOR counter IN 1 .. l_key_list.COUNT
LOOP
obj_in_obj := l_object.get_object(l_key_list (counter));
l_key_obj := obj_in_obj.get_keys;
FOR counter_all_obj IN 1 .. l_key_obj.COUNT
LOOP
DBMS_OUTPUT.put_line (
l_key_list (counter)||'.'||l_key_obj (counter_all_obj)
|| ' : '
|| apex_json.get_varchar2(p_path => l_key_list (counter)||'.'|| l_key_obj (counter_all_obj), p_values => tv));
END LOOP;
END LOOP;
END;

Syntax error. in query expression -Delphi

I have following query and face error and i am Using XE8 with MS Access
Syntax error. in query expression 'select CCarID from tblcar where Car = (LX008)'
Procedure TFNewCarAct.BtnSaveClick(Sender: TObject);
begin
adoQueryCCA.Close();
adoQueryCCA.SQL.Clear;
adoQueryCCA.SQL.Add('INSERT INTO tblcaractivity ([CCarID],[Date],[Millage],[SerRcd],[EOType],[EOQunt],[AirFil],[GOil])');
adoQueryCCA.SQL.Add('values (select CCarID from tblcar where Car = ('+ComboBox2.Text+'))');
adoQueryCCA.SQL.Add('VALUES(:Date,:Millage,:SerRcd,:EOType,:EOQunt,:AirFil,:GOil)');
adoQueryCCA.Parameters.ParamByName('Date').Value:= Edit6.Text;
adoQueryCCA.Parameters.ParamByName('Millage').Value:= Edit1.Text;
adoQueryCCA.Parameters.ParamByName('SerRcd').Value:= memo1.Text;
adoQueryCCA.Parameters.ParamByName('EOType').Value:= Edit2.Text;
adoQueryCCA.Parameters.ParamByName('EOQunt').Value:= Edit3.Text;
adoQueryCCA.Parameters.ParamByName('AirFil').Value:= Edit4.Text;
adoQueryCCA.Parameters.ParamByName('GOil').Value:= Edit5.Text;
adoQueryCCA.ExecSQL;
ShowMessage('Done');
end;
Update:
procedure TFNewCarAct.FromShow(Sender: TObject);
begin
ADOQueryCT.Open;
while Not ADOQueryCT.Eof do
begin
ComboBox1.Items.Add(ADOQueryCT.FieldByName('Name').AsString);
ADOQueryCT.Next;
end;
ADOQueryCT.Close;
if ComboBox1.Items.Count > 0 then ComboBox1.ItemIndex := 0;
end;
procedure TFNewCarAct.OnComboBox1Change(Sender: TObject);
begin
ComboBox2.Items.BeginUpdate;
try
ComboBox2.Clear;
ADOQueryCC.Parameters.ParamByName('Name').Value := ComboBox1.Text;
ADOQueryCC.Open;
while Not ADOQueryCC.Eof do
begin
ComboBox2.Items.AddObject(ADOQueryCC.FieldByName('Car').AsString, '');
ADOQueryCC.Next;
end;
ADOQueryCC.Close;
if ComboBox2.Items.Count > 0 then ComboBox2.ItemIndex := 0;
finally
ComboBox2.Items.EndUpdate;
end;
end;
The Car in the comboBox2 acquire from the tblecar and want to save the FK in the tblcaractivity table.
The suggestion provides by the Victoria now cause "Unspecified error".
Can you help how i modify my code to save FK in tblcaractivity table.
Give a try;
Procedure TFNewCarAct.BtnSaveClick(Sender: TObject);
begin
adoQueryCCA.Close();
adoQueryCCA.SQL.Clear;
adoQueryCCA.SQL.Add('INSERT INTO tblcaractivity ([CCarID],[Date],[Millage],[SerRcd],[EOType],[EOQunt],[AirFil],[GOil])');
adoQueryCCA.SQL.Add('VALUES(:CCarID,:Date,:Millage,:SerRcd,:EOType,:EOQunt,:AirFil,:GOil)');
adoQueryCCA.Parameters.ParamByName('CCarID').Value:= Integer(ComboBox2.Items.Objects[ComboBox2.ItemIndex]);
adoQueryCCA.Parameters.ParamByName('Date').Value:= Edit6.Text;
adoQueryCCA.Parameters.ParamByName('Millage').Value:= Edit1.Text;
adoQueryCCA.Parameters.ParamByName('SerRcd').Value:= memo1.Text;
adoQueryCCA.Parameters.ParamByName('EOType').Value:= Edit2.Text;
adoQueryCCA.Parameters.ParamByName('EOQunt').Value:= Edit3.Text;
adoQueryCCA.Parameters.ParamByName('AirFil').Value:= Edit4.Text;
adoQueryCCA.Parameters.ParamByName('GOil').Value:= Edit5.Text;
adoQueryCCA.ExecSQL;
ShowMessage('Done');
end;
procedure TFNewCarAct.FromShow(Sender: TObject);
begin
ADOQueryCT.Open;
while Not ADOQueryCT.Eof do
begin
ComboBox1.Items.Add(ADOQueryCT.FieldByName('Name').AsString);
ADOQueryCT.Next;
end;
ADOQueryCT.Close;
if ComboBox1.Items.Count > 0 then ComboBox1.ItemIndex := 0;
end;
procedure TFNewCarAct.OnComboBox1Change(Sender: TObject);
begin
ComboBox2.Items.BeginUpdate;
try
ComboBox2.Clear;
ADOQueryCC.Parameters.ParamByName('Name').Value := ComboBox1.Text;
ADOQueryCC.Open;
while Not ADOQueryCC.Eof do
begin
ComboBox2.Items.AddObject(ADOQueryCC.FieldByName('Car').AsString, TObject(ADOQueryCC.FieldByName('CCarID').AsInteger));
ADOQueryCC.Next;
end;
ADOQueryCC.Close;
if ComboBox2.Items.Count > 0 then ComboBox2.ItemIndex := 0;
finally
ComboBox2.Items.EndUpdate;
end;
end;

IBQuery insert - Column unknown / Unsupported feature

Im trying to insert a row into a firebird database (embedded), but geting an exception when calling:
datamodule1.IBQuery1.prepare
Project xyz.exe raised exception class EIBInterBaseError with message
'Dynamic SQL Error SQL error code = -206 Column unknown INDEX_ At
line, column 25'.
with datamodule1.IBQuery1 do
begin
close;
With SQL do
begin
clear;
Add( 'INSERT INTO MST_EVENTS (eventindex, state_, event_, param_, date_, time_, devID_, gateway_)' );
Add( 'VALUES (:eventindex, :state_, :event_, :param_, :date_, :time_, :devid_, :gateway_') );
end;
//
GeneratorField.Field := 'Nr_';
GeneratorField.Generator := 'GEN_MST_EVENTS_ID';
//
Params[0].AsInteger := FMst.EventRecordIndex;
Params[1].AsSmallInt := FMst.EventRecordState;
Params[2].AsString := eventToStr(FMst.EventRecordEvent);
Params[3].AsSmallInt := 0;
Params[4].AsDate := FMst.EventRecordDate;
Params[5].AsTime := FMst.EventRecordTime;
Params[6].AsLongWord := FMst.EventRecordDevID;
Params[7].AsString := FMst.EventRecordIP;
//
if ( prepared = false ) then
prepare; //Throws an exception here (SOLVED)
execSQL; //Now getting exception here
end;
I have the following components tied together:
IBDatabase
IBTransaction
DataSource
IBQuery
Above problem solved - Edit >>
Ok, i have changed
Add( 'INSERT INTO MST_EVENTS (eventindex, state_, event_, param_, date_, time_, devID_, gateway_)' );
to
Add( 'INSERT INTO MST_EVENTS ("eventindex", "state_", "event_", "param_", "date_", "time_", "devID_", "gateway_")' );
... (so im using quotation marks) and now it finds the fields, but get another exception at line:
IBQuery1.execSQL:
Exception class EIBClientError with message 'Unsupported feature'
My fields are:
Nr_ : INTEGER
eventindex : INTEGER
state_ : SMALLINT
event_ : VARCHAR(50)
param_ : SMALLINT
date_ : DATE
time_ : TIME
devID_ : BIGINT
gateway_ : VARCHAR(50)
Firebird version is 2.5 embedded 32bit
I took out all the string and date/time parameters, yet i get the exception.
Using IBExpert and the same client/server .dll i can insert the row flawlessly (using all the values).
The solution was changing line
Params[6].AsLongWord := FMst.EventRecordDevID;
to
Params[6].AsLargeInt := FMst.EventRecordDevID;
But please how to auto-increment the field 'Nr_'?
with datamodule1.IBQuery1 do
begin
close;
With SQL do
begin
clear;
Add( 'INSERT INTO MST_EVENTS (eventindex, state_, event_, param_, date_, time_, devID_, gateway_)' );
Add( 'VALUES (:eventindex, :state_, :event_, :param_, :date_, :time_, :devid_, :gateway_') );
end;
//
GeneratorField.Field := 'Nr_';
GeneratorField.Generator := 'GEN_MST_EVENTS_ID';
//
Params[0].AsInteger := FMst.EventRecordIndex;
Params[1].AsSmallInt := FMst.EventRecordState;
Params[2].AsString := eventToStr(FMst.EventRecordEvent);
Params[3].AsSmallInt := 0;
Params[4].AsDate := FMst.EventRecordDate;
Params[5].AsTime := FMst.EventRecordTime;
Params[6].AsLargeInt := FMst.EventRecordDevID;
Params[7].AsString := FMst.EventRecordIP;
//
if ( prepared = false ) then
prepare; //Throws an exception here (SOLVED)
execSQL; //Now getting exception here
end;
I made the generator in flamerobin.
But getting exception (at calling 'execSQL'):
EDIT >>
I set up a generator and a BEFORE INSERT trigger in IBExpert:
And now its ok.

One Step Installer

I'm looking for a way to create a one page installer in Inno Setup, just look at this screenshot:
Can anyone please give me the codes for doing this?
Or totally I would like to merge pages abilities in Inno Setup. For example merge Select directory page with Components page and etc
It's not easy to do by default. But it can be done, the following code
produced a page like this one.
[Setup]
AppName=Test
AppVersion=1.5
DefaultDirName={code:AppDir}
;Disable all of the default wizard pages
DisableDirPage=yes
DisableProgramGroupPage=yes
DisableReadyMemo=yes
DisableReadyPage=yes
DisableStartupPrompt=yes
DisableWelcomePage=yes
;May want this, after install.
DisableFinishedPage=no
[Messages]
ButtonNext=Install
[Files]
Source:"e:\test.txt"; DestDir: "{app}"
Source:"e:\test.txt"; DestDir: "{app}"; DestName: "test1.txt"; Check: Option1;
Source:"e:\test.txt"; DestDir: "{app}"; DestName: "test2.txt"; Check: Option2;
[Code]
var
MainPage : TWizardPage;
edtFolderToInstall : TEdit;
InstallLocation : String;
Opt1, Opt2 : Boolean;
ChkOption1 : TCheckBox;
ChkOption2 : TCheckBox;
function AppDir(Param: String): String;
begin
// Set Default if not set.
if InstallLocation = '' then
InstallLocation := ExpandConstant('{pf}') + 'test';
result := InstallLocation;
end;
function Option1 : Boolean;
begin
result := Opt1;
end;
function Option2 : Boolean;
begin
result := Opt2;
end;
procedure BrowseClick(Sender : TObject);
var
Dir : String;
begin
Dir := edtFolderToInstall.Text;
if BrowseForFolder('Select Folder',Dir,false) then
edtFolderToInstall.Text := Dir;
end;
procedure InitializeWizard();
var
lblFolderToInstall : TLabel;
btnFolderToInstall : TButton;
begin
MainPage := CreateCustomPage(wpWelcome,'Setup - Test App Name','This will install "Test App Name" to your computer');
lblFolderToInstall := TLabel.Create(MainPage);
lblFolderToInstall.Parent := MainPage.Surface;
lblFolderToInstall.Top := 10;
lblFolderToInstall.Left := 10;
lblFolderToInstall.Caption := 'If you would like to select a different folder, Click Browse.'
edtFolderToInstall := TEdit.Create(MainPage);
edtFolderToInstall.Parent := MainPage.Surface;
edtFolderToInstall.Top := 25;
edtFolderToInstall.Left := 10;
edtFolderToInstall.Width := 250;
edtFolderToInstall.Text := WizardDirValue;
btnFolderToInstall := TButton.Create(MainPage);
btnFolderToInstall.Parent := MainPage.Surface;
btnFolderToInstall.top := 25;
btnFolderToInstall.Left := 275;
btnfolderToInstall.Caption := 'Browse...';
btnFolderToInstall.OnClick := #BrowseClick;
ChkOption1 := TCheckBox.Create(MainForm);
ChkOption1.Parent := MainPage.Surface;
ChkOption1.Top := 50;
ChkOption1.Left := 10;
ChkOption1.Caption := 'Option 1';
ChkOption2 := TCheckBox.Create(MainForm);
ChkOption2.Parent := MainPage.Surface;
ChkOption2.Top := 75;
ChkOption2.Left := 10;
ChkOption2.Caption := 'Option 2';
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
result := True;
// Next pressed, better make sure selected items are correct.
if CurPageId = MainPage.ID then
begin
InstallLocation := edtFolderToInstall.Text;
Opt1 := ChkOption1.Checked;
Opt2 := ChkOption2.Checked;
end;
end;
To pull this off, I use {code:AppDir} as the default directory. This tells InnoSetup to use the function AppDir to retrieve the installation directory. I then can set it using my custom dialog.
Instead of using [Components] and/or [Tasks] I have to use Check in the [Files] Section.