Type mismatch in expression in Delphi 7 on SQL append - sql

I have a code, that checks the current date when a form is loaded, performs a simple calculation, and appends a SQL in Delphi. It works on Windows 7 with Delphi 7, and on another computer with Xp, but doesn't on 3 other computers with Xp. When the form is loaded it shows a "Type mismatch in expression", and points to the line after the append. What could be the problem?
procedure TfmJaunumi.FormCreate(Sender: TObject);
var d1, d2: TDate;
begin
d1:= Date;
d2:= Date-30;
With qrJaunumi do
begin
Open;
SQL.Append('WHERE Sanem_datums BETWEEN' + #39 + DateToStr(d1) +
#39 + 'AND' + #39 + DateToStr(d2) + #39);
Active := True;
end;
end;

As robsoft says, it is probably the internationalisation settings. You could use parameterised queries instead - they are generally simpler if using dates and times.
Also, the Open after the with's begin isn't needed - in fact it will open the query without the WHERE clause you are adding.
procedure TfmJaunumi.FormCreate(Sender: TObject);
var d1, d2: TDate;
begin d1:= Date; d2:= Date-30; With
qrJaunumi do
begin
SQL.Append('WHERE Sanem_datums BETWEEN :StartDate AND :EndDate');
// exact expression will vary according to DB connection type.
// Example is for TADOQuery.
Parameters.ParamByName('StartDate').Value := d1;
Parameters.ParamByName('EndDate').Value := d2;
Active := True;
end;
end;

You may use a prepared statement to overcome any localization problems with date time values. DateToStr depends on the client side. FormatDateTime can fail if the server's localization doesn't accept the date format.
procedure TfmJaunumi.FormCreate(Sender: TObject);
var
d1, d2: TDate;
begin
d1:= Date;
d2:= Date - 30;
//qrJaunumi.SQL.Clear; removed because it would remove the "SELECT ... FROM ..." part
qrJaunumi.SQL.Add('WHERE Sanem_datums BETWEEN :StartDate AND :StopDate ');
qrJaunumi.Prepared := True;
qrJaunumi.ParamByName('StartDate').AsDateTime := d1;
qrJaunumi.ParamByName('StopDate').AsDateTime := d2;
qrJaunumi.Open; // = qrJaunumi.Active := True;
end;
The space after ":StopDate" is important because Delphi has a bug in the parameter parser unless they fixed it in newer versions.

It's almost certainly to do with the local internationalisation settings on those computers - DateToStr will return a string in the local date format (possibly MM/DD/YYYY or DD/MM/YYYY) - and depending on where you are this might not be what you're expecting.
I suspect you'll find that the computers it's not working on think they're in a different country/use a different internationalisation setting to the computers where it's working.
A better solution would be to use FormatDateTime to get the date into a standard format that your SQL Server installation will accept, so there's no chance that any local 'internationalisation' settings can interfere like this.

Unfortunately none of the above worked, but the solution was to replace the Format with "yy.mm.dd." instead of "yyyy.mm.dd.", and adding single quotes. Weird, it says the format is "yyyy.mm.dd." everywhere.
The code looks like this now:
procedure TfmJaunumi.FormCreate(Sender: TObject);
var d1, d2: TDate; d3, d4, atd: String;
begin
d1:= Date;
d3:= FormatDateTime('yy.mm.dd.',d1);
d2:= Date-30;
d4:= FormatDateTime('yy.mm.dd.',d2);
atd := '''';
With qrJaunumi do
begin
Open;
SQL.Append('WHERE Sanem_datums BETWEEN'+ atd+d4+atd +'AND'+ atd+d3+atd+';');
Active := True;
end;
end;

Hi I had same error and found different solution from MS Support:
SQL.Text:='Delete * from TableName where((kno='+(inttostr(userNo))+')and(Sanem_datums >= # '+(FormatDateTime('mm-dd-yy',d1))+' # ))'; ExecSQL;
https://support.microsoft.com/en-us/kb/175258

Related

Is possible to set filter option in SMDBGrid to CaseInsensitive?

I have SMDBGrid component with show filter bar option set to true, but filter just working in case-sensitive mode
1.Try with lower case
2.Try with upper case
I have tried to insert the code in SMDBgrid.pas like this
procedure TSMDBGrid.ApplyFilter;
var
TempCol: Integer;
begin
if (eoFilterAutoApply in ExOptions) then
begin
TempCol := LeftCol;
BeginUpdate;
try
if DataLink.Active then
begin
DataLink.DataSet.CheckBrowseMode;
DataLink.DataSet.Filtered := False;
DataLink.DataSet.OnFilterRecord := nil;
DataLink.DataSet.OnFilterRecord := OnFilterRecord;
DataLink.DataSet.FilterOptions := [foCaseInsensitive]; <-- this the inserted code
DataLink.DataSet.Filtered := not FilterIsEmpty();//True;
end;
finally
LeftCol := TempCol;
EndUpdate;
end;
end;
if Assigned(OnFilterChanged) then
OnFilterChanged(Self);
end;
But no luck, Is posible filter the record ignoring the case?
PS:
I use Delphi 2009
You may use the OnAccentStringConvert event to transform the value for filter in column before compare:
begin
Result := UpperCase(S)
end;
Looks like I cope with this problem too. Trying to find any solution for Delphi XE 10.3 community edition and wrote to author of SMDBGrid and he found workaround.
Please use SQL ADOQuery as follows.
SELECT UPPER(field) FROM your_table
then use event OnAccentStringConvert and uppercase S String as follows:
function TYourFormName.DBGrridNameAccentStringConvert(Sender: TObject; const S: string): string;
begin
Result := UpperCase(S)
end;
This works very ugly, but at least works. Or you may just create filter by yourself for every table.

Delphi 2007 Adoquery Parameters not working

ADOQuerySelect.Close;
ADOQuerySelect.SQL.Add(' AND (дата_заказа between #'+dat+'# and #'+da+'#)');
if ComboBox6.Text <> '' then
begin
ADOQuerySelect.Parameters.ParamByName('Name').Value := ComboBox6.Text ;
ADOQuerySelect.SQL.Add(' AND (Наименование = :Name)');
end;
ADOQuerySelect.Open;
I use Delphi 2007, MS Access. And i dont now how work with parameters. On this code, i have error: parameter Name not found. I tried many other variants of code, but they all not working. I add parameter Name via GUI with datatype ftstring;
Changing SQL in your code clears the existing parameters, so there's no parameter called 'Name' at the time you try to set its value. You then create the Name parameter, but it's too late.
Change the order of your statements:
ADOQuerySelect.Close;
ADOQuerySelect.SQL.Add(' AND (дата_заказа between #'+dat+'# and #'+da+'#)');
if ComboBox6.Text <> '' then
begin
ADOQuerySelect.SQL.Add(' AND (Наименование = :Name)');
ADOQuerySelect.Parameters.ParamByName('Name').Value := ComboBox6.Text ;
end;
ADOQuerySelect.Open;
You should be using parameters for all your replacements, BTW. Let the database driver handle conversions and date formats and quoting values and all of that for you.
In the object inspector ADOQuerySelect should have 'Name' among list of parameters.
You can also use the following code to create the parameter 'Name':
with ADOQuerySelect.Parameters.AddParameter do
begin
Name := 'Name';
DataType := ftString;
end;

Adding Many (UDFs) Validation Functions to Oracle - Which Method Run Fastest

I have to move around 50+ validation functions into Oracle. I'm looking for the approach that runs fastest, but also would like to get around a boolean issue if possible. The return object for them all needs to be the same so that the application can react off the result in a consistent fashion and alert the user or display whatever popups, messages we may need. I created a valObj for this, but not sure yet if that is the best approach. The return format can be changed because the front-end that reacts off of it is not developed yet. In the end it will contain many different validation functions, from integer, number, phone, email, IPv4, IPv6, etc... This is what I have so far...
/***
This is the validation object.
It stores 1 for valid, 0 for not valid and some helper text that can be relayed back to the user.
***/
create or replace type valObj as object (
result number(1),
resultText varchar(32000)
);
/***
Coming from ColdFusion this seems clean to me but the function
will end up being a couple thousand lines long.
***/
create or replace function isValid(v in varchar2, format in varchar2)
return valObj
is
test number;
begin
if format = 'number' then
begin
test := to_number(v);
return valObj(1,null);
exception when VALUE_ERROR then return valObj(0,'Invalid number. Valid formats are: 12345, 12345.67, -12345, etc...');
end;
elsif format = 'integer' then
null; --TO DO
elsif format = 'email' then
null; --TO DO
elsif format = 'IPv4' then
null; --TO DO
elsif format = 'IPv6' then
null; --TO DO
end if;
--dozens of others to follow....
end;
/
/* Example Usage in SQL */
select isValid('blah','number') from dual; -- returns: (0, Invalid number. Valid formats are: 12345, 12345.67, -12345, etc...)
select isValid('blah','number').result from dual; -- returns: 0
select isValid('blah','number').resulttext from dual; -- returns: Valid formats are: 12345, 12345.67, -12345, etc...
select isValid(1234567890.123,'number') from dual; -- returns: 1,{null}
select isValid(1234567890.123,'number').result from dual; -- returns: 1
select isValid(1234567890.123,'number').resulttext from dual; -- returns: {null}
/* Example Usage in PL/SQL */
declare
temp valObj;
begin
temp := isValid('blah','number');
if (temp.result = 0) then
dbms_output.put_line(temp.resulttext);
else
dbms_output.put_line('Valid');
end if;
end;
/
My questions are:
When using it in PL/SQL I would love to be able to do boolean checks instead like this: if (temp.result) then but I can't figure out a way, cause that won't work in SQL. Should I just add a 3rd boolean attribute to the valObj or is there another way I don't know of?
These validation functions could end up being called within large loops. Knowing that, is this the most efficient way to accomplish these validations?
I'd appreciate any help. Thanks!
UPDATE: I forgot about MEMBER FUNCTIONS. Thanks #Brian McGinity for reminding me. So I'd like to go with this method since it keeps the type and its functions encapsulated together. Would there be any speed difference between this method and a stand-alone function? Would this be compiled and stored the same as a stand-alone function?
create or replace type isValid as object (
result number(1),
resulttext varchar2(32000),
constructor function isValid(v varchar, format varchar) return self as result );
/
create or replace type body isValid as
constructor function isValid(v varchar, format varchar) return self as result as
test number;
begin
if format = 'number' then
begin
test := to_number(v);
self.result := 1;
self.resulttext := null;
return;
exception when VALUE_ERROR then
self.result := 0;
self.resulttext := 'Invalid number. Valid formats are: 12345, 12345.67, -12345, etc...';
return;
end;
elsif format = 'phone' then
null; --TO DO
end if;
--and many others...
end;
end;
/
/* Example Usage in SQL */
select isValid('a','number') from dual;
/* Example Usage in PL/SQL */
declare
begin
if (isValid('a','number').result = 1) then
null;
end if;
end;
/
TEST RESULTS:
/* Test isValid (the object member function), this took 7 seconds to run */
declare
begin
for i in 1 .. 2000000 loop
if (isValid('blah','number').result = 1) then
null;
end if;
end loop;
end;
/* Test isValid2 (the stand-alone function), this took 16 seconds to run */
declare
begin
for i in 1 .. 2000000 loop
if (isValid2('blah','number').result = 1) then
null;
end if;
end loop;
end;
Both isValid and isValid2 do the same exact code, they just run this line test := to_number(v); then do the exception if it fails and return the result. Does this appear to be a valid test? The Object member function method is actually faster than a stand-alone function???
The stand-alone function can be much faster if you set it to DETERMINISTIC and if the data is highly repetitive. On my machine this setting decreased run time from 9 seconds to 0.1 seconds. For reasons I don't understand that setting does not improve performance of the object function.
create or replace function isValid2(v in varchar2, format in varchar2)
return valObj
deterministic --<< Hit the turbo button!
is
test number;
begin
if format = 'number' then
begin
test := to_number(v);
return valObj(1,null);
exception when VALUE_ERROR then return valObj(0,'Invalid number. Valid formats are: 12345, 12345.67, -12345, etc...');
end;
end if;
end;
/
May also want to consider utilizing pls_integer over number. Don't know if it will buy you much, but documents suggest some gain will be had.
http://docs.oracle.com/cd/B10500_01/appdev.920/a96624/03_types.htm states,
"You use the PLS_INTEGER datatype to store signed integers. Its magnitude range is -2*31 .. 2*31. PLS_INTEGER values require less storage than NUMBER values. Also, PLS_INTEGER operations use machine arithmetic, so they are faster than NUMBER and BINARY_INTEGER operations, which use library arithmetic. For efficiency, use PLS_INTEGER for all calculations that fall within its magnitude range."

How to union data from different databases?

I came across the necessity to union two selects from different databases, namely paradox (in bde) and ms sql server.
Currently bde (through TQuery) is used only in this part of the programm (i.e. dbgrid). Now I need to add some data stored in ms sql server database (with which I usually use TADOQuery) to the same grid.
Although queries are executed over completely different tables, the result set of columns is named and typed similarly (I mean, if I had these tables, say, in ms sql server database, I could use a trivial union for that).
Is there any way to unite recordsets selected from these in delphi7 that I could use the result as a data source for a dbgrid?
You could use a clientdataset, created by the definitions of eg. the dataset of your SQL-Server dataset and add data of your paradox dataset. TFieldDefArray can be empty in your case.
type
TMyFieldDef = Record
Name: String;
Size: Integer;
DataType: TFieldType;
end;
TFieldDefArray = array of TMyFieldDef;
function GetClientDSForDS(ADataSet: TDataSet; AFieldDefArray: TFieldDefArray; AClientDataSet: TClientDataSet = nil; WithRecords: Boolean = true)
: TClientDataSet;
var
i: Integer;
Function NoAutoInc(ft: TFieldType): TFieldType;
begin
if ft = ftAutoInc then
Result := ftInteger
else
Result := ft;
end;
begin
if Assigned(AClientDataSet) then
Result := AClientDataSet
else
Result := TClientDataSet.Create(nil);
Result.Close;
Result.FieldDefs.Clear;
for i := 0 to ADataSet.FieldCount - 1 do
begin
Result.FieldDefs.Add(ADataSet.Fields[i].FieldName, NoAutoInc(ADataSet.Fields[i].DataType), ADataSet.Fields[i].Size);
end;
for i := 0 to High(AFieldDefArray) do
Result.FieldDefs.Add(AFieldDefArray[i].Name, AFieldDefArray[i].DataType, AFieldDefArray[i].Size);
Result.CreateDataSet;
for i := 0 to ADataSet.FieldCount - 1 do
begin
Result.FieldByName(ADataSet.Fields[i].FieldName).DisplayLabel := ADataSet.Fields[i].DisplayLabel;
Result.FieldByName(ADataSet.Fields[i].FieldName).Visible := ADataSet.Fields[i].Visible;
end;
if WithRecords then
begin
ADataSet.First;
while not ADataSet.Eof do
begin
Result.Append;
for i := 0 to ADataSet.FieldCount - 1 do
begin
Result.FieldByName(ADataSet.Fields[i].FieldName).Assign(ADataSet.Fields[i]);
end;
Result.Post;
ADataSet.Next;
end;
end;
end;
another attempt might be creating a linked server for paradox, I didn't try that...
http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/SQL_Server_2008/Q_24067488.html
No problem with AnyDAC LocalSQL. You can execute SQL's with any DataSet, not only select SQL, insert, update, delete SQL too.
You can use the Built-in TClientDataSet functionality to union the data by appending the data from the second dataset to the data of the first one.
There are different ways to do it, my preferred one because the simple code would be to add two DataSetProviders and link it to each of your DataSets, for example
dspBDE.DataSet := MyTQuery;
dspADO.DataSet := MyAdoQuery;
Then, to open your DataSets, you can just do:
MyClientDataSet.Data := dspBDE.Data;
MyClientDataSet.AppendData(dspADO.Data, True);
To make this to work, both DataSets have to match the field number and data types. Since your structures are similar, you can work by typecasting in your SQL if this does not happen automatically.
BDE supports (or supported) heterogeneous queries
This allows queries to span more than one dataset, but with a limited SQL syntax.
IIRC I used a few over a decade ago for some quick'n'dirty datamerges, but I can't remember the specifics - I haven't touched BDE for years.
Several years ago (Delphi 7) i used TxQuery, but i'dont know if it is still in development
I have found this link

Error while executing sql script!

I am defining a variable in "userdata.sql",its contents are
SET DEFINE ON;
DEFINE name = Gaurav
DEFINE today =10/10/2011 --variable that contain date value.
==================================================================================
I am creating another file called xyz.sql
#userdata.sql
DECLARE
v_date DATE;
v_name varchar2(10);
BEGIN
v_date:='&today';
v_name:='&name';
dbms_output.put_line('name is '||v_name);
dbms_output.put_line('date is '||v_date);
end;
On execution of xyz.sql its throwing an error
ora-01840 input value not long enough for date format.
Please suggest the solution to it.
The RDBMS i am using is ORACLE
Change this line:
v_date:='&today';
to:
v_date:=to_date('&today','DD/MM/YYYY');
i.e. specify the date format (it could be 'MM/DD/YYYY' instead).