mysql插入和更新问题记录

UPDATE base_dictionary_class
SET id = 3, class_group = 4, class_name = 6
WHERE id = 3 AND class_group = 4;

IF ROW_COUNT()=0 THEN
INSERT INTO
base_dictionary_class (id, class_group, class_name)
VALUES (3, 4, 6);
END IF;

1、问题分析

  1. IF 语句的用法

    • SQL 的 IF 语句一般是在存储过程或触发器中使用,而不能在常规的 SQL 语句中直接使用。 如果你在数据库客户端或管理工具中直接执行这段代码,会导致错误。
  2. 更新和插入的逻辑

    • UPDATE 语句的逻辑上似乎是想要更新某一条记录,但在更新条件上使用了 id = 3class_group = 4,这意味着只有在记录已经存在且符合条件时,才会进行更新。若没有符合条件的记录,才会插入新记录。

2、修正建议

如果你的目标是实现上述逻辑,可以将其放入一个存储过程,或者通过应用程序代码来处理。以下是一个如何在存储过程中实现这一逻辑的示例:

使用存储过程
DELIMITER //

CREATE PROCEDURE UpdateOrInsert()
BEGIN
    -- 更新记录
    UPDATE base_dictionary_class
    SET class_group = 4, class_name = 6
    WHERE id = 3 AND class_group = 4;

    -- 检查更新是否影响行数
    IF ROW_COUNT() = 0 THEN
        -- 插入新记录
        INSERT INTO base_dictionary_class (id, class_group, class_name)
        VALUES (3, 4, 6);
    END IF;
END //

DELIMITER ;

解释

  1. DELIMITER //: 改变语句结束符,以便可以在存储过程体中使用 ;
  2. CREATE PROCEDURE: 创建一个名为 UpdateOrInsert 的存储过程。
  3. UPDATE: 尝试更新记录。
  4. IF ROW_COUNT() = 0: 如果没有记录被更新,则插入新记录。

调用存储过程

在创建存储过程后,你可以通过以下命令调用它:

CALL UpdateOrInsert();

直接在应用程序中处理逻辑

如果不想使用存储过程,你可以在应用程序的代码逻辑中实现类似的功能。首先执行 UPDATE,然后检查影响的行数,再决定是否执行 INSERT

总结

在 SQL 中,IF 语句需要在存储过程或触发器中使用,不能直接用于普通的 SQL 脚本中。你可以将整个逻辑放入存储过程,或者在你的应用程序中处理这种逻辑。

在 SQL 中,IF 语句不能在常规的 SQL 语句中直接使用,它只能在存储过程、函数或触发器中使用。因此,如果你在 SQL 客户端中直接运行你提供的代码,会导致语法错误。

要使这个逻辑可以直接运行,你需要用单独的 SQL 语句处理更新和插入操作。可以通过应用程序逻辑或者在 SQL 脚本中使用条件查询来实现类似的效果。以下是如何修改你的 SQL 代码,使其能够直接运行的几种方法:

3、方法 1: 使用条件逻辑和多条语句

你可以分别执行更新和插入的操作,但在更新之后使用一个简单的 SELECT 来判断是否有行被更新。

-- 更新记录
UPDATE base_dictionary_class
SET id = 4, class_group = 4, class_name = 6
WHERE id = 5 AND class_group = 4;

-- 检查更新是否影响行数
SELECT ROW_COUNT() AS affected_rows;

-- 插入新记录(如果需要)
INSERT INTO base_dictionary_class (id, class_group, class_name)
SELECT 5, 4, 6
WHERE ROW_COUNT() = 0;

上面语句在你的 SQL 代码中,你希望检查更新是否影响了行数,并在没有影响任何行的情况下插入新记录。但是,ROW_COUNT() 只能在当前会话中使用,而在插入新记录的 INSERT 语句中,它可能不返回你预期的结果。因为每次执行 SQL 语句后,ROW_COUNT() 的结果都会更新。这里我们可以使用其他方法来实现你想要的功能。

以下是一个更新逻辑的改写示例,确保可以正确处理更新和插入:

-- 更新记录
UPDATE base_dictionary_class
SET class_name = 6
WHERE id = 2 AND class_group = 1;

-- 检查更新是否影响行数
SET @affected_rows = ROW_COUNT();

-- 插入新记录(如果没有更新)
INSERT INTO base_dictionary_class (id, class_group, class_name)
SELECT 2, 1, 6
WHERE @affected_rows = 0;

关键改动说明:

  1. 设置变量:在检查受影响行数时,将 ROW_COUNT() 的结果存储在一个用户定义的变量中,例如 @affected_rows。这样,在插入语句中可以使用这个变量进行判断,而不会受到 ROW_COUNT() 的影响。

  2. 更新语句:在更新语句中,只更新 class_name。因为你已经在 WHERE 子句中指定了 idclass_group,这条更新语句会准确更新对应的记录。

  3. 插入语句:在插入新记录的 INSERT 语句中,使用 @affected_rows = 0 作为条件。这确保只有在更新未影响行时才会插入新记录。

注意事项:

  • 确保 base_dictionary_class 表中允许有重复的 id 值(如 id = 2),否则插入操作可能会因为唯一性约束而失败。如果 id 字段是主键,应该考虑使用不同的 id 值进行插入。
  • 如果在执行此 SQL 代码的环境中不支持用户变量(如某些 ORM 框架),你可以通过编程逻辑来分步执行更新和插入操作。

另外的解决方案:

如果你可以使用存储过程或事务,可以将这些逻辑封装起来,这样可以更清晰地管理状态和操作。是错的,修改为

4、方法 2: 使用 INSERT ... ON DUPLICATE KEY UPDATE

如果你的表有唯一索引(例如,id 列),你可以使用 INSERT ... ON DUPLICATE KEY UPDATE 来合并这两个操作。

INSERT INTO base_dictionary_class (id, class_group, class_name)
VALUES (5, 4, 6)
ON DUPLICATE KEY UPDATE
    class_group = 4, class_name = 6;

这种方法的优点是无论是插入还是更新,它都可以在一个语句中完成。注意,在使用此方法之前,确保 id 列是唯一的主键或有唯一索引。

5、方法 3: 使用存储过程(如前所述)

如果你希望保留 IF 语句,可以将其放入存储过程中。

DELIMITER //

CREATE PROCEDURE UpdateOrInsert()
BEGIN
    -- 更新记录
    UPDATE base_dictionary_class
    SET id = 4, class_group = 4, class_name = 6
    WHERE id = 5 AND class_group = 4;

    -- 检查更新是否影响行数
    IF ROW_COUNT() = 0 THEN
        -- 插入新记录
        INSERT INTO base_dictionary_class (id, class_group, class_name)
        VALUES (5, 4, 6);
    END IF;
END //

DELIMITER ;

-- 调用存储过程
CALL UpdateOrInsert();

选择方法

  • 如果你只是想快速执行更新和插入,方法 1方法 2 是最简洁的。
  • 如果你的数据库逻辑更复杂,或者你希望重用这段代码,那么使用 方法 3(存储过程)可能是更好的选择。

请根据你的需求和数据库结构选择适合的方法。

6、方法 4: python连接mysql完成插入和更新版本1

from sqlalchemy import create_engine,text
from sqlalchemy.orm import sessionmaker

# 建立数据库连接,用于入ip服务器database数据库下表格中
def engine_conn():
    # 建立数据库连接,用于入ip服务器database数据库
    url = urllib.parse.quote_plus('xxx@xx')
    engine = create_engine(f"mysql+pymysql://{user}:{url}@{ip}:{port}/{database}?charset=utf8")
    return engine

def get_column_names(table_name):
    engine = engine_conn()
    query = f"SELECT * FROM {table_name} LIMIT 0"
    df = pd.read_sql_query(query, engine)
    column_names = df.columns.tolist()
    # 注:这里还可能通过information_shema系统数据库获取
    '''
    python执行cursor.fetchall()将返回元组列表[(,),(,),...]
    SELECT COLUMN_NAME
	FROM information_schema.COLUMNS
	WHERE TABLE_SCHEMA = 'your_database_name'
	  AND TABLE_NAME = 'your_table_name';
	'''
    return column_names

def update_and_insert_hrs(table,df_data,engine):
    Session = sessionmaker(bind=engine)
    session = Session()
    total_rows = len(df_data)
    for index, row in tqdm(df_data.iterrows(), total=total_rows, unit='row', desc='Processing'):
        sql_insert = f'''
                    INSERT INTO {table} ({", ".join(df_data.columns)})
                    SELECT {":" + ", :".join(df_data.columns)}
                    WHERE NOT EXISTS 
                    (SELECT column1, column2, column3  FROM {table} 
                    WHERE column1 = :column1 AND column2 = :column2 AND column3 = :column3
                    )
                '''

        dic_params = {col: getattr(row, col) for col in df_data.columns}
        session.execute(text(sql_insert), dic_params)

        sql_update = f'''
                    UPDATE {table}
                    SET  {", ".join([f"{column} = :{column}"
                                     for column in df_data.columns if column != 'column1' and column != 'column2' and column != 'column3'])}
                    WHERE column1 = :column1 AND column2 = :column2 AND column3 = :column3
                    '''
        session.execute(text(sql_update), dic_params)

    session.commit()  # 将所有数据的插入和更新操作一起提交
    session.close()  # 关闭session

此方法存在插入后又更新一次的情况,但对整体任务完成没有影响。

7、方法 5: python连接mysql完成插入和更新版本2

import pymysql

ip='xxx'
port='xxx'
user='xxx'
passwd='xxx'
db='xxx'

def get_conn():
    conn = pymysql.connect(host={ip},
                           port={port},
                           user={user},
                           passwd={passwd},
                           db={db},
                           charset="utf8")
    return conn

def update_and_insert_1(table, column1, column2, column3):
    conn = get_conn()
    cursor = conn.cursor()
    column3 = column3[:-1]
    update_sql = f"""
                    UPDATE {table} 
                    SET column2={column2}, column3='{column3}' 
                    WHERE column1='{column1}';
                  """
    insert_sql = f"""
                    INSERT INTO {table} (column1, column2, column3)
                    SELECT '{column1}', {column2}, '{column3}'
                    WHERE NOT EXISTS (SELECT 1  FROM {table} WHERE column1 = '{column1}' AND column2={column2} AND column3='{column3}');
                  """
    # 执行更新操作
    cursor.execute(update_sql)
    # 注意:这里执行更新操作后,没有执行conn.commit()提交事物,可能会出错,可加上去尝试

    # 检查是否更新了行(这里不直接检查 ROW_COUNT,而是通过再次查询来避免竞态条件)
    cursor.execute("SELECT COUNT(*) FROM {table} WHERE column1 = %s AND photo_class is null",
                   (column1))
    count = cursor.fetchone()[0]

    # 如果没有更新行,则执行插入操作
    if count == 0:
        cursor.execute(insert_sql)
        conn.commit()  # 提交事务(如果需要的话)
    conn.close()
    return None
    
def update_and_insert_2(table, column_order, dic_result):
    """Get the photo category."""
    conn = get_conn()
    cursor = conn.cursor()
    # 遍历字典
    for key, value_ls in dic_result.items():
        # 将列表转换为逗号分隔的字符串(注意:这里假设列表中的元素不包含逗号或特殊字符)
        column2 = ', '.join(map(str, value_ls))

        # 准备 SQL 语句(使用参数化查询来避免 SQL 注入)
        update_sql = """  
        UPDATE {table}  
        SET column2 = %s  
        WHERE column_order = %s AND column1 = %s;  
        """
        insert_sql = """  
        INSERT INTO {table} (column_order, column1, column2)  
        SELECT %s, %s, %s  
        WHERE NOT EXISTS (  
            SELECT 1  
            FROM {table}  
            WHERE column_order = %s AND column1 = %s  
        );  
        """

        # 执行更新操作
        cursor.execute(update_sql, (column2, column_order, key))
        # conn.commit()  # 提交事务(如果需要的话),此处需特别注意,需要注释回去

        # 检查是否更新了行(这里不直接检查 ROW_COUNT,而是通过再次查询来避免竞态条件)
        cursor.execute("SELECT COUNT(*) FROM {table} WHERE column_order = %s AND column1 = %s",
                       (column_order, key))
        count = cursor.fetchone()[0]

        # 如果没有更新行,则执行插入操作
        if count == 0:
            cursor.execute(insert_sql, (column_order, key, column2, column_order, key))
            conn.commit()  # 提交事务(如果需要的话)
    conn.close()
    return None

8、方法 6: 在mysql部分关键字段设置成unique可避免重复

try:
	cursor.execute(insert)
except:
	cursor.execute(update)

try:
	df.to_sql()
except:
	continue()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值