chgs2011
Goto Top

SQL Trigger für INSERT und UPDATE scheitert, weil INSERTED in Unterabfrage mehr als einen Wert liefert

Hallo zusammen,

ich habe eine bestehende Tabelle1, die ich per Trigger überwachen möchte.
Es sollen INSERT und UPDATE überwacht werden, so dass die Daten in einer weiteren Tabelle2 (KUNDENADRESSE) gesichert werden.
Ich frage also im Trigger zuerst ab, ob die Datenzeile bereits existiert, wenn nicht INSERT in Tabelle2 (KUNDENADRESSE), ansonsten Tabelle2 nur UPDATE.

Wenn ich jetzt auf Tabelle1 (tAdresse) einen UPDATE Befehl absetze und mehr als eine Zeile betroffen ist,
dann erscheint Meldung 512 mit "Die Unterabfrage hat mehr als einen Wert zurückgegeben.".

Ich dachte, dass INSERTED alle ankommenden Datenzeilen verarbeitet, kann aber wohl doch nur mit einer Zeile umgehen.
Habe nur etwas on "CURSOR" gelesen, aber hatte diese Funktion noch nie genutzt.

Wie müsste ich denn den Trigger umbauen, dass mehrere INSERTED Zeilen verarbeitet werden können?

CREATE TRIGGER [tgr_KUNDENADRESSE] ON [dbo].[tAdresse]
AFTER INSERT, UPDATE
AS
BEGIN
	IF (SELECT COUNT(*) FROM [dbo].[KUNDENADRESSE] WHERE TEMP_tAdresse_kAdresse=(SELECT kAdresse FROM inserted)) = '0'  
		INSERT INTO [dbo].[KUNDENADRESSE] (
			TEMP_tAdresse_kAdresse,
			TEMP_tAdresse_kKunde,
			TEMP_tKunde_cKundenNr,
			TEMP_tAdresse_cFirma,
			TEMP_tAdresse_cFirma_BACKUP,
			TEMP_tAdresse_cZusatz,
			TEMP_tAdresse_cZusatz_BACKUP,
			TEMP_tAdresse_cTitel,
			TEMP_tAdresse_cTitel_BACKUP,
			TEMP_tAdresse_cVorname,
			TEMP_tAdresse_cVorname_BACKUP,
			TEMP_tAdresse_cName,
			TEMP_tAdresse_cName_BACKUP,
			TEMP_tAdresse_cStrasse,
			TEMP_tAdresse_cStrasse_BACKUP,
			TEMP_tAdresse_cPLZ,
			TEMP_tAdresse_cPLZ_BACKUP,
			TEMP_tAdresse_cOrt,
			TEMP_tAdresse_cOrt_BACKUP,
			TEMP_tAdresse_cAdressZusatz,
			TEMP_tAdresse_cAdressZusatz_BACKUP,
			TEMP_tAdresse_cUSTID,
			TEMP_tAdresse_cUSTID_BACKUP,
			TEMP_tkunde_dErstellt,
			TEMP_DATE,
			TEMP_UNDO,
			TEMP_TODO)
		(SELECT
			inserted.kAdresse,
			inserted.kKunde,
			'',  
			'',  
			inserted.cFirma,
			'',  
			inserted.cZusatz,
			'',  
			inserted.cTitel,
			'',  
			inserted.cVorname,
			'',  
			inserted.cName,
			'',  
			inserted.cStrasse,
			'',  
			inserted.cPLZ,
			'',  
			inserted.cOrt,
			'',  
			inserted.cAdressZusatz,
			'',  
			inserted.cUSTID,
			'',  
			'',  
			'N',  
			'N'  
		FROM inserted);
	ELSE
		UPDATE [dbo].[KUNDENADRESSE]
		SET
			TEMP_tKunde_cKundenNr = '',  
			TEMP_tAdresse_cFirma = cFirma,
			TEMP_tAdresse_cZusatz = cZusatz,
			TEMP_tAdresse_cTitel = cTitel,
			TEMP_tAdresse_cVorname = cVorname,
			TEMP_tAdresse_cName = cName,
			TEMP_tAdresse_cStrasse = cStrasse,
			TEMP_tAdresse_cPLZ = cPLZ,
			TEMP_tAdresse_cOrt = cOrt,
			TEMP_tAdresse_cAdressZusatz = cAdressZusatz,
			TEMP_tAdresse_cUSTID = cUSTID,
			TEMP_tkunde_dErstellt = '',  
			TEMP_DATE = NULL
		FROM [dbo].[KUNDENADRESSE] f
			INNER JOIN inserted i ON i.kAdresse = f.TEMP_tAdresse_kAdresse;
END
GO

Content-ID: 395733

Url: https://administrator.de/forum/sql-trigger-fuer-insert-und-update-scheitert-weil-inserted-in-unterabfrage-mehr-als-einen-wert-liefert-395733.html

Ausgedruckt am: 23.12.2024 um 05:12 Uhr

chgs2011
chgs2011 16.12.2018 um 11:27:47 Uhr
Goto Top
Vielleicht waren hier hilfreiche Infos, aber wüsste nicht wie umsetzen?!

http://www.datenbankforum.com/threads/trigger-liefert-mehr-als-einen-ei ...
sabines
sabines 16.12.2018 aktualisiert um 15:44:57 Uhr
Goto Top
Moin,

wozu ein Trigger an dieser Stelle, dass kannst Du doch mit T-SQL abfackeln.
Überarbeite Dein Datenbankdesign (Programmablauf), der Trigger ist bei richtigem Design unnötig, und macht, wie Du schon gesehen hast, in anderen Fällen Probleme SQL Trigger für INSERT und UPDATE scheitert, weil INSERTED in Unterabfrage mehr als einen Wert liefert.

Gruss
chgs2011
chgs2011 16.12.2018 um 17:09:07 Uhr
Goto Top
Danke für den Tipp, du hast aber meinen eigenen Thread hier jetzt verlinkt, oder? face-big-smile

T-SQL klingt ja nach nach Schleifen CURSOR siehe Link oder?
Kann mir ja hierzu jemand helfen? Da wäre ich überfragt.

Bzgl. Trigger, jein ... ich bin eigentlich fast darauf angewiesen, da ich auf eine bestehende Datenbank andocke.
Ich möchte daher Änderungen in einer Tabelle erkennen und in meine eigene Tabelle sichern.
sabines
sabines 17.12.2018 um 06:50:25 Uhr
Goto Top
Ja, ich habe Deinen Thread verlinkt, damit klar wird worüber gesprochen wird.
Du hättest ggfs. auch im alten Thread weiterfragen können.

Wie oft willst Du diese Tabelle updaten, reicht es nicht den Trigger dafür zu deaktivieren, wenn's was einmaliges ist?
chgs2011
chgs2011 17.12.2018 aktualisiert um 08:52:19 Uhr
Goto Top
Nein, das deaktivieren hilft mir nicht, es ist ein zusätzlicher Trigger der benötigt wird.

Ich hatte nun mehrfach den Sonderfall, dass beim UPDATE Trigger auch mehrere Datenzeilen ankommen.
Mein Trigger beendet ja daher mit "Meldung 512: Die Unterabfrage hat mehr als einen Wert zurückgegeben."

Habe nun hier paar Interessante Tipps gelesen:
http://www.sqlservercentral.com/blogs/steve_jones/2010/09/23/common-sql ...


Leider fehlt mir aber das KnowHow, wie ich das nun umsetze in meinem Beispiel.
Ich bin nicht sicher, ob ich evtl. die Zeilen in einer TEMP-Tabelle indexieren muss, damit die Verarbeitung einfacher geht?!
Diesen Umweg wollte ich mir sparen, da ich ja eigentlich "NUR" mit "multiple rows" im UPDATE Befehl klar kommen muss.

CREATE TRIGGER [tgr_KUNDENADRESSE] ON [dbo].[tAdresse]
AFTER UPDATE
AS
IF @@ROWCOUNT > 1
	BEGIN
		UPDATE [dbo].[KUNDENADRESSE]
		SET
			WDL_tKunde_cKundenNr = '',  
			WDL_tAdresse_cFirma = cFirma,
			WDL_tAdresse_cZusatz = cZusatz,
			WDL_tAdresse_cTitel = cTitel,
			WDL_tAdresse_cVorname = cVorname,
			WDL_tAdresse_cName = cName,
			WDL_tAdresse_cStrasse = cStrasse,
			WDL_tAdresse_cPLZ = cPLZ,
			WDL_tAdresse_cOrt = cOrt,
			WDL_tAdresse_cAdressZusatz = cAdressZusatz,
			WDL_tAdresse_cUSTID = cUSTID,
			WDL_tkunde_dErstellt = '',  
			WDL_DATE = NULL
		FROM inserted i
			INNER JOIN [dbo].[KUNDENADRESSE] f ON f.WDL_tAdresse_kAdresse = i.kAdresse;
	END

Beispiel, Datumsbereich ist etwas größer, nun kommen mehrere Datenzeilen an, was an sich kein Problem ist.
ABER "kKunde" kann in diesem Fall mehrfach vorkommen, da dieser mehrere Adressen jeweils hat.
Hier hat also der Trigger wohl Probleme für die Zuordnung, welche "kAdresse" nun gemeint ist bei einem "kKunde".
17-12-2018 08-50-11
MadMax
MadMax 17.12.2018 um 15:42:32 Uhr
Goto Top
Hallo chgs2011,

nimm den Trigger aus Deinem obersten Beitrag und laß beim "insert into Kundenadresse ... (select ... from inserted)" einfach mal die Klammern um das select weg, dann dürfte es passen.

Gruß, Mad Max
spaceman127
spaceman127 17.12.2018 um 16:31:54 Uhr
Goto Top
Moin chgs2011,
ändere mal folgende Zeile.

IF (SELECT COUNT(*) FROM [dbo].[KUNDENADRESSE] WHERE TEMP_tAdresse_kAdresse=(SELECT kAdresse FROM inserted)) = '0'

in

IF (SELECT COUNT(*) FROM [dbo].[KUNDENADRESSE] WHERE TEMP_tAdresse_kAdresse IN(SELECT kAdresse FROM inserted)) = '0'

Also aus dem = ein IN machen.


Gruß Spaceman127
chgs2011
chgs2011 17.12.2018 um 19:39:51 Uhr
Goto Top
@MadMax und @spaceman127 und @sabines

Danke euch für die Anteilnahme und die Tipps.

Aktuell wirft aber der UPDATE-Befehl den Fehler, nicht der INSERT-Befehl.
INSERTs sind es meistens ja ohnehin nur "einzelne Datensätze", nur bei UPDATE sicher nicht.


Ich habe nun eine vollständige Testumgebung erstellt, bitte legt euch mal diese Umgebung an,
dann sollte man das Problem schneller finden und lösen können.

Anbei kompletter String zur Erstellung der Testumgebung:
IF OBJECT_ID(N'[dbo].[tAdresse_TMP]', N'U') IS NOT NULL  
BEGIN
	DROP TABLE [dbo].tAdresse_TMP;
END


IF OBJECT_ID(N'[dbo].[tkunde_TMP]', N'U') IS NOT NULL  
BEGIN
	DROP TABLE [dbo].tkunde_TMP;
END


CREATE TABLE tAdresse_TMP (
        kAdresse_TMP varchar(255),
        kInetAdresse_TMP varchar(255),
        kKunde_TMP varchar(255),
        cFirma_TMP varchar(255),
        cAnrede_TMP varchar(255),
        cTitel_TMP varchar(255),
        cVorname_TMP varchar(255),
        cName_TMP varchar(255),
        cStrasse_TMP varchar(255),
        cPLZ_TMP varchar(255),
        cOrt_TMP varchar(255),
        cLand_TMP varchar(255),
        cTel_TMP varchar(255),
        cZusatz_TMP varchar(255),
        cAdressZusatz_TMP varchar(255),
        cPostID_TMP varchar(255),
        cMobil_TMP varchar(255),
        cMail_TMP varchar(255),
        cFax_TMP varchar(255),
        cBundesland_TMP varchar(255),
        cISO_TMP varchar(255),
        nStandard_TMP varchar(255),
        nTyp_TMP varchar(255),
        cUSTID_TMP varchar(255),
        bRowversion_TMP varchar(255),
    CONSTRAINT kAdresse_TMP
    PRIMARY KEY (kAdresse_TMP)
);


CREATE TABLE tkunde_TMP (
        kKunde_TMP varchar(255),
        kInetKunde_TMP varchar(255),
        kKundenKategorie_TMP varchar(255),
        cKundenNr_TMP varchar(255),
        dErstellt_TMP varchar(255),
        fRabatt_TMP varchar(255),
        cNewsletter_TMP varchar(255),
        cEbayName_TMP varchar(255),
        kBuyer_TMP varchar(255),
        cGeburtstag_TMP varchar(255),
        cWWW_TMP varchar(255),
        cSperre_TMP varchar(255),
        kKundenGruppe_TMP varchar(255),
        nDrittland_TMP varchar(255),
        nZahlungsziel_TMP varchar(255),
        kSprache_TMP varchar(255),
        cHerkunft_TMP varchar(255),
        cKassenKunde_TMP varchar(255),
        cHRNr_TMP varchar(255),
        kZahlungsart_TMP varchar(255),
        nDebitorennr_TMP varchar(255),
        cSteuerNr_TMP varchar(255),
        nKreditlimit_TMP varchar(255),
        kKundenDrucktext_TMP varchar(255),
        nMahnstopp_TMP varchar(255),
        nMahnrhythmus_TMP varchar(255),
        kFirma_TMP varchar(255),
        fProvision_TMP varchar(255),
        nVertreter_TMP varchar(255),
        fSkonto_TMP varchar(255),
        nSkontoInTagen_TMP varchar(255),
        bRowversion_TMP varchar(255),
    CONSTRAINT kKunde_TMP
    PRIMARY KEY (kKunde_TMP)
);


IF OBJECT_ID(N'[dbo].[KUNDENADRESSE]', N'U') IS NULL  
BEGIN
	CREATE TABLE [dbo].[KUNDENADRESSE]
	(
		TEST_tAdresse_kAdresse INTEGER NOT NULL,
		TEST_tAdresse_kKunde INTEGER NOT NULL,
		TEST_tKunde_cKundenNr varchar(30) NULL,
		--- START - Felder AdressKorrektur ---
		TEST_tAdresse_cFirma varchar(128) NULL,
		TEST_tAdresse_cFirma_BACKUP varchar(128) NULL,
		TEST_tAdresse_cZusatz varchar(128) NULL,
		TEST_tAdresse_cZusatz_BACKUP varchar(128) NULL,
		TEST_tAdresse_cTitel varchar(64) NULL,
		TEST_tAdresse_cTitel_BACKUP varchar(64) NULL,
		TEST_tAdresse_cVorname varchar(255) NULL,
		TEST_tAdresse_cVorname_BACKUP varchar(255) NULL,
		TEST_tAdresse_cName varchar(255) NULL,
		TEST_tAdresse_cName_BACKUP varchar(255) NULL,
		TEST_tAdresse_cStrasse varchar(255) NULL,
		TEST_tAdresse_cStrasse_BACKUP varchar(255) NULL,
		TEST_tAdresse_cPLZ varchar(24) NULL,
		TEST_tAdresse_cPLZ_BACKUP varchar(24) NULL,
		TEST_tAdresse_cOrt varchar(255) NULL,
		TEST_tAdresse_cOrt_BACKUP varchar(255) NULL,
		TEST_tAdresse_cAdressZusatz varchar(255) NULL,
		TEST_tAdresse_cAdressZusatz_BACKUP varchar(255) NULL,
		TEST_tAdresse_cUSTID varchar(20) NULL,
		TEST_tAdresse_cUSTID_BACKUP varchar(20) NULL,
		--- ENDE - Felder AdressKorrektur ---
		TEST_tKunde_dErstellt datetime NULL,
		TEST_DATE datetime NULL,
		TEST_UNDO char(1) NULL,
		TEST_TODO char(1) NULL,
		CONSTRAINT TEST_tAdresse_kAdresse
		PRIMARY KEY(TEST_tAdresse_kAdresse)
	)
END

   
INSERT INTO tAdresse_TMP (kAdresse_TMP, kInetAdresse_TMP, kKunde_TMP, cFirma_TMP, cAnrede_TMP, cTitel_TMP, cVorname_TMP, cName_TMP, cStrasse_TMP, cPLZ_TMP, cOrt_TMP, cLand_TMP, cTel_TMP, cZusatz_TMP, cAdressZusatz_TMP, cPostID_TMP, cMobil_TMP, cMail_TMP, cFax_TMP, cBundesland_TMP, cISO_TMP, nStandard_TMP, nTyp_TMP, cUSTID_TMP, bRowversion_TMP)
VALUES        ('83592', '0', '5588', 'Firma 1', 'Herr', '', 'Timo', 'Bollerwagen', 'Baumweg 1', '77777', 'Ortschaft', 'Deutschland', 'NULL', '', '', 'NULL', 'NULL', 'NULL', '', '', 'DE', '1', '1', 'NULL', '0x00000000007A2959'),  
                ('83593', '0', '23340', 'Firma 222', 'Herr', '', 'Timo', 'Bollerwagen', 'Baumweg 1', '77777', 'Ortschaft', 'Deutschland', '', '', '', 'NULL', '', 'NULL', '', '', 'DE', '1', '1', 'NULL', '0x00000000007B99DE'),  
                ('83594', '0', '49781', 'NULL', 'Mr', 'NULL', 'Max', 'Musterman', 'Musterstreet 12', '55566', 'Kaff', 'Deutschland', 'NULL', 'NULL', 'NULL', 'NULL', 'NULL', 'NULL', 'NULL', 'NULL', 'DE', '1', '1', 'NULL', '0x00000000006EA7D1'),  
                ('83597', 'NULL', '49782', 'firmenname', 'NULL', 'NULL', 'vorname', 'nachname', 'strasse 0', '0', 'stadt', 'Deutschland', 'NULL', 'firmenzusatz', 'NULL', 'NULL', 'NULL', 'NULL', 'NULL', 'NULL', 'DE', '1', '0', 'NULL', '0x00000000007B9A0E'),  
                ('83595', 'NULL', '49782', 'testfirma', '', '', 'testvorname', 'testnachname', 'teststraße 4d2', '0', 'teststadtt', 'Deutschland', '', '', '', 'NULL', '', '', '', '', 'DE', '1', '1', '', '0x00000000007B9A0F'),  
                ('47429', '0', '49783', 'NULL', 'NULL', 'NULL', 'Walter', 'Husten', 'Im Zwerchfell 5', '98764', 'Bauch', 'Deutschland', 'NULL', 'NULL', 'Eingang hinten', 'NULL', 'NULL', 'NULL', 'NULL', 'NULL', 'DE', '0', '0', 'NULL', '0x00000000007B9A0C'),  
                ('83596', 'NULL', '49783', '', '', '', '', 'aaaa', 'ssss', '40000', 'Großstadt', 'Deutschland', '', '', '', 'NULL', '', '', '', '', 'DE', '1', '1', '', '0x00000000007B9A0D');  



INSERT INTO tkunde_TMP (kKunde_TMP, kInetKunde_TMP, kKundenKategorie_TMP, cKundenNr_TMP, dErstellt_TMP, fRabatt_TMP, cNewsletter_TMP, cEbayName_TMP, kBuyer_TMP, cGeburtstag_TMP, cWWW_TMP, cSperre_TMP, kKundenGruppe_TMP, nDrittland_TMP, nZahlungsziel_TMP, kSprache_TMP, cHerkunft_TMP, cKassenKunde_TMP, cHRNr_TMP, kZahlungsart_TMP, nDebitorennr_TMP, cSteuerNr_TMP, nKreditlimit_TMP, kKundenDrucktext_TMP, nMahnstopp_TMP, nMahnrhythmus_TMP, kFirma_TMP, fProvision_TMP, nVertreter_TMP, fSkonto_TMP, nSkontoInTagen_TMP, bRowversion_TMP)
VALUES        ('5588', '1', '4', '5208', '2012-09-20 00:00:00.000', '0.00000000000000', 'N', '', '0', '', '', 'N', '1', '0', '0', '1', '', 'N', '', '0', '0', '', '0', '0', '0', '0', '0', 'NULL', '0', '0.00000000000000', '0', '0x0000000000776ED8'),  
                ('23340', '1', '4', '22959', '2014-07-03 00:00:00.000', '0.00000000000000', 'N', '', '0', '', '', 'N', '2', '0', '0', '1', '', 'N', '', '0', '0', '', '0', '0', '0', '0', '0', 'NULL', '0', '0.00000000000000', '0', '0x0000000000776D8C'),  
                ('49781', '2', '4', '49400', '2016-04-03 00:00:00.000', '0.00000000000000', 'N', 'NULL', '0', '00.00.0000', 'NULL', 'N', '1', '0', '0', '3', 'NULL', 'N', 'NULL', '0', '0', 'NULL', '0', 'NULL', '0', '0', '0', 'NULL', '0', '0.00000000000000', '0', '0x000000000071C4AE'),  
                ('49782', '0', '0', '85532', '2018-11-21 00:00:00.000', '0.00000000000000', 'N', '', '0', '', '', 'N', '1', '0', '0', '1', '', 'N', '', '0', '0', '', '0', '0', '0', '0', '0', 'NULL', '0', '0.00000000000000', '0', '0x0000000000777370'),  
                ('49783', '0', '0', '85533', '2018-11-21 00:00:00.000', '0.00000000000000', 'N', '', '0', '', '', 'N', '1', '0', '0', '1', '', 'N', '', '0', '0', '', '0', '0', '0', '0', '0', 'NULL', '0', '0.00000000000000', '0', '0x0000000000779998');  


SELECT * FROM tAdresse_TMP;
SELECT * FROM tkunde_TMP;


IF OBJECT_ID('[dbo].[tgr_KUNDENADRESSE]', 'TR') IS NOT NULL  
BEGIN
    DROP TRIGGER [tgr_KUNDENADRESSE];
END
GO

CREATE TRIGGER [tgr_KUNDENADRESSE] ON [dbo].[tAdresse_TMP]
AFTER INSERT, UPDATE
AS
BEGIN
	IF (SELECT COUNT(*) FROM [dbo].[KUNDENADRESSE] WHERE TEST_tAdresse_kAdresse=(SELECT kAdresse_TMP FROM inserted)) = '0'  
		INSERT INTO [dbo].[KUNDENADRESSE] (
			TEST_tAdresse_kAdresse,
			TEST_tAdresse_kKunde,
			TEST_tKunde_cKundenNr,
			TEST_tAdresse_cFirma,
			TEST_tAdresse_cFirma_BACKUP,
			TEST_tAdresse_cZusatz,
			TEST_tAdresse_cZusatz_BACKUP,
			TEST_tAdresse_cTitel,
			TEST_tAdresse_cTitel_BACKUP,
			TEST_tAdresse_cVorname,
			TEST_tAdresse_cVorname_BACKUP,
			TEST_tAdresse_cName,
			TEST_tAdresse_cName_BACKUP,
			TEST_tAdresse_cStrasse,
			TEST_tAdresse_cStrasse_BACKUP,
			TEST_tAdresse_cPLZ,
			TEST_tAdresse_cPLZ_BACKUP,
			TEST_tAdresse_cOrt,
			TEST_tAdresse_cOrt_BACKUP,
			TEST_tAdresse_cAdressZusatz,
			TEST_tAdresse_cAdressZusatz_BACKUP,
			TEST_tAdresse_cUSTID,
			TEST_tAdresse_cUSTID_BACKUP,
			TEST_tkunde_dErstellt,
			TEST_DATE,
			TEST_UNDO,
			TEST_TODO)
		(SELECT
			inserted.kAdresse_TMP,
			inserted.kKunde_TMP,
			(SELECT tkunde_TMP.cKundenNr_TMP FROM tkunde_TMP WHERE tkunde_TMP.kKunde_TMP = (SELECT kKunde_TMP FROM inserted)),
			'',  
			inserted.cFirma_TMP,
			'',  
			inserted.cZusatz_TMP,
			'',  
			inserted.cTitel_TMP,
			'',  
			inserted.cVorname_TMP,
			'',  
			inserted.cName_TMP,
			'',  
			inserted.cStrasse_TMP,
			'',  
			inserted.cPLZ_TMP,
			'',  
			inserted.cOrt_TMP,
			'',  
			inserted.cAdressZusatz_TMP,
			'',  
			inserted.cUSTID_TMP,
			(SELECT tkunde_TMP.dErstellt_TMP FROM tkunde_TMP WHERE tkunde_TMP.kKunde_TMP = (SELECT kKunde_TMP FROM inserted)),
			NULL,
			'N',  
			'N'  
		FROM inserted);
	ELSE
		UPDATE [dbo].[KUNDENADRESSE]
		SET
			TEST_tKunde_cKundenNr = (SELECT tkunde_TMP.cKundenNr_TMP FROM tkunde_TMP WHERE tkunde_TMP.kKunde_TMP = (SELECT kKunde_TMP FROM inserted)),
			TEST_tAdresse_cFirma = cFirma_TMP,
			TEST_tAdresse_cZusatz = cZusatz_TMP,
			TEST_tAdresse_cTitel = cTitel_TMP,
			TEST_tAdresse_cVorname = cVorname_TMP,
			TEST_tAdresse_cName = cName_TMP,
			TEST_tAdresse_cStrasse = cStrasse_TMP,
			TEST_tAdresse_cPLZ = cPLZ_TMP,
			TEST_tAdresse_cOrt = cOrt_TMP,
			TEST_tAdresse_cAdressZusatz = cAdressZusatz_TMP,
			TEST_tAdresse_cUSTID = cUSTID_TMP,
			TEST_tkunde_dErstellt = (SELECT tkunde_TMP.dErstellt_TMP FROM tkunde_TMP WHERE tkunde_TMP.kKunde_TMP = (SELECT kKunde_TMP FROM inserted)),
			TEST_DATE = NULL
		FROM [dbo].[KUNDENADRESSE] f
			INNER JOIN inserted i ON i.kAdresse_TMP = f.TEST_tAdresse_kAdresse;
END
GO



So, wenn ihr das habt, dann feuert mal ein UPDATE-Befehl ab, dann sollte der Trigger den Fehler werfen:
UPDATE tAdresse_TMP
SET nStandard_TMP = (tAdresse_TMP.nStandard_TMP + 1)
FROM tAdresse_TMP INNER JOIN tkunde_TMP ON tAdresse_TMP.kKunde_TMP = tkunde_TMP.kKunde_TMP
WHERE (CONVERT(DATE, tkunde_TMP.dErstellt_TMP, 121) >= '2018-11-20') AND (CONVERT(DATE, tkunde_TMP.dErstellt_TMP, 121) <= '2018-11-22');  

Damit könnt ihr mal schauen, was wohl im Trigger ankommt:
SELECT * FROM tAdresse_TMP INNER JOIN tkunde_TMP ON tAdresse_TMP.kKunde_TMP = tkunde_TMP.kKunde_TMP
WHERE (CONVERT(DATE, tkunde_TMP.dErstellt_TMP, 121) >= '2010-10-20') AND (CONVERT(DATE, tkunde_TMP.dErstellt_TMP, 121) <= '2018-11-25');  


So, ich hoffe das hilft weiter und finden den Fehler, ich verzweifel leider wirklich.
ukulele-7
ukulele-7 18.12.2018 um 17:14:01 Uhr
Goto Top
Grundsätzlich ist ein Trigger in diesem Szenario eine sinnvolle Wahl. Besser wäre eigentlich nur eine Sicht auf die Daten durch den anderen DB Server. Einen Cursor solltest du unbedingt vermeiden, der ist hier auch gar nicht notwendig.

Problematisch in deinem Trigger ist erstmal diese Zeile:
IF (SELECT COUNT(*) FROM [dbo].[KUNDENADRESSE] WHERE TEMP_tAdresse_kAdresse=(SELECT kAdresse FROM inserted)) = '0'  
Wie du schon erkannt hast liefert INSERTED immer alle vom SQL Befehl betroffenen Zeilen, der Trigger feuert genau einmal und du musst alle deine Datensätze mit deinem Code abfrühstücken, so der Plan.

An dieser Stelle könntest du also höchstens
TEMP_tAdresse_kAdresse=(SELECT
durch
TEMP_tAdresse_kAdresse IN (SELECT
ersetzen, denn der Select liefert dir halt auch mehrere Werte zurück und die kannst du mit gleich nicht prüfen.

Aber sinnvoll erscheint mir diese Prüfung allgemein nicht. Du prüfst, ob mind. ein Datensatz aus Inserted schon in der neuen Tabelle vorhanden ist. Wenn das der Fall ist, wird kein Datensatz aus Inserted eingefügt. Also können deine Daten theoretisch inkonsistent sein, auch wenn das vermutlich einfach nicht vorkommt. Nur irgendwie ist das einfach nicht elegant.

Hier mal ein Gegenvorschlag als pseudo Code:
INSERT INTO zieltabelle(s1,s2)
SELECT quelltabelle.s1,quelltabelle.s2
FROM inserted quelltabelle
LEFT JOIN zieltabelle
ON quelltabelle.pk = zieltabelle.pk
WHERE zieltabelle.pk IS NULL

UPDATE zieltabelle
SET zieltabelle.s1 = quelltabelle.s1
FROM zieltabelle
INNER JOIN inserted quelltabelle
ON quelltabelle.pk = zieltabelle.pk
WHERE isnull(zieltabelle.s1,'') != isnull(quelltabelle.s1,'')  
Der erste Block wird immer nur Datensätze einfügen die noch gar nicht existieren. Der zweite Block aktualisiert alle Datensätze die sich in Spalte 1 unterscheiden (Vorsicht beim abgleich mit NULL-Werten und Formaten). Das kann man entweder für alle Spalten einzeln machen oder alles in einem Rutsch. Ich bin immer ein Freund davon nur Daten zu schreiben wenn sie sich dadurch ändern aber das ist eigentlich nur wichtig wenn z.B. ein Logging statt findet.

Alternativ kannst du ein großes MERGE bauen das deine Daten aus Inserted synchronisiert. Beides wird halt durch den Trigger ausgelöst und aktualisiert die Zieltabelle.
spaceman127
spaceman127 18.12.2018 um 17:18:13 Uhr
Goto Top
Moin chgs2011,

der Trigger in deinem ersten Beitrag ist aber anders als der im letzten Beitrag.
Auf den ersten Beitrag beruhen natürlich unsere Antworten.
Welchen willst du denn jetzt verwenden?

Gruß
Spaceman127
chgs2011
chgs2011 18.12.2018 um 18:33:23 Uhr
Goto Top
@spaceman127
Ich hatte zunächst alles abgespeckt, um das Problem einzugrenzen.

Jetzt habe ich mir die Mühe gemacht, das komplette Konstrukt als Testumgebung aufzubauen, damit man damit besser direkt testen kann.

Wäre also sehr verbunden, wenn man den Trigger / die Testumgebung des letzten Posts in Betracht zieht.
MadMax
Lösung MadMax 18.12.2018 um 18:33:25 Uhr
Goto Top
Hallo chgs2011,

nachdem Du Dir hier soviel Mühe gegeben hast, soll sie auch belohnt werden:
Den Fehler in Deinem Skript vom Anfang hat Dir Spaceman127 gesagt, das war das "in" statt "=".

In Deiner zurechtgemachten Testumgebung hast Du dann diesen Fehler noch an anderer Stelle eingebaut.
Du mußt darauf achten, wo ein einzelner Wert und wo eine Menge von Werten erwartet wird. Hinter einem "=" wird ein einzelner Wert erwartet. Kommen mehrere Werte an, dann kommt es zu dem Fehler.

Konkret ist das die Zeile 154:
IF (SELECT COUNT(*) FROM [dbo].[KUNDENADRESSE] WHERE TEST_tAdresse_kAdresse=(SELECT kAdresse_TMP FROM inserted)) = '0'

Da hat Dir Spaceman127 schon gesagt, daß es
TEST_tAdresse_kAdresse in (SELECT kAdresse_TMP FROM inserted)
heißen muß.

Außerdem noch viermal der Fehler in den Zeilen 186, 207, 215 und 226:
(SELECT tkunde_TMP.cKundenNr_TMP FROM tkunde_TMP WHERE tkunde_TMP.kKunde_TMP = (SELECT kKunde_TMP FROM inserted))

Da ist hinten derselbe Fehler, wie er schon in Zeile 154 ist und außerdem noch, daß das gesamte select mehrere Zeilen liefert, aber nur ein Wert erwartet wird.

Das löst Du mit:
(SELECT tkunde_TMP.cKundenNr_TMP FROM tkunde_TMP WHERE tkunde_TMP.kKunde_TMP = inserted.kKunde_TMP)
bzw. im update benutzt Du einen Alias, da ist es:
(SELECT tkunde_TMP.cKundenNr_TMP FROM tkunde_TMP WHERE tkunde_TMP.kKunde_TMP = i.kKunde_TMP)

Die Abfrage in Zeile 154 ist übrigens sowieso nicht wirklich gut, die dürfte zu falschen Ergebnissen führen. Angenommen Du aktualierst fünf Adressen und davon ist eine bereits in [KUNDENADRESSE] vorhanden, dann liefert Dein count (*) = 1 und die fehlenden vier Adressen werden nicht angelegt.

Das kann man lösen indem man das if wegläßt und dafür beim insert eine where-Bedingung anhängt:
where not exists (select 1 from [KUNDENADRESSE] where TEST_tAdresse_kAdresse = inserted.kAdresse_TMP)

Oder man verwendet gleich den Befehl merge.

Ich hoffe, ich konnte Deine Verzweiflung abwenden face-wink

Gruß, Mad Max
chgs2011
chgs2011 18.12.2018 um 18:36:53 Uhr
Goto Top
WOW, vielen Dank @4400667902

Ich habe schon etwas gehofft von dir zu lesen, habe einen ähnlichen Beitrag von dir gelesen, konnte aber die Idee nicht umsetzen.

Deine Hinweise leuchten mir absolut ein, war dann auch mein Verdacht.
Ich habe leider kein SQL beruflich gelernt, man bringt sich es über die Jahre selbst bei.
Leider fehlt einem dann gerade in solchen speziellen Abfragen das KnowHow. face-sad

Das ersetzen von "=" mit "in" hatte ich natürlich versucht, hatte aber mein Problem nicht gelöst. face-sad
chgs2011
chgs2011 18.12.2018 um 18:39:48 Uhr
Goto Top
@MadMax
Jetzt geht es aber schlag auf schlag face-big-smile
Auch dir ein besonderes Dankeschön, ich werde mich auch gleich ans Testen machen, weil es mir keine Ruhe lässt!

P.S. aus dem Grund habe ich alles mal als Testumgebung aufgebaut, ich dachte mir so ist es einfacher, wenn man kurz alles einspielen kann.

Ich melde mich nochmals ...
chgs2011
chgs2011 18.12.2018 um 19:01:44 Uhr
Goto Top
@MadMax @spaceman127

Oh mann, ich war wohl echt komplett blind mit den Zeilen 127, 186, 207, 215, 226 (-.-)

OK, aber der Hinweis auf Entfall IF-Abfrage + UPDATE und zusätzlicher WHERE-Bedingung ist natürlich auch weltklasse,
mit meiner SQL 2014er Version klappt es nun auch!

Ich hatte hier eher die bedenken, ich trenne alles mit INSERT und UPDATE, vor allem aus dem Hintergrund um auf "WHERE NOT EXISTS" zu verzichten.
Vielleicht kam ich mit MySQL ins schleudern, ich versuchte diese Bedingungen immer zu vermeiden, falls diese in in bestimmten SQL Versionen nicht zur Verfügung steht. Habe es aber nun in 2014 + 2016 getestet, bislang passt jetzt alles.

AAAAHHHHHHHHHHHH vielen vielen DANK euch!!!
ukulele-7
ukulele-7 19.12.2018 aktualisiert um 11:55:37 Uhr
Goto Top
Ja hier wurde auch auf einen alten Beitrag von mir verlinkt (im Datenbankforum), mittlerweile habe ich auch dazu gelernt und meine Trigger sehen anders aus. Guck dir mal meinen Pseudo Code an, das kannst du theoretisch 1:1 mit deinen Tabellen umschreiben.

Und / Oder du guckst dir den MERGE-Befehl an, eigentlich muss der Trigger ja nichts anderes machen als bei einer Veränderung der Daten in der Quell-Tabelle einen MERGE zwischen den geänderten Daten (Inahlt von Inserted) und der Zieltabelle durchführen. Das ist mit MERGE nur ein einziges Statement.

PS: Auf das IF kannst du damit eben auch gänzlich verzichten.
chgs2011
chgs2011 19.12.2018 aktualisiert um 14:19:19 Uhr
Goto Top
Klingt ebenfalls interessant, zumal ich MERGE sicher mal gebrauchen kann.

Hatte mich hier an Punkt D) schon versucht:
https://docs.microsoft.com/de-de/sql/t-sql/statements/merge-transact-sql ...

Aber ohne Hilfe habe ich MERGE bislang nicht umgesetzt bekommen, habe daher auf meine bestehende Abfrage zurückgegriffen.

Eine Lösung mit MERGE würde ich mir aber auch sehr gerne anschauen.
ukulele-7
ukulele-7 19.12.2018 aktualisiert um 15:05:49 Uhr
Goto Top
Ich habe auch noch nicht viel mit MERGE gemacht. Beim letzten Versuch hatte ich irgendein Problem weshalb ich dann davon abgerückt bin und es mit einem INSERT und einem UPDATE wie in meidem Beispiel beschrieben umgesetzt habe.

Hier mein letztes Fall:
MERGE datev_eodb_mandanten_backup AS t
USING datev_eodb_mandanten AS s
ON		t.MDTGUID = s.MDTGUID
AND		t.MDTID = s.MDTID
WHEN	MATCHED
AND (	isnull(t.MDTVON,''1900-01-01 00:00:00.000'') != isnull(s.MDTVON,''1900-01-01 00:00:00.000'')  
OR		isnull(t.MDTBIS,''1900-01-01 00:00:00.000'') != isnull(s.MDTBIS,''1900-01-01 00:00:00.000'')  
OR		isnull(t.MDTSTATUS,0) != isnull(s.MDTSTATUS,0)
OR		isnull(t.MDTNR,0) != isnull(s.MDTNR,0)
OR		isnull(t.MDTNAME,'''') != isnull(s.MDTNAME,'''')  
OR		isnull(t.MDTTYP,'''') != isnull(s.MDTTYP,'''')  
OR		isnull(t.MDTPLZ,'''') != isnull(s.MDTPLZ,'''')  
OR		isnull(t.MDTORT,'''') != isnull(s.MDTORT,'''')  
OR		isnull(t.MDTSTR,'''') != isnull(s.MDTSTR,'''')  
OR		isnull(t.MDTGID,0) != isnull(s.MDTGID,0)
OR		isnull(t.MDTGNAME,'''') != isnull(s.MDTGNAME,'''')  
OR		isnull(t.DOHR,'''') != isnull(s.DOHR,'''') )  
THEN
	UPDATE
	SET		t.MDTVON = s.MDTVON,
			t.MDTBIS = s.MDTBIS,
			t.MDTSTATUS = s.MDTSTATUS,
			t.MDTNR = s.MDTNR,
			t.MDTNAME = s.MDTNAME,
			t.MDTTYP = s.MDTTYP,
			t.MDTPLZ = s.MDTPLZ,
			t.MDTORT = s.MDTORT,
			t.MDTSTR = s.MDTSTR,
			t.MDTGID = s.MDTGID,
			t.MDTGNAME = s.MDTGNAME,
			t.DOHR = s.DOHR
WHEN	NOT MATCHED BY TARGET
THEN
	INSERT(MDTGUID,MDTID,MDTVON,MDTBIS,MDTSTATUS,MDTNR,MDTNAME,MDTTYP,MDTPLZ,MDTORT,MDTSTR,MDTGID,MDTGNAME,DOHR)
	VALUES(s.MDTGUID,s.MDTID,s.MDTVON,s.MDTBIS,s.MDTSTATUS,s.MDTNR,s.MDTNAME,s.MDTTYP,s.MDTPLZ,s.MDTORT,s.MDTSTR,s.MDTGID,s.MDTGNAME,s.DOHR)
WHEN	NOT MATCHED BY SOURCE
THEN
	DELETE;
Kann dir leider nicht mehr sagen wo es gehakt hat aber die Syntax sollte passen.
chgs2011
chgs2011 19.12.2018 um 18:49:23 Uhr
Goto Top
Ich habe die Syntax mal eben umgebaut und angepasst, vielen Dank!

Die Funktion MERGE ist GEIL! face-big-smile

Ich finde es auch nett, dass man bei MERGE für INSERTs auch nicht zwingend die Tabellenstruktur vollständig haben muss,
fehlende Spalten werden direkt mit NULL befüllt.

Das gefällt mir äußerst gut und wieder was gelernt! face-smile
chgs2011
chgs2011 19.12.2018 um 19:32:12 Uhr
Goto Top
So habe den Syntax mal komplett aufgebaut und getestet, so schön wie MERGE auch ist,
bin ich aktuell nicht sicher, ob hier immer auf die ganze DB Tabelle gefeuert wird.

Habe 85.000 Datensätze, beim ersten feuern zieht er ALLE an, obwohl ich nur einen bearbeitet habe.
In meiner neuen Tabelle sind somit alle Datenzeilen drin.

Ich müsste also schon auch in deiner Syntax abfangen können, WELCHE Datensätze jetzt geändert wurden (UPDATE).
Es dürfen dann nicht gleich alle gezogen werden, das könnte die DB lahm legen.