Взятие первых N строк таблицы с условием - PullRequest
0 голосов
/ 03 сентября 2018

Это надуманный пример некоторых данных планирования, которые мы обрабатываем.

Идея в том, чтобы наивно задавать вопрос

Учитывая, что у проекта есть N оставшихся незапланированных часов, head_count (количество людей, работающих над ним), и предположение, что каждый работник будет работать 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. Взять все dim_dates, где is_weekend равно false, а date_actual выше последней запланированной даты проекта

Вот скрипка с данными: http://sqlfiddle.com/#!17/f6a90/3

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

Использование промежуточной суммы, чтобы сохранить оставшиеся часы для каждого проекта. И держать их в пределах лимита.

В подзапросе он ограничивает вычисленную максимальную дату.
Чтобы он не рассчитывался для каждой следующей даты из 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 здесь

0 голосов
/ 03 сентября 2018

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 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...