For hsql, literals, whether column values or table names, are in single quotes. INSERT INTO tablename (col1, col2,...) VALUES (val1, val2,...); UPDATE tablename SET col = 'val' WHERE expression; You generally can not executeUpdate() on a query. Can only executeQuery it. Standards docs http://www.wiscorp.com/SQLStandards.html Excellent Oracle SQL ref: http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10759/toc.htm SQL Time/Date types, all direct java.util.Date subclasses. Selection of COLUMN type is easy, to save milliseconds, always need a TIMESTAMP-like column. Then, use the setter() to give you the right resolution. Oracle to second: DATE col, setTimestamp(), getTimestamp(). (Oracle setTime() and getTime() do not preserve dates). HSQLDB to second: TIME col, getTimestamp(), setTimestamp() (but be aware returned times are sometimes in UT). Either to sub-second: TIMESTAMP w/ getTimestamp() and setTimestamp(). TYPES RETURNED Related to col type and ps getter. Unrelated to inserted data type. ps.getObject() returns Vendor-determined types which may be either vendor classes or java.sql.*. ps.getX() ALWAYS returns the requested java.sql.* type. Date is to the millisecond. Seems to be intended for localization. toString() and valueOf() only do yyyy-mm-dd. ps.setDate() sets only the date. Time. Ditto, but does not seem to be intended for localization. toString() and valueOf() only do hh:mm:ss. ps.setTime() sets only the time of day. Like others, but with nanoseconds value. Should not compare with other java.util.Dates. toString() and valueOf() only do yyyy-mm-dd hh:mm:sss.f[ffffffff]. These all have JDBC static Type.valueOf(String) TO converters. HSQLDB getObject() always returns the java.sql.* type most appropriate for the column type. HSQLDB can't getDate() from a TIME col. HSQLDB can't getTime() from a DATE col. HSQLDB don't do setTime() to a TIMESTAMP field. HSQLDB setTimestamp() always stores a time that gets localized properly. HSQLDB columns store resolution according to the corresponding java.sql.* type EXCEPT THAT TIMEs store DATE + TIME (down to second). HSQLDB setTime() stores DATE AND time of day down to the second (regardless of column type). (NO SUB-SECONDS) Oracle has only DATEs and TIMESTAMPs, both of which store body date and time (but with different resolution). Oracle DATEs store only to the second. TIMESTAMP has configurable subseconds (don't know default). N.b. since DATE cols can only store to second, then regardless of ps.set*() or rs.get*(), you can't get better resolution than second. Oracle getObject() returns oracle.sql.TIMESTAMP for TIMESTAMP cols-- which doesn't even have a decent toString(); and java.sql.Timestamps for DATE cols! Oracle setTime() stores time of day down to the second (regardless of column type). (NO DATE OR SUB-SECONDS) Oracle setDate() stores only date (regardless of column type). Oracle permits all set*()s and get*()s with both DATE and TIMESTAMP cols. Only portable way to transfer date/time fields without losing anything seems to be to use getTimestamp() and setTimestamp() and use its toString() and valueOf(). (With both Oracle and HSQLDB...) Nulls are an exception to Join relationships. I.e., uniqueness and FK's do not constrain nullity. You can have multiple nulls in a unique column. (Use NOT NULL if that's what you want). The following apply to Joins, regardless of whether PK or FK are used. Null values are not joined (i.e., are ignored on both sides) in a Join. If both columns contain multiple nulls, no joined row will be made with any null. Uniqueness (without additional Nullality constraints) constrains NULLs exactly as if they were real distinct values (at least with HSQLDB 1.8.0.10). IF YOU WANT TO JOIN WITH NULLS, you must UNION a regular JOIN with a SELECT... WHERE a.x IS NULL and b.y IS NULL PRIMARY KEY implies a NON-NULL constraint, but FK does not. Therefore, can have unjoined NULLs in FK cols. In both Oracle and HSQLDB, the referenced column of a PK must have a unique constraint. SQL joins (other than FROM... WHERE Inner joins): ... FROM tbl1 JOIN tbl2 ON Default INNER JOIN selects rows common to the joined tables. Can use either normal FROM tbl1, tbl2 WHERE or FROM tbl1 INNER JOIN tbl2 ON AN OUTER JOIN selects more than just the joined rows. LEFT JOIN produces >= 1 output row for each row of the LEFT table. RIGHT JOIN produces >= 1 output row for each row of the RIGHT table. (with nulls for non-joined values). In Oracle, use (+) for the >=1 row table. Standard SQL replace "LEFT JOIN" or "RIGHT JOIN" for "INNER JOIN" (with "LEFT meaing the FROM table, and "RIGHT" meaning the JOIN table). Literals: Concatenation: 'word one' 'word two' (don't need || operator) Bit constants: B'010' (case-insensitive. No space between "b" and ') Binary constants: X'a0b3' (case-insensitive. No space between "x" and ') Can use concatenation for bit and binary substrings. For binaries, the substrings must be complect octets = 2 hex digits. HyperSQL returns lower-case hex digits. Group by clauses (but not order by) require real, original column names. Can use a subquery or view to allow you to group. There's probably a less invasive way to do this, but I don't know it. Oracle's CREATE OR REPLACE is not usable with most object types. It specifically is usable with VIEWs, but not with TABLEs. No parens around "distinct" parameters. OUTER JOINS LEFT/RIGHT indicate the sequence of the table in the FROM list, Left or Right of the X JOIN keywords. The indicated LEFT/RIGHT table produces >= 1 output-row-per-table-row. 1 for each non-match of the total WHERE + 1 or more for each match of the total WHERE NULLS "= null" and "!= null" does not work. You must use "IS [not] NULL". "!= x" of "<> x" does not match nulls. This is true for at least Oracle and HyperSQL. Echoing string: Only ultra-portable is to select a constant, like SELECT 'a string' FROM dual; HSQLDB: CALL 'a string';