Benutzer mit den meisten Antworten
Gleiche Abfrage mehrfach ausführen - Spaltennamen jeweils ändern

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!
Antworten
-
Hallo Christian,
entweder, Du machst es wie Benjamin beschreibt oder aber - wenn es schon dynamisches SQL sein soll - verwende zumindest zwei Besonderheiten:
- sp_executesql
- QUOTENAME für die Kapselung des Strings
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)- Bearbeitet Uwe RickenMVP Mittwoch, 27. Juli 2016 07:35
- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Samstag, 30. Juli 2016 12:49
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Administrator Freitag, 5. August 2016 12:55
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 -
Hallo Christian,
entweder, Du machst es wie Benjamin beschreibt oder aber - wenn es schon dynamisches SQL sein soll - verwende zumindest zwei Besonderheiten:
- sp_executesql
- QUOTENAME für die Kapselung des Strings
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)- Bearbeitet Uwe RickenMVP Mittwoch, 27. Juli 2016 07:35
- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Samstag, 30. Juli 2016 12:49
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Administrator Freitag, 5. August 2016 12:55
-
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