MySQL: @ ตัวแปรกับตัวแปร ความแตกต่างคืออะไร?


501

ในคำถามอื่นที่ฉันโพสต์มีคนบอกฉันว่ามีความแตกต่างระหว่าง:

@variable

และ:

variable

ใน MySQL เขายังกล่าวถึงวิธี MSSQL มีขอบเขตชุดและ MySQL มีขอบเขตเซสชัน บางคนสามารถอธิบายเรื่องนี้ให้ฉันได้ไหม


1
ฉันคุ้นเคยกับ MsSQL ดังนั้นความคิดนี้จึงไม่เคยทำให้ฉันถามคำถามดังกล่าว คำตอบที่ให้ไว้นี่คือสิ่งที่ฉันไม่มีในความคิด !! ขอบคุณ ..
Ken

คำตอบ:


624

MySQLมีแนวคิดของตัวแปรที่ผู้ใช้กำหนด

พวกเขาเป็นตัวแปรที่พิมพ์อย่างหลวม ๆ ที่อาจเริ่มต้นที่ไหนสักแห่งในเซสชั่นและเก็บค่าของพวกเขาจนกว่าเซสชั่นจะสิ้นสุดลง

พวกเขาได้รับการต่อเติมด้วย@เครื่องหมายเช่นนี้@var

คุณสามารถเริ่มต้นตัวแปรนี้ด้วยSETคำสั่งหรือภายในในแบบสอบถาม:

SET @var = 1

SELECT @var2 := 2

เมื่อคุณพัฒนาโพรซีเดอร์ที่เก็บในMySQLคุณสามารถส่งผ่านพารามิเตอร์อินพุตและประกาศตัวแปรโลคัล:

DELIMITER //

CREATE PROCEDURE prc_test (var INT)
BEGIN
    DECLARE  var2 INT;
    SET var2 = 1;
    SELECT  var2;
END;
//

DELIMITER ;

ตัวแปรเหล่านี้ไม่ได้เติมไว้พร้อมกับคำนำหน้าใด ๆ

ความแตกต่างระหว่างตัวแปรขั้นตอนและตัวแปรที่ผู้ใช้กำหนดเฉพาะเซสชันคือตัวแปรขั้นตอนจะเริ่มต้นใหม่NULLทุกครั้งที่มีการเรียกใช้โพรซีเดอร์ในขณะที่ตัวแปรเฉพาะเซสชันไม่ได้เป็น:

CREATE PROCEDURE prc_test ()
BEGIN
    DECLARE var2 INT DEFAULT 1;
    SET var2 = var2 + 1;
    SET @var2 = @var2 + 1;
    SELECT  var2, @var2;
END;

SET @var2 = 1;

CALL prc_test();

var2  @var2
---   ---
2     2


CALL prc_test();

var2  @var2
---   ---
2     3


CALL prc_test();

var2  @var2
---   ---
2     4

ดังที่คุณเห็นvar2(ตัวแปรขั้นตอน) จะเริ่มต้นใหม่ทุกครั้งที่มีการเรียกขั้นตอนขณะที่@var2(ตัวแปรเฉพาะเซสชัน) ไม่

(นอกจากตัวแปรที่ผู้ใช้กำหนดเอง MySQL ยังมี "ตัวแปรระบบ" ที่กำหนดไว้ล่วงหน้าซึ่งอาจเป็น "ตัวแปรทั่วโลก" เช่น@@global.portหรือ "ตัวแปรเซสชัน" เช่น@@session.sql_mode"ตัวแปรเซสชัน" เหล่านี้ไม่เกี่ยวข้องกับเซสชันที่ผู้ใช้กำหนด ตัวแปร.)


43
โปรดทราบด้วยว่ามีตัวแปรทั่วโลกที่มีอยู่: ดูSELECT @@version;ตัวอย่าง นี่คือเหตุผลว่าทำไมการใช้งานDELIMITER @@ไม่ใช่ความคิดที่ดีจริงๆ
Mchl

13
มันทำให้คำถามใหม่สำหรับ newcomes ... มีความแตกต่างระหว่าง "var = var" และ "var: = var" ในตัวอย่างของคุณหรือไม่?
confiq

13
@confiq: ไม่มีเลย
Quassnoi

10
คำถามอื่นสำหรับผู้มาใหม่ เมื่อไรแนะนำให้ใช้@vs ไม่?
pixelfreak

73
@confiq, @Quassnoi: มีหนึ่งความแตกต่างที่สำคัญระหว่าง:=และ=และนั่นคือการ:=ทำงานเป็นผู้ประกอบการกำหนดตัวแปรทุกที่ในขณะที่=ทำงานได้ด้วยวิธีการในSETงบและเป็นผู้ประกอบการเปรียบเทียบทุกที่อื่น ดังนั้นSELECT @var = 1 + 1;จะปล่อยให้ @var ไม่เปลี่ยนแปลงและคืนค่าบูลีน (1 หรือ 0 ขึ้นอยู่กับค่าปัจจุบันของ @var) ในขณะที่SELECT @var := 1 + 1;จะเปลี่ยน @var เป็น 2 และส่งคืน 2
Dewi Morgan

71

ใน MySQL, @variableบ่งชี้ตัวแปรที่ผู้ใช้กำหนด คุณสามารถกำหนดของคุณเอง

SET @a = 'test';
SELECT @a;

นอกโปรแกรมที่จัดเก็บไว้ a variable, ภายนอก@, เป็นตัวแปรระบบซึ่งคุณไม่สามารถกำหนดได้

ขอบเขตของตัวแปรนี้คือเซสชันทั้งหมด นั่นหมายความว่าในขณะที่การเชื่อมต่อกับฐานข้อมูลของคุณยังคงมีอยู่ตัวแปรยังคงสามารถใช้งานได้

สิ่งนี้ตรงกันข้ามกับ MSSQL ซึ่งตัวแปรจะพร้อมใช้งานในชุดการสืบค้นปัจจุบันเท่านั้น (กระบวนงานที่เก็บไว้สคริปต์หรืออย่างอื่น) มันจะไม่สามารถใช้ได้ในชุดที่แตกต่างกันในเซสชั่นเดียวกัน


2
ไม่สับสนกับตัวแปรเซสชั่นที่มีชวเลขSET @@a = 'test';cf เลย dev.mysql.com/doc/refman/5.1/en/set-statement.html
RobM

@RobM พวกเขาเรียกว่าตัวแปรระบบไม่ใช่ตัวแปรเซสชัน
Pacerier

1
@Pacerier: ฉันอ่านเอกสารผิดหรือเปล่า? "" "เพื่อระบุอย่างชัดเจนว่าตัวแปรเป็นตัวแปรเซสชันนำหน้าชื่อโดย SESSION, @@ session., หรือ @@." ""
RobM

5
@RobM คุณอ่านผิด อ่านทั้งย่อหน้าไม่ใช่แค่ย่อหน้าภายในสัญลักษณ์หัวข้อย่อย มีตัวแปรเซสชันสองแบบ: 1) ตัวแปรเซสชันที่ผู้ใช้กำหนดและ 2) ระบบ -  ตัวแปรเซสชันที่กำหนด @@คุณไม่สามารถตั้งตัวแปรเซสชั่นที่ผู้ใช้กำหนดโดยใช้ ตัวอย่างเช่นset@@my_var=1, set@@session.my_var=1และset session my_var=1จะไม่ทำงานเพราะmy_varไม่ได้เป็นระบบตัวแปรในขณะที่เราสามารถทำได้set@@big_tables=1, set@@session.big_tables=1และset session big_tables=1เพราะbig_tablesเป็นตัวแปรระบบ
Pacerier

1
@GovindRai: ในคำตอบ Quassnoi var2เป็นตัวแปรที่ไม่มี@คำนำหน้า แต่ไม่ใช่ตัวแปรระบบ: มันเป็นตัวแปรขั้นตอน สิ่งนี้ได้รับอนุญาตเพราะมันอยู่ในขั้นตอนการจัดเก็บ (aka โปรแกรมที่เก็บไว้) นอกเหนือจากกระบวนงานที่เก็บไว้แล้วตัวแปรที่ไม่มี@คือตัวแปรของระบบ
LarsH

10

MSSQL ต้องการให้ตัวแปรภายในโพรซีเดอร์เป็น DECLAREd และ folks ใช้ไวยากรณ์ @Variable (DECLARE @TEXT VARCHAR (25) = 'text') นอกจากนี้ MS อนุญาตให้ประกาศภายในบล็อกใด ๆ ในโพรซีเดอร์ซึ่งแตกต่างจาก mySQL ซึ่งต้องการ DECLARE ทั้งหมดที่ด้านบน

ในขณะที่ดีในบรรทัดคำสั่งฉันรู้สึกว่าการใช้ "set = @variable" ภายในกระบวนงานที่เก็บไว้ใน mySQL มีความเสี่ยง ไม่มีขอบเขตและตัวแปรอยู่ในขอบเขตของขอบเขต สิ่งนี้คล้ายกับตัวแปรใน JavaScript ที่ประกาศโดยไม่มีคำนำหน้า "var" ซึ่งก็คือเนมสเปซส่วนกลางและสร้างการชนและการเขียนทับที่ไม่คาดคิด

ฉันหวังว่าคนดี ๆ ที่ mySQL จะอนุญาตให้ DECLARE @Variable ที่ระดับบล็อกต่าง ๆ ภายในกระบวนงานที่เก็บไว้ สังเกตเห็นเครื่องหมาย @ (ที่เครื่องหมาย) คำนำหน้า @ sign ช่วยแยกชื่อตัวแปรออกจากชื่อคอลัมน์ตารางซึ่งมักจะเหมือนกัน แน่นอนหนึ่งสามารถเพิ่มคำนำหน้า "v" หรือ "l_" ได้เสมอ แต่เครื่องหมาย @ เป็นวิธีที่สะดวกและกระชับเพื่อให้ชื่อตัวแปรตรงกับคอลัมน์ที่คุณอาจกำลังดึงข้อมูลจากโดยไม่ต้องปิดบังมัน

MySQL เป็นเครื่องมือใหม่ในการจัดเก็บและทำงานได้ดีสำหรับรุ่นแรก มันจะเป็นเรื่องน่ายินดีที่ได้เห็นว่าพวกเขาใช้ภาษาที่ไหนและดูที่ฝั่งเซิร์ฟเวอร์ของภาษาที่พัฒนาแล้ว


3

โดยหลักการแล้วฉันใช้ UserDefinedVariables (เติมด้วย @) ภายในกระบวนงานที่เก็บไว้ สิ่งนี้ทำให้ชีวิตง่ายขึ้นโดยเฉพาะเมื่อฉันต้องการตัวแปรเหล่านี้ในกระบวนงานที่เก็บไว้สองกระบวนขึ้นไป เมื่อฉันต้องการตัวแปรเฉพาะภายใน ONE Stored Procedure เท่านั้นฉันใช้ System Variable (โดยไม่ต้องใส่เครื่องหมาย @)

@Xybo: ฉันไม่เข้าใจว่าทำไมการใช้ @variables ใน StoredProcedures จึงมีความเสี่ยง คุณช่วยอธิบาย "ขอบเขต" และ "ขอบเขต" ได้ง่ายขึ้นหน่อย (สำหรับฉันในฐานะมือใหม่)?


3
สิ่งนี้ละเมิดหลักการวิศวกรรมซอฟต์แวร์พื้นฐาน โปรดอย่าเขียนโค้ดบรรทัดอับเรณูจนกว่าคุณจะรู้ว่าขอบเขตคืออะไรและทำไมการใช้ตัวแปรทั่วโลกจึงเป็นแนวคิดที่แย่มาก เมื่อฉันเรียนคลาสการเขียนโปรแกรม 101 ครั้งฉันจำได้ว่าการใช้ทั่วโลกสำหรับทุกสิ่งจะส่งผลให้ "F" โดยอัตโนมัติ มีข้อยกเว้นพิเศษ แต่ตามกฎทั่วไป - อย่าทำ!
BuvinJ

ทำไม? - @Variables เป็นเรื่องธรรมดาใน MySQL-Book ทุกตัว
ปีเตอร์

แน่นอนว่าในสคริปต์ "flat" ที่ไม่มีการเรียกใช้ฟังก์ชันโพรซีเดอร์ทริกเกอร์ ฯลฯ และถ้าคุณเพิ่งจะเรียกใช้งานสคริปต์แบบง่าย ๆ นั้นหรือชุดคำสั่งที่ จำกัด และจากนั้นจึงปิดเซสชัน (จึงเป็นการทำลาย globals ของคุณ) ในกรณีเช่นนั้นไปข้างหน้าและใช้พวกเขาหากคุณต้องการ แต่อย่าใช้มันในฟังก์ชั่น! หากคุณเพียงแค่ตัวแปรหรือขอบเขตทั่วโลกของ Google คุณจะพบการสนับสนุนมากมายสำหรับแนวคิดที่ว่าพวกเขาได้รับการยอมรับในระดับสากล นี่คือจุดเริ่มต้น: wiki.c2.com/?GlobalVariablesAreBadหรือสำหรับคำอธิบายทั่วไปเพิ่มเติม: en.wikipedia.org/wiki/Global_variable
BuvinJ

2
ใน MySQL, @variables เป็นระดับโลก นี่เป็นการยืนยันที่ง่ายดาย ตั้งหนึ่งนอกฟังก์ชั่นแล้วประเมินผลภายในหนึ่ง ในทางกลับกันให้ตั้งค่าหนึ่งในฟังก์ชันและประเมินผลภายนอก คุณจะเห็นฟังก์ชั่นไม่ได้ป้องกันขอบเขตดังกล่าว พวกเขาเหยียบนิ้วเท้าของอีกฝ่าย
BuvinJ

1
การใช้คำศัพท์ MySQL @@GLOBALตัวแปรต่าง ๆ ยิ่ง "ทั่วโลก" และร้ายกาจ พวกเขาข้ามช่วง! @variablesมี "ขอบเขตเซสชั่น" ดังนั้นอย่างน้อยพวกเขาก็ยังคงอยู่ในลักษณะนั้น ในภาษาปกติใด ๆ ที่เป็นสิ่งที่คุณเรียกว่าขอบเขต "ทั่วโลก" (เมื่อข้ามฟังก์ชัน ฯลฯ ) แนวคิด MySQL ของ "global" น่าจะเรียกว่า "universal" ซึ่งมันครอบคลุมขอบเขตของกระบวนการที่เรียกใช้ โดยทั่วไป "ทั่วโลก" ไม่สามารถทำได้ในภาษามาตรฐานเนื่องจากกระบวนการไม่แชร์พื้นที่หน่วยความจำ สิ่งนี้เกิดจากแนวโน้ม (vs volatile) ที่คงอยู่ของ SQL
BuvinJ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.