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?

Asked By: Bijan

||

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

fiddle

Answered By: nbk

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.

Answered By: forpas
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.