阿星的空间

化身SQLBOY,我写了一个专门的数据处理包-DotQuery,这是第一个版本

前言

使用Python写脚本,做数据处理是比较方便的事儿,特别是许多重复性的数据工作或者钉钉机器人之类的,写一个脚本,数据拉取-拼接-输出,一气呵成。

然而这里出现一个痛点,随着用到的SQL脚本越来越多,或者脚本里需要拼接的不同源的数据越来越多,在review时想要追溯一些字段的逻辑就变得异常复杂困难,从字段找到变量,从变量找到函数,从函数找到SQL出处,碰上一些认真的同学,这里的每个环节都会用上abcd不同的命名,能把你脑子转晕掉。

所以,何不简单一些,跳过这些中间环节,所见即所得,顾名即思义,直接 sql.字段 一把梭搞定。

这里还有另外一个痛点,就是 .语法,我对于大量重复的 result['字段'] 写法有点受不了了,这里的方括号啊单引号啊太啰嗦了,所以,我直接将其他语言常见的.语法逻辑拿了过来,甚至实现了 result.字段.to_fixed(2)这样的链式调用,总之,就是既要无脑还要强大。

于是就有了这个 DotQuery

注:在写SQL过程中,我是非常喜欢用中文做字段命名的,不喜勿喷,大家自行选择。

DotQuery

python下的数据查询高效工具,通过包装sql查询结果对象,支持点语法进行数据键值的快速查询和输出,提高数据查询和开发效率。

通常用于单脚本场景的数据查询,不建议用于公开对外的业务场景。

简单的说,就是化身sql boy,无脑写SQL即可。

安装与使用

  1. 直接将本包dotquery置于python项目下,在脚本中import
  2. 通过DotQuery方法初始化数据库连接以及指定sqls所在目录
  3. 在sqls目录中根据业务场景进行sql编写,并保存为函数同名文件
  4. 在脚本中,通过dq.xxx(参数)执行对应数据查询,获得查询结果
  5. 根据业务需求,直接通过 result.字段 的方式使用目标字段,

注1:也可以支持result.字段一.plus(result.字段二)这样的更多预置的 .方法 来进行数字或字符的二次处理。

注2:是的,根据自己的喜好,字段名可以直接是中文。

示例

example.py

import os
from dotquery import DotQuery

if __name__ == '__main__':
    dq = DotQuery(
                 host='127.0.0.1'
                ,user='root'
                ,passwd='123456'
                ,port=3306
                ,db='test'
                ,charset='utf8'
                ,sqls_path=os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "./sqls/"))
                ).val_if_none('-') # 在后续使用过程中,如果调用到不存在的字段,则使用默认值-

    user_count=dq.user_count('2024-12-07')

    print(f"最后注册时间:{user_count.最后注册时间}")
    print(f"新注册用户:{user_count.新注册用户}")
    print(f"新注册用户两倍数:{user_count.新注册用户.times(2)}")
    print(f"男性用户:{user_count.男性用户}")
    print(f"男性用户占比:{user_count.男性用户.rateof(user_count.新注册用户)}")
    print(f"女性用户:{user_count.女性用户}")
    print(f"女性用户/男性用户:{(user_count.女性用户 / user_count.男性用户).to_fixed(1)}")
    print(f"女性用户/(女性用户+男性用户):{(user_count.女性用户/(user_count.女性用户 + user_count.男性用户)).times(100).to_fixed(1).suffix('%')}")
    print(f"不存在用户:{user_count.不存在用户}")
    print(f"不存在用户二:{user_count.不存在用户二.vin('?')}")

    user_count2=dq.user_count('2024-12-08')
    print(f"最后注册时间:{user_count2.最后注册时间}")
    print(f"环比前日:{user_count2.新注册用户.minus(user_count.新注册用户).prefix('+').to_fixed(0)}")

打印结果:

最后注册时间:2024-12-07 15:37:58
新注册用户:4
新注册用户两倍数:8.0
男性用户:3
男性用户占比:75.00%
女性用户:1
女性用户/男性用户:0.3
女性用户/(女性用户+男性用户):25.0%
不存在用户:-
不存在用户二:?
最后注册时间:2024-12-08 15:37:58
环比前日:+2

文件布局:

----------
|-dotquery/
|  |-dotquery.py
|  |-...
|-sqls/
|  |-user_count.py
|-example.py

sql举例: sqls/user_count.py

# 使用与.py文件同名的函数,返回结果为sql字符 用于直接查询数据 或 sql,params 用于参数化查询
# 示例中使用字符拼接的方式获得SQL,是存在注入隐患的,请根据业务场景自行合理实现。
def user_count(target_day):
    return f"""
SELECT
     COUNT(1) AS `新注册用户`
    ,COUNT(IF(`gender`='MALE',1,NULL)) AS `男性用户`
    ,COUNT(IF(`gender`='FEMALE',1,NULL)) AS `女性用户`
    ,MAX(`create_time`) AS `最后注册时间`
FROM user
WHERE `create_time` BETWEEN '{target_day}' AND '{target_day} 23:59:59'
"""

更多示例详见example.py或源代码

todo

√ 基础功能:实现自动关联执行sql脚本、支持查询结果对象的若干点语法(基础的数学计算、转换、判断能力
□ 支持常量替换,如$[yyyy-mm-dd]可以替换为日期
□ 支持变量替换,如${target_day}可以替换为参数的值
□ 支持共用代码块替换,如$<user_table>可以替换为共用的代码块
□ 支持.sql文件
□ 支持请求API获得数据
□ 支持多层嵌套的数据中进行路径搜索(通常用于API请求获得的JSON体),如 result.find('order.price') 或 result.search('*.price')
□ .sql文件支持变体,如神策请求
□ 支持数据导出为csv/excel/html
□ 支持数据流式查询和处理
□ 支持写入数据
□ 支持流式写入数据
□ ...

其他说明

数据库操作类使用的是 pymysql

License

MIT

原文来自阿星的空间:https://wanyaxing.com/blog/20241209170900.html

X