none
Gleiche Abfrage mehrfach ausführen - Spaltennamen jeweils ändern RRS feed

  • Frage

  • Hallo SQL-Entwickler,

    ich habe eine etwas komplexere UPDATE-Abfrage, die ich in meinem Code mit jeweils veränderten Spaltennamen mehrfach ausführen will. Ganz grob: Es sollen zwei Spalten, die verschiedene Zeiten enthalten ausgewählt werden und die Zeitdifferenz zwischen den Spalten gebildet werden und in eine weitere Spalte eingefügt werden. Das funktioniert auch.  

    Natürlich kann ich diese Abfrage 10 mal in meinen Code einfügen und die Spaltennamen jeweils ändern. Aber das ist ja nicht wirklich schön, oder?

    Ich hatte mich jetzt dazu schon belesen und eine Realisierung mit einer Prozedur gefunden: 

    ALTER PROCEDURE [dbo].[Prozedur3]
    	@Wert1 nvarchar(50),
    	@Wert2 nvarchar(50),
    	@Wert3 nvarchar(50),
    AS
    BEGIN
    
    	SET NOCOUNT OFF;
    	DECLARE @sqlText nvarchar(max); 
    
    	SET @sqlText = N' 
            
            Update Tabelle1
            Set ' + @Wert3 + ' = select datediff(second, ' + @Wert1 + ', ' + @Wert2 + ') 
            Where ...
            '
            Exec (@sqlText)
    End 
        

    (der Code innerhalb der Prozedur ist in Wirklichkeit sehr viel größer) 

    Und in meinem Hauptcode führe ich die Prozedur dann mehrfach mit

    Exec Prozedur3 'Spalte1', 'Spalte2', 'Spalte3'

    aus und verändere die Spaltennamen. 

    Das funktioniert auch. 

    Ich habe jetzt aber schon mehrfach gelesen, dass man sowas nicht macht.  

    Wie macht man sonst sowas? 

    Wenn ihr sonst Infos benötigt dann meldet euch. Schon einmal vielen Dank und freundliche Grüße!

    Mittwoch, 27. Juli 2016 06:52

Antworten

  • Hallo Christian,

    entweder, Du machst es wie Benjamin beschreibt oder aber  - wenn es schon dynamisches SQL sein soll - verwende zumindest zwei Besonderheiten:

    Deine beschriebene Variante ist schnell ein Opfer von "SQL Injection" und das kann I. d. R. böse enden...

    Was glaubst Du, wird als Command herauskommen, wenn die Prozedur so ausgeführt wird:

    EXEC dbo.prozedur3 'Spalte1', 'Spalte2', 'ID = ID; DROP DATABASE demo_db; --';

    Wenn Du schon mit dynamischem SQL arbeiten willst, schreibe Deine Prozedur wie folgt um:

    CREATE PROCEDURE [dbo].[Prozedur3]
    	@Wert1 nvarchar(50),
    	@Wert2 nvarchar(50),
    	@Wert3 nvarchar(50)
    AS
    BEGIN
    	SET NOCOUNT ON;
    
    	DECLARE @sqlText nvarchar(4000);
    	SET @sqlText = N'UPDATE dbo.Tabelle1 SET ' + QUOTENAME(@Wert3) + ' = DATEDIFF(SECOND, ' + QUOTENAME(@Wert1) + ', ' + QUOTENAME(@Wert2) + ') WHERE ...'
    
    	PRINT @sqltext;
    	EXEC sp_executesql @sqlText;
    End 
    GO


    Uwe Ricken (Blog | Twitter)
    Microsoft Certiied Master - SQL Server 2008
    Microsoft Certified Solution Master - CHARTER Data Platform
    Microsoft Certified Solution Expert - Data Platform
    db Berater GmbH
    Microsoft SQL Server Blog (german only)


    Mittwoch, 27. Juli 2016 07:34

Alle Antworten

  • Hallo Christian,

    wenn du immer in der Spalte3 die Differenz von zwei anderen (immer den gleichen) Spalten berechnet haben möchtest würde ich dir empfehlen eine Berechnete Spalte zu nutzen und den SQL Server hier automatisch diese Aufgabe zu übergeben.

    https://msdn.microsoft.com/de-de/library/ms188300.aspx


    Benjamin Hoch
    MCSE: Data Platform
    MCSA: SQL Server 2012/2014
    MCSA: Windows Server 2012
    Blog

    Mittwoch, 27. Juli 2016 07:11
  • Hallo Christian,

    entweder, Du machst es wie Benjamin beschreibt oder aber  - wenn es schon dynamisches SQL sein soll - verwende zumindest zwei Besonderheiten:

    Deine beschriebene Variante ist schnell ein Opfer von "SQL Injection" und das kann I. d. R. böse enden...

    Was glaubst Du, wird als Command herauskommen, wenn die Prozedur so ausgeführt wird:

    EXEC dbo.prozedur3 'Spalte1', 'Spalte2', 'ID = ID; DROP DATABASE demo_db; --';

    Wenn Du schon mit dynamischem SQL arbeiten willst, schreibe Deine Prozedur wie folgt um:

    CREATE PROCEDURE [dbo].[Prozedur3]
    	@Wert1 nvarchar(50),
    	@Wert2 nvarchar(50),
    	@Wert3 nvarchar(50)
    AS
    BEGIN
    	SET NOCOUNT ON;
    
    	DECLARE @sqlText nvarchar(4000);
    	SET @sqlText = N'UPDATE dbo.Tabelle1 SET ' + QUOTENAME(@Wert3) + ' = DATEDIFF(SECOND, ' + QUOTENAME(@Wert1) + ', ' + QUOTENAME(@Wert2) + ') WHERE ...'
    
    	PRINT @sqltext;
    	EXEC sp_executesql @sqlText;
    End 
    GO


    Uwe Ricken (Blog | Twitter)
    Microsoft Certiied Master - SQL Server 2008
    Microsoft Certified Solution Master - CHARTER Data Platform
    Microsoft Certified Solution Expert - Data Platform
    db Berater GmbH
    Microsoft SQL Server Blog (german only)


    Mittwoch, 27. Juli 2016 07:34
  • Okay vielen Dank für die Tipps! 

    Leider ist es nicht immer Spalte 3. 

    SQL-Injektion: Ich denke, dass im Zuge dessen meine Tabelle gelöscht werden würde. 


    Mittwoch, 27. Juli 2016 08:19
  • Hallo Christian,

    dein Schönheitsempfinden in allen Ehren, nur ist das Ausführen einer Prozedur zehn mal hintereinander schlicht und einfach ineffizient, selbst wenn man die potentielle SQL Injection ignoriert. Denn dazu muss die Tabellenzeile jedes mal geändert werden sowie die Änderung protokolliert werden. Das dauert deutlich länger als wenn man es einmalig in einem längeren Anweisungsblock erledigt.

    Wenn es wirklich 10 Werte (oder mehr) sind, sollte man prüfen, ob es nicht sinnvoll ist, die Tabelle aufzuteilen und durch weitere Normalisierung zu erreichen, dass man die Aktualisierung in einer Anweisung und ohne dynamische Spaltenermittlung durchführen kann.

    Gruß Elmar

    Mittwoch, 27. Juli 2016 08:27
    Beantworter