Hi,
meine Auftraggeber sind verzückt, das die Ballettschule jetzt so eine gut funktionierende DB hat, also Access FE und MS Sql Be.
Alle funktioniert problemlos und performant...
Aber wie sagt der Engländer: Give them an inch, they take a mile!
Jetzt möchten sie historische Datenhaltung, also in der Historie wissen, was eine Kunde in der Schule alles so gemacht hat:
• Änderungen der Personendaten
• Änderungen der Kursbelegungen
• Ggf. Zahlungsmoral
Ich musst da erstmal schlucken, denn ich denke das ist nicht ganz so trivial.
Technisch fallen mir dazu natürlich sofort Trigger ein, aber zunächst geht es erstmal um das Design.
Nehmen wir mal ein winziges Beispiel, an dem man aber das Prinzip gut erklären kann.
Es gibt eine Tabelle Person, der Einfachheit halber jetzt nur mit den Spalten PersonId (Pk), Nachname und Vorname.
Dann gibt es eine Tabelle Partner mit den Spalten personid(fk zu personid), RolleId und PartnerId (pk)
Dann gibt es eine Tabelle Konto mit einem Kontoinhaber. Diese Spalte Kontoinhaber ist aber keine Spalte aus der Personentabelle, sondern aus Partner, mit der RolleId, die der Rolle Kontoinhaber entspricht. Der Grund dafür ist, das die Person noch andere Rollen in der Schule einnehmen kann und darüber ist man sehr flexibel.
Ok.
Nun kommt die Historie ins Spiel. Man könnte z.B. eine Tabelle History_Person anlegen, die dann die Spalten PersonId (aus der ursprünglichen Tabelle) NachName, Vorname und einen neuen PK PersonId_his sowie ein Spalte event, die die Werte insert, update, delete annehmen kann und da wird die Historie abgelegt, dazu kommt noch das Eventdatum.
Ähnlich wäre es mit der Tabelle Partner die dann so eine History Tabelle hätte : personid, partnerid, Rolleid, partnerid_his (pk), event, eventdatum.
Nur frage ich mich dann, wie dann die RI-Beziehungen zwischen den history Tabellen wären, sie können ja eigentlich nur zwischen den neuen Spalten sein...
Das ist alles noch ganz ins Unreine gesprochen und ich stehe noch ganz am Anfang und wollt nur mal ein paar Ideen sammeln.
Aber auch jeden Fall ein spannendes Thema.
Hallo Martin,
SQL Server bietet dazu von Haus aus History-Tabellen an. Dazu muß man ein paar zusätzliche Felder in die betreffenden Tabellen einfügen zur History-Verwaltung und SQL Server handhabt dann Änderungen in Tabellen automatisch in die entsprechenden History-Tabellen.
Infos siehe hier:
https://learn.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables?view=sql-server-ver16
https://learn.microsoft.com/en-us/sql/relational-databases/tables/manage-retention-of-historical-data-in-system-versioned-temporal-tables?view=sql-server-ver16
https://sqlspreads.com/blog/temporal-tables-in-sql-server/
https://www.google.de/url?sa=t&source=web&rct=j&opi=89978449&url=https://www.youtube.com/watch%3Fv%3D5Ohrm3GMD_A%26pp%3DygUPI2RldmJodW1pZGVvcmlh&ved=2ahUKEwi1rY67ipGLAxWr8LsIHeGmK1IQwqsBegQIHxAE&usg=AOvVaw2EcSkBw0BXaRGgGzzZq7QO
Die Bindung an die History kann allerdings Schwierigkeiten mit sich bringen, wenn es z.B. um das einzelne Kopieren von Tabellen geht.
Ich würde Dir empfehlen, Deine Auftraggeber auf die DSGVO hinzuweisen, da es um personenbezogene Daten geht und noch dazu mit einer Art von Profilbildung aus den Daten, was problematisch ist.
https://www.srd-rechtsanwaelte.de/blog/profiling-neuerungen-dsgvo-bdsg
Gruß
Christian
Zitat von: MartinHan am Januar 25, 2025, 14:56:53Jetzt möchten sie historische Datenhaltung, also in der Historie wissen, was eine Kunde in der Schule alles so gemacht hat
:
• Änderungen der Personendaten
Bzgl. der Personendaten wäre das wohl eine Änderungshistorie. - Das ist eine gängige Funktionalität und du wirst sicherlich bei einer Recherche zahlreiche Informationen und Beispiele dazu finden. Ein guter Startpunkt sind die von
@Bitsqueezer erwähnten Temporal Tables.
Vorsicht bzgl. Datenschutz. In der Historie speicherst du Daten, die für die Geschäftsbeziehung mit dem Kunden eigentlich nicht mehr erforderlich sind. Für einen gewissen Zeitraum lässt sich das mit der Nachvollziehbarkeit von Änderungen rechtfertigen, aber nicht unbegrenzt lange.
Zitat von: MartinHan am Januar 25, 2025, 14:56:53• Änderungen der Kursbelegungen
• Ggf. Zahlungsmoral
Diese Daten sind eigentlich in sich bereits historisch.
Ein Kunde belegt einen Kurs für eine bestimmte Zeit (Von/Bis).
Eine Rechnung wird an einem Datum ausgestellt und an einem folgenden Datum, ggf. nach Mahnung, bezahlt.
Wenn du diese Informationen nicht absichtlich löscht, sind die bereits historisch nachvollziehbar.
Falls es dir hier um eine rein technische Änderungshistorie geht, siehe oben.
Hi,
danke für eure Tipps. ich bin erstaunt über mich, das ich das mit der Änderungshistorie bei den Personendaten schon hinbekommen habe. Die Zeiträume-Spalten definiert, bei einem Kunden eine Hausnummer geändert und schon wurde ein historischer Satz angelegt. Toll.
Ab wie das mit den Beziehungsdaten ist, ist mir noch schleierhaft. Anhand der Rechnungen wird es nicht gehen, es gibt viele Kurs, die das gleiche kosten und auf der Rechnung, die aber keine Rechnung ist, sondern nur eine Zeile in einem Lastschrifteinzug, sind die Kurse nicht vermerkt.
Zu einer Kursbelegung kommt man über Person>Partner>vertrag>Kursbelegung. Bei der Kursbelegung steht dann zu welchem Vertrag sie gehört und welcher Kurs besucht wird.
Aber lasst mich mal fummeln, vielleicht klappt es ja.
Ich werde berichten.
Und danke!
Martin
Zitat von: MartinHan am Januar 25, 2025, 17:45:19Anhand der Rechnungen wird es nicht gehen, es gibt viele Kurs, die das gleiche kosten und auf der Rechnung, die aber keine Rechnung ist, sondern nur eine Zeile in einem Lastschrifteinzug, sind die Kurse nicht vermerkt.
Die Rechnung hatte ich für den Stichpunkt "Zahlungsmoral" erwähnt.
Zitat von: MartinHan am Januar 25, 2025, 17:45:19Zu einer Kursbelegung kommt man über Person>Partner>vertrag>Kursbelegung. Bei der Kursbelegung steht dann zu welchem Vertrag sie gehört und welcher Kurs besucht wird.
Da hast du dann ja die Information. Von wann bis wann ein Kurs belegt wird, musst du ja sowieso speichern. Es wird ja häufiger vorkommen, dass ein Kunde *jetzt gerade* einen Kurs belegt, aber auch jetzt schon klar ist, dass er diesen Kurs ab einen gewissen Stichtag nicht weiter belegen wird.
Hi,
ich kann auf keinen Fall erwarten, das alle die Abläufe in einer Ballettschuile kennen.
Die meisten Kurse sind Dauerkurse, es gibt kein definiertes Ende.
Einige Kurse gibt es schon seit 30 Jahren!
Die Schüler melden sich an und bleiben für unbestimmte Zeit in dem Kurs bis sie kündigen oder der Kurs mangels Masse aufgelöst wird, was aber selten vorkommt.
Das ist im Übrigen auch der große Unterschied zu Tanzschulen, da bucht man einen Kurs, der dann für n Monate läuft und dann bucht man den nächsten.
Das ist auch der Grund, warum es auf dem Markt fast keine Kaufsoftware für Ballettschulen gibt. Es gibt haufenweise für Tanzschulen. Es gibt zwar eine, aber die ist bezgl. Datenmodell so grottenschlecht, das ich mich entschieden habe es selbst zu machen.
Sie haben dieses Rollenmodell nicht verstanden. Im Extremfall kann es so sein:
Eine Mutter meldet ihr Kind zu einem Kurs an, sie ist also Vetragspartner
das Kind ist Kursteilnehmer und belegt einen Kurs
Die Mutter belegt selbst auch einen Kurs und ist also neben Vertragspartner auch Kursteilnehmer
Die Kursgebühren werden von der Oma bezahlt, die ist Kontoinhaber
Ich möchte natürlich jede Person nur einmal im System haben und muss dann die Rollen verwalten, was über die Partnertabelle schon seid vielen Jahren wunderbar klappt.
Die Kaufsoftware, die sich oben erwähnte, hat für die verschiedenen Rollen die Personen redundant gespeichert, da läuft es mir kalt den Rücken runter...
Aber ich will das Forum nicht langweilen mit meiner speziellen Problemstellung und werde mich ab morgen wieder der Historie widmen.
Cu, Martin
Hallo Martin,
ist nicht langweilig, man kann immer nur dazulernen.. :)
Ein Kurs für Balett über 30 Jahre? Da sollte man doch meinen, alles gelernt zu haben. Ist es dann nicht eher sowas wie eine Mitgliedschaft in einem Fitnessklub, also nur als Übung, um nicht aus derselben zu kommen? Kann mir nicht vorstellen, daß man da noch Neues lernt...
Gruß
Christian
Hi,
ja der Kurs bleibt, nur die Mitglieder wechseln natürlich. Der Vergleich mit dem Fitnessstudio passt schon, ich buche also eine Leistung auf unbestimmte Zeit.
Bei Kindern ist es etwas anders. Die durchlaufen, je nach Begabung, eine Reihe von Kursen: Tänzerische Früherziehung 1, TF 2 , Tf3...bis sie irgendwann "groß" sind und beim Ballett bleiben.
D.h. Die Kurse bleiben gleich und die Schüler durchlaufen sie, ähnlich wie Stufen in der Schule.
Die historische Datenhaltung soll eben genau das transparent machen, den Werdegang der Schüler durch die Schule und den Kursen.
Wenn man die hat, kann man die Schüler auch besser beraten, welche Möglichkeiten sie haben. Desweiteren kann man unternehmerisch sehen, welche Kurse gut laufen, und wo mehr Abgänge sind.
Wie das nun rechtlich zu bewerten ist, da werde ich drüber nachdenken.
MfG
Martin
Zu dem rechtlichen:
In unseren Verträgen steht:
Mit der Speicherung und Auswertung der Daten nur für den internen Gebrauch bin ich einverstanden.
Ich denke, das dürfte reichen oder?
Martin
Hallo Martin,
diese Formulierung dürfte noch nicht reichen. I.d.R. wird eine solche Einwilligungserklärung so gestaltet, daß sie nochmal extra unterschrieben werden muß.
Aber hier noch ein paar zusätzliche Infos:
https://www.datenschutz.org/einwilligungserklaerung/ (https://www.datenschutz.org/einwilligungserklaerung/)
Gruß
Knobbi38
Ok...sehe ich mit an.
Jetzt habe ich die Temporalen Tabellen eingereichtet.
Wenn ich in Access eine Änderung in der Tabelle Person mache, kommt der Reservierte Fehler -7776
Im ssms kann ich aber einen Update durchführen.
Bei anderen Tabellen geht es, nur bei der personen Tabelle nicht
Eine Idee?
Martin
Hallo Martin,
also ich habe mal einen Test mit A2013 und SQL Server 2022 und ODBC Treiber 17 gemacht.
Die Testtabelle:
CREATE TABLE Produkte (
ProduktID INT PRIMARY KEY CLUSTERED,
Produktname VARCHAR(100) NOT NULL,
Preis DECIMAL(10, 2) NOT NULL,
GueltigVon DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
GueltigBis DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (GueltigVon, GueltigBis)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.ProdukteHistorie));
Tabelle verlinken und neue Datensätze hinzufügen geht ohne Probleme.
Beim Ändern bestehender Daten gibt es dagegen ein Problem, hier scheint SQL Server mit seinen internen Triggern zur Verwaltung der History-Tabelle dann im Zusammenhang mit Access Probleme zu bekommen, daher der Fehler.
SSMS funktioniert mit .NET und hat daher eine Offline-Verarbeitung, was ganz anders funktioniert.
Aber man kann sich ja abschauen, was SSMS da macht und mit Hilfe des SQL Server Profilers findet man den passenden UPDATE-Befehl. SSMS verwendet dazu sp_executeSQL, aber das ist natürlich nicht nötig, man kann auch direkt per UPDATE arbeiten, auch von Access aus. Man muß es halt nur mit ADO machen, dann geht es.
Für die Beispieltabelle oben habe ich nach der Verlinkung schnell ein Auto-Formular erstellt mit folgendem Code:
Option Compare Database
Option Explicit
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Not Me.NewRecord Then
If UpdateProdukt(Me.ProduktID, Me.Produktname.OldValue, Me.Preis.OldValue, Me.Produktname, Me.Preis) Then
' Verwerfen der Access-Änderungen
Cancel = True
Me.Undo
Me.Requery
End If
End If
End Sub
Private Function UpdateProdukt(ProduktID As Integer, alterProduktname As String, alterPreis As Double, neuerProduktname As String, neuerPreis As Currency) As Boolean
Dim cn As ADODB.Connection
Dim cmd As ADODB.Command
Dim strSQL As String
On Error GoTo Fehlerbehandlung
' Verbindungsobjekt erstellen
Set cn = New ADODB.Connection
UpdateProdukt = False
' Verbindungsparameter
Dim strConnection As String
strConnection = "Driver={ODBC Driver 17 for SQL Server};Server=DeinServer;Database=DeineDatenbank;Trusted_Connection=Yes;"
' Verbindung öffnen
cn.Open strConnection
' Command-Objekt erstellen
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cn
strSQL = "UPDATE Produkte " & _
"SET Produktname = ?, Preis = ? " & _
"WHERE (ProduktID = ?) " & _
" AND (Produktname = ?) " & _
" AND (Preis = ?)"
cmd.CommandType = adCmdText ' Wichtig: adCmdText für sp_executesql
cmd.CommandText = strSQL
cmd.Parameters.Append cmd.CreateParameter(, adVarChar, adParamInput, 100, neuerProduktname) '1. Parameter
cmd.Parameters.Append cmd.CreateParameter(, adCurrency, adParamInput, , neuerPreis) '2. Parameter
cmd.Parameters.Append cmd.CreateParameter(, adInteger, adParamInput, , ProduktID) '3. Parameter
cmd.Parameters.Append cmd.CreateParameter(, adVarChar, adParamInput, 100, alterProduktname) '4. Parameter
cmd.Parameters.Append cmd.CreateParameter(, adCurrency, adParamInput, , alterPreis) '5. Parameter
' Ausführen der Anweisung
cmd.Execute
Set cmd = Nothing
cn.Close
Set cn = Nothing
UpdateProdukt = True
Ende:
If Not cn Is Nothing Then
If cn.State = adStateOpen Then cn.Close
End If
Set cmd = Nothing
Set cn = Nothing
Exit Function
Fehlerbehandlung:
MsgBox "Fehler beim Aktualisieren des Produkts: " & Err.Description, vbCritical
Resume Ende
End Function
Das Beispiel ist natürlich Gaga, es sollte beim WHERE natürlich nur die PK-ID der Tabelle verwendet werden. Aber es zeigt, wie es im Prinzip funktioniert.
Der Trick ist, nur den UPDATE bei Access zu verhindern, was in Form_BeforeUpdate geschieht. Wenn es ein INSERT ist, dann geht es ohne Probleme mit Access, daher die Frage nach NewRecord.
Wenn es ein bestehender Datensatz ist, wird erst versucht, den UPDATE "hintenrum" zu erledigen und wenn das erfolgreich war, mit Cancel=True der UPDATE von Access verhindert und die Änderungen im Formular rückgängig gemacht, so daß es für den Access-User so aussieht, als wäre eine ganz normale Speicherung im Hintergrund gelaufen.
Mit der Methode funktioniert es einwandfrei auch mit system-versioned Tabellen.
Alternativ kannst Du das natürlich auch mit einer SP machen, aber das wäre dann schon wieder aufwendiger. Ein einfacher UPDATE-Befehl tut es völlig.
Requery: Eigentlich genügt normalerweise ein Refresh, wenn man nur einen UPDATE durchführt. Der Datensatzzeiger bleibt auf dem gleichen Datensatz, Refresh kann nur kein INSERT und DELETE aktualisieren. Leider funktioniert das hier nicht, ohne Requery gibt es dann die Fehlermeldung, daß ein anderer Benutzer Änderungen gemacht hat.
Da bei Requery wieder zum ersten Datensatz gesprungen wird, muß man sich dann die ID merken vor dem UPDATE und mit FindFirst wieder zum Datensatz zurückspringen. Wenn man Application.Echo abschaltet, sieht man das im Frontend auch nicht. Für Endlosformulare habe ich dazu mal eine Klasse geschrieben, findest Du auf meiner Downloadseite (https://www.ccedv.de) unter "CCReposition". Hierbei wird dann auch die Bildschirmposition des Datensatzzeigers nach einem Requery wiederhergestellt (ohne würde der Datensatz zum ersten in der angezeigten Liste werden, auch wenn der Datensatz vorher in der Mitte stand).
Gruß
Christian
Hi,
der Fehler hat sich erledigt. Durch viele Fehlversuche war da wohl was strubbelig.
Ich habe die DB platt gemacht un neu angelegt, un bei den Kerntabellen die Historie angeknipst.
Jetzt geht es weiter...Die Darstellung der Historien in Access Frontend...
Es gibt doch in Access doch auch diese Formulare mit den Reitern, die könnte man doch gut für die Historien nehmen wenn es nicht zu viele sind.
Dein Hinweis auf ADO ist gut, werde ich mir ansehen. Das Ganz muss aber intensiv getestet werden, ehe man das Produktiv macht.
Aber der Anfang ist jetzt gemacht.
Danke!
Martin
Hi,
die Darstellung der Versionen im Formular Personen ist nicht das Problem.
Ich muss es nur umstellen von einem gebundenen Formular zu einem unbebundenen und kann dann die historischen Daten, die ich in einer Listbox auswählen kann, in dem gleichen Formular darstellen.
Es werden auch nicht so viele Versionen sein, nur wenn mal jemand umzieht oder sich die Handynummer geändert hat, also überschaubar.
Spannend wird es, wenn das Beziehungsgeflecht komplexer wird...
Aber jetzt nicht mehr...hallo Rotwein!
Martin
Hallo,
ZitatJetzt möchten sie historische Datenhaltung, also in der Historie wissen, was eine Kunde in der Schule alles so gemacht hat:
• Änderungen der Personendaten
• Änderungen der Kursbelegungen
• Ggf. Zahlungsmoral
Ich frage mich, was mit einer Datenhistorie bezweckt werden soll.
Wenn die Datenbank korrekt normalisiert aufgebaut ist, so sind doch die Daten an sich schon historisch.
Bei Änderungen der Personandaten, so ist das doch in einem neuen Datensatz abzubilden, sonst würden sich alte abhängige Datensätze auch auf neue Personendaten beziehen.
Wozu also Daten in Historietabellen verschieben ?
Die ganzen Zusammenhänge der Schlüsselfelder gehen doch verloren.
Und Speicherplatz wird doch da auch nicht gespart.
Wenn man alte Daten ausblenden will, so kann man doch z.B. in der Kunden/Personentabelle ein Feld einbauen (Archiv z.B.) um nicht mehr benötigte Daten nicht anzuzeigen. Die über Fremdschlüssel abhängige Daten werden dann ja auch nicht mehr angezeigt.
Und was den Datenschutz betrifft, können ja die Daten auch in den Originaltabellen anonymisiert werden.
Also, wozu Daten in extra Tabellen auslagern ?
Ich hoffe, ich habe das Ansinnen richtig verstanden und mein Beitrag ist nicht ganz daneben.
Hallo Klaus,
ob das alles klappt weiß ich auch noch nicht. Aber die Idee ist, das man auf Knopfdruck nachvollziehen kann, wer welche Kurse in der Vergangenheit besucht hat. Aktuell wird ja immer nur der aktuelle Stand gespeichert, die Historie ist weg.
Natürlich könnte ich selbst etwas basteln, aber wenn die DB das für mich abnimmt, find ich das besser.
Und eins habe ich von dir nicht verstanden, warum soll ich einen neuen Personensatz erzeugen, wenn jemnand umzieht? Per heute wird die neue Adresse eingetragen und fertig. Wo der Mensch vorher gewohnt hat, könnte man natürlich aus alten Sicherungen rausfinden, wäre aber dpch etwas umständlich.
Wenn man deiner Philosophie folgt, hast du natürlich recht, dann brauchte man die Hitorie nicht.
Ich werde berichten ab es klappt oder nicht und danke für deinen Beitrag.
Martin
Hallo,
ZitatAber die Idee ist, das man auf Knopfdruck nachvollziehen kann, wer welche Kurse in der Vergangenheit besucht hat.
Und genau darum sollte eine normalisierte Struktur angelegt werden.
ZitatUnd eins habe ich von dir nicht verstanden, warum soll ich einen neuen Personensatz erzeugen, wenn jemnand umzieht?
Aber genau das willst Du doch mit der Historie machen. Dann kannst Du doch gleich bei Umzug einen neuen Datensatz anlegen. Außerdem könnte es durchaus wichtig sein zu wissen, wo jemand vorher gewohnt hat. Und bei Umzug würde man auch keinen neuen Personendatensatz anlegen, sondern nur einen weiteren Datensatz für die Adresse.
Mit Deinem Wunsch eine Historie anzulegen, machst Du genau das was Du in der Datenbank vermeiden willst. Und historiche Daten hast Du bis jetzt auch noch nicht. Warum dann nicht gleich die DB so gestalten, dass sich die Historie automatisch ergibt. Ändern musst Du sowieso.
Ich halte solche Historietabellen für ersatzlos überflüssig, wenn die Datenbank entsprechend gestaltet wird.
Hallo Klaus,
man kann das so machen, also die Adressen in einer eigenen Tabelle speichen, wenn dann jemand umzieht kriegt die Person einen neuen FK. Bei mir ist eben die Adresse hart bei der Person.
Aber ob ich jetzt einen neuen Satz in der Adresstabelle anlege oder einen historische Satz anlege, ich denke der Unterschied sind ein paar Bytes...
bei den Personen ist das auch alles noch einfach, aber wenn es in die etwas kompxeren Beziehunge geht, gerät man leicht ins Unterholz...
So Cod may help...
Hallo,
Zitatwenn dann jemand umzieht kriegt die Person einen neuen FK.
Nein, so rum nicht. Wenn der FK in die Person kommt, ist die Historie weg. Die Adresse bekommt einen FK zur Person.
Zitataber wenn es in die etwas kompxeren Beziehunge geht, gerät man leicht ins Unterholz...
Aber mit Deinen Historietabellen doch erst recht. Du musst ja auch für die Historietabellen Beziehungen anlegen, und die entsprechenden Inhalte die sich über die Fremdschlüssel ergeben ggf. mit in diese Historietabellen verschieben. Das gibt doch alles ein ziemliches Chaos mit neuen Bezeihnugen für die Historietabellen. Und wenn Du das nicht machst (mit den Beziehungen), hast Du in den Historietabellen zusammenhangslose Daten stehen.
Die Historietabellen sind nach meiner Auffassung eine Sackgasse und viel zu umständlich.
Zitat von: MartinHan am Januar 28, 2025, 11:43:39Aktuell wird ja immer nur der aktuelle Stand gespeichert, die Historie ist weg.
Das ist doch für die Kursteilnahme organisatorisch gar nicht wirklich möglich. Wenn deine Historie dafür "weg" ist, dann schießt du dir hier mit aller Gewalt selbst ins Bein.
Zitat von: MartinHan am Januar 25, 2025, 22:41:41Einige Kurse gibt es schon seit 30 Jahren!
Die Schüler melden sich an und bleiben für unbestimmte Zeit in dem Kurs bis sie kündigen oder der Kurs mangels Masse aufgelöst wird, was aber selten vorkommt.
Aber die Schüler kündigen doch nicht hier und jetzt auf der Stelle. Sie kündigen zu einem bestimmten Datum. Dieses Kündigungsdatum erfasst du in der Zurdnungstabelle des Teilnehmers zu dem Kurs. - Fertig!
Das musst du doch sowieso machen, oder wie funktioniert das aktuell? Stellen sich die Mitarbeiter einen Wecker auf den Stichtag der Kündigung, und wenn er klingelt löschen sie dann sofort den Teilnehmer aus dem Kurs?
Zitat von: MzKlMu am Januar 28, 2025, 12:47:07Die Historietabellen sind nach meiner Auffassung eine Sackgasse und viel zu umständlich.
Mindestens für die Kursteilnahmen stimme ich hier absolut zu. Bei einem sinnvollen Datenbankdesign ist eine zusätzliche Historientabelle unnötig.
Hallo,
also die History-Tabelle ist nicht per se unnütz. Aber ihr eigentlicher Zweck ist in der Tat eher "forensische Datenhaltung", um nachvollziehen zu können, wann welche Änderungen an einem Datensatz gemacht wurde, denn JEDE Änderung am Datensatz wird automatisch einen neuen Eintrag in der History erzeugen. Daraus am Ende eine Statistik zu erstellen mit den Informationen, die dazu notwendig sind, ist dann schon ein wenig Detailarbeit.
Das einzige ist halt, daß die History-Tabelle automatisch von SQL Server verwaltet wird, so daß man sich selbst keine Gedanken um das Konzept machen muß.
Dennoch: Wenn man ganz bestimmte Informationen sichern möchte, sind "herkömmliche" Historientabellen, die man selbst verwaltet, ebenfalls nicht schwer zu realisieren und wahrscheinlich deutlich einfacher auszuwerten. Wenn man eine Tabelle Kurse hat und Personen und dazu eine m:n-Tabelle PersonenZuKursen, dann kann man halt für jede neue Kursbelegung einen neuen Eintrag erzeugen mit Datum, dann hat man ja eine History, die nur Informationen zu Kursen bietet.
Es kommt halt immer darauf an, was man am Ende damit machen will und wieviel Zeit man für die Umsetzung hat. Im Fall der Kursteilnahme ist sicherlich richtig, daß man diese Daten ohnehin erfaßt, sonst würde eine Kursverwaltung ja nicht möglich sein.
Gruß
Christian
wir haben ganz viele Wecker...es klingelt ständig...
nein Spaß´beiseite, eine Änderung einer Kusbelegung ist per sofort möglich. Der Kunde erhält eine Vertragsänderung, die er unterschreibt und die neue Kursbelegung wird eingegeben. Die davor gültig war ist dann weg.
Kündigungen können gelten für den ganzen Vertrag, dann sind auch alle Kursbelegungen gekündigt oder auch nur einzelne Kursbelegungen.
Kursbelegungen können z.B. auch ruhen, wenn jemand längere Zeit krank ist z.B. .
Am Monatsersten werden dann die Beträge für alle Verträge neu berechnet, wo dann eben diese Informationen einfließen und das Geld wird eingezogen. So hat es sich seid 30 Jahren bewährt und ist gängige Praxis in vielen Schulen.
Ihr habe ja alle recht, natürlich könnte ich mit da z.B. mit triggern selbst etwas basteln, aber ich fand die Lösung mit der Historie irgendwie cool...und Zeit habe ich genug, es ist jetzt kein Dringlichkeitsprojekt.
Hallo Martin,
also wenn es Dir um Historie geht - warum überschreibst Du denn dann die alten Kursdaten? Es ist doch ebenso leicht, für jede neue Buchung einfach eine neue Zeile einzufügen. Schon ist Dein Problem gelöst.
Gruß
Christian
Hallo,
ZitatIhr habe ja alle recht, natürlich könnte ich mit da z.B. mit triggern selbst etwas basteln,
Wozu Trigger, egal wo, Datenänderungen sind ein neuer Datensatz. Wozu das noch zusätzlich in Historietabellen schreiben. Und diese Historietabellen sind doch auch nicht gerade einfach. Wenn diese Tabellen sinnvollerweise auch abhängige Daten zeigen sollen, müssen doch diese ebenfalls in weitere Tabellen ausgelagert werden.
Zitatund die neue Kursbelegung wird eingegeben. Die davor gültig war ist dann weg.
Und da genau beginnt doch das Problem. Bevor die neue Kursbelegung eingegeben wird, muss diese doch erst in die Historietabelle geschrieben werden, erst dann kann die Kursbelegung überschrieben werden. Da kann ich die vorherige Kursbelegung doch gleich drin lassen und habe dann meine Historie, automatisch.
Als ich kann diesen Historietabellen nichts abgewinnen. Ich halte diese nach wie vor für Deine Aufgabenstellung für überflüssig. Ändere lieber die DB entsprechend, dass die Daten automatisch auch die Historie abbilden.
Hallo,
ich werde mir alle Ratschläge mal ansehen, ich wollte es aber mit diesen Historischen Tabellen einfach mal machen und möchte dazu erste Eindrücke schildern.
Die DB ist in Produktion soweit stabil, und wenn da noch Fixes zu machen sind, haben ich dafür noch eine separate Umgebung.
Ich habe also für die Tabellen Person, Partner, Kursbelegung, Vertrag, Kurs jeweils Hitorische Tabellen angelegt.
Als Beispiel:
Stefanie besucht die Kurse Ballett 1 und Ballett Fortg., diese Kurs werden mir auch als aktuelle angezeigt.
Es bestehen also 2 Datensätze in der Tabelle Kursbelegung, in denen jeweils die ID der Kurse stehen, der Bezug zu Stefanie geschieht über einen FK, ebenso zu dem Vertrag, zu dem diese Kursbelegungen gehören.
Dann habe ich ihr noch einen weiteren Kurs HopHop 1 zugewiesen.
Das System hat dann in der History Tabelle der Kursbelegung die obigen beiden Kurse abgelegt, also quasi die komplette Belegungskonfiguration...das validTo Datum war dann das Erfassungsdatum des Neuen Kurses. Hätte ich jetzt so nicht erwartet, finde es aber auch gut. Die History Daten der Kurse standen dann auf 2025.1.25 (Der Tag der Einrichtung) bis 9999.12.31.
Dann habe ich ein Änderung an einem der Kurse gemacht und das hatte zur Folge, das der Bezug der Kursbelegung dann auf die historische Tabelle des Kurses zeigte.
Also ich würde mal sagen, das System funtioniert. Natürlich gilt diese Aussage jetzt nur auf diesen kleinen Testfall, wie das Praxix aussieht, wird man sehen.
Ein kleines Problem war dabei aber, das es einige Konstrukte für die Auswertung der temporalen Tabellen in T-SQL gibt, die in Access nicht verfügbar sind:
z.B. FOR SYSTEM_TIME as of @zeitpunkt
D.H. ich hole mir die Daten über eine StP, klappt aber auch problemlos.
Spannend wäre es jetzt natürlich, wenn ich Stephanie komplett lösche, dann dürfte sie in den aktuellen Tabellen gar nicht mehr sichtbar sein, in den historischen aber schon noch.
Es gibt also noch einiges zu testen.
Man lernt nie aus...
Martin
Hallo Klaus,
danke für deinen Beitrag.
Bei den einzelnen Datensätzen die Felder Validfrom und Validto einzufügen ist sicherlich denkbar, nur werden die Abfragen dann deutlich komplexer, da ja kaum ein Tabelle alleine da steht, sondern irgendwie verknüpft ist mit anderen und die dann auch wieder einer Historie unterliegen können. Das kann dann sehr komplex werden.
Mit den Temporalen Tabellen habe ich ganz andere Auswertemöglichkeiten, wie hier beschrieben:
https://learn.microsoft.com/de-de/sql/relational-databases/tables/querying-data-in-a-system-versioned-temporal-table?view=sql-server-ver16
Hallo Christian,
danke für deinen Beitrag.
Aber nichts anderes mache ich heute. Wenn eine neue Kursbelegung dazu kommet, erstelle ich einen neuen Satz in der Tabelle Kursbelegung mit einem Erfassungsdatum und schon habe ich die Historie, für neue KB.
Nur bei Löschungen dürfte ich den Satz nicht physisch löschen, sondern müßte ihn z.B. mit einem "gültigbis Datum" kennzeichnen.
Ein update einer KB bezgl. Kurs ist ja nicht weiteres als ein delete mit darauf folgenden insert, so das dann die grade beschriebenen Mechanismen greifen.
Aber nichts anderes machen doch die temporalen Tabellen auch, oder sehe ich das falsch?
Das würde man sicherlich noch hinbekommen...es wird nur diffiziel, wenn noch abhängige Tabellen ins Spiel kommen.
Ich versuche mir Dinge immer bildlich vozustellen. In diesem Szenario sehe die die aktuellen Daten wie auf einem Plateau,ganz oben. Von jeder Tabelle geht eine Treppe nach unten auf der dann die historischen Daten liegen. Kommt eine Version dazu, steigen alle anderen eine Stufe weiter runter und die neue nimmt oben, eine Stufe unter dem Plateau, Platz.
Die Beziehungen zu anderen Tabellen wandern dann auch mit runter, das kann schon recht komplex werden.
Das zu programmieren wäre eine Aufgabe für einen (wie sagen wir im Ruhrgebiet) für einen der Mutter unf Vatter erschlagen hat.
Dazu kommen noch die erweiterten Auswertemöglichkeiten...also für mich haben die temporalen Tallen immer noch die Nase vorn.
Aber ich bleibe weiter dran und hoffe nicht zu langweilen und will mich keineswegs aufdrängen! Wenn ich das tun sollte, bitte ich um Nachricht.
Auch bin ich dankbar für die fachliche Diskussion.
Martin
Zitat von: MartinHan am Januar 26, 2025, 01:20:56In unseren Verträgen steht:
Mit der Speicherung und Auswertung der Daten nur für den internen Gebrauch bin ich einverstanden.
Mal ganz davon abgesehen, ob das so ausreicht (ich denke eher nicht), was machst du denn, wenn ein Kunde euch explizit zur Löschung seiner Daten auffordert?
Das nur mal als Denkanstoß.
Hallo Martin,
in SQL Server gibt es übrigens auch die Option "SET DEFAULT" bei Löschweitergabe. Wenn Du z.B. eine Dummy-Person mit ID 0 anlegst, kannst Du das als Default für eine Personen-ID eintragen. Das kann man auch im Frontend nutzen, um z.B. schon andere Daten zu erfassen, die Person später anzulegen und dann erst in den Kursdaten auswählen.
Vor allem aber kann man das nutzen, wenn jemand verlangt, seine Personendaten zu löschen. SQL Server tauscht dann die PersonenID gegen die 0 aus (oder was immer Du als DummyID benutzen willst), löscht dann aber z.B. die Kursdaten nicht.
Das hat den Vorteil, daß diese von da an anonymisiert sind. Dem Unternehmen gehen die Informationen aber nicht verloren, d.h., man kann z.B. Statistiken über die beliebtesten Kurse oder die, die am meisten einbringen, weiterhin fahren, da solche ohnehin nicht Personendaten mit einschließen. Bei einer normalen Löschweitergabe würden die Daten aber weg sein und dann wird es schwierig.
Der Unterschied der früheren Kurse in der gleichen Tabelle zu History-Tabellen ist ganz einfach, daß die History-Tabellen wirklich JEDE Änderung an einem Datensatz speichern. Nervöse Menschen wie wir Programmierer speichern immer alle paar Sekunden nach einer Änderung ( ;) ), und wenn ein User das auch macht, wird jedesmal ein neuer Datensatz in der History-Tabelle angelegt. Also z.B. einen Namen ändern, dann speichern, dann feststellen, da fehlt noch ein Buchstabe, dann speichern, ach, da ist noch ein Bindestrich zuviel, ändern, speichern... sind schon drei Datensätze in der History-Tabelle. Für Audits ist sowas gut, weil es "forensische" Daten sichert, also wirklich jede Änderung festhält. Für Deinen Zweck ist es sicherlich einfacher, nur einen neuen Kurs anzulegen und den alten entsprechend zu markieren (etwa mit einem Bis-Datum etc.) und dann kann man so oft Änderungen speichern, wie man will. Du hast dann die Kontrolle, welche Änderungen zu neuen Datensätzen führen. Bei History-Tabellen wird jede Änderung an jedem Feld der Tabelle gespeichert. Abhängige Tabellen sind hiermit ebenso ausgeschlossen, da History-Tabellen sich nur auf die Tabelle beschränken, für die sie angelegt wurden.
In dem Kurs-Szenario sehe ich jetzt aber auch nicht sooo viele Abhängigkeiten. Darüber hinaus hättest Du die Möglichkeit, alle zusammenhängenden Daten auch in eine Extratabelle zu schreiben, auch redundant. So wird es etwa in den üblichen Datawarehouse-Datenbanken gemacht, um einfaches und schnelles Reporting zu ermöglichen, da kommt es nicht auf Normalisierung und nicht auf Speicherplatz an. Somit legst Du dann quasi eine Reporting-Datenbank an (kann auch eine getrennte Datenbank sein), ohne zwingend gleich ein professionelles Datawarehouse-Schema zu bauen (was seine ganz eigenen Regeln hat, die ganz anders sind als OLTP-Datenbanken). Also quasi ein Journal, je nachdem, was man sichern möchte, auch mehrere. Damit fallen Abhängigkeiten ganz weg und Du hast ein einfaches Reporting. Quasi die Vorteile aus History-Tabellen und Datawarehouse, aber sehr vereinfacht.
Dabei sind auch nicht zwingend Trigger notwendig (würde ich auch nicht empfehlen, da es zum einen die Speicherung der Daten ein wenig verlangsamt und außerdem muß man sehr vorsichtig bei deren Programmierung sein). Stattdessen z.B. ein Job in einer Reporting-Datenbank, der dort automatisiert z.B. jede Stunde oder wie aktuell es sein soll eine SP auf der Reporting-Datenbank startet, die dann alle aktuellen Daten in die entsprechenden Journaltabellen schreibt.
Berichte, sei es Access, Excel, SSRS, PowerBI oder was immer Du so verwendest, können dann außerdem unabhängig von der eigentlichen Datenbank erstellt werden und belasten diese nicht. Ebenso möglich, die Datenbank auf einen ganz anderen Server zu verlegen, wenn man Performance aufteilen will (aber ich denke, bei einer Ballettschule wohl eher nicht notwendig.. ).
Gruß
Christian
PhilS:
Da sprichst du ein generelles Problem an, was mich schon immer beschäftgt hat.
Ich war 30 Jahre in einem großen IT Unternehmen für Banken beschäftigt.
Dort wurden jeden Tag zig Magnetbänder in einem atomsicheren Bunker verbracht und dort 10 Jahre aufbewahrt (so schreibt es das Gesetz vor).
Wenn jetzt ein Kunde fordert, das alle seine Daten gelöscht werden, so kann er das tun...in den aktuellen Beständen kein Problem.
Es werden aber mit Sicherhet nicht alle Magnetbänder der letzten Jahre durchgesucht, um diesen einen Kunden zu löschen um diese dann neu zu erstellen. Das wird nicht passieren.
Vergleichbar ist es mit unserer kleinen Anwendung.
Natürlich haben wir Sicherungen, als Db-Backup, aber bei aller Geneigheit, ich werde die jetzt nicht wieder einzeln laden, den Kunden entfernen und ein neues Backup ersatellen.
Ich denke, das ist ein Fact, den wir als IT-Leute eingestehen müssen und es wird auch der Öffentlichkeit nicht bewußt sein.
Frage beantworted?
Martin
Christian
Danke!
Du schreibst immer so ausführlich, das mus ich erstmal sacken lassen---
Melde mich morgen
Martin
Hallo Martin,
ich bin berüchtigt für "kurze" Nachrichten... :D
Zum Backup gibt es hier z.B. einen Artikel (sicherlich nicht rechtlich verbindlich):
https://ra-bock.de/blog/ungel%C3%B6ste-frage-im-datenschutz.-m%C3%BCssen-personenbezogene-daten-in-einem-backup-gel%C3%B6scht-werden,-wenn-der-betroffene-eine-l%C3%B6schung-nach-art.-17-dsgvo-verlangt
Gruß
Christian
Zitat von: MartinHan am Januar 31, 2025, 00:04:12Natürlich haben wir Sicherungen, als Db-Backup, aber bei aller Geneigheit, ich werde die jetzt nicht wieder einzeln laden, den Kunden entfernen und ein neues Backup ersatellen.
[...]
Frage beantworted?
Es war nicht direkt eine Frage, "beantwortet" ist sie allerdings nicht.
Das Magnetband/Backup-Szenario wurde mit Inkrafttreten der DSGVO häufig angeführt und diskutiert. - Aus meiner Sicht eher unnötig.
1.) Mit einer gesetzlichen Aufbewahrungsfrist kannst du ein Löschersuchen nach DSGVO zurückweisen.
2.) Daten in einem Backup sind natürlich noch gespeichert, aber sie sind nicht mehr in der aktiven Verarbeitung und werden dieser auch nicht wieder zugeführt, ausser evtl. in einem außergewöhnlichen, sicherlich dokumentierten, Disaster-Recovery-Fall. Nach Ablauf einer definierten Aufbewahrungsfrist, egal ob gesetzlich oder firmenintern, werden sie dann automatisch gelöscht.
Solange deine Historientabellen ein rein technisches Audit-Log sind, könnte man da noch ähnlich argumentieren. Insbesondere wenn es auch dort eine begrenzte Aufbewahrungsfrist gibt.
Dein aktuelles Vorhaben, so wie ich es im Moment verstehe, ist es aber diese Historientabellen den Benutzern direkt für Auswertungen zugänglich zu machen. - Wenn du das tust, ändert sich die Rolle der Historientabellen von einen technischen Audit-Log zu einer aktiven Verarbeitung.
Aus der aktiven Verarbeitung musst du Daten auf ein Löschersuchen nach DSGVO hin aber durchaus löschen, wenn dem nicht direkt rechtliche Pflichten widersprechen.
Hallo,
jetzt komm ich wieder mit meiner Meinung um die Ecke. :)
Wenn ich mir den Aufwand betrachte, den Martin für diese Historientabellen aufwendet, so bin ich nach wie vor der Auffassung, dass ein normalisierter Aufbau der DB viel, viel geeigneter ist historische Daten abzubilden, als das aufwendige Konstrukt mit den Historientabellen.
Was die DSGVO so habe ich dazu mal eine Frage an die Experten:
Wenn die DB normalisiert aufgebaut ist, so gibt es die Personendaten in genau einer Tabelle. Wenn jetzt jemand seine Daten gelöscht haben will, würde es da nicht genügen in der Personentabelle die echten Personendaten mit z.B. XXXX zu überschreiben ?
Würde da das Überschreiben (XXXX) nur des Nachnamens nicht schon genügen.
Die Originaldaten sind ja dann unwiederbringlich weg (von Backups mal abgesehen). Und alle Tabelle mit einem Fremdschlüssel zur Person können uneingeschränkt benutzt werden, ohne dass es einen Bezug gibt zur Person.
Würde das nicht ausreichen ?
Zitat von: MzKlMu am Januar 31, 2025, 10:03:13Wenn die DB normalisiert aufgebaut ist, so gibt es die Personendaten in genau einer Tabelle. Wenn jetzt jemand seine Daten gelöscht haben will, würde es da nicht genügen in der Personentabelle die echten Personendaten mit z.B. XXXX zu überschreiben ?
Eher nein.
Erstmal müsstest du sicherstellen, dass nirgends sonst Daten gespeichert sind, die Rückschlüsse auf die Identität der Person zulassen (TelNr, Email, Kontonummern, Adressen, usw.). Insbesondere Freitext/Kommentar-Felder sind ein unterschätztes Risiko, weil da oft auch Personendaten drinstehen.
Auch eigentlich neutrale Informationen, wie Z.B. eine Kundennummer, sind problematisch, wenn sie zusammen mit zuvor erstellen Dokumenten (Geschäftsbriefe, Rechnung, etc.) Rückschlüssel auf die Identität zulassen.
Man könnte generell argumentieren, dass eine Kundennummer dadurch dass sie einem Kunden zugewiesen wurde, dauerhaft, also auch wenn die anderen Kundendaten überschrieben sind, als Personenbezogenes Datum im Sinne der DSGVO gilt.
Nur den Nachnamen zu überschreiben reicht definitiv nicht aus.
Hallo,
also der Aufwand für die Historientabellen hält sich doch sehr in Grenzen.
Ich muss für jede Tabelle, die historisiert werden soll eine Historientabelle mit den identischen Spalten wie die ursprüngliche anlegen. Dann mit "alter Table" zwei Datetime2 Spalten an die unsprüngliche Tabelle anfügen und den Prozess aktivieren. Wenn man erstmal verstanden hat wie es geht, Sache von Minuten.
Dann im Access FE einige Abfragen oder über ein StP auf die Historie einrichten, auch das ist relativ einfach.
Dann kann man natürlich Auswertungen verfassen, bis ich meinen letzten Atemzug mache, also z.B. über "Schülerwanderungen", also wieviele sind von einem Grundkurs zu einem Fortgeschrittenen Kurs "gewandert", da ist noch vieles denkbar.
Was die rechtliche Seite angeht bin ich noch unsicher. Wir haben alle Kursänderungen auch schriftlich in Form von Vertragsänderungen in Papierform, die Daten liegen also vor. In allen diesen Vertragsänderungen steht das Passus, das der Kunde mit der Speicherung der Daten nur für den internen Gebrauch einverstanden ist.
Es ist bis jetzt noch nicht zu einem Rechtsstreit gekommen, knock on wood...
Das Löschen der Daten aus Historientabellen ist auch nicht ganz trivial. ich lese mich da noch ein.
Es gibt aber wohl einen Parameter der dazu führt, das die historischen Daten nach einem definierten Zeitraum automatisch gelöscht werden. Das werde ich mir noch anschauen.
Aber ich teste noch weiter.
Martin
Hi,
das mit dem Komplett-Löschen der Daten habe ich jetzt verstanden und auch schon getestet.
Man muss bei allen beteiligten Tabellen
SYSTEM_VERSIONING = OFF
setzen, dann sind die Historischen Tabellen wie ganz normale Tabellen.
Dann die Löschung durch führen und danach wieder
SYSTEM_VERSIONING = ON
Dann ist die Person komplett gelöscht.
q.e.d
Martin
Hallo Christian,
nach einigen Tagen in stiller Askese und Programmierung bin ich ich doch zu der Überzeugung gekommen, dass die Temporalen Tabellen doch eine gute Lösung sind.
Würde ich das selbst machen, liefe es doch auf stwas ähnliches hinaus, ich muss speichern, von wann bis wann ein Datensatz gültig war, ich wüßte nicht, wie es sonst gehen sollte.
Nichts anderes machen die temporalen, bzw. historischen Tabellen...
Nur das das ganze Geraffel von der DB erledigt wird, von mir keine einzelne Zeile Coding, finde ich gut.
Ich bin jetzt dabei in meinem Access-Fe Abfragen und Auswertungen zu entwicklen, klappt prima!
Ich hatte mir selbst ein Archiv-System bebastelt, das kann ich ietzt in die Tonne kloppen.
Danke für deine Beiträge!
Martin
Hallo Martin,
alles gut - wenn es für Dich paßt, warum nicht?
Am besten testest Du mal die Historien-Tabellen mit Auswertungsabfragen - denn sie sollen ja nicht dem Selbstzweck dienen, Du möchtest daraus ja Informationen gewinnen.
Dann kann man am ehesten sehen, ob sie für Dich das leisten, was Du Dir davon erhofft hast.
Gruß
Christian
Hallo,
ein für mich unerklärliches Phänomen:
Wenn ich einen Datensatz ändere, wird ja ein historischer DS erzeugt und die validvon bzw. validbis Felder angepasst.
Das klappt auch soweit, nur ist das Datum der Änderung eine Stunde zurück...
Der Server ist für die Entwicklung lokal installiert, die Systemzeit passt.
So habe ich die Historisierung definiert (bei einer schon bestehenden Tabelle)
/****** Object: Table [history].[Person] Script Date: 21.01.2025 17:15:25 ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[history].[Person]') AND type in (N'U'))
DROP TABLE [history].[Person]
GO
/****** Object: Table [History].[Person] Script Date: 21.01.2025 17:15:25 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [history].[Person](
[PersonId] [int] NOT NULL,
[NachName] [nvarchar](255) NULL,
[Vorname] [nvarchar](255) NULL,
---weitere Spalten ....
ValidFrom DATETIME2(0) NOT NULL,
ValidTo DATETIME2(0) NOT NULL,
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[person]
ADD ValidFrom datetime2(0) GENERATED ALWAYS AS ROW START HIDDEN
CONSTRAINT DF_person_SysStart DEFAULT DATEADD(second, -1, SYSUTCDATETIME()),
ValidTo datetime2(0) GENERATED ALWAYS AS ROW END HIDDEN
CONSTRAINT DF_person_SysEnd DEFAULT CONVERT(datetime2 (0), '9999-12-31 23:59:59'),
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo);
GO
ALTER TABLE [dbo].person
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [History].person));
GO
CREATE NONCLUSTERED INDEX IX_person_ID_Period_Columns
ON History.person (ValidTo, ValidFrom,personid);
GO
Danke für Hilfe
Martin
Hallo Martin,
das Problem ist, daß SQL Server UTC Time verwendet.
Die Lösung ist "AT TIME ZONE" zu verwenden, wie hier beschrieben:
https://learn.microsoft.com/en-us/sql/relational-databases/tables/temporal-table-usage-scenarios?view=sql-server-ver16&redirectedfrom=MSDN
Gruß
Christian
oh my Buddha, ein endloser Artikel...
Bitte in Kurzform...
was much ich ändern?
Hallo Martin,
suche auf der Seite einfach nach "AT TIME ZONE", dann findest Du die passenden Beispielcodes.
Gruß
Christian
Ok, habe ich jetzt verstanden.
Danke.