Autor Téma: Jedinečná hodnota poľa - rád by som to už uzavrel.  (Přečteno 638 krát)

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5465
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional

Prvá pripomienka:
  Výnimky sú výnimky a nemajú sa používať na logiku aplikácie. S tým plne súhlasím. Ale pre tento prípad by to bolo pre mňa najjednoduchšie a 100 % riešenie problému. Navyše ho takto dokážem urobiť na jedinom mieste. Aj s fokusom na dotknutý DB komponent.
Druhá pripomienka
  Všetky kontroly je potrebné, priam nutné, vykonať už pred Post. Aby nedošlo k žiadnej výnimke!
.
Z doterajšieho štúdia a predošlých diskusií mi vyplýva, že mám pre každú tabuľku a jedinečné pole urobiť samostatné riešenie. Ja som dúfal, že to všetko urobím na jednom jedinom mieste.
.
Pre jednoduché zoznamy/číselníky a tabuľky, v ktorých sú indexy nad jedným poľom, je jednoduché urobiť SQL query. V takých prípadoch nie je ani predpoklad veľkého počtu záznamov.
Samozrejme treba riešiť, brať do úvahy:
  • Konkurenčný prístup k DB. Kvôli tomu mi bolo odporúčané riešiť daný problém až pri Post (OnBeforePost) – Tretia pripomienka. Asi toto má byť cesta pre mňa. Žiaľ tu padne riešenie na jednom mieste
  • Či sa jedná o Insert alebo o Edit. Pre každý prípad bude iný SQL.Text
Narážam na problém ako riešiť Query pri zložených jedinečných indexoch. S tým sa môžem poriadne natrápiť ???
Príklad zloženého indexu:
Popis:
  Každá SVB má v každom roku definované služby. Služba sa nemôže opakovať. A každá služba musí mať v rámci SVB a roka jedinečný analytický účet. Z toho mi vyplývajú dva indexy
  SVB,Rok,Služba
  SVB,Rok,AnalÚčet
Podľa mňa by index SVB,Rok,Služba,AnalÚčet nefungoval správne. Jedna služba by mohla mať viac účtov a jeden účet viac služieb.
Predpokladám tvorbu dvoch Query.
.
Žiaľ, FDTable neposkytuje žiadnu možnosť akoby som zistil/označil, že tam mám požiadavku na jedinečné pole. Tým mi padá možnosť automatizácie. Tag poľa už používam na iné účely.
.
Chybové hlásenie je v tvare:
[FireDAC][Phys][FB]violation of PRIMARY or UNIQUE KEY constraint "UQ_ROOMTITLES" on table "ROOMTITLES"
Problematic key value is ("TITLE" = 'Detská izba')
.
Dokážem ho rozobrať ho na drobné a patrične to využiť. Toto riešenie samozrejme porušuje prvú a druhú pripomienku.
Do Nového roka všetko najlepšie :-*  a veľa trpezlivosti so mnou 8)
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5465
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #1 kdy: 01-01-2020, 10:31:08 »
Prosím, aspoň hlasujte ktorou cestou by ste šli Vy. Ďakujem.
  • OnBeforePost
  • Všetko na jednom mieste
  • Využiť výnimku
  • Niečo iné - konkretizovať
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline vandrovnik

  • Guru
  • *****
  • Příspěvků: 1112
  • Karma: 47
    • Verze Delphi: 10.3
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #2 kdy: 01-01-2020, 12:47:58 »
Ahoj, už jsem někde psal dříve, že se snažím unikátním klíčům (krom primárních) vyhnout, protože ve výjimečných případech nám to dělalo problémy při práci na více pobočkách ("maximálně jednou za 10 let" - ale samozřejmě se to stane, jakmile je člověk na dovolené...). Takže když už, vyvolal bych výjimku v nějakém triggeru BEFORE INSERT or UPDATE (a dělám to jen v případě, že se nejedná o import dat z pobočky). Nicméně pokud pobočky s nezávislými servery neplánuješ, unikátní klíč (nebo několik unikátních klíčů) bys mohl klidně použít.

Když vyvoláš v triggeru výjimku, může to být nějaká Tebou definovaná výjimka:
CREATE EXCEPTION EX_ZAKAZ_SMAZANI 'Zaznam nesmi byt vymazan.';
a pak někde:
IF (...) THEN EXCEPTION EX_ZAKAZ_SMAZANI;

V aplikaci pak můžeš podle názvu výjimky zobrazit lepší hlášku (delší, v různých jazycích apod.).

Nedělal bych, snad až na nějaké výjimečné případy, kontrolu v aplikaci v OnBeforePost, protože kontrolu na úrovni databáze chci mít vždy a duplikovat ji ještě v aplikaci nechci (dřív nebo později by se mi určitě stalo, že to v aplikaci zapomenu zkontrolovat, že to zkontroluju jinak než v databázi, případně že mezi kontrolou a zápisem proběhne zápis jiným uživatelem nebo si uživatel data zapíše nějakým jiným nástrojem přímo do tabulky).

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5465
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #3 kdy: 01-01-2020, 14:18:51 »
Ďakujem. Hlavne za objasnenie vlastnej kontroly v aplikácii a v DB pomocou spúšte. To mi veľmi pomôže.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline miroB

  • Guru
  • *****
  • Příspěvků: 585
  • Karma: 17
    • Verze Delphi: D1,2,3,4,7,2005,2009, XE8,S,B,T10.2.2 Pro
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #4 kdy: 01-01-2020, 22:18:09 »
..
Tag poľa už používam na iné účely.
..
Táto poznámka je buď zbytočná.
Ak nie je zbytočná, tak je možné "Tag poľa"

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5465
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #5 kdy: 01-01-2020, 23:01:57 »
Posledný príspevok od vandrovníka mi pomohol uvedomiť si rozdiel robiť kontrolu v aplikácii na klientovi a v DB bez vyvolania výnimky pri Post. Len sa mi nepáči, že musím nájsť správne riešenia a pritom DB to už má vyriešené. A bez chýb.
Ja tag používam jednoduchým spôsobom. Ten Enum mi na um neprišiel. Používam ho na niekoľko účelov:

  • Pole string určuje minimálny počet vyžadovaných znakov
  • pole je číselný údaj: musí byť kladný, (ne)môže byť nulová hodnota
Všetky údaje sa automaticky načítajú z FDTable a slúžia na základnú kontrolu údajov. Viď dole.
Kód: Delphi [Vybrat]
  1.   TDBEditControl = class(TObject)
  2.   strict private
  3.     FAllowZero: Boolean;
  4.     FDesired: Boolean;
  5.     FEditWinCtrl: TWinControl;
  6.     FFieldType: TFieldType;
  7.     FLocalName: string;
  8.     FMinLength: Word;
  9.     FNameField: string;
  10.     FOnlyPositive: Boolean;
  11.     FOrderBy: Integer;
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5465
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #6 kdy: 03-01-2020, 14:07:37 »

Dopracoval som sa k tomuto kódu:
Kód: Delphi [Vybrat]
  1. BEGIN
  2.   IF (INSERTING) THEN
  3.   BEGIN
  4.     IF (EXISTS (SELECT COUNT(*) FROM ROOMTITLES AS RT WHERE (RT.TITLE = NEW.TITLE) GROUP BY RT.TITLE)) THEN
  5.     BEGIN
  6.       EXCEPTION DUPLICATE_VALUE;
  7.     END
  8.   END
  9.   ELSE
  10.   BEGIN
  11.     IF (UPDATING) THEN
  12.     BEGIN
  13.       IF (EXISTS (SELECT COUNT(*) FROM ROOMTITLES RT WHERE (RT.TITLE = NEW.TITLE) AND
  14.         (RT.IDROOMTITLES <> OLD.IDROOMTITLES) GROUP BY RT.TITLE)) THEN
  15.       BEGIN
  16.         EXCEPTION DUPLICATE_VALUE;
  17.       END
  18.     END
  19.   END
  20. END
Dúfam, že tak to je správne. Dávam to tu preto, lebo som ešte nič podobné nerobil. Ďakujem.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline vandrovnik

  • Guru
  • *****
  • Příspěvků: 1112
  • Karma: 47
    • Verze Delphi: 10.3
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #7 kdy: 03-01-2020, 14:15:27 »
IF EXISTS (SELECT COUNT(*)
- tam nedávej Count, jen hvězdičku

GROUP BY mi tam přijde zbytečné.

Ale jinak, nebudeš-li řešit ty importy z jiných poboček, a máš-li tam stejně jen jednu Exception (pořád stejnou), tak můžeš snadněji použít ten unikátní klíč (či několik klíčů), jak jsi psal na začátku.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5465
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #8 kdy: 03-01-2020, 14:57:55 »
Citace
GROUP BY mi tam přijde zbytečné.
Ak to tam nedám, tak sa mi vráti jeden záznam s nulou. Takto je DataSet prázdny. Je možné, že mi to iba EMS Manager takto zobrazuje.
Citace
Ale jinak, nebudeš-li řešit ty importy z jiných poboček, a máš-li tam stejně jen jednu Exception (pořád stejnou), tak můžeš snadněji použít ten unikátní klíč (či několik klíčů), jak jsi psal na začátku.
Ale ja netuším ako by som ho použil. Budem vďačný za navedenie ako na to. Ukážku či odkaz.
Všetky príklady sú na jedno kopyto: INSERT INTO...
Importy nikdy riešiť nebudem a stačí mi jediná Exception. Po jej vyvolaní si to ošetrím na klientovi. Na zobrazovanie chýb používam TAdvTaskDialog. Ten má 5 textov: Title, Instruction, Content, ExpandedText, Footer.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5465
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #9 kdy: 03-01-2020, 15:00:58 »
Ja tie unikátne kľúče nad tabuľkou (nie unique index) mám. Ponechávam ich tam ako poslednú poistku pred zdvojením údajov.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline vandrovnik

  • Guru
  • *****
  • Příspěvků: 1112
  • Karma: 47
    • Verze Delphi: 10.3
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #10 kdy: 03-01-2020, 15:04:34 »
Ak to tam nedám, tak sa mi vráti jeden záznam s nulou. Takto je DataSet prázdny. Je možné, že mi to iba EMS Manager takto zobrazuje.

No a když vyhodíš COUNT i GROUP BY?

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5465
  • Karma: 41
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Jedinečná hodnota poľa - rád by som to už uzavrel.
« Odpověď #11 kdy: 03-01-2020, 15:10:58 »
Tak je prázdny. Upravím to.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.