อะไรคือความแตกต่างระหว่างSET
และSELECT
คำสั่งเมื่อกำหนดตัวแปรใน T-SQL?
อะไรคือความแตกต่างระหว่างSET
และSELECT
คำสั่งเมื่อกำหนดตัวแปรใน T-SQL?
คำตอบ:
- SET เป็นมาตรฐาน ANSI สำหรับการกำหนดตัวแปร SELECT ไม่ได้
- ตลาดหลักทรัพย์สามารถกำหนดตัวแปรได้ครั้งละหนึ่งตัวเท่านั้น SELECT สามารถทำการมอบหมายได้หลายรายการพร้อมกัน
- หากกำหนดจากแบบสอบถามตลาดหลักทรัพย์สามารถกำหนดค่าสเกลาร์ได้เท่านั้น หากแบบสอบถามส่งคืนค่า / หลายแถว SET จะเพิ่มข้อผิดพลาด SELECT จะกำหนดหนึ่งในค่าให้กับตัวแปรและซ่อนความจริงที่ว่ามีการส่งคืนค่าหลายค่า (ดังนั้นคุณอาจไม่เคยรู้เลยว่าทำไมบางอย่างผิดปกติที่อื่น - สนุกกับการแก้ปัญหาที่เกิดขึ้น)
- เมื่อกำหนดจากแบบสอบถามถ้าไม่มีค่าส่งคืน SET จะกำหนดค่า NULL โดยที่ SELECT จะไม่ทำการมอบหมายเลย (ดังนั้นตัวแปรจะไม่ถูกเปลี่ยนจากค่าก่อนหน้า)
- เท่าที่ความแตกต่างของความเร็ว - ไม่มีความแตกต่างโดยตรงระหว่าง SET และ SELECT อย่างไรก็ตามความสามารถของ SELECT ในการทำการมอบหมายหลายครั้งในหนึ่งช็อตทำให้ได้เปรียบในเรื่องความเร็วเหนือ SET เล็กน้อย
SELECT @Int = @Int + 1, @Int = @Int + 1
ถ้า@Int
เริ่มจาก 0 มันจะจบลงที่ 2 ซึ่งจะมีประโยชน์มากเมื่อทำการจัดการสตริงต่อเนื่องกัน
ฉันเชื่อว่าSET
เป็นมาตรฐาน ANSI ในขณะที่SELECT
ไม่ใช่ โปรดสังเกตพฤติกรรมที่แตกต่างของSET
vs. SELECT
ในตัวอย่างด้านล่างเมื่อไม่พบค่า
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' */
select @var = (select name from master.sys.tables where name = 'qwerty')
คุณจะได้รับ @var เป็นโมฆะ ตัวอย่างที่คุณให้ไม่ใช่แบบสอบถามเดียวกัน
(select name from master.sys.tables where name = 'qwerty')
หนึ่งสำหรับและname from master.sys.tables where name = 'qwerty'
อื่น ๆ ... คุณไม่เห็นว่า?
(select name from master.sys.tables where name = 'qwerty')
เป็นคิวรีย่อยสเกลาร์และname from master.sys.tables where name = 'qwerty'
เป็นคิวรีธรรมดา การแสดงออกที่แตกต่างกันสองอย่างนั้นไม่ควรที่จะให้ผลลัพธ์ที่เหมือนกันถึงแม้ว่าดูเหมือนว่าคุณกำลังบ่งบอกว่าพวกเขาควร หากคุณพยายามที่จะบอกว่าSET
และSELECT
คำหลักมีการใช้งานที่แตกต่างกันคุณไม่ควรใช้สองนิพจน์ที่แตกต่างกันในตัวอย่างของคุณ msdn.microsoft.com/en-us/library/ms187330.aspx
เมื่อเขียนแบบสอบถามความแตกต่างนี้ควรคำนึงถึง:
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*/
นอกเหนือจาก ANSI และความเร็ว ฯลฯ มันมีความแตกต่างที่สำคัญมากซึ่งสำคัญสำหรับฉันเสมอ มากกว่า ANSI และความเร็ว จำนวนข้อบกพร่องที่ฉันได้แก้ไขเนื่องจากการมองข้ามที่สำคัญนี้มีขนาดใหญ่ ฉันค้นหาสิ่งนี้ระหว่างการตรวจสอบโค้ดตลอดเวลา
-- 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;
เกือบตลอดเวลานั่นไม่ใช่สิ่งที่นักพัฒนาตั้งใจจะทำ ในข้างต้นแบบสอบถามตรงไปข้างหน้า แต่ฉันได้เห็นแบบสอบถามที่ค่อนข้างซับซ้อนและค้นหาว่ามันจะส่งกลับค่าเดียวหรือไม่ไม่สำคัญ บ่อยครั้งที่แบบสอบถามมีความซับซ้อนมากกว่านี้และโดยบังเอิญมีการส่งคืนค่าเดียว ในระหว่างการทดสอบนักพัฒนาทั้งหมดเป็นเรื่องปกติ แต่นี่เป็นเหมือนระเบิดติ๊ก ๆ และจะทำให้เกิดปัญหาเมื่อเคียวรีส่งคืนผลลัพธ์หลายรายการ ทำไม? เพราะมันจะกำหนดค่าสุดท้ายให้กับตัวแปร
ตอนนี้ลองทำสิ่งเดียวกันกับSET
:
-- Act
set @employeeId = (select e.EmployeeId from dbo.Employee e);
คุณจะได้รับข้อผิดพลาด:
แบบสอบถามย่อยส่งคืนมากกว่า 1 ค่า สิ่งนี้ไม่ได้รับอนุญาตเมื่อเคียวรีย่อยตามหลัง =,! =, <, <=,>,> = หรือเมื่อใช้เคียวรีย่อยเป็นนิพจน์
นั่นเป็นที่น่าตื่นตาตื่นใจและมีความสำคัญมากเพราะเหตุผลที่คุณจะต้องการกำหนดบางจิ๊บจ๊อย "รายการสุดท้ายในผล" @employeeId
เพื่อ ด้วยselect
คุณจะไม่ได้รับข้อผิดพลาดใด ๆ และคุณจะใช้เวลาหลายนาที, การแก้จุดบกพร่องชั่วโมง
บางทีคุณกำลังมองหา ID เดียวและSET
จะบังคับให้คุณแก้ไขข้อความค้นหาของคุณ ดังนั้นคุณอาจทำสิ่งที่ชอบ:
-- Act
-- Notice the where clause
set @employeeId = (select e.EmployeeId from dbo.Employee e where e.EmployeeId = 1);
print @employeeId;
ทำความสะอาด
drop table Employee;
โดยสรุปการใช้:
SET
: เมื่อคุณต้องการกำหนดค่าเดียวให้กับตัวแปรและตัวแปรของคุณใช้สำหรับค่าเดียวSELECT
: เมื่อคุณต้องการกำหนดค่าหลายค่าให้กับตัวแปร ตัวแปรอาจเป็นตาราง, ตารางชั่วคราวหรือตัวแปรตารางเป็นต้น