I am using TIBOQuery, with "file_full_path" is a calculated field.
First, I open query to get data from database
with qryFiles do
begin
Close;
ParamByName('id_dre').Value := Self.qryListID_DRE.AsString;
ParamByName('id_use').Value := rUser.ID_USE;
Open;
end;
Then I load qrery data into TdxMemData named memFiles:
memFiles.Close;
memFiles.LoadFromDataSet(qryFiles);
memFiles.Open;
And I show value of the "file_full_path" field:
ShowMessage(memFiles.FieldByName('file_full_path').Value);
Code in OnCalcFields of the query:
procedure TfrmDocsGoodRegisterDetail.qryFilesCalcFields(DataSet: TDataSet);
begin
DataSet.FieldByName('file_full_path').Value := WideLowerCase(ExtractFileDir(rSys.PathSDK)
+ '\' + DataSet.FieldByName('id_dre').AsString
+ '\' + DataSet.FieldByName('id_dfo').AsString
+ '\' + DataSet.FieldByName('file_name').AsString);
end;
Problem is when I put "file_full_path" at the last in qrery fields order, it works fine.
But when I change that field to any other positions (not at the bottom), it return null at ShowMessage line of code.
Does anyone know why? Please help, thank you.
Related
I have an MS SQL Server 2019 table that has a column named "Char" and it is defined as nvarchar(4).
In my sample Delphi 10.3.3 code, I have a line that says:
found := ADODataSet1.Locate('Char', '⓪', []);
There is no record in the table with such a value, but when I execute the code, Locate returns True and positions to the first record in the result set. If I add a record with that value, Locate still returns True, but positions to the first record in the result set, not the record with the desired character.
With an ASCII character, the code works as expected.
Update:
The first record in my table has "0" in the Char column. If I delete that, then Locating "⓪" returns False. If I add "⓪" to the table then Locate finds that one, but if both "⓪" and "0" are included, then it finds the ASCII digit. If I try to locate "②", it returns the record with "2" in it. The Char column, by the way is a unique index on the table.
Steps to recreate problem.
SQL Server 2019, default US installation
Create table
CREATE TABLE [dbo].[Things](
[Thing] nvarchar NOT NULL
) ON [PRIMARY]
I created a VCL application with a TADODataSet, a TMemo and a TButton
Here is the code for the button:
procedure TForm2.Button1Click(Sender: TObject);
{} procedure Add2Table(aString: string);
begin
with ADODataSet1 do begin
Insert;
FieldByName('Thing').AsString := aString;
Post;
Memo1.Lines.Add('Added: ' + aString);
end;
end;
const
cTarget = '①';
begin
with ADODataSet1 do begin
Close;
CommandText := 'Select * from Things';
Open;
Memo1.Clear;
Memo1.Lines.Add('RecordCount ' + IntToStr(RecordCount));
Add2Table('0');
Add2Table('1');
Add2Table('2');
Add2Table('⓪');
Add2Table(cTarget);
Add2Table('②');
Close; Open;
Memo1.Lines.Add('Trying to locate: ' + cTarget);
if Locate('Thing', cTarget, []) then
Memo1.Lines.Add(Format('Found %s in record %d', [
FieldByName('Thing').AsString, Recno]))
else
Memo1.Lines.Add('Not found');
end;
end;
When the program runs, instead of finding the target character, "①", it finds '1'.
I am looking for a solution to a rather serious problem I'm facing;
I want to delete a record in a dbGrid but when I click on my coded button and confirm 'Delete', I find no immediate results. In order to find the result of the deleted record, I have to close the program and re-run it. Only then do I see that the record is deleted.
My coding looks basically as follows
procedure TfrmPunte.btnDeleteClick(Sender: TObject);
var
sName, sLeerderNo : string;
begin
with dmPunte do
begin
sLeerderNo := tblLeerder['LeerderNr'];
sName := tblLeerder['NaamVan'];
if MessageDlg('Is jy seker dat jy ' + sName + ' met Leerder Nommer ' + sLeerderNo + ' wil wis van die rekords? Neem kennis dat al die rekords van sy/haar aktiwiteite ook uitgevee sal word!', mtWarning, [mbOk, mbCancel],0) = mrOK then
tblDeelname.Open;
tblDeelname.First;
while NOT tblDeelname.Eof do
begin
if tblDeelname['LeerderNr'] = sLeerderNo then
tblDeelname.Delete;
tblDeelname.Next;
end;
tblLeerder.Delete;
tblLeerder.Active := False;
tblLeerder.Active := True;
end;
end;
I am using an ADO table connected to ADO connection connected to an ACCESS database. I do appologize, some variable names are in Afrikaans.
What should I do?
Table.refresh does not work in every environment. The safe way is
Table.Active := False;
Table.Active := True;
Be aware of a problem that the actual dataset is lost. You can store it and get back locate.
XML file:
<Partner>
...
</Partner>
<Partner>
<K1>10</K1>
<K2>3</K2>
<K3>5254304</K3>
<K4>test name</K4>
<K5>637.51</K5>
<K6>159.38</K6>
<K7>802.39</K7>
<K8>0.00</K8>
<K9>802.39</K9>
<Invoices>
<Invoice>
<R1>1</R1>
<R2>4-02R0113-12</R2>
<R3>2014-12-29</R3>
<R4>2014-12-29</R4>
<R5>398</R5>
<R6>637.51</R6>
<R7>159.38</R7>
<R8>802.39</R8>
<R9>0.00</R9>
<R10>802.39</R10>
</Invoice>
</Invoices>
</Partner>
<Partner>
...
</Partner>
In my XML file I have repeating nodes <Partner>. Every partner has its own identification number written in node <K3>.
Every partner can have multiple invoices.
I need to find and read values in <R6> and <R7> in the invoice where
I know values for <R2>, <R3>, <R8>.
How do I search for specific Invoice where search criteria are multiple fields <R2>, <R3>, <R8> of partner where search criteria is field <K3> and get field values for <R6> and <R7>?
How to add multi criteria to SelectSingleNode?
My code:
procedure TfrmTest.TestReadOmniXML;
var
xml: IXMLDocument;
iNodePartner, iNodePartnerInvoice, iNodePartnerInvoiceR6, iNodePartnerInvoiceR7 : IXMLNode;
begin
xml := CreateXMLDoc;
xml.Load('c:\test.xml');
iNodePartner := XML.SelectSingleNode('//Partner[K3=' + '0254304' + ']');
iNodePartnerInvoice := iNodePartner.SelectSingleNode(
//single query works OK
'.//Racuni/Racun[R2=' + '4-02R0113-12' + ']'
//but I need to add these fields also
// ' and [R3=' + '2014-12-29' + ']' +
// ' and [R8=' + '802.39' + ']'
);
if Assigned( iNodePartnerInvoice ) then
begin
iNodePartnerInvoiceR6 := iNodePartnerInvoice.SelectSingleNode('./R6');
Label1.Caption := iNodePartnerInvoiceR6.Text;
iNodePartnerInvoiceR7 := iNodePartnerInvoice.SelectSingleNode('./R7');
Label2.Caption := iNodePartnerInvoiceR7.Text;
end;
...
end;
OmniXMLXPath doesn't support that out of the box. I have, however, added support for consecutive filters last year, but forgot to push that change to the public site :(
With the updated version, this will work:
program Project29;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
OmniXML,
OmniXMLXpath,
OmniXMLUtils;
var
xml: IXMLDocument;
node: IXMLNode;
begin
xml := CreateXMLDoc;
if XMLLoadFromFile(xml, 'c:\0\partner.xml') then begin
node := xml.SelectSingleNode('//Partner/Invoices/Invoice[R2="4-02R0113-12"][R3="2014-12-29"][R8="802.39"]');
if not assigned(node) then
Writeln('not found')
else begin
Writeln('R6=', GetNodeTextStr(node, 'R6', ''));
Writeln('R7=', GetNodeTextStr(node, 'R7', ''));
end;
end;
Readln;
end.
For now, you can get the fresh OmniXMLXPath.pas here: https://www.dropbox.com/s/nnvrz6wnmnpmxzn/OmniXMLXPath.pas
Given the example above, you can do something along the lines of:
//Partner[K2=3]/Invoices/Invoice[R1=1 and R5=398]
This gets the Ivoices of partner with K2=3 where ivoices have specific values for r1 and r5. Then, depending on how you need to process the invoices that match these criteria (e.g. if there is more than one invoice) you can then use an XPath expression (like sum or something else) to return a single value calculated from these Invoice elements.
Accordingly OmniXMLXPath.pas file, OmniXML does not support logical operation in XPath. So you can't search by 2+ attributes simultaneously.
You can select multiple nodes by calling SelectNodes('//Partner[K3=5254304]/Invoices/Invoice[R2='4-02R0113-12']) and check nodes by another attributes.
Or use MSXML parser (OmniXML_MSXML unit) if you can. This will work on your demo data:
procedure TForm1.Button1Click(Sender: TObject);
var
xml: IXMLDocument;
iNodePartner: IXMLNode;
begin
xml := CreateXMLDoc;
xml.Load('c:\test.xml');
iNodePartner := XML.selectSingleNode('//Partner[K3=5254304]/Invoices/Invoice[R2=''4-02R0113-12'' and R8=''802.39'']');
if iNodePartner = nil then
MessageDlg('Not found',mterror,[mbok],0);
end;
I have the following problem.
When I use a SQL Select statement to filter records it either gives an error or does not show the record it should.
If the field has a ' in the value it gives an sql error,
If the value is (i'm) the error says the sintax is not correct for (i'), so the single ' cuts off the rest of the sql statement,
I have tried using code to change all the ' into " and then i do not get an error, but i do not get any records either.
Below is the code:
To convert the ' into ":
Function RestoreFromsqlFormat(SQLText:String):String;
Var
Sqlnew,sqlold:String;
Begin
sqlold:=SqlText;
if Pos('"',SQLText)<>0 then
Begin
while Pos('"',sqlold)<>0 do
Begin
SqlNew:=Copy(SqlOld,0,Pos('"',SqlOld)-1)+'''';
SqlOld:=Copy(SqlOld,Pos('"',sqlOld)+1,Length(sqlOld));
End;
End;
Result:=SQlNew+SqlOld;
End;
And when calling the sql select from statement, I am getting the following error :
Active:=False;
Sql.Text:='select*from backup_folders where (user_id='''+userID+''') and (folder='''+PreparesqlFormat('my name wouldn''t be here')+''')';
Active:=True;
May i know how to overcome this error ?
This is the wrong way to use SQL.
Get rid of your PreparesqlFormat() function and use AnsiQuotedStr() instead:
Active := False;
Sql.Text := 'select * from backup_folders where (user_id=' + AnsiQuotedStr(userID, #39) + ') and (folder=' + AnsiQuotedStr('my name wouldn''t be here', #39) + ')';
Active := True;
A better option is to use a parameterized query instead. Let the DB handle quotes for you:
Active := False;
// depending on which DB component you are using, you might need to use # instead of :
Sql.Text := 'select * from backup_folders where (user_id=:PUserID) and (folder=:PFolder)';
ParamByName('PUserID').AsString := userID;
ParamByName('PFolder').AsString := 'my name wouldn''t be here';
Active := True;
i m trying to build an invoice program that holds data in an Access db. i have some tedit s, buttons, one datasource, one adotable, one dbgrid and a popup menu. database format is accdb.
Problem: i want the program to filter records while user is typing. it might filter dbgrid or tedit, doesn t matter. i somehow found some code, for example:
Table1.FilterOptions:=[foCaseInsensitive];
Table1.Filter:='Filmadi='+QuotedStr(Edit1.Text+'*');
Table1.Filtered:=true;
the code above gives this error: Project Project1.exe raised exception class eoleexception with message: Item cannot be found in the collection corresponding to the requested name or ordinal
other examples give various errors.
sincerely
onur
Use LIKE operator in your filter:
procedure DoIncrementalFilter(Dataset: TDataSet; const FieldName, SearchTerm: string);
begin
Assert(Assigned(Dataset), 'No dataset is assigned');
if SearchTerm = '' then
Dataset.Filtered := False
else
begin
Dataset.Filter := FieldName + ' LIKE ' + QuotedStr(SearchTerm + '*');
Dataset.Filtered := True;
end;
end;
Example:
DoIncrementalFilter(ADOTable1, 'Filmadi', Edit1.Text);