I just found out that Oracle 12c supports correlating a query several levels deep which is unsupported in 11g and previous versions.
select
*
from
tab1 a
where
not exists
(select
*
from
(select
*
from
tab2 b
where a.X = b.X))
But I could not find this documented in Oracle website. Is there any other such hidden SQL features added to Oracle 12c? Are all such changes to SQL in 12c documented somewhere?
To explain this we need to dive into history a little bit.
Ability to use correlated sub-queries with more than 1 level was also in Oracle 10g R1 and it was properly documented (https://docs.oracle.com/cd/B14117_01/server.101/b10759/queries007.htm) back those days...
Oracle performs a correlated subquery when a nested subquery
references a column from a table referred to a parent statement any
number of levels above the subquery.
... but it was not properly working. :)
So starting with Oracle 10g R2 this functionality was disabled and documentation had changed.
Also (if you have an access) you can see Bug 15990897 : QUERY WITH CORRELATED VARIABLE USED IN 2ND LEVEL SUBQUERY FAILS WITH ORA-904 on Metalink (Fixed in Product Version 12.1.0.1.0). I'm not sure why it's considered as a bug given that it works according to documentation (10g R2, 11g R1, 11g R2) but that is how it is.
So, functionality was disabled after 10.1 and before 12.1 but documentation even for 12.2 (https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/Using-Subqueries.html) says
Oracle performs a correlated subquery when a nested subquery
references a column from a table referred to a parent statement one
level above the subquery.
Cut a long story short, this functionality is enabled in 12c R1 and 12c R2 but documentation is not fixed and apparently there is no mentioning about this improvement in New Features guide.
PS. As far as I remember standard SQL 2003 allows correlation only to one level deep - everyone is welcome to check (http://www.wiscorp.com/sql_2003_standard.zip).
But Oracle has a lot of improvements above the standard anyway.
Related
Is there any standard sql command that can show you the current RDBMS and version?
The reason for this question is that I am using a CMS remotely that use a SQL database, but I don't know which RDBMS is being used, so I thought maybe there is standard SQL command to print it, something similar to SQL server's ##version
This is not a direct answer to the question, but since there is no standard sql query or function to show the RDBMS, I will post the queries/functions/vars used to identify it.
-- SQL SERVER
SELECT ##version;
-- Postgres, mysql, mariadb
SELECT version();
-- Oracle
SELECT * FROM v$version;
-- sqlite
select sqlite_version();
Please pay attention that Mysql and Sqlite will show only the version and will not include engine name in contrast to other RDBMS.
I have just started on a project that involves building a web application replacement for an old Access application that was already backed by an SQL database.
The issue i have hit is that the Access application has a bunch of queries within it that use '*=' as condition operators (ie "where field1 *= 'Something'") which when i run the application cause it to crash.
I have tried to verify if the operator is valid or if the original developers have handed over an intentionally broken version of the application.
Can any one provide verification that '*=' (ie asterix equals) is or is not a valid operator in an Access query?
Don't worry; your original developers are not trying to pass you intentionally broken code. It's just that the code is very old.
*= (and its counterpart =*) were a non-standard SQL operator supported originally by Sybase SQL and inherited by Microsoft SQL Server in the mid-90's. *= meant LEFT JOIN (and its counterpart =* meant RIGHT JOIN)1
(Microsoft SQL Server was originally a repackaged edition of Sybase SQL, licensed from Sybase, adapted and recompiled to run on Microsoft's brand-new Windows NT Operating System. The partnership was eventually discontinued and Microsoft rewrote the code from scratch without Sybase's involvement, and that's the product we still have today)
The operator *= was a way to express LEFT JOIN operations, before there was such a thing as a LEFT JOIN operator:
SELECT *
FROM a, b
WHERE a.id *= b.id
Is the same as:
SELECT *
FROM a
LEFT JOIN b
ON a.id = b.id
These operators have been deprecated for more than a decade and are no longer supported at all, ever since SQL Server 2012. Using them in earlier versions of SQL Server is possible but requires the whole database to have a legacy-mode setting called compatibility_level to be set to 80 ("SQL Server 2000 mode").
Access has never supported these operators.2
You need to locate the code doing these outer joins and replace them with suitable LEFT JOIN (or RIGHT JOIN for =*) operations.
Finally, you should be aware that *= is not an exact mirror of LEFT JOIN. I don't remember all the details, but it goes something like this: If there are only two tables involved, or if there is a central table and all the LEFT JOINs go from the central table to immediate leaf tables, you can replace *= with LEFT JOIN in a straightforward fashion. However, if the outer joins cross more than two tables out, then *= behaves different than the naive replacement and you need to research it more carefully. I might be wrong about the details. Be careful!
1Compare this weird syntax for LEFT JOIN with this variant of an INNER JOIN, which is still perfectly acceptable today:
SELECT *
FROM a, b
WHERE a.id = b.id
Is exactly the same as:
SELECT *
FROM a
INNER JOIN b
ON a.id = b.id
2UPDATE: Upon re-reading your question I realize you were talking about pass-through queries executed by SQL Server. Then your choices depend on what version of SQL server you are using.
If you are able to run the application against SQL server 2008 R2 or earlier, you can temporarily switch compatibility_level to 80 to give you time to fix your queries.
More likely than not, you are having this problem precisely because you are trying to move the database to a version of SQL Server newer than 2008 R2, which doesn't support compatibility_level 80. When you loaded the database on a version of SQL Server newer than 2008 R2, the setting was automatically increased to the lowest value supported by your version of SQL Server (but higher than 80, which would no longer be supported). Then your only reasonable choice is to stay on SQL server 2008 R2 for now (and switch the database back to compatibility_level 80 if necessary) while you work on fixing the application queries.
Drupal uses db_query_range() for the reason that not all databases support LIMIT,
can you name a few?
DB2, MSSQL, Oracle, and Informix all do not support LIMIT. As a matter of fact, it's not in the SQL standard. (The standard one is "FETCH FIRST" indeed)
Here is a good source for SQL comparisons: http://troels.arvin.dk/db/rdbms/#select-limit
Microsoft SQL Server does not support LIMIT. It supports the TOP statement which can be used to accomplish similar things. The primary limitation with TOP is the inability to specify an offset.
ms sql, oracle.
and actually LIMIT doesn't exists in ANSI SQL '92 which all modern databases should follow. so currently it's just an unnecessary extension/syntactic sugar/specific sql dialect
DB2, Oracle, and MS SQL Server do not support the LIMIT clause.
Google for <database name> LIMIT, and you'll get to know the equivalent supported clause for that database, or whether LIMIT itself is supported.
On the flip side, ANSI-92 SQL provides the ROW_NUMBER() window function for achieving this, which is supported on many databases. See SELECT (SQL) on Wikipedia.
will the sql queries i run in ms-access also work on mysql without any changes ?
It's possible, but it depends on what the queries use. Date and string functions are the most likely to cause problems when porting queries.
The DATEDIFF keyword is supported on both Access & MySQL, but the function takes different parameters:
Access: DATEDIFF
MySQL: DATEDIFF
Well, if the coder wrote the queries with portability in the forefront of their mind then there's a good chance that you will need to make only minimal changes. However, you could only expect the most simple queries to work with no changes, regardless of which SQL product were involved.
In an ideal world, all SQL products would comply with ISO/ANSI Standard SQL with vendor extensions. In reality, while mySQL generally has a good track record in Standard SQL compliance, the Access Database Engine's record is rather poor -- it still doesn't even conform to entry level SQL-92, which was a fairly fundamental requirement even a decade ago (and seemingly none too difficult to achieve either).
[Your question is in all lower case. I've assumed by 'queries' you mean SQL DML SELECT. If you use 'queries' to mean INSERT/UPDATE/DELETE SQL DML plus SQL DDL and SQL DCL then this changes the answer. You should note the the Access Database Engine's UPDATE SQL DML is proprietary and non-deterministic; further, it does not support SQL-92's scalar subquery syntax. This is of major significance when porting to a SQL product.]
Thanks for your question. It just goes to show that it's worth considering portability from day one.
I would like to add one more point to OMG Ponies answer
Transform that is use for cross tab queries in MS ACCESS cannot be used in MySQL
e.g.
TRANSFORM Sum([M_Sales].[Amount]) AS SumOfAmount
SELECT [M_Sales].[Department]
FROM M_Sales
GROUP BY [M_Sales].[Department]
PIVOT Format([M_Sales].[Sale_date],"mmm") In ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
in MSACCESS ( taken from )
could be something in MySql Common MySQL Queries . Just visit the Pivot table section
Given some of your previous questions, you could save some time with MySQL, compared to Access: 12.1.10. CREATE TABLE Syntax
The developer environment db server is SqlServer 2005 (developer edition)
Is there any way to make sure my SQL Queries will run in SqlServer 2000?
This database is set to Compatibility level "SQL Server 2000 (80)" but some queries that run without problems in the development system can not run in the Test Server (SqlServer).
(The problems seems to be in subqueries)
Compatibility levels are designed to work the opposite way - to allow an older version of T-SQL code to work without modifications on a newer version of SQL Server. The changes typically involve T-SQL syntax and reserved words, and it's possible to use SQL Server 2005 features such as INCLUDED columns in indexes on a database in Compatibility Level 80. However, you can't use 2005 T-SQL features such as CROSS APPLY.
Your best option is to develop/test all your code against a SQL Server 2000 instance. Note that you can use 2005's Management Studio to connect to the SQL Server 2000 instance, so you don't have to go backwards with regards to tools.
Problem solved:
In correlated subqueries you have to (in SQL2000) explicitly define the external field.
SQL2005:
SELECT * FROM Loans WHERE EXISTS (SELECT * FROM Collaterals WHERE COLLATERAL_LOAN=LOAN_NUMBER)
SQL2000:
SELECT * FROM Loans WHERE EXISTS (SELECT * FROM Collaterals WHERE COLLATERAL_LOAN=Loans.LOAN_NUMBER)
You should always explicitly define all fields, otherwise you will not get an error when you make a mistake and write
SELECT * FROM Loans WHERE EXISTS (SELECT * FROM Collaterals WHERE LOAN_NUMBER=Loans.LOAN_NUMBER)
If Collaterals-table doesn't have column LOAN_NUMBER, the Loans-table is used instead.