Wypełnianie elementu PickList kontrolki DBGrid za pomocą SQL
Poniżej przedstawiono, jak korzystając z SQL utworzyć listę unikalnych wartości (wartości bez duplikatów) występujących w kolumnie tabeli bazy danych, a następnie wykorzystać je we własności PickList komponentu DBGrid. Własność PickList jest analogią do ComboBox występującą w gridzie.
Podczas edycji komórki grida istnieje możliwość otwarcia PickListy i wybrania z niej wartości już istniejącej, zamiast ponownego wpisywania. Korzystanie z PickListy nie jest konieczne. Można wpisać nową wartość nie korzystając z PickList.
Przyjęto, że komponent ADOTable i komponenty ADOQuery zostały umieszczone w module danych. To zalecany sposób, choć zamiast ADO można użyć innej techniki bazodanowej.
Przykład obejmuje tworzenie listy klientów (ang. customers) oraz listy produktów (ang. products). Wykorzystywane są zdarzenia tabeli zamówień (ang. orders) – BeforeInsert i BeforeEdit.
Dodano dwie metody – funkcję FindFieldIndexInGrid i procedurę FillPickList. Ponieważ parametrem pierwszej z nich jest komponent DBGrid, w interfejsie, w klauzuli uses trzeba dodać nazwę modułu DBGrids, obsługującego gridy bazodanowe. Z kolei, ponieważ metody operują na gridzie w implementacji, w klauzuli uses wpisano odwołanie do formy głównej (może to być inna forma – ta na której położony jest grid).
Pierwsza z metod znajduje wśród nazw pól występujących w gridzie nazwę zadaną w parametrze AFieldName i zwraca indeks znalezionej nazwy pola. Ten indeks jest wykorzystywany przez drugą metodę do określenia, na którym polu tabeli TOrders wykonać kwerendę SELECT DISTINCT, gdzie DISTINCT zapewnia unikalność wartości, aby następnie wstawić listę z kwerendy do własności PickList. Dwie metody zostały użyte po to, by rozdzielić różne funkcjonalności – znalezienie indeksu i wypełnienie PickListy.
Zrezygnowano z tworzenia kwerendy SQL w sposób dynamiczny i wykorzystano ADOQuery ze stałą kwerendą w polu SQL.
Ilustracja działania
Interfejs i implementacja
unit DataModule1
interface
uses
DBGrids, {...};
type
TDm = class(TDataModule)
{...}
TOrders: TADOTable;
TOrdersCustomerName: TStringField;
TOrdersProductName: TStringField;
QPickListCustomers: TADOQuery;
QPickListProducts: TADOQuery;
procedure TOrdersBeforeInsert(DataSet: TDataSet);
procedure TOrdersBeforeEdit(DataSet: TDataSet);
{...}
private
function FindFieldIndexInGrid(AGrid: TDBGrid; AFieldName: String; var AFieldNotFound: Boolean): Integer;
procedure FillPickList(AQuery: TADOQuery; AFieldName: String);
{...}
end;
var
Dm: TDm;
implementation
uses
UnitMain;
{
Funkcja znajdująca indeks nazwy pola AFieldName w gridzie AGrid.
AFieldNotFound informuje, czy zadaną nazwę znaleziono.
}
function TDm.FindFieldIndexInGrid(AGrid: TDBGrid; AFieldName: String; var AFieldNotFound: Boolean): Integer;
var
I: Integer;
begin
AFieldNotFound := True;
Result := -1;
for I := 0 to AGrid.Columns.Count - 1 do
if AGrid.Columns[I].FieldName = AFieldName then
begin
AFieldNotFound := False;
Result := I;
Break;
end;
end;
{
Procedura wypełniająca DBGridOrders.PickList dla nazwy pola AFieldName z użyciem AQuery.SQL
Rezultat kwerendy AQuery jest przepisywany do DBGridOrders.PickList.
}
procedure TDm.FillPickList(AQuery: TADOQuery; AFieldName: String);
var
IndexError: Boolean;
FieldIndex: Integer;
begin
with FormMain do
begin
FieldIndex := FindFieldIndexInGrid(DBGridOrders, AFieldName, IndexError);
if not IndexError then
begin
DBGridOrders.Columns[FieldIndex].PickList.Clear;
AQuery.Active := True;
AQuery.First;
while not AQuery.Eof do
begin
DBGridOrders.Columns[FieldIndex].PickList.Add(AQuery.FieldByName(AFieldName).AsString);
AQuery.Next;
end;
AQuery.Active := False;
end;
end;
end;
Kwerendy SQL
-- Kwerendy pobierające z tabeli Orders wszystkie występujące wartości
-- pól CustomerName i ProductName bez duplikatów (dzięki użyciu DISTINCT)
--Kwerenda w QPickListCustomers.SQL
SELECT DISTINCT CustomerName FROM Orders
ORDER BY CustomerName
--Kwerenda w QPickListProducts.SQL
SELECT DISTINCT ProductName FROM Orders
ORDER BY ProductName
Przykład użycia
{
Wywołanie metody wypełniającej PickList w zdarzeniu BeforeInsert tabeli Orders
}
procedure TDm.TOrdersBeforeInsert(DataSet: TDataSet);
begin
FillPickList(QPickListCustomers, 'CustomerName');
FillPickList(QPickListProducts, 'ProductName');
end;
{
Wywołanie metody wypełniającej PickList w zdarzeniu BeforeEdit tabeli Orders
}
procedure TDm.TOrdersBeforeEdit(DataSet: TDataSet);
begin
TOrdersBeforeInsert(DataSet);
end;