InterBase i Delphi 7 - programowanie baz danych

Artur

Witam - bardzo mało jest artykułów poświeconych tej tematyce a na forum powtarzają się pytania dotyczące Delphi i InterBase więc wychodzę naprzeciw i postanowiłem napisać artykuł. A więc zaczynamy

Zakładam że każdy ma zainstalowane Delphi, ja mam Delphi 7 i wszystkie poniższe przykłady będą tworzone w takiej wersji. Proponuję zainstalować InterBase - ja zainstalowałem InterBase 6 (W1-V6.0.1.0) - razem z serwerem baz danych (po zainstalowniu koło Tray'a pojawia się ikonka) instaluje się klient czyli program IBConsole - za pomocą tego programu można zarządzać bazą danych. Praktycznie wszystko wykonuje się w nim za pomocą języka SQL. A więc uruchamiamy IBConsole - następnie klikamy na InterBase Servers wtedy pojawia sie okienko w którym musimy podać login i hasło aby zalogowac się na serwerze InterBase (jesli nic nie zmienialiśmy to jest to użytkownik SYSDBA i hasło masterkey).

Następnie z menu głównego programu wybieramy DataBase->Create DataBase
i wpisujemy alias i ewentualnie ścieżkę do pliku ja wpisałem następujące alias: koledzy i filename: H:\Documents and Settings\hawk\Pulpit\baza\ZNAJOMI.GDB - rozszerzenie gdb jest rozszerzeniem historycznym - można stosować inne rozszerzenia ale ja jestem wierny umowom :). Teraz klikamy Ok i mamy już bazę danych utworzoną. Stwórzmy teraz tabelę przechowującą informacje o znajmych (oczywiście użyjemy SQL-a). Wybieramy z menu głównego IBConsole Tools->Interactive SQL i w górnej części okna wpisujemy:

CREATE TABLE znajomi
(
   Id_znajomego           INTEGER       NOT NULL,
   Imie                   VARCHAR(20)   NOT NULL,
   Nazwisko               VARCHAR(30)   NOT NULL,
   Adres                  VARCHAR(50)   NOT NULL,
   Telefon                VARCHAR(20),
   Komorka                VARCHAR(20),
   Email                  VARCHAR(20),
   PRIMARY KEY(Id_znajomego)
);

Nie będe dokładnie opisywał składni każdego polecenia SQL - odsyłam do pomocy InterBase lub do jakiejś książki o SQL-u. Nie będę także opisywał teoretycznych aspektów projektowania baz danych. Powiem tylko że powyższa tabela nie do końca spełnia założenia tworzenia baz danych - ale jest to tylko przykład.
Klikamy przycisk Execute Query(Ctrl+E) i już mamy utworzoną tabelę.
Teraz przechodzimy do Delphi i spróbujmy napisać program obsługujący naszą bazę danych. Naszą aplikacje oprzemy na technologii IBX (InterBase Express). W Delphi 7 są dwie zakładki z komponentami InterBase i InterBase Admin.
Oki zaczynamy.

Wrzucamy na Formę komponent
IBDatabase1, IBQuery1, IBTransaction1, DataSource1(z zakładki Data Access) i DBGrid1 (z zakładki Data Control)

Ustawiamy właściwości dl tych komponentów:
dla IBDatabase1
ustawiamy właściwość DatabaseName na utworzony przed chwilą plik bazy danych H:\Documents and Settings\hawk\Pulpit\baza\ZNAJOMI.GDB.
ustawiamy właściwość DefaultTransaction na IBTransaction1
dla IBQuery1
ustawiamy właściwość Database na IBDataBase1
ustawiamy włąsciwość Transaction na IBTransaction1
klikamy na właściwość SQL i w pole SQL wpisujemy Select * From znajomi //wyświetli nam wszystkie rekordy z tabeli znajomi
dla IBTransaction1
ustawiamy właściwość DefaultDatabase na IBDataBase1
dla DataSource1
ustawiamy właściwość DataSet na IBQuery1
dla DBGrid1
ustawiamy właściwość DataSource na DataSource1
ustawiamy właściwość Option->dgRowSelect na True //żeby zaznaczać cały wiersz tabeli
ustawiamy właściwość ReadOnly na True // tylko do odczytu

Na koniec ustawiamy właściwość Active na True dla IBTransaction1 i dla IBQuery1
i już powinniśmy ujrzeć nagłówki kolumn w tabelce - zapisujemy projekt i kompilujemy
Gdy będziemy próbowali uruchomić program najpierw pojawi się okienko Database Login i trzeba będzie tam wpisać SYSDBA i masterkey (czyli login i hasło dla InterBase). Aby pozbyć się tego natrętnego okienka klikamy dwa razy na komponent IBDataBase1 i wypełniamy pola login: SYSDBA, password: masterkey i odznaczamy "ptaszka" przy opcji Login Prompt. Następnie musimy ponownie ustawić IBQuery1.Active na True;
Gdy teraz uruchomimy program nie zobaczymy już denerwującego okna.

Teraz dwukrotnie klikamy na DBGrid1 i naciskamy przycisk Add All Fields - możemy kliknąć na każde pole i pozmieniać jego właściwości takie jak wyświetlana nazwa (Title->Caption) długość (Width) i tu możemy również sprawić że pole nie będzie wyświetlane Visible na False - ja ustawiłem pole Id_znajomego żeby nie bylo widoczne

Spróbujmy teraz zrobić dodawanie nowej osoby z poziomu naszej aplikacji
Wrzucamy na formę kilka etykiet i kontrolek Edit
w Edit1 - będziemy wpisywać Imię
w Edit2 - będziemy wpisywać Nazwisko
w Edit3 - będziemy wpisywać Adres
w Edit4 - będziemy wpisywać Telefon
w Edit5 - będziemy wpisywać Telefon komórkowy
w Edit6 - będziemy wpisywać Email
Dodajemy przycisk Button1 po nacisnięciu którego będzie dopisywany rekord do bazy danych
Teraz napiszmy procedury odpowiedzialne za wyświetlanie, dodawanie i usuwanie wpisów w bazie danych

procedure zapytanieSelect(zapytanie:String; IBQuery:TIBQuery);
//procedura wykonuje zapytanie SELECT - wyświetla wszystkie dane w tabeli 
begin
    IBQuery.Close;                //zamykamy komponent Query - musimy to zrobić
    IBQuery.SQL.Clear;            //czyścimy treść starego zapytania
    IBQuery.SQL.Add(zapytanie);   //wpisujemy nowe zapytanie
    IBQuery.Open;                 //wykonujemy zapytanie Open dla zapytania typu SELECT
end;

procedure zapytanieDelete(zapytanie:String; tabela:String; IBQuery:TIBQuery; IBDatabase:TIBDataBase);
//procedura usuwa jeden wpis z bazy danych
begin
    IBQuery.Close;                //zamykamy komponent Query - musimy to zrobić
    IBQuery.SQL.Clear;            //czyścimy treść starego zapytania
    IBQuery.SQL.Add(zapytanie);   //wpisujemy nowe zapytanie
    IBQuery.ExecSQL;              //wykonujemy zapytanie ExecSQL dla zapytań typu INSERT, UPDATE, DELETE
    IBDataBase.Connected:=False;  //rozłączamy się z bazą danych - bardzo ważny moment
    IBDatabase.Connected:=True;   //łączymy się ponownie z bazą danych
    zapytanieSelect('SELECT * FROM ' + tabela + ';', Form1.IBQuery1);  //wykonujemy zapytanie SELECT w celu wyświetlenia zaktualizowanych rekordów
end;

procedure zapytanieInsert(zapytanie:String;IBQuery:TIBQuery);
//procedura dodaje jeden wpis do bazy danych
begin
    IBQuery.Close;               //zamykamy komponent Query - musimy to zrobić
    IBQuery.SQL.Clear;           //czyścimy treść starego zapytania
    IBQuery.SQL.Add(zapytanie);  //wpisujemy nowe zapytanie
    IBQuery.ExecSQL;             //wykonujemy zapytanie ExecSQL dla zapytań typu INSERT, UPDATE, DELETE
end;

function pzapytanieSelect(zapytanie:String;IBQuery:TIBQuery;co:String):string;
//funkcja wykonuje zapytanie SELECT i zwraca wartość pola zadanego jako parametr "co"
begin
    IBQuery.Close;               //zamykamy komponent Query - musimy to zrobić
    IBQuery.SQL.Clear;           //czyścimy treść starego zapytania
    IBQuery.SQL.Add(zapytanie);  //wpisujemy nowe zapytanie
    IBQuery.Open;                //wykonujemy zapytanie Open dla zapytania typu SELECT
    result:=IBQuery.FieldByName(co).AsString;  //zwracamy interesujące nas pole jako wynik funkcji
end;

Bardzo ważne linie kodu zamieszczam ponizej - odpowiedzialne sa ona za rozłączenie i ponowne połączenie z bazą danych. Po co je stosuję? Otóż gdyby ich nie było to po wykonaniu zapytania INSERT nowy wpis zostałby dodany, ale nie zobaczylibyśmy tego - trzeba by było wyłączyć i włączyć program. A po rozłączeniu i ponownym połączeniu sie z bazą danych i wykonaniu zapytania SELECT wszystko działa poprawnie - czyli widać nowododany wpis.

IBDataBase.Connected:=False;  //rozłączamy się z bazą danych - bardzo ważny moment
IBDatabase.Connected:=True;   //łączymy się ponownie z bazą danych

Mając juz wszystkie niezbędne procedury i funkcji oprogramowujemy zdarzenie naciśnięcia przycisku - dodanie jednego wpisu do bazy danych

procedure TForm1.Button1Click(Sender: TObject);
var klucz_glowny:integer;
begin
    if (Edit1.Text<>'') and (Edit2.Text<>'') and (Edit3.Text<>'') then
    //sprawdzamy czy wszelkie niezbędne informacje zostały wpisane czy użytkownik uzupełnił pola Imię Nazwisko i Adres - pozostałe pola nie są wymagane
    begin
        try  //zaczynamy blok try - chcemy pobrać maxymalną wartość klucza głownego aby kolejny rekord zapisać pod numerem o 1 większym
           klucz_glowny:=StrToInt(pzapytanieSelect('SELECT MAX(ID_znajomego) AS ID FROM znajomi ;',Form1.IBQuery1,'ID'));  //zapytanie służące do wybierania maksymalnego numeru
           klucz_glowny:=klucz_glowny+1; //zwiększamy o 1 klucz główny (dotychczasowy maksymalny numer)
        except
           on EConvertError do klucz_glowny:=1; //jeśli w bazie nie było żadnego wpisu to ustawiamy wartość klucza głównego na 1
        end;
        if not IBTransaction1.InTransaction then
           IBTransaction1.StartTransaction; //uruchamiamy transakcę
        zapytanieInsert('INSERT INTO znajomi (Id_znajomego,Imie,Nazwisko,Adres,Telefon,Komorka,Email) VALUES ("'+IntToStr(klucz_glowny)+'", "'+Edit1.Text+'", "'+Edit2.Text+'", "'+Edit3.Text+'", "'+Edit4.Text+'", "'+Edit5.Text+'", "'+Edit6.text+'"); ',Form1.IBQuery1); //wywołujemy procedurę dodającą nowe dane do bazy danych
        IBTransaction1.Commit;//ustawiamy stan transakcji na Commit czyli wszystko sie udało
    end
    else
    //jęsli użytkownik nie uzupełnił wszystkich wymaganych pól to wyświetlamy komunikat
        Showmessage('Uzupeelnij wszystkie pola');  
    zapytanieSelect('SELECT * FROM znajomi',Form1.IBQuery1,Form1.IBDatabase1);//wyświetlamy wszystkie rekordy - wykonujemy zapytanie SELECT w celu pokazania że nowy wpis został dodany do bazy danych
end;

Ok teraz nadeszła pora żeby zaprogramować usuwanie rekordu z bazy danych - zrobimy to w następujący sposób klikniemy na polu DBGRid1 wpis, który chcemy usunąć i prawym klawiszem myszy wybierzemy opcje usuń wpis - wpis wtedy zostanie usunięty. Aby to zrobić dodajmy nowy komponent - PopupMenu1(menu rozwijane po kliknięciu prawym klawiszem myszy) i dadamy do niego opcję "Usuń wpis" Dla komponentu DBGrid1 zmieniamy właściwość PopupMenu na PopupMenu1.
Następnie stwórzmy zmienną globalną co:string; - będzie ona przechowywała numer osoby który został kliknięty lewym klawiszem myszy. Oprogramujemy zdarzenie onCellClick komponentu DBGrid1

procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
    co:=DBGrid1.Fields[0].AsString;//jak klikniemy którekolwiek pole w DBGrid to zmienna co bedzie miała wartość  przechowywaną w kolumnie Nr dla klikniętego rekordu
end;

Teraz zostaje nam juz tylko oprogramowanie zdarzenia wybrania "usuń wpis" dla menu podręcznego

procedure TForm1.Usuwpis1Click(Sender: TObject);
begin
    zapytanieDelete('DELETE FROM znajomi WHERE ID_znajomego =' + co + ';', 'znajomi', Form1.IBQuery1, Form1.IBDatabase1);  //wykonujemy zapytanie Delete gdzie Id_znajomego jest równe wartości przechowywanej w zmiennej "co"
end;

Zróbmy jeszcze sortowanie tabeli wg kolumny komponentu DBGrid1, która zostanie kliknieta. W tym celu oprogramowujemy zdarzenie onTitleClick dla komponentu DBGrid1.

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var atrybut, wartosc:string;
begin
   atrybut:=Column.Title.Caption;                //pobieramy napis kolumny na który klikneliśmy
   // w poniższych if-ach liczy sie wielkość liter
   if atrybut='Nr' then wartosc:='ID_znajomego'; //w zależności od nazwy kolumny ustawiamy wartość zmiennej "wartość" na pole odpowiadające danej kolumnie przechowywane w baie danych - np jeśli klikniemy kolumnę "Nr" to posortujemy dane wg atrybutu "ID_znajomego"
   if atrybut='IMIĘ' then wartosc:='Imie';
   if atrybut='NAZWISKO' then wartosc:='Nazwisko';
   if atrybut='ADRES' then wartosc:='Adres';
   if atrybut='TELEFON' then wartosc:='Telefon';
   if atrybut='KOMÓRKA' then wartosc:='Komorka';
   if atrybut='EMAIL' then wartosc:='Email';

   zapytanieSelect('SELECT * FROM znajomi ORDER BY '+ wartosc +';',Form1.IBQuery1, Form1.IBDatabase1); //wykonujemy zapytanie SELECT z klauzulą ORDER BY sortującą rosnąco dane wg kolumny podanej w parametrze "wartosc"
   DBGRid1.Repaint;//odświerzamy DBGrid1
   DBGrid1.Refresh;
end;

Aby zrobić zapytanie UPDATE można usunąć dany rekord i dodać ponownie lub zastosować zapytanie UPDATE - ale to już nie jest trudne (mam nadzieję) po lekturze tego artykułu

Poniżej zamieszczam cały kod programu:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Db, IBDatabase, IBCustomDataSet, IBQuery, Grids, DBGrids, StdCtrls, Menus;

type
  TForm1 = class(TForm)
    IBDatabase1: TIBDatabase;
    DataSource1: TDataSource;
    IBQuery1: TIBQuery;
    IBTransaction1: TIBTransaction;
    DBGrid1: TDBGrid;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Edit5: TEdit;
    Edit6: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Button1: TButton;
    PopupMenu1: TPopupMenu;
    Usuwpis1: TMenuItem;
    procedure Button1Click(Sender: TObject);
    procedure DBGrid1CellClick(Column: TColumn);
    procedure Usuwpis1Click(Sender: TObject);
    procedure DBGrid1TitleClick(Column: TColumn);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  co:string;

implementation

procedure zapytanieSelect(zapytanie:String; IBQuery:TIBQuery; IBDataBase:TIBDataBase);
//procedura wyświetla wszystkie dane w tabeli 
begin
    IBDataBase.Connected:=False;  //rozłączamy się z bazą danych - bardzo ważny moment
    IBDatabase.Connected:=True;   //łączymy się ponownie z bazą danych
    IBQuery.Close;                //zamykamy komponent Query - musimy to zrobić
    IBQuery.SQL.Clear;            //czyścimy treść starego zapytania
    IBQuery.SQL.Add(zapytanie);   //wpisujemy nowe zapytanie
    IBQuery.Open;                 //wykonujemy zapytanie Open dla zapytania typu SELECT
end;

procedure zapytanieDelete(zapytanie:String; tabela:String; IBQuery:TIBQuery; IBDatabase:TIBDataBase);
//procedura usuwa jeden wpis z bazy danych
begin
    IBQuery.Close;                //zamykamy komponent Query - musimy to zrobić
    IBQuery.SQL.Clear;            //czyścimy treść starego zapytania
    IBQuery.SQL.Add(zapytanie);   //wpisujemy nowe zapytanie
    IBQuery.ExecSQL;              //wykonujemy zapytanie ExecSQL dla zapytań typu INSERT, UPDATE, DELETE
    zapytanieSelect('SELECT * FROM ' + tabela + ';', Form1.IBQuery1, Form1.IBDatabase1);  //wykonujemy zapytanie SELECT w celu wyświetlenia zaktualizowanych rekordów
end;

procedure zapytanieInsert(zapytanie:String; IBQuery:TIBQuery);
//procedura dodaje jeden wpis do bazy danych
begin
    IBQuery.Close;               //zamykamy komponent Query - musimy to zrobić
    IBQuery.SQL.Clear;           //czyścimy treść starego zapytania
    IBQuery.SQL.Add(zapytanie);  //wpisujemy nowe zapytanie
    IBQuery.ExecSQL;             //wykonujemy zapytanie ExecSQL dla zapytań typu INSERT, UPDATE, DELETE
end;

function pzapytanieSelect(zapytanie:String;IBQuery:TIBQuery;co:String):string;
begin
    IBQuery.Close;
    IBQuery.SQL.Clear;
    IBQuery.SQL.Add(zapytanie);
    IBQuery.Open;
    result:=IBQuery.FieldByName(co).AsString;
end;

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var klucz_glowny:integer;
begin
    if (Edit1.Text<>'') and (Edit2.Text<>'') and (Edit3.Text<>'') then
    begin
        try
           klucz_glowny:=StrToInt(pzapytanieSelect('SELECT MAX(ID_znajomego) AS ID FROM znajomi ;',Form1.IBQuery1,'ID'));
           klucz_glowny:=klucz_glowny+1;
        except
           on EConvertError do klucz_glowny:=1;
        end;
        if not IBTransaction1.InTransaction then
           IBTransaction1.StartTransaction;
        zapytanieInsert('INSERT INTO znajomi (Id_znajomego,Imie,Nazwisko,Adres,Telefon,Komorka,Email) VALUES ("'+IntToStr(klucz_glowny)+'", "'+Edit1.Text+'", "'+Edit2.Text+'", "'+Edit3.Text+'", "'+Edit4.Text+'", "'+Edit5.Text+'", "'+Edit6.text+'"); ',Form1.IBQuery1);
        IBTransaction1.Commit;
    end
    else
        Showmessage('Uzupeelnij wszystkie pola');
    zapytanieSelect('SELECT * FROM znajomi',Form1.IBQuery1,Form1.IBDatabase1);
end;

procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
    co:=DBGrid1.Fields[0].AsString;
end;

procedure TForm1.Usuwpis1Click(Sender: TObject);
begin
    zapytanieDelete('DELETE FROM znajomi WHERE ID_znajomego =' + co + ';', 'znajomi', Form1.IBQuery1, Form1.IBDatabase1);
end;

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var atrybut, wartosc:string;
begin
   atrybut:=Column.Title.Caption;
   if atrybut='Nr' then wartosc:='ID_znajomego';
   if atrybut='IMIĘ' then wartosc:='Imie';
   if atrybut='NAZWISKO' then wartosc:='Nazwisko';
   if atrybut='ADRES' then wartosc:='Adres';
   if atrybut='TELEFON' then wartosc:='Telefon';
   if atrybut='KOMÓRKA' then wartosc:='Komorka';
   if atrybut='EMAIL' then wartosc:='Email';

   zapytanieSelect('SELECT * FROM znajomi ORDER BY '+ wartosc +';',Form1.IBQuery1, Form1.IBDatabase1);
   DBGRid1.Repaint;
   DBGrid1.Refresh;
end;

end.

Treść pliku Project1.dfm

object Form1: TForm1
  Left = 183
  Top = 121
  Width = 794
  Height = 375
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 0
    Top = 168
    Width = 19
    Height = 13
    Caption = 'Imi'#281
  end
  object Label2: TLabel
    Left = 120
    Top = 168
    Width = 46
    Height = 13
    Caption = 'Nazwisko'
  end
  object Label3: TLabel
    Left = 240
    Top = 168
    Width = 27
    Height = 13
    Caption = 'Adres'
  end
  object Label4: TLabel
    Left = 416
    Top = 168
    Width = 36
    Height = 13
    Caption = 'Telefon'
  end
  object Label5: TLabel
    Left = 536
    Top = 168
    Width = 93
    Height = 13
    Caption = 'Telefon kom'#243'rkowy'
  end
  object Label6: TLabel
    Left = 656
    Top = 168
    Width = 25
    Height = 13
    Caption = 'Email'
  end
  object DBGrid1: TDBGrid
    Left = 0
    Top = 0
    Width = 786
    Height = 145
    Align = alTop
    DataSource = DataSource1
    Options = [dgTitles, dgIndicator, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgRowSelect, dgConfirmDelete, dgCancelOnExit]
    PopupMenu = PopupMenu1
    ReadOnly = True
    TabOrder = 0
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'MS Sans Serif'
    TitleFont.Style = []
    OnCellClick = DBGrid1CellClick
    OnTitleClick = DBGrid1TitleClick
    Columns = <
      item
        Expanded = False
        FieldName = 'ID_ZNAJOMEGO'
        Title.Caption = 'Nr'
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'IMIE'
        Title.Caption = 'IMI'#280
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'NAZWISKO'
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'ADRES'
        Width = 200
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'TELEFON'
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'KOMORKA'
        Title.Caption = 'KOM'#211'RKA'
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'EMAIL'
        Visible = True
      end>
  end
  object Edit1: TEdit
    Left = 0
    Top = 184
    Width = 121
    Height = 21
    TabOrder = 1
  end
  object Edit2: TEdit
    Left = 120
    Top = 184
    Width = 121
    Height = 21
    TabOrder = 2
  end
  object Edit3: TEdit
    Left = 240
    Top = 184
    Width = 177
    Height = 21
    TabOrder = 3
  end
  object Edit4: TEdit
    Left = 416
    Top = 184
    Width = 121
    Height = 21
    TabOrder = 4
  end
  object Edit5: TEdit
    Left = 536
    Top = 184
    Width = 121
    Height = 21
    TabOrder = 5
  end
  object Edit6: TEdit
    Left = 656
    Top = 184
    Width = 121
    Height = 21
    TabOrder = 6
  end
  object Button1: TButton
    Left = 0
    Top = 208
    Width = 777
    Height = 25
    Caption = 'Dodaj wpis'
    TabOrder = 7
    OnClick = Button1Click
  end
  object IBDatabase1: TIBDatabase
    Connected = True
    DatabaseName = 'H:\Documents and Settings\hawk\Pulpit\baza\ZNAJOMI.GDB'
    Params.Strings = (
      'user_name=sysdba'
      'password=masterkey')
    LoginPrompt = False
    DefaultTransaction = IBTransaction1
    IdleTimer = 0
    SQLDialect = 1
    TraceFlags = []
    Left = 64
    Top = 32
  end
  object DataSource1: TDataSource
    DataSet = IBQuery1
    Left = 216
    Top = 32
  end
  object IBQuery1: TIBQuery
    Database = IBDatabase1
    Transaction = IBTransaction1
    Active = True
    BufferChunks = 1000
    CachedUpdates = False
    SQL.Strings = (
      'Select * From znajomi')
    Left = 136
    Top = 32
  end
  object IBTransaction1: TIBTransaction
    Active = True
    DefaultDatabase = IBDatabase1
    AutoStopAction = saNone
    Left = 296
    Top = 32
  end
  object PopupMenu1: TPopupMenu
    Left = 168
    Top = 256
    object Usuwpis1: TMenuItem
      Caption = 'Usu'#324' wpis'
      OnClick = Usuwpis1Click
    end
  end
end

Treść pliku Project.dpr

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

Aby program działał na waszych kompach musicie utworzyc te pliki, utworzyć bazę danych znajomi z tabelą znajomi, i ewentualnie zmienić właściwość DataBaseName dla komponentu IBDatabase1 bo ja mam H:\Documents and Settings\hawk\Pulpit\baza\ZNAJOMI.GDB - chyba że macie bazę danych w takiej samej lokalizacji jak ja

16 komentarzy

Mam problem.... wszystko gra oprócz tego że nie mogę dodać rekordu do tabeli... wyskakuje mi błąd SQL 206 nieznana kolumna... :( nie wiem co zrobić pomóżcie ....

Witam. Mam takie pytanko. Powiedzmy ze mam juz ten generator, ktory przechowuje wartosc id ostatniego rekordu.. jak ta wartosc przypisac do zmiennnej w delphi?

Witam! Czy ktos wie jak zrobic ta baze danych ale za pomoca dwoch tabel i ja powiazac, w jaki sposob?co trzeba zrobic. Lamerskie pytanie ale dopiero sie ucze tego:) z gory dziekuje

ID_znajomego najlepiej jest generować za pomocą generatora
w wyzwalaczu ( trigger before insert ) .
Chociaż nie koniecznie tam, bo można taki generator wyzwolić już w kodzie programu.
Ale załóżmy, że tworzymy to w wyzwalaczu.
Czyli musimy wykreować taki generator (np. za pomocą programu IBConsole lub innego) instrukcją

create generator gen_id_znajomego;
commit work;

Następnie musimy wykreować trigger (wyzwalacz).
Czyli ponownie za pomocą programu IbConsole lub innego

create trigger znajomi_bef_ins for znajomi active before insert position 0
as
begin
if ( (new.id_znajomego is null) or (new.id_znajomego = 0) ) then
new.id_znajomego = gen_id(gen_id_znajomego, 1);
end;
commit work;

Przed create trigger może trzeba będzie umieścić klauzulę zamieniającą
znak średnika na inny terminator
(na przykład ^)

set term ^;

Zależy to od programu i sposobu w jaki będzie kreowany trigger.
W takim przypadku cała instrukcja SQL będzie miała postać

set autoddl off;
set term ^;

create trigger znajomi_bef_ins for znajomi active before insert position 0
as
begin
if ( (new.id_znajomego is null) or (new.id_znajomego = 0) ) then
new.id_znajomego = gen_id(gen_id_znajomego, 1);
end^
commit work^

set term ;^
set autoddl on;

#max po to w IB są generatory i wyzwalacz, żeby takich szopek nie robić. A jak w tym samym momencie dwaj klieci zrobią SELECT MAX()...
to do staniesz dwa razy to samo ID

upss ..... korekta kodu ...

poz_temp:=pzapytanieSelect('SELECT MAX(ID) as ID FROM ZAMOWIENIA',F_ADDZAM.IBQUERY,F_ADDZAM.IBTRANZ,F_ADDZAM.IBDBA,'ID');
if Length(poz_temp)>0 then
begin
pozycja:=StrToInt(poz_temp);
Inc(pozycja);
end else
begin
pozycja:=1;
end;

Troche inna forma zabezpieczenia klucza z mojego programu co pisze eConvert Error niestety nie wszedzie działa jak trzeba

do var :

poz_temp: string;
pozycja: integer;

A teraz kod "żywcem" wziety z mojego softu, może komuś się przyda

poz_temp:=pzapytanieSelect('SELECT MAX(ID) as ID FROM ZAMOWIENIA',F_ADDZAM.IBQUERY,F_ADDZAM.IBTRANZ,F_ADDZAM.IBDBA,'ID');
if Length(poz_temp>0) then
begin
pozycja:=Inc(StrToInt(poz_temp));
end else
begin
pozycja:=1;
end;

zgadzam się z Bodkiem, i trochę moich uwag:

  1. słyszałeś o czymś takim dla transakcji jak read commited
  2. zatwierdzanie lub odwoływanie transakcji (u Ciebie zamykanie i otwieranie połączenia z bazą, fuj)
  3. a co jeśli dwie osoby zacn edytować ten sam rekord w tym samym czasie?
  4. jedna transakcja do wszystkiego, toż to strasznie system obciąża
  5. w zapytaniach można stosować parametry - to powoduje, że kod jest czytelny i przerzysty

Jeśli torzysz jakiś artykuł to masz nadzieję, że ktoś z niego skożysta i będzie się na nim opierał podczas swoich początków, dlatego spoczywa na Tobie pewna odpowiedzialność ponieważ jeśli podasz złe wzorce to ktoś je od Ciebie przejmie. Po artykule widać, że sam nie do końca rozumiesz IB/FB oraz bazy danych jako takie. Temat jest tylko muśnięty i należało by z tego zrobić kilka odcinków poprzedzając je jakąś teorią.

To są moje wnioski, moim zamarem nie był obrażenie Cię ale wskazanie Ci drogi i pokazanie błędów, które jeszcze popełniasz.

Uwagi odnosnie artykulu:

  1. Bardziej chyba do gotowców niż do artykułów
  2. W ogóle nie wykorzystujesz transakcji a to przecież transakcyjna baza danych
  3. Nie piszesz nic o samym Interbase czy jego darmowym odpowiedniku bazie danych Firebird.
  4. Oprócz tabel i wierszy w tabelach są domeny, widoki, triggery, generatory, no i chyba najciekawsza i najważniejsza cecha serwerów SQL procedury
  5. Rozłączanie się z bazą danych i ponowne logowanie nie jest zbyt eleganckim sposobem uzyskania "odświeżenia widoku"
  6. Jako pierwsze podejście do Interbase w Delphi do działu gotowce - pierwsza klasa, jako artykuł o programowaniu baz danych w Delphi - nie najlepiej wyszło

Uwagi może subiektywne ale szczere (od roku programuję w OpenSource'owej kontynuacji Interbase - Firebird'zie)

Jak dla mnie całkiem całkiem, dopiero zaczynam w InterBas'ie i bazuje na tym artykule! dzieki:)

To nie jest komentarz, a raczej zapytanie czy jest w InterBase'ie takie cos jak AUTO_INCREMENT ?

Amras - jeśli w wersji Personal masz palety komponentów InterBase i Interbase Admin to na pewno będzie działać - a jeśli tych komponentów nie ma to trzeba radzić sobie inaczej... ja nie mam tej wersji Delphi to nie wiem jakie komponenty bazodanowe są w Personal - ale do Interbase da sie połączyć za pomocą dbExpress - może następny art napiszę o innych sposobach łączenia się z bazami:)

Proponuję, abyś napisał taki artykulik dla dbExpress :) Napewno byłby bardzo przydatny ~.^

a czy to działa na wszystkich wersjach Delphi 7?? Konkretnie sie pytam o wersje Personal.

Wg mnie artykulik pierwsza klasa....

_PiotR_ek - niestety nie ma takiego czegoś w InterBase jak auto_increment - ale można sobie z tym poradzić tworzac np procedurę składowaną albo organizując to za pomocą zapytań SQL - na pewno sam znajdziesz jakieś rozwiazanie:)