2

我想找到一种方法来使用 Redshift 确定这个日历月中剩余的工作日数。我目前有一个朋友写的 MySQL 版本。我对它是如何编写的甚至翻译成另一种方言都不太了解。但是,如果有人可以帮助翻译它,这将是一个非常有用的工具!

networkdays()输出的功能应该与 excel 中的功能一样。在此函数中,提供了 begin_date 和 end_date 作为函数的参数。它计算开始日期和结束日期之间的工作日(非周末日历天数)(含)。

这是当前的 MySQL:

SELECT 1 AS pk ,COUNT(*) AS remaining
FROM (
    SELECT WEEKDAY(DATE(DATE_FORMAT(CONVERT_TZ(NOW(), 'UTC', 'PST8PDT'), '%Y-%m-01') + INTERVAL (a.num-1) DAY)) AS weekdays
        FROM (
        SELECT @row := @row + 1 AS num
        FROM schema.table t, (SELECT @row := 0) r
    ) a
        WHERE a.num >= DAY(CONVERT_TZ(NOW(), 'UTC', 'PST8PDT'))
        AND a.num <= DAY((DATE_FORMAT(CONVERT_TZ(NOW(), 'UTC', 'PST8PDT'), '%Y-%m-01') + INTERVAL 1 MONTH) - INTERVAL 1 DAY)
) b
WHERE b.weekdays NOT IN (0,6)

任何帮助都会很棒!

4

4 回答 4

0

数据仓库的一个流行想法是创建一个calendar包含所有日期(或至少与公司相关的日期)的表,以及以下标志:

  • 公共假期
  • 工作日
  • 每月第一(工作)日
  • 每月最后一个(工作)日
  • 月数
  • 周数
  • 天数

虽然其中许多值可以通过日期函数计算,但通常更容易连接到calendar表以执行某些日期函数。

在计算剩余工作日的情况下,只需计算表中设置标志calendar的所需范围内的行数即可。is_work_day这可以通过一个JOIN或一个子查询来完成。

不像其中一些查询那么花哨,但通常更容易维护。此外,Amazon Redshift 不支持该generate_series功能,因此通常只能做到这一点。

也可以看看:

于 2016-03-19T03:35:56.460 回答
0

不需要函数,你可以用一条 SQL 语句来完成:

SELECT count(*)
FROM generate_series(CURRENT_TIME,
                     date_trunc('month', CURRENT_TIME) + interval '1 month - 1 day',
                     interval '1 day') days(d)
WHERE extract(dow from d) NOT IN (0, 6);

当然,如果需要,您可以将其包装在 SQL 函数中。考虑到您对当月剩余工作日的需求,您无需指定任何参数。

于 2016-03-19T00:45:07.433 回答
0

为了获得工作日的计数,您需要使用函数知道该月的第一天( ) 的日期。之后,您需要使用函数获取特定月份( ) 的天数,有一个关于此的wiki 页面。最后,您可以使用日期和数字的天数,不包括使用函数的周末天数。start_datedate_trunc()month_last_dayextract()generate_series()start_datemonth_last_daydate_part()

CREATE OR REPLACE FUNCTION extract_month_business_days(d DATE, count_remaining BOOLEAN)
  RETURNS INTEGER AS $$
DECLARE
  start_date DATE;
  month_last_day INTEGER;
  result INTEGER;
BEGIN
  IF count_remaining THEN
    start_date = d;
  ELSE
    start_date = date_trunc('month',d);
  END IF;
  month_last_day = extract(DAY FROM date_trunc('month',d) + INTERVAL '1 MONTH - 1 day');
  SELECT count(*) INTO result FROM generate_series(0,(month_last_day - extract(DAY FROM start_date))::INTEGER) day
    WHERE date_part('dow', start_date + day) NOT IN (0,6);
  RETURN result;
END;
$$ LANGUAGE plpgsql;

结果:

WITH t(dates) AS ( VALUES
  ('2016-02-18'::DATE),
  ('2016-03-18'::DATE),
  ('2016-04-18'::DATE),
  ('2016-05-18'::DATE)
)
SELECT
  to_char(dates,'Month YY') AS month,
  extract_month_business_days(dates,FALSE) AS number_business_days,
  extract_month_business_days(dates,TRUE) AS remaining_business_days
FROM t;

    month     | number_business_days | remaining_business_days 
--------------+----------------------+-------------------------
 February  16 |                   21 |                       8
 March     16 |                   23 |                      10
 April     16 |                   21 |                      10
 May       16 |                   22 |                      10
(4 rows)

更新 - 红移版

正如@John指出的,generate_series()在 AWS Redshift 中不可用,函数定义如下:

CREATE OR REPLACE FUNCTION extract_month_business_days(d DATE, count_remaining BOOLEAN)
  RETURNS INTEGER AS $$
DECLARE
  start_date DATE;
  month_last_day INTEGER;
  result INTEGER;
  i INTEGER;
BEGIN
  result = 0;
  IF count_remaining THEN
    start_date = d;
  ELSE
    start_date = date_trunc('month',d);
  END IF;
  month_last_day = extract(DAY FROM date_trunc('month',d) + INTERVAL '1 MONTH - 1 day');
  result = 0;
  FOR i IN 0..(month_last_day - extract(DAY FROM start_date))::INTEGER LOOP
    IF (date_part('dow', start_date + i) NOT IN (0,6)) THEN
      result = result + 1;
    END IF;
  END LOOP;
  RETURN result;
END;
$$ LANGUAGE plpgsql;
于 2016-03-19T00:05:24.920 回答
0

我的回答是拥有一张只有一大堆交易的表格,在您关心的月份中每天至少有一个交易。对我来说幸运的是,我们的系统允许用户在未来安排交易,所以我可以 ping 它一些简单的日期逻辑。

SELECT
count(CASE WHEN business_day < date(getdate()) THEN 1 END) as passed
,count(business_day) as total_business_days
FROM
  (SELECT distinct
   date(o.appointment_full_time) as business_day
  FROM
   orders o
  WHERE
   date_trunc('month', o.appointment_full_time) = date_trunc('month', getdate())
--this month
    AND extract(dow from o.appointment_full_time) not in (0,6)
--exclude weekends
    AND date(o.appointment_full_time) 
       not in ('2017-1-1', '2017-1-2', '2017-1-16', '2017-5-29', '2017-7-4', '2017-9-4',
          '2017-11-23', '2017-11-24', '2017-12-25', '2017-12-24', '2017-12-31')
--manually enter the holidays in once per year
 ) a
于 2017-07-26T17:02:34.830 回答