CREATE VIEW (Transact-SQL)

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例Azure Synapse AnalyticsAnalytics Platform System (PDW)Microsoft Fabric 中的 SQL 终结点Microsoft Fabric 中的仓库Microsoft Fabric SQL 数据库

创建虚拟表,其内容(列和行)由查询定义。 使用此语句可以创建数据库中一个或多个表中数据的视图。 例如,可以将视图用于以下用途:

  • 集中、简化和自定义每个用户对数据库的认识。

  • 用作安全机制,方法是允许用户通过视图访问数据,而不授予用户直接访问底层基表的权限。

  • 提供向后兼容接口来模拟架构已更改的表。

Transact-SQL 语法约定

语法

SQL Server 和 Azure SQL 数据库 的语法。

CREATE [ OR ALTER ] VIEW [ schema_name . ] view_name [ (column [ ,...n ] ) ]
[ WITH <view_attribute> [ ,...n ] ]
AS select_statement
[ WITH CHECK OPTION ]
[ ; ]  

<view_attribute> ::=
{  
    [ ENCRYPTION ]  
    [ SCHEMABINDING ]  
    [ VIEW_METADATA ]
}

Azure Synapse Analytics 和并行数据仓库的语法。

CREATE VIEW [ schema_name . ] view_name [  ( column_name [ ,...n ] ) ]   
AS <select_statement>   
[;]  

<select_statement> ::=  
    [ WITH <common_table_expression> [ ,...n ] ]  
    SELECT <select_criteria>  

Microsoft Fabric 数据仓库和 SQL 分析终结点的语法。

CREATE [ OR ALTER ] VIEW [ schema_name . ] view_name [  ( column_name [ ,...n ] ) ]   
[ WITH <view_attribute> [ ,...n ] ] AS <select_statement>   
[;]

<view_attribute> ::=
{  
    [ SCHEMABINDING ]  
}

<select_statement> ::=  
    [ WITH <common_table_expression> [ ,...n ] ]  
    SELECT <select_criteria>  

参数

或 ALTER

适用范围:Azure SQL 数据库、SQL Server(从 SQL Server 2016 (13.x) SP1 开始)。

有条件地删除视图(仅当其已存在时)。

schema_name
视图所属架构的名称。

view_name
视图名称。 视图名称必须符合有关标识符的规则。 可以选择是否指定视图所有者名称。


视图中的列使用的名称。 仅当列派生自算术表达式、函数或常量时,才需要列名;如果两列或更多列的名称可能相同,通常是因为联接;或指定视图中的列的名称与派生该列的名称不同。 还可以在 SELECT 语句中分配列名。

如果未指定 ,视图列将获取与语句中的 SELECT 列相同的名称。

注意

在视图的列中,无论基础数据的源如何,列名称的权限都会应用于 CREATE VIEWALTER VIEW 语句中。 例如,如果对 CREATE VIEW 语句中的列授予 SalesOrderID 权限,则 ALTER VIEW 语句可以命名 SalesOrderID 具有其他列名称的列,例如 OrderRef,仍具有与视图 SalesOrderID关联的权限。

指定视图要执行的操作。

select_statement

SELECT定义视图的语句。 该语句可以使用多个表和其他视图。 需要适当的权限才能从所创建的视图子句中 SELECT 引用的对象中进行选择。

视图不必是一个特定表的行和列的子集。 可以创建一个视图,该视图使用具有任何复杂性的子句的多个表或其他视图 SELECT

在索引视图定义中, SELECT 该语句必须是单个表语句或具有可选聚合的多表 JOIN 语句。

SELECT视图定义中的子句不能包括:

  • 一个ORDER BY子句,除非语句的 TOP select 列表中也有一个SELECT子句

    重要

    ORDER BY句仅用于确定视图定义中或TOP子句返回OFFSET的行。 ORDER BY除非在查询本身中也指定了该子句,否则ORDER BY子句不能保证查询时的有序结果。

  • INTO 关键字

  • OPTION

  • 引用临时表或表变量。

由于 select_statement 使用 SELECT 语句,因此使用子句中指定的 FROM 联接提示和表提示是有效的。 有关详细信息,请参阅 FROM (Transact-SQL)SELECT (Transact-SQL)

函数和多个SELECT语句通过select_statement分隔UNIONUNION ALL可用于

CHECK OPTION

要求对该视图执行的所有数据修改语句都必须符合 select_statement 中所设置的条件。 通过视图修改行时, WITH CHECK OPTION 请确保在提交修改后通过视图保持可见数据。

注意

CHECK OPTION仅适用于通过视图进行的更新。 它不适用于直接对视图的基础表执行的任何更新。

加密

适用于:SQL Server 2008 (10.0.x) 及更高版本和 Azure SQL 数据库。

加密包含语句文本CREATE VIEW 中的条目。 使用 WITH ENCRYPTION 可防止视图作为 SQL Server 复制的一部分发布。

SCHEMABINDING

将视图绑定到基础表的架构。 指定时 SCHEMABINDING ,不能以影响视图定义的方式修改基表或表。 必须首先修改或删除视图定义本身,才能删除将要修改的表的依赖关系。 使用 SCHEMABINDING时, select_statement 必须包含两部分名称(架构)。object)引用的表、视图或用户定义的函数。 所有被引用对象都必须在同一个数据库内。

不能删除参与了使用 SCHEMABINDING 子句创建的视图的视图或表,除非该视图已被删除或更改而不再具有架构绑定。 否则,数据库引擎将引发错误。 此外,当这些语句影响视图定义时,对参与具有架构绑定的视图的表执行 ALTER TABLE 语句会失败。

VIEW_METADATA

指定为引用视图的查询请求浏览模式的元数据时,SQL Server 实例将向 DB-Library、ODBC 和 OLE DB API 返回有关视图的元数据信息,而不返回基表的元数据信息。 浏览模式元数据是 SQL Server 实例向这些客户端 API 返回的附加元数据。 如果使用此元数据,客户端 API 将可以实现可更新客户端游标。 浏览模式的元数据包含结果集中的列所属的基表的相关信息。

对于使用 VIEW_METADATA 创建的视图,浏览模式元数据在描述结果集中视图中的列时返回视图名称,而不是基表名称。

使用WITH VIEW_METADATA视图创建时,如果视图具有INSTEAD OF INSERT触发器,则其所有列(INSTEAD OF UPDATE列除外)都可以更新。 有关可更新视图的详细信息,请参阅“备注”。

备注

只能在当前数据库中创建视图。 必须是 CREATE VIEW 查询批处理中的第一个语句。 视图最多可以包含 1,024 列。

通过视图进行查询时,数据库引擎将进行检查以确保语句中任何位置被引用所有数据库对象都存在,这些对象在语句的上下文中有效,以及数据修改语句没有违反任何数据完整性规则。 如果检查失败,将返回错误消息。 如果检查成功,则将操作转换为对基础表的操作。

如果某个视图依赖于已删除的表(或视图),则当有人试图使用该视图时,数据库引擎将产生错误消息。 如果创建了新表或视图(该表的结构与以前的基表没有不同之处)以替换删除的表或视图,则视图将再次可用。 如果新表或视图的结构发生更改,则必须删除并重新创建该视图。

如果未使用 SCHEMABINDING 子句创建视图,则当对影响视图定义的视图基础的对象进行更改时, 请运行sp_refreshview 。 否则,当查询视图时,可能会生成意外结果。

创建视图时,有关该视图的信息将存储在下列目录视图中:sys.viewssys.columnssys.sql_expression_dependencies。 语句的文本 CREATE VIEW 存储在 sys.sql_modules 目录视图中。

对使用 数值浮点 表达式定义的视图使用索引的查询的结果可能与不使用视图索引的类似查询不同。 此差异可能是在基础表上INSERTDELETE舍入错误或UPDATE作造成的。

数据库引擎保存 SET QUOTED_IDENTIFIER 创建视图时的设置 SET ANSI_NULLS 。 使用视图时,将使用这些原始设置来分析视图。 因此,访问视图时,任何 SET QUOTED_IDENTIFIER 客户端会话设置都 SET ANSI_NULLS 不会影响视图定义。

在 Azure Synapse Analytics 中,视图不支持架构绑定。 因此,如果对基础对象进行了更改,则应删除并重新创建视图以刷新基础元数据。 有关详细信息,请参阅 Azure Synapse Analytics 中具有专用 SQL 池和无服务器 SQL 池的 T-SQL 视图

在 Azure Synapse Analytics 中,不支持可更新视图、DML 触发器(类型或AFTER),INSTEAD OF不支持分区视图。 有关详细信息,请参阅 Azure Synapse Analytics 中具有专用 SQL 池和无服务器 SQL 池的 T-SQL 视图

在 Azure Synapse Analytics 中,不支持分区视图。 有关详细信息,请参阅 Azure Synapse Analytics 中具有专用 SQL 池和无服务器 SQL 池的 T-SQL 视图

在 Fabric SQL 数据库中,可以创建视图,但它们不会 镜像到 Fabric OneLake 中。 有关详细信息,请参阅 Fabric SQL 数据库镜像的限制。

可更新视图

只要满足下列条件,即可通过视图修改基础基表的数据:

  • 任何修改(包括UPDATEINSERTDELETE语句)都必须仅引用一个基表中的列。

  • 视图中被修改的列必须直接引用表列中的基础数据。 不能通过任何其他方式对这些列进行派生,如通过以下方式:

    • 聚合函数:AVG、、COUNTSUMMINMAXGROUPINGSTDEVSTDEVP、和。 VARVARP

    • 计算。 不能从使用其他列的表达式中计算该列。 使用集合运算符 UNION、UNION ALL、CROSSJOIN、EXCEPT 和 INTERSECT 形成的列将计入计算结果,且不可更新。

  • 所修改的列不受或GROUP BYHAVING子句的影响DISTINCT

  • 在视图 select_statement 与子句一起 WITH CHECK OPTION 在任意位置不使用 TOP。

上述限制应用于视图的 FROM 子句中的任何子查询,就像其应用于视图本身一样。 通常情况下,数据库引擎必须能够明确跟踪从视图定义到一个基表的修改。 有关详细信息,请参阅通过视图修改数据

如果上述限制妨碍直接通过视图修改数据,则可以考虑以下选项:

  • INSTEAD OF 触发器

    INSTEAD OF 可以在视图上创建触发器,以使视图可更新。 将 INSTEAD OF 执行触发器,而不是定义触发器的数据修改语句。 此触发器允许用户指定必须发生以处理数据修改语句的操作集合。 因此,如果INSTEAD OF特定数据修改语句(INSERTUPDATEDELETE)上的视图存在触发器,则可以通过该语句更新相应的视图。 有关触发器的详细信息 INSTEAD OF ,请参阅 DML 触发器

  • 分区视图

    如果视图为分区视图,则可遵循某些限制对其进行更新。 必要时,数据库引擎将本地分区视图辨别为所有参与表和视图都在同一 SQL Server 实例上的视图,而将分布式分区视图辨别为视图中至少有一个表驻留在其他或远程服务器上的视图。

分区视图

分区视图是由以 UNION ALL 相同方式构建的成员表定义的视图,但单独存储为同一 SQL Server 实例或 SQL Server 服务器的一组自治实例(称为联合数据库服务器)中的多个表。

注意

对一个服务器的本地数据进行分区的首选方法是通过分区表。 有关详细信息,请参阅 Partitioned Tables and Indexes

设计分区方案时,必须清楚哪些数据属于每个分区。 例如,Customers 表的数据分布在三个服务器位置的三个成员表中:Customers_33 上的 Server1Customers_66 上的 Server2Customers_99 上的 Server3

Server1 的分区视图通过以下方式进行定义:

--Partitioned view as defined on Server1  
CREATE VIEW Customers  
AS  
--Select from local member table.  
SELECT *  
FROM CompanyData.dbo.Customers_33  
UNION ALL  
--Select from member table on Server2.  
SELECT *  
FROM Server2.CompanyData.dbo.Customers_66  
UNION ALL  
--Select from member table on Server3.  
SELECT *  
FROM Server3.CompanyData.dbo.Customers_99;  

一般情况下,如果视图为下列格式,则称其为分区视图:

SELECT <select_list1>  
FROM T1  
UNION ALL  
SELECT <select_list2>  
FROM T2  
UNION ALL  
...  
SELECT <select_listn>  
FROM Tn;  

创建分区视图的条件

  1. 选择 list

    • 在视图定义的列列表中,选择成员表中的所有列。

    • 确保每个 select list 中的同一序号位置上的列属于同一类型,包括排序规则。 列不能隐式转换为可转换类型,这通常就是这样 UNION

      此外,至少有一列(例如 <col>)必须按照相同的序号位置显示在所有选择列表中。 按照以下方式定义 <col>:成员表 T1, ..., Tn 分别在 C1, ..., Cn 上定义 CHECK 约束 <col>

      在表 C1 上定义的约束 T1 必须是以下格式:

      C1 ::= < simple_interval > [ OR < simple_interval > OR ...]  
      < simple_interval > :: =   
      < col > { < | > | \<= | >= | = < value >}   
      | < col > BETWEEN < value1 > AND < value2 >  
      | < col > IN ( value_list )  
      | < col > { > | >= } < value1 > AND  
      < col > { < | <= } < value2 >  
      
    • 约束必须按照以下方式定义:<col> 的任何指定值最多只能满足一个 C1, ..., Cn 约束,从而使约束形成一组不联接或不重叠的间隔。 定义不联接的约束的列 <col> 称为分区列。 分区列可以在基础表中具有不同的名称。 约束必须处于启用和信任状态,以使它们满足分区依据列的上述条件。 如果禁用了约束,请使用选项CHECK CONSTRAINT *constraint_name*重新启用约束检查ALTER TABLE,并使用WITH CHECK该选项来验证它们。

      以下示例显示有效的约束集合:

      { [col < 10], [col between 11 and 20] , [col > 20] }  
      { [col between 11 and 20], [col between 21 and 30], [col between 31 and 100] }  
      
    • 在选择列表中不能多次使用同一列。

  2. 分区列

    • 分区列是表的 PRIMARY KEY 的一部分。

    • 分区列不能是计算列、标识列、默认列或 timestamp 列。

    • 如果成员表中的同一列上存在多个约束,则数据库引擎将忽略所有约束,且在确定视图是否为分区视图时不考虑这些约束。 若要满足分区视图的条件,确保在分区依据列上只有一个分区约束。

    • 分区列的可更新性没有限制。

  3. 成员表或基础表 T1, ..., Tn

    • 表可以是本地表,也可以是通过由四部分组成的名称或基于 OPENDATASOURCE 或 OPENROWSET 的名称引用的运行 SQL Server 的其他计算机中的表。 OPENDATASOURCE 和 OPENROWSET 语法可以指定表名,但不能指定直接传递查询。 有关详细信息,请参阅 OPENDATASOURCE (Transact-SQL)OPENROWSET (Transact-SQL)

      如果一个或多个成员表是远程表,则视图将被称为“分布式分区视图”,并且将应用附加条件。 本部分后面将对其进行说明。

    • 同一个表不能在与 UNION ALL 语句组合的表中出现两次。

    • 成员表不能对表中的计算列创建索引。

    • 成员表在编号相同的列上具有所有 PRIMARY KEY 约束。

    • 视图中的所有成员表都具有相同的 ANSI 填充设置。 这可以通过使用 用户选项 选项或 sp_configure SET 语句进行设置。

修改分区视图中数据的条件

下面的限制适用于在分区视图中修改数据的语句:

  • INSERT 语句为视图中的所有列提供值,即使基础成员表对这些列有 DEFAULT 约束,或者它们是否允许 NULL 值。 对于具有 DEFAULT 定义的成员表列,语句不能显式使用关键字 DEFAULT

  • 要插入分区列的值满足至少一个基础约束;否则,插入作将失败并出现约束冲突。

  • UPDATE 语句不能将 DEFAULT 关键字指定为子句中的 SET 值,即使列在相应的成员表中定义了值 DEFAULT 也是如此。

  • 不能使用 INSERTUPDATE 语句修改视图中作为一个或多个成员表中标识列的列。

  • 如果其中一个成员表包含 时间戳 列,则无法使用 INSERTUPDATE 语句修改数据。

  • 如果其中一个成员表包含触发器或ON UPDATE CASCADE/SET NULL/SET DEFAULTON DELETE CASCADE/SET NULL/SET DEFAULT约束,则无法修改视图。

  • INSERT UPDATE DELETE如果存在具有同一视图或语句中任何成员表的自联接,则不允许对分区视图执行作。

  • 不支持将数据批量导入分区视图bcpBULK INSERTINSERT ... SELECT * FROM OPENROWSET(BULK...)语句。 但是,可以使用 INSERT 语句在分区视图中插入多行。

    注意

    若要更新分区视图,用户必须具有INSERTUPDATE成员表的权限和DELETE权限。

分布式分区视图的其他条件

对于分布式分区视图(其中有一个或多个成员表为远程表),适用下列附加条件:

  • 启动分布式事务,以确保所有受更新影响的节点的原子性。

  • XACT_ABORT SET选项设置为“工作”ONINSERTUPDATEDELETE“语句”。

  • 在分区视图中引用的远程表的所有 smallmoney 类型的列都将映射为 money 。 因此,本地表中相应的列(在选择列表中的相同序号位置中)必须也为 money 类型。

  • 数据库兼容级别为 110 和更高级别时,在分区视图中引用的远程表的所有 smalldatetime 类型的列都将映射为 smalldatetime 。 本地表中相应的列(在选择列表中的相同序号位置中)必须为 smalldatetime。 这是对早期版本的 SQL Server 的行为的更改,在早期版本中,在分区视图中引用的远程表的所有 smalldatetime 类型的列都将映射为 datetime,并且本地表中相应的列必须为 datetime 类型 。 有关详细信息,请参阅 ALTER DATABASE 兼容性级别 (Transact-SQL)

  • 分区视图中的所有链接服务器都不能是环回链接服务器。 这是一个指向同一个 SQL Server 实例的链接服务器。

对于涉及SET ROWCOUNTINSERT可更新分区视图和远程表的作,将忽略UPDATE该选项的设置DELETE

设置了成员表和分区视图的定义后,SQL Server 查询优化器将生成智能计划,从而有效利用查询访问成员表中的数据。 CHECK使用约束定义时,查询处理器会映射成员表中键值的分布。 当用户发出查询时,查询处理器会将映射与子句中指定的 WHERE 值进行比较,并生成一个执行计划,并在成员服务器之间传输最少的数据传输量。 因此,如果某些成员表位于远程服务器中,SQL Server 实例将解析分布式查询,以便必须传输的分布式数据量最小。

复制注意事项

若要对复制所涉及的成员表创建分区视图,需要考虑下列事项:

  • 如果基础表涉及到包含更新订阅的合并复制或事务复制,请确保 uniqueidentifier 列也包含在选择列表中。

    分区视图中的任何INSERT作都必须为 NEWID() 列提供值。 针对 uniqueidentifier 列的任何 UPDATE作都必须作为值提供 NEWID() ,因为不能使用 DEFAULT 关键字。

  • 通过视图进行的更新复制与在两个不同的数据库中复制表时相同:表由不同的复制代理进行处理,因此不能保证更新的顺序。

权限

要求在数据库中具有 CREATE VIEW 权限,并具有在其中创建视图的架构的 ALTER 权限。

示例

以下示例使用 AdventureWorks2022AdventureWorksDW2022 数据库。

答: 使用 CREATE VIEW 创建视图

以下示例使用 SELECT 语句创建视图。 当需要频繁地查询列的某种组合时,简单视图非常有用。 此视图的数据来自 AdventureWorks2022 数据库的 HumanResources.EmployeePerson.Person 表。 这些数据提供有关 Adventure Works Cycles 的雇员的姓名和雇用日期信息。 对于负责跟踪工作年限的人员,可创建此视图,但是不能授予此人访问这些表中的所有数据的权限。

CREATE VIEW hiredate_view  
AS
SELECT p.FirstName, p.LastName, e.BusinessEntityID, e.HireDate  
FROM HumanResources.Employee AS e   
JOIN Person.Person AS p ON e.BusinessEntityID = p.BusinessEntityID ;  
GO  

B. 使用 WITH ENCRYPTION

以下示例使用 WITH ENCRYPTION 选项,并显示计算列、重命名列以及多个列。

适用于:SQL Server 2008 (10.0.x) 及更高版本和 SQL 数据库。

CREATE VIEW Purchasing.PurchaseOrderReject  
WITH ENCRYPTION  
AS  
SELECT PurchaseOrderID, ReceivedQty, RejectedQty,   
    RejectedQty / ReceivedQty AS RejectRatio, DueDate  
FROM Purchasing.PurchaseOrderDetail  
WHERE RejectedQty / ReceivedQty > 0  
AND DueDate > CONVERT(DATETIME,'20010630',101) ;  
GO  

C. 使用 WITH CHECK OPTION

以下示例显示名为 dbo.SeattleOnly 的视图,此视图引用了五个表,并允许进行数据修改,以便仅适用于居住在西雅图的雇员。

CREATE VIEW dbo.SeattleOnly  
AS  
SELECT p.LastName, p.FirstName, e.JobTitle, a.City, sp.StateProvinceCode  
FROM HumanResources.Employee e  
INNER JOIN Person.Person p  
ON p.BusinessEntityID = e.BusinessEntityID  
    INNER JOIN Person.BusinessEntityAddress bea   
    ON bea.BusinessEntityID = e.BusinessEntityID   
    INNER JOIN Person.Address a   
    ON a.AddressID = bea.AddressID  
    INNER JOIN Person.StateProvince sp   
    ON sp.StateProvinceID = a.StateProvinceID  
WHERE a.City = 'Seattle'  
WITH CHECK OPTION ;  
GO  

D. 在视图中使用内置函数

以下示例显示包含内置函数的视图定义。 使用函数时,必须为派生列指定一个列名。

CREATE VIEW Sales.SalesPersonPerform  
AS  
SELECT TOP (100) SalesPersonID, SUM(TotalDue) AS TotalSales  
FROM Sales.SalesOrderHeader  
WHERE OrderDate > CONVERT(DATETIME,'20001231',101)  
GROUP BY SalesPersonID;  
GO  

E. 使用分区数据

以下示例将使用名称分别为 SUPPLY1SUPPLY2SUPPLY3SUPPLY4 的表。 这些表对应于位于不同区域的四个办事处的供应商表。

--Create the tables and insert the values.  
CREATE TABLE dbo.SUPPLY1 (  
supplyID INT PRIMARY KEY CHECK (supplyID BETWEEN 1 and 150),  
supplier CHAR(50)  
);  
CREATE TABLE dbo.SUPPLY2 (  
supplyID INT PRIMARY KEY CHECK (supplyID BETWEEN 151 and 300),  
supplier CHAR(50)  
);  
CREATE TABLE dbo.SUPPLY3 (  
supplyID INT PRIMARY KEY CHECK (supplyID BETWEEN 301 and 450),  
supplier CHAR(50)  
);  
CREATE TABLE dbo.SUPPLY4 (  
supplyID INT PRIMARY KEY CHECK (supplyID BETWEEN 451 and 600),  
supplier CHAR(50)  
);  
GO  
--Create the view that combines all supplier tables.  
CREATE VIEW dbo.all_supplier_view  
WITH SCHEMABINDING  
AS  
SELECT supplyID, supplier  
  FROM dbo.SUPPLY1  
UNION ALL  
SELECT supplyID, supplier  
  FROM dbo.SUPPLY2  
UNION ALL  
SELECT supplyID, supplier  
  FROM dbo.SUPPLY3  
UNION ALL  
SELECT supplyID, supplier  
  FROM dbo.SUPPLY4;  
GO
INSERT dbo.all_supplier_view VALUES ('1', 'CaliforniaCorp'), ('5', 'BraziliaLtd')    
, ('231', 'FarEast'), ('280', 'NZ')  
, ('321', 'EuroGroup'), ('442', 'UKArchip')  
, ('475', 'India'), ('521', 'Afrique');  
GO  

示例:Azure Synapse Analytics 和 Analytics Platform System (PDW)

F. 通过联接两个表来创建视图

以下示例通过搭配使用 SELECT 语句和 OUTER JOIN 来创建视图。 联接查询的结果将会填充视图。

CREATE VIEW view1  
AS 
SELECT fis.CustomerKey, fis.ProductKey, fis.OrderDateKey, 
  fis.SalesTerritoryKey, dst.SalesTerritoryRegion  
FROM FactInternetSales AS fis   
LEFT OUTER JOIN DimSalesTerritory AS dst   
ON (fis.SalesTerritoryKey=dst.SalesTerritoryKey);