数据仓库-日期维度表的设计与实现

时间维度表的制作

1 需求背景

在大数据分析模块中,我们需要从不同的维度分析主题表,包括常用的公用维度:时间维,地区维度,教育信息维…以及各种各样的业务维度:员工维度,部门维度…,业务维度就是我们从哪些角度去分析业务过程,本文就是做一张常用时间维度表。

时间维表由于是可预见的,因此可以一次性导入未来几十年的,当然对于一些节假日的设置可能只能获取未来一年的,因此可以每年全量更新一次。

2 维表设计

给出时间维度表的建表语句

CREATE DATABASE dim_db DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;

drop table dim_db.dim_date;
create table if not exists dim_db.dim_date
(
    udate      varchar(20) comment '日期',
    uyear      varchar(20) comment '年',
    uquarter   varchar(20) comment '季度',
    useason    varchar(20) comment '季节',
    umonth     varchar(20) comment '月',
    uday       varchar(20) comment '日',
    uweek      varchar(20) comment '第几周',
    uweekday   varchar(20) comment '周几:1-周一、2-周二、3-周三、4-周四、5-周五、6-周六、7-周日',
    is_workday varchar(20) comment '是否是工作日:1,0',
    udatetype  varchar(20) comment '节假日类型:工作日,法定上班[还班],周末,节假日',
    updatedate varchar(20) comment '数据更新日期'
);

这里额外解释三个字段

uquarter: 季度,按照阳历的日期分的,[1,2,3]第一季度,[4,5,6]为第二季度,[7,8,9]为第三季度,[10,11,12]为第四季度。

useason:季节,季节的划分有三种方式,本采用的是节气划分法。

  • 天文划分法,以春分、夏至、秋分、冬至为四季的开始;

  • 气象划分法,以3月至5月为春季,6月至8月为夏季,9月至11月为秋季,12月至2月为冬季;

  • 节气划分法,以立春、立夏、立秋、立冬为四季之始。

udatetype:法定上班指的是因为放假调休周末也要上班的日期,节假日会直接显示日期名称,实现的逻辑大家可以自行更改。

3 实现方式

3.1 安装库

本文实现的方式是基于python的chinese_calendar库和pymysql库将数据导入到mysql,接着生成csv文件导入导hive数据库里面。

  • MySQL:5.6.36 本地部署
  • chinese_calendar:1.8.0 这是一个基于阿里云开发的中国日历库,每年会更新
  • pymysql:1.0.2 连接mysql用的
  • python版本:3.7
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple chinesecalendar
pip install pymysql

3.2 实现代码

import chinese_calendar
import pymysql.cursors
import datetime
import pytz


def main():
    # (1)设置生成表中数据的开始和截至日期
    start_date = datetime.date(2010, 1, 1)
    end_date = datetime.date(2023, 12, 31)

    # (2)获取该时间段内所有的日期
    dates = chinese_calendar.get_dates(start_date, end_date)

    # (3)遍历日期,构造sql字符串
    strsql = '''INSERT INTO `dim_date`(`udate`,`uyear`,`uquarter`,`useason`,`umonth`,`uday`,`uweek`,`uweekday`,`is_workday`,`udateType`,`updatedate`)VALUES'''
    is_first_line = True

    # (4)设置生成节气的起始时间和截至日期
    # 因为需要 立春,立夏,立秋,立冬四个字段的名称,所以 [数据项的开始日期和截至日期区间]  应在 [节气的起始时间和截至日期的区间]内
    solar_term_start_date = datetime.date(2009, 11, 7)
    solar_term_end_date = datetime.date(2030, 12, 31)

    season_start_date_list = get_season_start_date_list(solar_term_start_date, solar_term_end_date)

    # get_current_season_index
    index = get_current_season_index(season_start_date_list, start_date)

    # (5)遍历日期集合构造sql
    for date in dates:
        # [1]udate: 日期
        udate = date.__str__()

        # [2]uyear: 年份
        uyear = str(date.year)

        # [3]umonth: 月份
        umonth = str(date.month)

        # [4]uquarter: 季度
        uquarter = get_quarter(date.month)

        # [5]useason: 季节
        useason = ''
        if season_start_date_list[index][0] <= date < season_start_date_list[index + 1][0]:
            useason = season_start_date_list[index][1]
        elif date >= season_start_date_list[index + 1][0]:
            index += 1
            useason = season_start_date_list[index][1]

        # [6]uday: 日
        uday = str(date.day)

        # [7]uweek: 第几周
        # 构造一个指定日期时间,时区[必选]的datetime 对象
        timezone = pytz.timezone('Asia/Shanghai')
        dt = datetime.datetime(date.year, date.month, date.day, tzinfo=timezone)
        uweek = str(int(dt.strftime("%U")) + 1)

        # [7]uweekday: 周几
        uweekday = str(date.isoweekday())
        # is_holiday, holidays = chinese_calendar.get_holiday_detail(date)
        is_workday = '1' if chinese_calendar.is_workday(date) else '0'

        # [9]udatetype: 日期类型
        udatetype = ''
        if is_workday == '1':
            if date.isoweekday() in [6, 7]:
                # udatetype = '法定上班'
                is_holiday, holidays = chinese_calendar.get_holiday_detail(date)
                udatetype = '法定上班-' + get_chinese_name(holidays)
            else:
                udatetype = '工作日'
        else:
            is_holiday, holidays = chinese_calendar.get_holiday_detail(date)
            if holidays is None:
                udatetype = '周末'
            else:
                udatetype = get_chinese_name(str(holidays))

        # [10]updatedate: 更新时间,默认是当天
        updatedate = datetime.date.today().__str__()
        # updatedate = datetime.date(2023, 5, 12).__str__() 手动指定更新日期

        # 判断是否首行
        if is_first_line:
            is_first_line = False
        else:
            strsql += ','

        # 构建单行数据库文本记录
        linerecord = '(\'' + udate + '\',\'' \
                     + uyear + '\',\'' \
                     + uquarter + '\',\'' \
                     + useason + '\',\'' \
                     + umonth + '\',\'' \
                     + uday + '\',\'' \
                     + uweek + '\',\'' \
                     + uweekday + '\',\'' \
                     + is_workday + '\',\'' \
                     + udatetype + '\',\'' \
                     + updatedate + '\')'

        print(linerecord)

        # 连接sql
        strsql += linerecord

    strsql += ';'

    # (4)将生成的数据插入到数据库
    # 连接配置信息
    config = {
        'host': '127.0.0.1',
        'port': 3306,
        'user': 'root',
        'password': '你的数据库密码',
        'db': 'dim_dib',
        'charset': 'utf8',
        'cursorclass': pymysql.cursors.DictCursor,

    }

    # 创建连接
    connection = pymysql.connect(**config)

    # 使用cursor创建游标对象
    cursor = connection.cursor()

    # 执行sql语句
    cursor.execute(strsql)
    connection.commit()

    # 关闭连接
    cursor.close()
    connection.close()



def get_quarter(month):
    '''
    获取月份对应的季度

    :param month: 月份
    :return: 季度
    '''
    if month in [1, 2, 3]:
        return '1'
    elif month in [4, 5, 6]:
        return '2'
    elif month in [7, 8, 9]:
        return '3'
    elif month in [10, 11, 12]:
        return '4'
    else:
        return None


def get_chinese_name(english_name):
    '''
    将英文节日名称映射成中文名称

    :param english_name: str
    :return: str
    '''
    if english_name == "New Year's Day":
        return "元旦"
    elif english_name == "Spring Festival":
        return "春节"
    elif english_name == "Tomb-sweeping Day":
        return "清明"
    elif english_name == "Dragon Boat Festival":
        return "端午"
    elif english_name == "Labour Day":
        return "劳动节"
    elif english_name == "National Day":
        return "国庆节"
    elif english_name == "Mid-autumn Festival":
        return "中秋"
    else:
        return "无效节日"


def get_season_start_date_list(start_date, end_date):
    '''
    返回[每个季节开始的日期和名称]的集合
    目前可求的范围是:[1900, 2100]

    :param start_date: 起始时间
    :param end_date: 结束时间
    :return: list,元素内容:(date,'春季'),或者(date,'夏季'),(date,'秋季'),(date,'冬季')
    '''
    solar_terms = chinese_calendar.get_solar_terms(start_date, end_date)

    date_season_list = []
    for term in solar_terms:
        term_name = term[1]
        udate = term[0]
        if term_name == '立春':
            date_season_list.append((udate, '春季'))
        elif term_name == '立夏':
            date_season_list.append((udate, '夏季'))
        elif term_name == '立秋':
            date_season_list.append((udate, '秋季'))
        elif term_name == '立冬':
            date_season_list.append((udate, '冬季'))

    return date_season_list


def get_current_season_index(season_start_date_list, start_date):
    '''
    获取起始时间对应季节的起始时间

    :param season_start_date_list: 每个季节起始时间的日期集合以及相应的季节名称
    :param start_date: 起始时间
    :return: 起始时间对应季节的起始时间 | 集合的下标
    '''
    for index in range(0,12000):
        if start_date >= season_start_date_list[index][0]:
            return index


if __name__ == '__main__':
    main()

3.3 生成数据和更新

使用程序的时候只需要设置程序最开始的start_date和end_date,更新数据同理,不过后续更新数据的时候应该选择更高版本的chinese_calendar库。

4 生成数据预览

这里贴出来了2010年一整年的数据,datagrip导出来的,已经核对过数据是没有问题的,大家可以在http://www.gov.cn/zwgk/2009-12/08/content_1482691.htm国务院办公厅发布的节假日安排核对假日信息,手机日历上的节假日信息个别有偏差。

udateuyearuquarteruseasonumonthudayuweekuweekdayis_workdayudatetypeupdatedate
2010-01-0120101冬季11150元旦2023-05-12
2010-01-0220101冬季12160元旦2023-05-12
2010-01-0320101冬季13270元旦2023-05-12
2010-01-0420101冬季14211工作日2023-05-12
2010-01-0520101冬季15221工作日2023-05-12
2010-01-0620101冬季16231工作日2023-05-12
2010-01-0720101冬季17241工作日2023-05-12
2010-01-0820101冬季18251工作日2023-05-12
2010-01-0920101冬季19260周末2023-05-12
2010-01-1020101冬季110370周末2023-05-12
2010-01-1120101冬季111311工作日2023-05-12
2010-01-1220101冬季112321工作日2023-05-12
2010-01-1320101冬季113331工作日2023-05-12
2010-01-1420101冬季114341工作日2023-05-12
2010-01-1520101冬季115351工作日2023-05-12
2010-01-1620101冬季116360周末2023-05-12
2010-01-1720101冬季117470周末2023-05-12
2010-01-1820101冬季118411工作日2023-05-12
2010-01-1920101冬季119421工作日2023-05-12
2010-01-2020101冬季120431工作日2023-05-12
2010-01-2120101冬季121441工作日2023-05-12
2010-01-2220101冬季122451工作日2023-05-12
2010-01-2320101冬季123460周末2023-05-12
2010-01-2420101冬季124570周末2023-05-12
2010-01-2520101冬季125511工作日2023-05-12
2010-01-2620101冬季126521工作日2023-05-12
2010-01-2720101冬季127531工作日2023-05-12
2010-01-2820101冬季128541工作日2023-05-12
2010-01-2920101冬季129551工作日2023-05-12
2010-01-3020101冬季130560周末2023-05-12
2010-01-3120101冬季131670周末2023-05-12
2010-02-0120101冬季21611工作日2023-05-12
2010-02-0220101冬季22621工作日2023-05-12
2010-02-0320101冬季23631工作日2023-05-12
2010-02-0420101春季24641工作日2023-05-12
2010-02-0520101春季25651工作日2023-05-12
2010-02-0620101春季26660周末2023-05-12
2010-02-0720101春季27770周末2023-05-12
2010-02-0820101春季28711工作日2023-05-12
2010-02-0920101春季29721工作日2023-05-12
2010-02-1020101春季210731工作日2023-05-12
2010-02-1120101春季211741工作日2023-05-12
2010-02-1220101春季212751工作日2023-05-12
2010-02-1320101春季213760春节2023-05-12
2010-02-1420101春季214870春节2023-05-12
2010-02-1520101春季215810春节2023-05-12
2010-02-1620101春季216820春节2023-05-12
2010-02-1720101春季217830春节2023-05-12
2010-02-1820101春季218840春节2023-05-12
2010-02-1920101春季219850春节2023-05-12
2010-02-2020101春季220861法定上班2023-05-12
2010-02-2120101春季221971法定上班2023-05-12
2010-02-2220101春季222911工作日2023-05-12
2010-02-2320101春季223921工作日2023-05-12
2010-02-2420101春季224931工作日2023-05-12
2010-02-2520101春季225941工作日2023-05-12
2010-02-2620101春季226951工作日2023-05-12
2010-02-2720101春季227960周末2023-05-12
2010-02-2820101春季2281070周末2023-05-12
2010-03-0120101春季311011工作日2023-05-12
2010-03-0220101春季321021工作日2023-05-12
2010-03-0320101春季331031工作日2023-05-12
2010-03-0420101春季341041工作日2023-05-12
2010-03-0520101春季351051工作日2023-05-12
2010-03-0620101春季361060周末2023-05-12
2010-03-0720101春季371170周末2023-05-12
2010-03-0820101春季381111工作日2023-05-12
2010-03-0920101春季391121工作日2023-05-12
2010-03-1020101春季3101131工作日2023-05-12
2010-03-1120101春季3111141工作日2023-05-12
2010-03-1220101春季3121151工作日2023-05-12
2010-03-1320101春季3131160周末2023-05-12
2010-03-1420101春季3141270周末2023-05-12
2010-03-1520101春季3151211工作日2023-05-12
2010-03-1620101春季3161221工作日2023-05-12
2010-03-1720101春季3171231工作日2023-05-12
2010-03-1820101春季3181241工作日2023-05-12
2010-03-1920101春季3191251工作日2023-05-12
2010-03-2020101春季3201260周末2023-05-12
2010-03-2120101春季3211370周末2023-05-12
2010-03-2220101春季3221311工作日2023-05-12
2010-03-2320101春季3231321工作日2023-05-12
2010-03-2420101春季3241331工作日2023-05-12
2010-03-2520101春季3251341工作日2023-05-12
2010-03-2620101春季3261351工作日2023-05-12
2010-03-2720101春季3271360周末2023-05-12
2010-03-2820101春季3281470周末2023-05-12
2010-03-2920101春季3291411工作日2023-05-12
2010-03-3020101春季3301421工作日2023-05-12
2010-03-3120101春季3311431工作日2023-05-12
2010-04-0120102春季411441工作日2023-05-12
2010-04-0220102春季421451工作日2023-05-12
2010-04-0320102春季431460清明2023-05-12
2010-04-0420102春季441570清明2023-05-12
2010-04-0520102春季451510清明2023-05-12
2010-04-0620102春季461521工作日2023-05-12
2010-04-0720102春季471531工作日2023-05-12
2010-04-0820102春季481541工作日2023-05-12
2010-04-0920102春季491551工作日2023-05-12
2010-04-1020102春季4101560周末2023-05-12
2010-04-1120102春季4111670周末2023-05-12
2010-04-1220102春季4121611工作日2023-05-12
2010-04-1320102春季4131621工作日2023-05-12
2010-04-1420102春季4141631工作日2023-05-12
2010-04-1520102春季4151641工作日2023-05-12
2010-04-1620102春季4161651工作日2023-05-12
2010-04-1720102春季4171660周末2023-05-12
2010-04-1820102春季4181770周末2023-05-12
2010-04-1920102春季4191711工作日2023-05-12
2010-04-2020102春季4201721工作日2023-05-12
2010-04-2120102春季4211731工作日2023-05-12
2010-04-2220102春季4221741工作日2023-05-12
2010-04-2320102春季4231751工作日2023-05-12
2010-04-2420102春季4241760周末2023-05-12
2010-04-2520102春季4251870周末2023-05-12
2010-04-2620102春季4261811工作日2023-05-12
2010-04-2720102春季4271821工作日2023-05-12
2010-04-2820102春季4281831工作日2023-05-12
2010-04-2920102春季4291841工作日2023-05-12
2010-04-3020102春季4301851工作日2023-05-12
2010-05-0120102春季511860劳动节2023-05-12
2010-05-0220102春季521970劳动节2023-05-12
2010-05-0320102春季531910劳动节2023-05-12
2010-05-0420102春季541921工作日2023-05-12
2010-05-0520102夏季551931工作日2023-05-12
2010-05-0620102夏季561941工作日2023-05-12
2010-05-0720102夏季571951工作日2023-05-12
2010-05-0820102夏季581960周末2023-05-12
2010-05-0920102夏季592070周末2023-05-12
2010-05-1020102夏季5102011工作日2023-05-12
2010-05-1120102夏季5112021工作日2023-05-12
2010-05-1220102夏季5122031工作日2023-05-12
2010-05-1320102夏季5132041工作日2023-05-12
2010-05-1420102夏季5142051工作日2023-05-12
2010-05-1520102夏季5152060周末2023-05-12
2010-05-1620102夏季5162170周末2023-05-12
2010-05-1720102夏季5172111工作日2023-05-12
2010-05-1820102夏季5182121工作日2023-05-12
2010-05-1920102夏季5192131工作日2023-05-12
2010-05-2020102夏季5202141工作日2023-05-12
2010-05-2120102夏季5212151工作日2023-05-12
2010-05-2220102夏季5222160周末2023-05-12
2010-05-2320102夏季5232270周末2023-05-12
2010-05-2420102夏季5242211工作日2023-05-12
2010-05-2520102夏季5252221工作日2023-05-12
2010-05-2620102夏季5262231工作日2023-05-12
2010-05-2720102夏季5272241工作日2023-05-12
2010-05-2820102夏季5282251工作日2023-05-12
2010-05-2920102夏季5292260周末2023-05-12
2010-05-3020102夏季5302370周末2023-05-12
2010-05-3120102夏季5312311工作日2023-05-12
2010-06-0120102夏季612321工作日2023-05-12
2010-06-0220102夏季622331工作日2023-05-12
2010-06-0320102夏季632341工作日2023-05-12
2010-06-0420102夏季642351工作日2023-05-12
2010-06-0520102夏季652360周末2023-05-12
2010-06-0620102夏季662470周末2023-05-12
2010-06-0720102夏季672411工作日2023-05-12
2010-06-0820102夏季682421工作日2023-05-12
2010-06-0920102夏季692431工作日2023-05-12
2010-06-1020102夏季6102441工作日2023-05-12
2010-06-1120102夏季6112451工作日2023-05-12
2010-06-1220102夏季6122461法定上班2023-05-12
2010-06-1320102夏季6132571法定上班2023-05-12
2010-06-1420102夏季6142510端午2023-05-12
2010-06-1520102夏季6152520端午2023-05-12
2010-06-1620102夏季6162530端午2023-05-12
2010-06-1720102夏季6172541工作日2023-05-12
2010-06-1820102夏季6182551工作日2023-05-12
2010-06-1920102夏季6192560周末2023-05-12
2010-06-2020102夏季6202670周末2023-05-12
2010-06-2120102夏季6212611工作日2023-05-12
2010-06-2220102夏季6222621工作日2023-05-12
2010-06-2320102夏季6232631工作日2023-05-12
2010-06-2420102夏季6242641工作日2023-05-12
2010-06-2520102夏季6252651工作日2023-05-12
2010-06-2620102夏季6262660周末2023-05-12
2010-06-2720102夏季6272770周末2023-05-12
2010-06-2820102夏季6282711工作日2023-05-12
2010-06-2920102夏季6292721工作日2023-05-12
2010-06-3020102夏季6302731工作日2023-05-12
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
数据仓库中的宽表和汇总表是数据仓库中非常重要的两个表。下面我向您介绍一下它们的设计方法: 1. 宽表设计方法 宽表是指包含了多个数据源(表)中的所有数据的一张表。它能够提高数据查询的效率,避免了多表关联查询的过程,同时也能够方便数据分析师进行数据建模、分析和报表制作。宽表的设计方法如下: - 根据业务需求,选择需要加入宽表的数据源,包括数据源的字段、数据类型等。 - 将各个数据源的数据合并到一张表中,通过一些特定的字段进行关联,如日期、地点、产品等。 - 对宽表进行必要的数据清洗和转换,包括数据类型的转换、数据格式的规范化、空值处理等。 - 对宽表进行性能优化,包括数据压缩、数据分区、索引等操作,提高查询效率。 2. 汇总表设计方法 汇总表是指在数据仓库中,把细节数据按照一定的规则聚合起来的一张表,通常是根据不同的维度进行聚合。汇总表的设计方法如下: - 根据业务需求,确定需要聚合的指标和维度。 - 对每个维度,定义需要聚合的指标和聚合方式,如求和、平均数、最大值、最小值等。 - 对于聚合结果,根据业务需求,可以设计多个汇总表,包括日、周、月、季度、年等不同的时间粒度表。 - 对汇总表进行必要的数据清洗和转换,包括数据类型的转换、数据格式的规范化、空值处理等。 - 对汇总表进行性能优化,包括数据压缩、数据分区、索引等操作,提高查询效率。 总之,数据仓库中的宽表和汇总表设计方法,需要根据具体的业务需求和数据特征进行设计和优化,以提高数据仓库的数据查询效率和数据分析的准确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yongfeicao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值