I'm currently writing tests for a spring boot application which is using a postgreSQL database. During test I want to replace the database by some in-memory variant like H2 or HSQLDB. Sadly both do not behave the same as the postgreSQL database.
I have migrations that look like
CREATE TABLE foo(id BIGSERIAL PRIMARY KEY, ...)
This results in hsqldb telling me
SQL State : 42525
Error Code : -5525
Message : identity definition not allowed: FOO_ID
So apparently creating the matching sequence for the primary key is forbidden. Is there a way to tell hsqldb to accept this?
You need to set PostgreSQL compatibility mode in HSQLDB.
SET DATABASE SQL SYNTAX PGS TRUE
Your table definition is then accepted and converted internally to the SQL Standard equivalent.
CREATE TABLE FOO(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY, ..
Related
I am currently using liquibase to apply changes to H2 and SQL Server.
Goal:
add a column id with auto increment to an existing table
add a primary key constraint with constraint name to id
Liquibase auto increment does not support SQL Server so I need to find a solution in SQL.
What I want is something like this:
<sql>
ALTER TABLE user ADD COLUMN id INT NOT NULL AUTO_INCREMENT;
</sql>
<addPrimaryKey columnNames="id" constraintName="userPK" tableName="user"/>
This statement is only working in H2 but not in SQL Server.
For SQL Server, IDENTITY seems to be the command to apply auto increment so I tried to write another statement that uses IDENTITY instead.
The problem with IDENTITY is that it automatically creates a primary key when using H2 which is not what I want because I would have to somehow find and rename it. SQL Server does not automatically create this primary key when using IDENTITY.
It is important to control the name of the primary key and that the name is the same for both databases.
I would appreciate any help.
Edit:
Another attempt was to split the sql commands:
<sql dbms="h2">
ALTER TABLE user ADD ID INT auto_increment;
</sql>
<sql dbms="mssql">
ALTER TABLE user ADD id INT IDENTITY(1, 1);
</sql>
<addPrimaryKey columnNames="id" constraintName="userPK" tableName="user"/>
H2 however ignores the constraintName in addPrimaryKey and instead generates another name. I wanted the names to be the same but I noticed that I can still use dropPrimaryKey to drop it.
Unfortunately, H2 1.4.200 doesn't yet emulate non-standard IDENTITY clause from SQL Server well enough and SQL Server doesn't support standard identity columns (ID BIGINT GENERATED BY DEFAULT AS IDENTITY etc.) supported by H2 and various other DBMS.
You need to compile H2 from its current sources available on GitHub:
https://github.com/h2database/h2database
There are build.cmd and build.sh scripts in h2 subdirectory. You need to launch a proper script for you OS with jar argument (build jar or ./build.sh jar). Use Java 8 or 11 (compiled jar will be compatible with more recent versions too).
With the compiled snapshot version you will be able to use
CREATE TABLE TEST1(ID BIGINT IDENTITY, V INT);
CREATE TABLE TEST2(V INT);
ALTER TABLE TEST2 ADD ID BIGINT IDENTITY;
and similar commands in MSSQLServer compatibility mode (append ;MODE=MSSQLServer to JDBC URL) and these commands will not create unexpected primary key constraints.
I'm porting a SQL Server based app to Oracle. Our Oracle DBA has given me a schema that was supposed to be identical to the original SQL Server schema (and generated from it), but the auto generated keys are missing. I am trying to alter these table PK's from a normal INT to incrementing. I am doing so with Oracle SQL Developer 4.0.3 and Oracle 12c.
The error I receive is ORA-01442: column to be modified to NOT NULL is already NOT NULL
I get this after editing the table, selecting the column and setting it's Identity dropdown to 'Generated as Identity'. I am not sure why SQl Developer is attempting to make it not null when it's already a PK.
My questions are: Is this the proper way to setup a generated key? How can I get around this? If I go alter all the required columns, can the DBA use the schema to regenerate whatever procedure he used to create it in the first place to allow proper generated keys and is there a better solution for creating a good schema to go forward with?
Thanks.
If the column is already definied as NOT NULL there is no need to re-defined it as NOT NULL. Therefore you get the error ora-01442.
The best way to obtain sequence values, such as identity in SQL Server, is define the column with default sequence, before inserting row:
CREATE SEQUENCE SEQ_NAME
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
ALTER TABLE table_name MODIFY column_name INT DEFAULT SEQ_NAME.NEXTVAL;
PD: This DEFAULT works with 12 c. To 11g or less, you must create a trigger
I need a very simple thing in SQL Database - I am using SQL Server and/or SQL Compact.
In c# I would write it like this
public class MyApp
{
public static int Version = 1;
}
e.g. I need to store configuration information in a form of singleton in SQL database.
Is there any better method than to create table with only one record?
Actually for my present needs it would be sufficient to have only one version number stored with database, but it must work both for SQL Server and SQL Compact database.
A table with one row is probably your best approach. Normally, you'd use a CHECK() constraint to guarantee you'll have only one row.
create table your_table_name (
one_row integer not null unique
default 1 check (one_row = 1),
version varchar(5) not null unique
);
insert into your_table_name values (1, '0.0.0');
If your platform doesn't support CHECK() constraints, but does support GRANT and REVOKE, you might be able to insert one row into the version table, then grant only update permissions. (Revoke delete and insert permissions.)
If your platform doesn't support CHECK() constraints, and doesn't support GRANT and REVOKE, but does support foreign key references, you might be able to replace the CHECK() constraint above with a foreign key reference to single-row table. This doesn't entirely solve the problem--you still have a single-row table that you can't adequately constrain.
If your dbms supports regular expressions in CHECK() constraints, you could add additional constraints to guarantee your version number follows a regular expression. You could also split the "version" into several columns of integers, each with its own constraints. But varchar(5) and varchar(7) seem to be the most common.
Does Firebird Database support Schema? If so, how can I create a schema in Firebird DB through ISQL? Please help me to create schemas in Firebird DB. I have tried to retrieve schema using
AbstractDatabaseMetaData.getSchemas()
But it is always retrieving empty resultset. Can anyone please help me in retrieving schemas? At least SYSTEM schema when there is no schema.
Firebird currently doesn't have schemas, and therefor Jaybird doesn't return any. This complies with the JDBC specification, which says:
If a given form of metadata is not available, an empty ResultSet will be returned.
Note that Firebird does have a CREATE SCHEMA, but that is simply an alias for CREATE DATABASE.
No, schema not supported, but you can create many databases files. Here manual for create database with Firebird tool. Also you can create database with IBExpert or similar tool.
Also, you can create sql-cript for automate it:
$ isql -q -i create-db.sql
Also you can run it from java code.
--Contents of create-db.sql
CREATE DATABASE '/my/path/my-db.fdb' page_size 8192 USER 'SYSDBA' PASSWORD 'masterkey';
CREATE EXCEPTION EX_SOME_EXCEPTION 'Some extension message';
CREATE TABLE ROOMS (
ID integer NOT NULL PRIMARY KEY,
Number char(10),
Name char(100),
Network char(100),
Memo char(100)
);
CREATE GENERATOR ROOMS_IDGEN;
SET TERM !! ;
CREATE TRIGGER ON_ROOMS_INS FOR ROOMS BEFORE INSERT AS
BEGIN
IF (NEW.ID IS NULL) THEN NEW.ID=GEN_ID(ROOMS_IDGEN, 1);
END !!
SET TERM ; !!
....
Is there a standardized way I can create a table in SQL with a column (lets call it ID) that is auto incremental so that I can basically use it in all databases?
(e.g. standardized in SQL-92)
If so - how? If not, why? I think auto_increment is a very often used property so I thought it would be very important to standardize it…
Nope, sorry. There is AUTO_INCREMENT in MySQL, but e.g. in MS SQL this is called IDENTITY and SERIAL in PGSQL. Many things are not really standardized in SQL - and most are in the schema creating area.
It's a mess, but you can use stuff like e.g. Hibernate/NHibernate to try to use a single code base.
Update: Few year later there is a more standard way that some DBMS support (e.g. PG SQL from version 10.0, so from October 2017):
GENERATED BY DEFAULT AS IDENTITY -- the value has a default auto incrementation, but you can insert your own.
GENERATED ALWAYS AS IDENTITY -- forbids inserting own values (in a standard query, might be overriden)
This is something that should work in PG SQL 10+, DB2, Oracle:
DROP TABLE IF EXISTS simple_test;
CREATE TABLE simple_test(
s_id int PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
);
Note however that this will not work in Microsoft SQL Server (not even in MS SQL Server 2022). MSSQL does not support the generated keyword. MySQL/MariaDb has generated columns, but MariaDb does not support the identity syntax.
So yeah, 10 years later the answer is kind of the same really -- it is still a mess and you should probably use a framework for that.
You can use so-called identity columns:
CREATE TABLE foo(id int GENERATED ALWAYS AS IDENTITY);
This is in the SQL standard and should be supported by PostgreSQL 10 and Oracle:
https://www.2ndquadrant.com/en/blog/postgresql-10-identity-columns/#comment-248607
In Oracle you need to create a SEQUENCE
SQLite uses it for rowid and a synonym of it e.g. RowIdSyn INTEGER PRIMARY KEY AUTOINCREMENT