Kiedy używać pojedynczych cudzysłowów, podwójnych cudzysłowów i odwrotnych znaków w MySQL

633

Próbuję nauczyć się najlepszego sposobu pisania zapytań. Rozumiem także znaczenie zachowania spójności. Do tej pory losowo używałem pojedynczych cudzysłowów, podwójnych cudzysłowów i odwrotnych zwrotów bez jakiejkolwiek realnej myśli.

Przykład:

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

Ponadto, w powyższym przykładzie, uważają, że table, col1, val1, itd. Mogą być zmienne.

Jaki jest na to standard? Co robisz?

Czytam tutaj odpowiedzi na podobne pytania przez około 20 minut, ale wydaje się, że nie ma ostatecznej odpowiedzi na to pytanie.

Nate
źródło
16
Zauważ, że jest to bardzo specyficzne pytanie dotyczące MySQL. SQL ogólnie (tj. ISO / ANSI SQL) ma inny zestaw cudzysłowów: podwójne cudzysłowy są dla ograniczonych identyfikatorów, np. "tablename"Pojedyncze cudzysłowy są dla literałów, np 'this is a some text'. Znaczniki wsteczne nigdy nie są używane w standardowym języku SQL. (Jeśli chcesz podać podwójny cudzysłów w identyfikatorze, wpisz go dwa razy jako "odd""tablename". Podobnie, podwójne pojedyncze cudzysłowy w literałach, jak 'Conan O''Brien'.)
jarlh

Odpowiedzi:

609

Znaki wsteczne należy stosować do identyfikatorów tabeli i kolumny, ale są one konieczne tylko wtedy, gdy identyfikator jest słowem kluczowym zastrzeżonym MySQL lub gdy identyfikator zawiera znaki spacji lub znaki spoza ograniczonego zestawu (patrz poniżej) Często zaleca się unikanie używania zastrzeżonych słów kluczowych w miarę możliwości jako identyfikatory kolumn lub tabel, unikając problemu cytowania.

W przypadku ciągów znaków, takich jak na VALUES()liście, należy używać pojedynczych cudzysłowów . Podwójne cudzysłowy są obsługiwane przez MySQL również dla wartości ciągów, ale pojedyncze cudzysłowy są szerzej akceptowane przez inne RDBMS, więc dobrym zwyczajem jest stosowanie pojedynczych cudzysłowów zamiast podwójnych.

MySQL oczekuje także DATEi DATETIMEwartości literalne być jedno-cytowany jako ciągi znaków, takich jak '2001-01-01 00:00:00'. Zapoznaj się z dokumentacją literatury daty i godziny, aby uzyskać więcej szczegółów, w szczególności alternatywy dla używania łącznika -jako ogranicznika segmentu w ciągach daty.

Korzystając z twojego przykładu, zacytowałbym podwójnie ciąg PHP i użyłem pojedynczych cudzysłowów na wartościach 'val1', 'val2'. NULLjest słowem kluczowym MySQL i specjalną (nie) wartością, dlatego nie jest cytowany.

Żaden z tych identyfikatorów tabeli lub kolumny nie jest słowem zastrzeżonym ani nie wykorzystuje znaków wymagających cytowania, ale i tak zacytowałem je za pomocą odwrotnych znaków (więcej o tym później ...).

Funkcje rodzime dla RDBMS (na przykład NOW()w MySQL) nie powinny być cytowane, chociaż ich argumenty podlegają tym samym regułom cytowania ciągów znaków lub identyfikatorów, o których już wspomniano.

Backtick (`)
tabela i kolumna ───────┬─────┬──┬──┬──┬────┬──┬────┬──┬────┬──┬ ───────┐
                      ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
$ query = " INSERT INTO` table` (`id`,` col1`, `col2`,` date`, `updated`)
                       WARTOŚCI (NULL, „val1”, „val2”, „2001-01-01”, NOW ()) ”;
                               ↑↑↑↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑↑↑ frazy 
Niecytowane słowo kluczowe ─────┴┴┴┘ │ │ │ │ │ │ │││││
Ciągi pojedynczego cudzysłowu (') ───────────┴────┴──┴────┘ │ │ │││││
Pojedynczy cytat (') DATA ───────────────────────────┴──────────┘ ││││ │
Niecytowana funkcja ─────────────────────────────────────────┴┴┴┴┘    

Zmienna interpolacja

Wzory cytowania dla zmiennych nie zmieniają się, chociaż jeśli zamierzasz interpolować zmienne bezpośrednio w ciągu, musi być on podwójnie cytowany w PHP. Po prostu upewnij się, że poprawnie zmieniłeś znaczenia zmiennych do użycia w SQL. ( Zalecane jest użycie zamiast tego interfejsu API obsługującego przygotowane instrukcje, jako zabezpieczenia przed wstrzyknięciem SQL ).

// To samo z niektórymi zamiennikami zmiennych
// Tutaj nazwa tabeli zmiennych $ table jest cytowana z powrotem i zmienne
// na liście WARTOŚCI są pojedynczymi cudzysłowami 
$ query = "INSERT INTO` $ table` (`id`,` col1`, `col2`,` date`) VALUES (NULL, '$ val1' , '$ val2' , '$ date' ) ";

Przygotowane wyciągi

Podczas pracy z przygotowanymi wyciągami zapoznaj się z dokumentacją, aby ustalić, czy należy wstawić symbole zastępcze wyciągów. Najbardziej popularnym API dostępne w PHP, PDO i MySQLi spodziewać nienotowanych zastępcze, jak większość przygotowanych API oświadczenie w innych językach:

// 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 (?, ?, ?, ?)";

Znaki wymagające cytowania wstecznego w identyfikatorach:

Zgodnie z dokumentacją MySQL nie trzeba cytować identyfikatorów (backtick) przy użyciu następującego zestawu znaków:

ASCII: [0-9,a-z,A-Z$_](podstawowe litery łacińskie, cyfry 0–9, dolar, podkreślenie)

Możesz użyć znaków poza tym zestawem jako identyfikatorów tabeli lub kolumn, w tym na przykład białych znaków, ale musisz je zacytować (cofnąć).

Michał Berkowski
źródło
43
ale pojedyncze cudzysłowy są szerzej akceptowane przez inne RDBMS ” - użycie pojedynczych cudzysłowów dla literałów łańcuchowych jest zdefiniowane (i wymagane) przez standard SQL
a_horse_w_na_nazną
@ a_horse_w_na_nazwie prawie nikt nie używa ANSI MySQL ('|' dla konkatru znaków - naprawdę?)
Good Person
3
to nie jest prawda: „MySQL oczekuje również, że wartości literalne DATA i DATETIME będą cytowane jako ciągi znaków takie jak„ 2001-01-01 00:00:00 ””
Kick_the_BUCKET
3
@evilReiko Dokumenty MySQL nie wydają się wyraźnie odnosić się do aliasów. Przyjmie pojedynczy, podwójny lub wsteczny dla aliasów, ale mogą mieć na to wpływ różne tryby ANSI SQL. Nie jestem pewien, czego wymaga specyfikacja SQL dla cudzysłowów aliasowych - Preferencje osobiste: dla spójności cytuję je tak samo jak identyfikatory kolumn - to znaczy albo je zaznaczam, jeśli to konieczne, albo zostawiam bez cudzysłowu, jeśli nie. Nie używam pojedynczych lub podwójnych cudzysłowów w aliasach.
Michał Berkowski
2
@GuneyOzsan Tak, bardzo wrażliwy. Nigdy nie używaj zmiennej dla nazwy tabeli, chyba że została ona zweryfikowana na liście dopuszczalnych nazw tabel - utwórz tablicę dopuszczalnych nazw i sprawdź, czy zmienna pasuje do czegoś na liście, aby była bezpieczna w użyciu. W przeciwnym razie nie będzie można bezpiecznie użyć zmiennej nazwy tabeli do użycia.
Michael Berkowski
121

Istnieją dwa typy cytatów w MySQL:

  1. ' do dołączania literałów łańcuchowych
  2. ` do dołączania identyfikatorów, takich jak nazwy tabel i kolumn

I "jest jeszcze jeden przypadek szczególny. Może być używany jednocześnie do jednego z wyżej wymienionych celów, w zależności od serwera MySQL sql_mode:

  1. Domyślnie" postać może być stosowane do osłaniania literały ciągów podobnie jak'
  2. W ANSI_QUOTEStrybie "znak może być używany do otaczania identyfikatorów podobnie jak`

Poniższe zapytanie spowoduje wygenerowanie różnych wyników (lub błędów) w zależności od trybu SQL:

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

ANSI_QUOTES wyłączone

Zapytanie wybierze literał ciągu, w "column"którym kolumna foojest równa łańcuchowi"bar"

Włączono ANSI_QUOTES

Zapytanie wybierze kolumnę, w columnktórej kolumna foojest równa kolumniebar

Kiedy używać czego

  • Sugeruję, aby unikać używania ", aby twój kod stał się niezależny od trybów SQL
  • Zawsze podawaj identyfikatory, ponieważ jest to dobra praktyka (sporo pytań na temat SO omawia to)
Salman A.
źródło
32

(Powyżej są dobre odpowiedzi dotyczące natury SQL twojego pytania, ale może to być również istotne, jeśli nie znasz PHP.)

Być może warto wspomnieć, że PHP obsługuje łańcuchy jedno- i podwójnie cudzysłowy inaczej ...

Ciągi cytowane są „literałami” i są właściwie ciągami WYSIWYG. Łańcuchy z podwójnym cudzysłowem są interpretowane przez PHP pod kątem możliwego podstawienia zmiennych (backticks w PHP nie są dokładnie łańcuchami; wykonują polecenie w powłoce i zwracają wynik).

Przykłady:

$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
Chris Trahey
źródło
23

Wsteczne są zwykle używane do wskazania identifieri, jak również, są bezpieczne przed przypadkowym użyciem Zarezerwowanych słów kluczowych .

Na przykład:

Use `database`;

W tym przypadku backticks pomoże serwerowi zrozumieć, że databasew rzeczywistości jest to nazwa bazy danych, a nie identyfikator bazy danych.

To samo można zrobić dla nazw tabel i nazw pól. Jest to bardzo dobry nawyk, jeśli otacza się identyfikator bazy danych backtickami.

Sprawdź odpowiedź, aby dowiedzieć się więcej o backticksach.


Teraz o podwójnych cytatach i pojedynczych cytatach (Michael już o tym wspomniał).

Ale aby zdefiniować wartość, musisz użyć pojedynczego lub podwójnego cudzysłowu. Zobaczmy inny przykład.

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

Tutaj celowo zapomniałem zawrzeć title1cytaty. Teraz serwer przyjmie title1jako nazwę kolumny (tj. Identyfikator). Aby wskazać, że jest to wartość, musisz użyć podwójnego lub pojedynczego cudzysłowu.

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

Teraz, w połączeniu z PHP, podwójne cudzysłowy i pojedyncze cudzysłowy znacznie ułatwiają pisanie zapytań. Zobaczmy zmodyfikowaną wersję zapytania w twoim pytaniu.

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

Teraz, używając podwójnych cudzysłowów w PHP, utworzysz zmienne $val1i $val2użyjesz ich wartości, tworząc w ten sposób idealnie poprawne zapytanie. Lubić

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

zrobi

INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, 'my value 1', 'my value 2')
Starx
źródło
15

MySQL, symbole te są wykorzystywane do oddzielania zapytanie `, ", 'i ().

  1. "lub 'są używane do dołączania wartości podobnych do łańcucha "26-01-2014 00:00:00"lub '26-01-2014 00:00:00'. Symbole te są tylko dla ciągi, funkcje zagregowane nie podoba now, sumalbo max.

  2. ` służy do dołączania nazw tabel lub kolumn, np select `column_name` from `table_name` where id='2'

  3. (i )po prostu dołącz części zapytania, np select `column_name` from `table_name` where (id='2' and gender='male') or name='rakesh'.

Kumar Rakesh
źródło
13

Literały łańcuchowe w MySQL i PHP są takie same.

Ciąg jest sekwencją bajtów lub znaków, zawartą w znakach pojedynczego cudzysłowu („” ”) lub podwójnego cudzysłowu („ ””).

Więc jeśli ciąg zawiera pojedyncze cudzysłowy, możesz użyć podwójnych cudzysłowów, aby zacytować ciąg, lub jeśli zawiera podwójne cudzysłowy, możesz użyć pojedynczych cudzysłowów, aby zacytować ciąg. Ale jeśli ciąg zawiera zarówno pojedyncze cudzysłowy, jak i podwójne cudzysłowy, musisz uciec od tego, który był używany do cytowania tego ciągu.

Najczęściej używamy pojedynczych cudzysłowów dla wartości ciągu SQL, więc musimy używać podwójnych cudzysłowów dla ciągu PHP.

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

I możesz użyć zmiennej w podwójnie cytowanym ciągu PHP:

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

Ale jeśli $val1lub $val2zawiera pojedyncze cudzysłowy, spowoduje to, że SQL będzie niepoprawny. Więc musisz uciec przed użyciem go w sql; po to mysql_real_escape_stringjest. (Chociaż przygotowane oświadczenie jest lepsze.)

xdazz
źródło
12

W połączeniu z PHP i MySQL podwójne cudzysłowy i pojedyncze cudzysłowy znacznie ułatwiają pisanie zapytań.

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

Załóżmy teraz, że używasz zmiennej post post do zapytania MySQL, użyj go w następujący sposób:

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

Jest to najlepsza praktyka wykorzystywania zmiennych PHP w MySQL.

vipul sorathiya
źródło
Dlatego podwójne cudzysłowy są elastyczne, ale nie mogą być używane jako identyfikatory.
rhavendc
Nigdy nie używaj bezpośrednio w zapytaniu danych nieskrytych!
jankal
@jankal To tylko przykład. Podałem, że jeśli używasz bezpośredniego wprowadzania danych przez użytkownika, to n, a następnie ...........
vipul sorathiya 28.12.2016
@vipulsorathiya Podaj w odpowiedzi, że zmienne POST powinny być zmienione. Teraz wskazujesz na użycie ich bezpośrednio w zapytaniu. Złe dla początkujących, którzy próbują tego ...
RFLdev
12

Było tu wiele pomocnych odpowiedzi, których kulminacją są dwa punkty.

  1. BACKTICKS (`) są używane wokół nazw identyfikatorów.
  2. POJEDYNCZE CYTATY (') są używane wokół wartości.

ORAZ jak powiedział @MichaelBerkowski

Znaki wsteczne należy stosować do identyfikatorów tabeli i kolumny, ale są one konieczne tylko wtedy, gdy identyfikator jest MySQLzastrzeżonym słowem kluczowym lub gdy identyfikator zawiera znaki spacji lub znaki poza ograniczonym zestawem (patrz poniżej) Często zaleca się unikanie używania zastrzeżonych słów kluczowych jako identyfikatory kolumn lub tabel, jeśli to możliwe, unikając problemu cytowania.

Zdarzają się jednak przypadki, w których identyfikator nie może być zastrzeżonym słowem kluczowym ani zawierać białych znaków lub znaków poza ograniczonym zestawem, ale koniecznie wymaga od nich odwrotnych znaków .

PRZYKŁAD

123E10to poprawna nazwa identyfikatora, ale także poprawna INTEGERliterał.

[Nie wchodząc w szczegóły, w jaki sposób uzyskasz taką nazwę identyfikatora], Załóżmy, że chcę utworzyć tymczasową tabelę o nazwie 123456e6.

Brak BŁĘDU w backticks.

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

BŁĄD, gdy nie używa się backicks.

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

Jednak 123451a6jest perfekcyjnie nazwa identyfikator (bez tylnych kleszczy).

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

Dzieje się tak całkowicie, ponieważ 1234156e6jest to również liczba wykładnicza.

MJ007
źródło
10

Jeśli tabela cols i wartości są zmiennymi, istnieją dwa sposoby:

W przypadku podwójnych cytatów ""pełne zapytanie:

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

Lub

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

Z pojedynczymi cytatami '':

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

Użyj znaczników wstecz, ``gdy nazwa kolumny / wartości jest podobna do słowa kluczowego zastrzeżonego MySQL.

Uwaga: jeśli oznaczasz nazwę kolumny nazwą tabeli, użyj tylnych znaczników w następujący sposób:

`table_name`. `column_name` <- Uwaga: wyklucz . z tyknięć.

diEcho
źródło
8

W przypadku ciągów znaków, takich jak na liście VALUES (), należy używać pojedynczych cudzysłowów.

Znaki wsteczne są zwykle używane do wskazania identyfikatora, a także zabezpieczają przed przypadkowym użyciem zastrzeżonych słów kluczowych.

W połączeniu z PHP i MySQL podwójne cudzysłowy i pojedyncze cudzysłowy znacznie ułatwiają pisanie zapytań.

John Igneel
źródło
4

Poza wszystkimi (dobrze wyjaśnionymi) odpowiedziami nie wymieniono poniższych pytań i często odwiedzam to pytanie.

W skrócie; MySQL myśli, że chcesz robić matematykę na własnej tabeli / kolumnie i interpretuje łączniki, takie jak „e-mail”, jako e minus mail .


Zastrzeżenie: Pomyślałem więc, że dodam to jako odpowiedź „FYI” dla tych, którzy są zupełnie nowi w pracy z bazami danych i mogą nie rozumieć już opisanych terminów technicznych.

Funk Forty Niner
źródło
1

Serwery SQL i MySQL, PostgreySQL, Oracle nie rozumieją podwójnych cudzysłowów („). Dlatego twoje zapytanie powinno być wolne od podwójnych cudzysłowów (”) i powinno używać tylko pojedynczych cudzysłowów (').

Podróż powrotna (`) jest opcjonalna do użycia w SQL i jest używana dla nazwy tabeli, nazwy bazy danych i nazw kolumn.

Jeśli próbujesz napisać zapytanie w swoim zapleczu, aby wywołać MySQL, możesz użyć podwójnego cudzysłowu („) lub pojedynczego cudzysłowu ('), aby przypisać zapytanie do zmiennej, takiej jak:

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

Jeśli wherew zapytaniu znajduje się instrukcja i / lub próba insertuzyskania wartości i / lub updatewartości, która jest łańcuchem, użyj pojedynczego cudzysłowu (') dla takich wartości, jak:

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.

Jeśli chcesz uniknąć tego zamieszania, gdy używasz podwójnych cudzysłowów („) i pojedynczych cudzysłowów ('), zalecamy trzymanie się pojedynczych cudzysłowów ('), będzie to obejmować odwrotny ukośnik (), taki jak:

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

Problem z podwójnymi („) lub pojedynczymi (”) cudzysłowami powstaje, gdy musieliśmy przypisać pewną wartość dynamiczną i wykonać pewne połączenie łańcuchowe, takie jak:

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 + '\'';

W razie potrzeby postępuj zgodnie z cytatami w JavaScript

NAVIN
źródło