[Delphi, IB] przegladanie danych, transakcje

0

Witam

Mam takie pytanko. Chce sobie napisać mała aplikacje w wykorzystaniem IB i Delphi. W IB mam kilka tabel w ktorych sa dane. Z zalozenia dostep do bazy bedzie mialo kilka osob. Chodzi mi o cos takiego jak w praktyce rozwiazuje sie problem transakcji przy uzyciu Delphi. Nie chialbym stosowac CachedUpdates.

  1. Np jest taka sytuacja, odpalam sobie program i przegladam dane np komponentem TIBTable, no ale jak jest IBTable.Active = True to wtedy jestem caly czas w transakcji - a gdy jest ustawiony wysoki poziom izolowania to blokuje innym prace :(
  2. A jak dodawac rekord zeby uniknac konfliktow ? Jak bede uzywal kontrolek bazodanowych np DBEdit to jak wywolam metode append to wejde w tryb dodawania rekordu i nie wyjde z niego dopoki go nie dodam, a ja chce tak, ze wypelniam sobie dane, i jak klikam dodaj to wtedy dopiero jest rozpoczynana transakcja i sa wywolywane procedury dodajace rekord. Czy uzywacie do takich celow zwyklych kontrolek TEdit ?
  3. Mam jedna tabele glowna w ktorej przechowywuje klucze ID z innych tabeli w ktorych sa dodatkowe dane, teraz chce dodac nowy rekord do tabeli glownej. Chce aby uzytkownik nie musial znac ID z dodatkowej tabeli, tylko zeby sobie wybral z listy wartosc z tej drugiej tabeli. Wydaje mi sie ze powinienem uzyc DBLockupComboBox - ok, ale jak zmieniam wartosc na liscie, a w innym okienku mam otwarta tabele z DBGrid to tam mi przeskakuje tak jak tu zmieniam, uff. Wierze ze wiecie o co chodzi ... No i teraz mam pytanie, jak to robicie ? Czy przepisac do zwyklego ComboBox'a wartoscie z tamtej tabeli ? Czy zastosowac druga transakcje ? Ogolnie czy stosujecie zwykle kontrolki (TEdit) do obslugi pol w bazach danych ? (wydaje mi sie to nie na miejscu szczegolnie przy desktopach, ale przy bazach SQL ... ?)
1
b0bik napisał(a)
  1. Np jest taka sytuacja, odpalam sobie program i przegladam dane np komponentem TIBTable, no ale jak jest IBTable.Active = True to wtedy jestem caly czas w transakcji - a gdy jest ustawiony wysoki poziom izolowania to blokuje innym prace :(

przeglądanie tabeli jej nie blokuje, chyba że silnik BD jest źle napisany

  1. A jak dodawac rekord zeby uniknac konfliktow ? Jak bede uzywal kontrolek bazodanowych np DBEdit to jak wywolam metode append to wejde w tryb dodawania rekordu i nie wyjde z niego dopoki go nie dodam, a ja chce tak, ze wypelniam sobie dane, i jak klikam dodaj to wtedy dopiero jest rozpoczynana transakcja i sa wywolywane procedury dodajace rekord. Czy uzywacie do takich celow zwyklych kontrolek TEdit ?

zwykłe kontrolki + SQL i wszystko śmiaga pięknie

weź tylko pod uwagę taki fakt, czy blokowanie w momencie rozpoczęcia edycji nie jest dobre :>. Co jeśli najpierw zacznie edytować klient A potem ten sam rekord zechce edytować klient B, klient B skończy i zapisze zmiany potem klient A skończy i zapisze zmiany i klient B w efekcie dostanie rekord, który zapisał klient A i albo zgłupieje albo będzie musiał edytować jeszcze raz. Przecież edycja blokuje tylko REKORD a nie tabelę i fakt rozpoczęcia danego rekordu przez jednego klienta powinien być sygnalizowany pozostałym.

  1. Mam jedna tabele glowna w ktorej przechowywuje klucze ID z innych tabeli w ktorych sa dodatkowe dane, teraz chce dodac nowy rekord do tabeli glownej. Chce aby uzytkownik nie musial znac ID z dodatkowej tabeli, tylko zeby sobie wybral z listy wartosc z tej drugiej tabeli. Wydaje mi sie ze powinienem uzyc DBLockupComboBox - ok, ale jak zmieniam wartosc na liscie, a w innym okienku mam otwarta tabele z DBGrid to tam mi przeskakuje tak jak tu zmieniam, uff.

Osobne IBQuery dla DBLockupComboBoxa załatwi sprawę

Wierze ze wiecie o co chodzi ... No i teraz mam pytanie, jak to robicie ? Czy przepisac do zwyklego ComboBox'a wartoscie z tamtej tabeli ? Czy zastosowac druga transakcje ? Ogolnie czy stosujecie zwykle kontrolki (TEdit) do obslugi pol w bazach danych ? (wydaje mi sie to nie na miejscu szczegolnie przy desktopach, ale przy bazach SQL ... ?)

co do transakcji i jak je rozplanować to poszukaj bo kiedyś była długa i raczej wyczerpująca temat dyskusja na forum.
Co do tego czy DBEdit czy Edit to już sam zdecyduj. Ja osobiście preferuję DBEdit w trybie tylko do odczytu do pokazywania danych a do wstawiania, kasowania i edycji zwykłe Edity z racji używania SQLa. Kontrolek Table nie powinno się używać gdyż zostały one tylko dla zgodności z poprzednimi wersjami no i jakby nie było zaciągają całą tabelę z bazy nawet jeśli potrzebujesz jednej czy dwóch kolumn. Jeśli już chcesz mieć ich funkcjonalność to DataSet lub Query + UpdateSQL.
Ogólnie też nie jestem za edycją danych wprost w DBGridzie a za pokazaniem osobnego okienka do edycji oraz dodania nowego rekordu. Można się na tym przejechać, szczególnie jeśli końcowy użytkownik ma tendencję do robienia kilku rzeczy na raz. Wystarczy, że nieopatrznie kliknie na komórce, wciśnie spację a potem np. strzałkę w dół i już coś się skasowało a potem informatyk be bo dane giną. Dlatego jeśli do edycji czy dodania danych potrzebne jest coś więcej niż przypadkowe czynności tym lepiej na tym system wychodzi

Jeszcze do edycji to jeśli zdecydujesz się na SQLa i powiadamianie userów, że dany rekord jest edytowany to daj znać napiszę Ci jak to się robi :)

0

Witam

Przede wszystkim dziękuje za odpowiedź, obawiałem się że nie będzie kogoś rzeczowego żeby mi jej udzielić.

Misiekd napisał(a)
b0bik napisał(a)
  1. Np jest taka sytuacja, odpalam sobie program i przegladam dane np komponentem TIBTable, no ale jak jest IBTable.Active = True to wtedy jestem caly czas w transakcji - a gdy jest ustawiony wysoki poziom izolowania to blokuje innym prace :(

przeglądanie tabeli jej nie blokuje, chyba że silnik BD jest źle napisany

Racja przy domyślnym Read Commited nie blokuje tabeli (chyba żebym miła NO RECORD VERSION), ale w sumie mi to nie potrzebne wystarczy mi READ COMMITED NO WAIT RECORD VERSION ok;

b0bik napisał(a)
  1. A jak dodawac rekord zeby uniknac konfliktow ? Jak bede uzywal kontrolek bazodanowych np DBEdit to jak wywolam metode append to wejde w tryb dodawania rekordu i nie wyjde z niego dopoki go nie dodam, a ja chce tak, ze wypelniam sobie dane, i jak klikam dodaj to wtedy dopiero jest rozpoczynana transakcja i sa wywolywane procedury dodajace rekord. Czy uzywacie do takich celow zwyklych kontrolek TEdit ?
Misiekd napisał(a)

zwykłe kontrolki + SQL i wszystko śmiaga pięknie

Rozumie ze robisz to tak, że pobierasz dane z np TEdit, wstawiasz je jako parametr do Query, SQL lub StoredProc no i Execute ? W sumie racja, tylko się zastanawiam jak używanie TQuery wpłynie na bieżącą transakcje, czy polecenie COMMIT mam też wysłać przez Query czy moze użyć metody Commit komponentu TIBTransaction żeby zatwierdzić te zmiany ? Nie miałeś takich problemów ? Czy po wykonaniu zapytania aktualizującego wszystko było widać tak jak trzeba ?

Misiekd napisał(a)

weź tylko pod uwagę taki fakt, czy blokowanie w momencie rozpoczęcia edycji nie jest dobre :>. Co jeśli najpierw zacznie edytować klient A potem ten sam rekord zechce edytować klient B, klient B skończy i zapisze zmiany potem klient A skończy i zapisze zmiany i klient B w efekcie dostanie rekord, który zapisał klient A i albo zgłupieje albo będzie musiał edytować jeszcze raz. Przecież edycja blokuje tylko REKORD a nie tabelę i fakt rozpoczęcia danego rekordu przez jednego klienta powinien być sygnalizowany pozostałym.

Tutaj masz całkowitą racje, blokowanie rekordów jest jak najbardziej pożądane dla zachowania integralności BD. Tylko ja to nie moge obczaić jednej rzeczy. Bo jak używam isql.exe, to jest tak że jak wydam polecenie UPDATE aktualizujące konkretny rekord to od tego momentu on będzie zablokowany dla innych, a jak to jest przy komponentach w Delphi ? Jak wywołam metodę Edit jakiegoś zbioru (TIBTable np) no i sobie wpisuje dane do kontrolek, to czy ten rekord już jest zablokowany dla innych czy dopiero jak wywołam metode Post ? (z tego co próbuje to dopiero po wydaniu metody Post rekord będzie blokowany).

  1. Mam jedna tabele glowna w ktorej przechowywuje klucze ID z innych tabeli w ktorych sa dodatkowe dane, teraz chce dodac nowy rekord do tabeli glownej. Chce aby uzytkownik nie musial znac ID z dodatkowej tabeli, tylko zeby sobie wybral z listy wartosc z tej drugiej tabeli. Wydaje mi sie ze powinienem uzyc DBLockupComboBox - ok, ale jak zmieniam wartosc na liscie, a w innym okienku mam otwarta tabele z DBGrid to tam mi przeskakuje tak jak tu zmieniam, uff.
Misiekd napisał(a)

Osobne IBQuery dla DBLockupComboBoxa załatwi sprawę

No to fakt, tak bedzie spox.

Wierze ze wiecie o co chodzi ... No i teraz mam pytanie, jak to robicie ? Czy przepisac do zwyklego ComboBox'a wartoscie z tamtej tabeli ? Czy zastosowac druga transakcje ? Ogolnie czy stosujecie zwykle kontrolki (TEdit) do obslugi pol w bazach danych ? (wydaje mi sie to nie na miejscu szczegolnie przy desktopach, ale przy bazach SQL ... ?)

Misiekd napisał(a)

co do transakcji i jak je rozplanować to poszukaj bo kiedyś była długa i raczej wyczerpująca temat dyskusja na forum.
Co do tego czy DBEdit czy Edit to już sam zdecyduj. Ja osobiście preferuję DBEdit w trybie tylko do odczytu do pokazywania danych a do wstawiania, kasowania i edycji zwykłe Edity z racji używania SQLa. Kontrolek Table nie powinno się używać gdyż zostały one tylko dla zgodności z poprzednimi wersjami no i jakby nie było zaciągają całą tabelę z bazy nawet jeśli potrzebujesz jednej czy dwóch kolumn. Jeśli już chcesz mieć ich funkcjonalność to DataSet lub Query + UpdateSQL.
Ogólnie też nie jestem za edycją danych wprost w DBGridzie a za pokazaniem osobnego okienka do edycji oraz dodania nowego rekordu. Można się na tym przejechać, szczególnie jeśli końcowy użytkownik ma tendencję do robienia kilku rzeczy na raz. Wystarczy, że nieopatrznie kliknie na komórce, wciśnie spację a potem np. strzałkę w dół i już coś się skasowało a potem informatyk be bo dane giną. Dlatego jeśli do edycji czy dodania danych potrzebne jest coś więcej niż przypadkowe czynności tym lepiej na tym system wychodzi

Jeszcze do edycji to jeśli zdecydujesz się na SQLa i powiadamianie userów, że dany rekord jest edytowany to daj znać napiszę Ci jak to się robi :)

No to tak w skrócie mi powiedz. Masz po prostu kontrolki TEdit czy TComboBox (z wartościami LookUp z innej tabeli) i na podstawie ich zawartości budujesz zapytanie lub parametryzujesz procedure składowaną i odpalasz (Execute) ? W sumie jakbyś napisał jak Ty to robisz to będe wdzięczny.

Z tego co widze to zabieram sie do tego od niewłaściwej strony - bo zaczynam teoretyzować a nie spróbowałem jeszcze tego praktykować. Lepiej chyba będzie jak napiszę app, i zacznę ją testować wtedy pewnie część się wyjaśni część się zagatwa : )

0
Misiekd napisał(a)

Kontrolek Table nie powinno się używać ...

Święta racja, chociaż Table nieraz się przydaje, np. DBLookupComboBox podłączony do Query i wyświetlający np. nazwiska, w przypadku dwóch takich samych nazwisk - goopieje, z Table nie ma tego problemu ale pewnie takich przypadków jest niewiele.

1

to może na pocztek trochę o tranakcja, IB i IBXach. IBXy mają taką cechę, że transakcja to osobna kontrolka (nie wiem, czy jeszcze jakieś kontrolki tak mają) więc nie musisz się bawić w rozpoczynanie i kończenie transakcji z poziomu SQLa. Co więcej każde query może mieć właśny komponent IBTransaction, czyli być zamknięte we własną transakcję. Co (jeszcz)więcej każda transakcja może mieć różny poziom izolacji. Nie przeszkadza to oczywiście podpiąć grupy IBQuery pod jedną transakcję. Dodatkowo komponent IBDataBase musi mieć też transaakcję, która jest transakcją domyślną dla kontrolek, którym nie zdefiniujesz wprost innej transakcji.

Teraz z drugiej strony - kiedy są potrzebne transakcje, jak długo powinny trwać, kiedy je otwierać i zamykać.
Z założenia transakcje powinny trwać tyle, ile jest wymagane i ani trochę dłużej. Powodowane jest to tym, że im więcej transakcji i im dłużej są one otwarte tym system ma coraz trudniej (zajmują więcej zasobów, serwer BD też musi gdzieś trzymać dane o wszystkich otwartych transakcjach, zmianach w nich itd). Z tego samego powodu zalecane jest wykonywanie Transaction.Commit (Roolback) zamiast Transaction.CommitRetaining(RollbackRetaining).
A więc jak już wcześniej wspomniałem jedna transakcja musi trwać przez cały czas połączenia z serwerem i ta idealnie się nadaje do wszelkich operacji typu SELECT - selectów nie trzeba zatwierdzać - nic przecież w bazie nie zmieniają (poza SELECT ... FOR UPDATE ale to za chwilę), i serwer też nie musi trymać info o zmianach bo ich nie ma. Domyślną więc zostawiamy dla SELCTów.
Dla zapytań zmieniających dane (INSERT, UPDATE, DELETE) tworzymy oddzielne transakcje. Przy założeniu, że w danym momencie z naszego programu można usunąć/zmodyfikować/dodać tylko JEDEN rekord (okienko modalne) wystarczy nam jedna dodatkowa transakcja (może, a wręcz powinna być na datamodule). Jeśli user może otworzyć sobie do edycji, w tym samym czasie, kilka okienek (co wg mnie jest błędem bo p. Kasia otworzy sobie 20 rekordów do edycji, po czym zawoła ją p. Ania i obie pójdą na 2h na kawę a system wisi) to niestety (albo stety) dla każdego otwartego okienka trzeba mieć osobną transakcję - tu wystarczy IBTransaction umiescić na formatce do edycji/dodania/usunięcia rekordu.

b0bik napisał(a)

Rozumie ze robisz to tak, że pobierasz dane z np TEdit, wstawiasz je jako parametr do Query, SQL lub StoredProc no i Execute ?

dokładnie. Przy małych systemach mam w kodzie INSERT INTO ...(...) VALUES(:p1, :p2, ...); i tyle, przy większych (aże jeden na razie :p) doszedłem do wniosku, że jednak opłaca się posiedzieć nad bazą i napisać Stored Proc, które mi wstawiają dane do bazy (ten system cały czas żyje i często są zmiany i co kiedyś wstawiało się do dwóch tabel teraz jeszcze ląduje w trzeciej itp i prościej mi zmienić SP w bazie niż w aplikacji, kąpilować ją i uaktualniać na wszystkich stanowiskach)

W sumie racja, tylko się zastanawiam jak używanie TQuery wpłynie na bieżącą transakcje, czy polecenie COMMIT mam też wysłać przez Query czy moze użyć metody Commit komponentu TIBTransaction żeby zatwierdzić te zmiany ?

przy IBXach cała procedura wygląda tak (INSERT z kodu delphi):

procedure btnOKClick()
begin
  IBTansaction1.StartTransaction; //do niej podpięte jest IBQuery1
  with IBQuery1, SQL do
  begin
    Clear;
    Add('INSERT INTO ...(...) VALUES(:p1, :p2, ...)');
    ParamByName('p1').AsString := edtxxx.Text;
    ParamByName('p2').AsString := edtxxx.Text;
    ...
    try
      Execute;
      IBTransaction1.Commit;
    except
      IBTransaction1.Roolback;
    end;
  end;
end;

Nie miałeś takich problemów ? Czy po wykonaniu zapytania aktualizującego wszystko było widać tak jak trzeba ?

i po wykonaniu tego, jeśli wszystkie transakcje masz na ReadCommited to jak ponownie odczytasz dane to są już widoczne po zmianie

Tylko ja to nie moge obczaić jednej rzeczy. Bo jak używam isql.exe, to jest tak że jak wydam polecenie UPDATE aktualizujące konkretny rekord to od tego momentu on będzie zablokowany dla innych

bo zapewne nie startujesz tam nowej transakcji tylko działasz w domyślnej, a dopóki nie zakończysz (zatwierdzisz lub cofniesz) tej, w której robiłeś UPDATE to dane na dobą sprawe nie są w bazie i rekord ma cały czas status "edytowany". Czyli Zatwierdzenie ub cofnięcie transakcji zapisuje (lub cofa) zmiany i zdejuje znacznik "edytown"z rekordu.

, a jak to jest przy komponentach w Delphi ? Jak wywołam metodę Edit jakiegoś zbioru (TIBTable np) no i sobie wpisuje dane do kontrolek, to czy ten rekord już jest zablokowany dla innych czy dopiero jak wywołam metode Post ? (z tego co próbuje to dopiero po wydaniu metody Post rekord będzie blokowany).

z IBTable nie kożystałem więc ciężko mi powiedzieć

No to tak w skrócie mi powiedz. Masz po prostu kontrolki TEdit czy TComboBox (z wartościami LookUp z innej tabeli) i na podstawie ich zawartości budujesz zapytanie lub parametryzujesz procedure składowaną i odpalasz (Execute) ? W sumie jakbyś napisał jak Ty to robisz to będe wdzięczny.

myślę, że powyższe i ten przykład, który tam jest wystarczą :)

Z tego co widze to zabieram sie do tego od niewłaściwej strony - bo zaczynam teoretyzować a nie spróbowałem jeszcze tego praktykować. Lepiej chyba będzie jak napiszę app, i zacznę ją testować wtedy pewnie część się wyjaśni część się zagatwa : )

co do teoretyzowania to jest to raczej dobra rzecz, bo nie zabieraz się bezwiedzy o temacie, a to potrafi zniechęćć bardzo starannie :). A co do testowania rozwiązań to co sam sprawdzisz to twoje :)

Jeszcze na koniec o edycji, blokowaniu i informowaniu usera, że dany rekord jest już edytowany. (WAŻNE: musisz mieć nowait w transakcji)
Cała procedura wygląda tak

  1. user naciska Button "Edytuj" (w zmiennej ID masz ID edytowanego rekordu - dla uatwienia :))
  2. robisz IBTransaction.StartTransaction;
  3. try
    4a. UPDATE edytowana_tablica SET pole_id = pole_id WHERE pole_id = :ID - jes to tzw pusty update, który nie zmienia nic ale ustawia rekord w tryb edycji
    4b. lub SELECT * FROM edytowana_tablica WHERE pole_id = :ID FOR UPDATE WITH LOCK
    efekt dla obu będzie taki sam
  4. pokazanie okienka do edycji rekordu, pobranie danych dla comboboxów, wypełnienie editów aktualnymi wartościami rekordu itp
  5. zrobienie UPDATE
  6. IBTransaction.Commit
  7. except
    8a. wypadało by sprawdzić czy aby mamy dedlock a nie np. błąd w skłani SQL lub problem z połączeniem
    8b. ktoś już edytuje ten rekord - info dla usera
    8c. IBTransactio.Roolback
  8. end (try)

cała "siła" tkwi w pierwszym UPDATE'cie (SELECT'cie), który "sprawdza" czy ktoś przypadkiem nie edytuje już tego rekordu.

PS. jak mi gdzieś zjadło literki lub spc to przez słabe baterie w klawiatórze :)

0

Witam

Wielkie dzięki !!! Z tego co widze bardzo mi to dobrze przedstawiłeś. Bardziej mi się klaruje wizja mojej aplikacji. Po pracy zaraz do tego zasiąde i będe działał.

Ale żeby nie zaczynać nowego posta, chciałbym zapytać jeszcze bazodanowców jak rozwiązali by takie dwa problemy:

  1. Mam tabele (OBIEKTY) i w niej są pewne dane opisowe (1 rekord - 1 obiekt), mam tabele WARSTWY i tam są pewne warswty konstrukcyjne (1 rekord - 1 warstwa konstrukcyjna). Główna tabela (OPRACOWANIA) zawiera info o opracowaniach (jaki obiekt (OBIEKT_ID), jaka warstwa (WARSTWA_ID) i inne) to wszystko powiązane obcymi kluczami (nie można dodać opracowania nieistniejącej warstwy lub nieistniejącego obiektu). Ale teraz bym chciał zrobić coś takiego w miarę prosto. Mam informacje ze w danym obiekcie (rekordzie z tabeli obiekty) mogą być tylko takie a takie warstwy (podzbiór tabeli warstwy - kilka jej rekordów). Chciałbym to jakoś zapisać w rekordzie obiektu. Myślałem żeby do tabeli Obiekty dodać kolumnę Warstwy która będzie tablicą integerów, ale czytałem że z obsługą tablic przez kontrolki IBX jest spory problem ?
    Jak dopisać do rekordu reprezentującego 1 obiekt, jakie mogą być na nim warstwy przy założeniu że liczba warstw jest zmienna (jedną warstwę może reprezentować 1 integer - numer klucza głównego w tabeli WARSTWY) ?

  2. Chciałbym prowadzić przy pomocy bazy danych, grafik dni roboczych (0) pracujących (1) dla pracowników. Nie chce dzielić tego na miesiące, tylko mieć jedną tabele (łatwiej potem wyciągnąć podsumowania). Założenia są takie, że skład osobowy się zmiania : (. Jak to teraz zrobić: kolumny to osoby, dni to wiersze czy odwrotnie ? Jak ktoś już nie pracuje (bo go już nie ma w firmie) to by miał NULL zamiast 0 albo 1. Liczba pracowników jest spora (jak na ilość kolumn w tabeli - powiedzmy może urosnąć do 50). Z drugiej strony liczba dni przez rok też jest spora ; )
    Macie jakieś pomysły ? Interesują mnie podstawowe informacje do wyciągnięcia: ile pracował, ile nie pracował, ile miał urlopu ...

0
  1. dodatowa tabela obiekt_earstwa z dwoma polami ID_WARSTWY i ID_OBIEKTU, gdzie dla każdej warstwy zapisywał byś które obiekty mogę do niej należeć

  2. Jeśli bez zapisywania godzin (start, stop) to najprościej będzie tak
    grafik


*id
dzien
miesiac
rok
data
id_osoby
praca_urlop

musisz też zdecydować, czy łatwiej Ci będzie z jedną kolumną Data czy z trzema - dziń, miesiąc, rok

i teraz ile pracował
SELECT SUM(*) FROM grafik WHERE id_osoby = ID AND praca_urlop = praca

ile urlopu
i teraz ile pracował
SELECT SUM(*) FROM grafik WHERE id_osoby = ID AND praca_urlop = urlop

ile nie pracował (przy założeniu, że jeśli go nie ma w danym dniu na grafiku to nie pracował)
i teraz ile pracował
SELECT (ilosc_dni_od_01_01_do_teraz) - SUM(*) FROM grafik WHERE id_osoby = ID

Sam grafik musiał byś tworzyć ręcznie, tzn np. w StringGridzie na podstawie danych z bazy

0
Misiekd napisał(a)
  1. dodatowa tabela obiekt_earstwa z dwoma polami ID_WARSTWY i ID_OBIEKTU, gdzie dla każdej warstwy zapisywał byś które obiekty mogę do niej należeć

Tego sie obawiałem : (

Misiekd napisał(a)
  1. Jeśli bez zapisywania godzin (start, stop) to najprościej będzie tak
    grafik

*id
dzien
miesiac
rok
data
id_osoby
praca_urlop

musisz też zdecydować, czy łatwiej Ci będzie z jedną kolumną Data czy z trzema - dziń, miesiąc, rok

i teraz ile pracował
SELECT SUM(*) FROM grafik WHERE id_osoby = ID AND praca_urlop = praca

ile urlopu
i teraz ile pracował
SELECT SUM(*) FROM grafik WHERE id_osoby = ID AND praca_urlop = urlop

ile nie pracował (przy założeniu, że jeśli go nie ma w danym dniu na grafiku to nie pracował)
i teraz ile pracował
SELECT (ilosc_dni_od_01_01_do_teraz) - SUM(*) FROM grafik WHERE id_osoby = ID

Sam grafik musiał byś tworzyć ręcznie, tzn np. w StringGridzie na podstawie danych z bazy

No jest to rozwiązanie. 1 rekord = 1 dniówka 1 pracownika. Myślałem żeby jakoś 1 rekord = 1 dniówka wszystkich. Ale to chyba nie realne.

I jeszcze dorzuce jedno pytanko.
Pisałeś żeby używać TIBQuery zamiast TIBTable. No w najprosym wydaniu TIBDatabase TIBTransaction TIBQuery, TUpdateSQL, DataSource i DBGrid. Wszystko Active i jest OK. W TUpdateSQL jest jako RefreshQuery Select * from tabelka (to samo w w Query). Teraz przy pomocy isql.exe dodaje jeden rekord, robie commit. W TIBTransaction mam ustawione ReadCommited no_wait. I jak daje TIBQuery.Refresh to sie nie odswieza (nie pokazuje dodanego wiersza) ani wywolanie metody Open tez nic nie zmienia :( Czy jest mozliwosc odswiezenia bez zamykania polaczenia z baza ? No nie wyobrazam sobie ze nie ma.

0
b0bik napisał(a)

Tego sie obawiałem : (

ale dlaczego, przecież to normalne roziązanie w takim przypadku i co najważniejsze nie ogranicza Cię do np. 10 obiektów dla warstwy lub 10 warstw dla obiektu

Myślałem żeby jakoś 1 rekord = 1 dniówka wszystkich. Ale to chyba nie realne.

gdybyś miał stałą i znaną liczbę pracowników to można by to tak zrobić ale wystarczy, że doszedł by jeden więcej i już trzeba bazę zmieniać - to nie jest optymalne :)

Pisałeś żeby używać TIBQuery zamiast TIBTable. No w najprosym wydaniu TIBDatabase TIBTransaction TIBQuery, TUpdateSQL, DataSource i DBGrid. Wszystko Active i jest OK. W TUpdateSQL jest jako RefreshQuery Select * from tabelka (to samo w w Query). Teraz przy pomocy isql.exe dodaje jeden rekord, robie commit. W TIBTransaction mam ustawione ReadCommited no_wait. I jak daje TIBQuery.Refresh to sie nie odswieza (nie pokazuje dodanego wiersza) ani wywolanie metody Open tez nic nie zmienia :( Czy jest mozliwosc odswiezenia bez zamykania polaczenia z baza ? No nie wyobrazam sobie ze nie ma.

eee jeśli close i open też nie zaciąga nowych danych to znaczy, że transakcja z isqla jeszcze trwa. Nie używałem isqla więc na 100% Ci nie powiem ale testuj to tak, że odpalasz swój program dwa razy, w jednym dodajesz a w drugim sprawdzasz czy jest - to najprostsze i najpewniejsze :)

pamiętaj, że przed open trzeba close zrobić bo inaczej nic się nie dzieje.

0
Misiekd napisał(a)

ale dlaczego, przecież to normalne roziązanie w takim przypadku i co najważniejsze nie ogranicza Cię do np. 10 obiektów dla warstwy lub 10 warstw dla obiektu

Racja racja. Ale myślałem żeby te zmienne tablicowe, jakoś wykorzystać, chociaż pewnie jak sie je da zastosować to o stałym rozmiarze a nie "dynamiczne".

Misiekd napisał(a)

eee jeśli close i open też nie zaciąga nowych danych to znaczy, że transakcja z isqla jeszcze trwa. Nie używałem isqla więc na 100% Ci nie powiem ale testuj to tak, że odpalasz swój program dwa razy, w jednym dodajesz a w drugim sprawdzasz czy jest - to najprostsze i najpewniejsze :)
pamiętaj, że przed open trzeba close zrobić bo inaczej nic się nie dzieje.

Oczywiście działa z isql tylko jak burak nie dałem close ; ]

0

Ale czemu Refresh nie działa ? No chyba po coś ta metoda jest.

Jak by ktoś szukał:

Note: The Refresh method does not work for all TDataSet descendants. In particular, TQuery components do not support the Refresh method if the query is not ?live?. To refresh a static TQuery, close and reopen the dataset.

0

chyba dla tego (z DB.pas)

procedure TDataSet.Refresh;
begin
  DoBeforeRefresh;
  CheckBrowseMode;
  UpdateCursorPos;
  try
    InternalRefresh;
  finally
    Resync([]);
    DoAfterRefresh;
  end;
end;

procedure TDataSet.InternalRefresh;
begin
end; 

natomiast TIBQuery nie implementuje własnego Refresh

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.