I would like to use reserved words such as "user" or "right" as table or column names in my databases. Until now I've been using back quotes, but I read somewhere that they are MySQL specific, and I would like to preserve database compatibility. I've also read about using ANSI mode with MySQL to avoid using back quotes, but I want everything in my apps to be UTF-8.
What can I do to use reserved words without using back quotes or losing cross database compatibility ?
MySQL supports the ANSI standard of using double quotes surrounding identifiers such as table and column names. You have to enable this option since by default MySQL recognizes both single and double quotes as enclosing string literals:
http://dev.mysql.com/doc/refman/5.1/en/server-sql-mode.html#sqlmode_ansi_quotes
Related
Is there a way to handle reserved table & column names in your app which can work through all kinds of databases like Oracle, MySQL, SQL Server, PostGreSQL etc.
Currently, I have to do the following :
Oracle - use double quotes.
MySQL - Use backtick or double quotes (depends if ANSI_QUOTES mode is enabled)
SQL Server - Use brackets
PostGreSQL - use double quotes.
I am aware that ANSI standard states to use double quotes but unfortunately not all dbms seem to support them.
Use double quotes. That's what the standard says, and surprisingly, it actually works on most platforms.
Require that MySQL have ANSI_QUOTES enabled, or set it at the session level:
SET SESSION sql_mode = 'ANSI'
(I used ANSI not just ANSI_QUOTES here because it makes MySQL generally a bit saner).
PostgreSQL doesn't require any special settings for identifiers (though very old versions need standard_conforming_strings = on to handle literals sensibly).
Neither does Oracle.
Modern MS-SQL shouldn't require any special settings to support double quoted identifiers:
When SET QUOTED_IDENTIFIER is ON (default), all strings delimited by double quotation marks are interpreted as object identifiers
The docs suggest that was the case in MS-SQL 2008, and if you still care about 2005 in a new application you have bigger problems.
SQLFiddles:
MySQL
MS-SQL 2008
Oracle 11g R2
Interestingly, I found that the SQLFiddle for PostgreSQL failed with an odd error. I suspect an SQLFiddle bug, as it's fine on the PostgreSQL command line and via PgJDBC. It fails with there is no table that match the following pattern [with].
All that said, if you're seriously trying to write ANSI SQL, I hope you don't plan on using:
Date/time maths
String concatenation
Non-trivial aggregates
Window functions (MySQL still doesn't support them)
Common table expressions
SQL/XML
Arbitrary precision decimal data types
Any kind of user defined procedure or function
Any kind of user-defined type
... lots more
because different vendors use different names, have different support for features, etc.
(On a side note, if I ever meet the person who decided to call Microsoft SQL Server "SQL" in a dark alley...)
I have used backticks (`) in some SELECT queries to escape fields such as 'first-name'. This will work on MySQL. These queries are run through a DBO class in a php application and I would like the application to be able to use other database servers, such as MSSQL and Posgres.
What is the best approach for allowing problematic field names to be used across all of these database servers? I was thinking of taking the fields as an array and quoting them with the escaping character that is appropriate to each.
[EDIT]
To clarify: I am building a tool that will be used to map configurations stored within the php application to the fields of an external database. I wanted to escape these as a precaution because I have no idea what field names will actually be mapped to and used within the queries.
The solution is very simple: do not use reserved words as identifiers. It makes the code more difficult to read anyways.
If you really need to use such words (as in "there is some obscure reason beyond your control"), you can just prefix all your identifiers by an arbitrary character, such as _ for example.
The cross-DBMS mechanism (as defined in SQL-92 and other standards) is using double-quoted delimited identifiers. According to this reference it's widely supported.
It's worth nothing that MySQL allows to enable/disable this syntax so you still need to ensure that session settings are correct before issuing any query.
MySQL uses backticks (`) by default, but can be configured to support proper ANSI quoting.
IMO: If you're connecting to MySQL, set it to ANSI mode, and while you're at it enable every STRICT option it has. It becomes much easier to write code that's portable against it then.
Of course, the best option has to be not using reserved words, but the list of reserved words can change over time so rigorous quoting isn't such a bad idea.
The proper way of escaping is not to use field names that need escaping.
If you still have to use escaping - use ". It is the standard one (defined by ANSI SQL).
Postgres and Oracle understand " escaping. But i do not know about MSSQL an MySQL.
In the following SQL statement, SQLite sorts correctly but MySQL does not:
However, if I don't include the quotation marks around the field names, it works correctly:
Can anyone explain the behavior that MySQL but not SQLite would not sort correctly if a field is defined with quotation marks?
"TotalOrders" (with double quotes) is a constant string - ordering by it doesn't do anything ... in essence you get the unsorted sequence of rows, which might seem to be correctly sorted.
You want
ORDER BY `TotalOrders`
with backticks. which is the column identifier.
In addition to Eugen's answer:
It might be worth noting that this behaviour depends on the configuration of MySQL.
The described behaviour only shows if MySQL is left in the default - non standard compliant configuration.
If it's configured to run in "ANSI mode" the double quotes are not used for string literals but for identifiers (as nearly all other DBMS).
Another solution to the problem would have been to make MySQL comply with the SQL standard by changing the SQL_MODE to "ANSI".
Then standard compliant single quotes are used for literals and the double quotes are used for identifiers.
I thought there would be another question about this but I was unable to find one. In MySQL with PHP I usually encapsulate my field names with backticks to mask any reserved names or characters. However, one of my colleagues has pointed out that this can also be achieved using square brackets. Excluding the fact that the backticks are not compatible with SQL server (apparently), what is the difference? Which should I use?
SELECT `username` FROM `users`
SELECT [username] FROM [users]
SQL Server/T-SQL uses square brackets (as well as MS Access), while MySQL uses backticks.
As far as I know, can turn up in documentation, or use in testing, square brackets are not valid for MySQL. So if you need to enclose a keyword as a table name in SQL Server, use [], and in MySQL use backticks, or double-quotes when ANSI_QUOTES is enabled.
From the documentation:
The identifier quote character is the backtick (“`”):
mysql> SELECT * FROM `select` WHERE `select`.id > 100;
If the ANSI_QUOTES SQL mode is enabled, it is also permissible to quote identifiers within double quotation marks:
mysql> CREATE TABLE "test" (col INT);
ERROR 1064: You have an error in your SQL syntax...
mysql> SET sql_mode='ANSI_QUOTES';
mysql> CREATE TABLE "test" (col INT);
Query OK, 0 rows affected (0.00 sec)
Both are non-standard ways to quote object names that should either be case-sensitive, are a reserved word or contain special characters that are not allowed otherwise.
The standard quoting character for such an identifier is a double quote. To be ANSI SQL compatible, you should use them:
SELECT "username" FROM "users"
But note that quoted identifiers are case-sensitive as per ANSI SQL. However both mentioned products do not obey to this requirement. Whether such an identifier is case-sensitive or not depends on a several (different) configuration settings in MySQL and the database collation in MS SQL Server.
Both DBMS can (and in my opinion should) be configured to accept the ANSI standard quote characters as well.
I would strongly recommend to avoid any object name that requires quoting. Using identifiers that do not require quoting will save you a lot of trouble in the long run.
Does MySQL allows to create database which has dot (.) in its name?
I'm using MySQL 5.1.22.
You can't use the dot in a database name. Also, I'd avoid using it in any identifier. A common convention is to use underscore instead. It will serve the same purpose and will avoid a LOT of confusion. If you do have a good reason for using strange and otherwise-illegal characters in a table or field name, then you have to escape it.
to escape identifiers in MySQL, use the backtick:
SELECT `select`, `some.field name`, `crazy()naming+here`
FROM `my-=+table`
Getting into the habit of backticking all field names regardless of whether you need to is a good practice in my opinion, but that's another story.
You can use . in names from MySQL 5.1.6 according to the documentation.
However, as has been said and will said again, please don't do it. For every problem you think you're solving now you'll be creating five which will bite you later on. Since . is used to qualify names - e.g. database.table or table.column you'll have to quote your database name every time you use it.*
You can do this with backticks:
CREATE TABLE `do.not.do.this` (col INT);
or using double quotes if you set the following option:
SET sql_mode='ANSI_QUOTES';
CREATE TABLE "asking.for.problems" (col INT);
* Not strictly true - you have to quote any character that's not alphanumeric or _ or $ , but . is a particularly troublesome option to have in your names.
Before MySQL 5.1.6, database and table names cannot contain /, \, ., or characters that are not allowed in file names (see 8.2. Schema Object Names).
In versions after 5.1.6 you have to quote your tablename with a backtick (`) - but as others also advised: you shouldn't do this to prevent any unnecessary trouble.
MySQL 5.0.22 doesn't appear to allow it:
% mysqladmin -uroot -pXXX create foo.bar
mysqladmin: CREATE DATABASE failed; error: 'Incorrect database name 'foo.bar''
Even it if it did allow it, I would strongly recommend against it.
At the very least you'd have to escape any reference to that database with backticks in every single query that ever uses it.