Delphi 10.3.3 FireDAC: DBGrid/FDQuery/MySQL VCL
Всем привет,
У меня есть таблица с этими полями
----------------------
| id | data |
----------------------
| 1 | 0=A;1=B;2=C |
| 2 | 2=Z |
| 3 | |
| 4 | 0=Y;1=X |
| 5 | |
| 6 | |
Каждая строка данных представляет только изменение в таблице
Я хотел бы, чтобы это отображалось в DBGRID:
-----------------------
| id | C0 | C1 | C2 |
-----------------------
| 1 | A | B | C |
| 2 | A | B | Z |
| 3 | A | B | Z |
| 4 | Y | X | Z |
| 5 | Y | X | Z |
| 6 | Y | X | Z |
На данный момент я могу сделать только следующую таблицу:
-----------------------
| id | C0 | C1 | C2 |
-----------------------
| 1 | A | B | C |
| 2 | | | Z |
| 3 | | | |
| 4 | Y | X | |
| 5 | | | |
| 6 | | | |
Для получения этого результата я создаю дополнительные столбцы в событии FDQuery1.BeforeOpen И в событии OnCreateFields я заполняю каждый столбец, но я не знаю содержимое предыдущей строки,
Итак, как мне заполнить недостающие поля в DBgrid? Спасибо, Франк.
1 ответ
Я думаю, вы имеете в виду OnCalcFields
, а не OnCreateFields
.
То, что вам нужно, безусловно, возможно, либо на стороне сервера, получая необходимые значения из предыдущей строки, используя, например. подзапрос SQL или на стороне клиента с использованием вычисляемых полей. Этот ответ о том, как сделать это на стороне клиента.
Проблема с выполнением расчетов на стороне клиента с использованием другой строки набора данных заключается в том, что для этого вам нужно иметь возможность перемещать курсор набора данных во время события OnCalcFields. Однако в это время набор данных будет находиться либо в состоянии dsCalcFields, либо в состоянии dsInternalCalc. и, пока это так, вы не можете легко перейти к другой строке в наборе данных. Возможно сделать это, но требует объявления класса набора данных-потомка (TMyFDQuery), чтобы вы могли получить доступ к SetTempState
необходимо сделать возврат к предыдущему состоянию после того, как вы получили необходимую информацию от «другого» row и, если то, что вам нужно, включает более одного поля, вам нужно где-то временно хранить значения. Так что делать это таким образом становится грязно.
Гораздо более чистый подход предполагает использование функционального сходства между наборами данных FireDAC и наборами данных TClientDataSet. Одной из приятных особенностей TClientDatasSets является легкость, с которой вы можете перемещать содержимое набора данных между двумя CDS, просто выполняя
CDS2.Data := CDS1.Data;
Наборы данных FireDAC могут выполнять тот же трюк, но между любыми типами наборов данных FD. Итак, что бы я сделал в вашей ситуации:
- Добавьте FDMemTable в свою форму/модуль данных и скопируйте в него данные запроса в событии AfterOpen FDQuery следующим образом:
procedure TForm2.FDQuery1AfterOpen(DataSet: TDataSet);
begin
FDQuery1.DisableControls;
try
FDMemTable1.Data := FDQuery1.Data;
FDMemTable1.Open;
finally
FDQuery1.First;
FDQuery1.EnableControls;
end;
end;
FDQuery1.First должен заставить его повторно выполнить свои вычисляемые поля после того, как данные FDMemTable станут доступны (во время начального FDQuery1.Open этого, конечно, быть не может).
- В событии FDQuery OnCalcFields используйте подобный код, чтобы основывать значения вычисляемых полей на значениях, взятых из предыдущей строки (если, конечно, она есть, первая строка не может иметь «предыдущую» строку):
procedure TForm2.FDQuery1CalcFields(DataSet: TDataSet);
begin
if FDMemTable1.Active then begin
if FDMemTable1.Locate('ContactID', FDQuery1.FieldByName('ContactID').AsInteger, []) then begin
FDMemTable1.Prior;
if not FDMemTable1.Bof then begin
// Set FDQuery1's calculated fields that depend on prior row
FDQuery1.FieldByName('PriorRowID').AsInteger := FDMemTable1.FieldByName('ContactID').AsInteger;
end;
end;
end;
end;
В этом примере мой запрошенный набор данных имеет первичный ключ ContactID
, а вычисленное значение — это просто значение ContactID из предыдущей строки. В жизни, конечно, так Было бы более эффективно использовать постоянные переменные поля, а не продолжать вызывать FieldByName
.
Я полагаю, что другой возможностью может быть использование метода CloneCursor для получения курсора поиска для доступа к «предыдущей» строке, но я сам этого не пробовал, и в любом случае это может быть невозможно (что происходит с вычисляемыми полями в копии CloneCuror ?).
Похожие вопросы
Новые вопросы
mysql
MySQL — это бесплатная система управления реляционными базами данных (RDBMS) с открытым исходным кодом, которая использует язык структурированных запросов (SQL). НЕ ИСПОЛЬЗУЙТЕ этот тег для других БД, таких как SQL Server, SQLite и т. д. Это разные БД, которые используют свои собственные диалекты SQL для управления данными. В вопросе всегда указывайте точную версию сервера. Версии 5.x сильно отличаются по своим возможностям от версий 8+.
TStringGrid
.