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.