converting a DB2 query into oracle query - sql

Previously we used DB2 as database, but now we are migrating to Oracle. Now, in our project we have extensively used sql's that were Db2 specific.
Is there any way to convert those DB2 specific queries to oracle supported queries.
Thanks

You have a lot of work ahead!
Between DB2 and Oracle, some important differences are (just an arbitrary enumeration of what I can think of):
Data types
Number data types: DB2 has many more standard types, such as SMALLINT, INTEGER, DOUBLE, etc. Those don't exist in Oracle SQL (although some exist in PL/SQL). This is important for DDL and for casting and some other use cases, such as the correctness of predicates
Date data types: Oracle's only difference between DATE and TIMESTAMP is the fact that TIMESTAMP has microseconds. But DATE may also contain time information. In DB2, DATE has no time information, I think.
Character data types: Read about the difference between VARCHAR and VARCHAR2 in Oracle
NULL. In Oracle, NULL is much more general than in DB2. Before DB2 v9.7, you had to cast NULL to any explicit type, e.g. cast(null as integer). That's not necessary in Oracle.
System objects
SYSIBM.DUAL simply becomes DUAL
Functions: They're all a bit different. You'll have to check case by case. For example, LOCATE becomes INSTR
Syntax
TRUNCATE IMMEDIATE becomes TRUNCATE
EXCEPT becomes MINUS
DB2's FETCH FIRST n ROWS ONLY: There is no such clause in Oracle. You'll have to use ROWNUM or ROW_NUMBER() OVER() filtering (see this example)
DB2's MERGE statement is more powerful than that of Oracle, in case you use this.
DB2 supports INSERT INTO .. (..) VALUES (..), (..), (..). With Oracle, you'd have to write INSERT INTO .. SELECT .. UNION ALL SELECT .. UNION ALL SELECT ..
Advanced
If you use stored procedures, they work a bit differently, especially with advanced data types involved, but that's out of scope here.
Your most efficient shot at this might be to use SQL abstraction of some sort. If you're using Java, I would recommend you wrap your SQL statements with jOOQ (Disclaimer: I work for the company behind jOOQ). jOOQ provides API-level abstraction for all of the above facts. A great deal of SQL can be executed both on DB2 and Oracle, without adaptation. We're also working on a more independent translator product: https://www.jooq.org/translate
On a higher level of abstraction, Hibernate (or other JPA implementations) can do the same for you

I found out that there are also some differences in the management of character strings.
DB2 doesn't care about the trailing whitespaces when comparing:
/* DB2 */
SELECT CASE WHEN ('A ' = 'A') THEN 'true' ELSE 'false' END FROM SYSIBM.SYSDUMMY1
--> true
/* Oracle */
SELECT CASE WHEN ('A ' = 'A') THEN 'true' ELSE 'false' END FROM DUAL
--> false
Oracle considers that '' equals NULL:
/* DB2 */
SELECT CASE WHEN ('' IS NULL) THEN 'true' ELSE 'false' END FROM SYSIBM.SYSDUMMY1
--> false
/* Oracle */
SELECT CASE WHEN ('' IS NULL) THEN 'true' ELSE 'false' END FROM DUAL
--> true

Related

Case insensitive search without using a function in the where clause

Any way to make a case insensitive without using a function in the where clause?
Please specify the database you are talking about when/if you reply. I am aware that MySQL is already case insensitive by default. What about Oracle or MSSQL or HANA?
select * from mytable WHERE upper(fieldname) = 'VALUE'
collate SQL_Latin1_General_CP1_CS_AS.
Default Collation is SQL_Latin1_General_CP1_CI_AS which is case insensitive. And if we need to make it case sensitive, then adding COLLATE Latin1_General_CS_AS makes the search case sensitive.
Query
select * from [mytable]
where [fieldname] = 'VALUE' collate SQL_Latin1_General_CP1_CS_AS;
Find a demo here
Since your question is tagged Oracle, I will provide a solution which works in Oracle.
You can set these session parameters for case insensitive searching
SQL> alter session set NLS_COMP=ANSI;
SQL> alter session set NLS_SORT=BINARY_CI;
SQL> select 1 from DUAL where 'abc' = 'ABC';
1
----------
1
Read more at Linguistic Sorting and String Searching
as #mathguy points out,
ALTER SESSION SET NLS_COMP=LINGUISTIC;
is more common than using ANSI
Making the column upper (or lower) case as you are showing in order to compare it, is the standard way of making a case insensitive comparision. (UPPER and LOWER are functions defined in the SQL standard.)
If you don't want to apply a function on the column, then you can of course write a recursive query to generate all upper/lower case permutations of the value ('VALUE', 'vALUE', 'VaLUE', ..., 'value') and check whether your column value is in this set. Standard SQL provides the SUBSTRING function for accessing substrings (e.g. the nth letter) and CHAR_LENGTH for getting the string's length.
It depends on the DBMS you are using and its version to what extent the standard is supported. In Oracle for example it's SUBSTR instead of SUBSTRING and LENGTH instead of CHAR_LENGTH. MySQL on the other hand features both SUBSTRING and CHAR_LENGTH directly, but only supports recursive queries as of version 8.0.
this will work:
SELECT *
FROM mytable
WHERE REGEXP_LIKE (column_name, 'value', 'i');
Oracle 12c answer
select * from mytable WHERE fieldname='Value' collate binary_ci
SAP HANA does not seem to have a way other than using upper or lower.
SQL Server and MySQL do not distinguish between upper and lower case letters—they are case-insensitive by default.
One could use CONTAINS Function. For example, Microsoft SQL Server query:
SELECT *
FROM TableName
WHERE ColumnName LIKE 'Abc%'
Maybe written in SAP HANA as:
SELECT *
FROM TableName
WHERE CONTAINS(ColumnName,'Abc%');
https://help.sap.com/viewer/05c9edaee7fe4d28ab3627d0b1583df6/2021_01_QRC/en-US/b45ff4c0e9ab4ba7a9e18a2552adeb3d.html

Common SQL to compare dates in SQL Server and ORACLE

I need to include a date comparison in my query where I compare a date string to a DATETIME column but i need it to work on both ORACLE and SQL Server and not have two separate queries.
Are there any date comparissons which will work on both oracle and sql?
ORACLE:
Select * from MyTable where myDate > DATE '2013-04-10'
SQL Server:
Select * from MyTable where myDate > convert(DATETIME,'2013-04-10', 126)
This portability issue only applies with literals.
I do not believe there is a fully portable way to do this because SQL Server does not support the ANSI literal DATE keyword and all the CAST, CONVERT, TO_DATE, and date functions are not identical on all platforms.
Note that your second query can also be written as Select * from MyTable where myDate > '20130410'.
It would be nice if there was support in SQL Server for the ANSI DATE literal feature (DB/2 and Teradata both have this).
I could not find a Connect item on this, nor anything about why SQL Server doesn't support the ANSI DATE, TIME and TIMESTAMP literal keywords.
I'm wondering in your scenario, whether it would be possible to use a parameter instead?
The solution in Jack's comment Common SQL to compare dates in SQL Server and ORACLE will make this code portable, but you will have to have a non-portable scalar function. This might be a viable option for you - note that in SQL Server, you will need to prefix a scalar function with its schema - this might introduce another wrinkle between the Oracle code and SQL code if you can't make the schemas the same name (note in Oracle, the prefix could be the name of a package instead of a schema if you put the function inside a package)
Is defining your own user-defined functions allowed? You could create a function which abstracts the DBMS specific code and returns a literal 'True' or 'False' result.
[MSSQL User Defined Functions: ]http://msdn.microsoft.com/en-ca/library/ms186755.aspx
[Oracle User Defined Functions]http://ocs.oracle.com/cd/B19306_01/server.102/b14200
Oracle apparently does not allow user defined functions to return a Boolean type, so a string (or numeric) result is required.

Can “Case statement“ be safely used in a regular/prepared statement of JDBC?

In our software we use Postgresql as a database with the JDBC3 driver type. Our JDBC statements use SQL containing “Case statement“ .
Will this code work if we switch to another driver or database:
Example:
SELECT r.routineid,
r.routinetypeid,
CASE WHEN (pc.version=20 and pc.parentid>0)
THEN CASE WHEN (r.processed='t')
THEN pc.processed ELSE r.processed
END
ELSE r.processed
END AS processed,
CASE WHEN (r.version=2 and r.parentid>0)
THEN (SELECT m_req
FROM routine
WHERE routineid=r.parentid
)
ELSE r.m_req
END AS m_req,
r.version
FROM (SELECT *
FROM routine
WHERE routinetypeid in (11,12)
AND (fbroutineid='130' OR fbroutineid='806')
) AS r
LEFT JOIN
routine pc
ON r.routineid=pc.parentid
ORDER BY r.routinetypeid;
The case statement is standard SQL and supported by almost all databases -- Oracle (except for the oldest versions), MySQL, SQL Server, DB2, Postgres, and all the Postgres derivatives. The one exception that I can readily think of is MS Access, but I would recommend that you avoid that anyway.
So, if your concern is compatibility for different database engines, you should be safe with case statements.
Your query has a nested select in the case statement. Different databases will handle this better or worse -- and I guess Postgres is on the worse side.
You can get around this by joining in a summarized table:
routine rparent
on rparent.routineid = r.parentid
And then using rparent.mreq instead of the subquery.

Comparisons with NULLs in SQL

ANSI-92 SQL mandates that comparisons with NULL evaluate to "falsy," eg:
SELECT * FROM table WHERE field = NULL
SELECT * FROM table WHERE field != NULL
Will both return no rows because NULL can't be compared like that. Instead, the predicates IS NULL and IS NOT NULL have to be used instead:
SELECT * FROM table WHERE field IS NULL
SELECT * FROM table WHERE field IS NOT NULL
Research has shown me that Oracle 1, PostgreSQL, MySQL and SQLite all support the ANSI syntax. Add to that list DB2 and Firebird.
Aside from SQL Server with ANSI_NULLS turned off, what other RDBMS support the non-ANSI syntax?
1 The whole empty string = NULL mess notwithstanding.
For what it's worth, comparing something to NULL is not strictly false, it's unknown. Furthermore, NOT unknown is still unknown.
ANSI SQL-99 defines a predicate IS [NOT] DISTINCT FROM. This allows you to mix nulls and non-null values in comarisons, and always get a true or false. Null compared to null in this way is true, otherwise any non-null compared to null is false. So negation works as you probably expect.
PostgreSQL, IBM DB2, and Firebird do support IS [NOT] DISTINCT FROM.
MySQL has a similar null-safe comparison operator <=> that returns true if the operands are the same and false if they're different.
Oracle has the hardest path. You have to get creative with use of NVL() or boolean expressions:
WHERE a = b OR (a IS NULL AND b IS NULL)
Yuck.
Here is a nice comparison of null handling in SQLite, PostgreSQL, Oracle, Informix, DB2, MS-SQL, OCELOT, MySQL 3.23.41, MySQL 4.0.16, Firebird, SQL Anywhere, and Borland Interbase

SQL to return fixed data in both SQL Server and Oracle

I need a common select statement that returns a fixed value / row without the need of tables, which has to work with both Oracle & Sql Server.
eg for Oracle I know I can use:
select 'O' AS INDICATOR from DUAL;
But this won't work on Sql Server.
Can this be done with the same SQL on both Oracle & SQL Server?
AFAIK, you'll need different queries, unless you can find a table that exists both on the SQL Server and on the Oracle Server.
Oracle uses the DUAL table for dummy queries, while the syntax to just select a constant on SQL server is a bit simpler:
select 'O' as Indicator
will return a one-row recordset.
P.S. If you intend to write just standard SQL and have it work on both SQL Server and Oracle, note that there are lots and lots of differences, even if you do not use database-side code (stored procedures and functions).
Off the top of my head, some things that are different:
Case statement syntax
NVL vs IsNull
Null sorting behaviour
Data conversion functions
String manipulation functions
etc, etc.
You can't select data in Oracle without from statement. So you need to have a table in Oracle (common practice is to use standard table - Dual). The best solution if you really need to run same query on both database servers is to create Dual table with only one row in MS SQL. But really it's better to use different queries for different servers (maybe via some abstraction layer).
Use a common table expression (CTE) e.g.
WITH D (INDICATOR)
AS
(
SELECT *
FROM (
VALUES ('O')
) T (c1)
)
SELECT INDICATOR
FROM D;
Or more simply in line:
SELECT *
FROM (
VALUES ('O')
) D (INDICATOR)
You can create the DUAL table in SQL Server:
CREATE TABLE DUAL (DUMMY NVARCHAR(1) NOT NULL);
INSERT INTO DUAL VALUES ('X');
and then use the same query as in Oracle:
select 'O' AS INDICATOR from DUAL;