Migration quick tips
This section provides migration tips that can help save time as you transition from SQL Server to Aurora MySQL. They address many of the challenges faced by administrators new to Aurora MySQL. Some of these tips describe functional differences in similar features between SQL Server and Aurora MySQL.
Management
-
The concept of a database in MySQL isn’t the same as SQL Server. A database in MySQL is synonymous with schema. For more information, see Databases and Schemas.
-
You can’t create explicit statistics objects in Aurora MySQL. Statistics are collected and maintained for indexes only.
-
The equivalent of
CREATE DATABASE… AS SNAPSHOT OF…in SQL Server resembles Amazon Aurora MySQL-Compatible Edition (Aurora MySQL) Database cloning. However, unlike SQL Server snapshots, which are read-only, Aurora MySQL cloned databases are updatable. -
In Aurora MySQL, database snapshot is equivalent to
BACKUP DATABASE… WITH COPY_ONLYin SQL Server. -
Partitioning in Aurora MySQL supports more partition types than SQL Server. However, be aware that partitioning in Aurora MySQL restricts the use of many other fundamental features such as foreign keys.
-
Partition
SWITCHin SQL Server can be performed between any two partitions of any two tables. In Aurora MySQL, you can onlyEXCHANGEa table partition with a full table. -
Unlike SQL Server statistics, Aurora MySQL doesn’t collect detailed key value distribution; it relies on selectivity only. When troubleshooting runtime, be aware that parameter values are insignificant to plan choices.
SQL
-
Triggers work differently in Aurora MySQL. You can run triggers for each row. The syntax for inserted and deleted for each row is
newandold. They always contain 0, or 1 row. -
You can’t modify triggers in Aurora MySQL using the
ALTERcommand. Drop and replace a trigger instead. -
Aurora MySQL doesn’t support
@@FETCH_STATUSsystem parameter for cursors. When you declare cursors in Aurora MySQL, create an explicitHANDLERobject, which can set a variable based on the row not found in cursor event. For more information, see Stored Procedures. -
To run a stored procedure, use
CALLinstead ofEXECUTE. -
To run a string as a query, use Aurora MySQL Prepared Statements instead of
sp_executesqlorEXECUTE (<String>). -
Aurora MySQL supports
AFTERandBEFOREtriggers. There is no equivalent toINSTEAD OFtriggers. The only difference betweenBEFOREandINSTEAD OFtriggers is that DML statements are applied row by row to the base table when usingBEFOREand doesn’t require an explicit action in the trigger. To make changes to data affected by a trigger, you canUPDATEthe new and old tables; the changes are persisted. -
Aurora MySQL doesn’t support user defined types. Use base types instead and add column constraints as needed.
-
The
CASEkeyword in Aurora MySQL isn’t only a conditional expression as in SQL Server. Depending on the context where it appears, you can useCASEfor flow control similar toIF <condition> BEGIN <Statement block> END ELSE BEGIN <statement block> END. -
In Aurora MySQL, terminate
IFblocks withEND IF. Also, terminateWHILEloops withEND WHILE. The same rule applies toREPEAT—END REPEATandLOOP—END LOOP. -
You can’t deallocate cursors in Aurora MySQL. Closing them provides the same behavior.
-
Aurora MySQL syntax for opening a transaction is
START TRANSACTIONas opposed toBEGIN TRANSACTION.COMMITandROLLBACKare used without theTRANSACTIONkeyword. -
The default isolation level in Aurora MySQL is
REPEATABLE READas opposed toREAD COMMITTEDin SQL Server. By default, it also uses consistent reads similar toREAD COMMITTED SNAPSHOTin SQL Server. -
Aurora MySQL supports Boolean expressions in
SELECTlists using the=operator. In SQL Server,=operators in select lists are used to assign aliases.SELECT Col1 = 1 FROM Tin Aurora MySQL returns a column with the aliasCol1 = 1, and the value 1 for the rows whereCol1 = 1, and 0 for the rows whereCol1 <> 1 OR Col1 IS NULL. -
Aurora MySQL doesn’t use special data types for UNICODE data. All string types may use any character set and any relevant collation including multiple types of character sets not supported by SQL Server such as UTF-8, UTF-32, and so on. A
VARCHARcolumn can be of a UTF-8 character set, and have alatin1_CIcollation for example. Similarly, there is noNprefix for string literals. -
You can define collations at the server, database, and column level similar to SQL Server. You can also define collations at the table level.
-
In SQL Server, you can use the
DELETE <Table Name>syntax omitting theFROMkeyword. This syntax isn’t valid in Aurora MySQL. Add theFROMkeyword to all delete statements. -
UPDATEexpressions in Aurora MySQL are evaluated in order from left to right. This behavior is different from SQL Server and the ANSI standard which require an all at once evaluation. For example, in the statementUPDATE Table SET Col1 = Col1 + 1, Col2 = Col1,Col2is set to the new value ofCol1. The end result is Col1 = Col2. -
In Aurora MySQL, you can use multiple rows with
NULLfor a UNIQUE constraint. In SQL Server, you can use only one row. Aurora MySQL follows the behavior specified in the ANSI standard. -
Although Aurora MySQL supports the syntax for
CHECKconstraints, they are parsed, but ignored. -
Aurora MySQL
AUTO_INCREMENTcolumn property is similar toIDENTITYin SQL Server. However, there is a major difference in the way sequences are maintained. SQL Server caches a set of values in memory and records the last allocation on disk. When the service restarts, some values may be lost, but the sequence continues from where it left off. In Aurora MySQL, each time you restart the service, the seed value toAUTO_INCREMETis reset to one increment interval larger than the largest existing value. Sequence position isn’t maintained across service restarts. -
Parameter names in Aurora MySQL don’t require a preceding "@". You can declare local variables such as
DECLARE MyParam1 INTEGER. -
Parameters that use the @sign don’t have to be declared first. You can assign a value directly, which implicitly declares the parameter. For example,
SET @MyParam = 'A'. -
The local parameter scope isn’t limited to an run scope. You can define or set a parameter in one statement, run it, and then query it in the following batch.
-
Error handling in Aurora MySQL is called condition handling. It uses explicitly created objects, named conditions, and handlers. Instead of
THROWandRAISERROR, it uses theSIGNALandRESIGNALstatements. -
Aurora MySQL doesn’t support the
MERGEstatement. Use theREPLACEstatement and theINSERT… ON DUPLICATE KEY UPDATEstatement as alternatives. -
In Aurora MySQL, you can’t concatenate strings with the
+operator. In Aurora MySQL,'A' + 'B'isn’t a valid expression. Use theCONCATfunction instead. For example,CONCAT('A', 'B'). -
Aurora MySQL doesn’t support aliasing in the select list using the
'String Alias' = Expression. Aurora MySQL treats it as a logical predicate, returns 0 or FALSE, and will alias the column with the full expression. Use theASsyntax instead. Also note that this syntax has been deprecated as of SQL Server 2008 R2. -
Aurora MySQL doesn’t support using the
DEFAULTkeyword forINSERTstatements. Use explicitNULLinstead. Also note that this syntax has been deprecated as of SQL Server 2008 R2. -
Aurora MySQL has a large set of string functions that is much more diverse than SQL Server. Some of the more useful string functions are:
-
TRIMisn’t limited to full trim or spaces. The syntax isTRIM([{BOTH | LEADING | TRAILING} [<remove string>] FROM] <source string>)). -
LENGTHin MySQL is equivalent toDATALENGTHin T-SQL.CHAR_LENGTHis the equivalent ofLENGTHin T-SQL. -
SUBSTRING_INDEXreturns a substring from a string before the specified number of occurrences of the delimiter. -
FIELDreturns the index position of the first argument in the subsequent arguments. -
FIND_IN_SETreturns the index position of the first argument within the second argument. -
REGEXPandRLIKEprovide support for regular expressions. -
STRCMPprovides string comparison. -
For more information, see String Functions and Operators
.
-
-
Aurora MySQL Date and Time functions differ from SQL Server functions and can cause confusion during migration. Consider the following example:
-
DATEADDis supported, but is only used to add dates. UseTIMESTAMPADD,DATE_ADD, orDATE_SUB. There is similar behavior forDATEDIFF. -
Do not use
CASTandCONVERTfor date formatting styles. In Aurora MySQL, useDATE_FORMATandTIME_FORMAT. -
If your application uses the
ANSI CURRENT_TIMESTAMPsyntax, conversion isn’t required. UseNOWin place ofGETDATE.
-
-
Object identifiers are case sensitive by default in Aurora MySQL. If you get an Object not found error, verify the object name case.
-
In Aurora MySQL, you can’t declare variables interactively in a script but only within stored routines such as stored procedures, functions, and triggers.
-
Aurora MySQL is much stricter than SQL Server in terms of statement terminators. Make sure that you always use a semicolons at the end of statements.
-
The syntax for
CREATE PROCEDURErequires parenthesis after the procedure name, similar to user-defined functions in SQL Server. You can’t use theASkeyword before the procedure body. -
Beware of control characters when copying and pasting a script to Aurora MySQL clients. Aurora MySQL is much more sensitive to these than SQL Server, and they result in frustrating syntax errors that are hard to spot.