Apache NiFi: failed INSERT statement caused by NOT NULL CONSTRAINT - sql

I have a JSON
{
"username" : "ChokkiAST",
"login_date" : "2021-01-15",
"active": true
}
I want to INSERT this data into database table with structure:
CREATE TABLE web.accounts_activity (
username text NOT NULL,
login_date date NOT NULL,
active bool NULL DEFAULT false,
id SERIAL NOT NULL,
CONSTRAINT web.accounts_activity_username_key UNIQUE (username),
CONSTRAINT cabinet_account_pkey PRIMARY KEY (id)
);
My JSON doesn't contain id field because database should auto generate values (I perform transffering from Spring JPA code). I tried with PutDatabaseRecord with INSERT statement and I got the error: CONSTRAINT ERROR: value NULL at column "id". Tried with UPSERT statement - same error.
Also I tried to use PutSQL processor with following SQL script (values from attributes):
INSERT INTO web.accounts_activity (username, login_date, active, id)
VALUES (${username}, ${login.date}, ${is.active}, DEFAULT);
And I got the error:
ERROR: current transaction is aborted, commands ignored until end of transaction block
So, how to exactly insert this id with Apache NiFi?

Remove id completely from the lists of columns and values. It will auto-generate a value, this is how serial works.
INSERT INTO web.accounts_activity (username, login_date, active)
VALUES (${username}, ${login.date}, ${is.active});

Related

postgres doesn't autogenerate PK if the PK is inserted manually

I have a simple table like this:
CREATE TABLE IF NOT EXISTS myval
(
id integer NOT NULL DEFAULT nextval('myval_myval_id_seq'::regclass),
name character varying(255),
CONSTRAINT "PK_aa671c3359a0359082a84ecb801" PRIMARY KEY (id)
)
the sequence definition is:
CREATE SEQUENCE IF NOT EXISTS myval_myval_id_seq
INCREMENT 1
START 1
MINVALUE 1
MAXVALUE 2147483647
CACHE 1
OWNED BY myval.myval_id;
when I insert data along with the primary key:
INSERT INTO myval(id, name) VALUES (1, 'sdf');
INSERT INTO myval(id, name) VALUES (2, 'sdf');
INSERT INTO myval(id, name) VALUES (3, 'sdf');
INSERT INTO myval(id, name) VALUES (4, 'sdf');
then, I insert it without the PK:
INSERT INTO myval(name) VALUES ('new sdf');
it gives an error saying:
duplicate key value violates unique constraint "PK_aa671c3359a0359082a84ecb801",
DETAIL: Key (myval_id)=(1) already exists.
I expected it to start with PK value of 5 but, instead it gives an error. Can we configure postgres to skip conflicting values and generate from the closest available value to use instead of throwing an error?
The best way to avoid such conflicts is to use identity columns - in this case a GENERATED ALWAYS AS IDENTITY seems the right option.
CREATE TABLE IF NOT EXISTS myval
(
id integer GENERATED ALWAYS AS IDENTITY,
name character varying(255),
CONSTRAINT "PK_aa671c3359a0359082a84ecb801" PRIMARY KEY (id)
);
This will work like a sequence (serial), however it will fail if the user tries to manually insert a value in this column
INSERT INTO myval (id,name)
VALUES (1,'foor');
ERROR: cannot insert a non-DEFAULT value into column "id"
DETAIL: Column "id" is an identity column defined as GENERATED ALWAYS.
TIP: Use OVERRIDING SYSTEM VALUE to override.
If for whatever reason you must override this behavior in a certain INSERT statement you can do so using OVERRIDING SYSTEM VALUE, as the error message above suggests
INSERT INTO myval (id,name) OVERRIDING SYSTEM VALUE
VALUES (1,'foo');
You might be able to achieve a sequential value using serial even if the user screws things up with inserts, e.g. using trigger functions. But such an architecture is hard to maintain and imho is definitely not worth the trouble.
Demo: db<>fiddle

PostgreSQL- insert result of query into exisiting table, auto-increment id

I have created an empty table with the following SQL statement. My understanding (based on this tutorial: https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-serial/) was that SERIAL PRIMARY KEY will automatically provide an auto-incremented id for every new row:
CREATE TABLE "shema".my_table
(
id SERIAL PRIMARY KEY,
transaction text NOT NULL,
service_privider text NOT NULL,
customer_id text NOT NULL,
value numeric NOT NULL
)
WITH (
OIDS = FALSE
);
ALTER TABLE "shema".my_table
OWNER to admin;
Now I am querying another tables and would like to save the result of that query into my_table. The result of the query outputs following schema:
transaction
service_provider
customer_id
value
meaning the schema of my_table minus id. when I try to execute:
INSERT into my table
Select {here is the query}
Then I am getting an error that column "id" is of type integer but expression is of type text. I interpret it that the sql query is looking for id column and cannot find it. How can I insert data into my_table without explicitly stating id number but have this id auto-generated for every row?
Always mention the columns you want to INSERT:
INSERT INTO schemaname.my_table("transaction", service_privider, customer_id, value)
SELECT ?, ?, ?, ?;
If you don't, your code will break now or somewhere in the future.
By the way, transaction is a reserved word, try to use a better column name.

How to execute an unordered SQL script

I have a SQL script but there is an issue with the order of the statements in the script
e.g.
INSERT INTO PERMISSIONS_FOR_ROLE (ROLE_ID, PERMISSION_ID) VALUES (3, 8);
INSERT INTO permissions (id, name) VALUES (8, 'update');
The order of occurrence in the script should have been reverse! And this results in a error because the foreign key with id 8 is not yet inserted when the first statement executes
leading to:
[Code: -177, SQL State: 23503] integrity constraint violation:
foreign key no parent; PERMISSIONS_FOR_ROLE_PERM_FK table: PERMISSIONS_FOR_ROLE value: 8
statements used to create the relationships are as below
create table PERMISSIONS ( ID bigint not null, NAME varchar(255), primary key (ID) );
create table PERMISSIONS_FOR_ROLE ( ROLE_ID bigint not null, PERMISSION_ID bigint not null, primary key (ROLE_ID, PERMISSION_ID) );
alter table PERMISSIONS_FOR_ROLE add constraint permissions_for_role_perm_fk foreign key (PERMISSION_ID) references PERMISSIONS;
Any suggestions on how to execute such a script ? I tried manually changing the order and the script executes properly but is there any other way to do it as its run as part of a ANT build target.
For mass inserts with very large scripts that are out of order, you can disable referential integrity checks with:
SET DATABASE REFERENTIAL INTEGRITY FALSE
see http://hsqldb.org/doc/2.0/guide/management-chapt.html#mtc_sql_settings on how to check for possible violations after the insert.

Is there a way to prevent a query from setting the serial primary key?

I've got a bunch of tables with the 'serial' keyword on a primary key so that auto-increment will work. The problem is that I can make a query to insert a row using any id number which overrides the auto-increment. Is there a reason for this? Or, is there a way to prevent a user from adding/changing this value?
Here's an example of my table config:
create table if not exists departments (
department_id serial primary key,
name varchar(64) not null unique
);
if I run the following query, I can add any number to primary key:
insert into departments (department_id, name) values (9001, 'FooBar')
I think I want to prevent this from happening. I'd like to get some opinions.
Use an identity column:
create table if not exists departments (
department_id integer primary key generated always as identity,
name varchar(64) not null unique
);
This will prevent an insert to override the generated value. You can still circumvent that by specifying OVERRIDING SYSTEM VALUE as part of your INSERT statement. But unless you specify that option, providing a value for the column will result in an error.
Related: PostgreSQL: serial vs identity
Unless '9001' isn't already in the registers, it shouldn't cause any trouble.
If the filed 'department_id' is already auto increment you can just run your insert statement like
INSERT INTO departments (name) VALUES ('FooBar')
I'm using Microsoft sql server and you can control the insert of value in identity column by below sql command
SET IDENTITY_INSERT [ [ database_name . ] schema_name . ] table_name { ON | OFF }
By setting it to 'OFF' you cannot insert a value in identity column.
For more info refer: https://learn.microsoft.com/en-us/sql/t-sql/statements/set-identity-insert-transact-sql?view=sql-server-ver15

Why is SQL server throwing this error: Cannot insert the value NULL into column 'id'?

I'm using the following query:
INSERT INTO role (name, created) VALUES ('Content Coordinator', GETDATE()), ('Content Viewer', GETDATE())
However, I'm not specifying the primary key (which is id). So my questions is, why is sql server coming back with this error:
Msg 515, Level 16, State 2, Line 1
Cannot insert the value NULL into column 'id', table 'CMT_DEV.dbo.role'; column does not allow nulls. INSERT fails.
The statement has been terminated.
I'm assuming that id is supposed to be an incrementing value.
You need to set this, or else if you have a non-nullable column, with no default value, if you provide no value it will error.
To set up auto-increment in SQL Server Management Studio:
Open your table in Design
Select your column and go to Column Properties
Under Indentity Specification, set (Is Identity)=Yes and Indentity Increment=1
use IDENTITY(1,1) while creating the table
eg
CREATE TABLE SAMPLE(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Status] [smallint] NOT NULL,
CONSTRAINT [PK_SAMPLE] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
)
If the id column has no default value, but has NOT NULL constraint, then you have to provide a value yourself
INSERT INTO dbo.role (id, name, created) VALUES ('something', 'Content Coordinator', GETDATE()), ('Content Viewer', GETDATE())
Encountered the same issue. This is something to do with your table creation. When you created table you have not indicate 'ID' column to be Auto Increment hence you get this error. By making the column Primary Key it cannot be null or contain duplicates hence without Auto Increment pretty obvious to throw column does not allow nulls. INSERT fails.
There are two ways you could fix this issue.
1). via MS SQL Server Management Studio
Got to MS SQL Server Management Studio
Locate your table and right click and select Design
Locate your column and go to Column Properties
Under Indentity Specification: set (Is Identity)=Yes and Indentity
Increment=1
2). via ALTER SQLs
ALTER TABLE table DROP COLUMN id; // drop the existing ID
ALTER TABLE table ADD id int IDENTITY(1, 1) NOT NULL; // add new column ID with auto-increment
ALTER TABLE table ADD CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id); // make it primary key
You either need to specify an ID in the insert, or you need to configure the id column in the database to have Identity Specification = Yes.
As id is PK it MUST be unique and not null.
If you do not mention any field in the fields list for insert it'll be supposed to be null or default value.
Set identity (i.e. autoincrement) for this field if you do not want to set it manualy every time.
You need to set autoincrement property of id column to true when you create the table or you can alter your existing table to do this.
you didn't give a value for id. Try this :
INSERT INTO role (id, name, created) VALUES ('example1','Content Coordinator', GETDATE()), ('example2', 'Content Viewer', GETDATE())
Or you can set the auto increment on id field, if you need the id value added automatically.
I had a similar problem and upon looking into it, it was simply a field in the actual table missing id (id was empty/null) - meaning when you try to make the id field the primary key it will result in error because the table contains a row with null value for the primary key.
This could be the fix if you see a temp table associated with the error. I was using SQL Server Management Studio.
WARNING! Make sure the target table is locked when using this method
(As per #OnurOmer's comment)
if you can't or don't want to set the autoincrement property of the id, you can set value for the id for each row like this:
INSERT INTO role (id, name, created)
SELECT
(select max(id) from role) + ROW_NUMBER() OVER (ORDER BY name)
, name
, created
FROM (
VALUES
('Content Coordinator', GETDATE())
, ('Content Viewer', GETDATE())
) AS x(name, created)
RULE: You cannot IGNORE those colums that do not allow null values, when inserting new data.
Your Case
You're trying to insert values, while ignoring the id column, which does not allow nulls. Obviously this won't work.
Gladly for you the "Identity Specification" seems to automatically fill the not nullable id values for you (see selected answer), when you later execute the insert query.
My Case
The problem (while using SSMS): I was having this error when trying to add a new non-nullable column to an already existing table with data. The error I'd got was:
Cannot insert the value NULL into column 'id_foreign', table 'MyDataBase.dbo.Tmp_ThisTable'; column does not allow nulls. INSERT fails.
The statement has been terminated.
The solution:
I created the column I needed id_foreign, allowing nulls.
I edited/inserted all the required values for id_foreign.
Once the values where in place, I went back and unchecked the "Allow Nulls" checkbox. Now the error was gone.