THIẾT LẬP so với CHỌN khi gán biến?


Câu trả lời:


411

Trích dẫn , tóm tắt từ bài viết này :

  1. SET là tiêu chuẩn ANSI cho phép gán biến, CHỌN thì không.
  2. SET chỉ có thể gán một biến tại một thời điểm, CHỌN có thể thực hiện nhiều phép gán cùng một lúc.
  3. Nếu gán từ truy vấn, SET chỉ có thể gán giá trị vô hướng. Nếu truy vấn trả về nhiều giá trị / hàng thì SET sẽ phát sinh lỗi. SELECT sẽ chỉ định một trong các giá trị cho biến và ẩn thực tế là nhiều giá trị được trả về (vì vậy bạn có thể không bao giờ biết tại sao có sự cố xảy ra ở nơi khác - hãy khắc phục sự cố đó)
  4. Khi gán từ truy vấn nếu không có giá trị nào được trả về thì SET sẽ gán NULL, trong đó SELECT sẽ không thực hiện phép gán nào cả (vì vậy biến sẽ không bị thay đổi so với giá trị trước đó)
  5. Về sự khác biệt về tốc độ - không có sự khác biệt trực tiếp giữa SET và SELECT. Tuy nhiên, khả năng thực hiện nhiều nhiệm vụ của CHỌN trong một lần chụp sẽ giúp nó có lợi thế về tốc độ so với SET.

3
Tôi đã không downvote, nhưng những điều sau đây không hoàn toàn chính xác: "Về sự khác biệt về tốc độ - không có sự khác biệt trực tiếp giữa SET và SELECT". Nếu bạn gán nhiều giá trị trong một lát, điều đó có thể nhanh hơn nhiều thông qua các bộ maultipl. Google lên "Gán nhiều biến với một CHỌN hoạt động nhanh hơn"
AK

14
@AlexKuznetsov: Câu sau đó nói chính xác điều đó.
Ngựa vằn OMG

3
@OMG Ponies: Nó có thể nhanh hơn 10 lần hoặc hơn, vì vậy tôi không chắc đó có phải là "lợi thế tốc độ nhẹ" hay không.
AK

2
Đặc biệt là khi sử dụng Vòng lặp While, tôi đã thấy hiệu suất HUGE tăng bằng cách đặt / khởi tạo lại tất cả các biến của mình bằng cách sử dụng một-chọn so với nhiều-Set. Tôi cũng có thể hợp nhất Biến logic của mình trong Chọn để tất cả chạy cùng một lúc: Ví dụ : SELECT @Int = @Int + 1, @Int = @Int + 1, nếu @Intbắt đầu bằng 0, thì kết thúc là 2. Điều này có thể rất hữu ích khi thực hiện các thao tác chuỗi liên tiếp.
MikeTeeVee

Thảo luận thú vị về sự khác biệt hiệu suất. Nếu việc đặt nhiều giá trị qua select nhanh hơn (để mã và thực thi) thì một cách không an toàn để tránh điểm 4 (giá trị biến của bạn không thay đổi nếu truy vấn trả về null) là đặt rõ ràng biến của bạn thành null trước khi chọn. Một khi bạn tính đến điều đó, làm thế nào để hai so sánh về hiệu suất? (Lưu ý bên lề: Tôi không hiểu lý do căn bản khi chọn không đặt biến của bạn thành null trong trường hợp truy vấn trả về null. Khi nào bạn muốn điều đó?)
youcantryreachingme

155

Tôi tin SETlà tiêu chuẩn ANSI trong khi SELECTkhông. Cũng lưu ý hành vi khác nhau của SETso với SELECTtrong ví dụ dưới đây khi không tìm thấy giá trị.

declare @var varchar(20)
set @var = 'Joe'
set @var = (select name from master.sys.tables where name = 'qwerty')
select @var /* @var is now NULL */

set @var = 'Joe'
select @var = name from master.sys.tables where name = 'qwerty'
select @var /* @var is still equal to 'Joe' */

4
+1 Tốt hơn là bạn nên chạy một lần để hiểu, kiểm tra, chơi, ghi nhớ rằng chỉ cần đọc nhưng các câu trả lời khác chỉ là văn bản
Gennady Vanin Геннадий Внаин

4
Nếu bạn thực sự sử dụng, select @var = (select name from master.sys.tables where name = 'qwerty')bạn sẽ nhận được @var là null. Ví dụ bạn đang đưa ra không phải là cùng một truy vấn.
Zack

4
Bạn có (select name from master.sys.tables where name = 'qwerty')cho một, và name from master.sys.tables where name = 'qwerty'cho người khác ... bạn không thấy điều đó?
Zack

4
@Zack: Mỗi là cú pháp chính xác cho những gì tôi đang cố gắng để demo; sự khác biệt giữa việc sử dụng SET so với SELECT để gán giá trị cho biến khi truy vấn cơ bản không trả về kết quả.
Joe Stefanelli

5
(select name from master.sys.tables where name = 'qwerty')là một truy vấn vô hướng, và name from master.sys.tables where name = 'qwerty'là một truy vấn đơn giản. Hai biểu thức khác nhau không được cho là tạo ra cùng một kết quả, mặc dù có vẻ như bạn đang ám chỉ rằng chúng nên. Nếu bạn đang cố gắng nói SETSELECTcác từ khóa có cách triển khai khác nhau, bạn không nên sử dụng hai biểu thức khác nhau trong các ví dụ của mình. msdn.microsoft.com/en-us/l Library / ms187330.aspx
Zack

27

Khi viết truy vấn, sự khác biệt này cần được ghi nhớ:

DECLARE @A INT = 2

SELECT  @A = TBL.A
FROM    ( SELECT 1 A ) TBL
WHERE   1 = 2

SELECT  @A
/* @A is 2*/

---------------------------------------------------------------

DECLARE @A INT = 2

SET @A = ( 
            SELECT  TBL.A
            FROM    ( SELECT 1 A) TBL
            WHERE   1 = 2
         )

SELECT  @A
/* @A is null*/

rất đẹp, cô đọng
SimplyInk

8

Ngoài một trong số đó là ANSI và tốc độ, vv, có một sự khác biệt rất quan trọng luôn luôn quan trọng với tôi; nhiều hơn ANSI và tốc độ. Số lượng lỗi tôi đã sửa do bỏ qua quan trọng này là lớn. Tôi tìm kiếm điều này trong quá trình đánh giá mã mọi lúc.

-- Arrange
create table Employee (EmployeeId int);
insert into dbo.Employee values (1);
insert into dbo.Employee values (2);
insert into dbo.Employee values (3);

-- Act
declare @employeeId int;
select @employeeId = e.EmployeeId from dbo.Employee e;

-- Assert
-- This will print 3, the last EmployeeId from the query (an arbitrary value)
-- Almost always, this is not what the developer was intending. 
print @employeeId; 

Hầu như luôn luôn, đó không phải là những gì nhà phát triển đang có ý định. Ở trên, truy vấn là thẳng về phía trước nhưng tôi đã thấy các truy vấn khá phức tạp và tìm hiểu xem liệu nó có trả về một giá trị duy nhất hay không, không phải là nhỏ. Truy vấn thường phức tạp hơn thế này và tình cờ nó đã trả về một giá trị duy nhất. Trong quá trình kiểm tra nhà phát triển tất cả đều ổn. Nhưng điều này giống như một quả bom đánh dấu và sẽ gây ra vấn đề khi truy vấn trả về nhiều kết quả. Tại sao? Bởi vì nó chỉ đơn giản sẽ gán giá trị cuối cùng cho biến.

Bây giờ chúng ta hãy thử điều tương tự với SET:

 -- Act
 set @employeeId = (select e.EmployeeId from dbo.Employee e);

Bạn sẽ nhận được một lỗi:

Truy vấn con trả về hơn 1 giá trị. Điều này không được phép khi truy vấn con theo sau = ,! =, <, <=,>,> = Hoặc khi truy vấn phụ được sử dụng làm biểu thức.

Điều đó thật tuyệt vời và rất quan trọng bởi vì tại sao bạn muốn gán một số "mục cuối cùng trong tầm thường" tầm thường cho @employeeId. Với selectbạn sẽ không bao giờ nhận được bất kỳ lỗi nào và bạn sẽ dành vài phút, hàng giờ để gỡ lỗi.

Có lẽ, bạn đang tìm kiếm một Id duy nhất và SETsẽ buộc bạn phải sửa truy vấn của mình. Do đó, bạn có thể làm một cái gì đó như:

-- Act
-- Notice the where clause
set @employeeId = (select e.EmployeeId from dbo.Employee e where e.EmployeeId = 1);
print @employeeId;

Dọn dẹp

drop table Employee;

Để kết luận, sử dụng:

  • SET: Khi bạn muốn gán một giá trị cho một biến và biến của bạn là cho một giá trị.
  • SELECT: Khi bạn muốn gán nhiều giá trị cho một biến. Biến có thể là bảng, bảng tạm thời hoặc biến bảng, v.v.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.