SQL视图-没有变量?


83

是否可以在View中声明变量?例如:

Declare @SomeVar varchar(8) = 'something'

给我语法错误:

关键字“ Declare”附近的语法不正确。

Answers:


66

你是对的。VIEW中不允许使用局部变量。

您可以在表值函数中设置局部变量,该变量将返回结果集(就像视图一样)。

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通常较慢。“ SQL Server的表值函数(TVF)似乎是个好主意,但它们掩盖了许多潜在的性能问题。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 2014年

这行得通,但是跨行应用的列是否不会为每行重新初始化?特别是对于计算值而言,这将意味着很大的性能损失。遗憾的是,视图中没有局部变量和CTE,有人知道为什么吗?
T_D 2015年

1
@T_D,您可以在“视图”中创建和使用“ CTE”。
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数据设计一致的性能更高的方法(与在proc中编写大量过程代码的反模式相反)是使用静态值创建一个单独的表并将其联接。从性能角度来看,这是非常有益的,因为SQL引擎可以围绕JOIN建立有效的执行计划,并且如果需要,您也可以添加索引。

使用函数(或任何内联计算值)的缺点是,对于返回的每个潜在行都会发生标注,这很昂贵。为什么?因为SQL必须首先使用计算的值创建完整的数据集,然后将WHERE子句应用于该数据集。

在十分之九的时间中,您不需要在查询中动态计算单元格值。最好弄清楚您将需要什么,然后设计一个支持它的数据模型,并用半动态数据(例如,通过批处理作业)填充该数据模型,并使用SQL Engine通过标准SQL进行繁重的工作。 。


3

是的,这是正确的,视图中不能包含变量(也存在其他限制)。

在可以用select语句替换结果的情况下,可以使用视图。


可以在select语句中替换表函数,并且该表函数具有局部变量。
JeffO's

您是说因为select语句不能包含局部变量,所以视图也不能包含局部变量?
JeffO's

1
@JeffO我说的是“视图中不能有变量”。这不清楚吗?
霍根

这是最后一句话。视图可以替换选择语句,但是这与变量有什么关系?表函数不能代替select语句,但是要包含变量吗?
JeffO

1
表函数也可以用select语句替换,但是表函数不能在视图可以使用的所有地方使用,例如联接。他想说的是,一个视图可以替换一个选择语句,但不能替换多个语句。BEGIN关键字在CREATE VIEW语句以及内联函数中均无效。需要创建一个多语句脚本。过程或多个语句函数可能是执行此操作的最佳方法。
Arlen Beiler

1

我要做的是创建一个执行与表变量相同的选择的视图,并将该视图链接到第二个视图。因此,一个视图可以从另一个视图中进行选择。这样可以达到相同的结果


2
Ben,除非您处理的表很小,否则可能会导致性能问题。
logixologist '16

即使具有非常小的表(3个记录),具有百万条记录的视图也会导致很大的性能问题。
st_stefanov

0

您需要多久刷新一次视图?我也有类似的情况,新数据每月一次。然后我必须加载它,并且在加载过程中必须创建新表。那时,我改变了看法以考虑这些变化。我在其他问题中将信息用作基础:

动态创建视图和同义词

在那里,建议这样做2种方式:

  1. 使用同义词。
  2. 使用动态SQL创建视图(这帮助我实现了结果)。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.