pymysql+动态封装update语句

初始方法:

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()


### 使用 `pymysql` 进行 Python 操作 MySQL 的封装方法 #### 封装思路 为了简化与 MySQL 数据库之间的交互,可以创建一个工具类来处理连接、执行 SQL 查询和其他数据库操作。此类应提供简便的方法来进行增删改查等基本操作,并能有效管理数据库连接。 #### 封装实现 下面展示了一个基于 `pymysql` 库构建的 MySQL 工具类的具体实例: ```python import pymysql class MySQLTool: def __init__(self, host='localhost', user='root', password='', db=''): """ 初始化数据库连接参数 :param host: 数据库服务器地址,默认为本地主机 :param user: 用户名,默认为 'root' :param password: 密码,默认为空字符串 :param db: 要使用的数据库名称,默认为空字符串表示不指定特定数据库 """ self.connection = None try: # 建立到MySQL数据库的连接 self.connection = pymysql.connect( host=host, user=user, password=password, database=db, charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor ) except Exception as e: print(f"Error connecting to the MySQL server: {e}") def execute_query(self, sql): """ 执行查询语句并返回结果集 """ result = [] with self.connection.cursor() as cursor: cursor.execute(sql) result = cursor.fetchall() return result def insert_data(self, table_name, data_dict): """ 插入新记录至给定表中 """ columns = ', '.join(data_dict.keys()) values_placeholder = ', '.join(['%s'] * len(data_dict)) query = f'INSERT INTO `{table_name}` ({columns}) VALUES ({values_placeholder});' affected_rows = 0 with self.connection.cursor() as cursor: affected_rows = cursor.execute(query, tuple(data_dict.values())) self.connection.commit() return affected_rows > 0 def update_data(self, table_name, set_clause, where_clause=None): """ 更新现有记录 """ query = f'UPDATE `{table_name}` SET {set_clause}' if where_clause is not None and isinstance(where_clause, str) and len(where_clause.strip()) > 0: query += f' WHERE {where_clause}' affected_rows = 0 with self.connection.cursor() as cursor: affected_rows = cursor.execute(query) self.connection.commit() return affected_rows > 0 def delete_data(self, table_name, condition): """ 删除满足条件的数据 """ query = f'DELETE FROM `{table_name}` WHERE {condition};' affected_rows = 0 with self.connection.cursor() as cursor: affected_rows = cursor.execute(query) self.connection.commit() return affected_rows > 0 def close_connection(self): """ 关闭数据库连接 """ if self.connection: self.connection.close() if __name__ == '__main__': tool = MySQLTool(host="your_host", user="your_user", password="your_password", db="test_db") # 测试插入功能 inserted = tool.insert_data('users', {'username': 'Alice', 'age': 30}) print(f"Insert successful? {inserted}") # 测试更新功能 updated = tool.update_data('users', "username=%s, age=%s", "id=1") print(f"Update successful? {updated}") # 测试删除功能 deleted = tool.delete_data('users', "id=2") print(f"Delete successful? {deleted}") # 测试查询功能 users = tool.execute_query("SELECT * FROM users;") for user in users: print(user) # 断开连接 tool.close_connection() ``` 此代码片段展示了如何利用 `pymysql` 创建一个名为 `MySQLTool` 的类,它能够方便地完成对 MySQL 数据库的各种常用操作[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值