What are the SQL Server query syntax not supported by MySQL? - mysql

I am working in a project where we are using SQL Server database currently. But recently a decision has been taken that the database will be changed to MySQL.
I am not using any stored procedures, views, triggers, user defined functions, etc. But I think even then some queries written for SQL Server will not be supported by MySQL.
Can anyone help: what are the things that I have to check (and change) so that all the queries will work properly for MySQL also?

Queries that I know without consulting the documentation that will not work:
(recursive) common table expressions
windowing functions
queries using the standard SQL string concatenation ||
UPDATEs with JOIN are different between the two systems
Date arithmetics: date_column + 1 behaves differently in SQL Server
Division by zero will produce an error
SQL Server will reject values that do not fit into a column (instead of silently truncating it, which MySQL does in the default installation)
DDL that will not work and might have an impact on performance and/or data quality
datetime columns where you need precision up to milliseconds
tables with check constraints
indexed views
triggers on views
table functions (select * from my_function(42);)
filtered indexes ("partial index")
function based indexes

There's always the option to take commercial support from MySQL AB for this problem. I'm pretty sure they've done enough MSSQL->MySQL migrations to know alot about that. If a price tag on the migration is not a problem.
Alternatively, you could try to run the MySQL Migration Toolkit over the data and look for meaningful error messages at the stuff it cannot migrate. MySQL Migration Toolkit is part of the MySQL GUI Tools.

Related

How can jOOQ be used to deal with multiple database engine depending on configuration

I'm an experienced and happy jOOQ user.
I'm now working on a project that need to support multiple database engines (PostgreSQL, MySQL, Oracle at least).
We want something with the low level enough to have control on our queries. JPA/Hibernate are too high level for us.
I know jOOQ works with a metamodel, and that metamodel is generated from the database schema.
Is there any way to reuse the same jOOQ query definitions against different database engines (with the same schema, apart from engine specific differences) ?
Fine if we need to recompile the java classes if necessary. Compile time configuration is fine for us.
jOOQ has been designed for this. You need to do these things:
Have a Configuration with a SQLDialect ready depending on your JDBC connection. That's the easy part. That Configuration will automatically generate vendor specific SQL for all of your jOOQ queries. This can be done at runtime. No need for any compile time adaptations.
Make sure your tables / columns always use the same case, or turn off quoting in jOOQ's identifiers for case insensitive behaviour (depending on your MySQL configuration, that might not be enough, see the MySQL manual). You can then re-use the generated code from any of your database dialects on all the other dialects.
Make sure you only use jOOQ API that is annotated with #Support({ MYSQL, ORACLE, POSTGRES }). For example, DSL.toDate() cannot be used, because it doesn't support MySQL, but DSL.trunc() can be used, because all 3 target dialects are present.
We're increasingly also adding dialect specific information to the jOOQ manual, e.g. for the SHL() function:
-- ASE, HSQLDB, SQLDATAWAREHOUSE, SQLSERVER, SYBASE
(1 * CAST(power(2, 4) AS int))
-- AURORA_MYSQL, AURORA_POSTGRES, COCKROACHDB, CUBRID, MARIADB, MEMSQL, MYSQL, POSTGRES, SQLITE, VERTICA
(1 << 4)
-- DB2, INFORMIX
(1 * CAST(power(2, 4) AS integer))
-- FIREBIRD
bin_shl(1, 4)
-- H2
lshift(1, 4)
-- ORACLE
(1 * CAST(power(2, 4) AS number(10)))
-- TERADATA
shiftleft(1, 4)
-- ACCESS, DERBY, HANA, INGRES, REDSHIFT
/* UNSUPPORTED */
In order to ensure you're not accidentally writing a query that doesn't work on some dialect, you can:
Run integration tests e.g. using testcontainers on each target dialect
Use jOOQ's Checker Framework or ErrorProne integration for static code analysis. See also this blog post here.

MySQL - No lock while selecting rows in table

I'm starting to study MySQL syntax and now I'm asking how to lock / unlock tables.
After a bit of research, it seems that mysql does not provide a single "nolock" key word.
But if I try to execute the following query:
select *from logs NOLOCK order by timestamp desc;
no errors occur. So, is there a standard way in order to achieve this?
NOLOCK is not an option supported by MySQL.
It's a feature specific to Microsoft SQL Server: https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table
You must understand that even though SQL is a common standard, each company who offers a SQL-compliant database product has implemented their own extensions to standard SQL. Therefore a product like Microsoft SQL Server has some syntax features that are not supported — and not needed — by other RDBMS products.
MySQL is not Microsoft SQL Server. They are two different implementations of RDBMS.
As Raymond commented above, you unintentionally used NOLOCK in a place where it would be interpreted by MySQL as a table alias.
... FROM logs [AS] NOLOCK ...
The SQL standard supports making the AS keyword optional when definining table aliases and column aliases. This can cause some weird surprises, even though it's technically legal syntax to omit the AS keyword.

Query to detect MySQL

I'm fixing a bug in a proprietary piece of software, where I have some kind of JDBC Connection (pooled or not, wrapped or not,...). I need to detect if it is a MySQL connection or not. All I can use is an SQL query.
What would be an SQL query that succeeds on MySQL each and every time (MySQL 5 and higher is enough) and fails (Syntax error) on every other database?
The preferred way, using JDBC Metadata...
If you have access to a JDBC Connection, you can retrieve the vendor of database server fairly easily without going through an SQL query.
Simply check the connection metadata:
string dbType = connection.getMetaData().getDatabaseProductName();
This will should give you a string that beings with "MySQL" if the database is in fact MySQL (the string can differ between the community and enterprise edition).
If your bug is caused by the lack of support for one particular type of statement which so happens that MySQL doesn't support, you really should in fact rely on the appropriate metadata method to verify support for that particular feature instead of hard coding a workaround specifically for MySQL. There are other MySQL-like databases out there (MariaDB for example).
If you really must pass through an SQL query, you can retrieve the same string using this query:
SELECT ##version_comment as 'DatabaseProductName';
However, the preferred way is by reading the DatabaseMetaData object JDBC provides you with.
Assuming your interesting preconditions (which other answers try to work around):
Do something like this:
SELECT SQL_NO_CACHE 1;
This gives you a single value in MySQL, and fails in other platforms because SQL_NO_CACHE is a MySQL instruction, not a column.
Alternatively, if your connection has the appropriate privileges:
SELECT * FROM mysql.db;
This is an information table in a database specific to MySQL, so will fail on other platforms.
The other ways are better, but if you really are constrained as you say in your question, this is the way to do it.
MySql may be the only db engine that uses backticks. That means something like this should work.
SELECT count(*)
FROM `INFORMATION_SCHEMA.CHARACTER_SETS`
where 1=3
I might not have the backticks in the right spot. Maybe they go like this:
FROM `INFORMATION_SCHEMA`.`CHARACTER_SETS`
Someone who works with MySql would know.

How portable (or not) is using SQLLiteral("NOW()") in web.py DB INSERTs?

I know this works fine if my database is MySQL. And maybe others.
seq_id = db.insert('mytable', first="Bob",last="Smith",joined=web.SQLLiteral("NOW()"))
Well, right now, the database customers will use is MySQL, but it may not be the case in the near future. How can I ensure I won't get headaches if the customer decides it has to work on Postgres, Oracle, SQL Server and whatnot?
CURRENT_TIMESTAMP is synonymous with NOW() and standard SQL so you might as well use that in preference.
Its not. Now() won't work in either SQL server or Oracle.
Its also probably not worth worrying about it at that built-in function level since there's lots of other problems you encounter before that.
For example this only works on MySQL even though it doesn't use built in functions
SELECT a, MAX(b), c
FROM
table
GROUP BY
a
Your best bet is to make sure your data access is separated cleanly from the rest of your code if you're really worried about it and build up a new data access layer for each Database you care about.

MySQL to SQL Server migration

I have a mysql database full of data which I need to keep but migrate to SQL Server 2008.
I know end to end where the data should go, table to table but I have no idea how to go about moving the data. I've looked around the web but it seems there are 'solutions' which you have to download and run. I'd rather if possible do something myself in terms of writing scripts or code.
Can anyone recommend the best way to do this please?
You have several options here:
On the sql server side, you can set up a connection to your old mysql db using something called a linked server. This will allow you to write sql code for sql server that returns data from the mysql tables. You can use this to build INSERT or SELECT INTO statements.
You can write queries for mysql to export your data as csv, and then use the BULK INSERT features of sql server to efficiently import the csv data.
You can use Sql Server integration services to set move the data over from mysql.
Regardless of which you choose, non-data artifacts like indexes, foreign keys, triggers, stored procedures, and security will have to be moved manually.
Have you tried tool from MSFT called SQL Server Migration Assistance for MySQL ???
https://www.microsoft.com/download/en/details.aspx?id=1495
Try this tutorial it is very easy to perform migration to SQL Server from Mysql and is straightforward as mentioned
http://www.codeproject.com/Articles/29106/Migrate-MySQL-to-Microsoft-SQL-Server
Thanks
You can use the Import/Export Wizard that comes with SQL Server Standard Edition.
Select your 'data source' from MySQL using the ODBC data source. Note: You will need to first install the from ODBC driver for MySQL (ODBC Connector). Then, select your SQL Server destination. Select all tables, and fire it up. You will need to add your primary and foreign keys, and indexes manually.
A bit more automated means would be by using the SQL Server Migration Assistant for MySQL, also free. It has the benefit of recreating the relationships and indexes automatically for you. Probably your best bet.
I did it once, some time ago. First you could couple your mssql server to the mysql server using the odbc mysql connector
http://dev.mysql.com/downloads/connector/
After the connection is made you can write you database procedure as you would if it were two mssql db's. Probably easiest to write some sql batch scripts including a cursor where you run through every every row of a table an decide on a field basis where you will need the field in the future.
example of a cursor: http://www.mssqltips.com/tip.asp?tip=1599
If you decide to go with the cursor, you can play with the parameter to increase performance. I especially remember the FORWARD_ONLY parameter giving a big boost.