Wypełnianie elementu PickList kontrolki DBGrid za pomocą SQL

Artur Protasewicz

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

Ilustracja PickList i SELECT DISTINCT.png

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;

0 komentarzy