I use this code for multi selecting rows in dataset. It works fine but if I execute it second, third etc time new rows are added to last rows. How empty bookmarklist of last selected rows?
var
sql: string;
i:integer;
query1.close;
query1.open;
query1.Filtered:=false;
for i := 0 to dbgrid1.SelectedRows.Count-1 Do Begin
dbgrid1.DataSource.DataSet.GotoBookmark(dbgrid1.SelectedRows.Items[i]);
s:=s+','+inttostr(dbgrid1.DataSource.DataSet.FieldByName('ID').AsInteger);
end;
delete(s,1,1);
sql:='ID in('+s+')';
query1.Filter:= sql;
query1.Filtered:=true;
frxReport1.LoadFromFile(ExtractFileDir(ExtractFileDir(ExtractFileDir(ExtractFilePath(ParamStr(0)))))+'\FastReports\Labels_DocOut_id.fr3');
frxReport1.PrepareReport;
frxReport1.ShowPreparedReport;
I tried:
query1.close; query1.open;
DBGrid1.SelectedRows.CurrentRowSelected := false;
dbgrid1.DataSource.DataSet.delete;
DBGrid1.SelectedRows.clear;
DBGrid1.SelectedRows.delete;
but without success.
Related
Delphi 10.4.2, Fast Report 6.
I use TFDQuery and TDbGrid components.
TDbGrid options: RawSelected,MultiSelected, AlwaysShowSelection=true
RangeBegin and RangeEnd of FrxDbDataset=rbCurrent.
If I select, for example, 3 rows (left ctrl+mouse) then SelectedRows.Count gets value 3 (as breakpoint shows) but is printed columns of only one row (last in numbering selected row in dbgrid). How to print columns of all selected rows? Is it possible without memtable or clientdataset?
query1.sql.text:='select * from datailtable where mastertable_id=:id';
query1.open;
dbgrid1.SelectedRows.CurrentRowSelected:=true;
for i := 0 to DBGrid1.SelectedRows.Count-1 Do Begin
DBGrid1.DataSource.DataSet.GotoBookmark(DBGrid1.SelectedRows.Items[i]);
end;
frxReport1.LoadFromFile(ExtractFilePath(ParamStr(0))+'Doc_id.fr3');
frxReport1.PrepareReport;
frxReport1.ShowPreparedReport;
UPDATE. solution:
var str, sSql, s: string;
Query1.filtered:=false;
sSql:='select * from datailTable where Master_id=:id';
for i := 0 to DBGrid1.SelectedRows.Count-1 Do Begin
DBGrid1.DataSource.DataSet.GotoBookmark(DBGrid1.SelectedRows.Items[i]);
s:=s+','+inttostr(DBGrid1.DataSource.DataSet.FieldByName('ID').AsInteger);
end;
delete(s,1,1);
str:='ID in('+s+')';
Query1.filter:=str;
Query1.filtered:=true;
frxReport1.LoadFromFile(ExtractFilePath(ParamStr(0))+'Doc_id.fr3');
frxReport1.PrepareReport;
frxReport1.ShowPreparedReport;
RangeBegin must be rbFirst, RangeEnd- reLast.
I want to add items from a query into a TListView using a for loop. But I get an error saying 'Too many actual parameters' from the ListViewShifts.Items.Add() line. What is the correct way of adding to the list from a query?
Qry := TFDQuery.Create(DBConnection);
Qry.Connection := DBConnection;
Qry.SQL.Text := 'SELECT Count(10) FROM Bookings WHERE NurseNo=:nurseID;';
Qry.Params.ParamByName('nurseID').AsInteger := NurseID;
Qry.Active := True;
//Fill the list view with the shifts that have the nurses ID
for Count := 0 to 10 do
begin
ListViewShifts.Items.Add(Qry.Fields[Count].AsString);
end;
You need to consider the following:
If your ListViewShifts variable is TListView, method ListViewShifts.Items.Add doesn't expect parameters. This is the reason for Too many actual parameters error.
SQL statement SELECT Count(10) FROM Bookings WHERE NurseNo=:nurseID; will return result set with only one column.
If you want to get the first 10 rows, then probably your statement should be: SELECT TOP(10) FROM Bookings WHERE NurseNo=:nurseID;
Use First, Eof and Next dataset methods to fetch records from your result set.
Next basic example shows how to add 10 items in your TListView:
procedure TMainForm.btnGet(Sender: TObject);
var
li: TListItem;
begin
Qry := TFDQuery.Create(DBConnection);
Qry.Connection := DBConnection;
Qry.SQL.Text := 'SELECT TOP(10) FROM Bookings WHERE NurseNo=:nurseID;';
Qry.Params.ParamByName('nurseID').AsInteger := NurseID;
Qry.Active := True;
Qry.First;
for Count := 1 to 10 do
begin
Qry.Next;
li := ListViewShifts.Items.Add;
li.Caption := Qry.Fields[0].AsString;
end;
(*
Qry.First;
while not Qry.Eof do begin
li := ListViewShifts.Items.Add;
li.Caption := Qry.Fields[0].AsString;
Qry.Next;
end;
*)
end;
VAR
SY1:INTEGER;
mydata:string;
begin
mydata:='mydatabasename';
qry_tables.Close;
qry_tables.SQL.Clear;
qry_tables.SQL.text:= 'SELECT TABLE_NAME NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = '+QuotedStr(mydata);
qry_tables.Open;
ListViewShifts.Clear;
for SY1 := 1 to qry_tables.RecordCount do
begin
ListViewShifts.Items.Add(qry_tables.FieldByName('NAME').TEXT);
qry_tables.NEXT;
end;
i used mysql
In order to show my data in some order, I have ORDER column. So I can move up and down rows. That is already working, I just swap ORDER number for the affected rows. My problem is, when I delete a row, I need to reorder all other rows. To show the rows in the proper order I use the .IndexFieldNames := 'ORDER', but when I iterate through all rows and assign the new ORDER number, with active index its pretty slow. When I remove the .IndexFieldNames := '', then the rows are not in the correct order anymore, and the new order is wrong.
Here is my code:
class procedure TDataModuleEx.ReOrderColumn(const aDataSet: TClientDataSet;
const aFieldName: string; aResetClone: Boolean);
var
clone: TClientDataSet;
newOrderNo: Integer;
begin
newOrderNo := 0;
clone := TClientDataSet.Create(nil);
try
clone.CloneCursor(aDataSet, aResetClone);
clone.IndexFieldNames := aFieldName;
clone.IndexFieldNames := ''; //Indexed Edit is too slow
clone.First;
while not clone.eof do
begin
Inc(newOrderNo);
clone.Edit;
clone.FieldByName(aFieldName).AsInteger := newOrderNo;
clone.Post;
clone.Next;
end;
finally
clone.Free;
end;
end;
How can I reorder my rows after one is deleted efficiently?
I made some testing on a table with 10 000 records. Procedure ReOrderColumn made renumbering for about 3 seconds. ClientDataSet. ApplyUpdate took about 30 seconds.
Total about 33 seconds.
I wrote stored procedure in Firebird database which made renumbering for about 3 seconds.
SET TERM ^ ;
create or alter procedure REORDER
as
declare variable ID integer;
declare variable I integer;
BEGIN
i = 0;
FOR
select new_table.id
from new_table
order by FORDER
INTO :ID
as cursor tcur
DO
BEGIN
i = :i + 1;
update new_table t set t.forder = :i
where current of tcur;
END
END^
SET TERM ; ^
From Delphi
procedure Reorder;
begin
//Apply changes to server
dm1.ClientDataSet1.ApplyUpdates(0);
//execute stored procedure
dm1.spReorder.ExecProc; <--- ABOUT 3 SEC FOR 10 000 records
//Refresh dataset
dm1.ClientDataSet1.Close;
dm1.ClientDataSet1.Open;
end;
I have a string grid, from which i can delete columns. I defined a CustomStringGrid type that allows me to use DeleteColumn method.
This is how it looks:
TCustomStringGrid = class(TStringGrid)
[...]
With tCustomStringGrid(mygrid) do
DeleteColumn(col)
end;
IS there something similar to add a column? I've tried InsertColumn but it doesn't seem to exist. I want to add a column at a particular position. In fact, if a user deletes a column i have an undo button which i want to reinsert the deleted column (i'm keeping the data in an array so i can recreate the column but i don't know how to insert one in a particular position).
Thank you!
It's not built in but easy to emulate, with ColCount = ColCount + 1 and MoveColumn from a HackClass.
type
THackGrid=Class(Grids.TCustomGrid)
End;
Procedure InsertColumn(G:TStringGrid;Position:Integer);
begin
if Position<G.ColCount then
begin
G.ColCount := G.ColCount + 1;
THackGrid(g).MoveColumn(G.ColCount - 1,Position);
end;
end;
procedure TMyForm.Button1Click(Sender: TObject);
begin
InsertColumn(StringGrid1,1);
end;
THack grid is not working, maybe it is ok when both cols are visible, but that works always :
Procedure MoveColumn(G:TStringGrid;OldPosition : integer;NewPosition:Integer);
var
i : integer;
temp : string;
begin
for i := 0 to g.rowcount - 1 do
begin
temp := g.cells[OldPosition,i];
g.cells[OldPosition,i] := g.cells[NewPosition,i];
g.cells[NewPosition,i] := temp;
end;
end;
I want to delete multiple selected records which I have displayed at TDBAdvGrid. A number of records are being selected by checking checkbox in front of them. After clicking on Delete button it triggers procedure as follows. It is returning values of selected rows id successfully only problem with deletion of all records. It deletes only first selected record.
procedure TForm5.Button3Click(Sender: TObject);
var
i,j,idn: Integer;
State: Boolean;
begin
j := 0;
for i := 1 to DBAdvGrid1.RowCount - 1 do
begin
if DBAdvGrid1.GetCheckBoxState(1,i,state) then
begin
if state then
begin
idn := StrToInt(DBAdvGrid1.Cells[6,i]);
UniQuery1.SQL.Text := 'Delete from userplays where id = :id';
UniQuery1.ParamByName('id').AsInteger := idn;
UniQuery1.ExecSQL;
end;
end;
end;
end;
It is deleting only first record in lineup. After deleting first record it breaks for loop and control goes back to TDBAdvGrid with updated data after delete.
Final code based on suggestion is as follows
j := 0;
DBAdvGrid1.BeginUpdate;
for i := 1 to DBAdvGrid1.RowCount - 1 do
begin
showmessage('inside rowcount loop');
if DBAdvGrid1.GetCheckBoxState(1,i,state) then
begin
if state then
begin
DBAdvGrid1.DataSource.DataSet.First;
DBAdvGrid1.DataSource.DataSet.MoveBy(i - 1 - j);
DBAdvGrid1.DataSource.DataSet.Delete;
j := j+1;
continue;
end;
end;
end;
This code works perfectly only when PageMode := False
Based on the suggestion above, I would like to make another suggestion...
//DBAdvGrid1.BeginUpdate;
query.First;
for i := 1 to DBAdvGrid1.RowCount - 1 do
begin
if DBAdvGrid1.GetCheckBoxState(1,i,state) then
begin
if state then
begin
//you can do whatever you want with the current selected record
end;
end;
query.Next;
end;
I think this is easier then using the MoveBy...
I even never changed PageMode, it's still on true. No idea if it's coincidence or not.
You can use cyBookmarks in the OnCheck event , with Virtual Table.
It creates a list of all records selected, and you can list them with
cyBookmarks.bookmarklits.count, so my example is like this :
procedure TForm2.cyDBGrid1CheckBoxClick(Sender: TObject);
begin
if cyBookmarks1.AddCurrentRecord then
begin
cyBookmarks1.BookmarkList.InsertBookmark(cyDBGrid1.CheckedList.CurrentRecord);
cyDBGrid1.Invalidate ;
end
else
begin
cyBookmarks1.RemoveCurrentRecord;
cyDBGrid1.Invalidate;
end;
if cyBookmarks1.BookmarkList.Count>0 then
begin
VirtualTable1.GotoBookmark(cyBookmarks1.BookmarkList.Items[0]);
lbl1.Caption:=VirtualTable1.FieldByName('N_ENREGISTREMENT').AsString;
end;
end;