SQLite Insert with the newly generated id - sql

I have a table with an auto increment field and another field VARCHAR filed. I would like to fill the string field with the newly generated id directly in the insert query. For example with table:
Person
(
id auto_increment,
name varchar
)
I would like to perform a query like this:
INSERT INTO Person(name) VALUE ('Person #' + ROWID())
Anyway to do this?

This will use the last inserted row id with the increment of 1 to generate the next person id. Keep in mind that for last_insert_rowid() you should not be doing concurrent inserts to the database.
INSERT INTO Person (name) SELECT 'Person #' || (last_insert_rowid()+1);
Alternatively this will read the biggest ID you currently have and increment +1 to it and then concatenate it with the text. If it returns null it uses 1.
INSERT INTO Person (name) SELECT 'Person #' || (IFNULL((MAX(id)+1),1)) FROM Person LIMIT 1;
This one will get the index of autoincrement:
INSERT INTO Person (name) SELECT 'Person #' || (seq+1) FROM sqlite_sequence WHERE name="person"
You can also do something like this:
INSERT INTO Person (name) VALUES (NULL);
INSERT INTO Person (name) VALUES (NULL);
INSERT INTO Person (name) VALUES (NULL);
INSERT INTO Person (name) VALUES (NULL);
INSERT INTO Person (name) VALUES (NULL);
INSERT INTO Person (name) VALUES (NULL);
INSERT INTO Person (name) VALUES (NULL);
INSERT INTO Person (name) VALUES (NULL);
UPDATE Person SET name = 'Person #' || id WHERE name IS NULL;
Or:
INSERT INTO Person (name) VALUES ('Person');
UPDATE Person SET name = name || ' #' || id WHERE id = last_insert_rowid();
This one will update the names that does not have a # with its row id:
INSERT INTO Person (name) VALUES ('Person');
INSERT INTO Person (name) VALUES ('Person');
INSERT INTO Person (name) VALUES ('Person');
INSERT INTO Person (name) VALUES ('Person');
UPDATE Person SET name = name || ' #' || id WHERE (LENGTH(name)-LENGTH(REPLACE(name, '#', ''))) = 0;
Live DEMO

You shouldn't store the same info twice. Just generate the string you want dynamically when you query:
SELECT name || '#' || id FROM Person

You have to do two sentences: INSERT + UPDATE, you cannot access the last insert id in the current insert sentence

The system will not reliably know that ID until the row is inserted. I would think the best solution would be a view (since SQLite does not support computed columns which would be the easiest route). Just insert the VARCHAR and use a view to build the concatenated value at request time using the inserted VARCHAR and the allocated ID.
Good Luck!

This will not be guranteed but this might work ...
INSERT INTO tab1(val) VALUES ('tab1 #' + cast((SELECT top 1 IDENT_CURRENT('tab1') + IDENT_INCR('tab1') FROM tab1) as varchar(20)))

Related

Not able to insert a row in a table which has auto incremented primary key

I have a table reportFilters which has the following column names:
The reportFilterId is auto increment. I want to insert a row in the table with the script below:
IF OBJECT_ID(N'ReportFilters', N'U') IS NOT NULL
BEGIN
IF NOT EXISTS (SELECT * FROM [ReportFilters]
WHERE ReportId IN (SELECT ReportId FROM [Reports] WHERE ReportType = 'Operational Insights Command Staff Dashboard') )
BEGIN
INSERT INTO [ReportFilters] Values(1, 'SelectView', 'Select Views', 13, 'Views','Views', 'SelectView', 'a', 'b', 'c' );
END
END
GO
But I am getting the following error:
Column name or number of supplied values does not match table definition.
Can I please get help on this ? Thanks in advance.
I think the problem is on inserted columns can't match with inserted data because that will instead by your table column order which is ReportFilterId instead of ReportId
So that there are 11 columns in your table but your statement only provides 10 columns.
I would use explicitly specify for inserted columns (inserted columns start from ReportId except your PK ReportFilterId column)
INSERT INTO [ReportFilters] (ReportId,ReportFilterName,ReportFilterTitle....)
Values (1, 'SelectView', 'Select Views', 13, 'Views','Views', 'SelectView', 'a', 'b', 'c' );

how can I reference another column inside postgres insert query?

I have the following table:
CREATE TABLE tab (
id SERIAL PRIMARY KEY,
code TEXT NOT NULL,
data TEXT
)
In some cases, I'd like to insert a new row ensuring that the code column is generated by the id column. In other cases the code is provided by the user.
For example:
INSERT INTO tab(code, data) VALUES ('code: ' || id::TEXT, 'my data');
The expected result is something like:
id
code
data
1
code: 1
abc
2
code: 2
xyz
INSERT INTO tab(code, data) VALUES ('user.provided.code', 'my data');
The expected result is something like:
id
code
data
1
code: 1
abc
2
code: 2
xyz
3
user.provided.code
xyz
Is it possibile in one statement?
It sounds like you want to default the coder to something based on the id. Unfortunately, this doesn't work in Postgres:
create table tab (
id integer primary key generated always as identity,
code text not null default ('code '||id::text),
data text
);
One option is a single statement that does both an insert and update:
with i as (
insert into tab (code, data)
values ('', 'my data'
returning *
)
update tab
set code = 'code: ' || id::TEXT
where tab.id in (select i.id from i);
Another is to use a trigger that assigns the value.
Use INSERT INTO .. SELECT as follows:
INSERT INTO tab(code, data)
select 'code: ' || id::TEXT, 'my data' from tab;
Note: In newly added data(above insert), you are missing to add id column data or I think it is auto generated.

While updating table1, how do I INSERT to table2 for every change in table 1?

I have a MEMBER table and NOTIFICATION table. On client side, I list all of the records in MEMBER table and there is a points column and this is shown as text input. So after I change the values for some members, I can click save button and this will update the records in my MEMBER table that's all right,
But the thing I want to accomplish is for every record whose points value has changed I want to INSERT a record in my notifications table.
I couldn't think of anything, how can I approach to this problem?
For notifications I made 3 tables by following the article in here
Use the output clause instead of trigger, they are bad.
You need the condition "where data_old <> data_new" case if you updated a column with the same value, SQL Server marked it as changed, even if the value hasn't changed
create table #example (id int identity(1,1) not null, data nvarchar(max));
insert into #example (data) values ('value 1'),('value 2'), ('value 3');
create table #audit (id int, data_old nvarchar(max), data_new nvarchar(max), [When] datetime not null default (getdate()));
insert into #audit (id, data_old, data_new)
select id, data_old, data_new
from (
update #example
set data = 'value changed'
output inserted.id, deleted.data as data_old, inserted.data as data_new
where id = 2
)changed (id, data_old, data_new)
where data_old <> data_new
select * from #audit
will result with this in #audit :
You have described what a trigger does.
create trigger trig_member_insert on members after update
as
begin
insert into notifications ( . . . )
select . . ., i.points as new_points u.points as old_points -- what you want to insert
from inserted i join
updated u
on i.member_id = u.member_id
where u.points <> i.points
end;
Storing something called "points" as a string seems like a very poor choice. It sounds like a number.

cannot insert the NULL value into the column

I have been trying to insert data into the database, but it's continuously showing me this error, even though I not writing the name of the column(MemID) in the first fields, rather I am trying to enter it separately like this
create table Member (
MemID VARCHAR(20) PRIMARY KEY,
FullName VARCHAR(50),
email VARCHAR(50),
gender VARCHAR(50),
Contact_Number VARCHAR(50),
Registration_Number VARCHAR(50),
User_S# INT
);
insert into Member (FullName, email, gender, Contact_Number,
Registration_Number, User_S#) values ('Jemmy Joutapaitis',
'jjoutapaitiscf#dailymail.co.uk', 'Male', '86-(804)800-8008',
'3574884734839928', 449);
insert into Member (FullName, email, gender, Contact_Number,
Registration_Number, User_S#) values ('Cleo Glynn', 'cglynncg#i2i.jp',
'Male', '81-(694)548-5205', '5443114970343516', 450);
insert into Member (FullName, email, gender, Contact_Number,
Registration_Number, User_S#) values ('Ivonne Deetlefs',
'ideetlefsch#virginia.edu', 'Female', '86-(257)683-5628',
'3571675846170605', 451);
insert into Member(MemID)
values('Mem0');
insert into Member(MemID)
values('Mem1');
insert into Member(MemID)
values('Mem2');
This code is giving me the error
Cannot insert the value NULL into column 'MemID', table
'master.dbo.Member'; column does not allow nulls. INSERT fails.
But I am inserting MemID column separately.
And also the table which has created above is not showing in the database, is it because of the error or something else?
That's not how inserts work.
When an insert is triggered sql tries to add the row immediately, without waiting for the consequent statements (it's stands true for any dml statements not only insert).
So when your first insert is triggered then sql is trying to put null in MemID as you haven't supplied any MemID in your insert.
Try inserting it in the very first place itself in the insert. Instead of separate statement something like:
insert into Member (MemID, FullName, email, gender, Contact_Number,
Registration_Number, User_S#) values ('Mem0','Jemmy Joutapaitis',
'jjoutapaitiscf#dailymail.co.uk', 'Male', '86-(804)800-8008',
'3574884734839928', 449);
EDIT
With response to your comment , I think Prepared statements is what you're looking for.
Since you're using python you could do prepare your insert statement like:
sql = "insert into Member (MemID, FullName, email, gender, Contact_Number,
Registration_Number, User_S#) values (%s,'Jemmy Joutapaitis',
'jjoutapaitiscf#dailymail.co.uk', 'Male', '86-(804)800-8008',
'3574884734839928', 449);"
sql = sql.format(self.db_scan_table)
//whenever you've memid ready use.
self.cursor.execute(sql, ('Mem01'))
Define an AUTO_INCREMENT column to generate ID values for you:
CREATE TABLE Member (
MemID INT AUTO_INCREMENT PRIMARY KEY,
-- ...
);
If this isn't practical because you need some kind of particular string definition for these then your only option is to supply it as part of the initial INSERT call. You have a constraint here, the PRIMARY KEY value must not be NULL.
should be able to using the query below. identify the next number
insert into member(memid,......)
values ( 'MEM' + cast((select count(1) from member)+1 as varchar(100)),... )
if you want to start with 1 then + 1
otherwise remove + 1
insert into member(memid,......)
values ( 'MEM' + cast((select count(1) from member) as varchar(100)),... )

How to to get the value of an auto increment column in postgres from a .sql script file?

In postgres I have two tables like so
CREATE TABLE foo (
pkey SERIAL PRIMARY KEY,
name TEXT
);
CREATE TABLE bar (
pkey SERIAL PRIMARY KEY,
foo_fk INTEGER REFERENCES foo(pkey) NOT NULL,
other TEXT
);
What I want to do is to write a .sql script file that does the following
INSERT INTO foo(name) VALUES ('A') RETURNING pkey AS abc;
INSERT INTO bar(foo_fk,other) VALUES
(abc, 'other1'),
(abc, 'other2'),
(abc, 'other3');
which produces the error below in pgAdmin
Query result with 1 row discarded.
ERROR: column "abc" does not exist
LINE 3: (abc, 'other1'),
********** Error **********
ERROR: column "abc" does not exist
SQL state: 42703
Character: 122
Outside of a stored procedure how do a define a variable that I can use between statements? Is there some other syntax for being able to insert into bar with the pkey returned from the insert to foo.
You can combine the queries into one. Something like:
with foo_ins as (INSERT INTO foo(name)
VALUES ('A')
RETURNING pkey AS foo_id)
INSERT INTO bar(foo_fk,other)
SELECT foo_id, 'other1' FROM foo_ins
UNION ALL
SELECT foo_id, 'other2' FROM foo_ins
UNION ALL
SELECT foo_id, 'other3' FROM foo_ins;
Other option - use an anonymous PL/pgSQL block like:
DO $$
DECLARE foo_id INTEGER;
BEGIN
INSERT INTO foo(name)
VALUES ('A')
RETURNING pkey INTO foo_id;
INSERT INTO bar(foo_fk,other)
VALUES (foo_id, 'other1'),
(foo_id, 'other2'),
(foo_id, 'other3');
END$$;
You can use lastval() to ...
Return the value most recently returned by nextval in the current session.
This way you do not need to know the name of the seqence used.
INSERT INTO foo(name) VALUES ('A');
INSERT INTO bar(foo_fk,other) VALUES
(lastval(), 'other1')
, (lastval(), 'other2')
, (lastval(), 'other3')
;
This is safe because you control what you called last in your own session.
If you use a writable CTE as proposed by #Ihor, you can still use a short VALUES expression in the 2nd INSERT. Combine it with a CROSS JOIN (or append the CTE name after a comma (, ins) - same thing):
WITH ins AS (
INSERT INTO foo(name)
VALUES ('A')
RETURNING pkey
)
INSERT INTO bar(foo_fk, other)
SELECT ins.pkey, o.other
FROM (
VALUES
('other1'::text)
, ('other2')
, ('other3')
) o(other)
CROSS JOIN ins;
Another option is to use currval
INSERT INTO foo
(name)
VALUES
('A') ;
INSERT INTO bar
(foo_fk,other)
VALUES
(currval('foo_pkey_seq'), 'other1'),
(currval('foo_pkey_seq'), 'other2'),
(currval('foo_pkey_seq'), 'other3');
The automatically created sequence for serial columns is always named <table>_<column>_seq
Edit:
A more "robust" alternative is to use pg_get_serial_sequence as Igor pointed out.
INSERT INTO bar
(foo_fk,other)
VALUES
(currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other1'),
(currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other2'),
(currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other3');