SQL INSERT but increment ID if exist without having to do separate SELECT query
Question:
I have a table with Primary Key on two columns: ID
(Users ID) and SQ
(Sequence, this starts at 1 and increments +1 for each ID
). A user should not have multiple instances of the same sequence #. Here is how the table looks:
ID SQ Code
------ -- ----
123456 1 123
654321 1 369
123456 2 234
I am trying to insert a value in column Code
but before I do that I need to check if a specific user already has that code and if so, receive the Sequence #.
Currently, I run:
# CodeExists is 1 if user has code already. 0 otherwise
# Max_SQ gives the maximum SQ that exists for this user
cursor.execute("SELECT MAX(CASE WHEN Code = ? THEN 1 ELSE 0 END) AS 'CodeExists', MAX(SQ) AS 'Max_SQ' FROM TABLENAME WHERE ID = ? GROUP BY ID", Code, User_PID)
data = cursor.fetchone()
if data is None: # This user does not have any codes, SQ starts at 1
SQ = 1
else:
CodeExists, SQ = data # Unpack query values
if int(CodeExists) == 1: # User already has the code we are trying to insert, skip
continue
else:
SQ = int(SQ) + 1 # Increment SQ
cursor.execute("INSERT INTO TABLENAME (ID,SQ,Code) VALUES(?,?,?)", User_PID, SQ, Code)
cursor.commit()
Examples:
- Trying to insert Code=123 for User=123456, should not insert. This user has code 123 already.
- Trying to insert Code=123 for User=654321, should insert with SQ=2
- Trying to insert Code=123 for User=999999, should insert with SQ=1
Given a Code # and User ID, is there a way to combine this into a single INSERT query?
Answers:
in MysQL you can do it like this
CREATE TABLE TABLENAME
(`ID` int, `SQ` int, `Code` int)
;
INSERT INTO TABLENAME
(`ID`, `SQ`, `Code`)
VALUES
(123456, 1, 123),
(654321, 1, 369),
(123456, 2, 234)
;
INSERT INTO TABLENAME (ID,SQ,Code)
SELECT 1223344,( SELECT COALESCE(MAX(SQ),0) +1 FROM TABLENAME WHERE ID = 1223344) ,666
WHERE NOT EXISTS ( SELECT 1 FROM TABLENAME WHERE ID = 1223344 AND Code = 666)
Records: 1 Duplicates: 0 Warnings: 0
INSERT INTO TABLENAME (ID,SQ,Code)
SELECT 123456,( SELECT COALESCE(MAX(SQ),0) +1 FROM TABLENAME WHERE ID = 123456) ,666
WHERE NOT EXISTS( SELECT 1 FROM TABLENAME WHERE ID = 123456 AND Code = 666)
Records: 1 Duplicates: 0 Warnings: 0
INSERT INTO TABLENAME (ID,SQ,Code)
SELECT 1223344,( SELECT COALESCE(MAX(SQ),0) +1 FROM TABLENAME WHERE ID = 1223344) ,666
WHERE NOT EXISTS( SELECT 1 FROM TABLENAME WHERE ID = 1223344 AND Code = 666)
Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM TABLENAME
ID
SQ
Code
123456
1
123
654321
1
369
123456
2
234
1223344
1
666
123456
3
666
Use a CTE to store the the ID
and Code
of the new row.
Then do a LEFT
join of the CTE to the table and aggregate to get the max SQ
for that ID
and increase it by 1.
In the HAVING
clause set the condition that if there is already a row in the table where the Code is the same as the one in the CTE then the query should not return any row to be inserted.
This is the query:
WITH cte AS (SELECT * FROM (VALUES (123456, 123))t (ID, Code))
INSERT INTO tablename (ID, SQ, Code)
SELECT c.ID,
COALESCE(MAX(t.SQ), 0) + 1,
c.Code
FROM cte c LEFT JOIN tablename t
ON t.ID = c.ID
GROUP BY c.ID, c.Code
HAVING MAX(CASE WHEN c.Code = t.Code THEN 1 END) IS NULL;
See the demo.
I have a table with Primary Key on two columns: ID
(Users ID) and SQ
(Sequence, this starts at 1 and increments +1 for each ID
). A user should not have multiple instances of the same sequence #. Here is how the table looks:
ID SQ Code
------ -- ----
123456 1 123
654321 1 369
123456 2 234
I am trying to insert a value in column Code
but before I do that I need to check if a specific user already has that code and if so, receive the Sequence #.
Currently, I run:
# CodeExists is 1 if user has code already. 0 otherwise
# Max_SQ gives the maximum SQ that exists for this user
cursor.execute("SELECT MAX(CASE WHEN Code = ? THEN 1 ELSE 0 END) AS 'CodeExists', MAX(SQ) AS 'Max_SQ' FROM TABLENAME WHERE ID = ? GROUP BY ID", Code, User_PID)
data = cursor.fetchone()
if data is None: # This user does not have any codes, SQ starts at 1
SQ = 1
else:
CodeExists, SQ = data # Unpack query values
if int(CodeExists) == 1: # User already has the code we are trying to insert, skip
continue
else:
SQ = int(SQ) + 1 # Increment SQ
cursor.execute("INSERT INTO TABLENAME (ID,SQ,Code) VALUES(?,?,?)", User_PID, SQ, Code)
cursor.commit()
Examples:
- Trying to insert Code=123 for User=123456, should not insert. This user has code 123 already.
- Trying to insert Code=123 for User=654321, should insert with SQ=2
- Trying to insert Code=123 for User=999999, should insert with SQ=1
Given a Code # and User ID, is there a way to combine this into a single INSERT query?
in MysQL you can do it like this
CREATE TABLE TABLENAME
(`ID` int, `SQ` int, `Code` int)
;
INSERT INTO TABLENAME
(`ID`, `SQ`, `Code`)
VALUES
(123456, 1, 123),
(654321, 1, 369),
(123456, 2, 234)
;
INSERT INTO TABLENAME (ID,SQ,Code)
SELECT 1223344,( SELECT COALESCE(MAX(SQ),0) +1 FROM TABLENAME WHERE ID = 1223344) ,666
WHERE NOT EXISTS ( SELECT 1 FROM TABLENAME WHERE ID = 1223344 AND Code = 666)
Records: 1 Duplicates: 0 Warnings: 0
INSERT INTO TABLENAME (ID,SQ,Code)
SELECT 123456,( SELECT COALESCE(MAX(SQ),0) +1 FROM TABLENAME WHERE ID = 123456) ,666
WHERE NOT EXISTS( SELECT 1 FROM TABLENAME WHERE ID = 123456 AND Code = 666)
Records: 1 Duplicates: 0 Warnings: 0
INSERT INTO TABLENAME (ID,SQ,Code)
SELECT 1223344,( SELECT COALESCE(MAX(SQ),0) +1 FROM TABLENAME WHERE ID = 1223344) ,666
WHERE NOT EXISTS( SELECT 1 FROM TABLENAME WHERE ID = 1223344 AND Code = 666)
Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM TABLENAME
ID | SQ | Code |
---|---|---|
123456 | 1 | 123 |
654321 | 1 | 369 |
123456 | 2 | 234 |
1223344 | 1 | 666 |
123456 | 3 | 666 |
Use a CTE to store the the ID
and Code
of the new row.
Then do a LEFT
join of the CTE to the table and aggregate to get the max SQ
for that ID
and increase it by 1.
In the HAVING
clause set the condition that if there is already a row in the table where the Code is the same as the one in the CTE then the query should not return any row to be inserted.
This is the query:
WITH cte AS (SELECT * FROM (VALUES (123456, 123))t (ID, Code))
INSERT INTO tablename (ID, SQ, Code)
SELECT c.ID,
COALESCE(MAX(t.SQ), 0) + 1,
c.Code
FROM cte c LEFT JOIN tablename t
ON t.ID = c.ID
GROUP BY c.ID, c.Code
HAVING MAX(CASE WHEN c.Code = t.Code THEN 1 END) IS NULL;
See the demo.