Представления SQL - без переменных?


83

Можно ли объявить переменную в представлении? Например:

Declare @SomeVar varchar(8) = 'something'

дает мне синтаксическую ошибку:

Неправильный синтаксис рядом с ключевым словом Declare.

Ответы:


66

Ты прав. Локальные переменные не допускаются в ВИДЕ.

Вы можете установить локальную переменную в функции с табличным значением, которая возвращает набор результатов (как это делает представление).

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

например

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

Его эффективность похожа на эффективность просмотра?
RaRdEvA

Нет, TVF часто медленнее. «Возвращающие табличное значение функции (TVF) SQL Server кажутся хорошей идеей, но они маскируют множество потенциальных проблем с производительностью. TVF заставляют части плана выполнения оставаться последовательными (они избегают параллелизма), они производят плохие оценки строк, а TVF с несколькими операторами могут даже не получить самую лучшую возможную оптимизацию. Короче говоря, TVF воняют ». brentozar.com/blitzcache/tvf-join
wp78de

49

Вы можете использовать WITH для определения ваших выражений. Затем выполните простой Sub-SELECT для доступа к этим определениям.

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
это константы, а не переменные!
Владислав

2
@Vladislav Он может так же легко использовать (отфильтрованные?) Данные из таблицы.
Dodecaphone

18

РЕДАКТИРОВАТЬ: Я попытался использовать CTE в своем предыдущем ответе, который был неверным, как указано @bummi. Вместо этого должен работать этот вариант:

Вот один из вариантов использования CROSS APPLY для решения этой проблемы:

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

Спасибо за исправление - обновлено, чтобы вместо этого использовать CROSS APPLY.
Daniel Neel

Это работает, но разве столбцы перекрестного применения не инициализируются повторно для каждой строки? Особенно для расчетных значений, которые будут означать большую потерю производительности. Просто грустно, что локальная переменная и CTE недоступны в представлении, кто-нибудь знает, почему?
T_D

1
@T_D вы можете создать и использовать CTE в View.
Semuserable

6

@datenstation имеет правильную концепцию. Вот рабочий пример, в котором CTE используется для кэширования имен переменных:

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

также через 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

также через 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

Использование функций, упомянутых в spencer7593, является правильным подходом для динамических данных. Для статических данных более производительный подход, который согласуется с дизайном данных SQL (в отличие от анти-шаблона написания массивного процедурного кода в sprocs), заключается в создании отдельной таблицы со статическими значениями и присоединении к ней. Это чрезвычайно выгодно с точки зрения производительности, поскольку SQL Engine может строить эффективные планы выполнения на основе JOIN, и вы также можете добавлять индексы, если это необходимо.

Недостатком использования функций (или любых встроенных вычисляемых значений) является то, что выноска выполняется для каждого потенциального возвращаемой строки, что дорого. Почему? Поскольку SQL должен сначала создать полный набор данных с вычисленными значениями, а затем применить предложение WHERE к этому набору данных.

В девяти случаях из десяти вам не понадобятся динамически вычисляемые значения ячеек в ваших запросах. Гораздо лучше выяснить, что вам понадобится, затем разработать модель данных, которая ее поддерживает, и заполнить эту модель данных полудинамическими данными (например, с помощью пакетных заданий) и использовать SQL Engine для выполнения тяжелой работы через стандартный SQL. .


3

Да, это правильно, у вас не может быть переменных в представлениях (есть и другие ограничения).

Представления можно использовать в случаях, когда результат можно заменить оператором выбора.


Табличную функцию можно заменить в операторе выбора, и она имеет локальные переменные.
JeffO

Вы говорите, что, поскольку оператор select не может иметь локальных переменных, представление тоже не может?
JeffO

1
@JeffO «У вас не может быть переменных в представлениях» - вот что я сказал. Это непонятно?
Hogan

Это последнее предложение. Представление может заменить оператор выбора, но какое это имеет отношение к переменным? Не может ли табличная функция заменить оператор выбора, но включить переменные?
JeffO

1
Табличную функцию также можно заменить оператором select, но табличные функции нельзя использовать везде, где это возможно, например, соединения. Он пытается сказать, что представление может заменить один оператор выбора, но не может заменить несколько операторов. Ключевое слово BEGIN недопустимо в операторе CREATE VIEW, а также во встроенной функции. Потребуется создать сценарий с несколькими операциями. Вероятно, лучший способ сделать это - процедуры или функции с несколькими операторами.
Арлен Бейлер,

1

Что я делаю, так это создаю представление, которое выполняет тот же выбор, что и переменная таблицы, и связываю это представление со вторым представлением. Таким образом, представление может выбирать из другого представления. Это дает тот же результат


2
Бен, это, скорее всего, вызовет проблемы с производительностью, если вы не имеете дело с очень маленькими таблицами.
логиксолог

Даже с очень маленькой таблицей (3 записи) представление с миллионом записей вызывает большие проблемы с производительностью.
st_stefanov

0

Как часто вам нужно обновлять вид? У меня похожий случай, когда новые данные приходят раз в месяц; затем мне нужно загрузить его, и в процессе загрузки я должен создавать новые таблицы. В этот момент я меняю свое мнение, чтобы учесть изменения. Я использовал в качестве основы информацию в этом другом вопросе:

Создание динамического просмотра и синонимов

Там предлагается сделать это двумя способами:

  1. используя синонимы.
  2. Использование динамического SQL для создания представления (именно это помогло мне добиться результата).
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.