2012-02-21 7 views
1

У меня есть эта существующая схема, где таблица расписания выглядит так (очень упрощена).Продолжить последнее значение за временной интервал

CREATE TABLE schedule (
    id   int(11) NOT NULL AUTO_INCREMENT, 
    name   varchar(45), 
    start_date date, 
    availability int(3), 
    PRIMARY KEY (id) 
); 

Для каждого человека указывается дата начала и процент от времени работы, затраченного на этот проект. Этот процент доступности неявно продолжает до тех пор, пока не будет указано более новое значение. Например, возьмем проект, который длится от 2012-02-27 до 2012-03-02:

id | name | start_date | availability 
------------------------------------- 
1 | Tom | 2012-02-27 |   100 
2 | Tom | 2012-02-29 |   50 
3 | Ben | 2012-03-01 |   80 

Так Том начинается февраля 27nd, полный рабочий день, до февраля, 29, из которого на него» будет доступно только с 50% его рабочего времени. Бен только начинается 1 марта и только с 80% его времени.

Теперь цель состоит в том, чтобы «нормализовать» эти скудные данные, так что есть результат строка для каждого человека за каждый день с наличием исходя из последнего указанного дня:

name | start_date | availability 
-------------------------------- 
Tom | 2012-02-27 |   100 
Tom | 2012-02-28 |   100 
Tom | 2012-02-29 |   50 
Tom | 2012-03-01 |   50 
Tom | 2012-03-02 |   50 
Ben | 2012-02-27 |   0 
Ben | 2012-02-28 |   0 
Ben | 2012-02-29 |   0 
Ben | 2012-03-01 |   80 
Ben | 2012-03-02 |   80 

Think диаграмма, показывающая доступности каждого человека с течением времени или вычисления значений «ресурса» в диаграмме выгорания. Я могу легко сделать это с помощью процедурного кода на уровне приложения, но предпочел бы более удобное и быстрое решение.

+1

Going процедурной может быть более в зависимости от того, как используются данные, поскольку для отсутствующих дат нет строк. –

+0

В ваших исходных данных я не вижу дату 2012-03-02 в любом месте. Откуда это происходит, как определяется окончание проекта? –

ответ

2

Для того, чтобы это было эффективно, я рекомендую создать таблицу calendar. Один, который содержит каждую интересующую дату. Затем вы используете это как шаблон для присоединения к вашим данным.

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

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

SELECT 
    * 
FROM 
    calendar 
CROSS JOIN 
    person 
LEFT JOIN 
    schedule 
    ON schedule.name  = person.name 
    AND schedule.start_date = (SELECT MAX(start_date) 
           FROM schedule 
           WHERE name = person.name 
            AND start_date <= calendar.date) 
WHERE 
     calendar.date >= <yourStartDate> 
    AND calendar.date <= <yourEndDate> 
    etc 


Часто, однако, это более эффективно бороться с ним в одном из двух других способов ...

Не допускать пробелов в данных, в первую очередь. Имейте ночной пакетный процесс или какую-либо другую бизнес-логику, обеспечивающую заполнение всех релевантных данных.

Или общайтесь с ним в своем клиенте. Верните каждое измерение в отчет (данные и имя) в качестве отдельных наборов данных, чтобы действовать как ваши шаблоны, а затем верните данные в качестве конечного набора данных. Ваш клиент может перебирать данные и заполнять пробелы, если это необходимо. Это больше кода, но на самом деле может использовать меньше ресурсов в целом, чем пытаться заполнить пробелы SQL.

(Если на стороне клиента код делает это медленно, вывесить другой вопрос изучения этого кода. При условии, что данные отсортированы, это acutally довольно быстро сделать в большинстве языков.)

+0

«Если ваш код клиента делает это медленно» => Ну, это не проблема.Основная проблема заключается в том, что, если я вычисляю значения в слое приложения, то я должен делать * все * последующие вычисления на клиентском уровне тоже, как и суммирование итогов. Это абсолютно похоже на то, что он принадлежит в БД (итерирование значений и увеличение общего количества). –

+0

@ StephenFriedrich - Если дата календаря предваряет любую запись для пользователя, запись Schedule будет NULL. В таких случаях вы можете использовать «COALESCE (доступность, 0)», чтобы превратить NULL в 0. Если вы получаете NULLS для дат, где существует предыдущая запись данных, что-то не так, и мне нужен пример кода вы были реализованы, чтобы иметь возможность исследовать. – MatBailie

+0

К сожалению, проблема, о которой я упоминал, была ошибкой в ​​настройке данных. Служит мне для того, чтобы не включать полные сценарии, включая инструкции вставки. Спасибо за решение! Еще проще добавить флаг, чтобы указать, является ли это явным или подразумеваемым (отображается серым в пользовательском интерфейсе): if (calendar.date = schedule.start_date, 1, 0) как явный –

Смежные вопросы