Golang-migrate returns "no change" - sql

I'm starting learn Go and SQL. I tryed to make initial migration using golang-migrate in my go project. Database is postgresql
This is migration file:
CREATE TABLE users
(
id serial not null unique,
name varchar(255) not null,
username varchar(255) not null unique,
password_hash varchar(255) not null,
)
CREATE TABLE todo_lists
(
id serial not null unique,
title varchar(255) not null,
description varchar(255),
);
CREATE TABLE users_lists
(
id serial not null unique,
user_id int references users (id) on delete cascade not null,
list_id int references todo_lists (id) on delete cascade not null,
);
CREATE TABLE todo_items
(
id serial not null unique,
title varchar(255) not null,
description varchar(255),
done boolean not null default false,
);
CREATE TABLE lists_items
(
id serial not null unique,
item_id int references todo_items (id) on delete cascade not null,
list_id int references todo_lists (id) on delete cascade not null,
);
The command I use:
migrate -path ./schema -database 'postgres://postgres:root#localhost:5432/to_do?sslmode=disable' up
And bash returns:
no change (without any error)
Where can be problem?

I put together a small guide to help you solve your issue. Please be sure to follow along and you would be good to go!
Run Postgres
To run the Postgres instance I used to test my solution I used the following command:
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres
This command spins up an instance of Postgres with these two things:
It sets up the port mapping (the port 5432 on your machine is mapped to the port 5432 of your Docker container).
It sets the password for the postgres user to postgres (just for the sake of the demo).
Create the migration scripts
To create the first migration script, I used the following command:
migrate create -ext sql -dir db/migrations -seq create_users_table
Thanks to this command, I was able to create the folder path db/migrations and two files within it (one for the up migration and one for the down one).
Fill the files with the code
The next step was to fill the above-created files with the CREATE and DROP statements. Let's start with the up one.
000001_create_users_table.up.sql file
CREATE TABLE IF NOT EXISTS users
(
id serial not null unique,
name varchar(255) not null,
username varchar(255) not null,
password_hash varchar(255) not null
);
CREATE TABLE IF NOT EXISTS todo_lists
(
id serial not null unique,
title varchar(255) not null,
description varchar(255)
);
CREATE TABLE IF NOT EXISTS users_lists
(
id serial not null unique,
user_id int references users (id) on delete cascade not null,
list_id int references todo_lists (id) on delete cascade not null
);
CREATE TABLE IF NOT EXISTS todo_items
(
id serial not null unique,
title varchar(255) not null,
description varchar(255),
done boolean not null default false
);
CREATE TABLE IF NOT EXISTS lists_items
(
id serial not null unique,
item_id int references todo_items (id) on delete cascade not null,
list_id int references todo_lists (id) on delete cascade not null
);
To make the migration idempotent I added the IF NOT EXISTS check. Take this as a best practice when you're about to write migrations.
000001_create_users_table.down.sql file
DROP TABLE IF EXISTS users_lists;
DROP TABLE IF EXISTS lists_items;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS todo_lists;
DROP TABLE IF EXISTS todo_items;
The same applies here with the IF EXISTS check. Pay attention to the order in which you're deleting stuff as you can easily get into error due to objects' dependencies.
Run migrations
To run this migration, be sure that the to_do DB is created.
To apply the migration run:
migrate -database 'postgres://postgres:postgres#localhost:5432/to_do?sslmode=disable' -path ./db/migrations up
With this, you'll get this output: 1/u create_users_table (44.392422ms).
If you run this twice, the second output will be: no change.
When you want to undo the migration, you've to run the following statement:
migrate -database 'postgres://postgres:postgres#localhost:5432/to_do?sslmode=disable' -path ./db/migrations down
This will undo all of the migrations applied so far. For a deeper understanding, please refer to the official doc: https://github.com/golang-migrate/migrate#cli-usage.
Let me know if this solves your issue or if you need anything else!

I resolve this problem by deleting migration table and correcting sql file (delete ',' in every string of last columns)

Related

H2 refuses to create auto_increment for Postgres emulated database

I created an in memory H2 database with JDBC URL
jdbc:h2:~/test;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DEFAULT_NULL_ORDERING=HIGH
The H2 web console refuses to let me do an auto_increment. I've seen serial for Postgres, but that doesn't work either.
At it's simplest, it hates:
create table test(id bigint auto_increment);
Syntax error in SQL statement "create table test(id bigint [*]auto_increment)"; expected "ARRAY, INVISIBLE, VISIBLE, NOT NULL, NULL, AS, DEFAULT, GENERATED, ON UPDATE, NOT NULL, NULL, DEFAULT ON NULL, NULL_TO_DEFAULT, SEQUENCE, SELECTIVITY, COMMENT, CONSTRAINT, COMMENT, PRIMARY KEY, UNIQUE, NOT NULL, NULL, CHECK, REFERENCES, ,, )"; SQL statement:
create table test(id bigint auto_increment) [42001-214] 42001/42001 (Help)
Why do I care:
My code base was failing with NULL not allowed for column "REV". I'm using JPA/Hibernate + Liquibase. In order to try the suggestions at
Hibernate Envers + Liquibase: NULL not allowed for column "REV"
I'm trying to add an auto_increment to my Liquibase changelog file.
You can use the SQL Standard's generation clause GENERATED ALWAYS AS IDENTITY. For example:
create table test (
id bigint generated always as identity,
name varchar(10)
);
See PostgreSQL Example.
It works the same way in H2. For example:
create table test(id bigint generated always as identity, name varchar(10));
insert into test (name) values ('Chicago') ;
select * from test;
Result:
ID NAME
-- -------
1 Chicago

Use a condition while creating a table in SQL

I'd like to create a table with a condition
create table TOTO
(
Id int not null,
zip as (if(zip > '00999' and zip < '96000') then zip) ,
PRIMARY KEY (Id)
);
All I get is an error message.
Do you know how to do that with the "zip" in type char ?
Thank you for your help !
You may want to use CHECK constraint instead
CREATE TABLE TOTO
(
Id int NOT NULL,
zip char,
PRIMARY KEY (Id),
CHECK (zip > '00999' AND zip < '96000')
);
You can get this done either using a CHECK CONSTRAINT or using a BEFORE INSERT or INSTEAD OF trigger
An example:
CREATE TRIGGER ChkZip
ON TOTO
INSTEAD OF INSERT
AS
BEGIN
IF (inserted.zip > '00999' and inserted.zip < '96000')
BEGIN
INSERT INTO TOTO (id,zip) VALUES (insered.id, inserted.zip)
END
ELSE
BEGIN
RAISERROR ('The entered zip code doesn't match criteria.' ,10,1)
ROLLBACK TRANSACTION
END
END
CREATE TABLE TOTO
(
Id INT NOT NULL,
zip VARCHAR2(10),
PRIMARY KEY (Id),
CONSTRAINT CHK_zip CHECK (zip > to_number('00999') AND zip < to_number('96000'))
);
You could use check constraint - the above script is based on Oracle Sql function
You need to create a new CHECK constraint so that your field is guaranteed to comply with this constraint each time it is set or modified (insert or update).
Here is an example adapted to SQL server (as you seem to be using that dbms) where the constraint is named so you can identify it more easily (better for maintainability)
create table TOTO
(
Id int not null,
zip char ,
PRIMARY KEY (Id),
CONSTRAINT CHK_zip CHECK(zip > '00999' and zip < '96000')
);
Note that you could formulate it using patterns as in the link I provided.

Remove Unique constraint on a column in sqlite database

I am trying to remove a UNIQUE constraint on a column for sqlite but I do not have the name to remove the constraint. How can I find the name of the UNIQUE constraint name to remove it.
Below is the schema I see for the table I want to remove the constraint
UNIQUE (datasource_name)
sqlite> .schema datasources
CREATE TABLE "datasources" (
created_on DATETIME NOT NULL,
changed_on DATETIME NOT NULL,
id INTEGER NOT NULL,
datasource_name VARCHAR(255),
is_featured BOOLEAN,
is_hidden BOOLEAN,
description TEXT,
default_endpoint TEXT,
user_id INTEGER,
cluster_name VARCHAR(250),
created_by_fk INTEGER,
changed_by_fk INTEGER,
"offset" INTEGER,
cache_timeout INTEGER, perm VARCHAR(1000), filter_select_enabled BOOLEAN, params VARCHAR(1000),
PRIMARY KEY (id),
CHECK (is_featured IN (0, 1)),
CHECK (is_hidden IN (0, 1)),
FOREIGN KEY(created_by_fk) REFERENCES ab_user (id),
FOREIGN KEY(changed_by_fk) REFERENCES ab_user (id),
FOREIGN KEY(cluster_name) REFERENCES clusters (cluster_name),
UNIQUE (datasource_name),
FOREIGN KEY(user_id) REFERENCES ab_user (id)
);
SQLite only supports limited ALTER TABLE, so you can't remove the constaint using ALTER TABLE. What you can do to "drop" the column is to rename the table, create a new table with the same schema except for the UNIQUE constraint, and then insert all data into the new table. This procedure is documented in the Making Other Kinds Of Table Schema Changes section of ALTER TABLE documentation.
I just ran into this myself. An easy solution was using DB Browser for SQLite
It let me remove a unique constraint with just a checkbox in a gui.
PRAGMA foreign_keys=off;
BEGIN TRANSACTION;
ALTER TABLE table_name RENAME TO old_table;
CREATE TABLE table_name
(
column1 datatype [ NULL | NOT NULL ],
column2 datatype [ NULL | NOT NULL ],
...
);
INSERT INTO table_name SELECT * FROM old_table;
COMMIT;
PRAGMA foreign_keys=on;
Source: https://www.techonthenet.com/sqlite/unique.php
I was just working through this issue on a small database and found it easier to dump the data as SQL statements, it prints out your tables exactly as they are and also adds the INSERT INTO statements to rebuild the DB.
The .help terminal command shows:
.dump ?OBJECTS? Render database content as SQL
and prints the SQL to the terminal, you can update it in a TXT file. For once off changes and tidying this seems like a reasonable solution albeit a little inelegant

Liquibase ignorable comments

Is there a way we can add comments in liquibase file which are not parsed by the program?
We are using the text format for the changes.sql and this is how it looks
--changeset Sapan.Parikh:MyUniqueAlphaNumericId5
--comment: Table created for liquibase testing purpose with non numeric id
--6:10 PM 11/10/2015
create table liqui_test11 (
id int primary key,
name varchar(255)
);
create table liqui_test9 (
id int primary key,
name varchar(255)
);
create table liqui_test10 (
id int primary key,
name varchar(255)
);
Our organization has been using similar change log for years and while migrating to Liquibase we want to be able to do two things.
Add dashes or hashes after each changeset.
And after every production build we add a comment at the end of the changes file.
For instance
--changeset Sapan.Parikh:MyUniqueAlphaNumericId5
--comment: Table created for liquibase testing purpose with non numeric id
--6:10 PM 11/10/2015
create table liqui_test11 (
id int primary key,
name varchar(255)
);
-----------------------------------------------------------------
--changeset Sapan.Parikh:MyUniqueAlphaNumericId4
--comment: Table created for liquibase testing purpose with non numeric id
--6:10 PM 11/10/2015
create table liqui_test12 (
id int primary key,
name varchar(255)
);
###------------------Build 10.0.1 Made-------------------
Now if we add just dashes- or # the luqibase task is breaking and DB upgrade does not happen. Is there a way to accommodate comments which are not parsed by liquibase engine?
You can just persist your comments and strip them right before executing liquibase
- can be done easily using sed

In H2 Database, add index while table creation in single query

I am trying to create table having different indexes with single query but H2 gives Error for example:
create table tbl_Cust
(
id int primary key auto_increment not null,
fid int,
c_name varchar(50),
INDEX (fid)
);
but this gives error as
Unknown data type: "("; SQL statement:
[Error Code: 50004]
[SQL State: HY004]
Due to this I have to run 2 different queries to create table with Index. First query to create table and then second query to add index with
create INDEX c_fid on tbl_Cust(fid);
Is there something wrong in my query or H2 simply does not support this creation of table with index in single query?
Interesting question. The solution is even more interesting, as it involves MySQL compatibility mode.
It's actually possible to perform the exact same command you wrote without any modification, provided you just add to your jdbc url the MySQL mode.
Example URL like this: jdbc:h2:mem:;mode=mysql
SQL remains:
create table tbl_Cust
(
id int primary key auto_increment not null,
fid int,
c_name varchar(50),
INDEX (fid)
);
Update count: 0
(15 ms)
Too bad I did not see this question earlier... Hopefully the solution might become handy one day to someone :-)
I could resolve the problem. According to
http://www.h2database.com/html/grammar.html#create_index
I modified the query. It works fine with my H2 server.
CREATE TABLE subscription_validator (
application_id int(11) NOT NULL,
api_id int(11) NOT NULL,
validator_id int(11) NOT NULL,
PRIMARY KEY (application_id,api_id),
CONSTRAINT subscription_validator_ibfk_1 FOREIGN KEY (validator_id) REFERENCES validator (id) ON UPDATE CASCADE
);
CREATE INDEX validator_id ON subscription_validator(validator_id);