You have a couple of flaws in your code.
First, you don't need IsEmpty, and you don't need either call to First. When you first open a query, the dataset is automatically set at the first row, and you can omit IsEmpty if you know you're going to iterate over the rows.
Second, you should never SELECT without a WHERE clause and then filter the data afterward. The only reason to SELECT without a WHERE is if you're absolutely certain you need every single row (and column) from the table. If you don't, add a WHERE in order to limit the number of rows that are returned from the server (and to avoid having to write so much code to filter it on the client side).
Try something like this instead. I don't know what datatype Fields[2] or Frame11.ID are, so I'm going to treat them as string as your existing code does. If they're not strings, then change both references to the actual data type needed. I'm also going to presume that Fields[2].FieldName is ID; again, if it's not, change the code accordingly.
procedure TFormOperator.TabSheetShowPapersShow(Sender: TObject);
var
GridRow: Integer;
begin
SQLQueryShowPapers.SQL.Text := 'SELECT * FROM papers WHERE ID = :ID';
SQLQueryShowPapers.Parameters.ParamByName('ID').Value := Frame11.ID;
SQLQueryShowPapers.Open; // No need for First. Happens automatically
StringGridShowPapers.RowCount := 1;
// No need for IsEmpty. If no rows were returned, this loop will not be entered
while not SQLQueryShowPapers.EOF do
begin
StringGridShowPapers.RowCount := StringGridShowPapers.RowCount + 1;
GridRow := StringGridShowPapers.RowCount - 1;
StringGridShowPapers.Cells[0, GridRow] := SQLQueryShowPapers.Fields[0].AsString;
StringGridShowPapers.Cells[1, GridRow] := SQLQueryShowPapers.Fields[1].AsString;
StringGridShowPapers.Cells[2, GridRow] := SQLQueryShowPapers.Fields[2].AsString;
SQLQueryShowPapers.Next;
end;
end;
As an aside, I'd do a couple of things:
Most importantly, stop using SELECT * and actually list the columns you need. It's easier to maintain the code, and it reduces overhead of moving data from the server across the network that you're not going to use.
Also, stop using hard-coded references to field positions (Fields[0], Fields[1], etc.). It's error prone, it will bite you in the backside when a column changes in the future, and it makes the code impossible to maintain 6 months from now when you don't remember exactly what order the columns are in or someone else needs to work with your code. Either add persistent fields to your query or use FieldByName to retrieve them by name.
Shorten the variable names to avoid typing somewhat. SQLQueryShowPapers, for instance, could just be QryPapers (unless you have some other type of query than a SQL query, that is), and StringGridShowPapers could be GridPapers or PaperGrid.
You'll note I added a local integer variable GridRow to reduce the typing required for all the repeated calls to StringGridShowPapers.RowCount - 1 in every access to Cells.
You'll also note I made it simpler to deal with adding new rows to StringGridShowPapers in the loop.
I also removed the need to test Fields[0].AsString = Frame11.ID by adding a parameter and a WHERE clause to your SQL statement. It also reduces the amount of data that has to pass from the server across the network, reduces the memory requirements of your application, and cuts the amount of time you spend unnecessarily reading rows you won't be using and skipping them (iterations through the loop). In other words, I removed the entire if test.
Lastly, you could reduce this entire code down to three lines (setting the SQL.Text, assigning a value to the parameter, and opening the query) if you got rid of the TStringGrid entirely and used a TDBGrid instead. It's specifically designed to display data from a dataset. All you do is add the TDBGrid to your form in place of the TStringGrid, drop a TDataSource as well, connect the TDBGrid.DataSource to theTDataSourceand theTDataSource.DataSet` to your query. Then open your query as usual, and the grid is automatically populated with the data with zero lines of code.
SQLQueryShowPapers.Next;is insideIF BEGIN... END. you need move it out from theIFIsEmptywas buggy at some time. You may useif not (Query.Bof and Query.Eof) then. Except that, move thatNextcall outside theifblock and remove bothFirstcalls.