How do I add an integer that does not already exist? - sql

If I have a table A with column INCREMENT_NUMBER. We will say that there are five rows.
1
2
3
4
4
If a user adds a new row to table A, the INCREMENT_NUMBER column of that row should be 5. (It could be anything, as long as it isn't a number 1-4.) Keep in mind
INCREMENT_NUMBER integer auto_increment primary key
will not work because I need to allow for duplicates in the table and I don't think
insert

If you want to allow duplicates, don't declare it as a PRIMARY KEY (and neither put a UNIQUE constraint on it).
In MySQL an AUTO_INCREMENT is allowed to have duplicates in that case - you just have to add a simple index on it:
CREATE TABLE test
( increment_number INTEGER NOT NULL AUTO_INCREMENT
, INDEX inc_index (increment_number)
) ;
INSERT INTO test
VALUES (1),(2),(3),(4),(4);
Test in SQL-Fiddle: test-1
INSERT INTO test
VALUES
(NULL);
SELECT *
FROM test ;
Results in:
increment_number
----------------
1
2
3
4
4
5
In SQL-Server, you'll have to toggle the IDENTITY_INSERT setting ON and OFF to have similar behaviour:
CREATE TABLE test
( increment_number INT IDENTITY(1,1) NOT NULL
, name varchar(20) NOT NULL
) ;
SET IDENTITY_INSERT test ON ;
INSERT INTO test (increment_number, name)
VALUES
(1, 'Alex'),
(2, 'Bill'),
(3, 'Cathy'),
(4, 'Diana'),
(4, 'Dean');
And then test-2:
SET IDENTITY_INSERT test OFF ;
INSERT INTO test (name)
VALUES
('Elaine') ;
SELECT *
FROM test ;
Results in:
increment_number | name
---------------------------
1 Alex
2 Bill
3 Cathy
4 Diana
4 Dean
5 Elaine

Related

How to UPDATE or INSERT in PostgreSQL

I want to UPDATE or INSERT a column in PostgreSQL instead of doing INSERT or UPDATE using INSERT ... ON CONFLICT ... because there will be more updates than more inserts and also I have an auto incrementing id column that's defined using SERIAL so it increments the id column everytime it tries to INSERT or UPDATE and that's not what I want, I want the id column to increase only if it's an INSERT so that all ids would be in an order instead
The table is created like this
CREATE TABLE IF NOT EXISTS table_name (
id SERIAL PRIMARY KEY,
user_id varchar(30) NOT NULL,
item_name varchar(50) NOT NULL,
code_uses bigint NOT NULL,
UNIQUE(user_id, item_name)
)
And the query I used was
INSERT INTO table_name
VALUES (DEFAULT, 'some_random_id', 'some_random_name', 1)
ON CONFLICT (user_id, item_name)
DO UPDATE SET code_uses = table_name.code_uses + 1;
Thanks :)
Upserts in PostgreSQL do exactly what you described.
Consider this table and records
CREATE TABLE t (id SERIAL PRIMARY KEY, txt TEXT);
INSERT INTO t (txt) VALUES ('foo'),('bar');
SELECT * FROM t ORDER BY id;
id | txt
----+-----
1 | foo
2 | bar
(2 Zeilen)
Using upserts the id will only increment if a new record is inserted
INSERT INTO t VALUES (1,'foo updated'),(3,'new record')
ON CONFLICT (id) DO UPDATE SET txt = EXCLUDED.txt;
SELECT * FROM t ORDER BY id;
id | txt
----+-------------
1 | foo updated
2 | bar
3 | new record
(3 Zeilen)
EDIT (see coments): this is the expected behaviour of a serial column, since they're nothing but a fancy way to use sequences. Long story short: using upserts the gaps will be inevitable. If you're worried the value might become too big, use bigserial instead and let PostgreSQL do its job.
Related thread: serial in postgres is being increased even though I added on conflict do nothing

Generate unique IDs in non-unique columns

Consider this table:
ex_table
| gid | val |
| --- | --- |
| 1 | v1 |
| 1 | v2 |
| 2 | v3 |
Notice that gid is the id-like column and not unique.
I want to be able to insert values into the table either by generating a unique gid or by specifying which one to use.
For example:
INSERT INTO ex_table (val)
SELECT --....
Should generate a unique gid, while
INSERT INTO ex_table (gid, val)
SELECT --....
Should use the provided gid.
Any way to do this?
You can do what you want to the letter of what you say by using overriding system value and an auto-generated column. For instance:
create table t (
gid int generated always as identity,
name varchar(255)
);
Then
insert into t (name) values ('abc');
insert into t (gid, name) overriding system value values (1, 'def')
will insert two rows with a gid value of 1.
Here is an example.
Just one caveat: Inserting your own value does not change the next value that is automatically generated. So, if you manually insert values that do not exist, then you might find that duplicates are later generated for them.
You can try something like this
CREATE SEQUENCE table_name_id_seq;
CREATE TABLE table_name (
gid integer NOT NULL DEFAULT nextval('table_name_id_seq'),
name varchar);
ALTER SEQUENCE table_name_id_seq
OWNED BY table_name.id;
OR SIMPLY
CREATE TABLE table_name(
gid SERIAL,
name varchar);
AND THEN TO INSERT
INSERT INTO fruits(gid,name)
VALUES(DEFAULT,'Apple');

Add constraint unique column with null value

I need to create a constraint of integrity that ensures that in a column of a table there is only one null valor. The classic UNIQUE is not good because it does not detect multiple nulls ...
how can I do?
CREATE TABLE qwe(
id int
);
CREATE UNIQUE INDEX qwe_idx ON qwe(
CASE WHEN id IS null THEN 'NULL' ELSE to_char(id) END
);
INSERT INTO qwe VALUES(1);
1 row inserted.
INSERT INTO qwe VALUES(1);
Error starting at line : 9 in command -
INSERT INTO qwe VALUES(1)
Error report -
ORA-00001: naruszono więzy unikatowe (TEST.QWE_IDX)
INSERT INTO qwe VALUES(NULL);
1 row inserted.
INSERT INTO qwe VALUES(NULL);
Error starting at line : 9 in command -
INSERT INTO qwe VALUES(NULL)
Error report -
ORA-00001: naruszono więzy unikatowe (TEST.QWE_IDX)
SELECT * FROM qwe;
ID
----------
1
(null)

How to automatically set the value of a not primary key column with the value of the primary key in an insert query?

I am working on an INSERT query that insert a new row in a table named VulnerabilityAlertDocument
This table have 3 fields:
Id: that is an auto increment int and it is my PRIMARY KEY
VulnerabilityAlertId: this field is an int and must have the same value of **Id column
SourceId: is a varchar(50) and contains some text.
Now my problem is how to do that the VulnerabilityAlertId have the same value of the *auto increment Id value for this new record.
If I do something like:
INSERT INTO VulnerabilityAlertDocument
( [VulnerabilityAlertId], [SourceId] )
VALUES
(4, 'TEST');
it create a new record in the table in whic the Id column value is not specify because it is auto increment, and the VulnerabilityAlertId value is 4
I need that in this query, the VulnerabilityAlertId value is automatically setted with the value of the Id value of the new row
What can I do to do it?
As I understand your question is it like you want the VulnerabilityAlertId value automatically setted with the value of the Id column of the new row always?
If yes then you should alter the table definition and add VulnerabilityAlertId column as a persisted computed column as:
alter table VulnerabilityAlertDocument drop column VulnerabilityAlertId;
alter table VulnerabilityAlertDocument add VulnerabilityAlertId as id persisted;
by doing this there's no need to specify the values for VulnerabilityAlertId column as it will be computed every time a new row is inserted.
Hope this helps!!
Here's the way I'd skin this cat...
I would amend my table definition (apologies, can't think of a better field name right now):
CREATE TABLE your_table (
Id int identity(1,1) NOT NULL
, SourceId varchar(50) NULL
, ActualVulnerabilityAlertId int NULL
, VulnerabilityAlertId As Coalesce(ActualVulnerabilityAlertId, Id)
);
Essentially I have changed VulnerabilityAlertId to be a calculated field and added a new field to hold the "raw" data.
You can then populate the table like so:
INSERT INTO your_table (SourceId)
VALUES ('TEST 1');
INSERT INTO your_table (SourceId)
VALUES ('TEST 2');
INSERT INTO your_table (SourceId)
VALUES ('TEST 3');
INSERT INTO your_table (SourceId, ActualVulnerabilityAlertId)
VALUES ('TEST 4', 12345); -- Non-"default" value!
If you need to update a value then you need to refer to the ActualVulnerabilityAlertId field:
UPDATE your_table
SET ActualVulnerabilityAlertId = 937
WHERE SourceId = 'TEST 2';
Results:
SELECT Id
, SourceId
, ActualVulnerabilityAlertId
, VulnerabilityAlertId
FROM your_table
ORDER
BY Id;
Id SourceId VulnerabilityAlertId ActualVulnerabilityAlertId
-- -------- -------------------- --------------------------
1 TEST 1 1 NULL
2 TEST 2 937 937
3 TEST 3 3 NULL
4 TEST 4 12345 12345
There are 2 ways..
If you can split this into multiple statements, use ##Identity after inserting the record to update the recently inserted row.
or
2. make use of below built-in sql server function.
IDENT_CURRENT('table_name') + 1
If you want to populate VulnerabilityID with the newly created identity .
.then you have to ##Idenity to retrieve the latest identity generated and then send it to insert statement of VulnerabilityiD
For ex:
declare #vulid int
insert into tablename(params) --> Normal insert statement that generates identity
now, get that latest identity created by using
set #vulid=(select ##Identity) -> newly generated identity is stored in this varaibale now
Insert this into table now..
updatetablename set vulnerabilityid=#vulid;
This will ensure that latest generated id is inserted as Vulnerabilityid
Hope this helps..

PL/SQL developer how to get the row that made the insert fail?

I'm doing a method that inserts into the table which has a unique column. What I don't know is if I can access the insert value that made the insert fail.
For example:
table1(id,name, phone);
name is unique.
insert (1,a,123);
insert (2,a,1234);
What I want is when I do the second insert I to return the id value '1' without having to recur to a query.
Thank you in advance.
From oracle 10g r2 you can use log errors clause of insert command to log errors in a separate table. Here is an example:
SQL> create table test_table(
2 id number primary key,
3 col1 varchar2(7)
4 )
5 ;
Table created
-- creates a table for logging errors (table name will be prefaced with err$_)
SQL> begin dbms_errlog.create_error_log('TEST_TABLE'); end;
2 /
PL/SQL procedure successfully completed
-- violates primary key constraint
SQL> insert into test_table(id, col1)
2 ( select 1, level
3 from dual
4 connect by level <= 3)
5 log errors reject limit unlimited;
1 row inserted
SQL> commit;
SQL> select * from test_table;
ID COL1
---------- -------
1 1
SQL> select * from err$_test_table;
ORA_ERR_NUMBER$ ORA_ERR_MESG$ ORA_ERR_ROWID$ ORA_ERR_OPTYP$ ORA_ERR_TAG$ ID COL1
--------------- ------------------------------------------------------------------------------------------------------------
1 ORA-00001: unique constraint (HR.SYS_C008315) violated I 1 2
1 ORA-00001: unique constraint (HR.SYS_C008315) violated I 1 3
maybe you can write a trigger(before insert) on your table, on which insert about to happen. In this you can check if the column value(name) already exists in table.
In case it does you may insert this duplicate record in another table for further reference
Another approach is to write the insert in a procedure where the name may be checked and the duplicate name could be stored in a table.
Hope it helps