Was tut SELECT FROM VALUES?
Wann immer ihr eine kleine Tabelle brauchtet, die ihr beispielsweise für Joins oder ähnliches verwenden solltet, haben wir hier im Dojo mit temporären Tabellen (hashtables, #-Tabellen) gearbeitet. Der Nachteil daran ist, dass ihr diese Objekte, wenn ihr euer Skript mehrfach ausführen wollt, auch immer mit einem DROP TABLE IF EXISTS
abräumen musstet, was die Leserlichkeit nicht gerade erhöht. Und auch wenn ihr in einer Anwendung gegen eine kleine Tabelle joinen möchtet, die ihr zum Beispiel nicht in der Datenbank persistieren wollt oder auch nicht als temporäres Objekt in der TempDB anlegen wollt, dann gibt es mit SELECT FROM VALUES
eine Alternative zu den beliebten #-Tabellen.
Wie könnt ihr mit SELECT FROM VALUES arbeiten?
Beginnen wir zunächst damit, eine kleine Wertesammlung anzulegen, aus der wir abfragen möchten:
SELECT NinjaName ,Kills FROM ( VALUES ('Chimozuki', 45) ) as t(NinjaName, Kills)
Natürlich können wir hier auch mehr als eine Zeile mit Daten erzeugen:
SELECT NinjaName ,Kills FROM ( VALUES ('Chimozuki', 45) ,('Lushikute', 82) ) as t(NinjaName, Kills)
Was euch hier vielleicht auffällt ist, dass der SQL Server hier automatisch die Kills-Spalte als ganzzahligen Wert annimmt und damit auch den Durchschnitt als ganzzahligen Wert zurückgibt, ihr erhaltet hier also 63 als Durchschnitt. Wenn ihr dagegen Nachkommastellen für die Kills angebt, erhaltet ihr den exakten Wert 63.5:
SELECT AVG(Kills) FROM ( VALUES ('Chimozuki', 45.0) ,('Lushikute', 82.0) ) as t(NinjaName, Kills)
Doch ihr könnt gegen die Tabellen-Objekte wie gesagt auch Joins ausführen. Wenn ihr in der WideWorldImporters Datenbank beispielsweise die Application.Countries-Tabelle gegen einige fixe Werte filtern möchtet, könnt ihr das wie folgt tun:
SELECT [CountryID] ,[CountryName] ,[FormalName] ,[IsoAlpha3Code] ,[LatestRecordedPopulation] ,[Continent] FROM [Application].[Countries] as c INNER JOIN ( SELECT FilteredID FROM (VALUES (1), (11), (100)) as SelectedCountries(FilteredID) ) s ON c.CountryID = s.FilteredID
Natürlich ginge das hier auch einfacher mit einem IN
in der WHERE
-Bedingung, aber es geht hier ja ums Prinzip und nicht um die eleganteste Lösung für einige Beispielabfragen… Warum solltet ihr SELECT FROM VALUES
verwenden statt #-Tabellen? Ganz einfach: euer Code wird einfacher, wenn ihr die Objekte nicht selber abräumen müsst und Abfragen einfach mehrfach im selben Kontext ausführen könnt, ohne euch Gedanken über Duplikate zu machen. Außerdem braucht ihr keine CREATE
-Statements schreiben sondern könnt die Objekte einfach direkt in der Abfrage erzeugen und verwenden. Warum solltet ihr #-Tabellen statt SELECT FROM VALUES
verwenden? Ganz einfach: ihr könnt #-Tabellen indizieren und mehrfach verwenden, wodurch eure Abfragen performanter werden. Außerdem könnt ihr bei #-Tabellen die Spalten in den richtigen Datentypen erzeugen und senkt dadurch die Wahrscheinlichkeit für implizite Converts im Ausführungsplan. Es ist also wie so oft eine Frage, was ihr mit den temporären Objekten tun wollt, welches Objekt die richtige Wahl für euch ist. Genau wie beim Ninja gilt: ein Katana ist eine feine Sache, aber wenn der Gegner noch 50 Meter weit entfernt ist, sind Shuriken eventuell die bessere Wahl. Passt die Wahl eurer temporären Objekte dem Gegner an.