Python 如果匹配的MySQL行不存在,如何插入该行

Python 如果匹配的MySQL行不存在,如何插入该行,python,mysql,insert,mysql-python,Python,Mysql,Insert,Mysql Python,我的表bank有三列:uid、nick和balance 我可以很好地插入新行,但是很容易出现重复的nick,因为uid自动递增,使每一行都是唯一的。但是我不希望这样,我只希望每个nick有一行 target = input.group(2) cursor.execute ("INSERT INTO bank (nick, balance) VALUES('" + db.escape_string(target.lower()) + "', 5)") db.commit(

我的表
bank
有三列:uid、nick和balance

我可以很好地插入新行,但是很容易出现重复的
nick
,因为
uid
自动递增,使每一行都是唯一的。但是我不希望这样,我只希望每个
nick
有一行

    target = input.group(2)

    cursor.execute ("INSERT INTO bank (nick, balance) VALUES('" + db.escape_string(target.lower()) + "', 5)")
    db.commit()

    bot.say('An account for ' + target + ' has been created.')

到目前为止,这是我的代码,但是我不确定如何创建一个
选择
查询,然后在插入新行之前检查表中是否已经存在
尼克

使用该递增ID听起来没有意义。
而是考虑帐户的唯一标识符,例如帐号。 另一个答案表明,在
nick
上添加一个独特的约束的危险在于,随着人口的增长,可能会有两个或两个以上的人希望使用相同的
nick

    target = input.group(2)

    cursor.execute ("INSERT INTO bank (nick, balance) VALUES('" + db.escape_string(target.lower()) + "', 5)")
    db.commit()

    bot.say('An account for ' + target + ' has been created.')
此外,您应该将要插入的值作为第二个参数传递给
execute()
,至少有两个原因*

cursor.execute("""INSERT INTO bank (nick, balance) 
                  VALUES (%s, %s);""", (target.lower(), 5))
*原因有两个:

  • 您不必手动处理任何报价问题。Mysql-Python将为您解决这个问题
  • 您可以避免SQL注入攻击的可能性

  • 请注意:对于所有类型的参数,而不仅仅是字符串,参数占位符是
    %s
    。因此,您不需要像插入整数那样执行任何操作。

    我想您使用的是psycopg2

    cursor.execute(“从nick=%s的银行选择*,[nick])

    nick=cursor.fetchall()


    如果尼克…

    我会采取不同的方法。我会在
    nick
    列的DB级别添加一个唯一的约束:

    ALTER TABLE bank ADD UNIQUE (nick);
    
    在Python代码中,然后放置一个
    try
    except
    ,以适当地处理违反唯一约束的异常。

    我正在使用Python(3.6)和MySql,我想在添加记录之前检查记录。 这是我的密码:

    import mysql.connector
    
    mydb = mysql.connector.connect(
      host="localhost",
      user="user",
      passwd="password",
      database='football'
    )
    
    mycursor = mydb.cursor()
    
    def write_to_db(db_table, col_list, data_list, *supply_id):
        """
        Takes a record, checks if it already exists and if not inserts it, returning its index or None
        :param db_table: name of table to be checked / inserted into
        :param col_list: column/field names in a list eg.  ['meat', 'sides']
        :param data_list: data to be found or inserted eg ['spam', 'eggs']
        :param supply_id: Only if you supply calculated id as tuple ('table_id', table_id_val)
        :return: If lists don't match =None Else =Index of found record or Index of inserted one
        """
        if len(col_list) != len(data_list) or len(col_list) == 0: # List lengths must match
            return None     # Otherwise returned index is None
        # Build search SQL - Select - table - Where - match conditions
        find_existing_sql = 'SELECT * FROM {} '.format(db_table)    # Which table
        find_existing_sql += 'WHERE {} = {} '.format(col_list[0], data_list[0])
        sql_end = ' LIMIT 1 ;'
        if len(col_list) > 1:  # Provided record has more than 1 column
            and_sql = ' AND {} = {} '           # add extra match condition for each column
            for indx in list(range(1, len(col_list))):
                find_existing_sql += and_sql.format(col_list[indx], data_list[indx])
            find_existing_sql += sql_end        # Complete SQL to find given record
        my_cursor.execute(find_existing_sql)    # Query database with SQL
        seek_response = my_cursor.fetchall()    # Read the seek a record response
        record_exists = len(seek_response) > 0  # Length = 0 not found, > 0 found
        if record_exists:
            return seek_response[0][0]          # Return id = the first item from the first list of items
        else:
            # Build insert SQL - Insert into  - table - column names - values 
            insert_sql = 'INSERT INTO {} ('.format(db_table)    # Which table
            if supply_id is not None:       # If you supplied an index
                id_col = supply_id[0][0]    # first item in first arg = index name
                id_val = supply_id[0][1]    # second item in first arg = index value
                col_list =[id_col] + col_list       # Add index column name on the front of column list
                data_list = [id_val] + data_list    # Add index value on front of data_list
            first_col = '{}'.format(col_list[0])    # Start listing columns
            more_cols_vals = ', {}'                 # To add more coumns/values if needed
            values_sql = ') VALUES ( {} '.format(data_list[0]) # Start listing values
            end_sql = ' );'  
            insert_cols_sql = insert_sql + first_col    
            if len(col_list) > 1:       
                for indx in list(range(1, len(col_list))):
                    insert_cols_sql += more_cols_vals.format(col_list[indx])
                    values_sql += more_cols_vals.format(data_list[indx])
            # Put Insert SQL together
            insert_new_sql = insert_cols_sql + values_sql + end_sql
            my_cursor.execute(insert_new_sql) # Insert the new record into db
            mydb.commit()
            if supply_id is not None:   # If you supplied an index
                return id_val           # Return that
            else:                           # if not
                return my_cursor.lastrowid  # Return auto-generated index
    
    如果您提供自己生成的索引,此函数将获取表名、列名列表、要插入的值列表和可选元组

        ('table_id', table_id_value)
    
    但是如果不提供这个元组,MySQL将使用自动生成的索引进行插入。 该例程假定表的第一列是索引

    如果找到的记录已经存在,则返回该记录的索引;如果该记录不存在,则返回插入该记录时使用的索引。索引可以是MySQL生成的索引,也可以是您提供的索引。 如果列名列表和值列表长度不匹配,则返回None

    我已经使用Python构建了SQL语句,因此您可以拥有可变数量的列。 您可以在SQL中传递值(虽然我不知道如何对数量可变的列和值传递值),但我一直遇到“参数数量错误”的错误,并使用Python的string.format()解决了这一问题

    即使只提供一个元组,*supply_id(通常是*args)参数也是一个列表,因此我需要两个索引来访问第一个参数,然后是0或1来访问元组中的列名和值


    .fetchall()本身对于防止“未读记录”错误是必需的,因为如果找到记录,它会从游标中清除数据

    uid
    基本上是我唯一标识帐户的方式,这就是为什么我设置它为每个新帐户添加一个。谢谢你的提示,我会的。但我仍然无法解决原来的问题。那么,这些账户是如何重复的呢?两个账户不能有相同的
    缺口
    余额
    ?这似乎是一种任意的限制……新帐户仍然可以使用相同的
    nick
    一次又一次地添加,而
    uid
    只会不断增加。您的问题现在似乎与问题中所写的略有不同……根据应用程序逻辑,您可能还希望在INSERT中添加一个on REPLICATE KEY子句,而不是处理异常。@liquorvicar Yes,具体取决于应用程序逻辑。就个人而言,越是“行为”逻辑,它就越适合Python(而不是SQL)。在这种情况下,
    UNIQUE
    约束是
    DDL
    ,本身不是“行为”。然而,这只是我个人的喜好。我对这个
    独特的
    有点困惑,查询如何知道
    nick
    值是什么?“我试着搜索,但这一切对我来说似乎有点太混乱了。@Markum解释
    UNIQUE
    约束。基本上,如果您的代码尝试插入一个已经存在的
    nick
    值,那么约束将被违反,并且Python代码中会出现异常,您可以像往常一样通过
    try
    except
    来实现。