python写入一年时间到系统交易日表,区分交易日非交易日,效果如下图

python根据字符串年月日时分秒获取年月日 python 获取年份_数据库

1.需要用到的临时表和目标表

1.1 创建临时表
-- Create table
create table TEMPDATA_AA
(
  c1  VARCHAR2(30),
  c2  VARCHAR2(30),
  c3  VARCHAR2(30),
  c4  VARCHAR2(30),
  c5  VARCHAR2(30),
  c6  VARCHAR2(30),
  c7  VARCHAR2(30),
  c8  VARCHAR2(30),
  c9  VARCHAR2(30),
  c10 VARCHAR2(30),
  n1  NUMBER(9),
  n2  NUMBER(9),
  n3  NUMBER(9),
  n4  NUMBER(9),
  n5  NUMBER(9),
  n6  NUMBER(9),
  n7  NUMBER(9),
  n8  NUMBER(9),
  n9  NUMBER(9),
  n10 NUMBER(9)
)
tablespace USERS
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
1.2 创建目标表
-- Create table
create table T_XTJYR
(
  naturalday   NUMBER(8),
  tradeday     NUMBER(8),
  year         NUMBER(4),
  quarter      NUMBER(1),
  month        NUMBER(2),
  week         NUMBER(1),
  year_month   NUMBER(6),
  year_weeknum NUMBER(6),
  weeknum      NUMBER(2),
  is_workday   NUMBER(1)
)
tablespace USERS
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
-- Create/Recreate primary, unique and foreign key constraints 
alter table T_XTJYR
  add unique (NATURALDAY)
  using index 
  tablespace USERS
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );

2.准备和插入数据

# oracle 数据库测试连接
import cx_Oracle
import pandas as pd
con = cx_Oracle.connect('scott/123@localhost:1521/orcl',encoding='utf-8')
sql = ''' SELECT * FROM tempdata_aa a '''
cur = con.cursor()
cur.execute(sql)
df = pd.read_sql(sql,con)  # 只能读不能写数据
print(df)
# 多维列表转换成一维列表,后面提取每年的数据时会用到
from calendar import Calendar
def array_to_list(array):
    if not isinstance(array, (list, )):
        return [array]
    else:
        list_y = []
        for item in array:
            list_y += array_to_list(item)
    # 转换去重 
    return list(set(list_y))

if __name__ == '__main__':
#     a = [[[1,2],3],[4,[5,6]],[6,8,9]]
#     print(array_to_list(a))
    b =  Calendar(firstweekday=0).yeardatescalendar(2021,12)
    c = array_to_list(b)
    print(c,len(c))
#     d = list(map(lambda n: int(n.strftime('%Y%m%d')),c))
#     print(d)
# 获取某年的节假日列表,编写判断否是节假日函数
import requests
import json


# 从百度的php接口中获取到数据
def catch_url_from_baidu(calcultaion_year, month):
    headers = {
        "Content-Type": "application/json;charset=UTF-8"
    }
    param = {
        "query": calcultaion_year + "年" + month + "月",
        "resource_id": "39043",
        "t": "1604395059555",
        "ie": "utf8",
        "oe": "gbk",
        "format": "json",
        "tn": "wisetpl",
        "cb": ""
    }
    # 抓取位置:百度搜索框搜索日历,上面的日历的接口,可以在页面上进行核对
    r = requests.get(url="https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php",
                     headers=headers, params=param).text
    month_data = json.loads(r)["data"][0]["almanac"]
    not_work_day = []
    for one in month_data:
        # 先转换成int类型的
        date_str=one["year"] + "-" + one["month"] + "-" + one["day"]
        c = int(dt.strptime(date_str,'%Y-%m-%d').strftime('%Y%m%d'))
        # 开始判断节假日类型
        if (one["cnDay"] == '日' or one["cnDay"] == '六'):
            if ('status' in one):
                if (one["status"] == "2"):
                    # status为2的时候表示周末的工作日,比如10月10日。即百度工具左上角显示“班”的日期
                    continue
                else:
                    # 普通周末时间
                    not_work_day.append(c)
                    continue
            else:
                # 普通周末时间。(接口中,如果左上角没有特殊表示,则不会返回status)
                not_work_day.append(c)
                continue
        if ('status' in one and one["status"] == "1"):
            # status为1的时候表示休息日,比如10月1日。即百度工具左上角显示“休”的日期
            not_work_day.append(c)
    return not_work_day


# 输出格式,可以修改成insert语句进行输出
def print_info(calcultaion_year):
    # 此处只能算当年之前的,因为国务院是每年12月份才会发布第二年的放假计划,所以此接口对于下一年的统计是错的。
    # eg:2020年11月4日,国务院没有发布21年的放假计划,那查询2021年元旦的时候,元旦那天不显示休息
    calculation_month = ["2", "5", "8", "11"]
    # 因该接口传入的时间,查询了前一个月,当前月和后一个月的数据,所以只需要2、5、8、11即可全部获取到。比如查询5月份,则会查询4,5,6月分的数据
    list_not_workday=[]
    for one_month in calculation_month:
        a = catch_url_from_baidu(calcultaion_year, one_month)
        list_not_workday.append(a)
    list_not_workday = array_to_list(list_not_workday)
    return list_not_workday

# 判断是否是交易日函数
def is_workday(num1):
    if num1 in list_not_workday:
        return 0
    else:
        return 1

if __name__ == '__main__':
    calcultaion_year = "2020"
    print_info(calcultaion_year)
    print(list_not_workday)
    print(len(list_not_workday))
# 数据写入临时表
from calendar import Calendar
def insert_date(year):
    """ 先写入一年的自然日到临时表 tempdata_aa 中 """
    date_array = Calendar(firstweekday=0).yeardatescalendar(year,12)
    date_list = array_to_list(date_array)
    con = cx_Oracle.connect('scott/123@localhost:1521/orcl',encoding='utf-8')
#     sql = ''' DELETE FROM tempdata_aa WHERE 1=1 '''
#     con.cursor().execute(sql)
#     con.commit()
    j = 0
    for i in date_list:
        if int(i.year) == year: # 过滤掉年头和年尾的非本年日期
            i = int(i.strftime('%Y%m%d'))
            # 是交易日,即为i,
            # 是节假日,执行小于自然日且为交易日的最大日期
            is_work = is_workday(i) # 0是节假日,1是交易日
            try:
                sql =f'''INSERT INTO  tempdata_aa(n1,n2)  VALUES({i},{is_work})'''
                con.cursor().execute(sql)
                con.commit()
                j += 1
                print('第{}次插入数据成功'.format(j))
            except Exception as e:
                print('第{}次数据插入失败:{}'.format(j, e))
                continue 
    # 关闭连接
    if 'con' in dir():
        con.close()

if __name__ == '__main__':
    year = 2021
    insert_date(year)                

# 数据准备完成,开始向目标表中插入数据
# 如果该年的数据已经插入,则删除该数据或跳出程序
try:
    con = cx_Oracle.connect('scott/123@localhost:1521/orcl',encoding='utf-8')
    sql =f''' INSERT INTO t_xtjyr
                      (naturalday,
                       tradeday,
                       YEAR,
                       quarter,
                       MONTH,
                       week,
                       year_month,
                       year_weeknum,
                       weeknum)
                      SELECT to_char(n1, 'yyyymmdd') AS naturalday,
                             tradeday,
                             to_char(n1, 'yyyy') AS YEAR,
                             to_char(n1, 'q') AS quarter,
                             to_char(n1, 'mm') AS MONTH,
                             to_char(n1, 'd') - 1 AS week, --0 为周末
                             to_char(n1, 'yyyymm') AS year_month,
                             to_char(n1, 'yyyyww') AS year_weeknum,
                             to_char(n1, 'ww') AS weeknum
                        FROM (SELECT to_date(a2.n1, 'yyyymmdd') AS n1,
                                     MAX(a1.n1) AS tradeday,
                                     a2.n2
                                FROM tempdata_aa a2
                                LEFT JOIN tempdata_aa a1
                                  ON a1.n1 <= a2.n1
                                 AND a1.n2 = 1
                               GROUP BY a2.n1, a2.n2
                               ORDER BY a2.n1)
--注意该方法在年初的几天假里,获取去去年的交易日,如果去年没有数据就会出现null值 '''
    con.cursor().execute(sql)
    con.commit()
    
except Exception as e:
    print('数据插入失败:{}'.format(e))
finally:
    if 'con' in dir():
        con.close()    


# 目标表主数据完成,开始写接口 有时间写吧



注意:
1.如果是第一次时开始使用节假日,一定要先把 list_not_workday列表先插入所有的数据,然后再检查临时表 tempdata_aa
2.表t_test 提供了2000年——2021的数据,也可以直接使用,当然后续每年12月份更新次年的数据就要使用上面的逻辑