【问题标题】:"select * from table" vs "select colA, colB, etc. from table" interesting behaviour in SQL Server 2005SQL Server 2005 中的“从表中选择 *”与“从表中选择 colA、colB 等”的有趣行为
【发布时间】:2010-09-24 04:51:35
【问题描述】:

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

受问题 *What is the reason not to use 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 * 重建视图,它将按预期工作。

【问题讨论】:

  • 我不明白,示例代码中的任何地方都没有 D 列。
  • @Hogan 你需要向下滚动代码示例,表 startTest 被删除并再次创建,这次有 4 列:A、B、D、C
  • 谢谢,不知道我怎么错过了。
  • 很好的信息,但我认为这应该放在“社区维基”中,因为这不是一个问题。

标签: sql sql-server sql-server-2005 tsql views


【解决方案1】:

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

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

【讨论】:

  • 好点。我总是使用不允许这样做的SCHEMABINDING
【解决方案2】:

这对于 any RDBMS 下的视图来说是相当标准的行为,而不仅仅是 MSSQL,因此必须谨慎对待包含“select * from”的视图的使用。

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

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

【讨论】:

    猜你喜欢
    • 2016-05-06
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多