Benutzer mit den meisten Antworten
2 Tabellen mit 1:1-Beziehung synchronisieren?

Frage
-
Hallo,
ich habe zwei Tabellen:
- personal
idx int,fname varchar(50),lname varchar(50),
primary key(idx) - personal_detail
idx int,detail_1 int,detail_2 int,
primary key (idx),
foreign key (idx) references personal(idx) on delete cascade
Diese beiden Tabellen sollen immer synchron sein, d. h. wenn für jeden Eintrag in der Tabelle personal soll es einen Eintrag in der Tabelle personal_detail geben.
Das kann ich natürlich auf Anwendungsebene machen, aber ist es auch auf Datenbankebene möglich?
Wie würde man das realisieren? Falls man es mit einem INSTEAD OF-Trigger lösen könnte, wie würde dieser dann genau aussehen? Wie geht man insbesondere damit um, wenn ein INSERT-Befehl nur einige aber nicht alle Attribute enthielte?
Danke
Magnus - personal
Antworten
-
Hallo Knorpi,
Du hast Recht - die Fremdschlüsseleinschränkung bezieht sich nur die Detailtabelle aber nicht auf die Mastertabelle. Wie Benjamin bin ich selbst auch immer etwas skeptisch in Bezug auf Trigger. Sie haben einige Nachteile, die halt abgewogen werden müssen (Dabei lasse ich mal die Probleme aus Sicht eines Programmierers aussen vor!):
- Trigger erzeugen temporäre Objekte (INSERTED und DELETED) in TEMPDB
- Trigger sind Bestandteil der Benutzertransaktion und blockieren Ressourcen, die im Trigger angesprochen werden
- Die Verwendung von Triggern führt häufig zu Deadlock-Situationen, wenn im Trigger weitere Objekte angesprochen werden (wie in Deinem Beispiel)
Dein Beispiel als Referenz sieht Punkt 2 der "Bedenken" wie folgt aus:
CREATE TABLE dbo.personal ( idx int NOT NULL PRIMARY KEY CLUSTERED, fname char(50) NOT NULL, lname char(50) NOT NULL ); CREATE TABLE dbo.personal_detail ( personal_idx int NOT NULL PRIMARY KEY CLUSTERED, detail_1 int NOT NULL DEFAULT (0), detail_2 int NOT NULL DEFAULT (0), CONSTRAINT fk_personal FOREIGN KEY (personal_idx) REFERENCES dbo.personal (idx) ON DELETE CASCADE ); GO -- Insert ONE record to avoid system blocked resources -- when locks are investigated INSERT INTO dbo.personal (idx, fname, lname) VALUES (1, 'Uwe', 'Ricken'); GO -- Create the trigger for insertion of data in reference table CREATE TRIGGER dbo.trg_personal_io_insert ON dbo.personal INSTEAD OF INSERT AS SET NOCOUNT ON; -- Insert data from personal INSERT INTO dbo.personal SELECT * FROM inserted; -- Insert data into referencial table INSERT INTO dbo.personal_detail (personal_idx) SELECT i.idx FROM inserted AS i LEFT JOIN dbo.personal_detail AS d ON (i.idx = d.personal_idx) WHERE d.personal_idx IS NULL; SET NOCOUNT OFF; GO
Das obige Beispiel habe ich aus Deinen Anforderungen entnommen und den entsprechenden Trigger (hätte auch ein INSERT-Trigger sein können) implementiert. Nun wird ein weiterer Datensatz eingetragen. Dabei wird aber dieser Vorgang in einer expliziten Transaktion ausgeführt. Ich lasse die Transaktion zunächst geöffnet!
BEGIN TRANSACTION insertdata; GO INSERT INTO dbo.personal (idx, fname, lname) VALUES (2, 'Beate', 'Ricken'); SELECT resource_type, CASE WHEN resource_type = N'OBJECT' THEN OBJECT_NAME(resource_associated_entity_id) ELSE CAST(resource_associated_entity_id AS nvarchar(255)) END AS resource_type, request_mode, request_type, request_status FROM sys.dm_tran_locks WHERE request_session_id = @@SPID;
Der erste Teil der Abfrage fügt in die Tabelle dbo.personal einen neuen Datensatz ein. Im zweiten Statement überprüfe ich, welche Ressourcen durch die Benutzertransaktion blockiert sind.
An der Abbildung kannst Du sehr schön erkennen, dass Ressourcen beider Tabellen blockiert werden. Solange die Transaktion nicht abgeschlossen ist, kann keine der beiden Ressourcen freigegeben werden und andere Prozesse müssen warten.
1:1-Beziehungen machen - entgegen der Meinung von Benjamin - in manchen Szenarien sicherlich Sinn. Zum Beispiel sind sie sinnvoll, wenn nur wenige Datensätze in der "Master"-Tabelle zugehörige Detaildaten besitzen; nur dieses Szenario ist in Deinem Modell nicht vorgesehen - also (aus meiner Sicht) kein Vorteil!
Sie kommen aber eher selten vor. Tatsächlich - und da bin ich wieder auf der Seite von Benjamin - sind die Informationen der "Detailtabelle" ja vollständig vom Schlüssel der Mastertabelle abhängig; und damit wiederum sollten sie Bestandteil der Mastertabelle sein.
1:1-Beziehungen haben wir in der Entwicklung in den 90ern verwendet, um z. B. Personendaten von Gehaltsdaten zu trennen. Letztendlich ging das aber immer zu Lasten der Performance, da ja ein JOIN zwischen Master und Detail vorhanden sein musste. Besser ware ein Konzept, in dem Du keinen Zugriff auf die Tabellen selbst sondern auf Views oder Stored Procedures erteiltst, die wiederum die Sicht auf die Daten einschränken.
MCM - SQL Server 2008
MCSE - SQL Server 2012
db Berater GmbH
SQL Server Blog (german only)- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Dienstag, 29. März 2016 06:37
- Als Antwort markiert Aleksander Chalabashiev Dienstag, 5. April 2016 08:58
-
So habe mal ein Beispiel für die gespeicherte Prozedur fertig (nicht schön aber sollte als Beispiel funktionieren)
use master go create database demodb go use demodb go create table personen_details( id int not null, abteilung char(20) not null, geburtstag date not null, CONSTRAINT PK_ID PRIMARY KEY NONCLUSTERED (id)); go create table personen( id int not null, name char(20) not null, vorname char(20) not null, CONSTRAINT FK_personen_details FOREIGN KEY (id) REFERENCES personen_details (id) ON DELETE CASCADE ON UPDATE CASCADE) go CREATE PROCEDURE Personeninsert @id int, @Name char(20), @Vorname char(20), @abteilung char(20), @geburtag date AS insert into personen_details values(@id,@abteilung,@geburtag); insert into personen values (@id, @Name,@Vorname); GO exec Personeninsert 2 ,'Name' ,'Vorname' ,'IT' ,'01/01/2000'
Gruß Benjamin
PS. Meine Ablehnung für 1:1 Realtionen stammt noch aus dem Studium wo man für sowas gleich böse Punkte abgezogen bekommen hat. Stichwort Normalisierung
Benjamin Hoch
MCSE: Data Platform
MCSA: Windows Server 2012
Blog
- Bearbeitet Benjamin.Hoch Mittwoch, 23. März 2016 06:47
- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Dienstag, 29. März 2016 06:37
- Als Antwort markiert Aleksander Chalabashiev Dienstag, 5. April 2016 08:58
Alle Antworten
-
Hallo Knorpi,
wenn ich deine Tabellendefinition richtig lese, dann hast du es bereits richtig umgesetzt. Um dein Ziel zu erreichen muss man eine Fremdschlüsselbeziehung setzt
https://msdn.microsoft.com/de-de/library/ms189049%28v=sql.120%29.aspx?f=255&MSPPError=-2147217396
Durch das setzten von "not null" wird erzwungen dass es auch einen Wert in der anderen Tabelle geben muss. SOnst gibt es eine Fremdschlüsselverletzung. Trigger braucht man nur wenn die beiden Tabellen nicht in der selben Datenbank sind.
Wenn du nur eine 1:1 Beziehung hast, kannst du die zweite Tabelle besser weg lassen und alle Daten in die erste Tabelle schreiben. Eine zweite Tabelle macht eigentlich erst ab einer 1:n Beziehung sinn.
Wenn ein Atribut immer angegeben werden muss, wird die entsprechende Spalte mit "not Null" definiert. So wird sichergestellt dass ein Wert vorhanden sein muss. Ohne den Wert würde der Einfügevorgang abbrechen.
Gruß Benjamin
Benjamin Hoch
MCSE: Data Platform
MCSA: Windows Server 2012
Blog -
Hallo Benjamin,
danke für Deine Hinweise.
Die FOREIGN KEY-Klausel bewirkt m. M. nach nur, dass die Werte für idx in der Tabelle personal_detail aus der Tabelle personal kommen müssen.
Aber wie kann man erreichen, dass bei einem INSERT in der Tabelle personal automatisch eine entsprechende Zeile in in der Tabelle personal_detail angelegt wird?
Magnus
-
Hallo Magnus,
das ginge bspw. über einen Trigger in "personal". Siehe dazu bspw.:
Also in etwa so:
CREATE TRIGGER [dbo].[AddPersonalDetail] ON [dbo].[personal] AFTER INSERT AS BEGIN SET NOCOUNT ON; INSERT INTO dbo.personal_detail( detail_1 ) SELECT idx FROM inserted END GO
Beachte aber, dass ein Trigger nicht zwingend für einen einzigen Datensatz ausgeführt wird. Die inserted und deleted Tabellen können, wie jede andere Tabelle auch, x Datensätze gleichzeitig beinhalten. Das sollte man berücksichtigen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Ein Trigger ist hier keine gute Wahl. Da es sich um eine 1:1 Beziehung handelt frage ich mich aber immer noch warum es zwei getrennte Tabellen gibt.
Wenn du dies aber dennoch so umsetzen möchtest empfehle ich dir eine gespeicherte Prozedur welche automatisch einen Insert in beide Tabellen macht.
https://msdn.microsoft.com/de-de/library/ms345415%28v=sql.120%29.aspx?f=255&MSPPError=-2147217396
Benjamin Hoch
MCSE: Data Platform
MCSA: Windows Server 2012
Blog -
Hallo Benjamin,
warum ist ein Trigger hier keine gute Wahl?
Die gespeicherte Prozedur kann man umgehen, das INSERT nicht.
Ansonsten kann es durchaus Gründe für eine separate Tabelle mit 1:1-Beziehung geben. Das möchte ich in diesem Thread aber nicht weiter thematisieren.
Magnus
-
Hallo Magnus,
Warum ist der Trigger hier keine gut Wahl? Nun der Trigger kann zwar super einen neuen Eintrag in der zweiten Tabelle setzten. Aber was kann den der Trigger dort sinnvoll eintragen? Nicht außer dem Fremdschlüssel den es aus der ersten Tabelle bekommt. Woher soll der Trigger auch die anderen Informationen bekommen. Entweder stehen sie schon in der ersten Tabelle (dann brauche ich sie in der zweiten nicht) oder der Trigger kann hellsehen. Somit würde der Trigger einen Datensatz ohne inhaltlichen nutzen produzieren. Ob einem durch einen Datensatz mit Nullwerten und dem Fremdschüssel geholfen ist? Da kann ich auch alle paar Stunden prüfen ob es neue Datensätze in der einen Tabelle gibt und die fehlenden dann nachträglich erzeugen. Die fehlenden Datensätze kann man dann ganz leicht durch einen Left Join (Right Join ginge auch) herausfinden.
Eine richtig gesetzte Fremdschlüsselbeziehung kann man nicht umgehen. Entweder man gibt gleich alle nötigen Informationen mit um beide Tabellen sinnvoll zu füllen oder der Insert scheitert. Von daher wäre es auch überhaupt kein Problem die gespeicherte Prozedur zu umgehen, denn auch ein direkter Insert ohne die erforderlichen Werte für beide Tabellen würde scheitern. Die gespeicherte Prozedur würde hier nur als Hilfsmittel dienen alle Daten korrekt zu erfassen und als Paarinsert zu verarbeiten.
So ich hoffe mal es klar geworden warum ich es nicht über einen Trigger lösen würde.
Gruß Benjamin
Benjamin Hoch
MCSE: Data Platform
MCSA: Windows Server 2012
Blog -
Hallo Benjamin,
Deine Aussage zu der Fremdschlüsselbeziehung würde ich gerne nochmal vertiefen:
"Eine richtig gesetzte Fremdschlüsselbeziehung kann man nicht umgehen."
So wie ich die Beziehung definiert habe, stellt diese nur sicher, dass als Werte für das Attribut idx in der Tabelle personal_detail nur existierende Werte aus der Tabelle personal in Frage kommen, mehr nicht. Habe ich hier eventiell nicht alle Möglichkeiten ausgeschöpft?
Ansonsten kann ich diese Fremdschlüsselbeziehung sehr wohl ignorieren, indem ich zu einem Eintrag in personal den zugehörigen Eintrag in personal_detail einfach nicht erstelle.
Gruss
Magnus
-
Hallo Knorpi,
Du hast Recht - die Fremdschlüsseleinschränkung bezieht sich nur die Detailtabelle aber nicht auf die Mastertabelle. Wie Benjamin bin ich selbst auch immer etwas skeptisch in Bezug auf Trigger. Sie haben einige Nachteile, die halt abgewogen werden müssen (Dabei lasse ich mal die Probleme aus Sicht eines Programmierers aussen vor!):
- Trigger erzeugen temporäre Objekte (INSERTED und DELETED) in TEMPDB
- Trigger sind Bestandteil der Benutzertransaktion und blockieren Ressourcen, die im Trigger angesprochen werden
- Die Verwendung von Triggern führt häufig zu Deadlock-Situationen, wenn im Trigger weitere Objekte angesprochen werden (wie in Deinem Beispiel)
Dein Beispiel als Referenz sieht Punkt 2 der "Bedenken" wie folgt aus:
CREATE TABLE dbo.personal ( idx int NOT NULL PRIMARY KEY CLUSTERED, fname char(50) NOT NULL, lname char(50) NOT NULL ); CREATE TABLE dbo.personal_detail ( personal_idx int NOT NULL PRIMARY KEY CLUSTERED, detail_1 int NOT NULL DEFAULT (0), detail_2 int NOT NULL DEFAULT (0), CONSTRAINT fk_personal FOREIGN KEY (personal_idx) REFERENCES dbo.personal (idx) ON DELETE CASCADE ); GO -- Insert ONE record to avoid system blocked resources -- when locks are investigated INSERT INTO dbo.personal (idx, fname, lname) VALUES (1, 'Uwe', 'Ricken'); GO -- Create the trigger for insertion of data in reference table CREATE TRIGGER dbo.trg_personal_io_insert ON dbo.personal INSTEAD OF INSERT AS SET NOCOUNT ON; -- Insert data from personal INSERT INTO dbo.personal SELECT * FROM inserted; -- Insert data into referencial table INSERT INTO dbo.personal_detail (personal_idx) SELECT i.idx FROM inserted AS i LEFT JOIN dbo.personal_detail AS d ON (i.idx = d.personal_idx) WHERE d.personal_idx IS NULL; SET NOCOUNT OFF; GO
Das obige Beispiel habe ich aus Deinen Anforderungen entnommen und den entsprechenden Trigger (hätte auch ein INSERT-Trigger sein können) implementiert. Nun wird ein weiterer Datensatz eingetragen. Dabei wird aber dieser Vorgang in einer expliziten Transaktion ausgeführt. Ich lasse die Transaktion zunächst geöffnet!
BEGIN TRANSACTION insertdata; GO INSERT INTO dbo.personal (idx, fname, lname) VALUES (2, 'Beate', 'Ricken'); SELECT resource_type, CASE WHEN resource_type = N'OBJECT' THEN OBJECT_NAME(resource_associated_entity_id) ELSE CAST(resource_associated_entity_id AS nvarchar(255)) END AS resource_type, request_mode, request_type, request_status FROM sys.dm_tran_locks WHERE request_session_id = @@SPID;
Der erste Teil der Abfrage fügt in die Tabelle dbo.personal einen neuen Datensatz ein. Im zweiten Statement überprüfe ich, welche Ressourcen durch die Benutzertransaktion blockiert sind.
An der Abbildung kannst Du sehr schön erkennen, dass Ressourcen beider Tabellen blockiert werden. Solange die Transaktion nicht abgeschlossen ist, kann keine der beiden Ressourcen freigegeben werden und andere Prozesse müssen warten.
1:1-Beziehungen machen - entgegen der Meinung von Benjamin - in manchen Szenarien sicherlich Sinn. Zum Beispiel sind sie sinnvoll, wenn nur wenige Datensätze in der "Master"-Tabelle zugehörige Detaildaten besitzen; nur dieses Szenario ist in Deinem Modell nicht vorgesehen - also (aus meiner Sicht) kein Vorteil!
Sie kommen aber eher selten vor. Tatsächlich - und da bin ich wieder auf der Seite von Benjamin - sind die Informationen der "Detailtabelle" ja vollständig vom Schlüssel der Mastertabelle abhängig; und damit wiederum sollten sie Bestandteil der Mastertabelle sein.
1:1-Beziehungen haben wir in der Entwicklung in den 90ern verwendet, um z. B. Personendaten von Gehaltsdaten zu trennen. Letztendlich ging das aber immer zu Lasten der Performance, da ja ein JOIN zwischen Master und Detail vorhanden sein musste. Besser ware ein Konzept, in dem Du keinen Zugriff auf die Tabellen selbst sondern auf Views oder Stored Procedures erteiltst, die wiederum die Sicht auf die Daten einschränken.
MCM - SQL Server 2008
MCSE - SQL Server 2012
db Berater GmbH
SQL Server Blog (german only)- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Dienstag, 29. März 2016 06:37
- Als Antwort markiert Aleksander Chalabashiev Dienstag, 5. April 2016 08:58
-
Es gibt schon Fälle, wo 1:1-Beziehungen Sinn machen, z.B. bei Personen und LastLoginID oder LastPageVisited - die häufig aktualisiert werden und daher nicht in der Stammtabelle stehen müssen - manchmal will man daraus evtl. auch eine 1:n-Tabelle machen. Der Unterdatensatz sollte aber immer optional sein, Krücken mit Trigger etc. machen es unnötig kompliziert und können auch die Performance beeinträchtigen.
Sebastian Leupold (MVP)
-
So habe mal ein Beispiel für die gespeicherte Prozedur fertig (nicht schön aber sollte als Beispiel funktionieren)
use master go create database demodb go use demodb go create table personen_details( id int not null, abteilung char(20) not null, geburtstag date not null, CONSTRAINT PK_ID PRIMARY KEY NONCLUSTERED (id)); go create table personen( id int not null, name char(20) not null, vorname char(20) not null, CONSTRAINT FK_personen_details FOREIGN KEY (id) REFERENCES personen_details (id) ON DELETE CASCADE ON UPDATE CASCADE) go CREATE PROCEDURE Personeninsert @id int, @Name char(20), @Vorname char(20), @abteilung char(20), @geburtag date AS insert into personen_details values(@id,@abteilung,@geburtag); insert into personen values (@id, @Name,@Vorname); GO exec Personeninsert 2 ,'Name' ,'Vorname' ,'IT' ,'01/01/2000'
Gruß Benjamin
PS. Meine Ablehnung für 1:1 Realtionen stammt noch aus dem Studium wo man für sowas gleich böse Punkte abgezogen bekommen hat. Stichwort Normalisierung
Benjamin Hoch
MCSE: Data Platform
MCSA: Windows Server 2012
Blog
- Bearbeitet Benjamin.Hoch Mittwoch, 23. März 2016 06:47
- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Dienstag, 29. März 2016 06:37
- Als Antwort markiert Aleksander Chalabashiev Dienstag, 5. April 2016 08:58
-
Hallo zusammen,
zunächst einmal vielen Dank für die ausführlichen Hinweise und sorry für die Verspätung...
Der Punktabzug bei fehlender Normalisierung war im Studium schon richtig. Aus heutiger Sicht würde ich das aber vorsichtig vergleichen wollen mit der übertriebenen Kopfbewegung bei der Führerscheinprüfung, damit der Prüfer sieht, dass man in den Spiegel geschaut hat. Die grundlegenden Regeln sind natürlich wichtig, aber nicht immer um jeden Preis. Der Vergleich mag weit her geholt sein, passt m. M. zumindest auf die Ablehnung von 1:1-Tabellen ganz gut. Wenn ich bspw. sehr viele Attribute zu einer Person habe, die in einige wenige Kategorien fallen und ich auf der Oberfläche für jede Kategorie einen eigenen Bereich (z. B. "Tab") habe, dann macht es für mich durchaus Sinn, die Attribute auf verschiedene Tabellen aufzuteilen. Wenn ich das nicht tue und trotzdem die Kategorisierung auch im Modell abbilden möchte, muss ich dies über die Attributnamen tun, z. B. durch die Verwendung von Präfixen (cat1_attr1, cat1_attr2, ...), was das Datenmodell auch nicht gerade kompakter macht. Ich würde daher 1:1-Beziehungen nicht grundsätzlich ablehnen.
Nichtdestotrotz muss ich aber einräumen, dass ich in diesem Fall eigentlich nur eine optionale 1:1-Beziehung brauche, also eine, bei der die Einträge in der Tabelle personal_detail optional sind. Der Grund, warum ich sicherstellen wollte, dass zu jedem Eintrag in der Tabelle personal auch ein Eintrag in der Tabelle personal_detail existiert, ist schlicht die Vermeidung einer Unsicherheit (s. u.) bei der anschliessenden Abfrage.
Zur Erklärung muss ich die Tabellen konkretisieren:
- personal
idx int,fname varchar(50),lname varchar(50),
primary key(idx) - personal_detail
idx int,ersthelfer bit,ersthelfer_ausbildung date,
primary key (idx),
foreign key (idx) references personal(idx) on delete cascade
Das boolesche Attribut ersthelfer gibt an, ob eine Person zu den "Ersthelfern" gehört, also im Notfall erste Hilfe leisten kann. Das Attribut ersthelfer_ausbildung enthält ggf. das Datum, an dem die Person dazu ausgebildet wurde.
Nun soll eine vorhandene, auf der Tabelle personal basierende, Abfrage um diese Attribute erweitert werden. Hier ein vereinfachtes Beispiel mit einem Sub-Select:SELECT idx,fname,lname, (SELECT ersthelfer FROM personal_detail WHERE (idx = personal.idx)) AS ersthelfer FROM personal
Hier soll das Attribut ersthelfer true sein, wenn es einen passenden Eintrag in der Tabelle personal_detail gibt und das darin enthaltene Attribut ersthelfer true ist. In allen anderen Fällen soll es false sein. Leider nimmt es auch den Wert NULL an, wenn es keinen passenden Eintrag in der Tabelle personal_detail gibt. Aber auch in diesen Fällen soll es false sein.
Ich habe hier bewusst ein Sub-Select angegeben, da die Abfrage in Wirklichkeit bereits aus mehreren Joins besteht und ich diese nicht unnötig anwachsen lassen möchte, damit der View "wartbar" bleibt. Auch die Möglichkeit einer Skalar-Funktion ist mir bewusst, aber auch diese möchte ich zunächst vermeiden, da es in der Tabelle personal_detail noch viele solcher Attribute gibt. Wenn es nicht anders geht, tendiere ich aber dazu.
Gibt es eine einfache Möglichkeit, innerhalb des Sub-Selects die NULL-Werte durch false-Werte zu ersetzen? Wie würdet Ihr das ansonsten lösen?
Ansonsten nochmals danke für die Erläuterungen. Ein Trigger scheidet für mich danach aus.
Viele Grüße
Magnus
- Bearbeitet Knorpi Mittwoch, 30. März 2016 06:35
- personal
-
Wenn es dir nur darum geht einen Null wert zu maskieren würde ich hier einfach einen anderen Weg nehmen.
Persönlich wäre mein Weg die allgemeine Tabelle mit zwei zusätzlichen Spalten zu erweitern
istErsthelfer bit not null default (0) Ersthelfer seit date null
solange nichts angebenen wird ist der Status Ersthelfer 0 (false), dieser wird immer vom System automatisch gesetzt. Beim setzten des Datumswertes kann man dann auch automatisch mit ändern lassen.
Oder man definiert ein Datumwert als false wie 01.01.1900 welche dann dort eingetragen wird und dann in der Abfrage über die Where Bedingung gefiltert wird.
istErsthelfer date not null default (01/01/1900)
Gruß Benjamin
Benjamin Hoch
MCSE: Data Platform
MCSA: Windows Server 2012
Blog -
Ich wäre vorsichtig mit "falschen" Default-Werten und zusätzlichen "Merkfeldern" in Tabellen, die zu Inkonsistenzen führen können. Bei BIT-Feldern ist ein Default oft sinnvoll, allerdings kann man auf "istErsthelfer" verzichten, wenn man Null in "ErsthelferSeit" als "kein Ersthelfer" interpretiert.
Will man Nullwerte bei der Übergabe an die Anwendung vermeiden, kann man das bequem in einer View erreichen:
SELECT IsNull(ErsthelferSeit, 1900-01-01T00:00) AS ErsthelferSeit,
CASE WHEN ErsthelferSeit IS Null THEN 0 ELSE 1 END AS IstErsthelfer
FROM PersonalSebastian Leupold (MVP)
-
Hier würde ich einen Join bevorzugen aber sonst
SELECT A.idx,A.fname,A.lname, D.ersthelfer FROM personal_detail as D, personal as A where A.idx = D.idx
Benjamin Hoch
MCSE: Data Platform
MCSA: Windows Server 2012
Blog- Bearbeitet Benjamin.Hoch Mittwoch, 30. März 2016 08:45
-
Hier ist das beste Beispiel warum eine 1:1 Beziehung nicht zielführend ist. Du versucht hier ein Problem zu lösen was du ohne die 1:1 Beziehung gar nicht hättest.
Speicher diese eine Information IstErsthelfer in die normale personal Tabelle und du kannst über ganz simple Select Abfrage alle gewünschten Informationen bekommen und musst nicht auf teure Joins zurückgreifen.
Benjamin Hoch
MCSE: Data Platform
MCSA: Windows Server 2012
Blog -
Benjamin,
ich stimme zu, dass es für eine Eigenschaft keinen Sinn macht, aber wenn dann noch etliche Detailinformationen dazu kommen (Kenntnisse, Prüfungen) und nicht jeder Ersthelfer ist, macht es Sinn, diese in einer Untertabelle abzulegen.
Sebastian Leupold (MVP)
-
Wenn es wie du sagst mehre Eigenschaften werden wie Prüfungen sind, wird es ja keine 1:1 Beziehung mehr da man dann ja am besten einen eignen Datensatz pro Prüfung/Fähigkeit anlegen kann/sollte. Man schreibt ja nicht in ein Char Feld dann "1. Prüfung 16.01.13, 2. Prüfung 19.05.14". Somit bekommt man ja eine 1:n Beziehung welche so absolut richtig in einer Untertabelle aufgehoben ist.
Benjamin Hoch
MCSE: Data Platform
MCSA: Windows Server 2012
Blog -
Wenn es wie du sagst mehre Eigenschaften werden wie Prüfungen sind, wird es ja keine 1:1 Beziehung mehr da man dann ja am besten einen eignen Datensatz pro Prüfung/Fähigkeit anlegen kann/sollte. Man schreibt ja nicht in ein Char Feld dann "1. Prüfung 16.01.13, 2. Prüfung 19.05.14". Somit bekommt man ja eine 1:n Beziehung welche so absolut richtig in einer Untertabelle aufgehoben ist.
Da stimme ich zu, das wäre dann die flexibelste Lösung.Sebastian Leupold (MVP)