SQL Views - keine Variablen?


83

Ist es möglich, eine Variable in einer Ansicht zu deklarieren? Zum Beispiel:

Declare @SomeVar varchar(8) = 'something'

gibt mir den Syntaxfehler:

Falsche Syntax in der Nähe des Schlüsselworts 'Declare'.

Antworten:


66

Du hast Recht. Lokale Variablen sind in einer VIEW nicht zulässig.

Sie können eine lokale Variable in einer Tabellenwertfunktion festlegen, die eine Ergebnismenge zurückgibt (wie in einer Ansicht).

http://msdn.microsoft.com/en-us/library/ms191165.aspx

z.B

CREATE FUNCTION dbo.udf_foo()
RETURNS @ret TABLE (col INT)
AS
BEGIN
  DECLARE @myvar INT;
  SELECT @myvar = 1;
  INSERT INTO @ret SELECT @myvar;
  RETURN;
END;
GO
SELECT * FROM dbo.udf_foo();
GO

Ist seine Effizienz ähnlich wie die einer Ansicht?
RaRdEvA

Nein, TVFs sind oft langsamer. "Die tabellenwertigen Funktionen (TVFs) von SQL Server scheinen eine gute Idee zu sein, maskieren jedoch eine Vielzahl potenzieller Leistungsprobleme. TVFs führen dazu, dass Teile eines Ausführungsplans seriell bleiben (sie vermeiden Parallelität). Sie führen zu schlechten Zeilenschätzungen. und TVFs mit mehreren Anweisungen erhalten möglicherweise nicht einmal die beste verfügbare Optimierung. Kurz gesagt - TVFs stinken. " brentozar.com/blitzcache/tvf-join
wp78de

49

Sie können WITH verwenden, um Ihre Ausdrücke zu definieren. Führen Sie dann eine einfache Unterauswahl aus, um auf diese Definitionen zuzugreifen.

CREATE VIEW MyView
AS
  WITH MyVars (SomeVar, Var2)
  AS (
    SELECT
      'something' AS 'SomeVar',
      123 AS 'Var2'
  )

  SELECT *
  FROM MyTable
  WHERE x = (SELECT SomeVar FROM MyVars)

3
Dies ist eine Konstante, keine Variable!
Vladislav

2
@Vladislav Es kann genauso einfach (gefilterte?) Daten aus einer Tabelle verwenden.
Dodecaphone

18

BEARBEITEN: Ich habe versucht, bei meiner vorherigen Antwort einen CTE zu verwenden, der falsch war, wie @bummi hervorhob. Diese Option sollte stattdessen funktionieren:

Hier ist eine Option, die eine CROSS APPLY verwendet, um dieses Problem zu umgehen:

SELECT st.Value, Constants.CONSTANT_ONE, Constants.CONSTANT_TWO
FROM SomeTable st
CROSS APPLY (
    SELECT 'Value1' AS CONSTANT_ONE,
           'Value2' AS CONSTANT_TWO
) Constants

Vielen Dank für die Korrektur - aktualisiert, um stattdessen CROSS APPLY zu verwenden.
Daniel Neel

Dies funktioniert, aber werden die Spalten des Cross Apply nicht für jede Zeile neu initialisiert? Insbesondere für berechnete Werte würde dies einen großen Leistungsverlust bedeuten. Es ist nur traurig, dass Local Variable und CTE in einer Ansicht nicht verfügbar sind. Hat jemand eine Idee warum?
T_D

1
@T_D Sie können 'CTE' in 'View' erstellen und verwenden.
Semuserable

6

@datenstation hatte das richtige Konzept. Hier ist ein Arbeitsbeispiel, das CTE verwendet, um die Namen von Variablen zwischenzuspeichern:

CREATE VIEW vwImportant_Users AS
WITH params AS (
    SELECT 
    varType='%Admin%', 
    varMinStatus=1)
SELECT status, name 
    FROM sys.sysusers, params
    WHERE status > varMinStatus OR name LIKE varType

SELECT * FROM vwImportant_Users

auch über JOIN

WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name 
    FROM sys.sysusers INNER JOIN params ON 1=1
    WHERE status > varMinStatus OR name LIKE varType

auch über CROSS APPLY

WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name 
    FROM sys.sysusers CROSS APPLY params
    WHERE status > varMinStatus OR name LIKE varType

4

Die Verwendung von Funktionen wie spencer7593 ist ein korrekter Ansatz für dynamische Daten. Bei statischen Daten besteht ein leistungsfähigerer Ansatz, der mit dem SQL-Datenentwurf übereinstimmt (im Gegensatz zum Anti-Muster, massiven Prozedurcode in Sprocs zu schreiben), darin, eine separate Tabelle mit den statischen Werten zu erstellen und diese zu verknüpfen. Dies ist aus Sicht der Leistung äußerst vorteilhaft, da die SQL Engine effektive Ausführungspläne für einen JOIN erstellen kann und Sie bei Bedarf auch Indizes hinzufügen können.

Der Nachteil der Verwendung von Funktionen (oder von inline berechneten Werten) besteht darin, dass das Callout für jede potenzielle zurückgegebene Zeile erfolgt, was kostspielig ist. Warum? Weil SQL zuerst ein vollständiges Dataset mit den berechneten Werten erstellen und dann die WHERE-Klausel auf dieses Dataset anwenden muss.

Neun von zehn Fällen sollten Sie in Ihren Abfragen keine dynamisch berechneten Zellenwerte benötigen. Es ist viel besser, herauszufinden, was Sie benötigen, dann ein Datenmodell zu entwerfen, das dies unterstützt, dieses Datenmodell mit semidynamischen Daten zu füllen (z. B. über Batch-Jobs) und die SQL Engine zu verwenden, um das schwere Heben über Standard-SQL durchzuführen .


3

Ja, das ist richtig. Sie können keine Variablen in Ansichten haben (es gibt auch andere Einschränkungen).

Ansichten können für Fälle verwendet werden, in denen das Ergebnis durch eine select-Anweisung ersetzt werden kann.


Eine Tabellenfunktion kann in einer select-Anweisung ersetzt werden und verfügt über lokale Variablen.
JeffO

Wollen Sie damit sagen, dass eine select-Anweisung keine lokalen Variablen haben kann, eine Ansicht auch nicht?
JeffO

1
@ JeffO "Sie können keine Variablen in Ansichten haben", habe ich gesagt. Ist das unklar?
Hogan

Es ist der letzte Satz. Eine Ansicht kann eine select-Anweisung ersetzen, aber was hat das mit Variablen zu tun? Könnte eine Tabellenfunktion eine select-Anweisung nicht ersetzen, sondern Variablen einschließen?
JeffO

1
Eine Tabellenfunktion kann auch durch eine select-Anweisung ersetzt werden, Tabellenfunktionen können jedoch nicht überall verwendet werden, wo eine Ansicht dies kann, z. B. Verknüpfungen. Er versucht zu sagen, dass eine Ansicht eine einzelne select-Anweisung ersetzen kann, aber nicht mehrere Anweisungen. Das Schlüsselwort BEGIN ist in einer CREATE VIEW-Anweisung sowie in einer Inline-Funktion ungültig. Es wäre erforderlich, ein Multistatement-Skript zu erstellen. Prozeduren oder Funktionen mit mehreren Anweisungen sind wahrscheinlich der beste Weg, dies zu tun.
Arlen Beiler

1

Ich erstelle eine Ansicht, die dieselbe Auswahl wie die Tabellenvariable ausführt, und verknüpfe diese Ansicht mit der zweiten Ansicht. So kann eine Ansicht aus einer anderen Ansicht auswählen. Dies erzielt das gleiche Ergebnis


2
Ben, dies würde wahrscheinlich ein Leistungsproblem verursachen, es sei denn, Sie haben es mit sehr kleinen Tabellen zu tun.
Logixologe

Selbst bei sehr kleinen Tabellen (3 Datensätze) verursacht eine Ansicht mit Millionen Datensätzen große Leistungsprobleme.
st_stefanov

0

Wie oft müssen Sie die Ansicht aktualisieren? Ich habe einen ähnlichen Fall, in dem die neuen Daten einmal im Monat eingehen. dann muss ich es laden und während des Ladevorgangs muss ich neue Tabellen erstellen. In diesem Moment ändere ich meine Ansicht, um die Änderungen zu berücksichtigen. Ich habe die Informationen in dieser anderen Frage als Grundlage verwendet:

Ansicht dynamisch erstellen & Synonyme

Dort wird vorgeschlagen, dies auf zwei Arten zu tun:

  1. mit Synonymen.
  2. Verwenden von dynamischem SQL zum Erstellen einer Ansicht (dies hat mir geholfen, mein Ergebnis zu erzielen).
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.