2008-11-26 23 views
14

Xin lỗi cho một bài đăng dài, nhưng tôi cần đăng một số mã để minh họa sự cố."chọn * từ bảng" vs "chọn colA, colB, v.v ... từ bảng" hành vi thú vị trong SQL Server 2005

Lấy cảm hứng từ câu hỏi * What is the reason not to use select ?, tôi quyết định chỉ ra một số quan sát về hành vi chọn * mà tôi đã nhận thấy một số thời gian trước đây.

Vì vậy, hãy là mã nói cho chính nó:

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 

Nếu bạn thực hiện các truy vấn sau đây và nhìn vào kết quả của 2 câu chọn cuối cùng, kết quả mà bạn sẽ thấy sẽ là như sau:

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 

Như bạn có thể thấy trong kết quả của chọn a, b, c từ dbo.vStartest dữ liệu của cột c đã được thay thế bằng dữ liệu từ cột d.

Tôi tin rằng đó là liên quan đến cách chế độ xem được biên soạn, sự hiểu biết của tôi là các cột được ánh xạ theo chỉ mục cột (1,2,3,4) thay vì tên.

Tôi nghĩ tôi sẽ đăng nó như một cảnh báo cho những người sử dụng lựa chọn * trong SQL của họ và gặp phải hành vi không mong muốn.

Lưu ý: Nếu bạn xây dựng lại chế độ xem sử dụng chọn * mỗi lần sau khi bạn sửa đổi bảng, nó sẽ hoạt động như mong đợi.

+1

Tôi không hiểu, không có cột D ở bất kỳ đâu trong mã ví dụ. – Hogan

+1

@ Bạn cần cuộn xuống ví dụ mã, bảng starTest bị thả và tạo lại lần nữa, lần này với 4 cột: A, B, D, C – kristof

+0

cảm ơn, không biết làm thế nào tôi bỏ lỡ điều đó. – Hogan

Trả lời

15

sp_refreshview để sửa chữa quan điểm, hoặc sử dụng VỚI SCHEMABINDING trong định nghĩa khung nhìn

Nếu một cái nhìn không được tạo ra với mệnh đề SCHEMABINDING, sp_refreshview nên được chạy khi thay đổi được thực hiện để các đối tượng cơ bản chế độ xem ảnh hưởng đến định nghĩa của chế độ xem. Nếu không, chế độ xem có thể tạo ra các kết quả không mong muốn khi được truy vấn .

+0

Tôi sẽ thêm, không sử dụng SELECT * trong mã sản xuất – kristof

+0

Điểm tốt. Tôi luôn sử dụng SCHEMABINDING mà không cho phép điều này – gbn

2

này được hành vi khá chuẩn cho quan điểm dưới bất kỳ RDBMS, không chỉ MSSQL, và lý do tại sao việc sử dụng các quan điểm bao gồm "select * from" phải được xử lý một cách thận trọng.

Công cụ SQL sẽ biên dịch từng chế độ xem - về cơ bản là các bước từ điển/phân tích cú pháp và lưu trữ kết quả đó. Do đó, nếu bạn thay đổi các bảng cơ bản thì việc biên dịch lại rõ ràng luôn được yêu cầu trừ khi cơ sở dữ liệu có một phương pháp gắn thẻ khung nhìn để được kiểm tra trong các trường hợp như vậy.

Vấn đề có thể (cũng) cũng áp dụng cho các thủ tục được lưu trữ và các đối tượng cơ sở dữ liệu tương tự.

Các vấn đề liên quan