MySQL: @variable so với biến. Có gì khác biệt?


501

Trong một câu hỏi khác, tôi đã đăng một người nói với tôi rằng có một sự khác biệt giữa:

@variable

và:

variable

trong MySQL. Ông cũng đề cập đến cách MSSQL có phạm vi lô và MySQL có phạm vi phiên. Ai đó có thể giải thích về điều này cho tôi?


1
Tôi quen thuộc với MsQuery và vì thế tôi không bao giờ nghĩ ra câu hỏi như vậy. Các câu trả lời được cung cấp ở đây đã đeo bám tôi điều gì đó mà tôi không có IDEA về !! Thx ..
Ken

Câu trả lời:


624

MySQLcó khái niệm về các biến do người dùng định nghĩa .

Chúng là các biến được gõ lỏng lẻo có thể được khởi tạo ở đâu đó trong phiên và giữ giá trị của chúng cho đến khi phiên kết thúc.

Chúng được đặt trước một @dấu hiệu, như thế này:@var

Bạn có thể khởi tạo biến này bằng một SETcâu lệnh hoặc bên trong một truy vấn:

SET @var = 1

SELECT @var2 := 2

Khi bạn phát triển một thủ tục được lưu trữ trong MySQL, bạn có thể truyền các tham số đầu vào và khai báo các biến cục bộ:

DELIMITER //

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

DELIMITER ;

Các biến này không được đặt trước với bất kỳ tiền tố nào.

Sự khác biệt giữa biến thủ tục và biến do người dùng xác định theo phiên là biến thủ tục được khởi tạo lại cho NULLmỗi lần thủ tục được gọi, trong khi biến cụ thể theo phiên không phải là:

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

Như bạn có thể thấy, var2(biến thủ tục) được khởi tạo lại mỗi lần thủ tục được gọi, trong khi @var2(biến cụ thể theo phiên) thì không.

(Ngoài các biến do người dùng xác định, MySQL cũng có một số "biến hệ thống" được xác định trước, có thể là "biến toàn cục", chẳng hạn như @@global.port"biến phiên", chẳng hạn như @@session.sql_mode"các biến phiên" này không liên quan đến định nghĩa người dùng theo phiên cụ thể biến.)


43
Cũng lưu ý rằng có sẵn các biến toàn cục: Xem SELECT @@version;ví dụ. Đây cũng là một lý do, tại sao sử dụng DELIMITER @@không thực sự là một ý tưởng tốt.
Mchl

13
nó tạo ra những câu hỏi mới cho kết quả mới ... có sự khác biệt nào giữa "var = var" và "var: = var" như trong ví dụ của bạn không?
confiq

13
@confiq: không có.
Quassnoi

10
Một câu hỏi khác cho một người mới. Khi nào nên dùng @vs không?
pixelfreak

73
@confiq, @Quassnoi: có một sự khác biệt đáng kể giữa :==, đó là :=hoạt động như một toán tử gán biến ở khắp mọi nơi, trong khi =chỉ hoạt động theo cách đó trong các SETcâu lệnh và là toán tử so sánh ở mọi nơi khác. Vì vậy, SELECT @var = 1 + 1;sẽ giữ nguyên @var và trả về boolean (1 hoặc 0 tùy thuộc vào giá trị hiện tại của @var), trong khi SELECT @var := 1 + 1;sẽ thay đổi @var thành 2 và trả về 2.
Dewi Morgan

71

Trong MySQL, @variablechỉ ra một biến do người dùng định nghĩa . Bạn có thể xác định của riêng bạn.

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

Bên ngoài các chương trình được lưu trữ, a variable, không có @, là một biến hệ thống , mà bạn không thể tự xác định.

Phạm vi của biến này là toàn bộ phiên. Điều đó có nghĩa là trong khi kết nối của bạn với cơ sở dữ liệu tồn tại, biến vẫn có thể được sử dụng.

Điều này trái ngược với MSSQL, trong đó biến sẽ chỉ khả dụng trong lô truy vấn hiện tại (thủ tục được lưu trữ, tập lệnh hoặc cách khác). Nó sẽ không có sẵn trong một lô khác nhau trong cùng một phiên.


2
Không bị nhầm lẫn với các biến phiên, có tốc ký SET @@a = 'test';, cf dev.mysql.com/doc/refman/5.1/en/set-statement.html
RobM

@RobM, Chúng được gọi là biến hệ thống , không phải biến phiên.
Pacerier

1
@Pacerier: Tôi có đọc nhầm tài liệu không? "" "Để chỉ rõ rằng một biến là biến phiên, đặt trước tên của nó bằng SESSION, @@ session. Hoặc @@." ""
RobM

5
@RobM, bạn đang đọc nhầm. Đọc qua toàn bộ đoạn văn, không chỉ đoạn văn trong dấu đầu dòng. Nói một cách đơn giản, có hai loại biến phiên: 1) Biến phiên do người dùng xác định và 2)  biến phiên do hệ thống xác định. Bạn không thể đặt biến phiên do người dùng xác định bằng cách sử dụng @@. Ví dụ, set@@my_var=1, set@@session.my_var=1, và set session my_var=1sẽ không hoạt động vì my_varkhông phải là một hệ thống biến, trong khi chúng ta có thể làm set@@big_tables=1, set@@session.big_tables=1set session big_tables=1big_tableslà một biến hệ thống.
Pacerier

1
@GovindRai: Trong câu trả lời của Quassnoi, var2là một biến không có @tiền tố, nhưng nó không phải là biến hệ thống: đó là biến thủ tục. Điều này được cho phép bởi vì nó trong một thủ tục được lưu trữ (còn gọi là chương trình được lưu trữ). Ngoài các thủ tục được lưu trữ, một biến không có @là một biến hệ thống.
LarsH

10

MSSQL yêu cầu các biến trong quy trình là DECLAREd và mọi người sử dụng cú pháp @Variable (DECLARE @TEXT VARCHAR (25) = 'text'). Ngoài ra, MS cho phép khai báo trong bất kỳ khối nào trong quy trình, không giống như myQuery yêu cầu tất cả các DECLARE ở trên cùng.

Mặc dù tốt trên dòng lệnh, tôi cảm thấy việc sử dụng "set = @variable" trong các thủ tục được lưu trữ trong myQuery là rủi ro. Không có phạm vi và biến số sống qua ranh giới phạm vi. Điều này tương tự với các biến trong JavaScript được khai báo mà không có tiền tố "var", sau đó là không gian tên toàn cục và tạo ra các xung đột và ghi đè bất ngờ.

Tôi hy vọng rằng những người giỏi tại myQuery sẽ cho phép DECLARE @Variable ở nhiều cấp độ khối khác nhau trong một quy trình được lưu trữ. Lưu ý @ (tại dấu). Tiền tố dấu @ giúp tách các tên biến khỏi tên cột trong bảng - vì chúng thường giống nhau. Tất nhiên, người ta luôn có thể thêm tiền tố "v" hoặc "l_", nhưng dấu @ là một cách tiện dụng và ngắn gọn để có tên biến khớp với cột mà bạn có thể trích xuất dữ liệu mà không bị ghi đè.

MySQL là mới đối với các thủ tục được lưu trữ và họ đã làm một công việc tốt cho phiên bản đầu tiên của họ. Sẽ là một niềm vui khi thấy nơi họ hình thành ở đây và để xem các khía cạnh phía máy chủ của ngôn ngữ trưởng thành.


3

Về nguyên tắc, tôi sử dụng UserDefinedVariabled (được thêm trước @) trong Thủ tục lưu trữ. Điều này làm cho cuộc sống dễ dàng hơn, đặc biệt là khi tôi cần các biến này trong hai hoặc nhiều Thủ tục lưu trữ. Chỉ khi tôi cần một biến chỉ trong MỘT Thủ tục được lưu trữ, hơn là tôi sử dụng Biến hệ thống (không có tiền tố @).

@Xybo: Tôi không hiểu tại sao sử dụng @variable trong StoredProcedures lại có rủi ro. Bạn có thể vui lòng giải thích "phạm vi" và "ranh giới" dễ dàng hơn một chút (đối với tôi là một người mới)?


3
Điều này vi phạm các nguyên tắc kỹ thuật phần mềm cơ bản. Vui lòng không viết dòng mã bao phấn cho đến khi bạn biết chính xác phạm vi là gì và tại sao sử dụng biến toàn cục thường là một ý tưởng tồi. Khi tôi học 101 lớp lập trình, vì tôi nhớ sử dụng toàn cầu cho hầu hết mọi thứ sẽ dẫn đến chữ "F" tự động. Có những trường hợp ngoại lệ đặc biệt, nhưng như một quy tắc chung - đừng làm điều đó!
BuvinJ

Tại sao? - @Variabled hoàn toàn phổ biến trong mọi Sách của MySQL.
Peter

Chắc chắn, trong một tập lệnh "phẳng" không có chức năng gọi, thủ tục, trình kích hoạt, v.v. và nếu bạn chỉ thực hiện tập lệnh đơn giản đó, hoặc một bộ lệnh giới hạn và sau đó kết thúc phiên (từ đó phá hủy toàn cầu của bạn). Trong trường hợp đó, hãy tiếp tục và sử dụng chúng nếu bạn muốn. Nhưng KHÔNG sử dụng chúng bên trong một chức năng! Nếu bạn chỉ đơn giản là các biến hoặc phạm vi toàn cầu của Google, bạn sẽ ngay lập tức tìm thấy sự hỗ trợ to lớn cho ý tưởng rằng chúng đang được tán thành. Đây là điểm bắt đầu: wiki.c2.com/?GlobalVariabledAreBad hoặc để giải thích tổng quát hơn: en.wikipedia.org/wiki/Global_variable
BuvinJ

2
Trong MySQL, @variable là toàn cầu. Điều này dễ dàng được xác nhận. Đặt một bên ngoài của một chức năng và sau đó đánh giá nó bên trong một chức năng. Ngược lại, đặt một bên trong hàm và đánh giá nó bên ngoài hàm. Bạn sẽ thấy chức năng không bảo vệ phạm vi như vậy. Họ giẫm lên ngón chân của nhau.
BuvinJ

1
Sử dụng thuật ngữ MySQL, @@GLOBALcác biến thậm chí còn "toàn cầu" và quỷ quyệt hơn. Họ giao nhau! @variablescó "phạm vi phiên", vì vậy ít nhất họ vẫn bị giới hạn theo cách đó. Tuy nhiên, trong bất kỳ ngôn ngữ bình thường nào là phạm vi mà bạn gọi là phạm vi "toàn cầu" (khi chúng giao nhau chức năng, v.v.). Khái niệm "toàn cầu" của MySQL có lẽ nên được gọi là "phổ quát", theo đó nó vượt ra ngoài ranh giới của quá trình vận hành nó. Một "toàn cầu" thường không thể làm điều đó trong một ngôn ngữ tiêu chuẩn, vì các quy trình không chia sẻ không gian bộ nhớ. Điều này xuất phát từ xu hướng liên tục (so với biến động) của SQL.
BuvinJ
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.