Widoki SQL - brak zmiennych?


83

Czy można zadeklarować zmienną w widoku? Na przykład:

Declare @SomeVar varchar(8) = 'something'

daje mi błąd składni:

Niepoprawna składnia w pobliżu słowa kluczowego „Declare”.

Odpowiedzi:


66

Masz rację. Zmienne lokalne nie są dozwolone w WIDOKU.

Możesz ustawić zmienną lokalną w funkcji wycenianej w tabeli, która zwraca zestaw wyników (tak jak robi to widok).

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

na przykład

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

Czy jego skuteczność jest podobna do widoku?
RaRdEvA

Nie, TVF są często wolniejsze. „Funkcje tabelaryczne (TVF) programu SQL Server wydają się dobrym pomysłem, ale maskują szereg potencjalnych problemów z wydajnością. Funkcje TVF powodują, że części planu wykonania pozostają szeregowe (unikną równoległości), generują złe oszacowania wierszy, a TVF z wieloma stwierdzeniami może nawet nie uzyskać najlepszej dostępnej optymalizacji. Krótko mówiąc - TVF śmierdzi ”. brentozar.com/blitzcache/tvf-join
wp78de

49

Możesz użyć WITH do zdefiniowania swoich wyrażeń. Następnie wykonaj prosty PODWYBÓR, aby uzyskać dostęp do tych definicji.

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
to są stałe, a nie zmienne!
Vladislav

2
@Vladislav Równie łatwo może używać (przefiltrować?) Dane z tabeli.
Dodecaphone,

18

EDYCJA: Próbowałem użyć CTE w mojej poprzedniej odpowiedzi, która była niepoprawna, jak wskazał @bummi. Zamiast tego ta opcja powinna działać:

Oto jedna opcja za pomocą CROSS APPLY, aby obejść ten problem:

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

Dzięki za korektę - zaktualizowano, aby zamiast tego używać CROSS APPLY.
Daniel Neel

To działa, ale czy kolumny funkcji Cross Apply nie są ponownie inicjowane dla każdego wiersza? Szczególnie w przypadku obliczonych wartości oznaczałoby to dużą utratę wydajności. To po prostu smutne, że zmienna lokalna i CTE nie są dostępne w widoku, ktoś ma pomysł, dlaczego?
T_D

1
@T_D możesz tworzyć i używać 'CTE' w 'Widok'.
Semuserable

6

@datenstation miał poprawną koncepcję. Oto działający przykład, który używa CTE do buforowania nazw zmiennych:

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

również za pośrednictwem 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

również za pośrednictwem 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

Używanie funkcji, jak wspomniano spencer7593, jest poprawnym podejściem do danych dynamicznych. W przypadku danych statycznych bardziej wydajnym podejściem, które jest spójne z projektowaniem danych SQL (w porównaniu ze wzorcem tworzenia masowego kodu proceduralnego w sprocach) jest utworzenie oddzielnej tabeli z wartościami statycznymi i dołączenie do niej. Jest to niezwykle korzystne z punktu widzenia wydajności, ponieważ aparat SQL może budować efektywne plany wykonania wokół JOIN, aw razie potrzeby można również dodawać indeksy.

Wadą korzystania z funkcji (lub dowolnych wartości obliczonych w wierszu ) jest to, że wywołanie występuje dla każdego potencjalnego zwróconego wiersza, co jest kosztowne. Czemu? Ponieważ SQL musi najpierw utworzyć pełny zestaw danych z obliczonymi wartościami, a następnie zastosować klauzulę WHERE do tego zestawu danych.

W dziewięciu przypadkach na dziesięć nie powinieneś potrzebować dynamicznie obliczanych wartości komórek w zapytaniach. Jest o wiele lepiej, aby dowiedzieć się, co trzeba, a następnie zaprojektować model danych, który obsługuje tę funkcję, a propaguje model danych z semi-dynamicznych danych (za pomocą zadań wsadowych na przykład) i korzystać z SQL Silnik zrobić dźwiganie ciężarów poprzez standardowe SQL .


3

Tak, to prawda, nie możesz mieć zmiennych w widokach (są też inne ograniczenia).

Widoki mogą być używane w przypadkach, w których wynik można zastąpić instrukcją select.


Funkcję tabelową można zastąpić w instrukcji select i ma ona zmienne lokalne.
JeffO,

Czy mówisz, że skoro instrukcja select nie może mieć zmiennych lokalnych, widok też nie może?
JeffO

1
@JeffO „nie możesz mieć zmiennych w widokach” - tak powiedziałem. Czy to jest niejasne?
Hogan

To ostatnie zdanie. Widok może zastąpić instrukcję select, ale co to ma wspólnego ze zmiennymi? Czy funkcja tabeli nie mogła zastąpić instrukcji select, ale uwzględnić zmienne?
JeffO,

1
Funkcję tabeli można również zastąpić instrukcją select, ale funkcji tabelowych nie można używać wszędzie tam, gdzie jest to możliwe, na przykład w przypadku łączenia. Próbuje powiedzieć, że widok może zastąpić pojedynczą instrukcję select, ale nie może zastąpić wielu instrukcji. Słowo kluczowe BEGIN jest nieprawidłowe w instrukcji CREATE VIEW, a także w funkcji wbudowanej. Konieczne byłoby stworzenie scenariusza wielostanowiskowego. Procedury lub funkcje wielu instrukcji są prawdopodobnie najlepszym sposobem na to.
Arlen Beiler

1

Tworzę widok, który dokonuje takiego samego wyboru, jak zmienna tabeli i łączy ten widok z drugim widokiem. Tak więc widok można wybrać z innego widoku. Daje to ten sam wynik


2
Ben, prawdopodobnie spowodowałoby to problem z wydajnością, chyba że masz do czynienia z bardzo małymi stołami.
logiksolog,

Nawet przy bardzo małej tabeli (3 rekordy) widok z milionem rekordów powoduje duże problemy z wydajnością.
st_stefanov

0

Jak często musisz odświeżyć widok? Mam podobny przypadek, w którym nowe dane pojawiają się raz w miesiącu; następnie muszę go załadować, a podczas procesów ładowania muszę tworzyć nowe tabele. W tym momencie zmieniam swój pogląd, aby rozważyć zmiany. Jako podstawę użyłem informacji w tym drugim pytaniu:

Utwórz widok Dynamicznie i synonimy

Tam proponuje się zrobić to na 2 sposoby:

  1. używając synonimów.
  2. Używanie dynamicznego SQL do tworzenia widoku (to pomogło mi osiągnąć mój wynik).
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.