Add variable columns to INSERT statement
You’re not using values except for its length. But this should be the same length than cols, so use that instead.

You also don't need a for-loop to build a list with the same element N times, list multiplication can handle that just fine.

Lastly, I would use f-strings or at least str.format instead of string concatenation, it is prettyier.

def insert_statement(db, columns):
    column_names = ', '.join(columns)
    placeholders = ', '.join(['%s'] * len(columns))
    return f'INSERT INTO {db} ({column_names}) VALUES ({placeholders})'


Usage:

&gt;&gt;&gt; insert_statement('Publicationes', ['item_id', 'title', 'price'])
'INSERT INTO Publicationes (item_id,title,price) VALUES (%s,%s,%s)'


Depending on your calling site, you can also make columns a variable length argument, it may be easier to use:

def insert_statement(db, *columns):
    column_names = ', '.join(columns)
    placeholders = ', '.join(['%s'] * len(columns))
    return f'INSERT INTO {db} ({column_names}) VALUES ({placeholders})'


Usage:

&gt;&gt;&gt; insert_statement('Publicationes', 'item_id', 'title', 'price')
'INSERT INTO Publicationes (item_id,title,price) VALUES (%s,%s,%s)'




But you should limit yourself to only use this function using trusted input. If anything comming from a user enters here, this is a vulnerability waiting to happen:

&gt;&gt;&gt; user_input = "price) VALUES (42, 'foobar', 0.00); DROP TABLE Publicationes; -- Now this a vulnerability in disguise :"
&gt;&gt;&gt; insert_statement('Publicationes', 'item_id', 'title', user_input)
"INSERT INTO Publicationes (item_id, title, price) VALUES (42, 'foobar', 0.00); DROP TABLE Publicationes; -- Now this a vulnerability in disguise :) VALUES (%s, %s, %s)"