Of course, we do our job before and searched this community or the web for similar posts but we found nothing.
Issue:
We are not happy with our current hosting provider and have to make change. In the middle of our database switch from MySQL 5.7 to MariaDB 10.3, we have recognized a SET handling difference, which works perfect in MySQL.
SQL code:
SET #sb = 0;
SELECT art,sb
FROM ARTICLE
WHERE(#sb:=sb) > 700 AND #sb <= 1000 >AND art = 'AM';
MySQL result:
art
sb
AM
900.00
AM
960.00
AM
1000.00
AM
770.00
AM
800.00
the list is much longer...
MariaDB result:
art
sb
AM
770.00
AM
960.00
AM
1200.00
AM
3000.00
only 10 rows...
In fact there is a difference between them.
But we want to know:
Can we configure this in MariaDB, that we get the same result in MySQL?
Should we replace the Set handling in MariaDB with another one?
No, this is not possible.
In fact, the MySQL documentation warns about the use of variable assignments inside SQL statements:
The order of evaluation for expressions involving user variables is undefined. For example, there is no guarantee that SELECT #a, #a:=#a+1 evaluates #a first and then performs the assignment.
What's more, this is a "feature" that is subject to removal:
Previous releases of MySQL made it possible to assign a value to a user variable in statements other than SET. This functionality is supported in MySQL 8.0 for backward compatibility but is subject to removal in a future release of MySQL.
So you should not rely on that, and rewrite your queries.
The MySQL documentation is quite clear on this point:
As a general rule, other than in SET statements, you should never assign a value to a user variable and read the value within the same statement.
That your code ever worked was something of a coincidence. The reason for such warnings is that behavior may change between releases; or even that the results may be inconsistent between runs on the same database.
You should replace the variables with window functions. The exact function is a bit unclear. Sample data, desired results, and a clear explanation of the results always helps.
Related
I must make an exponentiation of a number and I don't know which function to use between POW() and POWER(). Which of the two functions is better?
Looking at the MySQL documentation I saw that they are synonymous, but I wanted to understand if there was a reason for two functions that do the same thing.
POWER is the synonym of POW. So nothing is better, it is the same:
POWER(X,Y)
This is a synonym for POW().
Using two different names for the same function gives you the possibility to port an SQL query from one dialect to an other dialect without (big) changes.
An example:
You want to use the following TSQL query on MySQL too:
SELECT POWER(2,2) -- 4
Now you can write these query specific for the dialects:
SELECT POWER(2,2) -- 4 - TSQL (POW is not available on TSQL)
SELECT POW(2,2) -- 4 - MySQL
But you can also use the POWER function on MySQL since this is a synonym for POW:
SELECT POWER(2,2) -- 4 - TSQL and MySQL
pow and power are synonyms in MySQL.
I'd use power since it's part of the ANSI SQL standard and using it would make your code easier to port if you ever decide to use a different database.
It seems to me like MySQL is setting up a subtle trap for me. It allows to select column that is neither aggregate function like sum nor specified in group by clause. Therefor value in that column from my point of view is totally random.
I think in Oracle database that wasn't possible (but I used it like 5 years ago so something might change in this regard).
Is there any way to prevent from such nasty/trap-a-like behavior or at least tell it to warn me? Tools should work with developer not set up traps.
I'm using MySQL 5.6.30 and MySQL Workbench 6.3.7
The behaviour you describe is known. MySQL gives the correct result set for any valid and sane query. It can return unexpected data on queries that make no sense.
While debugging an issue in our software system, I came across a prepared statement that looks something like this:
"UPDATE Command SET expiredWhen=status, status='expired' WHERE id=?;"
The expiredWhen field is supposed to be set to whatever value is in the status field, then the status field is supposed to be set to "expired". It worked as expected in our MySQL 5.1 environment, but in MySQL 5.5 expiredWhen is being set to "expired".
What is the expected result of this statement? Is this a race condition, and we were lucky that it ever worked? Or is there defined behavior for this statement that changed from version 5.1 to 5.5?
The documentation is consistent between versions 5.1 and 5.5:
Single-table UPDATE assignments are generally evaluated from left to
right. For multiple-table updates, there is no guarantee that
assignments are carried out in any particular order
This suggests that it shouldn't be a race condition. That said, the word "generally" is a little concerning - it would probably be safest to assume that it could be a race condition.
I was wondering what types of things usually vary between SQL implementations when looking at the query statements. One thing that I thought was the use of IS NULL in the WHERE clause. See bleow for example. I'm writing a query statement parser that handles the statement and queries in a custom language and need to account for most of the general differences between the more widely used SQL products.
Oracle Syntax:
SELECT * FROM TABLE WHERE COLUMN_A IS NULL
SELECT * FROM TABLE WHERE COLUMN_A IS NOT NULL
MySQL Syntax?
SQL Server Syntax?
I'm not sure you're going to find a definitive list of all differences. A few things I can think of off the top of my head:
MySQL uses LIMIT while SQL Server uses TOP.
SQL Server is much stricter on GROUP BY operations than MySQL, requiring that all non-aggregated columns from the SELECT appear in the GROUP BY clause.
SQL Server supports a proprietary UPDATE FROM and DELETE FROM syntax that goes beyond the ANSI standard.
Functions that exist in one system but not another. MySQL has FIND_IN_SET and GROUP_CONCAT that don't exist in SQL Server. Likewise, SQL Server has ROW_NUMBER() that doesn't exist in MySQL.
The IS NULL / IS NOT NULL syntax is ANSI standard SQL, and supported in all three of those RDBMS as you have listed it for Oracle.
IS NULL and IS NOT NULL is the same pretty much everywhere. The main differences for basic queries would relate to function calls, and those are vastly different so you'll have to be more specific there.
There are plenty of things that vary between different RDMBS implementation. Here's a simple example which doesn't use any specific function:
In Oracle, you can update table A from data in table B as follows:
UPDATE A
SET (COL1,COL2) = (SELECT B.COL3, B.COL4 FROM B WHERE B.COL5 = A.COL6)
WHERE A.COL7 = 3
AND EXISTS (SELECT 1 FROM B WHERE B.COL5 = A.COL6);
But in SQL Server the same task can be done as follows:
UPDATE A
SET COL1 = B.COL3, COL2 = B.COL4
FROM B
WHERE B.COL5 = A.COL6
AND A.COL7 = 3;
Additionally, the Oracle syntax is invalid in SQL Server and vice versa, so you can't settle for a common denominator. Writing a parser for this particular syntax is a challenge, so a general parser seems to be a highly non-trivial task.
You can apply both queries to all the rdbms. This is standard ansi.
About a decade ago I bookmarked a link, long since broken, to a document entitled, "Levels of Vendor Compliance with ANSI SQL". I've kept it so I can think, "Ah, how quaint." The Standard is now ISO (I = international) and not just ANSI (A = USA). Nobody tries to document this kind of thing for more than one SQL product anymore.
All vendors pay close attention to the SQL Standard and will declare level compliance on a feature-by-feature basis. Even when no such declaration is forthcoming you know they have read the Standard spec, even if it means a concious decision to extend or to do things completely differently. If you are interested in portability then get used to writing Standard SQL that is implemented by, or similar to syntax in, the SQL products you wish to target.
Taking mySQL and SQL Server as examples. I would guess that some mySQL features (e.g. ORDER BY LIMIT) are closer to Standards than SQL Server is (TOP) because mySQL have come to the party later and actually had a Standard spec to follow and no legacy version to be compatible with. I would guess that other features in mySQL (update on duplicate key) are further from Standards (SQL Server extends MERGE from Standards) because they wanted something easier to implement and simpler users. I would a guess some mySQL features are close to those in SQL Server to be able to poach users!
I am deploying a Ruby on Rails application that I developed with Sqlite3 to a server with either MySQL or PostgreSQL. I quickly discovered that the "group by" and "strftime" functions that I am using heavily to produce by-month rollup reports are working differently or not compatible between the various databases.
I can refactor my code to do the grouping, summing and averaging - but the database does such a nice job of it and reduces the processing required by the server! Advanced applications go beyond simple select and join. ActiveRecord gives us :group, but the DATABASES are not CONSISTENT.
So my question is a matter of architecture - does anyone expect to create truly "database portable" applications in Ruby on Rails? Should I modify my codebase to work with MySQL only and forget about the other databases? Should I modify my codebase to do the advanced grouping, summing, and averaging?
cheers - Don
Several comments:
Develop and test with the same RDBMS brand and version that you're going to deploy to.
Writing portable SQL code is hard because vendors have all these non-standard extra functions and features. For example, strftime() is not part of the ANSI SQL standard. The only way to resolve this is to RTM for each database you use, and learn what functions they have in common. Sometimes they have a function of a different name that you can use in a similar way. There's no short-cut around this -- you have to study the manuals.
All the databases support GROUP BY, but SQLite and MySQL are kind of more permissive about certain usage than standard ANSI SQL (and all other brands of database which do follow the standard). Specifically, in your GROUP BY clause you must name every column in your select-list that isn't part of a grouping function.
The following two examples are right:
SELECT A, B, COUNT(C) FROM MyTable GROUP BY A, B;
SELECT A, COUNT(C) FROM MyTable GROUP BY A;
But the next one is wrong, because B has multiple values per group, and it's ambiguous which value it should return in a given row:
SELECT A, B, COUNT(C) FROM MyTable GROUP BY A;
No framework writes truly portable SQL. Rails' ActiveRecord solves this only in very trivial cases. In fact, ActiveRecord helps solve neither of the examples you give, of functions that are brand-specific, and non-standard GROUP BY clauses.
The problem is that especially with GROUP BY MySQL does it wrong. If you leave out columns from the group by MySQL simply returns "something" accepting that the results may be indeterminate.
You can (should) use the ONLY_FULL_GROUP_BY parameter to make MySQL throw an error if the result of your GROUP BY would not be clearly defined.
Actually there are a lot more settings that should be changed in MySQL to make it behave more sanely
You might be interested in reading this:
http://www.slideshare.net/ronaldbradford/mysql-idiosyncrasies-that-bite-201007