none
Update aus zwei Datensätzen RRS feed

  • Frage

  • Hallo allerseits,

    heute wende ich mich wieder mal an das Forum und wäre für Hilfestellung bei meinem Problem sehr dankbar. Ich habe Datensätze, die täglich auflaufen und die folgenden Felder darstellen.

    MANr         Datum           Beginn    Ende     VerspaetetDatum          VerspaetetZeit

    1             10.12.2012      10:00     18:00             0                                 0

    1             12.12.2012      10:30     20:00      10.12.2012                      19:00

    Es geht um Zeitkorrekturen, bei  denen ein Mitarbeiter z.B. am 12.12.2012 mitteilt, dass er am 10.12.2012 nicht um 18:00 Uhr sondern um 19:00 Uhr Feierabend gemacht hat. Es soll also die „VerspaetetZeit“ aus dem Datensatz vom 12.12. als „Ende“ in den Datensatz vom 10.12. übernommen und damit 18:00 Uhr ersetzt werden. Der Datensatz vom 12.12. bleibt unverändert.

    Wie stelle ich das am besten an? Ich bekomme keine vernünftige Update/Replace-Funktion hin.

    Vielen Dank schon mal für Hilfe.

    Gruß

    Volkmar

    Mittwoch, 9. Januar 2013 11:15

Alle Antworten

  • Hallo Volkmar,
    deine Datentypen sind mir nicht klar. Soll das ein String sein bei VerspaetetZeit und Ende?

    update  DeineTabelle set ende=verspaetetZeit where verspaetetZeit <>'0'

    Grüße Alexander

    Mittwoch, 9. Januar 2013 11:26
  • Hallo Alexander,

    stimmt, habe ich vergessen zu sagen: Es sind varchar-Felder. Mit deinem Update-Vorschlag hatte ich es schon versucht, aber dabei bleibt die Änderung in der Zeile. Es soll aber so sein, dass der VerspaetetZeit-Wert aus dem zweiten Datensatz (19:00) den Ende-Wert (18:00)des ersten (vom Datum her betrachtet) ersetzt.

    Gruß

    Volkmar

    Mittwoch, 9. Januar 2013 12:12
  • Hallo Volkmar,

    möchtest Du dann die Zeit in die ursprüngliche Zeile (in deinem Beispiel die obere) schreiben, oder soll die die 19.00 bei eine Query (Abfrage) erscheinen?

    Gruss Bernhard

    Mittwoch, 9. Januar 2013 12:39
  • Hallo Volkmar,

    Du benötigst keine Updates sondern nur eine View, die Aktualisierungen entsprechend widerspiegelt. Dennoch solltest Du ev. mal das Datenmodell überdenken; große Vorteile sehe ich da nicht :)

    USE tempdb
    GO
    DECLARE	@t TABLE
    (
    	MANr		int	NOT NULL,
    	Datum		char(10)	NOT NULL,
    	Beginn		char(5)	NOT NULL,
    	Ende		char(5)	NOT NULL,
    	VerspaetetDatum	char(10)	NULL,
    	VerspaetetZeit	char(5)	NULL
    );
    INSERT INTO @t
    (MANr, Datum, Beginn, Ende, VerspaetetDatum, VerspaetetZeit)
    VALUES
    (1, '10.12.2012', '10:00', '18:00', '0', '0'),
    (1, '12.12.2012', '10:30', '20:00', '10.12.2012', '19:00'),
    (2, '11.12.2012', '09:00', '15:00', '0', '0'),
    (3, '12.12.2012', '10:00', '14:30', '0', '0'),
    (3, '13.12.2012', '09:00', '18:00', '12.12.2012', '20:00')
    SELECT * FROM @t;
    SELECT	o.MANr,
    	o.Datum,
    	o.Beginn,
    	o.Ende
    FROM	@t o LEFT JOIN @t v
    	ON	(
    		o.MANr = v.MANr AND
    		o.Datum	= v.VerspaetetDatum
    		)
    WHERE	v.MANr IS NULL
    UNION
    SELECT	o.MANr,
    	o.Datum,
    	o.Beginn,
    	v.VerspaetetZeit
    FROM	@t v INNER JOIN @t o
    	ON	(
    		v.MANr = o.MANr AND
    		v.VerspaetetDatum = o.Datum
    		)				


    Uwe Ricken

    MCITP Database Administrator 2005
    MCITP Database Administrator 2008
    MCITP Microsoft SQL Server 2008, Database Development

    db Berater GmbH
    http://www-db-berater.de
    SQL Server Blog (german only)


    Mittwoch, 9. Januar 2013 12:43
  • Hallo Bernhard,

    die Zeit soll in die ursprüngliche Zeile geschrieben werden.

    Gruß

    Volkmar

    Mittwoch, 9. Januar 2013 12:45
  • Hallo Volkmar,

    als ohne Deinen genauen Anwendungsfall zu kennen, aber dann würde ich den Vorschlag von Uwe (Ricken) folgen und das Datenmodell überdenken.

    Ich unreinen gesprochen würde ich dann die Änderung die direkt in die Tabelle schreiben und die Änderung in einer Historytabelle dokumentieren...

    Gruss Bernhard

    Mittwoch, 9. Januar 2013 13:18
  • Hallo Uwe, hallo Bernhard,

    danke für eure Hilfe. Die Datensätze bestehen natürlich nicht nur aus den paar Werten, sondern sind sehr viel länger und stammen aus Quellen, die ich derzeit nicht beeinflussen kann. Anhand dieser Datensätze werden umfangreiche Berechnungen durchgeführt und die hier aufgezeigten Änderungen "von Hand" vorgenommen - das will ich abstellen ohne das Datenmodell zu ändern.

    Gibt es keine Möglichkeit einen Wert von einer Zeile in eine andere zu übertragen?

    Gruß

    Volkmar

    Mittwoch, 9. Januar 2013 13:35
  • Hallo Volkmar,

    hast Du denn Einfluss auf die Tabelle, wenn Du sagst, "kommen aus Quellen die Du nicht beeinfluss kannst" würde mir nur die Möglichkeit einfallen

    auf die Tabelle einen INSERT-Trigger zusetzen, der die eingefügte Zeile auswertet und dann die andere "Parent"-Zeile updatet..

    Gruss Bernhard

    Mittwoch, 9. Januar 2013 13:51
  • Hallo Bernhard,

    ja, auf die Tabelle kann ich zugreifen und auch ggf. Ergänzungen vornehmen. Wie könnte denn eine Lösung mit einem INSERT-Trigger aussehen.

    Gruß

    Volkmar

    Mittwoch, 9. Januar 2013 14:04
  • Hallo Volkmar,

    mal so auf die schnelle (ohne funktionsgarantie!)

    CREATE TRIGGER VerspaetDatumergaenzenen ON table_2 FOR INSERT
    AS 
    BEGIN
    	-- SET NOCOUNT ON added to prevent extra result sets from
    	-- interfering with SELECT statements.
    	SET NOCOUNT ON;
    
        -- Insert statements for trigger here
        DECLARE @wasupdated nvarchar(10),
    			@MANr		nvarchar(10),
    			@Datum		nvarchar(10),
    			@VZeit		nvarchar(10)
    		
        
        SET @wasupdated = (SELECT VerspaetetDatum FROM INSERTED);
        SET @MANr = (SELECT MANr FROM INSERTED);
        SET @VDatum = (SELECT VerspaetetDatum FROM INSERTED);
        SET @VZeit = (SELECT VerspaetetZeit FROM INSERTED);
            
        IF (@wasupdated != 0) 
    		UPDATE dbo.table_2 SET VerspaetetDatum = @Vzeit WHERE MANr = @MANr AND Datum = @VDatum
    
    END
    GO

    In der virutellen Tabelle "INSERTED" schreibt der SQL-Server selbst den aktuell eingefügten Datensatz.

    In Deinem Beispiel war der "leere / Standardwert" 0 für das Datum oder die Zeit, deswegen das ungleich 0.

    Datentypen musst Du natürlich auch Deinem gegebenheiten anpassen.

    Es ist auch eventuell nicht der eleganteste Code, aber sollte funktionieren.

    Bei Fragen oder Probleme versuche ich gerne zu helfen..

    Gruss Bernhard

    Mittwoch, 9. Januar 2013 14:19
  • So kompliziert, wie Bernhard es gemacht hat, muss es nicht gleich sein :)
    Das nachfolgende Beispiel macht das eleganter und einfacher und berücksicht auch mehrere Datensätze (das ist das Manko an Bernhards - dennoch gutem - Beispiel)

    USE tempdb
    GO
    IF OBJECT_ID('dbo.test', 'U') IS NOT NULL
    	DROP TABLE dbo.Test
    	GO
    CREATE TABLE dbo.Test
    (
    	MANr			int		NOT NULL,
    	Datum			char(10)	NOT NULL,
    	Beginn			char(5)		NOT NULL,
    	Ende			char(5)		NOT NULL,
    	VerspaetetDatum	char(10)	NULL,
    	VerspaetetZeit	char(5)		NULL,
    	
    	CONSTRAINT pk_Test PRIMARY KEY CLUSTERED 
    	(
    		MANr,
    		Datum
    	)
    )
    GO
    CREATE TRIGGER dbo.trg_Test
    ON dbo.Test
    FOR INSERT, UPDATE
    AS
    	SET NOCOUNT ON
    	
    	UPDATE	t
    	SET	t.Ende = i.VerspaetetZeit
    	FROM	inserted i INNER JOIN dbo.Test t
    		ON	(
    				i.MANr = t.MANr AND
    				i.VerspaetetDatum = t.Datum
    			)
    	WHERE	i.VerspaetetDatum != '0'
    	
    	SET NOCOUNT OFF
    GO
    	
    INSERT INTO dbo.Test
    (MANr, Datum, Beginn, Ende, VerspaetetDatum, VerspaetetZeit)
    VALUES
    (1, '10.12.2012', '10:00', '18:00', '0', '0'),
    (1, '12.12.2012', '10:30', '20:00', '10.12.2012', '19:00'),
    (2, '11.12.2012', '09:00', '15:00', '0', '0'),
    (3, '12.12.2012', '10:00', '14:30', '0', '0'),
    (3, '13.12.2012', '09:00', '18:00', '12.12.2012', '20:00')
    SELECT * FROM dbo.Test;
    Dennoch würde ich mit Triggern vorsichtig sein, wenn es sich um ein eingekauftes Produkt handelt. In diesem Fall würdest Du nämlch jeglichen Supportanspruch verlieren. Gleichwohl dringend anzuraten sind Tests in einer DEV-Umgebung!

    Uwe Ricken

    MCITP Database Administrator 2005
    MCITP Database Administrator 2008
    MCITP Microsoft SQL Server 2008, Database Development

    db Berater GmbH
    http://www-db-berater.de
    SQL Server Blog (german only)


    Mittwoch, 9. Januar 2013 14:32
  • Hallo Uwe,

    hatte ich ja auch schon bemerkt, dass eventuell eleganter geht. Du hast es ja auch geschrieben, dass es trotzdem ein gutes Beispiel ist. Ich denke es vielleicht für Anfänger oder "SQL-Unbedarfte" leichter zu verstehen... Mal abgesehen von der Frage, ob sich diese an solch eine Aufgabenstellung wagen sollten. Aber man wächst mit den Aufgaben ;-)

    Deswegen mal für mich: Du schreibst meine Lösung ist nicht für mehrere Datensätze geeignet. Ich bin bis dato davon ausgegangen, dass der SQL-Server den Trigger für jeden INSERT aufruft, auf wenn mehrere Datensätze eingefügt werden.

    Danke und Gruss

    Bernhard

    Mittwoch, 9. Januar 2013 14:41
  • Deswegen mal für mich: Du schreibst meine Lösung ist nicht für mehrere Datensätze geeignet. Ich bin bis dato davon ausgegangen, dass der SQL-Server den Trigger für jeden INSERT aufruft, auf wenn mehrere Datensätze eingefügt werden.

    Hallo Bernhard,

    du hast recht, dass der Trigger pro INSERT durchgeführt wird - aber das gilt immer für die Transaktion selbst.

    Ein einfaches Beispiel, wie es auf jeden Fall mit Deinem Trigger funktionieren wird:

    INSERT INTO dbo.Test
    (MANr, Datum, Beginn, Ende, VerspaetetDatum, VerspaetetZeit)
    VALUES
    (1, '10.12.2012', '10:00', '18:00', '0', '0')

    Hierbei wird innerhalb der Transaktion nur EIN Datensatz eingefügt. Nun nehmen wir ein anderes Beispiel, in dem mehrere Datensätze in einer Transaktion eingetragen werden:

    INSERT INTO dbo.Test
    (MANr, Datum, Beginn, Ende, VerspaetetDatum, VerspaetetZeit)
    SELECT 1, '10.12.2012', '10:00', '18:00', '0', '0'
    UNION
    SELECT 2, '11.12.2012', '09:00', '15:00', '0', '0'
    UNION
    SELECT 3, '12.12.2012', '10:00', '14:30', '0', '0')

    Nun kann Dein Trigger nicht mehr funktionieren, da er immer darauf abzielt, nur einen Datensatz in inserted vorzufinden. Ein ganz simples Beispiel, dass Du ausprobieren kannst, verdeutlicht das Problem. Als Beispiel nehme ich die Daten aus der diesem Thread zugrunde liegenden Relation:

    DECLARE @MANr int
    SELECT  @MANr = MANr FROM dbo.test
    SELECT  @MANr

    Das Ergebnis wird sicherlich überraschend kommen, es wird die 3 sein. Das liegt daran, dass der Variablen immer der Wert des LETZTEN Datensatzes aus dem Resultset zugewiesen wird!

    Würde nun also der Trigger so eingesetzt werden, wie von Dir vorgeschlagen, würde nur der letzte Datensatz aus inserted berücksichtigt werden.


    Uwe Ricken

    MCITP Database Administrator 2005
    MCITP Database Administrator 2008
    MCITP Microsoft SQL Server 2008, Database Development

    db Berater GmbH
    http://www-db-berater.de
    SQL Server Blog (german only)

    Mittwoch, 9. Januar 2013 14:52
  • Hallo Uwe,

    danke für die Erklärung!

    Bernhard

    Mittwoch, 9. Januar 2013 15:10
  • Hallo Bernhard, hallo Uwe,

    ich danke euch sehr für die Unterstützung. Nun ist es an mir die Lösungen umzusetzen und - wichtig - zu verstehen. Bisher habe ich noch keine Trigger verwendet und bin deshalb sehr gespannt. Ich melde mich wieder, wenn alles läuft - so hoffe ich.

    Also nochmals vielen Dank und einen schönen Abend.

    Gruß

    Volkmar

    Mittwoch, 9. Januar 2013 15:15
  • Hallo Bernhard, hallo Uwe,

    dank eurer Unterstützung habe ich mein Problem lösen können - alles läuft prima und ich experimentiere gerade noch weiter mit Triggern. Die Funktion ist ja zunächst verlockend, aber man verliert auch leicht die Übersicht, sobald mehrere zum Einsatz kommen. Man "sieht" sie ja nicht.

    Danke für die Hilfe.

    Gruß

    Volkmar

    Donnerstag, 10. Januar 2013 10:18