Gambas Fat Client vs Trigger in Datenbanken

Spezielle Fragen zu PostgreSQL, MySQL, SQLite, SQL ...
Antworten
Benutzeravatar
4tionov
Site Admin
Beiträge: 252
Registriert: So 18. Mai 2014, 22:40
Kontaktdaten:

Gambas Fat Client vs Trigger in Datenbanken

Beitrag von 4tionov » Sa 10. Nov 2018, 13:39

Weil bei einer Diskussion im Hintergrund das Thema Trigger aufkam, wollte ich mal ein Beispiel geben, wo man in einer 2-Tier-Architektur Trigger verwendet.

Eine 2-Tier-Architektur ist im Prinzip die Situation Datenbank und (FAT) Client, der darauf zugreift:
https://de.wikipedia.org/wiki/Schichten ... rchitektur

Das ist etwas, was man mit Gambas hervorragend darstellen kann. Man legt eine Datenbank auf den Server (oder den eigenen Computer) und programmiert mit Gambas Clients, die darauf zugreifen können, Daten anzeigen, verändern und wieder in der DB speichern können. Die meiste Zeit befindet sich die Programmlogik, mit der die Veränderung von Daten erfolgt im Client, die Datenbank ist ein reiner Datenspeicher. Das ist in der Regel praktisch, zuerst einmal einfach zu programmieren und hat den Vorteil, dass sich Datenbanken leicht(er) austauschen lassen.

Manchmal möchte man aber Programmlogik direkt auf der Seite der Datenbank selbst haben. Dazu ein kleines Beispiel:

Eine Telefonnummer kann verschieden notiert werden, z.B:

0 1234 567
+49 (0) 1234 567
+49 1234 567
0049 1234 567

Dazu kommen noch alle Sonderformen, die sich Leute so ausdenken, wie

01234/567
01234 56-7
(01234) 567

usw usf

Wenn man Telefonnummern in Tabellen speichern, den Benutzern anzeigen, aber auch vom Computer durchsuchbar machen möchte, ist es sinnvoll dem Computer eine eindeutige Telefonnummer zu präsentieren: +491234567

Man kann jetzt den Benutzer dazu zwingen, die Telefonnummer immer genau so einzugeben, für Menschen ist es aber ärgerlich und schlecht lesbar, genau deshalb haben sie ja verschiedene Methoden zur besseren Lesbarkeit entwickelt.

Man kann auch im Gambas-Programm eine Routine schreiben, die die Telefonnummer vor dem Abspeichern in der Datenbank umwandelt.

Was aber, wenn verschiedene Clients auf die DB zugreifen und dort eine Telefonnummer speichern können? Z.B. ein Gambas-Programm, eine PHP-oder java-Webapp usw. ?

Genau dann ist es sinnvoll, die Programmlogik nicht im Client, sondern in der Datenbank vorzuhalten. Das kann mit einem Trigger gelöst werden. In meiner Datenbank habe ich das so umgesetzt, dass die Datenbank die Telefonnummer in zwei Spalten der Tabelle tbtelefon speichert, "nummer" und "suchstr". In "nummer" kommt, was Benutzer eingegeben haben und da gibt es keine Beschränkungen.

Bei jeder Änderung von "nummer" feuert aber ein Datenbank-Trigger, extrahiert die Telefonnummer aus der Eingabe, und speichert sie in der für den Computer lesbaren Form in der Spalte "suchstr" ab.

Damit können nun verschiedene Clients auf die Datenbank zugreifen, ihre Telefonnummer in beliebigen Formen speichern, die Datenbank selbst sorgt für die eindeutige und durchsuchbare Speicherung der Nummer in einer extra Spalte.

Hier ein Beispiel wie ich das mal in PostgreSQL umgesetzt habe. Eine Triggerfunktion telefon_suchstr() ruft die Funktion telefonnr_sanitize_de() auf, die aus einer in beliebiger Form eingegebenen Telefonnummer die E.164-Nummer ohne Leerzeichen macht:
[+]
CREATE OR REPLACE FUNCTION telefon_suchstr()
RETURNS trigger AS
$BODY$DECLARE
sTelefonnummer varchar := new.nummer::text;
begin

NEW.suchstr = telefonnr_sanitize_de(sTelefonnummer);
return NEW;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION telefon_suchstr()
OWNER TO postgres;


-- Function: telefonnr_sanitize_de(character varying)

-- DROP FUNCTION telefonnr_sanitize_de(character varying);

CREATE OR REPLACE FUNCTION telefonnr_sanitize_de(telefonnummer character varying)
RETURNS character varying AS
$BODY$begin

-- eingefügte (0) entfernen, wenn links ein + steht
if left(telefonnummer,1) = '+' then
telefonnummer = replace(telefonnummer, '(0)'::text, ''::text);
end if;

-- + zu Beginn ersetzen durch 00
telefonnummer = regexp_replace(telefonnummer, '^\+'::text, '00'::text);

-- alles was nicht Zahl ist, entfernen
telefonnummer = regexp_replace(telefonnummer, '\D'::text, ''::text, 'g'::text);

-- 00 zu Beginn ersetzen durch +
telefonnummer = regexp_replace(telefonnummer, '^00'::text, '+'::text);

-- 0 zu beginn ersetzen mit +49
telefonnummer = regexp_replace(telefonnummer, '^0'::text, '+49'::text);

return telefonnummer;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION telefonnr_sanitize_de(character varying)
OWNER TO postgres;
COMMENT ON FUNCTION telefonnr_sanitize_de(character varying) IS 'Macht aus Telefonnummern, so wie sie unsere Kunden übergeben einen Suchstring';
Zusätzlich kann die Funktion telefonnr_sanitize_de() nun in beliebigen Abfragen verwenden, z.B.
shell code
select telefonnr_sanitize_de('+31 (0) 123 456');
liefert "+31123456"
shell code
select kdnr from tbtelefon where suchstr = telefonnr_sanitize_de('+31 (0) 123 456');
liefert alle Kundennummern für eine Telefonnummer, die "+31 (0) 123 456" oder "0031123456" oder "+31 123 45-6" lautet usw ...
Alles Gute,

4tionov

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste