14

为冗长的帖子道歉,但我需要发布一些代码来说明问题。

受问题启发 *不使用 select 的原因是什么,我决定指出我前一段时间注意到的 select * 行为的一些观察结果。

所以让代码自己说话:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[starTest]') AND type in (N'U'))
DROP TABLE [dbo].[starTest]
CREATE TABLE [dbo].[starTest](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [A] [varchar](50) NULL,
    [B] [varchar](50) NULL,
    [C] [varchar](50) NULL
) ON [PRIMARY]

GO

insert into dbo.starTest(a,b,c)
select 'a1','b1','c1'
union all select 'a2','b2','c2'
union all select 'a3','b3','c3'

go
IF  EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[vStartest]'))
DROP VIEW [dbo].[vStartest]
go
create view dbo.vStartest as
select * from dbo.starTest
go

go
IF  EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[vExplicittest]'))
DROP VIEW [dbo].[vExplicittest]
go
create view dbo.[vExplicittest] as
select a,b,c from dbo.starTest
go


select a,b,c from dbo.vStartest
select a,b,c from dbo.vExplicitTest

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[starTest]') AND type in (N'U'))
DROP TABLE [dbo].[starTest]
CREATE TABLE [dbo].[starTest](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [A] [varchar](50) NULL,
    [B] [varchar](50) NULL,
    [D] [varchar](50) NULL,
    [C] [varchar](50) NULL
) ON [PRIMARY]

GO

insert into dbo.starTest(a,b,d,c)
select 'a1','b1','d1','c1'
union all select 'a2','b2','d2','c2'
union all select 'a3','b3','d3','c3'

select a,b,c from dbo.vExplicittest
select a,b,c from dbo.vStartest

如果您执行以下查询并查看最后 2 个 select 语句的结果,您将看到的结果如下:

select a,b,c from dbo.vExplicittest
a1  b1  c1
a2  b2  c2
a3  b3  c3

select a,b,c from dbo.vStartest
a1  b1  d1
a2  b2  d2
a3  b3  d3

正如您在select a,b,c from dbo.vStartest的结果中看到的那样,c 列的数据已被 d 列的数据替换。

我相信这与视图的编译方式有关,我的理解是列是由列索引 (1,2,3,4) 映射的,而不是名称。

我想我会把它作为警告发布给在他们的 SQL 中使用 select * 并遇到意外行为的人。

注意:如果您在每次修改表后重建使用 select * 的视图,它将按预期工作。

4

2 回答 2

16

sp_refreshview修复视图,或者在视图定义中使用 WITH SCHEMABINDING

如果视图不是使用 SCHEMABINDING 子句创建的,则当对影响视图定义的视图下的对象进行更改时,应运行 sp_refreshview。否则,视图在被查询时可能会产生意想不到的结果。

于 2008-11-27T07:10:02.460 回答
2

这对于任何RDBMS下的视图来说都是非常标准的行为,而不仅仅是 MSSQL,并且必须谨慎对待包含“select * from”的视图的使用的原因。

SQL 引擎将编译每个视图 - 这基本上是字典/解析步骤并存储结果。如果您因此更改基础表,则始终需要显式重新编译,除非数据库具有某种方法来标记视图以在这种情况下进行检查。

该问题也可能(将)也适用于存储过程和类似的数据库对象。

于 2008-12-05T18:21:02.573 回答