Add auto increment with labeled primary key to existing table in SQL Server and H2 / Liquibase - sql

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.

Related

Joomla : libraries mysql schema does not working for Insert records, add primary key, drop table command

On extension update, instead of using update SQL schema I have given a custom button like fix database under that extension. It working fine. Custom script executes from same schema folder structure i.e. "/sql/updates/mysql"
But some DDL commands are not working like INSERT, ALTER for adding primary key for already existing table, DROP to delete table.
I have checked the MysqlChangeItem.php file (using Joomla 3.8.10) under "libraries/src/Schema/ChangeItem" & found the different DDL commands which are handled but does not found about INSERT/adding primary key for existing table/drop table.
Can you please suggest the solution

How to tell HSQLDB to allow identity definition for SERIAL?

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, ..

Add auto generated key to existing PK in Oracle

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

Change primary key on SQL database

I have a database that I migrated from MySql using SQL Server Migration Assistant and it is now stored in Azure.
SSMA apparently generated a new primary key column, named ssma$rowid, for one of the tables. I am trying to change the PK back to Card_Key, but I am getting the following error:
An error was encountered while applying the changes.
An exception occurred while executing the Transact-SQL statement:
ALTER TABLE [carddb].[Cards] ALTER COLUMN [Card_Key] INT NOT NULL.
The index 'Card_Key' is dependent on column 'Card_Key'.
ALTER TABLE ALTER COLUMN Card_Key failed because one or more objects
access this column.
How can I make Card_Key the PK again?
The easiest might be to create a new table [cards2] with the correct primary key and copy your data from [cards] into the new table (just run a INSERT INTO cards2 ... SELECT ... FROM cards). Once that's done, you can drop (or rename to [cardsold] be on the safe side) the original table [cards], and rename the new table as [cards]: sp_rename cards2, cards
This should work.

sql server helper stored procedure or utility for alter table alter column IDENTITY(1,1)

I wanted to modify a column in a sql server 2005 table to IDENTITY(1,1)
Incidentally this table is empty and the column to be changed is a primary key.
This column is also a foreign key for two other tables.
After googling I found that you cannot use Alter table syntax to modify a column and make it an indentity column.
Link #1 : How do I add the identity property to an existing column in SQL Server
Link #2 : Adding an identity to an existing column -SQL Server
I ended up checking the dependent tables (2 of them) removing the foreign keys (generated the script from SSMS) then dropping the main table then re-creating with identity. (could try the rename option here as well)
Then re-created the foreign keys for the earlier dependent two tables.
But all this was manual work, any scripts or SPs out there to make this easier.
Ideally all these steps would be done by such a script/tool/utility:
Check dependent tables keys
Generate Create and drop foreign key scripts for this
Generate create script for the main table
drop the main table (or rename the table if the table has data)
re-create the table with identity column enabled
re-create foreign keys
You can use SSMS to generate a script (Edit a table, save script), but otherwise it's a manual process as you identified.
The SSMS scripts will pick up dependencies etc. For this kind of work, I tend to use SSMS to generate a basic script, pimp it a bit, run it carefully, then use a comparison tool (such as Red Gate compare) to generate a safer version.
Edit: The SSMS error is not an error, it's a safety check that can be switched off
(This is merely a follow-up to gbn's post with more details -- it isn't all that easy to figure this stuff out.)(
It isn't impossible to write a utility to do this, just very complex and very hard. Fortunately, Microsoft has already done it -- its called SSMS (or SMO?). To generate such a script:
In the Object Explorer, drill down to the database and table that you want to modify
Right click and select Design
Make the desired changes to the one table in the design screen. It's reasonably intuitive.
To add/remove the identity property, select the column in the upper pane, and in the lower pane/"Column Properties" tab, expand and configure the settings under "Identity Specification".
To generate a script to implement all your changes, incorporating all the dependent key changes, click on the "Generate Change Script" toolbar button. This is also an option under the "Table Designer" menu.
I also do this to generate scripts (that I later modify--SSMS doesn't always produce the most efficient code.) Once done, you can exit out without saving your changes -- leaving you a DB you can test your new script on.
drop the pk and build the same datatype column
copy the data of the column which you want to set identity to the new column.
drop the old column
reset primary key
ALTER TABLE UserRole
DROP CONSTRAINT PK_XX
ALTER TABLE XX
ADD newX int not null identity(1,1) primary key
update XX set newX = oldX
alter table XX
DROP COLUMN oldX
this is the simplest way to set identity column.
if you don't want to use the long generated script.