KnowDotNet NetRefactor

Converting Access SQL to Oracle

Tips to Help You Convert

by Les Smith
Print this Article Discuss in Forums

There are numerous incompatibilities between Access/Jet SQL and Oracle SQL, including the following:

1. The date delimiter is "#" in Access and " ' " (single quote) in Oracle.

2. In CHAR Datatype, Oracle returns trailing spaces. Access does not return trailing spaces in String data type. In Oracle, use VarChar2 Datatype.

3. Jet allows use of the "Join" keyword. Oracle uses "(+)" following the joined field(s). Join is not a recognized word in Oracle.

4. IIF() is allowed in Jet but in Oracle, you must use the DECODE function. See Oracle documentation.

5. The following functions in Jet must be translated in Oracle.

Mid(fld, 2, 2) - Substr(fld, 2, 2)
Left(2) - Substr(fld, 1, 2)
Right(n) - Substr( fld, Instr(...),n)
Len() - LENGTH()
Year(Fld) = 1997 - to_char(Fld, 'yyyy') = '1997'
Month(Fld) = 6 - to_char(fld, 'mm') = '06'
Trim(Fld) - LTrim() or RTrim()

6. Generally, you need to use "to_date('01/23/1978', 'mm/dd/yyyy')" to format a date for comparison in Oracle SQL whereas in Jet Sql you could simply use "#01/23/1978#".

7. "RENAME" is a reserved word in Oracle and is therefore an illegal field or table name, but not in Jet.

8. If a memory variable is used in a SQL statement, and the variable is a string with trailing spaces, Jet will trim the value before comparing to the database field. Oracle will not! Therefore, the following will work in Jet but not Oracle, assuming the Oracle field in VARCHAR[2].

Sql = " ... where fldname = 'abc ' ...."

9. Oracle SQL will not find uppercase data in the database if the value in the SQL statement is lowercase. Assume that the LastName field contains the value 'SMITH' in the Oracle table Policy. Access will make a find on the following SQL and Oracle will not (Like character would be "*" for Access.

select * from Policy where LastName Like 'smith%'

10. Conversion of Memo (Jet) fields to Oracle can be a problem. The only data type in Oracle that is analogous to the Memo in Jet is the Long. Although it can hold up to 2gb of string data, you cannot append more than approximately 5,000 characters to the existing Long field because you exceed the length of the maximum string length in an Oracle SQL Statement.

Additionally, you cannot use such expressions, as the following, usable in Jet, in Oracle. They result in the error, "Invalid use of Long Datatype."

select distinct LONGFLD


It seems impossible to use a query to determine rows where there is data in the Long field since a Long field that has '' in it is not Null.

Oracle 8 has Append and Get Chunk commands, but the documentation in the Oracle 7.2 Book does not mention these functions, nor are there any examples of how to update a Long field that exceeds 5,000+ characters.

11. Use of the following sql can be extremely slow in Oracle.

select * from table where policy in
(select policy2 from table2 where .....)

Try using the Oracle Minus operator instead. It uses indexes where the "in (select...)" does not. See the Oracle documentation for usage of the Minus.

12. It is normal, when using Jet, to fill the recordsource property of a data control at design time, even if you are going to fill it with a specific SQL sometime after Form_Load. This is done in order to use the Grid Designer when a data control is bound to a Grid or Combo, etc. However, when the form loads, all such data controls are refreshed. If you have the table name as the data control recordsource, which would be normal for designer use, and assuming that dbSQLPassThrough is being used, the entire table is returned to the client machine and refreshed into the grid, even if the grid is not visible, i.e., on a different tab. In Jet, this will not be the case if "UseExactRow" property is not set and therefore will not take an inordinate amount of time, but in Oracle it could be disastorous!

An easy way to deal with this is to set the recordsource to "" in the Form_Load event, especially if you are connected to Oracle. Later on, your code will set the recordsource to the specific SQL as required. Note that this must be done in the Form_Load because the Grid will be refreshed by the time the Activate Event is fired.

13. Be aware that, when using dbSQLPassThrough, the entire recordset, specified by the SQL, is returned to the client machine, and is therefore readonly. At this point the recordset belongs to the client, and Oracle is out of the picture. In praticality, there is no difference between a Snapshot and Dynaset in passthrough mode.

14. Use of apostrophes (') in names and abbreviations are a problem in SQL. In Access, it may be circumvented by use of the double quote (") to encapsulate string data in the SQL statement instead of the apostrophe, thus allowing the use of the (') in the string. In Oracle, you can use two single quotes ('') to denote an apostrophe. The string below is valid in Oracle Sql.

... Set Lastname = 'O''Toole',...

It is a good idea to use the Replace() function to prepare any string field that could have a single quote in it, to insert two single quotes. For example,
...SQL = SQL & "set LastName = '" & Replace(lsNameVar, "'", "''") & "', "

15. In Access, an empty string ("") is not Null. Oracle's default parameter for Null is set to '' (double single quotes or empty string). In other words, Oracle, by default, treats an empty string field as Null. Therefore, the following code which works in Access, does not work in Oracle.

...Where RTrim(Fld) <> ''.....

In Oracle, change the SQL to:

... Where Fld is not null....

Also, the following sql will not work if a field is Null.

... Where STATE <> 'Z'...

Even though the field is null, and therefore <> 'Z', the row containing the Null field will not be returned. In order to get the row, you must enhance the SQL as:

...where (STATE <> 'Z' or STATE is Null)...


16. When using dbSQLPassThrough with DAO, the RecordsAffected Property will always return -1, and there is apparently no way to determine whether any records were affected by an action sql or not. (classic ADO)

17. When printing an error message from ODBC, if you print Error, as in the errors object, you will print "ODBC Call Failed", which is useless. Instead, print Errors(0).Description (or both) and you will get the true error description returned from the ODBC data source.

18. If you are having trouble with a bound data control returning less than the correct number of row, i.e., returns 100 rows when it should have returned 200 or more, set the DefaultCursorType to 1 (ODBC Cursor). For some reason this is not always required, but it will solve the problem of truncated recordsets in a data control connected to Oracle.

19. Access allows an Order By clause at the end of a query that uses a Union, but if you try this in Oracle, it will not work because Oracle ignores the column names in the result set from the Union.
Not to worry! You can Order By column positions from the select statement. In other words, if Name is returning in column 3 of the result set, and you want to order by Name, then use "Order By 3..."
20. Sometimes, while using (Classic) ADO, the following construct will yield NULL, even when it is not null!
lsLastName = rs!LastName

It is better to use the following construct, and it will solve the problem.
lsLastName = rs.Fields("lastname").value

If you have comments on any of my articles, or want to ask a question, contact me on my blog at
Les's Blog.

Writing Add-Ins for Visual Studio .NET
Writing Add-ins for Visual Studio .NET
by Les Smith
Apress Publishing