I have a little piece of code that gets a corresponding value from database when one is entered, that is, in a database like this
Code Name
1 A
2 B
3 C
When you enter 1 in the code area, it returns A, and if you enter B in the Name area, it returns 2.
I can get this to work just fine with the following code but an error message would pop out showing "Cannot perform this operation on a closed dataset"
Does anyone know how to solve this problem? Any help would be appreciated. Thanks
procedure TStock_Bookkeeping.Stock_Code_ValueChange(Sender: TObject);
begin
Price_Per_Share_Value.Text := GetCurrentPrice(Stock_Code_Value.text);
ExecuteSQL_CodeToName(Stock_Code_Value.Text);
end;
procedure TStock_Bookkeeping.Stock_Name_ValueChange(Sender: TObject);
begin
ExecuteSQL_NametoCode(Stock_Name_Value.Text);
end;
procedure TStock_Bookkeeping.ExecuteSQL_CodeToName(const inCode: string);
var
query : TFDQuery;
begin
query := TFDQuery.Create(nil);
try
ConnectToSQLite;
query.Connection := FDConnection1;
query.SQL.Text := 'SELECT * FROM Code_Name where Code =' + '"' + inCode + '"' ;
query.Active := True;
query.Open();
while not query.Eof do
begin
Stock_Name_Value.text := query.FieldByName('Name').AsString;
query.Next;
end;
finally
query.Close;
query.DisposeOf;
end;
end;
procedure TStock_Bookkeeping.ExecuteSQL_NameToCode(const inName: string);
var
query : TFDQuery;
memTable : TFDMemtable;
begin
query := TFDQuery.Create(nil);
try
ConnectToSQLite;
query.Connection := FDConnection1;
query.SQL.Text := 'SELECT * FROM Code_Name where Name ='+'"'+ inName+'"';
query.Active := True;
query.Open();
while not query.Eof do
begin
Stock_Code_Value.text := query.FieldByName('Code').AsString;
query.Next;
end;
finally
query.Close;
query.DisposeOf;
end;
end;
Set a breakpoint and walk the code (F7):
If the Stock_Code_ValueChange event is connected to the Stock_Code_Value edit box when you change the value of Stock_Code_Value.Text you are changing the value of Stock_Name_Value.Text which then fires the Stock_Name_ValueChange event but you have not completed the Stock_Code_ValueChange event.
Add a Stock_Name_ValueOnChange := nil as the first line of the Stock_Code_ValueChange procedure and a Stock_Name_ValueOnChange := Stock_Name_ValueChange as the last line of the procedure to stop the Stock_Name_ValueChange event from firing while the Stock_Code_ValueChange event is processing.
Then do the opposite for the Stock_Name_ValueChange event.
Related
I'm trying to implement a pl sql program that export the content of all tables of a particular user in a file but i'm getting 'command not properly ended' problem whenever i run it.
here is my code:
create or replace procedure userTable(name dba_tables.owner%type)
is
cursor cur1 is select table_name from dba_tables where owner = upper(name);
cursor cur(tabName in varchar2) is select column_name from dba_tab_columns where owner = upper(name) and table_name = upper(tabName);
V$FILEP UTL_FILE.FILE_TYPE;
type dyncursor is ref cursor;
dyn dyncursor;
req varchar2(32767):='select to_char(';
lig Varchar2(32767);
i integer:=1;
begin
if existUser(name) = true then
V$FILEP := UTL_FILE.FOPEN('DIRT001','TEST09.UTL','W');
for vc1 in cur1 loop
for vc in cur(to_char(vc1.table_name)) loop
if (i=1) then
req:=req||vc.column_name||')';
i:=0;
else
req:=req||'||'||''','''||'||'||'to_char('||vc.column_name||')';
end if;
end loop;
req:=req||' from '||name||'.'||'to_char('||vc1.table_name||')';
open dyn for req;
loop
fetch dyn into lig;
exit when dyn%notfound;
dbms_output.put_line(lig);
UTL_FILE.PUT_LINE(V$FILEP,lig );
end loop;
close dyn;
end loop;
UTL_FILE.FCLOSE(V$FILEP);
else
dbms_output.put_line('user invalid');
end if;
end;
/
create or replace function existUser(name dba_users.username%type)
return boolean is
nb number :=0;
begin
select count(*) into nb from dba_users where username = upper(name);
if nb = 0 then
return false;
else
return true;
end if;
end;
/
Expanding on what has been mentioned in the comments, adding a DBMS_OUTPUT is going to show you that you have 'from schema.to_char(table_name)'.....
vc1.table_name & vc.column_name are already character (varchar2) so there is no need to do a to_char on them in the first place so just removing to_char from around all these is a good first step.
Then if it still does not work add the DBMS_OUTPUT as suggested by Arkadiusz Ćukasiewicz in the comments to see what other issues you may have.
I am trying to create an xml file from an oracle database.
I am not able to get the correct format and was wondering if I could get some assistance.
This is part of the script:
l_record_element := dbms_xmldom.createElement(l_domdoc, 'record_type');
dbms_xmldom.setAttribute(l_record_element,'desc', r_dept.public1);
l_record_node := dbms_xmldom.appendChild(l_dept_node,dbms_xmldom.makeNode(l_record_element));
my output:
<record_type desc="Public"/>
The output I need:
<record_type desc="Public">PUBLIC</record_type>
Thanks!
You need to create and append a text node with the PUBIC value.
Demo showing that coming from the same cursor that provides the record type:
set serveroutput on
declare
l_domdoc dbms_xmldom.domdocument;
l_dept_node dbms_xmldom.domnode;
l_record_node dbms_xmldom.domnode;
l_record_element dbms_xmldom.domelement;
l_record_text dbms_xmldom.domtext;
l_tmp_node dbms_xmldom.domnode;
l_xmltype xmltype;
l_buffer varchar2(32767);
begin
l_domdoc := dbms_xmldom.newDOMDocument; --(xmltype('<data />'));
for r_dept in (select 'Public' as public1, 'PUBLIC' as public2 from dual) loop
l_dept_node := dbms_xmldom.makeNode(l_domdoc);
-- code you showed
l_record_element := dbms_xmldom.createElement(l_domdoc, 'record_type');
dbms_xmldom.setAttribute(l_record_element,'desc', r_dept.public1);
l_record_node := dbms_xmldom.appendChild(l_dept_node, dbms_xmldom.makeNode(l_record_element));
-- add a text node
l_record_text := dbms_xmldom.createTextNode(l_domdoc, r_dept.public2);
l_tmp_node := dbms_xmldom.appendChild(l_record_node, dbms_xmldom.makeNode(l_record_text));
-- display the node for demo
l_xmltype := dbms_xmldom.getXmlType(l_domdoc);
dbms_xmldom.freeDocument(l_domdoc);
dbms_output.put_line(l_xmltype.getClobVal);
end loop;
end;
/
<record_type desc="Public">PUBLIC</record_type>
PL/SQL procedure successfully completed.
This is the code I've got at the moment:
procedure TfrmLogin.performQuery;
begin
query.SQL.Text := 'SELECT * FROM LoginDatabase';
query.Open;
end;
procedure TfrmLogin.FormCreate(Sender: TObject);
begin
con := TFDConnection.Create(nil);
query := TFDQuery.Create(con);
con.LoginPrompt := false;
con.Open('DriverID=SQLite;Database=C:\Users\katiee\Documents\Embarcadero\' +
'Studio\Projects\ProgramDatabase;');
query.Connection := con;
performQuery;
username := query.FieldByName('Username').AsString;
passcode := query.FieldByName('Passcode').AsString;
end;
procedure TfrmLogin.btnLoginClick(Sender: TObject);
begin
if (edtUsername.Text = username) and (edtPasscode.Text = passcode) then
frmPayInfo.show
else
if MessageDlg('The username or password entered is incorrect.', mtWarning,
[mbOK, mbCancel], 0) = mrCancel then
frmLogin.Close;
end;
Right now the code, as it doesn't read all database entries, only allows the first database entry as correct answer.
I need to be able to enter any correct combination of username and pass-code from the database and open the form.
Why not call the .Locate method on the dataset? This way you will not be opening and closing the dataset, as you would need to with using a parameterised query.
Using the .Locate method will allow you to check (based off one, or many fields) if a certain record can be found.
If the record is found .Locate will return true.
For example.
if query.Locate('username;passcode', VarArrayOf([query.FieldByName('Username').AsString, query.FieldByName('Passcode').AsString]), [loPartialKey]) then
begin
frmPayInfo.show;
end
else
begin
Showmessage('User not found, or password incorrect');
end;
I haven't got Delphi on this machine, so syntax may not be 100%.
My query,when run takes about 7 seconds to do what is supposed to.But,since its inserting about 30 records,I think it is too slow.Now,either I am running the query that is not written well or it does actually takes this much time. But that would be strange. The underlying database is SQLite and the query looks like this :
procedure TForm1.cxButton1Click(Sender: TObject);
begin
with UNIquery2 do begin
Close;
SQL.Clear;
UNIQuery1.First;
while Uniquery1.EOF = false do begin
SQL.Text:= 'INSERT INTO MYTABLE (FIELD1,FIELD2,FIELD3,FIELD4) VALUES (:a1,:a2,:a3,:a4)';
ParamByName('a1').asString := AdvOfficeStatusBar1.Panels[0].Text;
ParamByName('a2').asString := UniTable1.FieldByName('FIELD2').asString;
ParamByName('a3').asString := Uniquery1.FieldByName(',FIELD3').asString;
ParamByName('a4').Value := Uniquery1.FieldByName('FIELD4').Value;//boolean field true/false
Uniquery1.Next;
ExecSQL;
end;
end;
end;
So can someone tell me if this is OK or am I missing something ?
All fields are text except the 'a4' which is boolean (true/false).
The answer,modified (based on suuggestion from LS_dev):
procedure TForm1.cxButton1Click(Sender: TObject);
begin
with UNIquery2 do begin
Close;
SQL.Clear;
SQL.Add('INSERT INTO MYTABLE (FIELD1,FIELD2,FIELD3,FIELD4) VALUES (:a1,:a2,:a3,:a4)');
SQL.Prepare;
UniTransaction.AddConnection(UniConnection2);
UniTransaction.StartTransaction;
try
UNIQuery1.First;
while Uniquery1.EOF = false do begin
Params[0].asString := AdvOfficeStatusBar1.Panels[0].Text;
Params[1].asString := UniTable1.FieldByName('FIELD2').asString;
Params[2].asString := Uniquery1.FieldByName(',FIELD3').asString;
Params[3].Value := Uniquery1.FieldByName('FIELD4').Value;//boolean field true/false
Uniquery1.Next;
ExecSQL;
end;
UniTransaction.Commit;
finally
if UNIquery2.Connection.InTransaction then
UNIquery2.Connection.Rollback;
end;
end;
end;
Don't know Delphi, but will suggest some improvements:
You are not using a transaction. You should have something like something like auto-commit disabled and COMMIT command after all insertions;
Your SQL.Text:=... should probably be out of while. If this property set compiles SQL statement, putting it out of while will prevent unnecessary VDBE compilations;
If your intent is copying rows from one table to another (with a static field), you may doing using a single SQL command like INSERT INTO MYTABLE SELECT :a1, FIELD2, FIEDL3, FIELD4 FROM source_table, setting ParamByName('a1').asString := AdvOfficeStatusBar1.Panels[0].Text
This is generic DB usage improvement, hope gives you some direction.
Suggestion using unique SQL:
procedure TForm1.cxButton1Click(Sender: TObject);
begin
with UNIquery2 do
begin
SQL.Clear;
SQL.Add('INSERT INTO MYTABLE (FIELD1,FIELD2,FIELD3,FIELD4) SELECT ?,FIELD2,FIELD3,FIELD4 FROM UNIquery1_source_table');
Params[0].asString := AdvOfficeStatusBar1.Panels[0].Text;
ExecSQL;
end;
end;
Suggestion using improved DB handling:
procedure TForm1.cxButton1Click(Sender: TObject);
begin
with UNIquery2 do
begin
Close;
SQL.Clear;
SQL.Add('INSERT INTO MYTABLE (FIELD1,FIELD2,FIELD3,FIELD4) VALUES (:a1,:a2,:a3,:a4)');
SQL.Prepare;
UniTransaction.AddConnection(UniConnection2);
UniTransaction.StartTransaction;
UNIQuery1.First;
while Uniquery1.EOF = false do
begin
Params[0].asString := AdvOfficeStatusBar1.Panels[0].Text;
Params[1].asString := UniTable1.FieldByName('FIELD2').asString;
Params[2].asString := Uniquery1.FieldByName(',FIELD3').asString;
Params[3].Value := Uniquery1.FieldByName('FIELD4').Value;//boolean field true/false
Uniquery1.Next;
ExecSQL;
end;
UniTransaction.Commit;
end;
end;
If the SQL INSERT itself is slow, I recommend to test its execution speed in an interactive client first. Or write a simple test application which performs one hard-coded INSERT and measures its execution time.
Also you can use the debugger, logging or a profiler to find out the operation in your code which consumes time - it could be the Uniquery1.Next or the ExecSQL for example.
i am trying to print specifics detail for a specific record from a database by the following code
procedure TReportsForm.BitBtn1Click(Sender: TObject);
begin
if edit1.Text = '' then
begin
ShowMessage('Please enter the serial number first');
Edit1.SetFocus;
end
else
begin
with AddIndividualsAccountADOQuery do
begin
SQL.Clear;
SQL.Add('Select * from IndividualAccount where [Serial Number]=:Sno');
Parameters.ParamByName('Sno').Value:=edit1.Text;
Open;
Active := True;
singlememberreportform.QuickRep1.Preview;
end;
if AddIndividualsAccountADOQuery.RecordCount = 0 then
begin
ShowMessage('Empty Jonathan database to view records.');
end
end;
end;
the problem is that when i run the program, the quickreport displays all the records in the database instead of printing only records with edit1.text.in other words the report that runs is similar to just typing
procedure TReportsForm.BitBtn1Click(Sender: TObject);
begin
singlememberreportform.QuickRep1.Preview;
end;
Any idea of the problem?