使用sql语句计算周次及起始日期

本文介绍了一种使用SQL计算特定日期范围内的周次及其起始日期的方法。通过设定周一为每周第一天,并运用SQL语句计算指定日期的周次与周内天数,实现了周期性报表的自动生成。

       最近在做周报填报的功能,其中需要算一下周次及起始日期。本打算用程序代码算一下的,但是感觉用sql更有意思,所以搜了一些相关的知识以及前人写的相关的sql语句,在此基础上进行了完善。

       1、国际标准周日是每周的第一天,但是在咱们中国人还是习惯周一为每周的第一天,因此首先要把周一设置为每周的第一天

SET DATEFIRST 1

          2、计算你传过来时间段的开始日期是本年的第几周和周几(如果为周日则周次再加一)

DATEPART(dw, @tmpDate)
SELECT   DATEPART(WEEK, @tmpDate)

         3、完整sql(这里我传的时间段是2017-01-15至2017-01-31)

SET DATEFIRST 1
DECLARE @tmpDate DATETIME

DECLARE @index INT
DECLARE @table TABLE
    (
      WeekTimes INT ,
      FirstDay DATE ,
      EndDay DATE
    )
SET @tmpDate = '2017-1-15'
DECLARE @YearFistWK INT= DATEPART(dw, @tmpDate)
SET @index = ( SELECT   DATEPART(WEEK, @tmpDate)   
             )
IF ( @YearFistWK = 7 )
    BEGIN 
        SET @index = @index + 1
    END
WHILE @tmpDate <= '2017-1-31'
    BEGIN
        INSERT  INTO @table
                SELECT  @index ,
                        a.FirstDay ,
                        b.EndDay
                FROM    ( SELECT    1 AS ID ,
                                    DATEADD(wk, DATEDIFF(wk, 0, @tmpDate), 0) AS FirstDAy
                        ) a
                        LEFT JOIN ( SELECT  1 AS ID ,
                                            DATEADD(wk,
                                                    DATEDIFF(wk, 0, @tmpDate),
                                                    6) AS EndDay
                                  ) b ON a.ID = b.ID

        SET @tmpDate = DATEADD(DAY, 7, @tmpDate)

        SET @index = @index + 1

    END
SELECT  *
FROM    @table

          4、运行结果


-- dw3bqksoper select current.OperDate as OperDate, Max(current.KsMc) as KsMc, current.KsDm as KsDm, sum(current.AllOperSl) as AllOperSl, sum(last_year.OldAllOperSl) as OldAllOperSl, sum(current.OperZss) as OperZss, sum(last_year.OldOperZss) as OldOperZss, sum(current.JrOperZss) as JrOperZss, sum(last_year.OldJrOperZss) as OldJrOperZss, sum(current.ZdOperZss) as ZdOperZss, sum(last_year.OldZdOperZss) as OldZdOperZss, sum(current.ZlOperZss) as ZlOperZss, sum(last_year.OldZlOperZss) as OldZlOperZss, sum(current.ZzSl) as ZzSl, sum(last_year.OldZzSl) as OldZzSl, sum(current.YzSl) as YzSl, sum(last_year.OldYzSl) as OldYzSl, sum(current.WzSl) as WzSl, sum(last_year.OldWzSl) as OldWzSl, sum(current.JzSl) as JzSl, sum(last_year.OldJzSl) as OldJzSl, sum(current.SjSl) as SjSl, sum(last_year.OldSjSl) as OldSjSl, max(current.OperAddrDm) as OperAddrDm, max(current.OperAddrMc) as OperAddrMc, sum(current.WcOperSl) as WcOperSl, sum(last_year.OldWcOperSl) as OldWcOperSl, sum(current.SDRG1) as SDRG1, sum(last_year.OldSDRG1) as OldSDRG1, sum(current.SDRG2) as SDRG2, sum(last_year.OldSDRG2) as OldSDRG2, sum(current.SDRG3) as SDRG3, sum(last_year.OldSDRG3) as OldSDRG3, sum(current.SDRG4) as SDRG4, sum(last_year.OldSDRG4) as OldSDRG4, sum(current.ESDSl) as ESDSl, sum(last_year.OldESDSl) as OldESDSl from ( select date(a.OperDate) as OperDate, Max(f.KsMc) as KsMc, a.KsDm, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) then 1 else 0 end) as AllOperSl, 0 as OldAllOperSl, sum(case when e.OperSxID=1002189778 then 1 else 0 end) as OperZss, 0 as OldOperZss, sum(case when e.OperSxID=1002189861 then 1 else 0 end) as JrOperZss, 0 as OldJrOperZss, sum(case when e.OperSxID=1002189906 then 1 else 0 end) as ZdOperZss, 0 as OldZdOperZss, sum(case when e.OperSxID=1002189980 then 1 else 0 end) as ZlOperZss, 0 as OldZlOperZss, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and a.StatusCode>='DB10' and a.StatusCode<='DB45' then 1 else 0 end) as ZzSl, 0 as OldZzSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and a.StatusCode='DB50' then 1 else 0 end) as YzSl, 0 as OldYzSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and a.StatusCode>='DB05' and a.StatusCode<'DB10' then 1 else 0 end) as WzSl, 0 as OldWzSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and a.JzFlag='1' then 1 else 0 end) as JzSl, 0 as OldJzSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and (e.GKID=1002190291) then 1 else 0 end) as SjSl, 0 as OldSjSl, a.OperAddrDm, max(case when a.OperAddrDm='82' then 'DSA手术室' when a.OperAddrDm='84' then '内镜手术室' when a.OperAddrDm='BD' then '日间手术室' else '大手术室' end) as OperAddrMc, sum(case when (e.WcOperFlag='1') then 1 else 0 end) as WcOperSl, 0 as OldWcOperSl, sum(case when (e.SDRGID=1002190064) then 1 else 0 end) as SDRG1, 0 as OldSDRG1, sum(case when (e.SDRGID=1002190090) then 1 else 0 end) as SDRG2, 0 as OldSDRG2, sum(case when (e.SDRGID=1002190126) then 1 else 0 end) as SDRG3, 0 as OldSDRG3, sum(case when (e.SDRGID=1002190153) then 1 else 0 end) as SDRG4, 0 as OldSDRG4, sum(case when (e.OperSxID=1002189980) then 1 else 0 end) as ESDSl, 0 as OldESDSl from BqOperTzd a inner join bqopertzdmx b on a.UniqueID=b.BqOperTzdID inner join CwYlMl e on b.OperID=e.YlID left join BqOperDjk d on a.UniqueID=d.BqOperTzdID and d.DelFlag='0' inner join RsBqKsXx f on a.KsDm=f.KsDm where (date(a.OperDate) BETWEEN CURRENT_DATE - interval 30 day and CURRENT_DATE) and a.StatusCode>'DB00' and a.StatusCode<'DB99' and a.DelFlag='0' group by date(a.OperDate),a.OperAddrDm,a.KsDm) as current, (select date(a.OperDate) as OperDate, Max(f.KsMc) as KsMc, a.KsDm, 0 as AllOperSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) then 1 else 0 end) as OldAllOperSl, 0 as OperZss, sum(case when e.OperSxID=1002189778 then 1 else 0 end) as OldOperZss, 0 as JrOperZss, sum(case when e.OperSxID=1002189861 then 1 else 0 end) as OldJrOperZss, 0 as ZdOperZss, sum(case when e.OperSxID=1002189906 then 1 else 0 end) as OldZdOperZss, 0 as ZlOperZss, sum(case when e.OperSxID=1002189980 then 1 else 0 end) as OldZlOperZss, 0 as ZzSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and a.StatusCode>='DB10' and a.StatusCode<='DB45' then 1 else 0 end) as OldZzSl, 0 as YzSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and a.StatusCode='DB50' then 1 else 0 end) as OldYzSl, 0 as WzSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and a.StatusCode>='DB05' and a.StatusCode<'DB10' then 1 else 0 end) as OldWzSl, 0 as JzSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and a.JzFlag='1' then 1 else 0 end) as OldJzSl, 0 as SjSl, sum(case when (e.OperSxID=1002189778 or e.OperSxID=1002189861 or e.OperSxID=1002189906 or e.OperSxID=1002189980) and (e.GKID=1002190291) then 1 else 0 end) as OldSjSl, a.OperAddrDm, max(case when a.OperAddrDm='82' then 'DSA手术室' when a.OperAddrDm='84' then '内镜手术室' when a.OperAddrDm='BD' then '日间手术室' else '大手术室' end) as OperAddrMc, 0 as WcOperSl, sum(case when (e.WcOperFlag='1') then 1 else 0 end) as OldWcOperSl, 0 as SDRG1, sum(case when (e.SDRGID=1002190064) then 1 else 0 end) as OldSDRG1, 0 as SDRG2, sum(case when (e.SDRGID=1002190090) then 1 else 0 end) as OldSDRG2, 0 as SDRG3, sum(case when (e.SDRGID=1002190126) then 1 else 0 end) as OldSDRG3, 0 as SDRG4, sum(case when (e.SDRGID=1002190153) then 1 else 0 end) as OldSDRG4, 0 as ESDSl, sum(case when (e.OperSxID=1002189980) then 1 else 0 end) as OldESDSl from BqOperTzd a inner join bqopertzdmx b on a.UniqueID=b.BqOperTzdID inner join CwYlMl e on b.OperID=e.YlID left join BqOperDjk d on a.UniqueID=d.BqOperTzdID and d.DelFlag='0' inner join RsBqKsXx f on a.KsDm=f.KsDm where (date(a.OperDate) BETWEEN CURRENT_DATE - interval 30 day- INTERVAL 1 year and CURRENT_DATE - interval 1 year) and a.StatusCode>'DB00' and a.StatusCode<'DB99' and a.DelFlag='0' group by date(a.OperDate),a.OperAddrDm,a.KsDm) as last_year where DATE_FORMAT(current.OperDate,'%m-%d')=DATE_FORMAT(last_year.OperDate,'%m-%d') and current.OperAddrDm=last_year.OperAddrDm and current.KsDm=last_year.KsDm group by current.OperDate,current.OperAddrDm,current.KsDm order by current.OperDate -- dm1bqksoper select OperDate, KsMc, KsDm, AllOperSl, OldAllOperSl, OperZss, OldOperZss, JrOperZss, OldJrOperZss, ZdOperZss, OldZdOperZss, ZlOperZss, OldZlOperZss, ZzSl, OldZzSl, YzSl, OldYzSl, WzSl, OldWzSl, JzSl, OldJzSl, SjSl, OldSjSl, OperAddrDm, OperAddrMc, WcOperSl, OldWcOperSl, SDRG1, OldSDRG1, SDRG2, OldSDRG2, SDRG3, OldSDRG3, SDRG4, OldSDRG4, ESDSl, OldESDSl from dw3bqksoper where OperDate>=CURRENT_DATE - interval 30 day CREATE TABLE `dm1bqksoper_weekly_comparison2` ( id BIGINT AUTO_INCREMENT PRIMARY KEY, current_iso_week VARCHAR(10) NOT NULL COMMENT '当前 ISO 编号(如 2024-35)', last_year_iso_week VARCHAR(10) COMMENT '去年同期 ISO 编号(如 2023-35)', week_label varchar(50) DEFAULT NULL COMMENT '周次序列(如第32(2025-08-04 - 2025-08-10))', week_start DATE NOT NULL COMMENT '起始日期一)', week_end DATE NOT NULL COMMENT '结束日期日)', week_seq INT NOT NULL COMMENT '序号(从最近到最远)', KsDm VARCHAR(50) DEFAULT NULL COMMENT '科室代码', KsMc VARCHAR(100) DEFAULT NULL COMMENT '科室名称', OperAddrDm VARCHAR(50) DEFAULT NULL COMMENT '手术室代码', OperAddrMc VARCHAR(100) DEFAULT NULL COMMENT '手术室名称', current_year_count INT DEFAULT 0 COMMENT '本年每手术量', last_year_count INT DEFAULT 0 COMMENT '去年每手术量', current_year_SjSl INT DEFAULT 0 COMMENT '本年每国考四级手术量', last_year_SjSl INT DEFAULT 0 COMMENT '去年每国考四级手术量', yoy_change INT DEFAULT NULL COMMENT '每同比变化量(当前 - 去年)', yoy_change_percent DECIMAL(5,2) DEFAULT NULL COMMENT '每同比变化', current_year_AllOperSl INT DEFAULT 0 COMMENT '本年每手术总人数', last_year_AllOperSl INT DEFAULT 0 COMMENT '去年每手术总人数' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='科室手术报'; 这是dm层从dw层抽取的日维度数据sql逻辑,现在我需要新的dm层用于对比今年和去年的维度数据对比,要求按照iso 8601标准按周次对比。新的dm层叫dm1bqksoper_weekly_comparison2,建表语句已经给你。
最新发布
08-05
WITH RECURSIVE current_week_monday AS ( -- 获取当前一(用于构建范围) SELECT DATE_SUB(CURRENT_DATE, INTERVAL WEEKDAY(CURRENT_DATE) DAY) AS current_monday ), -- 生成最近14日期范围(基于一) week_dates AS ( SELECT DATE_SUB(cm.current_monday, INTERVAL (seq * 7) DAY) AS week_start FROM (SELECT 0 AS seq UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12 UNION ALL SELECT 13) AS seq CROSS JOIN current_week_monday cm ORDER BY week_start DESC ), -- 获取 ISO 信息 iso_week_info AS ( SELECT week_start, DATE_ADD(week_start, INTERVAL 6 DAY) AS week_end, DATE_FORMAT(week_start, '%Y-%U') AS iso_week_num, DATE_FORMAT(DATE_ADD(week_start, INTERVAL -1 YEAR), '%Y-%U') AS last_year_iso_week_num, ROW_NUMBER() OVER (ORDER BY week_start DESC) AS week_seq FROM week_dates ), -- 当前年份的科室+手术室数据 current_year_dept AS ( SELECT i.week_start, i.week_end, i.iso_week_num, i.week_seq, d.KsDm, d.KsMc, o.OperAddrDm, o.OperAddrMc, COALESCE(SUM(o.YzSl), 0) AS current_year_count, COALESCE(SUM(o.AllOperSl), 0) AS current_year_AllOperSl, COALESCE(SUM(o.SjSl), 0) AS current_year_SjSl FROM iso_week_info i CROSS JOIN (SELECT DISTINCT KsDm, KsMc FROM dw3bqksoper) AS d LEFT JOIN dw3bqksoper o ON o.KsDm = d.KsDm AND o.OperDate BETWEEN i.week_start AND i.week_end GROUP BY i.week_start, i.week_end, i.iso_week_num, i.week_seq, d.KsDm, d.KsMc, o.OperAddrDm, o.OperAddrMc ), -- 去年同期数据 last_year_dept AS ( SELECT DATE_ADD(i.week_start, INTERVAL -1 YEAR) AS last_year_week_start, DATE_ADD(DATE_ADD(i.week_start, INTERVAL -1 YEAR),INTERVAL 6 DAY)AS last_year_week_end, DATE_FORMAT(DATE_ADD(i.week_start, INTERVAL -1 YEAR), '%Y-%U') AS last_year_iso_week_num, d.KsDm, d.KsMc, o.OperAddrDm, o.OperAddrMc, COALESCE(SUM(o.YzSl), 0) AS last_year_count, COALESCE(SUM(o.AllOperSl), 0) AS last_year_AllOperSl, COALESCE(SUM(o.SjSl), 0) AS last_year_SjSl FROM iso_week_info i CROSS JOIN (SELECT DISTINCT KsDm, KsMc FROM dw3bqksoper) AS d LEFT JOIN dw3bqksoper o ON o.KsDm = d.KsDm AND o.OperDate BETWEEN DATE_ADD(i.week_start, INTERVAL -1 YEAR) AND DATE_ADD(DATE_ADD(i.week_start, INTERVAL -1 YEAR), INTERVAL 6 DAY) GROUP BY DATE_ADD(i.week_start, INTERVAL -1 YEAR), d.KsDm, d.KsMc, o.OperAddrDm, o.OperAddrMc ) -- 最终结果集 SELECT i.iso_week_num AS current_iso_week, l.last_year_iso_week_num AS last_year_iso_week, i.week_start, i.week_end, i.week_seq, c.KsDm, c.KsMc, c.OperAddrDm, c.OperAddrMc, c.current_year_count, l.last_year_count, c.current_year_SjSl, l.last_year_SjSl, (c.current_year_count - l.last_year_count) AS yoy_change, CASE WHEN l.last_year_count > 0 THEN ROUND((c.current_year_count - l.last_year_count) / l.last_year_count * 100, 2) ELSE NULL END AS yoy_change_percent, c.current_year_AllOperSl, l.last_year_AllOperSl FROM current_year_dept c LEFT JOIN last_year_dept l ON c.week_start = DATE_ADD(l.last_year_week_start, INTERVAL 1 YEAR) AND c.KsDm = l.KsDm AND c.OperAddrDm = l.OperAddrDm INNER JOIN iso_week_info i ON c.week_start = i.week_start WHERE c.current_year_count >= 0 ORDER BY i.week_seq, c.KsDm, c.OperAddrDm; CREATE TABLE `dm1bqksoper_weekly_comparison2` ( id BIGINT AUTO_INCREMENT PRIMARY KEY, current_iso_week VARCHAR(10) NOT NULL COMMENT '当前 ISO 编号(如 2024-35)', last_year_iso_week VARCHAR(10) COMMENT '去年同期 ISO 编号(如 2023-35)', week_label varchar(50) DEFAULT NULL COMMENT '周次序列(具体日段)', week_start DATE NOT NULL COMMENT '起始日期一)', week_end DATE NOT NULL COMMENT '结束日期日)', week_seq INT NOT NULL COMMENT '序号(从最近到最远)', KsDm VARCHAR(50) DEFAULT NULL COMMENT '科室代码', KsMc VARCHAR(100) DEFAULT NULL COMMENT '科室名称', OperAddrDm VARCHAR(50) DEFAULT NULL COMMENT '手术室代码', OperAddrMc VARCHAR(100) DEFAULT NULL COMMENT '手术室名称', current_year_count INT DEFAULT 0 COMMENT '本年每手术量', last_year_count INT DEFAULT 0 COMMENT '去年每手术量', current_year_SjSl INT DEFAULT 0 COMMENT '本年每国考四级手术量', last_year_SjSl INT DEFAULT 0 COMMENT '去年每国考四级手术量', yoy_change INT DEFAULT NULL COMMENT '同比变化量(当前 - 去年)', yoy_change_percent DECIMAL(5,2) DEFAULT NULL COMMENT '同比变化百分比', current_year_AllOperSl INT DEFAULT 0 COMMENT '本年每手术总人数', last_year_AllOperSl INT DEFAULT 0 COMMENT '去年每手术总人数' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='科室手术报'; 我现在想新增一个week_label字段,打个比方如果今天是2025年7月30日,显示‘本(2025.7.28 - 2025.8.3)’,之前的显示‘过去第一(2025.7.21 - 2025.7.27)’......
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值