UPSERT compatible with mySql and postgreSQL - mysql

I've been googling and trying different queries but I haven't managed to get the UPSERT query to work with both mySql and postgreSql. Does anyone here know how to do it?

There is not one, and cannot be one. PostgreSQL doesn't have an UPSERT statement. The new 9.5 statement INSERT ... ON CONFLICT UPDATE ... is syntactically different from MySQL's INSERT ... ON DUPLICATE KEY UPDATE ... because it's also semantically different, i.e. it works differently.
The newer PostgreSQL statement, added in 9.5, was designed with an awareness of MySQL's syntax. The decision not to use the same syntax was intentional because MySQL's statement has big ambiguities around handling of multiple unique indexes etc, where it basically shrugs and says "dunno".
You can possibly hide it behind stored functions, but really, this is why your application should be able to run different SQL on a different DBMS. Trying to always write one statement that works for all target DBMSes is a lost cause even if you're just targeting MySQL and PostgreSQL.

Related

Is there a functionality similar to ctid in postgres for MySQL/Snowflake or other databases?

I have been trying to remove duplicates from the table but I need more of a generalized way of doing it. There are numerous ways to do it if the table has a unique identifier like row ID. But otherwise, it seems to be very difficult and different for different databases.
I even explored CTE (Common Table Expressions) to do the same but seems that databases do not allow the use of CTE followed by DELETE clause (at least what I saw with MySQL and Snowflake).
But in PostgreSQL, there seems to be a way in which we can achieve this without necessarily having any unique identifier. This is through the use of ctid, a system column in PostgreSQL. I am curious if there is a similar functionality like ctid for other databases especially MySQL and Snowflake is what I am interested in currently.
I am curious if there is a similar functionality like ctid for other databases especially MySQL and Snowflake is what I am interested in currently.
There is no CTID in Snowflake.

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.

Configuring Index text length MySQL in Doctrine

I have a text field in my database and a index on it for the first 10 characters. How do I specify that in my Doctrine Entity?
I can't find any information about database specific options for indexes anywhere :/
This is my "partial" MySQL create statement:
KEY `sourceaddr_index` (`sourceaddr`(10)),
And this is my #Index in doctrine:
#ORM\Index(name="sourceaddr_index", columns={"sourceaddr"}, options={}),
This dosnt interfere with the regular use, but I noticed the problem when deploying development to a new laptop, and creating the database based on my entities...
Any help would be appreciated :)
Possible since Doctrine 2.9, see: https://github.com/doctrine/dbal/pull/2412
#Index(name="slug", columns={"slug"}, options={"lengths": {191}})
Unfortunately, Doctrine seem to be very picky with whitespace location, so e.g. update --dump-sql yields:
DROP INDEX slug ON wp_terms;
CREATE INDEX slug ON wp_terms (slug(191));
and even if you execute those, they messages will stay there (tested with MariaDB 10.3.14).
I've had very good luck naming the index in Doctrine, after manually creating it in MySQL. It's not pretty or elegant, and it's prone to cause errors moving from dev to production if you forget to recreate the index. But, Doctrine seems to understand it respect it.
In my entity, I have the following definition. Doctrine ignores the length option - it's wishful thinking on my part.
/**
* Field
*
* #ORM\Table(name="field", indexes={
* #ORM\Index(name="field_value_bt", columns={"value"}, options={"length": 100})
* })
And in MySQL, I execute
CREATE INDEX field_value_bt ON field (value(100))
As far as I've seen, Doctrine just leaves the index alone so long as it's named the same.
In short: you can't set this within Doctrine. Doctrine's ORM is specifically focused on cross vendor compatability and the type of index you're describing, though supported in many modern RDBMS, is somewhat outside the scope of Doctrine to handle.
Unfortunately there isn't an easy way around this if you use Doctrine's schema updater (in Symfony that would be php app/console doctrine:schema:update --force) as if you manually update the database, Doctrine will sometimes, regress that change to keep things in sync.
In instances where I've needed something like this I've just set up a fixture that sends the relevant ALTER TABLE statement via SQL. If you're going to be distributing your code (i.e. it may run on other/older databases) you can wrap the statement with a platform check to make sure.
It's not ideal but once your app/software stabilises, issues like this shouldn't happen all that often.

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.

What are the SQL Server query syntax not supported by 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.