T-SQL Ninja #50

SELECT FROM VALUES

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.

Referenzen

Ninja-Notebooks @ GitHub

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.