Khi nào nên sử dụng dấu ngoặc đơn, dấu ngoặc kép và backticks trong MySQL


633

Tôi đang cố gắng học cách tốt nhất để viết truy vấn. Tôi cũng hiểu tầm quan trọng của sự nhất quán. Cho đến bây giờ, tôi đã ngẫu nhiên sử dụng dấu ngoặc đơn, dấu ngoặc kép và backticks mà không có suy nghĩ thực sự.

Thí dụ:

$query = 'INSERT INTO table (id, col1, col2) VALUES (NULL, val1, val2)';

Ngoài ra, trong ví dụ trên, hãy xem xét rằng table, col1, val1, vv có thể được biến.

Tiêu chuẩn cho việc này là gì? Bạn làm nghề gì?

Tôi đã đọc câu trả lời cho các câu hỏi tương tự ở đây trong khoảng 20 phút, nhưng có vẻ như không có câu trả lời dứt khoát cho câu hỏi này.


16
Lưu ý rằng đây là một câu hỏi cụ thể của MySQL. SQL nói chung (ví dụ ISO / ANSI SQL) có một bộ khác nhau của dấu ngoặc kép: dấu ngoặc kép là dành cho định danh phân, ví dụ "tablename", và dấu nháy đơn là cho literals, ví dụ 'this is a some text'. Back-tick không bao giờ được sử dụng trong SQL tiêu chuẩn. (Nếu bạn cần bao gồm một trích dẫn kép trong một mã định danh, hãy nhập nó hai lần như "odd""tablename"vậy. Tương tự, trích dẫn hai lần bằng chữ, như 'Conan O''Brien'.)
jarlh

Câu trả lời:


610

Backticks được sử dụng cho mã định danh bảng và cột, nhưng chỉ cần thiết khi mã định danh là từ khóa dành riêng cho MySQL hoặc khi mã định danh chứa các ký tự khoảng trắng hoặc ký tự nằm ngoài một bộ giới hạn (xem bên dưới) Nên tránh sử dụng từ khóa dành riêng như định danh cột hoặc bảng khi có thể, tránh vấn đề trích dẫn.

Dấu ngoặc đơn nên được sử dụng cho các giá trị chuỗi như trong VALUES()danh sách. Báo giá kép cũng được MySQL hỗ trợ cho các giá trị chuỗi, nhưng các trích dẫn đơn được RDBMS khác chấp nhận rộng rãi hơn, do đó, nên sử dụng các trích dẫn đơn thay vì gấp đôi.

MySQL cũng mong đợi DATEDATETIMEcác giá trị theo nghĩa đen sẽ được trích dẫn đơn dưới dạng chuỗi như thế nào '2001-01-01 00:00:00'. Tham khảo tài liệu Văn học Ngày và Giờ để biết thêm chi tiết, đặc biệt là các lựa chọn thay thế cho việc sử dụng dấu gạch nối -làm dấu phân cách trong chuỗi ngày.

Vì vậy, bằng cách sử dụng ví dụ của bạn, tôi sẽ trích dẫn hai chuỗi PHP và sử dụng các trích dẫn đơn trên các giá trị 'val1', 'val2'. NULLlà một từ khóa MySQL và một giá trị đặc biệt (không) và do đó không được trích dẫn.

Không có định danh bảng hoặc cột nào trong số này là các từ dành riêng hoặc sử dụng các ký tự yêu cầu trích dẫn, nhưng dù sao tôi cũng đã trích dẫn chúng bằng các backticks (sẽ nói thêm về điều này sau ...).

Các hàm có nguồn gốc từ RDBMS (ví dụ, NOW()trong MySQL) không nên được trích dẫn, mặc dù các đối số của chúng phải tuân theo cùng một chuỗi hoặc các quy tắc trích dẫn định danh đã được đề cập.

Backtick (`)
bảng & cột ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ Giới thiệu
                      ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
$ query = " XÁC NHẬN VÀO` bảng` (`id`,` col1`, `col2`,` date`, `update`)
                       GIÁ TRỊ (NULL, 'val1', 'val2', '2001-01-01', NOW ()) ";
                               ↑ ↑ ↑ ↑↑↑↑↑ 
Từ khóa không được trích dẫn ─────┴┴┴┘ │ │ │ │
Các chuỗi trích dẫn đơn (') ───────────┴────┴──┴────┘
Đơn trích dẫn (') NGÀY ───────────────────────────┴──────────┘ │
Chức năng không được trích dẫn ─────────────────────────────────────────┴┴┴┴┘    

Nội suy biến

Các mẫu trích dẫn cho các biến không thay đổi, mặc dù nếu bạn có ý định nội suy các biến trực tiếp trong một chuỗi, thì nó phải được trích dẫn kép trong PHP. Chỉ cần đảm bảo rằng bạn đã thoát đúng các biến để sử dụng trong SQL. ( Nên sử dụng API hỗ trợ các câu lệnh được chuẩn bị thay thế, để bảo vệ chống lại việc tiêm SQL ).

// Điều tương tự với một số thay thế biến
// Ở đây, một tên bảng biến $ bảng được trích dẫn ngược và các biến
// trong danh sách GIÁ TRỊ được trích dẫn đơn 
$ query = " XÁC NHẬN VÀO` $ bảng` (`id`,` col1`, `col2`,` date`) VALUES (NULL, '$ val1' , '$ val2' , '$ date' ) ";

Báo cáo đã chuẩn bị

Khi làm việc với các báo cáo đã chuẩn bị, hãy tham khảo tài liệu để xác định xem có giữ chỗ của tuyên bố hay không. Các API phổ biến nhất có sẵn trong PHP, PDO và MySQLi, mong đợi các trình giữ chỗ không được trích dẫn , cũng như các API câu lệnh được chuẩn bị sẵn trong các ngôn ngữ khác:

// PDO example with named parameters, unquoted
$query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (:id, :col1, :col2, :date)";

// MySQLi example with ? parameters, unquoted
$query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (?, ?, ?, ?)";

Các ký tự yêu cầu trích dẫn backtick trong định danh:

Theo tài liệu của MySQL , bạn không cần trích dẫn (backtick) số nhận dạng bằng cách sử dụng bộ ký tự sau:

ASCII: [0-9,a-z,A-Z$_](chữ cái Latinh cơ bản, chữ số 0-9, đô la, gạch dưới)

Bạn có thể sử dụng các ký tự ngoài bộ được đặt làm định danh bảng hoặc cột, bao gồm cả khoảng trắng chẳng hạn, nhưng sau đó bạn phải trích dẫn (backtick) chúng.


43
" nhưng các trích dẫn đơn được chấp nhận rộng rãi hơn bởi các RDBMS khác " - sử dụng các trích dẫn đơn cho các chuỗi ký tự được xác định (và bắt buộc) theo tiêu chuẩn SQL
a_horse_with_no_name

@a_horse_with_no_name hầu như không ai sử dụng ANSI MySQL ('|' cho chuỗi concat - thật sao?)
Người tốt

3
điều này không đúng: "MySQL cũng hy vọng các giá trị theo nghĩa đen của DATE và DATETIME sẽ được trích dẫn một lần dưới dạng các chuỗi như '2001-01-01 00:00:00'"
Kick_the_BucksET

3
@evilReiko Tài liệu MySQL dường như không đề cập đến trích dẫn bí danh rõ ràng. Nó sẽ chấp nhận một, hai hoặc backtick cho các bí danh nhưng điều đó có thể bị ảnh hưởng bởi các chế độ SQL ANSI khác nhau. Tôi không chắc chắn thông số kỹ thuật SQL yêu cầu trích dẫn bí danh - Sở thích cá nhân: để thống nhất tôi trích dẫn chúng giống như định danh cột - nghĩa là tôi sẽ sao lưu chúng nếu cần hoặc không bỏ qua chúng nếu không. Tôi không sử dụng dấu ngoặc đơn hoặc kép trên bí danh.
Michael Berkowski

2
@GuneyOzsan Vâng, rất dễ bị tổn thương. Không bao giờ sử dụng biến cho tên bảng trừ khi nó được xác thực theo danh sách tên bảng có thể chấp nhận - tạo một mảng tên cho phép và kiểm tra biến đó khớp với thứ gì đó trong danh sách để đảm bảo an toàn khi sử dụng. Nếu không, bạn không thể thoát một cách an toàn một biến tên bảng để sử dụng.
Michael Berkowski

121

Có hai loại trích dẫn trong MySQL:

  1. ' để kèm theo chuỗi ký tự
  2. ` để kèm theo các định danh như tên bảng và cột

Và sau "đó là một trường hợp đặc biệt. Nó có thể được sử dụng cho một trong những mục đích nêu trên tại một thời điểm tùy thuộc vào máy chủ MySQL sql_mode:

  1. Theo mặc định , "ký tự có thể được sử dụng để bao quanh chuỗi ký tự giống như'
  2. Trong ANSI_QUOTESchế độ, "ký tự có thể được sử dụng để gửi kèm mã định danh giống như`

Truy vấn sau đây sẽ tạo ra các kết quả (hoặc lỗi) khác nhau tùy thuộc vào chế độ SQL:

SELECT "column" FROM table WHERE foo = "bar"

ANSI_QUOTES bị vô hiệu hóa

Truy vấn sẽ chọn chuỗi ký tự "column"trong đó cột foobằng chuỗi"bar"

Đã bật ANSI_QUOTES

Truy vấn sẽ chọn cột columntrong đó cột foobằng cộtbar

Khi nào thì sử dụng những gì

  • Tôi khuyên bạn nên tránh sử dụng "để mã của bạn trở nên độc lập với các chế độ SQL
  • Luôn luôn trích dẫn định danh vì nó là một thực hành tốt (khá một vài câu hỏi về SO thảo luận này)

32

(Có những câu trả lời hay ở trên liên quan đến bản chất SQL của câu hỏi của bạn, nhưng điều này cũng có thể có liên quan nếu bạn chưa quen với PHP.)

Có lẽ điều quan trọng là đề cập đến PHP xử lý đơn và đôi trích dẫn chuỗi khác nhau ...

Các chuỗi trích dẫn đơn là 'chữ' và là các chuỗi WYSIWYG khá nhiều. Các chuỗi trích dẫn kép được PHP diễn giải để thay thế biến có thể xảy ra (backticks trong PHP không phải là chuỗi chính xác; chúng thực thi một lệnh trong shell và trả về kết quả).

Ví dụ:

$foo = "bar";
echo 'there is a $foo'; // There is a $foo
echo "there is a $foo"; // There is a bar
echo `ls -l`; // ... a directory list

23

Backticks thường được sử dụng để chỉ ra identifiervà cũng như an toàn khi vô tình sử dụng Từ khóa dành riêng .

Ví dụ:

Use `database`;

Ở đây, backticks sẽ giúp máy chủ hiểu rằng databasetrên thực tế tên của cơ sở dữ liệu, không phải là định danh cơ sở dữ liệu.

Tương tự có thể được thực hiện cho tên bảng và tên trường. Đây là một thói quen rất tốt nếu bạn bọc định danh cơ sở dữ liệu của mình bằng backticks.

Kiểm tra câu trả lời này để hiểu thêm về backticks.


Bây giờ về dấu ngoặc kép & dấu ngoặc đơn (Michael đã đề cập đến điều đó).

Nhưng, để xác định một giá trị, bạn phải sử dụng dấu ngoặc đơn hoặc dấu ngoặc kép. Hãy xem một ví dụ khác.

INSERT INTO `tablename` (`id, `title`) VALUES ( NULL, title1);

Ở đây tôi đã cố tình quên để bọc title1với dấu ngoặc kép. Bây giờ, máy chủ sẽ lấy title1tên cột (tức là định danh). Vì vậy, để chỉ ra rằng đó là một giá trị bạn phải sử dụng dấu ngoặc kép hoặc dấu ngoặc đơn.

INSERT INTO `tablename` (`id, `title`) VALUES ( NULL, 'title1');

Bây giờ, kết hợp với PHP, dấu ngoặc kép và dấu ngoặc đơn làm cho thời gian viết truy vấn của bạn dễ dàng hơn nhiều. Hãy xem phiên bản sửa đổi của truy vấn trong câu hỏi của bạn.

$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, '$val1', '$val2')";

Bây giờ, bằng cách sử dụng dấu ngoặc kép trong PHP, bạn sẽ tạo các biến $val1$val2để sử dụng các giá trị của chúng do đó tạo ra một truy vấn hoàn toàn hợp lệ. Giống

$val1 = "my value 1";
$val2 = "my value 2";
$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, '$val1', '$val2')";

sẽ làm

INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, 'my value 1', 'my value 2')

15

Trong MySQL, các biểu tượng này được sử dụng để phân định một truy vấn `, ", '().

  1. "hoặc 'được sử dụng để bao quanh chuỗi giống như giá trị "26-01-2014 00:00:00"hoặc '26-01-2014 00:00:00'. Những biểu tượng này chỉ dành cho các chuỗi, chức năng không tổng hợp thích now, sumhoặc max.

  2. ` được sử dụng để kèm theo tên bảng hoặc cột, vd select `column_name` from `table_name` where id='2'

  3. ()chỉ đơn giản là bao gồm các phần của một truy vấn, ví dụ select `column_name` from `table_name` where (id='2' and gender='male') or name='rakesh'.


13

Các chuỗi ký tự trong MySQL và PHP là như nhau.

Chuỗi là một chuỗi các byte hoặc ký tự, được đặt trong một ký tự đơn (trích dẫn) hoặc dấu ngoặc kép (ký hiệu ").

Vì vậy, nếu chuỗi của bạn chứa dấu ngoặc đơn, thì bạn có thể sử dụng dấu ngoặc kép để trích dẫn chuỗi hoặc nếu chuỗi chứa dấu ngoặc kép, thì bạn có thể sử dụng dấu ngoặc đơn để trích dẫn chuỗi. Nhưng nếu chuỗi của bạn chứa cả dấu ngoặc đơn và dấu ngoặc kép, bạn cần thoát khỏi chuỗi được sử dụng để trích dẫn chuỗi.

Hầu hết, chúng tôi sử dụng các trích dẫn đơn cho một giá trị chuỗi SQL, vì vậy chúng tôi cần sử dụng dấu ngoặc kép cho chuỗi PHP.

$query = "INSERT INTO table (id, col1, col2) VALUES (NULL, 'val1', 'val2')";

Và bạn có thể sử dụng một biến trong chuỗi trích dẫn kép của PHP:

$query = "INSERT INTO table (id, col1, col2) VALUES (NULL, '$val1', '$val2')";

Nhưng nếu $val1hoặc $val2chứa các trích dẫn đơn, điều đó sẽ làm cho SQL của bạn bị sai. Vì vậy, bạn cần phải thoát nó trước khi nó được sử dụng trong sql; đó là những gì mysql_real_escape_stringdành cho. (Mặc dù một tuyên bố chuẩn bị là tốt hơn.)


12

Kết hợp giữa PHP và MySQL, dấu ngoặc kép và dấu ngoặc đơn làm cho thời gian viết truy vấn của bạn dễ dàng hơn nhiều.

$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, '$val1', '$val2')";

Bây giờ, giả sử bạn đang sử dụng biến bài đăng trực tiếp vào truy vấn MySQL, hãy sử dụng nó theo cách này:

$query = "INSERT INTO `table` (`id`, `name`, `email`) VALUES (' ".$_POST['id']." ', ' ".$_POST['name']." ', ' ".$_POST['email']." ')";

Đây là cách thực hành tốt nhất để sử dụng các biến PHP vào MySQL.


Do đó, dấu ngoặc kép rất linh hoạt nhưng không thể được sử dụng làm định danh.
rhavendc

Vui lòng không bao giờ trực tiếp sử dụng đầu vào người dùng không thoát khỏi truy vấn của bạn!
jankal

@jankal Nó chỉ example.I quy định rằng nếu bạn đang sử dụng đầu vào người sử dụng trực tiếp sau đó n rồi ...........
Vipul sorathiya

@vipulsorathiya Vui lòng xác định trong câu trả lời của bạn rằng các biến POST nên được thoát. Bây giờ bạn đang chỉ vào việc sử dụng chúng trực tiếp trong truy vấn của bạn.
Thật

12

Đã có nhiều câu trả lời hữu ích ở đây, nói chung đạt đến hai điểm.

  1. BACKTICKS (`) được sử dụng xung quanh tên định danh.
  2. SINGLE QUOTES (') được sử dụng xung quanh các giá trị.

VÀ như @MichaelBerkowski đã nói

Backticks được sử dụng cho mã định danh bảng và cột, nhưng chỉ cần thiết khi mã định danh là MySQLtừ khóa dành riêng hoặc khi mã định danh chứa các ký tự khoảng trắng hoặc ký tự nằm ngoài một bộ giới hạn (xem bên dưới) Nên tránh sử dụng các từ khóa dành riêng như định danh cột hoặc bảng khi có thể, tránh vấn đề trích dẫn.

Có một trường hợp mặc dù một định danh không thể là một từ khóa dành riêng hoặc chứa khoảng trắng hoặc các ký tự vượt quá giới hạn nhưng nhất thiết phải yêu cầu backticks xung quanh chúng.

THÍ DỤ

123E10là một cái tên định danh hợp lệ mà còn là một giá trị INTEGERvăn chương.

[Không đi sâu vào chi tiết làm thế nào bạn có được một tên định danh như vậy], Giả sử tôi muốn tạo một bảng tạm thời có tên 123456e6.

Không có LRI trên backticks.

DB [XXX]> create temporary table `123456e6` (`id` char (8));
Query OK, 0 rows affected (0.03 sec)

LRI khi không sử dụng backticks.

DB [XXX]> create temporary table 123451e6 (`id` char (8));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '123451e6 (`id` char (8))' at line 1

Tuy nhiên, 123451a6là một tên định danh hoàn toàn tốt (không có dấu lại).

DB [XXX]> create temporary table 123451a6 (`id` char (8));
Query OK, 0 rows affected (0.03 sec)

Điều này là hoàn toàn bởi vì 1234156e6cũng là một số mũ.


10

Nếu bảng cols và giá trị là biến thì có hai cách:

Với dấu ngoặc kép "", truy vấn đầy đủ:

$query = "INSERT INTO $table_name (id, $col1, $col2)
                 VALUES (NULL, '$val1', '$val2')";

Hoặc là

 $query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.")
               VALUES (NULL, '".$val1."', '".$val2."')";

Với dấu ngoặc đơn '':

$query = 'INSERT INTO '.$table_name.' (id, '.$col1.', '.$col2.')
             VALUES (NULL, '.$val1.', '.$val2.')';

Sử dụng đánh dấu lại ``khi tên cột / giá trị tương tự như từ khóa dành riêng cho MySQL.

Lưu ý: Nếu bạn đang biểu thị một tên cột bằng tên bảng thì hãy sử dụng đánh dấu lại như thế này:

`table_name`. `column_name` <- Lưu ý: loại trừ . khỏi dấu tích ngược.


8

Dấu nháy đơn nên được sử dụng cho các giá trị chuỗi như trong VALUES) danh sách (.

Backticks thường được sử dụng để chỉ định danh và cũng như an toàn khi vô tình sử dụng các từ khóa dành riêng.

Kết hợp giữa PHP và MySQL, dấu ngoặc kép và dấu ngoặc đơn làm cho thời gian viết truy vấn của bạn dễ dàng hơn nhiều.


4

Bên cạnh tất cả các câu trả lời (được giải thích rõ), không có câu trả lời nào được đề cập sau đây và tôi thường xuyên truy cập Câu hỏi này.

Tóm lại; MySQL nghĩ rằng bạn muốn làm toán trên bảng / cột của riêng mình và diễn giải các dấu gạch nối như "e-mail" là e dấu trừ mail .


Tuyên bố miễn trừ trách nhiệm: Vì vậy, tôi nghĩ rằng tôi sẽ thêm câu này dưới dạng câu trả lời "FYI" cho những người hoàn toàn mới làm việc với cơ sở dữ liệu và những người có thể không hiểu các thuật ngữ kỹ thuật được mô tả.


1

Các máy chủ SQL và MySQL, PostgreySQL, Oracle không hiểu dấu ngoặc kép ("). Do đó, truy vấn của bạn không được có dấu ngoặc kép (") và chỉ nên sử dụng dấu ngoặc đơn (').

Back-trip (`) là tùy chọn để sử dụng trong SQL và được sử dụng cho tên bảng, tên db và tên cột.

Nếu bạn đang cố gắng viết truy vấn vào back-end của mình để gọi MySQL thì bạn có thể sử dụng dấu ngoặc kép (") hoặc dấu ngoặc đơn (') để gán truy vấn cho một biến như:

let query = "select id, name from accounts";
//Or
let query = 'select id, name from accounts';

Nếu một wherecâu lệnh trong truy vấn của bạn và / hoặc cố gắng insertmột giá trị và / hoặc một updategiá trị là chuỗi, hãy sử dụng một trích dẫn (') cho các giá trị này như:

let querySelect = "select id, name from accounts where name = 'John'";
let queryUpdate = "update accounts set name = 'John' where id = 8";
let queryInsert = "insert into accounts(name) values('John')";

//Please not that double quotes are only to be used in assigning string to our variable not in the query
//All these below will generate error

let querySelect = 'select id, name from accounts where name = "John"';
let queryUpdate = 'update accounts set name = "John" where id = 8';
let queryInsert = 'insert into accounts(name) values("John")';

//As MySQL or any SQL doesn't understand double quotes("), these all will generate error.

Nếu bạn muốn tránh xa sự nhầm lẫn này khi sử dụng dấu ngoặc kép (") và dấu ngoặc đơn ('), bạn nên sử dụng dấu ngoặc đơn ('), điều này sẽ bao gồm dấu gạch chéo ngược () như:

let query = 'select is, name from accounts where name = \'John\'';

Vấn đề với dấu ngoặc kép (") hoặc dấu ngoặc đơn (') phát sinh khi chúng ta phải gán một số giá trị động và thực hiện một số nối chuỗi như:

let query = "select id, name from accounts where name = " + fName + " " + lName;
//This will generate error as it must be like name = 'John Smith' for SQL
//However our statement made it like name = John Smith

//In order to resolve such errors use
let query = "select id, name from accounts where name = '" + fName + " " + lName + "'";

//Or using backslash(\)
let query = 'select id, name from accounts where name = \'' + fName + ' ' + lName + '\'';

Nếu cần giải phóng mặt bằng, hãy làm theo các trích dẫn trong JavaScript

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.