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、问题分析
-
IF 语句的用法:
- SQL 的
IF语句一般是在存储过程或触发器中使用,而不能在常规的 SQL 语句中直接使用。 如果你在数据库客户端或管理工具中直接执行这段代码,会导致错误。
- SQL 的
-
更新和插入的逻辑:
UPDATE语句的逻辑上似乎是想要更新某一条记录,但在更新条件上使用了id = 3和class_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 ;
解释
- DELIMITER //: 改变语句结束符,以便可以在存储过程体中使用
;。 - CREATE PROCEDURE: 创建一个名为
UpdateOrInsert的存储过程。 - UPDATE: 尝试更新记录。
- 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;
关键改动说明:
-
设置变量:在检查受影响行数时,将
ROW_COUNT()的结果存储在一个用户定义的变量中,例如@affected_rows。这样,在插入语句中可以使用这个变量进行判断,而不会受到ROW_COUNT()的影响。 -
更新语句:在更新语句中,只更新
class_name。因为你已经在WHERE子句中指定了id和class_group,这条更新语句会准确更新对应的记录。 -
插入语句:在插入新记录的
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()

255

被折叠的 条评论
为什么被折叠?



