带条件的表格前N行

时间:2018-09-03 16:05:33

标签: sql postgresql

这是我们处理的一些调度数据的虚构示例。

这个想法是天真地问这个问题

  

鉴于一个项目还有N个计划外的剩余小时数,总人数(从事此工作的人数),并假设每个工人将工作8天;该项目需要在最后安排的一天之后的哪些非周末天?

我有一个简化的dim_dates表:

CREATE TABLE dim_dates (
  date_actual DATE NOT NULL,
  is_weekend BOOLEAN NOT NULL
);

和项目表:

CREATE TABLE projects (
  id SERIAL PRIMARY KEY NOT NULL,
  last_scheduled_date DATE NOT NULL,
  remaining_hours_required INT NOT NULL,
  head_count INTEGER NOT NULL
);

因此,鉴于此项目:

INSERT INTO projects (last_scheduled_date, remaining_hours_required, head_count) 
VALUES ('2018-01-04', 21, 1);

参加CEIL(remaining_hours_required::decimal / (8 * head_count))后,我们需要3天的工作时间。日期2018-01-04是星期四,所以我们应该以下面的星期五,星期一和星期二作为结束日期。

要获得接下来的非周末假期,我们可以轻松加入dim_dates:

SELECT p.*, d.* 
FROM projects p
INNER JOIN dim_dates d ON (
  d.date_actual > p.last_scheduled_date
  AND
  d.is_weekend IS FALSE
);

哪些人会在非周末的日期后给我们全部。我的难题是如何将此设置过滤为3行。

(必要的)任务描述是:

  1. 计算完成项目所需的剩余天数
  2. 获取is_weekend为false且date_actual高于项目的最后计划日期的所有dim_dates

在这里摆弄数据:http://sqlfiddle.com/#!17/f6a90/3

2 个答案:

答案 0 :(得分:1)

SQL DEMO

WITH dates AS (
  SELECT *, 
  row_number() OVER(ORDER BY date_actual ASC) AS rownum
  FROM dim_dates
  WHERE date_actual > '2018-01-04'::date
  AND is_weekend IS FALSE
), remain_days AS (
    SELECT CEIL (remaining_hours_required::decimal / (8 * head_count))
    FROM projects p
)    
SELECT * 
FROM dates
JOIN remain_days
  ON rownum <= ceil 

答案 1 :(得分:1)

每个项目使用运行总和来保留剩余时间。 并保持这些限制。

在子查询中,它限制了计算出的最大日期。
这样就不会从dim_dates中的每个下一个日期开始计算。

SELECT 
  id as projectId
, date_actual as weekDay
, row_number()
     over (partition by id order by date_actual desc)-1 as daysRemaining
FROM
(
SELECT
 p.id, d.date_actual, p.head_count
, p.last_scheduled_date, p.remaining_hours_required 
,(p.remaining_hours_required 
   - sum(8*head_count) over 
        (partition by p.id order by date_actual)
  ) as remaining_hours
FROM projects p
JOIN dim_dates d 
  ON (d.date_actual > p.last_scheduled_date
  AND d.date_actual <= p.last_scheduled_date + cast(ceil(((p.remaining_hours_required/5.0)*7.0)/(8*p.head_count))+1 as int)
  AND d.is_weekend IS FALSE)
) q
WHERE remaining_hours > (-8*head_count)
ORDER BY id, date_actual;

在SQL小提琴here上进行测试