【问题标题】:Fetch first weekday and last weekday from table in MySQL从 MySQL 中的表中获取第一个工作日和最后一个工作日
【发布时间】:2022-06-10 16:38:35
【问题描述】:

我在 mysql 中有一个日程表。我想根据国家代码获取表格的第一天和最后一天。

表格

COUNTRY_CODE IS_WORKING FROM_TIME END_TIME DAY
IN no NULL NULL Sunday
IN yes 09:00:00 18:00:00 Monday
IN yes 09:00:00 18:00:00 Tuesday
IN yes 09:00:00 18:00:00 Wednesday
IN yes 09:00:00 18:00:00 Thursday
IN yes 09:00:00 18:00:00 Friday
IN no NULL NULL Saturday
UAE yes 10:00:00 19:00:00 Sunday
UAE yes 10:00:00 19:00:00 Monday
UAE yes 10:00:00 19:00:00 Tuesday
UAE yes 10:00:00 19:00:00 Wednesday
UAE yes 10:00:00 19:00:00 Thursday
UAE no NULL NULL Friday
UAE no NULL NULL Saturday
UK yes 09:00:00 18:00:00 Sunday
UK yes 09:00:00 18:00:00 Monday
UK yes 09:00:00 18:00:00 Tuesday
UK yes 09:00:00 18:00:00 Wednesday
UK yes 09:00:00 18:00:00 Thursday
UK yes 09:00:00 18:00:00 Friday
UK no NULL NULL Saturday

我想要如下结果:

COUNTRY_CODE START_WORKING_DAY END_WORKING_DAY
IN Monday Friday
UAE Sunday Thursday
UK Sunday Friday

【问题讨论】:

  • 有可以代表订单的列吗?如何定义您的START_WORKING_DAYEND_WORKING_DAY 每个国家代码
  • 抱歉,这张桌子的设计简直就是一场噩梦。您应该摆脱这 3 列并使用 2 日期时间列作为开始和和。然后你可以计算你想要的一切
  • LAG() 对于开始日为 NULL,而 LEAD() 对于结束日为 NULL。正式的工作日可能在一周的中间,因此您必须使用 2 行构建 2 周表(按工作日编号 + 7 * 副本编号排序)并检查第一个和上一个工作日之前的工作日。
  • @Thallius 但此数据没有日期
  • @Akina 我认为您正在阅读不存在的需求

标签: mysql datetime


【解决方案1】:

我认为这很简单:

select COUNTRY_CODE, 
   dayname(min(str_to_date(concat(197001,DAY),"%X%V%W"))) start_working_day,
   dayname(max(str_to_date(concat(197001,DAY),"%X%V%W"))) end_working_day
from test
where IS_WORKING="yes"
group by 1

【讨论】:

  • 这是一个非常好的解决方案,比我的更干净 ? +1
【解决方案2】:

下面的解决方案也许可以简化一点,但我现在想不出更好的解决方案。

我已经使用了两次行号和顺序,包括星期日作为第一天和星期六作为最后一天,这样你就可以唯一地识别行。

with cte as 
( select *, row_number() over( partition by COUNTRY_CODE order by  
        CASE
          WHEN Day = 'Sunday' THEN 1
          WHEN Day = 'Monday' THEN 2
          WHEN Day = 'Tuesday' THEN 3
          WHEN Day = 'Wednesday' THEN 4
          WHEN Day = 'Thursday' THEN 5
          WHEN Day = 'Friday' THEN 6
          WHEN Day = 'Saturday' THEN 7
        END ASC ) as min_row_num,
     row_number() over(partition by COUNTRY_CODE order by  
    CASE
          WHEN Day = 'Sunday' THEN 1
          WHEN Day = 'Monday' THEN 2
          WHEN Day = 'Tuesday' THEN 3
          WHEN Day = 'Wednesday' THEN 4
          WHEN Day = 'Thursday' THEN 5
          WHEN Day = 'Friday' THEN 6
          WHEN Day = 'Saturday' THEN 7
     END DESC) as max_row_num
  from test
  where IS_WORKING='yes'
) select c2.COUNTRY_CODE, START_WORKING_DAY,END_WORKING_DAY
  from   ( select COUNTRY_CODE,min(DAY) as END_WORKING_DAY
                from cte 
                where max_row_num = (select min(max_row_num) from cte)
                group by COUNTRY_CODE
          ) as c1 
  inner join 
          ( select COUNTRY_CODE,min(DAY) as START_WORKING_DAY
                from cte 
                where min_row_num = (select min(min_row_num) from cte)
                group by COUNTRY_CODE
           ) as c2 on c1.COUNTRY_CODE=c2.COUNTRY_CODE

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=f9100085f28ce84195615c7add66d0e2

【讨论】:

  • FIND_IN_SET 比你的长 CASE 短。
  • @Akina case 可能比 FIND_IN_SET 更快
猜你喜欢
  • 1970-01-01
  • 2023-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-07
  • 2021-01-09
  • 1970-01-01
  • 2017-01-20
相关资源
最近更新 更多