mdbq 1.5.6__py3-none-any.whl → 1.5.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -138,6 +138,57 @@ class MysqlDatasQuery:
138
138
  )
139
139
  return df
140
140
 
141
+ def tg_rqbb(self):
142
+ start_date, end_date = self.months_data(num=self.months)
143
+ projection = {
144
+ '日期': 1,
145
+ '场景名字': 1,
146
+ '主体id': 1,
147
+ '花费': 1,
148
+ '展现量': 1,
149
+ '点击量': 1,
150
+ '总购物车数': 1,
151
+ '总成交笔数': 1,
152
+ '总成交金额': 1,
153
+ '直接成交笔数': 1,
154
+ '直接成交金额': 1,
155
+ '人群名字': 1,
156
+ }
157
+ df = self.download.data_to_df(
158
+ db_name='推广数据2',
159
+ table_name='人群报表',
160
+ start_date=start_date,
161
+ end_date=end_date,
162
+ projection=projection,
163
+ )
164
+ return df
165
+
166
+ def tg_gjc(self):
167
+ start_date, end_date = self.months_data(num=self.months)
168
+ projection = {
169
+ '日期': 1,
170
+ '场景名字': 1,
171
+ '宝贝id': 1,
172
+ '词类型': 1,
173
+ '词名字/词包名字': 1,
174
+ '花费': 1,
175
+ '展现量': 1,
176
+ '点击量': 1,
177
+ '总购物车数': 1,
178
+ '总成交笔数': 1,
179
+ '总成交金额': 1,
180
+ '直接成交笔数': 1,
181
+ '直接成交金额': 1,
182
+ }
183
+ df = self.download.data_to_df(
184
+ db_name='推广数据2',
185
+ table_name='关键词报表',
186
+ start_date=start_date,
187
+ end_date=end_date,
188
+ projection=projection,
189
+ )
190
+ return df
191
+
141
192
  def idbm(self):
142
193
  """ 用生意经日数据制作商品 id 和编码对照表 """
143
194
  data_values = self.download.columns_to_list(
@@ -213,6 +264,55 @@ class MysqlDatasQuery:
213
264
  df = pd.DataFrame(data=data_values)
214
265
  return df
215
266
 
267
+ def jdjzt(self):
268
+ start_date, end_date = self.months_data(num=self.months)
269
+ projection = {
270
+ '日期': 1,
271
+ '产品线': 1,
272
+ '触发sku id': 1,
273
+ '跟单sku id': 1,
274
+ '花费': 1,
275
+ '展现数': 1,
276
+ '点击数': 1,
277
+ '直接订单行': 1,
278
+ '直接订单金额': 1,
279
+ '总订单行': 1,
280
+ '总订单金额': 1,
281
+ '直接加购数': 1,
282
+ '总加购数': 1,
283
+ 'spu id': 1,
284
+ }
285
+ df = self.download.data_to_df(
286
+ db_name='京东数据2',
287
+ table_name='推广数据_京准通',
288
+ start_date=start_date,
289
+ end_date=end_date,
290
+ projection=projection,
291
+ )
292
+ return df
293
+
294
+ def sku_sales(self):
295
+ start_date, end_date = self.months_data(num=self.months)
296
+ projection = {
297
+ '日期': 1,
298
+ '商品id': 1,
299
+ '货号': 1,
300
+ '成交单量': 1,
301
+ '成交金额': 1,
302
+ '访客数': 1,
303
+ '成交客户数': 1,
304
+ '加购商品件数': 1,
305
+ '加购人数': 1,
306
+ }
307
+ df = self.download.data_to_df(
308
+ db_name='京东数据2',
309
+ table_name='sku_商品明细',
310
+ start_date=start_date,
311
+ end_date=end_date,
312
+ projection=projection,
313
+ )
314
+ return df
315
+
216
316
  @staticmethod
217
317
  def months_data(num=0, end_date=None):
218
318
  """ 读取近 num 个月的数据, 0 表示读取当月的数据 """
@@ -236,6 +336,7 @@ class GroupBy:
236
336
  else:
237
337
  self.output = os.path.join('数据中心/数据库导出')
238
338
  self.data_tgyj = {} # 推广综合聚合数据表
339
+ self.data_jdtg = {} # 京东推广数据,聚合数据
239
340
 
240
341
  @staticmethod
241
342
  def try_except(func): # 在类内部定义一个异常处理方法
@@ -319,6 +420,88 @@ class GroupBy:
319
420
  }
320
421
  )
321
422
  return df
423
+ elif '人群报表' in table_name:
424
+ df.rename(columns={
425
+ '场景名字': '营销场景',
426
+ '主体id': '商品id',
427
+ '总购物车数': '加购量',
428
+ '总成交笔数': '成交笔数',
429
+ '总成交金额': '成交金额'
430
+ }, inplace=True)
431
+ df = df.astype({
432
+ '商品id': str,
433
+ '花费': float,
434
+ '展现量': int,
435
+ '点击量': int,
436
+ '加购量': int,
437
+ '成交笔数': int,
438
+ '成交金额': float,
439
+ '直接成交笔数': int,
440
+ '直接成交金额': float,
441
+ }, errors='raise')
442
+ df.fillna(0, inplace=True)
443
+ if is_maximize:
444
+ df = df.groupby(['日期', '营销场景', '商品id', '花费', '展现量', '点击量', '人群名字'], as_index=False).agg(
445
+ **{'加购量': ('加购量', np.max),
446
+ '成交笔数': ('成交笔数', np.max),
447
+ '成交金额': ('成交金额', np.max),
448
+ '直接成交笔数': ('直接成交笔数', np.max),
449
+ '直接成交金额': ('直接成交金额', np.max)
450
+ }
451
+ )
452
+ else:
453
+ df = df.groupby(['日期', '营销场景', '商品id', '花费', '展现量', '点击量', '人群名字'], as_index=False).agg(
454
+ **{
455
+ '加购量': ('加购量', np.min),
456
+ '成交笔数': ('成交笔数', np.min),
457
+ '成交金额': ('成交金额', np.min),
458
+ '直接成交笔数': ('直接成交笔数', np.max),
459
+ '直接成交金额': ('直接成交金额', np.max)
460
+ }
461
+ )
462
+ df.insert(loc=1, column='推广渠道', value='万相台无界版') # df中插入新列
463
+ return df
464
+ elif '关键词报表' in table_name:
465
+ df.rename(columns={
466
+ '场景名字': '营销场景',
467
+ '宝贝id': '商品id',
468
+ '总购物车数': '加购量',
469
+ '总成交笔数': '成交笔数',
470
+ '总成交金额': '成交金额'
471
+ }, inplace=True)
472
+ df = df.astype({
473
+ '商品id': str,
474
+ '花费': float,
475
+ '展现量': int,
476
+ '点击量': int,
477
+ '加购量': int,
478
+ '成交笔数': int,
479
+ '成交金额': float,
480
+ '直接成交笔数': int,
481
+ '直接成交金额': float,
482
+ }, errors='raise')
483
+ df.fillna(0, inplace=True)
484
+ if is_maximize:
485
+ df = df.groupby(['日期', '营销场景', '商品id', '词类型', '词名字/词包名字', '花费', '展现量', '点击量'], as_index=False).agg(
486
+ **{'加购量': ('加购量', np.max),
487
+ '成交笔数': ('成交笔数', np.max),
488
+ '成交金额': ('成交金额', np.max),
489
+ '直接成交笔数': ('直接成交笔数', np.max),
490
+ '直接成交金额': ('直接成交金额', np.max)
491
+ }
492
+ )
493
+ else:
494
+ df = df.groupby(['日期', '营销场景', '商品id', '词类型', '词名字/词包名字', '花费', '展现量', '点击量'], as_index=False).agg(
495
+ **{
496
+ '加购量': ('加购量', np.min),
497
+ '成交笔数': ('成交笔数', np.min),
498
+ '成交金额': ('成交金额', np.min),
499
+ '直接成交笔数': ('直接成交笔数', np.max),
500
+ '直接成交金额': ('直接成交金额', np.max)
501
+ }
502
+ )
503
+ df.insert(loc=1, column='推广渠道', value='万相台无界版') # df中插入新列
504
+ return df
322
505
  elif '宝贝指标' in table_name:
323
506
  """ 聚合时不可以加商家编码,编码有些是空白,有些是 0 """
324
507
  df['宝贝id'] = df['宝贝id'].astype(str)
@@ -456,6 +639,38 @@ class GroupBy:
456
639
  }
457
640
  )
458
641
  return df
642
+ elif '京准通' in table_name:
643
+ df = df.groupby(['日期', '产品线', '触发sku id', '跟单sku id', 'spu id', '花费', '展现数', '点击数'], as_index=False).agg(
644
+ **{'直接订单行': ('直接订单行', np.max),
645
+ '直接订单金额': ('直接订单金额', np.max),
646
+ '总订单行': ('总订单行', np.max),
647
+ '总订单金额': ('总订单金额', np.max),
648
+ '直接加购数': ('直接加购数', np.max),
649
+ '总加购数': ('总加购数', np.max),
650
+ }
651
+ )
652
+ df = df[df['花费'] > 0]
653
+ self.data_jdtg.update(
654
+ {
655
+ table_name: df[['日期', '产品线', '触发sku id', '跟单sku id', '花费']],
656
+ }
657
+ )
658
+ return df
659
+ elif '京东_sku_商品明细' in table_name:
660
+ df = df[df['商品id'] != '合计']
661
+ df = df.groupby(['日期', '商品id', '货号', '访客数', '成交客户数', '加购商品件数', '加购人数'],
662
+ as_index=False).agg(
663
+ **{
664
+ '成交单量': ('成交单量', np.max),
665
+ '成交金额': ('成交金额', np.max),
666
+ }
667
+ )
668
+ self.data_jdtg.update(
669
+ {
670
+ table_name: df,
671
+ }
672
+ )
673
+ return df
459
674
  else:
460
675
  print(f'<{table_name}>: Groupby 类尚未配置,数据为空')
461
676
  return pd.DataFrame({})
@@ -487,13 +702,47 @@ class GroupBy:
487
702
  df = pd.merge(df, syj, how='left', left_on=['日期', '商品id'], right_on=['日期', '宝贝id'])
488
703
  df.drop(labels='宝贝id', axis=1, inplace=True)
489
704
  df.drop_duplicates(subset=['日期', '商品id', '花费', '销售额'], keep='last', inplace=True, ignore_index=True)
705
+ df.fillna(0, inplace=True)
490
706
  df['成本价'] = df['成本价'].astype('float64')
707
+ df['销售额'] = df['销售额'].astype('float64')
708
+ df['销售量'] = df['销售量'].astype('int64')
491
709
  df['商品成本'] = df.apply(lambda x: (x['成本价'] + x['销售额']/x['销售量'] * 0.11 + 6) * x['销售量'] if x['销售量'] > 0 else 0, axis=1)
492
710
  df['商品毛利'] = df.apply(lambda x: x['销售额'] - x['商品成本'], axis=1)
493
711
  df['毛利率'] = df.apply(lambda x: round((x['销售额'] - x['商品成本']) / x['销售额'], 4) if x['销售额'] > 0 else 0, axis=1)
494
712
  df['盈亏'] = df.apply(lambda x: x['商品毛利'] - x['花费'], axis=1)
495
713
  return df
496
714
 
715
+ def performance_jd(self, jd_tg=True):
716
+ jdtg, sku_sales = self.data_jdtg['京东_京准通'], self.data_jdtg['京东_sku_商品明细']
717
+ jdtg = jdtg.groupby(['日期', '跟单sku id'],
718
+ as_index=False).agg(
719
+ **{
720
+ '花费': ('花费', np.sum)
721
+ }
722
+ )
723
+ cost = self.data_tgyj['商品成本']
724
+ df = pd.merge(sku_sales, cost, how='left', left_on='货号', right_on='款号')
725
+ df = df[['日期', '商品id', '货号', '成交单量', '成交金额', '成本价']]
726
+ if jd_tg is True:
727
+ # 完整的数据表,包含全店所有推广、销售数据
728
+ df = pd.merge(df, jdtg, how='left', left_on=['日期', '商品id'], right_on=['日期', '跟单sku id']) # df 合并推广表
729
+ else:
730
+ df = pd.merge(jdtg, df, how='left', left_on=['日期', '跟单sku id'], right_on=['日期', '商品id']) # 推广表合并 df
731
+ df = df[['日期', '跟单sku id', '花费', '货号', '成交单量', '成交金额', '成本价']]
732
+ df.fillna(0, inplace=True)
733
+ df['成本价'] = df['成本价'].astype('float64')
734
+ df['成交金额'] = df['成交金额'].astype('float64')
735
+ df['花费'] = df['花费'].astype('float64')
736
+ df['成交单量'] = df['成交单量'].astype('int64')
737
+ df['商品成本'] = df.apply(
738
+ lambda x: (x['成本价'] + x['成交金额'] / x['成交单量'] * 0.11 + 6) * x['成交单量'] if x['成交单量'] > 0 else 0,
739
+ axis=1)
740
+ df['商品毛利'] = df.apply(lambda x: x['成交金额'] - x['商品成本'], axis=1)
741
+ df['毛利率'] = df.apply(
742
+ lambda x: round((x['成交金额'] - x['商品成本']) / x['成交金额'], 4) if x['成交金额'] > 0 else 0, axis=1)
743
+ df['盈亏'] = df.apply(lambda x: x['商品毛利'] - x['花费'], axis=1)
744
+ return df
745
+
497
746
  def as_csv(self, df, filename, path=None, encoding='utf-8_sig',
498
747
  index=False, header=True, st_ascend=None, ascend=None, freq=None):
499
748
  """
@@ -592,20 +841,21 @@ def data_aggregation_one(service_databases=[{}], months=1):
592
841
 
593
842
  # 从数据库中获取数据, 返回包含 df 数据的字典
594
843
  # 单独处理某一个聚合数据库,在这里修改添加 data_dict 的值
844
+ ######################################################
845
+ ################# 修改这里 ##########################
846
+ ######################################################
595
847
  data_dict = [
596
848
  {
597
849
  '数据库名': '聚合数据',
598
- '集合名': '天猫_店铺来源_日数据_旧版',
599
- '唯一主键': ['日期', '一级来源', '二级来源', '三级来源'],
600
- '数据主体': sdq.dplyd_old(),
601
- },
602
- {
603
- '数据库名': '聚合数据',
604
- '集合名': '天猫_店铺来源_日数据',
605
- '唯一主键': ['日期', '一级来源', '二级来源', '三级来源'],
606
- '数据主体': sdq.dplyd(),
850
+ '集合名': '京东_sku_商品明细',
851
+ '唯一主键': ['日期', '商品id', '成交单量'],
852
+ '数据主体': sdq.sku_sales(),
607
853
  },
608
854
  ]
855
+ ######################################################
856
+ ################# 修改这里 ##########################
857
+ ######################################################
858
+
609
859
  for items in data_dict: # 遍历返回结果
610
860
  db_name, table_name, unique_key_list, df = items['数据库名'], items['集合名'], items['唯一主键'], items['数据主体']
611
861
  df = g.groupby(df=df, table_name=table_name, is_maximize=True) # 2. 聚合数据
@@ -680,6 +930,30 @@ def data_aggregation(service_databases=[{}], months=1):
680
930
  '唯一主键': ['款号'],
681
931
  '数据主体': sdq.sp_cost(),
682
932
  },
933
+ {
934
+ '数据库名': '聚合数据',
935
+ '集合名': '京东_京准通',
936
+ '唯一主键': ['日期', '产品线', '触发sku id', '跟单sku id', '花费', ],
937
+ '数据主体': sdq.jdjzt(),
938
+ },
939
+ {
940
+ '数据库名': '聚合数据',
941
+ '集合名': '京东_sku_商品明细',
942
+ '唯一主键': ['日期', '商品id', '成交单量'],
943
+ '数据主体': sdq.sku_sales(),
944
+ },
945
+ {
946
+ '数据库名': '聚合数据',
947
+ '集合名': '天猫_人群报表',
948
+ '唯一主键': ['日期', '推广渠道', '营销场景', '商品id', '花费', '人群名字'],
949
+ '数据主体': sdq.tg_rqbb(),
950
+ },
951
+ {
952
+ '数据库名': '聚合数据',
953
+ '集合名': '天猫_关键词报表',
954
+ '唯一主键': ['日期', '推广渠道', '营销场景', '商品id', '花费', '词类型', '词名字/词包名字',],
955
+ '数据主体': sdq.tg_gjc(),
956
+ },
683
957
  ]
684
958
  for items in data_dict: # 遍历返回结果
685
959
  db_name, table_name, unique_key_list, df = items['数据库名'], items['集合名'], items['唯一主键'], items['数据主体']
@@ -711,14 +985,22 @@ def data_aggregation(service_databases=[{}], months=1):
711
985
  icm_update=['日期', '商品id'], # 设置唯一主键
712
986
  service_database=service_database,
713
987
  )
988
+ res = g.performance_jd(jd_tg=False) # 盈亏表,依赖其他表,单独做
989
+ m.df_to_mysql(
990
+ df=res,
991
+ db_name='聚合数据',
992
+ table_name='_京东_推广商品销售',
993
+ drop_duplicates=False,
994
+ icm_update=['日期', '跟单sku id', '货号', '花费'], # 设置唯一主键
995
+ service_database=service_database,
996
+ )
714
997
 
715
998
  # 这里要注释掉,不然 copysh.py 可能有问题,这里主要修改配置文件,后续触发 home_lx 的 optimize_datas.py(有s)程序进行全局清理
716
999
  # optimize_data.op_data(service_databases=service_databases, days=3650) # 立即启动对聚合数据的清理工作
717
1000
 
718
1001
 
719
1002
  if __name__ == '__main__':
720
- # data_aggregation(service_databases=[{'home_lx': 'mysql'}], months=1)
721
- data_aggregation_one(service_databases=[{'company': 'mysql'}], months=1)
1003
+ data_aggregation(service_databases=[{'company': 'mysql'}], months=1) # 正常的聚合所有数据
1004
+ # data_aggregation_one(service_databases=[{'company': 'mysql'}], months=1) # 单独聚合某一个数据库,具体库进函数编辑
722
1005
  # optimize_data.op_data(service_databases=[{'company': 'mysql'}], days=3650) # 立即启动对聚合数据的清理工作
723
1006
 
724
-
mdbq/mysql/mysql.py CHANGED
@@ -180,87 +180,87 @@ class MysqlUpload:
180
180
  for data in datas:
181
181
  # data 是传进来待处理的数据, 不是数据库数据
182
182
  # data 示例: {'日期': Timestamp('2024-08-27 00:00:00'), '推广费余额': 33299, '品销宝余额': 2930.73, '短信剩余': 67471}
183
- # try:
184
- cols = ', '.join(f"`{item}`" for item in data.keys()) # 列名需要转义
185
- # data.update({item: f"{data[item]}" for item in data.keys()}) # 全部值转字符, 不是必须的
186
- values = ', '.join([f'"{item}"' for item in data.values()]) # 值要加引号
187
- condition = []
188
- for k, v in data.items():
189
- condition += [f'`{k}` = "{v}"']
190
- condition = ' AND '.join(condition) # 构建查询条件
191
- # print(condition)
192
-
193
- if drop_duplicates: # 查重插入
194
- sql = "SELECT %s FROM %s WHERE %s" % (cols, table_name, condition)
195
- # sql = f"SELECT {cols} FROM `{table_name}` WHERE `创建时间` = '2014-09-19 14:32:33'"
196
- # print(sql)
197
- cursor.execute(sql)
198
- result = cursor.fetchall() # 获取查询结果, 有结果返回 list 表示数据已存在(不重复插入),没有则返回空 tuple
199
- if not result: # 数据不存在则插入
200
- sql = f"INSERT INTO `{table_name}` ({cols}) VALUES (%s);" % (values)
201
- cursor.execute(sql)
202
- # else:
203
- # print(f'重复数据不插入: {condition[:50]}...')
204
- elif icm_update: # 增量更新, 专门用于聚合数据,其他库不要调用
205
- """ 使用增量更新: 需确保 icm_update['主键'] 传进来的列必须是数据表中唯一主键,值不会发生变化且不会重复,否则可能产生覆盖情况 """
206
- sql = 'SELECT COLUMN_NAME FROM information_schema.columns WHERE table_schema = %s AND table_name = %s'
207
- cursor.execute(sql, (db_name, {table_name}))
208
- columns = cursor.fetchall()
209
- cols_exist = [col['COLUMN_NAME'] for col in columns] # 数据表的所有列, 返回 list
210
- update_col = [item for item in cols_exist if item not in icm_update and item != 'id'] # 除了主键外的其他列
211
-
212
- # unique_keys 示例: `日期`, `推广费余额`
213
- unique_keys = ', '.join(f"`{item}`" for item in update_col) # 列名需要转义
183
+ try:
184
+ cols = ', '.join(f"`{item}`" for item in data.keys()) # 列名需要转义
185
+ # data.update({item: f"{data[item]}" for item in data.keys()}) # 全部值转字符, 不是必须的
186
+ values = ', '.join([f'"{item}"' for item in data.values()]) # 值要加引号
214
187
  condition = []
215
- for up_col in icm_update:
216
- condition += [f'`{up_col}` = "{data[up_col]}"']
217
- condition = ' AND '.join(condition) # condition值示例: `品销宝余额` = '2930.73' AND `短信剩余` = '67471'
218
- sql = f"SELECT {unique_keys} FROM `{table_name}` WHERE {condition}"
219
- # print(sql)
220
- # sql = f"SELECT {unique_keys} FROM `{table_name}` WHERE `创建时间` = '2014-09-19 14:32:33'"
221
- cursor.execute(sql)
222
- results = cursor.fetchall() # results 是数据库取出的数据
223
- if results: # 有数据返回,再进行增量检查
224
- for result in results: # results 是数据库数据, data 是传进来的数据
225
- change_col = [] # 发生变化的列名
226
- change_values = [] # 发生变化的数据
227
- for col in update_col:
228
- # 因为 mysql 里面有 decimal 数据类型,要移除末尾的 0 再做比较(df 默认将 5.00 小数截断为 5.0)
229
- df_value = str(data[col])
230
- mysql_value = str(result[col])
231
- if '.' in df_value:
232
- df_value = re.sub(r'0+$', '', df_value)
233
- df_value = re.sub(r'\.$', '', df_value)
234
- if '.' in mysql_value:
235
- mysql_value = re.sub(r'0+$', '', mysql_value)
236
- mysql_value = re.sub(r'\.$', '', mysql_value)
237
- if df_value != mysql_value: # 传进来的数据和数据库比较, 有变化
238
- # print(f'{data['日期']}{data['商品id']}{col} 列的值有变化,{str(data[col])} != {str(result[col])}')
239
- change_values += [f"`{col}` = \"{str(data[col])}\""]
240
- change_col.append(col)
241
- not_change_col = [item for item in update_col if item not in change_col]
242
- # change_values 是 df 传进来且和数据库对比后,发生了变化的数据,值示例: [`品销宝余额` = '9999.0', `短信剩余` = '888']
243
- if change_values: # change_values 有数据返回,表示值需要更新
244
- if not_change_col:
245
- not_change_values = [f'`{col}` = "{str(data[col])}"' for col in not_change_col]
246
- not_change_values = ' AND '.join(not_change_values) # 示例: `短信剩余` = '888' AND `test1` = '93'
247
- # print(change_values, not_change_values)
248
- condition += f' AND {not_change_values}' # 重新构建完整的查询条件,将未发生变化的列加进查询条件
249
- change_values = ', '.join(f"{item}" for item in change_values) # 注意这里 item 外面没有反引号
250
- sql = "UPDATE `%s` SET %s WHERE %s" % (table_name, change_values, condition)
251
- # print(sql)
252
- cursor.execute(sql)
253
- else: # 没有数据返回,则直接插入数据
254
- sql = f"INSERT INTO `{table_name}` ({cols}) VALUES ({values});"
188
+ for k, v in data.items():
189
+ condition += [f'`{k}` = "{v}"']
190
+ condition = ' AND '.join(condition) # 构建查询条件
191
+ # print(condition)
192
+
193
+ if drop_duplicates: # 查重插入
194
+ sql = "SELECT %s FROM %s WHERE %s" % (cols, table_name, condition)
195
+ # sql = f"SELECT {cols} FROM `{table_name}` WHERE `创建时间` = '2014-09-19 14:32:33'"
196
+ # print(sql)
255
197
  cursor.execute(sql)
256
- else:
257
- sql = f"INSERT INTO `{table_name}` ({cols}) VALUES (%s);" % (values)
258
- cursor.execute(sql)
259
- # except Exception as e:
260
- # # print(data)
261
- # # print(values)
262
- # print(f'mysql -> df_to_mysql 报错: {e}, {self.filename}')
263
- # # breakpoint()
198
+ result = cursor.fetchall() # 获取查询结果, 有结果返回 list 表示数据已存在(不重复插入),没有则返回空 tuple
199
+ if not result: # 数据不存在则插入
200
+ sql = f"INSERT INTO `{table_name}` ({cols}) VALUES (%s);" % (values)
201
+ cursor.execute(sql)
202
+ # else:
203
+ # print(f'重复数据不插入: {condition[:50]}...')
204
+ elif icm_update: # 增量更新, 专门用于聚合数据,其他库不要调用
205
+ """ 使用增量更新: 需确保 icm_update['主键'] 传进来的列必须是数据表中唯一主键,值不会发生变化且不会重复,否则可能产生覆盖情况 """
206
+ sql = 'SELECT COLUMN_NAME FROM information_schema.columns WHERE table_schema = %s AND table_name = %s'
207
+ cursor.execute(sql, (db_name, {table_name}))
208
+ columns = cursor.fetchall()
209
+ cols_exist = [col['COLUMN_NAME'] for col in columns] # 数据表的所有列, 返回 list
210
+ update_col = [item for item in cols_exist if item not in icm_update and item != 'id'] # 除了主键外的其他列
211
+
212
+ # unique_keys 示例: `日期`, `推广费余额`
213
+ unique_keys = ', '.join(f"`{item}`" for item in update_col) # 列名需要转义
214
+ condition = []
215
+ for up_col in icm_update:
216
+ condition += [f'`{up_col}` = "{data[up_col]}"']
217
+ condition = ' AND '.join(condition) # condition值示例: `品销宝余额` = '2930.73' AND `短信剩余` = '67471'
218
+ sql = f"SELECT {unique_keys} FROM `{table_name}` WHERE {condition}"
219
+ # print(sql)
220
+ # sql = f"SELECT {unique_keys} FROM `{table_name}` WHERE `创建时间` = '2014-09-19 14:32:33'"
221
+ cursor.execute(sql)
222
+ results = cursor.fetchall() # results 是数据库取出的数据
223
+ if results: # 有数据返回,再进行增量检查
224
+ for result in results: # results 是数据库数据, data 是传进来的数据
225
+ change_col = [] # 发生变化的列名
226
+ change_values = [] # 发生变化的数据
227
+ for col in update_col:
228
+ # 因为 mysql 里面有 decimal 数据类型,要移除末尾的 0 再做比较(df 默认将 5.00 小数截断为 5.0)
229
+ df_value = str(data[col])
230
+ mysql_value = str(result[col])
231
+ if '.' in df_value:
232
+ df_value = re.sub(r'0+$', '', df_value)
233
+ df_value = re.sub(r'\.$', '', df_value)
234
+ if '.' in mysql_value:
235
+ mysql_value = re.sub(r'0+$', '', mysql_value)
236
+ mysql_value = re.sub(r'\.$', '', mysql_value)
237
+ if df_value != mysql_value: # 传进来的数据和数据库比较, 有变化
238
+ # print(f'{data['日期']}{data['商品id']}{col} 列的值有变化,{str(data[col])} != {str(result[col])}')
239
+ change_values += [f"`{col}` = \"{str(data[col])}\""]
240
+ change_col.append(col)
241
+ not_change_col = [item for item in update_col if item not in change_col]
242
+ # change_values 是 df 传进来且和数据库对比后,发生了变化的数据,值示例: [`品销宝余额` = '9999.0', `短信剩余` = '888']
243
+ if change_values: # change_values 有数据返回,表示值需要更新
244
+ if not_change_col:
245
+ not_change_values = [f'`{col}` = "{str(data[col])}"' for col in not_change_col]
246
+ not_change_values = ' AND '.join(not_change_values) # 示例: `短信剩余` = '888' AND `test1` = '93'
247
+ # print(change_values, not_change_values)
248
+ condition += f' AND {not_change_values}' # 重新构建完整的查询条件,将未发生变化的列加进查询条件
249
+ change_values = ', '.join(f"{item}" for item in change_values) # 注意这里 item 外面没有反引号
250
+ sql = "UPDATE `%s` SET %s WHERE %s" % (table_name, change_values, condition)
251
+ # print(sql)
252
+ cursor.execute(sql)
253
+ else: # 没有数据返回,则直接插入数据
254
+ sql = f"INSERT INTO `{table_name}` ({cols}) VALUES ({values});"
255
+ cursor.execute(sql)
256
+ else:
257
+ sql = f"INSERT INTO `{table_name}` ({cols}) VALUES (%s);" % (values)
258
+ cursor.execute(sql)
259
+ except Exception as e:
260
+ # print(data)
261
+ # print(values)
262
+ print(f'mysql -> df_to_mysql 报错: {e}, {self.filename}')
263
+ # breakpoint()
264
264
  connection.commit() # 提交事务
265
265
  connection.close()
266
266
 
mdbq/mysql/s_query.py CHANGED
@@ -46,41 +46,44 @@ class QueryDatas:
46
46
 
47
47
  self.config.update({'database': db_name})
48
48
  connection = pymysql.connect(**self.config) # 重新连接数据库
49
- try:
50
- with connection.cursor() as cursor:
51
- # 3. 获取数据表的所有列信息
52
- sql = 'SELECT COLUMN_NAME FROM information_schema.columns WHERE table_schema = %s AND table_name = %s'
53
- cursor.execute(sql, (db_name, {table_name}))
54
- columns = cursor.fetchall()
55
- cols_exist = [col['COLUMN_NAME'] for col in columns] # 数据表的所有列, 返回 list
56
-
57
- # 4. 构建 SQL 查询语句
58
- if projection: # 获取指定列
59
- columns_in = []
60
- for key, value in projection.items():
61
- if value == 1 and key in cols_exist:
62
- columns_in.append(key) # 提取值为 1 的键并清理不在数据表的键
63
- columns_in = ', '.join(columns_in)
64
- if '日期' in cols_exist: # 不论是否指定, 只要数据表有日期,则执行
65
- sql = (f"SELECT {columns_in} FROM {db_name}.{table_name} "
66
- f"WHERE {'日期'} BETWEEN '{start_date}' AND '{end_date}'")
67
- else: # 数据表没有日期列时,返回指定列的所有数据
68
- sql = f"SELECT {columns_in} FROM {db_name}.{table_name}"
69
- else: # 没有指定获取列时
70
- if '日期' in cols_exist: # 但数据表有日期,仍然执行
71
- columns_in = ', '.join(cols_exist)
72
- sql = (f"SELECT {columns_in} FROM {db_name}.{table_name} "
73
- f"WHERE {'日期'} BETWEEN '{start_date}' AND '{end_date}'")
74
- else: # 没有指定获取列,且数据表也没有日期列,则返回全部列的全部数据
75
- sql = f"SELECT * FROM {db_name}.{table_name}"
76
- cursor.execute(sql)
77
- rows = cursor.fetchall() # 获取查询结果
78
- columns = [desc[0] for desc in cursor.description]
79
- df = pd.DataFrame(rows, columns=columns) # 转为 df
80
- except Exception as e:
81
- print(f'{e}')
49
+ # try:
50
+ with connection.cursor() as cursor:
51
+ # 3. 获取数据表的所有列信息
52
+ sql = 'SELECT `COLUMN_NAME` FROM information_schema.columns WHERE table_schema = %s AND table_name = %s'
53
+ cursor.execute(sql, (db_name, {table_name}))
54
+ columns = cursor.fetchall()
55
+ cols_exist = [col['COLUMN_NAME'] for col in columns] # 数据表的所有列, 返回 list
56
+
57
+ # 4. 构建 SQL 查询语句
58
+ if projection: # 获取指定列
59
+ columns_in = []
60
+ for key, value in projection.items():
61
+ if value == 1 and key in cols_exist:
62
+ columns_in.append(key) # 提取值为 1 的键并清理不在数据表的键
63
+ columns_in = [f"`{item}`" for item in columns_in]
64
+ columns_in = ', '.join(columns_in)
65
+ if '日期' in cols_exist: # 不论是否指定, 只要数据表有日期,则执行
66
+ sql = (f"SELECT {columns_in} FROM `{db_name}`.`{table_name}` "
67
+ f"WHERE {'日期'} BETWEEN '{start_date}' AND '{end_date}'")
68
+ else: # 数据表没有日期列时,返回指定列的所有数据
69
+ sql = f"SELECT {columns_in} FROM `{db_name}`.`{table_name}`"
70
+ else: # 没有指定获取列时
71
+ if '日期' in cols_exist: # 但数据表有日期,仍然执行
72
+ cols_exist = [f"`{item}`" for item in cols_exist]
73
+ columns_in = ', '.join(cols_exist)
74
+ sql = (f"SELECT {columns_in} FROM `{db_name}`.`{table_name}` "
75
+ f"WHERE {'日期'} BETWEEN '{start_date}' AND '{end_date}'")
76
+ else: # 没有指定获取列,且数据表也没有日期列,则返回全部列的全部数据
77
+ all_col = ', '.join([f"`{item}`" for item in cols_exist if item != 'id'])
78
+ sql = f"SELECT %s FROM `%s`.`%s`" % (all_col, db_name, table_name)
79
+ cursor.execute(sql)
80
+ rows = cursor.fetchall() # 获取查询结果
81
+ columns = [desc[0] for desc in cursor.description]
82
+ df = pd.DataFrame(rows, columns=columns) # 转为 df
83
+ # except Exception as e:
84
+ # print(f'{e}')
82
85
  return df
83
- finally:
86
+ # finally:
84
87
  connection.close()
85
88
 
86
89
  if len(df) == 0:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mdbq
3
- Version: 1.5.6
3
+ Version: 1.5.8
4
4
  Home-page: https://pypi.org/project/mdbsql
5
5
  Author: xigua,
6
6
  Author-email: 2587125111@qq.com
@@ -5,7 +5,7 @@ mdbq/aggregation/aggregation.py,sha256=gvfaRx-LnzUKlp_kynSsvAnFGEccMKRxS5zPT6URe
5
5
  mdbq/aggregation/df_types.py,sha256=oQJS2IBU3_IO6GMgbssHuC2yCjNnbta0QPGrFOwNLnU,7591
6
6
  mdbq/aggregation/mysql_types.py,sha256=DQYROALDiwjJzjhaJfIIdnsrNs11i5BORlj_v6bp67Y,11062
7
7
  mdbq/aggregation/optimize_data.py,sha256=u2Kl_MFtZueXJ57ycy4H2OhXD431RctUYJYCl637uT0,4176
8
- mdbq/aggregation/query_data.py,sha256=9osiGFJkvmHPB8DAfmII7EJLwmyYUPwKjKhKYvLnfjU,35495
8
+ mdbq/aggregation/query_data.py,sha256=niMR9WytRmMzF0rMkQKbt7doLX5ELO5aHSiiZXku8Zs,48288
9
9
  mdbq/bdup/__init__.py,sha256=AkhsGk81SkG1c8FqDH5tRq-8MZmFobVbN60DTyukYTY,28
10
10
  mdbq/bdup/bdup.py,sha256=LAV0TgnQpc-LB-YuJthxb0U42_VkPidzQzAagan46lU,4234
11
11
  mdbq/clean/__init__.py,sha256=A1d6x3L27j4NtLgiFV5TANwEkLuaDfPHDQNrPBbNWtU,41
@@ -24,8 +24,8 @@ mdbq/log/mylogger.py,sha256=oaT7Bp-Hb9jZt52seP3ISUuxVcI19s4UiqTeouScBO0,3258
24
24
  mdbq/mongo/__init__.py,sha256=SILt7xMtQIQl_m-ik9WLtJSXIVf424iYgCfE_tnQFbw,13
25
25
  mdbq/mongo/mongo.py,sha256=v9qvrp6p1ZRWuPpbSilqveiE0FEcZF7U5xUPI0RN4xs,31880
26
26
  mdbq/mysql/__init__.py,sha256=A_DPJyAoEvTSFojiI2e94zP0FKtCkkwKP1kYUCSyQzo,11
27
- mdbq/mysql/mysql.py,sha256=o2QRV3JZ_jva8u3ScFiMGcgnInSGFYfADm1-nEKMr4M,43051
28
- mdbq/mysql/s_query.py,sha256=a33aYhW6gAnspIZfQ7l23ePln9-MD1f_ukypr5M0jd8,8018
27
+ mdbq/mysql/mysql.py,sha256=6hILGosp2fwTp9qgc9IMFTmNzAz0ZG8rznmPxXHY-eA,43331
28
+ mdbq/mysql/s_query.py,sha256=WD_pwgUA9pSQMvNKUxQoHKQf2LgkV8PyQV9Te3AJYs4,8175
29
29
  mdbq/mysql/year_month_day.py,sha256=VgewoE2pJxK7ErjfviL_SMTN77ki8GVbTUcao3vFUCE,1523
30
30
  mdbq/other/__init__.py,sha256=jso1oHcy6cJEfa7udS_9uO5X6kZLoPBF8l3wCYmr5dM,18
31
31
  mdbq/other/porxy.py,sha256=UHfgEyXugogvXgsG68a7QouUCKaohTKKkI4RN-kYSdQ,4961
@@ -35,7 +35,7 @@ mdbq/pbix/__init__.py,sha256=Trtfaynu9RjoTyLLYBN2xdRxTvm_zhCniUkVTAYwcjo,24
35
35
  mdbq/pbix/pbix_refresh.py,sha256=JUjKW3bNEyoMVfVfo77UhguvS5AWkixvVhDbw4_MHco,2396
36
36
  mdbq/pbix/refresh_all.py,sha256=tgy762608HMaXWynbOURIf2UVMuSPybzrDXQnOOcnZU,6102
37
37
  mdbq/spider/__init__.py,sha256=RBMFXGy_jd1HXZhngB2T2XTvJqki8P_Fr-pBcwijnew,18
38
- mdbq-1.5.6.dist-info/METADATA,sha256=CISMYo5CRiOFsR7h_GgYSRkLgZydZnoKAvLj078WmoA,245
39
- mdbq-1.5.6.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
40
- mdbq-1.5.6.dist-info/top_level.txt,sha256=2FQ-uLnCSB-OwFiWntzmwosW3X2Xqsg0ewh1axsaylA,5
41
- mdbq-1.5.6.dist-info/RECORD,,
38
+ mdbq-1.5.8.dist-info/METADATA,sha256=TeXzPAKzEOXDldORH96e6ROQ3flMXAwL_zyAi6Ld-bo,245
39
+ mdbq-1.5.8.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
40
+ mdbq-1.5.8.dist-info/top_level.txt,sha256=2FQ-uLnCSB-OwFiWntzmwosW3X2Xqsg0ewh1axsaylA,5
41
+ mdbq-1.5.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (70.1.0)
2
+ Generator: bdist_wheel (0.44.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5