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

これは、MSSQLだけでなくRDBMSでのビューのかなり標準的な動作であり、「select*from」を含むビューの使用を注意して扱う必要がある理由です。

SQLエンジンは、各ビューをコンパイルします。これは、基本的に辞書式/解析ステップであり、その結果を格納します。したがって、基になるテーブルを変更する場合、そのような状況でチェックされるようにデータベースにビューにタグを付ける何らかの方法がない限り、明示的な再コンパイルが常に必要です。

この問題は、ストアドプロシージャや同様のデータベースオブジェクトにも当てはまる可能性があります(今後も当てはまります)。

于 2008-12-05T18:21:02.573 に答える