SET versus SELECT saat menetapkan variabel?

Jawaban:

411

Kutipan , yang merangkum dari artikel ini :

  1. SET adalah standar ANSI untuk penugasan variabel, SELECT tidak.
  2. SET hanya dapat menetapkan satu variabel pada satu waktu, SELECT dapat membuat banyak tugas sekaligus.
  3. Jika menetapkan dari kueri, SET hanya dapat menetapkan nilai skalar. Jika kueri mengembalikan beberapa nilai / baris maka SET akan memunculkan kesalahan. SELECT akan menetapkan salah satu nilai ke variabel dan menyembunyikan fakta bahwa beberapa nilai dikembalikan (jadi Anda mungkin tidak akan pernah tahu mengapa ada sesuatu yang salah di tempat lain - bersenang-senanglah memecahkan masalah itu)
  4. Saat menetapkan dari kueri jika tidak ada nilai yang dikembalikan maka SET akan menetapkan NULL, di mana SELECT tidak akan membuat penetapan sama sekali (sehingga variabel tidak akan berubah dari nilai sebelumnya)
  5. Sejauh perbedaan kecepatan - tidak ada perbedaan langsung antara SET dan SELECT. Namun kemampuan SELECT untuk membuat banyak penugasan dalam satu kesempatan memang memberikannya keunggulan kecepatan sedikit di atas SET.
OMG Ponies
sumber
3
Saya tidak downvote, tetapi yang berikut ini tidak sepenuhnya benar: "Sejauh perbedaan kecepatan - tidak ada perbedaan langsung antara SET dan SELECT". Jika Anda menetapkan beberapa nilai dalam satu slect, itu bisa jauh lebih cepat dari itu melalui set maultiple. Google naik "Menetapkan banyak variabel dengan satu SELECT berfungsi lebih cepat"
AK
14
@AlexKuznetsov: Kalimat setelahnya mengatakan hal itu.
OMG Ponies
3
@OMG Ponies: Ini bisa 10 kali lebih cepat atau lebih, jadi saya tidak yakin apakah itu "keunggulan kecepatan sedikit".
AK
2
Terutama ketika menggunakan Loop Sementara, saya telah melihat keuntungan kinerja BESAR dengan mengatur / menginisialisasi ulang semua variabel saya menggunakan one-Select vs many-Set's. Saya juga dapat mengkonsolidasikan Variabel-Logika saya di Pilih untuk semua berjalan sekaligus juga: Contoh:, SELECT @Int = @Int + 1, @Int = @Int + 1jika @Intdimulai sebagai 0, maka berakhir sebagai 2. Ini bisa sangat berguna ketika melakukan manipulasi string berturut-turut.
MikeTeeVee
Diskusi menarik tentang perbedaan kinerja. Jika pengaturan beberapa nilai melalui pilih lebih cepat (untuk kode dan mengeksekusi) maka satu cara yang gagal untuk menghindari poin 4 (nilai variabel Anda gagal berubah jika kueri mengembalikan nol) adalah secara eksplisit mengatur variabel Anda ke nol sebelum pilih. Setelah Anda memperhitungkannya, bagaimana keduanya membandingkan kinerja? (Catatan: Saya tidak mengerti alasan untuk memilih tidak mengatur variabel Anda ke nol jika permintaan mengembalikan nol. Kapan Anda menginginkannya?)
youcantryreachingme
155

Saya percaya SETstandar ANSI sedangkanSELECT tidak. Perhatikan juga perilaku berbeda SETvs SELECTdalam contoh di bawah ini ketika nilai tidak ditemukan.

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' */
Joe Stefanelli
sumber
4
+1 Lebih baik dijalankan sekali untuk memahami, memeriksa, bermain, menghafal bahwa hanya membaca tetapi jawaban lain hanya teks
Gennady Vanin Геннадий Ванин
4
Jika Anda benar-benar menggunakan select @var = (select name from master.sys.tables where name = 'qwerty')Anda akan mendapatkan @var sebagai null. Contoh yang Anda berikan bukan permintaan yang sama.
Zack
4
Anda punya (select name from master.sys.tables where name = 'qwerty')untuk satu, dan name from master.sys.tables where name = 'qwerty'untuk yang lain ... apakah Anda tidak melihatnya?
Zack
4
@Zack: Masing-masing adalah sintaks yang benar untuk apa yang saya coba demo; perbedaan antara menggunakan SET vs. SELECT untuk menetapkan nilai ke variabel ketika kueri yang mendasarinya tidak mengembalikan hasil.
Joe Stefanelli
5
(select name from master.sys.tables where name = 'qwerty')adalah subquery skalar, dan name from master.sys.tables where name = 'qwerty'merupakan kueri sederhana. Dua ekspresi yang berbeda tidak seharusnya menghasilkan hasil yang sama, meskipun sepertinya Anda menyiratkan bahwa mereka harus melakukannya. Jika Anda mencoba untuk mengatakan SETdan SELECTkata kunci memiliki implementasi yang berbeda, Anda tidak boleh menggunakan dua ekspresi yang berbeda dalam contoh Anda. msdn.microsoft.com/en-us/library/ms187330.aspx
Zack
27

Saat menulis pertanyaan, perbedaan ini harus diingat:

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*/
GorkemHalulu
sumber
sangat bagus, ringkas
SimplyInk
8

Selain dari yang ANSI dan kecepatan dll, ada perbedaan yang sangat penting yang selalu berarti bagi saya; lebih dari ANSI dan kecepatan. Jumlah bug yang saya perbaiki karena pengabaian penting ini besar. Saya mencari ini selama ulasan kode sepanjang waktu.

-- 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; 

Hampir selalu, bukan itu yang dimaksudkan pengembang. Dalam contoh di atas, kueri langsung tetapi saya telah melihat pertanyaan yang cukup kompleks dan mencari tahu apakah itu akan mengembalikan nilai tunggal atau tidak, tidak sepele. Permintaan sering lebih kompleks dari ini dan kebetulan telah mengembalikan nilai tunggal. Selama pengujian pengembang semuanya baik-baik saja. Tapi ini seperti bom detak dan akan menyebabkan masalah ketika kueri mengembalikan beberapa hasil. Mengapa? Karena itu hanya akan menetapkan nilai terakhir ke variabel.

Sekarang mari kita coba hal yang sama dengan SET:

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

Anda akan menerima kesalahan:

Subquery mengembalikan lebih dari 1 nilai. Ini tidak diizinkan ketika subquery mengikuti =,! =, <, <=,>,> = Atau ketika subquery digunakan sebagai ekspresi.

Itu luar biasa dan sangat penting karena mengapa Anda ingin menetapkan beberapa "item terakhir dalam hasil" yang sepele untuk @employeeId. Dengan selectAnda tidak akan pernah mendapatkan kesalahan dan Anda akan menghabiskan menit, jam debugging.

Mungkin, Anda mencari satu ID dan SETakan memaksa Anda untuk memperbaiki kueri Anda. Dengan demikian Anda dapat melakukan sesuatu seperti:

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

Membersihkan

drop table Employee;

Sebagai kesimpulan, gunakan:

  • SET: Ketika Anda ingin menetapkan nilai tunggal ke suatu variabel dan variabel Anda adalah untuk nilai tunggal.
  • SELECT: Ketika Anda ingin menetapkan beberapa nilai ke suatu variabel. Variabel dapat berupa tabel, tabel temp atau variabel tabel dll.
CodingYoshi
sumber