I am working on a Delphi XE5 Firemonkey Mobil app.
I use FireDac for connection.
Just trying to do a simple query insert into sQlite database and update the listview with the inserted info.
procedure TTabbedwithNavigationForm.Button4Click(Sender: TObject);
begin
DataModule1.qSelectCustomers.SQL.Text := 'insert into Invoice (Name) values(:newName)';
DataModule1.qSelectCustomers.ParamByName('newName').AsString := 'test';
DataModule1.qSelectCustomers.ExecSQL;
BindSourceDB1.DataSet.Refresh;
////LinkFillControlToField1.BindList.FillList;
end;
My problem is i am getting error.
error:= TFDQuery : Can not perform this operation on a closed dataset.
I have tried opening the dats set but no go.
Why will this not work ?
You can insert a record into a dataset with a select query like this:
DataModule1.qSelectCustomers.SQL.Text := 'SELECT * FROM Invoice';
DataModuel1.qSelectCustomers.Active := True;
DataModule1.qSelectCustomers.Append;
DataModule1.qSelectCustomers.FieldByName('Name').Value := 'test';
DataModule1.qSelectCustomers.Post;
Related
I write this code :
Var Q : TFDQuery;
begin
Q := TFDQuery.Create(Self);
Q.Connection := FDConnection1;
Q.Params.CreateParam(ftString,'N',ptOutput);// Try also ptResult
Q.Params.CreateParam(ftInteger,'ID',ptInput);
Q.SQL.Text := 'SELECT NOM FROM EMPLOYEE WHERE ID_EMP = :ID';
Q.Params.ParamByName('ID').Value := 1;
Q.Active := True;
ShowMessage( VarToStr(Q.Params.ParamByName('N').Value) );
The result should be the name of the employer.
I get an error :
'N' parameter not found
How can I get the result from the Query using the parameter?
If I can't , what is the the function of :
ptOutput
ptResult
Try this code:
procedure TForm1.ExecuteQuery;
var
SQL : String;
Q : TFDQuery;
begin
SQL := 'select ''Sami'' as NOM'; // Tested with MS Sql Server backend
try
Q := TFDQuery.Create(Self);
Q.Connection := FDConnection1;
Q.Params.CreateParam(ftString, 'Nom', ptOutput);// Try also ptResult
Q.SQL.Text := SQL;
Q.Open;
ShowMessage( IntToStr(Q.ParamCount));
Caption := Q.FieldByName('Nom').AsString;
finally
Q.Free; // otherwise you have a memory leak
end;
end;
You'll see that the created parameter no longer exists once the FDQuery is opened, because FireDAC "knows" that there is nothing it can do with it.
Then, replace Q.Open by Q.ExecSQL. When that executes you get an exception
with the message
Cannot execute command returning result set.
Hint: Use Open method for SELECT-like commands.
And that's your problem. If you use a SELECT statement, you get a result set whether
you like it or not, and the way to access its contents is to do something like
Nom := Q.FieldByName('Nom').AsString
You asked in a comment what is the point of ptOutput parameters. Suppose your database has a stored procedure defined like this
Create Procedure spReturnValue(#Value varchar(80) out)
as
select #Value = 'something'
Then, in your code you could do
SQL := 'exec spReturnValue :Value'; // note the absence of the `out` qualifier in the invocation of the SP
try
Q := TFDQuery.Create(Self);
Q.Connection := FDConnection1;
Q.Params.CreateParam(ftString, 'Value', ptOutput);// Try also ptResult
Q.SQL.Text := SQL;
Q.ExecSQL;
ShowMessage( IntToStr(Q.ParamCount));
Caption := Q.ParamByName('Value').AsString;
finally
Q.Free; // otherwise you have a memory leak
end;
which retrieves the output parameter of the Stored Proc into Q's Value parameter.
There is no need to manually create parameters. Data access components are smart enough to parse the SQL string and populate the parameters collection by themselves
Also to get the result you must read the query's fields. When you call Open on a Query component, the fields collection will be populated with the fields that you specified in the SELECT [fields] SQL statement
As a side note, I advice that you use the type-safe version to get the value from a TField or TParameter object: See more here
var
q : TFDQuery;
begin
q := TFDQuery.Create(Self);
q.Connection := FDConnection1;
q.SQL.Text := 'SELECT NOM FROM EMPLOYEE WHERE ID_EMP = :ID';
q.ParamByName('ID').AsInteger := 1;
q.Open;
ShowMessage(q.FieldByName('Nom').AsString);
end;
This is my first time doing a query with parameters. (Using Delphi Seattle and FireDAC in SQL Server)
(I'm planning on using DML once I get this working.)
Why am I getting this error:
[FireDAC][Phys][ODBC][Microsoft][SQL Server Native Client 11.0]
[SQL Server]Incorrect syntax near ':'.
with this query:
procedure TForm2.Button1Click(Sender: TObject);
var
FDParam: TFDParam;
begin
FDQuery1.SQL.Text := 'CREATE TABLE TestTable (Column1 Int)';
FDQuery1.ExecSQL;
FDQuery1.SQL.Text := 'INSERT INTO TestTable (Column1) VALUES (111)';
FDQuery1.ExecSQL; // works fine
FDParam := FDQuery1.Params.Add;
FDParam.Name := 'Column1';
FDParam.DataType := ftInteger;
FDParam.Paramtype := ptInput;
FDQuery1.SQL.Text := 'INSERT INTO TestTable (Column1) VALUES(:Column1)' ;
FDQuery1.ParamByName('Column1').AsInteger := 222;
FDQuery1.ExecSQL; // FAILS
end;
Ken and Johan: thanks for your comments.
Someone here had set the connection's ResourceOptions.ParamCreate and ParamExpand to false.
Overriding that in the FDQuery eliminated the problem.
Thank you again.
I have a grid that I use to display few query results (cxGrid1.ActiveLevel.GridView := cxGrid1DBTableView1; etc ...). On form close, I close the queries as well.
However, the former columns that were last displayed remain visible (when I return to that form again) How can I eliminate these traces of columns as well? I would like empty grid when I return to the form.
Edit : This is the query that I run :
procedure TForm2.cxRadioGroup1Click(Sender: TObject);
begin
case cxRadioGroup1.ItemIndex of
0: begin
with Form1.UniQuery3 do begin
Close;
sql.Clear;
sql.Add('select * from program_log');
Open;
cxGrid1.ActiveLevel.GridView := cxGrid1DBTableView1;
end;
end;
1: begin
with Form1.UniQuery4 do begin
Close;
sql.Clear;
sql.Add('select * from guests_log');
Open;
cxGrid1.ActiveLevel.GridView := cxGrid1DBTableView2;
end;
end;
end;
end;
Calling
cxGrid1DBTableView1.ClearItems;
Removes all traces of columns which are then unavailable if I want to run the query again.
The easiest way to accomplish this is to create another cxgridlevel > cxGrid1dbtableview. Then just call set this level on form show:
procedure TForm2.FormShow(Sender: TObject);
begin
cxGrid1.ActiveLevel.GridView := cxGrid1DBTableView3;
end;
Since it is assigned to nothing so will the grid display empty.
Calling cxGrid1DBTableView1.ClearItems will remove all columns. Just call it in your FormClose event handler. To recreate columns call cxGrid1DBTableView1.DataController.CreateAllItems function.
With Delphi 7 and SQL Server 2005 I'm trying to pass a multiline parameter (a Stringlist.text) to a TAdoQuery insert script.
The insert is successful, but when i take back data from the field, i take
Line 1 Line 2 Line 3
instead of
Line 1
Line 2
Line 3
The fieldtype in the table is nvarchar(MAX) and i can't change it to any other type, the table is not mine. I tried to change the parameter type from widestring to ftMemo, but nothing changes.
Any idea?
var
QRDestLicenze: TADOQuery;
LsLic := TStringList;
begin
LsLic := TStringList.Create;
LsLic.Add('Line 1');
LsLic.Add('Line 2');
LsLic.Add('Line 3');
QRDestLic.Parameters.FindParam('FieldName).Value := LsLic.Text;
QRDestLic.ExecSQL;
end;
I created a demo doing exactly the same thing, although using Delphi 6 and SQL Server 2008.
Memo1.Lines.Clear;
Memo1.Lines.Add('Line 1');
Memo1.Lines.Add('Line 2');
Memo1.Lines.Add('Line 3');
ADOQuery1.SQL.Text := 'INSERT INTO Absences '+
'(Employee, Date_from, Notes) '+
'VALUES (99999, ''16/04/2013'', :sNotes)';
ADOQuery1.Parameters.ParamValues['sNotes'] := Memo1.Lines.Text;
ADOQuery1.ExecSQL;
ADOQuery1.SQL.Text := 'SELECT Notes FROM Absences '+
'WHERE Employee = 99999';
ADOQuery1.Open;
Memo2.Lines.Text := ADOQuery1.FieldByName('Absence_notes').AsString;
This worked as expected, showing:
Line 1
Line 2
Line 3
in both memos.
The "Notes" field is of type VARCHAR(Max).
I left the parameter type as the default (ftString), and changed no other default settings on the TADOConnection or TADOQuery.
I was using the "Microsoft OLE DB Provider for SQL Server" as the ADO data link provider.
Could there be something else we might be able to try to reproduce your issue?
1st off I am Still a little green to Delphi so this might be a "mundane detail" that's being over looked. [sorry in advance]
I have a need to create a TSQLDataset or TClientDataSet from an Oracle 11g cursor contained in a package. I am using Delphi XE2 and DBExpress to connect to the DB and DataSnap to send the data back to the client.
I'm having problems executing the stored procedure from the Delphi code.
Package Head:
create or replace
PACKAGE KP_DATASNAPTEST AS
procedure GetFaxData(abbr varchar2, Res out SYS_REFCURSOR);
END KP_DATASNAPTEST;
Package Body:
create or replace
PACKAGE body KP_DATASNAPTEST AS
procedure GetFaxData(abbr varchar2, Res out SYS_REFCURSOR)is
Begin
open Res for
SELECT Name,
Address1,
City,
fax_nbr
FROM name
JOIN phone on name.Abrv = phone.abrv
WHERE phone.fax_nbr is not null and name.abrv = abbr;
end;
END KP_DATASNAPTEST;
I have no problem executing this procedure in SQL Developer the problem resides in this code on the DataSnap server:
function TKPSnapMethods.getCDS_Data2(): OleVariant;
var
cds: TClientDataSet;
dsp: TDataSetProvider;
strProc: TSQLStoredProc;
begin
strProc := TSQLStoredProc.Create(self);
try
strProc.MaxBlobSize := -1;
strProc.SQLConnection:= SQLCon;//TSQLConnection
dsp := TDataSetProvider.Create(self);
try
dsp.ResolveToDataSet := True;
dsp.Exported := False;
dsp.DataSet := strProc;
cds := TClientDataSet.Create(self);
try
cds.DisableStringTrim := True;
cds.ReadOnly := True;
cds.SetProvider(dsp);
strProc.Close;
strProc.StoredProcName:= 'KP_DATASNAPTEST.GetFaxData';
strProc.ParamCheck:= true;
strProc.ParamByName('abbr').AsString:= 'ZZZTOP';
strProc.Open; //<--Error: Parameter 'Abbr' not found.
cds.Open;
Result := cds.Data;
finally
FreeAndNil(cds);
end;
finally
FreeAndNil(dsp);
end;
finally
FreeAndNil(strProc);
self.SQLCon.Close;
end;
end;
I have also tried assigning the param value through the ClientDataSet without any luck.
I would not be apposed to returning a TDataSet from the function if its easier or produces results. The data is used to populate custom object attributes.
As paulsm4 mentioned in this answer, Delphi doesn't care about getting stored procedure parameter descriptors, and so that you have to it by yourself. To get params of the Oracle stored procedure from a package, you can try to use the GetProcedureParams method to fill the list with parameter descriptors and with the LoadParamListItems procedure fill with that list Params collection. In code it might look like follows.
Please note, that following code was written just in browser according to documentation, so it's untested. And yes, about freeing ProcParams variable, this is done by the FreeProcParams procedure:
var
ProcParams: TList;
StoredProc: TSQLStoredProc;
...
begin
...
StoredProc.PackageName := 'KP_DATASNAPTEST';
StoredProc.StoredProcName := 'GetFaxData';
ProcParams := TList.Create;
try
GetProcedureParams('GetFaxData', 'KP_DATASNAPTEST', ProcParams);
LoadParamListItems(StoredProc.Params, ProcParams);
StoredProc.ParamByName('abbr').AsString := 'ZZZTOP';
StoredProc.Open;
finally
FreeProcParams(ProcParams);
end;
...
end;
I don't think Delphi will automagically recognize Oracle parameter names and fill them in for you. I think you need to add the parameters. For example:
with strProc.Params.Add do
begin
Name := 'abbr';
ParamType := ptInput;
Value := ZZZTOP';
...
end;