INSERT fails with ORA-01400: cannot insert NULL - sql

I am working with ORACLE SQL Developer and I created a table with an id as PK, another FK, id_columnx and a column1 and inserted data into them. Then I added another 2 columns, column 2 and column 3 and when I try to insert data into these new added columns, I get the error:
ORA-01400: cannot insert NULL.
I have to mention that I don't have any triggers on the table and i DO have values in the INSERT statement. There seems to be a conflict with the PK id, but I don't understand why.
So here is the code:
create table mytable(id INT PRIMARY KEY, name varchar2(30));
insert into mytable values (1, 'Mary');
insert into mytable values (2, 'John');
insert into mytable values (3, 'Bill');
alter table mytable
add email VARCHAR2(30);
alter table mytable
add addess VARCHAR2(30);
insert into mytable (email, addess)
values ('mary#gmail.com', 'Street X');
And here is the error I get:
Error starting at line : 12 in command -
insert into mytable (email, addess)
values ('mary#gmail.com', 'Street X')
Error report -
ORA-01400: cannot insert NULL into ("ZAMFIRESCUA_49"."MYTABLE"."ID")

INSERT is for inserting new rows, UPDATE is for altering data in the current rows. As mentioned in the comments, it looks like you want to be updating Mary's row with her email/address:
UPDATE mytable
SET email = 'mary#gmail.com',
address = 'Street X'
WHERE ID = 1 --Mary's ID for example, replace with the ID of the row you want to update
You could also use a subquery to find the right ID so you don't have to always look it up:
UPDATE mytable
SET email = 'mary#gmail.com',
address = 'Street X'
WHERE ID = (SELECT ID FROM mytable WHERE name = 'Mary')
Edit:
I was thinking there were two tables while writing this answer, you could always just use the name field as your filter:
UPDATE mytable
SET email = 'mary#gmail.com',
address = 'Street X'
WHERE name = 'Mary'

You're missing a PK value in your last INSERT after the ALTER statements. Try this:
create table mytable(id INT PRIMARY KEY, name varchar2(30));
insert into mytable values (1, 'Mary');
insert into mytable values (2, 'John');
insert into mytable values (3, 'Bill');
alter table mytable add email VARCHAR2(30);
alter table mytable add addess VARCHAR2(30);
insert into mytable (id, email, addess) values (4, 'mary#gmail.com', 'Street X');

Related

PostgreSQL bulk update

In my PostgreSQL database I have the following schema:
CREATE TABLE atc_codes (
id bigint NOT NULL,
name character varying,
atc_code character varying
);
INSERT INTO atc_codes (id, name, atc_code) VALUES (1, 'granisetron', 'A04AA02');
INSERT INTO atc_codes (id, name, atc_code) VALUES (2, '', 'A04AA02');
INSERT INTO atc_codes (id, name, atc_code) VALUES (3, '', 'A04AA02');
INSERT INTO atc_codes (id, name, atc_code) VALUES (4, 'metoclopramide', 'A03FA01');
INSERT INTO atc_codes (id, name, atc_code) VALUES (5, '', 'A03FA01');
INSERT INTO atc_codes (id, name, atc_code) VALUES (6, '', 'A03FA01');
SELECT * FROM atc_codes;
id
name
atc_code
1
granisetron
A04AA02
2
A04AA02
3
A04AA02
4
metoclopramide
A03FA01
5
A03FA01
6
A03FA01
View on DB Fiddle
Now I want to do the following things:
Update all records with act_code equal to A04AA02 to have granisetron value in the name column.
Update all records with act_code equal to A03FA01 to have metoclopramide value in the name column.
In the real database there will be much more scenarios like that so using something like CASE statement is impossible in that case.
Can I do that in one query instead of two?
I found the solution with using view:
WITH act_codes_name AS (
SELECT
name,
atc_code
FROM
atc_codes
WHERE
name IS NOT NULL
)
UPDATE
atc_codes
SET
name = act_codes_name.name
FROM act_codes_name
WHERE act_codes_name.atc_code = atc_codes.atc_code;
Yes you could use a CASE WHEN (standard SQL "switch case") in the SET clause:
UPDATE atc_codes
SET name = CASE
WHEN atc_code = 'A04AA02' THEN 'granisetron'
WHEN atc_code = 'A03FA01' THEN 'metoclopramide'
ELSE name
END
WHERE atc_code IN('A04AA02', 'A03FA01');
To avoid mistakes, I added a ELSE (equivalent to a default case) and a WHERE clause to prevent updating rows that don't match. Both do the same thing and I think you could just use one or the other.

Create a unique constraint with CHECK in PostgreSQL

Consider that there is the following table:
create table table_1(
id serial
PRIMARY KEY,
col1 varchar(50),
col2 varchar(50),
status varchar(1) -- A=active P=pending D=Deleted
);
now what I want is to create a unique constraint on (col1,col2) but it should not consider those with status ='D' i.e Consider there is 2 rows in the table:
INSERT INTO table_1(col1,col2,status) VALUES ('row1', 'row1', 'A');
INSERT INTO table_1(col1,col2,status) VALUES ('row2', 'row2', 'D');
Then I should NOT be able to add the following row:
INSERT INTO table_1(col1,col2,status) VALUES ('row1', 'row1', 'A');
But I SHOULD be able to add the following row:
INSERT INTO table_1(col1,col2,status) VALUES ('row2', 'row2', 'A');
You can do this with a partial unique index:
create unique index id_table1_col1_col2_status on table_1(col1, col2, status)
where status <> 'D';
Here is a SQL Fiddle that you can use to see it work.

postgresql - use just created identity value to return newly inserted row

Using SQL Server I can write the following statement...
create table Person(
id int identity(1,1),
name varchar(50)
)
insert into Person(name) values ('John')
select * from Person where id = scope_identity()
In Postgres I can do this:
CREATE TABLE public.Person
(
id serial primary key,
name character varying(10) NOT NULL
)
INSERT INTO Person(name) VALUES ('Smith', 'John') RETURNING id;
How would I write an equivalent statement like I did in the SQL example where don't return the id, but the entire row that was just inserted?
As #cur4so stated, or alternatively
INSERT INTO Person(name) VALUES ('Smith', 'John') RETURNING *;
INSERT INTO Person (name) VALUES ('Smith John');
select * from Person where id = currval('person_id_seq');

Insert into a Informix table or update if exists

I want to add a row to an Informix database table, but when a row exists with the same unique key I want to update the row.
I have found a solution for MySQL here which is as follows but I need it for Informix:
INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE name="A", age=19
You probably should use the MERGE statement.
Given a suitable table:
create table table (id serial not null primary key, name varchar(20) not null, age integer not null);
this SQL works:
MERGE INTO table AS dst
USING (SELECT 1 AS id, 'A' AS name, 19 AS age
FROM sysmaster:'informix'.sysdual
) AS src
ON dst.id = src.id
WHEN NOT MATCHED THEN INSERT (dst.id, dst.name, dst.age)
VALUES (src.id, src.name, src.age)
WHEN MATCHED THEN UPDATE SET dst.name = src.name, dst.age = src.age
Informix has interesting rules allowing the use of keywords as identifiers without needing double quotes (indeed, unless you have DELIMIDENT set in the environment, double quotes are simply an alternative to single quotes around strings).
You can try the same behavior using the MERGE statement:
Example, creation of the target table:
CREATE TABLE target
(
id SERIAL PRIMARY KEY CONSTRAINT pk_tst,
name CHAR(1),
age SMALLINT
);
Create a temporary source table and insert the record you want:
CREATE TEMP TABLE source
(
id INT,
name CHAR(1),
age SMALLINT
) WITH NO LOG;
INSERT INTO source (id, name, age) VALUES (1, 'A', 19);
The MERGE would be:
MERGE INTO target AS t
USING source AS s ON t.id = s.id
WHEN MATCHED THEN
UPDATE
SET t.name = s.name, t.age = s.age
WHEN NOT MATCHED THEN
INSERT (id, name, age)
VALUES (s.id, s.name, s.age);
You'll see that the record was inserted then you can:
UPDATE source
SET age = 20
WHERE id = 1;
And test the MERGE again.
Another way to do it is create a stored procedure, basically you will do the INSERT statement and check the SQL error code, if it's -100 you go for the UPDATE.
Something like:
CREATE PROCEDURE sp_insrt_target(v_id INT, v_name CHAR(1), v_age SMALLINT)
ON EXCEPTION IN (-100)
UPDATE target
SET name = v_name, age = v_age
WHERE id = v_id;
END EXCEPTION
INSERT INTO target VALUES (v_id, v_name, v_age);
END PROCEDURE;

SQL Server 2008 Before Insert Trigger

I have the following Query:
Insert into tblTest (ID, Name, Age) VALUES (1, 'TestName', 20);
In my trigger I want to check - if the query's ID is equal to 1, send another query:
Insert into tblTest (ID, Name, Age) VALUES (2, 'TestName', 21);
Else, dont do anything.
The problem is, I dont know how to keep the parameters as is and just change the age, so basically I want to send the SAME query, and change a certain parameter (in this case, its the age parameter).
The rows about to be inserted can be found in the special inserted table. Here's an example:
if object_id('tblTest') is not null
drop table tblTest
create table tblTest (id int, name varchar(50), age int)
go
create trigger trg_tblTest_BeforeInsert
on tblTest
after insert
as begin
insert tblTest
select id + 1
, name
, age + 1
from inserted
where id = 1 -- Only for rows with id=1
end
go
insert tblTest (id, name, age) values (1, 'TestName', 20)
select * from dbo.tblTest
This prints:
id name age
1 TestName 20
2 TestName 21