初始方法:
import pymysql
def update_invoice_fields(order_sn, name=None, units=None, class_name=None, tax_rate=None):
"""
根据订单号更新发票相关字段
Parameters:
order_sn (str): 订单号
name (str): 商品名称
units (str): 商品单位
class_name (str): 税收分类名称
tax_rate (float): 税率
Returns:
int: 更新的行数
"""
# 连接MySQL数据库
conn = pymysql.connect(
host='rmics.com',
port=3306,
user='yui',
password='123456',
db='test',
charset='utf8'
)
# 创建游标对象,用于执行SQL语句
cursor = conn.cursor()
# 构造 SQL 语句
sql1 = """
UPDATE crm_invoice a
JOIN crm_invoice_info b ON a.id = b.invoice_id
JOIN( SELECT *, COUNT(*) AS cnt FROM crm_invoice_info GROUP BY invoice_id HAVING cnt = 1 )tmp ON tmp.id = b.id
JOIN order_goods n ON b.rec_id = n.rec_id
JOIN goods d ON n.goods_id = d.goods_id
"""
sql = """
WHERE a.ordersn = %(ordersn)s
"""
if class_name and tax_rate:
sql += "AND EXISTS(SELECT 1 FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s) "
elif class_name:
sql += "AND d.class_name = %(class_name)s "
elif tax_rate:
sql += "AND EXISTS(SELECT 1 FROM tax_categories WHERE class_name = b.class AND tax_rate = %(tax_rate)s) "
set_fields = []
if name:
set_fields.append("b.NAME = %(name)s")
set_fields.append("d.invoice_name = %(name)s")
if units:
set_fields.append("b.units = %(units)s")
set_fields.append("d.unit = %(units)s")
if class_name and tax_rate:
set_fields.append("b.class = %(class_name)s")
set_fields.append(
"b.class_code = (SELECT class_code FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s LIMIT 1)")
set_fields.append(
"b.tax_rate = (SELECT tax_rate FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s LIMIT 1)")
set_fields.append("d.class_name = %(class_name)s")
set_fields.append(
"d.class_code = (SELECT class_code FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s LIMIT 1)")
if not set_fields:
# 如果没有 SET 更新字段,则直接返回
return 0
info = "SET " + ", ".join(set_fields)
sql = sql1 + info + sql
print("执行的sql等于=========", sql)
# 执行SQL语句
params = {"order_sn": order_sn, "name": name, "units": units, "class_name": class_name, "tax_rate": tax_rate}
cursor.execute(sql, params)
# 提交更改
conn.commit()
# 获取更新的行数
rowcount = cursor.rowcount
print("执行成功的行数rowcount===", rowcount)
# 关闭游标和数据库连接
cursor.close()
conn.close()
# 返回更新的行数
return rowcount
update_invoice_fields("20220110134064", name="", units="", class_name="日用杂品", tax_rate=13)
# update_invoice_fields("20220110134064", name="面具")
封装一:
import pymysql
class BaseSQL:
"""
SQL 语句构造器基类
"""
def __init__(self, db_config, table, columns):
"""
初始化连接数据库和表信息
Args:
db_config (dict): 数据库连接信息
table (dict): 相关表名和列名
columns (list): 待更新的字段列表
"""
self.conn = pymysql.connect(**db_config)
self.table = table
self.columns = columns
def _build_where(self, where=None):
"""
构造 WHERE 条件语句
Args:
where (dict): 查询条件
Returns:
str: WHERE 条件语句
dict: WHERE 条件中的查询参数
"""
if not where:
return '', {}
where_conditions = []
params = {}
for key, value in where.items():
if value is None:
continue
if isinstance(value, (list, tuple)):
where_conditions.append(f"{key} IN ({','.join('%s' for _ in value)})")
params[key] = value
else:
where_conditions.append(f"{key} = %({key})s")
params[key] = value
if not where_conditions:
return '', {}
where_clause = "WHERE " + " AND ".join(where_conditions)
return where_clause, params
def _build_set(self, data):
"""
构造 SET 更新字段语句
Args:
data (dict): 待更新的字段和值
Returns:
str: SET 更新字段语句
dict: SET 更新字段中的值
"""
set_fields = []
params = {}
for field, value in data.items():
if value is not None:
set_fields.append(f"{self.columns[field]} = %({field})s")
params[field] = value
if not set_fields:
return '', {}
set_clause = "SET " + ", ".join(set_fields)
return set_clause, params
def execute(self, sql, params=None):
"""
执行 SQL 语句,返回执行结果和影响行数。
Args:
sql (str): SQL 语句
params (dict): SQL 语句中的参数
Returns:
tuple: 执行结果和影响行数
"""
try:
with self.conn.cursor() as cursor:
row_count = cursor.execute(sql, params)
result = cursor.fetchall()
self.conn.commit()
return result, row_count
except Exception as e:
self.conn.rollback()
raise e
@staticmethod
def build_params(data=None, where=None):
"""
构造 SQL 语句中的参数
Args:
data (dict): 待更新的字段和值
where (dict): 查询条件
Returns:
dict: SQL 语句中的参数
"""
params = {}
if where:
params.update(where)
if data:
params.update(data)
return params
class InvoiceUpdater(BaseSQL):
"""
更新发票相关字段
"""
def __init__(self, db_config, order_sn, name=None, units=None, class_name=None, tax_rate=None):
"""
初始化连接数据库和参数信息
Args:
db_config (dict): 数据库连接信息
order_sn (str): 订单号
name (str): 商品名称
units (str): 商品单位
class_name (str): 税收分类名称
tax_rate (float): 税率
"""
super().__init__(db_config, table=TABLES, columns=COLUMNS)
self.order_sn = order_sn
self.name = name
self.units = units
self.class_name = class_name
self.tax_rate = tax_rate
def update(self):
"""
更新发票相关字段
Returns:
int: 更新的行数
"""
where = {"a.order_sn": self.order_sn}
if self.class_name and self.tax_rate:
where["SELECT 1 FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s"] = None
elif self.class_name:
where["d.class_name"] = self.class_name
elif self.tax_rate:
where["SELECT 1 FROM tax_categories WHERE class_name = b.class AND tax_rate = %(tax_rate)s"] = None
data = {}
if self.name:
data[COLUMNS['name']] = self.name
data[COLUMNS['invoice_name']] = self.name
if self.units:
data[COLUMNS['units']] = self.units
data[COLUMNS['unit']] = self.units
if self.class_name and self.tax_rate:
data[COLUMNS['class']] = self.class_name
data[COLUMNS['class_code']] = "SELECT class_code FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s LIMIT 1"
data[COLUMNS['tax_rate']] = "SELECT tax_rate FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s LIMIT 1"
data[COLUMNS['class_name']] = self.class_name
data[COLUMNS['class_code']] = "SELECT class_code FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s LIMIT 1"
where_clause, where_params = self._build_where(where)
set_clause, set_params = self._build_set(data)
params = self.build_params(where=where_params, data=set_params)
if not set_clause:
# 如果没有 SET 更新字段,则直接返回
return 0
sql = f"""
UPDATE {self.table['invoice']} AS a
JOIN {self.table['invoice_info']} AS b ON a.{COLUMNS['invoice_id']} = b.{COLUMNS['invoice_id']}
JOIN (
SELECT *, COUNT(*) AS cnt FROM {self.table['invoice_info']} GROUP BY {COLUMNS['invoice_id']} HAVING cnt = 1
) AS tmp ON tmp.{COLUMNS['invoice_id']} = b.{COLUMNS['invoice_id']}
JOIN {self.table['order_goods']} AS n ON b.{COLUMNS['rec_id']} = n.{COLUMNS['rec_id']}
JOIN {self.table['goods']} AS d ON n.{COLUMNS['goods_id']} = d.{COLUMNS['goods_id']}
{set_clause}
{where_clause}
"""
result, row_count = self.execute(sql, params)
return row_count
封装三:
import pymysql
import logging
from datetime import datetime
# 数据库连接信息
DB_CONFIG = {
"host": "rmics.com",
"port": 3306,
"user": "yui",
"password": "123456",
"db": "test",
"charset": "utf8",
}
# 日志配置信息
LOG_CONFIG = {
"filename": "update_invoice_fields.log",
"level": logging.INFO,
"format": "[%(asctime)s] [%(levelname)s] %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
}
# 待更新的字段名和列名的对应关系
COLUMNS = {
"name": "b.NAME",
"units": "b.units",
"class_name": "b.class",
"tax_rate": "b.tax_rate",
"invoice_name": "d.invoice_name",
"class_code": "d.class_code",
"class_name2": "d.class_name",
"unit": "d.unit",
"tax_rate2": "b.tax_rate",
"class": "b.class",
"invoice_id": "id",
"rec_id": "rec_id",
"goods_id": "goods_id",
}
# 相关表名和列名的对应关系
TABLES = {
"invoice": "crm_invoice",
"invoice_info": "crm_invoice_info",
"order_goods": "military_order_goods",
"goods": "goods",
}
# 基础服务类,封装数据库和日志功能
class BaseService:
"""
基础服务类,封装数据库和日志功能
"""
def __init__(self, db_config=DB_CONFIG, logger_name="BaseService"):
"""
初始化数据库连接、日志记录器
Args:
db_config (dict): 数据库连接信息
logger_name (str): 日志记录器名称
"""
self.conn = pymysql.connect(**db_config)
self.logger = logging.getLogger(logger_name)
self.logger.setLevel(LOG_CONFIG["level"])
formatter = logging.Formatter(LOG_CONFIG["format"], LOG_CONFIG["datefmt"])
handler = logging.FileHandler(LOG_CONFIG["filename"])
handler.setFormatter(formatter)
self.logger.addHandler(handler)
def _build_where(self, where):
"""
构造 WHERE 子句
Args:
where (dict): WHERE 条件字典
Returns:
str: WHERE 子句
dict: WHERE 条件参数
"""
where_clause = ""
where_params = {}
for key, value in where.items():
if isinstance(value, str):
# 直接拼接字符串
where_clause += f" AND {key} = %(where_{key})s"
where_params[f"where_{key}"] = value
elif isinstance(value, dict):
# 拼接子查询
sub_clause, sub_params = self._build_where(value)
where_clause += f" AND ({sub_clause})"
where_params.update(sub_params)
elif isinstance(value, list):
# 拼接 IN 子句
where_clause += f" AND {key} IN %(where_{key})s"
where_params[f"where_{key}"] = value
elif value is None:
# 拼接 IS NULL 子句
where_clause += f" AND {key} IS NULL"
else:
raise ValueError(f"Invalid WHERE condition: {key}={value}")
if where_clause:
where_clause = "WHERE " + where_clause[5:]
return where_clause, where_params
def _build_set(self, data):
"""
构造 SET 子句
Args:
data (dict): 更新字段字典
Returns:
str: SET 子句
dict: 更新字段参数
"""
set_clause = ""
set_params = {}
for key, value in data.items():
if isinstance(value, str):
# 直接拼接字符串
set_clause += f", {key} = %(set_{key})s"
set_params[f"set_{key}"] = value
elif isinstance(value, dict):
# 拼接子查询
for sub_key, sub_value in value.items():
set_clause += f", {key} = ({sub_value})"
set_params.update({sub_key: sub_value})
elif isinstance(value, list):
# 暂不支持列表类型的更新
raise ValueError(f"Unsupported data type for SET clause: {key}={value}")
else:
# 直接拼接数值类型
set_clause += f", {key} = {value}"
if set_clause:
set_clause = "SET " + set_clause[2:]
return set_clause, set_params
def execute(self, sql, params=None):
"""
执行 SQL 语句
Args:
sql (str): SQL 语句
params (dict): SQL 语句参数
Returns:
tuple: 查询结果和影响行数
"""
cursor = self.conn.cursor()
try:
cursor.execute(sql, params)
self.conn.commit()
return cursor.fetchall(), cursor.rowcount
except Exception as e:
self.logger.error(f"Failed to execute SQL query: {sql}, params={params}, error={str(e)}")
raise ValueError(str(e)) from e
finally:
cursor.close()
# 更新发票相关字段
class InvoiceUpdater(BaseService):
"""
更新发票相关字段
"""
def __init__(self, order_sn=None, name=None, units=None, class_name=None, tax_rate=None, **kwargs):
"""
初始化订单号和待更新的字段信息
Args:
order_sn (str): 订单号
name (str): 发票名称
units (str): 单位
class_name (str): 税收分类名称
tax_rate (float): 税率
"""
super().__init__(db_config=DB_CONFIG, logger_name="InvoiceUpdater")
self.order_sn = order_sn
self.name = name
self.units = units
self.class_name = class_name
self.tax_rate = tax_rate
def execute(self):
"""
更新发票相关字段
Returns:
int: 更新的行数
"""
try:
where = {"a.order_sn": self.order_sn}
if self.class_name and self.tax_rate:
where[
"SELECT 1 FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s"] = None
elif self.class_name:
where["d.class_name"] = self.class_name
elif self.tax_rate:
where["SELECT 1 FROM tax_categories WHERE class_name = b.class AND tax_rate = %(tax_rate)s"] = None
data = {}
if self.name:
data["name"] = self.name
data["invoice_name"] = self.name
if self.units:
data["units"] = self.units
data["unit"] = self.units
if self.class_name and self.tax_rate:
data["class"] = self.class_name
data["class_code"] = "SELECT class_code FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s LIMIT 1"
data["tax_rate"] = "SELECT tax_rate FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s LIMIT 1"
data["class_name2"] = self.class_name
data["class_code2"] = "SELECT class_code FROM tax_categories WHERE class_name = %(class_name)s AND tax_rate = %(tax_rate)s LIMIT 1"
where_clause, where_params = self._build_where(where)
set_clause, set_params = self._build_set(data)
params = {**where_params, **set_params}
if not set_clause:
# 如果没有 SET 更新字段,则直接返回
return 0
sql = f"""
UPDATE {TABLES['invoice']} AS a
JOIN {TABLES['invoice_info']} AS b ON a.{COLUMNS['invoice_id']} = b.{COLUMNS['invoice_id']}
JOIN (
SELECT *, COUNT(*) AS cnt FROM {TABLES['order_goods']} WHERE {COLUMNS['rec_id']} IS NOT NULL GROUP BY {COLUMNS['goods_id']} HAVING cnt = 1
) AS c ON b.{COLUMNS['goods_id']} = c.{COLUMNS['goods_id']}
JOIN {TABLES['goods']} AS d ON c.{COLUMNS['rec_id']} = d.{COLUMNS['rec_id']}
{where_clause}
{set_clause}
"""
result, count = self.execute(sql, params=params)
self.logger.info(f"Updated {count} rows for ordersn={self.ordersn}")
return count
except Exception as e:
self.logger.error(f"Failed to update invoice fields for ordersn={self.ordersn}: {str(e)}")
raise ValueError(str(e)) from e
if __name__ == "__main__":
updater = InvoiceUpdater(
order_sn="123456",
name="测试发票",
units="个",
class_name="办公用品",
tax_rate=0.16
)
updater.execute()