"выбрать * из таблицы" против "выбрать colA, colB и т. д. из таблицы" интересное поведение в SQL Server 2005 - PullRequest
14 голосов
/ 26 ноября 2008

Извиняюсь за длинное сообщение, но мне нужно было опубликовать некоторый код, чтобы проиллюстрировать проблему.

Вдохновленный вопросом * В чем причина не использовать 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 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

Как вы можете видеть в результатах выберите a, b, c из dbo.vStartest данные столбца c были заменены данными из столбца d.

Я полагаю, что это связано с тем, как компилируются представления. Насколько я понимаю, столбцы отображаются по индексам столбцов (1,2,3,4), а не по именам.

Я думал, что опубликую это как предупреждение для людей, использующих select * в своем SQL и испытывающих неожиданное поведение.

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

Ответы [ 2 ]

16 голосов
/ 27 ноября 2008

sp_refreshview , чтобы исправить представление, или использовать WITH SCHEMABINDING в определении представления

Если представление не создано с Предложение SCHEMABINDING, sp_refreshview должен быть запущен при внесении изменений в объекты, лежащие в основе представления о том, что влияет на определение зрения. В противном случае представление может привести к неожиданные результаты при запросе.

2 голосов
/ 05 декабря 2008

Это довольно стандартное поведение для представлений в любой СУБД, а не только в MSSQL, и причину, по которой к использованию представлений, содержащих "select * from", следует относиться с осторожностью.

SQL Engine скомпилирует каждое представление - это в основном лексикографический / синтаксический анализ и сохранит результат этого. Если вы, следовательно, измените базовые таблицы, то всегда требуется явная перекомпиляция, если только в базе данных нет какого-либо метода тегирования представления, чтобы его можно было проверить в таких обстоятельствах.

Эта проблема может (будет) также применяться к хранимым процедурам и аналогичным объектам базы данных.

...