Triggerfrage: Bei neuer Wert in Tabelle A eine neue Zeile in Tabelle B

MysterioJN

SQL-Guru
Beiträge
158
Hallo zusammen,

ich hab folgendes Problem:

Es gibt eine "Tabelle A" mit einmaligen Artikelnummern (Stamm).
Dort werden durch ein DNN-Frontend fast täglich neue Artikelnummern angelegt.

Nun benötige ich zugleich die selbe neu angelegte Artikelnummer in "Tabelle B" (Kategorien).

Ich könnte mir vorstellen, das ich mit einem Trigger in der Tabelle A sagen kann, wenn neue Artikelnummer/Datenzeile, dann leg mir in Tabelle B eine neue Datenzeile mit der Artikelnummer an.

Ich hab leider nur keine Ahnung, wie in diesem Fall der Trigger aussehen müsste.

Hoffe ihr könnt mir ein wenig weiterhelfen :-/

Liebe Grüße und schon mal danke fürs Lesen
Marco
 
Werbung:
Trigger-Aufstellung | Datenbank-Forum

Aber hier gerne nochmals:
1. Tabelle erstellen:
Code:
create table t_eins(id serial primary key, value text)

2. Tabelle erstellen:
Code:
create table t_zwei(id serial primary key, value text)

3. Trigger-Procedure erstellen:
Code:
create function copy() returns trigger as $copy$ begin insert into t_zwei(value) values (new.value); return new; end; $copy$ language plpgsql;

4. Trigger erstellen:
Code:
create trigger copy after insert on t_eins execute procedure copy()

Beiwort: Das Ganze natürlich in PostgreSQL geschrieben, aber ja, es sollte auch bei Microsoft SQL möglich sein ;)

EDIT: Habe vergessen, dem Trigger in Code 4 einen Namen zu geben, ausgebessert.
EDIT2: Scheint irgendein Fehler drinnen zu sein, aber ich lasse den Post mal so, wegen bösen Blicken, wenn ich ihn kravierend verändere :D
 
Zuletzt bearbeitet:
MSSQL Trigger unterscheiden sich von denen in PG, sowohl in Syntax als auch im Ablauf. Grundsätzlich geht das natürlich allerdings stellt sich bei deiner Beschreibung eine Sinnfrage, warum?

Wenn es zu jedem Datensatz in Tabelle A genau einen in Tabelle B gibt ist das ein Designfehler, siehe Normalisierung. Reden wir hier von einer 1:1-n Beziehung mag das sinnvoll sein aber dann würde normalerweise das Frontend den Datensatz in B anlegen, so wie es ja auch den Datensatz in A anlegt.
 
@ Ukulele: Hehe das ist dir gleich wieder aufgefallen ;)
Ja, streng genommen nach Normalisierung ist es ein Designfehler. Aber leider ein von den Shopbetreibern "gewollter".


Kurz gesagt, es kann für eine Artikelnummer maximal 5 Kategorien geben. Mehr lässt der Shop nicht zu. Daher Ist die Tabelle B auch tatsächlich "falsch normalisiert" aufgebaut (nicht nach Zeilen sondern nach Spalten) wie etwa:

ID, Artikelnummer, Kategorie1, Kategorie2, Kateogrie3, Kategorie4, Kategorie5

Um also die Kategorien verknüpfen zu können (im Front-End = Edit), bedarf es dem zwingend grundsätzlichen Vorkommen der in Tabelle A angelegten Artikelnummer auch in Tabelle B.
Daher leider meine "blöde" Nachfrage hier :-/
 
Jo dann mach das am besten mit einem Trigger, in etwa so:
Code:
CREATE TRIGGER   [dbo].[triggerA]
   ON       [dbo].[tabelleA]
   FOR INSERT, UPDATE
AS

BEGIN
SET NOCOUNT ON;
INSERT INTO tabelleB(pk_tabelleB,fk_tabelleA)
SELECT newid() AS pk_tabelleB,pk_tabelleA AS fk_tabelleA
FROM INSERTED
LEFT JOIN tabelleB ON pk_tabelleA = fk_tabelleA
WHERE fk_tabelleA IS NULL
END
GO
Damit hat der Datensatz natürlich noch keine Daten und es kann sein das das Frontend nicht merkt, das der Datensatz aktualisiert wurde, das musst du ausprobieren.

Der Join von INSERTED mit tabelleB und die WHERE-Bedingung sollen nur sicherstellen, das noch kein Datensatz existiert.
 
Da hast du mir es schon so vorgekaut und ich bin immer noch zu blöd die Verweise hinzubekommen, da Streng genommen es keinen FK gibt oder?

Spalten Tabelle A:
Primärschlüssel = PIDX
Artikelnummer = ANr

Spalten Tabelle B:
Primärschlüssel = PIDX
Artikelnummer = A_ANr
 
Bzw. ich bekomm immer folgenden Fehler:

Operandentypkollision: uniqueidentifier ist inkompatibel mit int


Kann das an der Funktion "newid()" liegen?
Die PIDX als Primärschlüssel beider Tabellen ist ein Int mit autowert.


Bzw ich schreib es mal nun wie es wirklich in den Tabellen heißt:
Artikelnr = BstNr

Tabelle A: MedKopf
Spalten: PIDX = INT/PK, BstNr = nvarchar(10)

Tabelle B: MedKategorie
Spalten: PIDX = INT/PK, Medkopf_BstNr = nvarchar(10)

Also folgendes getestet:

Code:
CREATE TRIGGER   [dbo].[Tr_MedKategorie]
   ON       [dbo].Medkopf
   FOR INSERT, UPDATE
AS

BEGIN
SET NOCOUNT ON;
INSERT INTO MedKategorie(PIDX,MedKopf_BstNr)
SELECT newid() AS pk_tabelleB, MedKopf_BstNr AS fk_tabelleA
FROM INSERTED
LEFT JOIN MedKategorie ON MedKopf_BstNr = BstNr
WHERE MedKategorie.PIDX IS NULL
END
GO
 
Zuletzt bearbeitet:
Einen Foreign Key muss es geben, es kann durchaus sein das der deckungsgleich mit dem PK ist. Dann ist es allerdings eine reine 1:1 Beziehung oder der Schlüssel ist nicht UNIQUE, dann hat die Tabelle keinen PK sondern nur den FK.

Bei dir sieht es so aus als sei PIDX ein PK in beiden Tabellen. BstNr ist in MedKopf eventuell eindeutig und wäre dann auch ein PK und in Tabelle B dann der FK auf Tabelle A.

Wenn das so ist und du hast einen fortlaufenden Integer als PIDX müsstest du noch prüfen ob der automatisch von der DB gesetzt wird, dann kannst du nämlich den Schlüssel gar nicht selbst bestimmen. Musst du den selbst setzen musst du ihn erst per Select ermitteln, das ist wenig optimal daher nehme ich bevorzugt UNIQUEIDENTIFIER...

Poste mal bitte die Spaltendefinition der beiden Spalten aus beiden Tabellen aus dem CREATE TABLE Statement, da steht ja (fast) alles drin.
 
Hallo Ukulele,

die PIDX Spalten sind immer autoincremente Primärschlüssel.

Hier mal einen Auszug des Create Statement der MedKopf
Code:
CREATE TABLE [dbo].[MedKopf](
    [PIDX] [int] IDENTITY(1,1) NOT NULL,
    [BstNr] [nvarchar](10) NOT NULL,
    [BstNr_Alt] [nvarchar](10) NULL,
    [Objekt_PIDX] [int] NULL,
    [Mandant_PIDX] [int] NOT NULL CONSTRAINT [DF_MedKopf_Mandant_PIDX]  DEFAULT ((2)),
    [Vermerk] [ntext] NULL,
    [Ausgemustert] [bit] NOT NULL CONSTRAINT [DF_MedKopf_Ausgemustert]  DEFAULT ((0)),
    [AdmVermerk] [ntext] NULL,
    [KTraeger] [nvarchar](10) NULL,
    [Lernziel] [nvarchar](max) NULL,
    [Zielgruppe] [nvarchar](max) NULL,
    [Tags] [nvarchar](max) NULL,
    [CreateDT] [datetime] NULL CONSTRAINT [DF_MedKopf_CreateDT]  DEFAULT (getdate()),
    [CreateUser] [nvarchar](50) NULL,
    [ModDT] [datetime] NULL,
    [ModUser] [nvarchar](50) NULL,
CONSTRAINT [PK_MedKopf_PIDX] PRIMARY KEY CLUSTERED
(
    [PIDX] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UniqueIX_MedKopf_BstNr] UNIQUE NONCLUSTERED
(
    [BstNr] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

ALTER TABLE [dbo].[MedKopf]  WITH CHECK ADD  CONSTRAINT [FK_MedKopf_Objekt] FOREIGN KEY([Objekt_PIDX])
REFERENCES [dbo].[Objekt] ([PIDX])
GO

Und hier der Tabelle B = MedKategorie (dort wo der die MedKopf.BstNr in MedKategorie.Medkopf_BstNr eingetragen werden soll)

Code:
/****** Object:  Table [dbo].[MedKategorie]    Script Date: 28.02.2018 10:39:12 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[MedKategorie](
    [PIDX] [int] IDENTITY(1,1) NOT NULL,
    [MedKopf_BstNr] [nvarchar](10) NOT NULL,
    [Kategorie_PIDX1] [int] NULL,
    [Kategorie_PIDX2] [int] NULL,
    [Kategorie_PIDX3] [int] NULL,
    [Kategorie_PIDX4] [int] NULL,
    [Kategorie_PIDX5] [int] NULL,
    [CreateDT] [datetime] NULL CONSTRAINT [DF_MedKategorie_CreateDT]  DEFAULT (getdate()),
    [CreateUser] [nvarchar](50) NULL,
    [ModDT] [datetime] NULL,
    [ModUser] [nvarchar](50) NULL,
CONSTRAINT [PK_MedKategorie_PIDX] PRIMARY KEY CLUSTERED
(
    [PIDX] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[MedKategorie]  WITH CHECK ADD  CONSTRAINT [FK_MedKategorie_MedKopf] FOREIGN KEY([MedKopf_BstNr])
REFERENCES [dbo].[MedKopf] ([BstNr])
GO

ALTER TABLE [dbo].[MedKategorie] CHECK CONSTRAINT [FK_MedKategorie_MedKopf]
GO

ALTER TABLE [dbo].[MedKategorie]  WITH CHECK ADD  CONSTRAINT [FK_MedKategorie1_Kategorie] FOREIGN KEY([Kategorie_PIDX1])
REFERENCES [dbo].[Kategorie] ([PIDX])
GO

ALTER TABLE [dbo].[MedKategorie] CHECK CONSTRAINT [FK_MedKategorie1_Kategorie]
GO

ALTER TABLE [dbo].[MedKategorie]  WITH CHECK ADD  CONSTRAINT [FK_MedKategorie2_Kategorie] FOREIGN KEY([Kategorie_PIDX2])
REFERENCES [dbo].[Kategorie] ([PIDX])
GO

ALTER TABLE [dbo].[MedKategorie] CHECK CONSTRAINT [FK_MedKategorie2_Kategorie]
GO

ALTER TABLE [dbo].[MedKategorie]  WITH CHECK ADD  CONSTRAINT [FK_MedKategorie3_Kategorie] FOREIGN KEY([Kategorie_PIDX3])
REFERENCES [dbo].[Kategorie] ([PIDX])
GO

ALTER TABLE [dbo].[MedKategorie] CHECK CONSTRAINT [FK_MedKategorie3_Kategorie]
GO

ALTER TABLE [dbo].[MedKategorie]  WITH CHECK ADD  CONSTRAINT [FK_MedKategorie4_Kategorie] FOREIGN KEY([Kategorie_PIDX4])
REFERENCES [dbo].[Kategorie] ([PIDX])
GO

ALTER TABLE [dbo].[MedKategorie] CHECK CONSTRAINT [FK_MedKategorie4_Kategorie]
GO

ALTER TABLE [dbo].[MedKategorie]  WITH CHECK ADD  CONSTRAINT [FK_MedKategorie5_Kategorie] FOREIGN KEY([Kategorie_PIDX5])
REFERENCES [dbo].[Kategorie] ([PIDX])
GO

ALTER TABLE [dbo].[MedKategorie] CHECK CONSTRAINT [FK_MedKategorie5_Kategorie]
GO
 
Dann ist das eigentlich nicht weiter kompliziert:
Code:
CREATE TRIGGER [dbo].[Tr_MedKategorie]
ON [dbo].[Medkopf]
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO MedKategorie(MedKopf_BstNr)
SELECT BstNr
FROM INSERTED
LEFT JOIN MedKategorie ON INSERTED.MedKopf_BstNr = MedKategorie.MedKopf_BstNr
WHERE MedKategorie.PIDX IS NULL
END
GO
 
Werbung:
Mit einer minimalen Anpassung kannst du auch den Eintrag für alte Einträge nachholen:
Code:
INSERT INTO MedKategorie(MedKopf_BstNr)
SELECT BstNr
FROM
MedKopf INSERTED
LEFT JOIN MedKategorie ON INSERTED.MedKopf_BstNr = MedKategorie.MedKopf_BstNr
WHERE MedKategorie.PIDX IS NULL
 
Zurück
Oben