Python3.因为不熟练SQL所以用pandas将表的一列按条件拆成若干列

Python3.因为不熟练SQL所以用pandas将表的一列按条件拆成若干列

想在数据库中完成某个整理操作但是没弄出来,干脆导出来整理完再塞回去(可是我还是很想知道用SQL怎么实现啊)。需求是这样的:

station_name date_ data_code data_
哥谭 2003/1/1 T_Day_Mean 49
哥谭 2003/1/1 T_Day_Mean_24 49
哥谭 2003/1/1 T_Day_Max 110
哥谭 2003/1/1 T_Day_Min 7
哥谭 2003/1/1 T_Day_Differ 103
哥谭 2003/1/1 T_Day_Max_HourMinute 32766
哥谭 2003/1/1 T_Day_Min_HourMinute 32766
赛博坦 2003/1/1 T_Day_Mean 50
赛博坦 2003/1/1 T_Day_Mean_24 50
赛博坦 2003/1/1 T_Day_Max 104
赛博坦 2003/1/1 T_Day_Min 11
赛博坦 2003/1/1 T_Day_Differ 93
赛博坦 2003/1/1 T_Day_Max_HourMinute 32766
赛博坦 2003/1/1 T_Day_Min_HourMinute 32766
阿斯加德 2003/1/1 T_Day_Mean 53
阿斯加德 2003/1/1 T_Day_Mean_24 53
阿斯加德 2003/1/1 T_Day_Max 108
阿斯加德 2003/1/1 T_Day_Min 3
阿斯加德 2003/1/1 T_Day_Differ 105
阿斯加德 2003/1/1 T_Day_Max_HourMinute 32766
阿斯加德 2003/1/1 T_Day_Min_HourMinute 32766

要把上表[dbo].[TEM_temp]的data_列按照data_code列分成若干列到新表[dbo].[TEM],即变成每天每个站点只有一条记录,每条记录里除了站点名称、日期外有T_Day_Mean等7个温度指标,如下:

station_name date_ T_Day_Mean T_Day_Mean_24 T_Day_Max T_Day_Min T_Day_Differ T_Day_Max_HourMinute T_Day_Min_HourMinute
哥谭 2003/1/1 49 49 110 7 103 32766 32766
赛博坦 2003/1/1 50 50 104 11 93 32766 32766
阿斯加德 2003/1/1 53 53 108 3 105 32766 32766

Python3代码如下

import pandas as pd
from sqlalchemy import create_engine

# 构造连接数据库的engine
userstr = 'UID:password@host/dbname'
linkstr = f'mssql+pyodbc://{userstr}?driver=SQL+Server'
con = create_engine(linkstr, encoding='utf-8')
# 数据全部读出来
sql = 'SELECT * FROM [dbo].[TEM_temp];'
old_frame = pd.read_sql(sql, con)
# 开始整理
# 按照data_code列拆出索要获得的某一字段
new_frame = old_frame[old_frame['data_code'] == 'T_Day_Mean'].copy()
del(new_frame['data_code'])  # 删掉data_code列
# 改列名
new_frame.rename(columns={
   
   'data_': 'T_Day_Mean', 
                          'history_record':'tem_history_record'}, inplace=True)
# 同理处理剩下的字段,并按照station_name和date_列merge到新表
fields = ['T_Day_Min', 'T_Day_Max', 'T_Day_Differ', 'T_Day_Min_HourMinute', 
          'T_Day_Max_HourMinute', 'T_Day_Mean_24']
for field in fields:
    temp = old_frame[old_frame['data_code'] == field].copy()
    temp.drop(columns=['data_code', 'history_record'], inplace=True)
    temp.rename(columns={
   
   'data_': field}, inplace=True)
    new_frame = new_frame.merge(temp, on=['station_id', 'station_name', 'date_'])  # merge到新表
# 整理下列的顺序
order = ['station_name',
         'date_',
         'T_Day_Mean',
         'T_Day_Min',
         'T_Day_Max',
         'T_Day_Differ',
         'T_Day_Min_HourMinute',
         'T_Day_Max_HourMinute',
         'T_Day_Mean_24',
         'history_record']
new_frame = new_frame[order]
# 塞回数据库
new_frame.to_sql('TEM', con, if_exists='replace', index=False)

然而我一开始用SQL整理时花了40多分钟,tempdb把剩余50G硬盘空间都用光最终还是失败了,报错“The transaction log for database ‘tempdb’ is full due to ‘ACTIVE_TRANSACTION’”。我的SQL脚本是这样的:

SELECT
    t1.station_name,
    t1.date_,
    t1.data_ AS T_Day_Mean,
    t2.data_ AS T_Day_Min,
    t3.data_ AS T_Day_Max,
    t4.data_ AS T_Day_Differ,
    t5.data_ AS T_Day_Min_HourMinute,
    t6.data_ AS T_Day_Max_HourMinute,
    t7.data_ AS T_Day_Mean_24,
    t1.tem_history_record
INTO
    [dbo].[TEM]
FROM
    [dbo].[TEM_temp] AS t1,
    [dbo].[TEM_temp] AS t2,
    [dbo].[TEM_temp] AS t3,
    [dbo].[TEM_temp] AS t4,
    [dbo].[TEM_temp] AS t5,
    [dbo].[TEM_temp] AS t6,
    [dbo].[TEM_temp] AS t7
WHERE
    t1.date_ = t2.date_
    AND t1.date_ = t3.date_
    AND t1.date_ = t4.date_
    AND t1.date_ = t5.date_
    AND t1.date_ = t6.date_
    AND t1.date_ = t7.date_
    AND t1.data_code = 'T_Day_Mean'
    AND t2.data_code = 'T_Day_Min'
    AND t3.data_code = 'T_Day_Max'
    AND t4.data_code = 'T_Day_Differ'
    AND t5.data_code = 'T_Day_Min_HourMinute'
    AND t6.data_code = 'T_Day_Max_HourMinute'
    AND t7.data_code = 'T_Day_Mean_24'
ORDER BY 3, 1;

好吧,就在写这篇傻文的时候,我发现我的SQL脚本里WHERE中忘记写

    t1.station_name = t2.station_name
    AND t1.station_name = t3.station_name
    AND t1.station_name = t4.station_name
    AND t1.station_name = t5.station_name
    AND t1.station_name = t6.station_name
    AND t1.station_name = t7.station_name
    AND 

忘记限制站点相同了,难怪之前费时费硬盘又失败。。。刚刚加上试了一下,只要14秒就跑出了正确的结果。。。我是个傻子。。。

不过仔细看一下发现了一点区别,[dbo].[TEM]中的data_是decimal(18,3)型数据,pandas读出来再写进去就变成了float型数据,而用SQL的话数据格式就没变,所以感觉还是SQL比较靠谱。

Anyway,我用两种方法都实现了我的这个简单需求。However,这两种方法感觉都比较复杂,尤其是SQL,我通过内联结给同一张表起了7个名字太傻了,应该有更简单的方式或者有更方便的SQL语句但是我不知道,究竟是时间会告诉我答案,还是大神会告诉我答案?

猜你喜欢

转载自blog.csdn.net/modabao/article/details/82502589