ODP.Net, Entity Framework: ORA-00947 (not enough values) when trying to add a record with Store Generated Identity - vb.net

I have simple table where I want to insert new records.
The table has an ID column which is set as identity and generated always.
StoreGeneratedPattern=Identity is set for the ID column.
When I try to add a new record to the table in VB.Net
rec = New TEST_TABLE
ctx.TEST_TABLE.Add(rec)
ctx.SaveChanges()
It results in get ORA-00947: not enough values.
It seems as if the Entity Framework is creating an invalid SQL request. Something like INSERT INTO TEST_TABLE (ID, NAME) VALUES('Tom');.
How can I solve this situation?
How can I check, which SQL request is sent to Oracle?
Adding lines with direct sql queries works perfectly:
INSERT INTO TEST_TABLE (NAME) VALUES('Tom');
1 line affected.
The table's schemata is as follows:
CREATE TABLE "TEST_TABLE"
("NAME" VARCHAR2(20) NOT NULL ENABLE,
"ID" NUMBER GENERATED ALWAYS AS IDENTITY
MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOORDER NOCYCLE NOT NULL ENABLE,
CONSTRAINT "TEST_TABLE_PK" PRIMARY KEY ("ID") ENABLE
);
CREATE UNIQUE INDEX "TEST_TABLE_PK" ON "TEST_TABLE" ("ID");
Edit: I solved the problem: StoreGeneratedValue=Identity was set for NAME, not for ID. After correcting this, everything just works fine.

"Not enough values" comes when there are too few values passed on insert statement. Like this
insert into table_name(col1, col2, col3) values(1, 2)
I've passed 2 values whereas there are 3 columns listed in the beginning of insert. Thus, I almost sure, underlying insert statement lacks of a value.
You need to check content of inserting routine on VB side if posiible.
As a workaround I'd try to replace "GENERATED ALWAYS" with "GENERATED BY DEFAULT" and run the VB code with StoreGeneratedPattern=None

Related

How to insert without giving column names but not giving identity column

Table definition:
CREATE TABLE IF NOT EXISTS public.test
(
"Id" integer NOT NULL GENERATED ALWAYS AS IDENTITY (INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1),
"SomeColumn" character(100) COLLATE pg_catalog."default",
CONSTRAINT test_pkey PRIMARY KEY ("Id")
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.test
OWNER to postgres;
I am trying this query:
INSERT INTO public.test VALUES ('testData');
But PostgreSQL throws this error:
ERROR: invalid input syntax for type integer: "testData"
LINE 1: INSERT INTO public.test VALUES ('testData');
I know this is valid in SQL Server. Is there a way the achieve this behaviour in PostgreSQL?
I do not want to specify the column names. Columns are defined in the order, but the identity column does not exist in the query.
I want to not give the column names
That's a bad idea. You should always specify the target columns for an INSERT statement. Especially if you want to skip some, but not others.
However, if you insist on bad coding style, you can use the DEFAULT keyword
INSERT INTO public.test VALUES (DEFAULT, 'testData');

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

Auto increment issues postgresql

Facing some issues with the auto-increment property in postgresql
I created a table say emp
create table emp
( empid serial,
empname varcha(50),
primary key (empid)
);
I inserted one value with empid as blank:
insert into emp (empname) values ('test1');
Next insert by specifying the empid value:
insert into emp (empid,empname) values (2,'test2');
Now, the next time if I insert a value without specifying the empid value, it will give an error because it will try to insert the empid as 2:
insert into emp (empname) values ('test3');
ERROR: duplicate key value violates unique constraint "emp_pkey"
DETAIL: Key (empid)=(2) already exists.
Can someone help me with a workaround for this issue so that with or without specifying a value, the autoincrement should pick up the max(value) +1 ??
Thanks
You can't cleanly mix use of sequences and fixed IDs. Inserting values without using the sequence won't update the sequence, so you'll get collisions.
If you're doing your manual insertions in a bulk load phase or something you can:
BEGIN
LOCK TABLE the_table IN ACCESS EXCLUSIVE MODE
Do your INSERTs
SELECT setval('seq_name', 14), replacing 14 with the new sequence value. This can be a subquery against the table.
COMMIT
... but in general, it's better to just avoid mixing sequence ID generation and manually assigned IDs.

Get the value of an auto-increment variable in HSQLDB

I have a table that auto-increments its primary key. How can I return what this value currently is using SQL in HSQLDB?
I found this answer, but it doesn't give a full explanation of how to get it from a specific table.
If the primary key column is declared as IDENTITY, then I don't see a way to get the current value, except for calling the IDENTITY() as described in the other answer, which doesn't give the answer for the specific table.
An alternative is to create the primary key column to use a specific sequence generator instead of IDENTITY. You can then select the current value of the sequence from the INFORMATION_SCHEMA.SEQUENCE table.
The sample below shows how this would work.
create sequence test_seq;
create table test (
id integer generated by default as sequence test_seq,
value varchar(10));
insert into test (value) values ('foo');
insert into test (value) values ('bar');
insert into test (value) values ('bash');
select * from test;
id value
0 'foo'
1 'bar'
2 'bash'
select next_value from information_schema.sequences where sequence_name = 'TEST_SEQ'
3

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.