Это возможно с простым SQL? Или процедура требуется? - PullRequest
0 голосов
/ 12 декабря 2010

(это в DB2 версии 9.5)

Скажем, у меня есть таблица с четырьмя столбцами:

C1: [EmployeeId]
C2: [StartDate] yyyy-mm-dd format
C3: [EndDate]   yyyy-mm-dd format
C4: [Age]

Комбинация [EmployeeId + StartDate] образует первичный ключ.
Теперь рассмотрим следующие примеры строк:

1     2010-01-16     2010-04-16     29
2     2010-02-16     2010-03-16     33
3     2010-05-16     2010-05-16     31

Существует гарантия, что все ДНИ будут 16-го числа, для всех дат, для всех строк. Другого пути нет.

Я пытаюсь написать запрос, который будет делать следующее:

Для любой строки, где начальный месяц меньше конечного месяца (например, строка 1), реплицируйте строку для каждого промежуточного месяца, включая последнюю строку. Таким образом, после выполнения запроса новые строки для строки 1 будут:

1     2010-01-16     2010-04-16     29
1     2010-02-16     2010-04-16     29
1     2010-03-16     2010-04-16     29
1     2010-04-16     2010-04-16     29

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

Вопросы:

  1. Возможно ли это в простом SQL? Или требуются процедуры?
  2. Если да, то как? (подсказки, код, что угодно)

Спасибо, что читаете, ребята. Постановка проблемы сложна, я надеюсь, что сделал все возможное, чтобы объяснить ее. Любая двусмысленность или несоответствие: пожалуйста, укажите, и я отредактирую это как можно скорее.

Ответы [ 2 ]

1 голос
/ 12 декабря 2010

Я думаю, что это должно сделать это:

SELECT e.employee_id, 
       date(extract(year from startdate)||'-'||mm.month_nr||'-'||extract(day from startdate)) as stardate,
       first_value(e.enddate) over (partition by employee_id order by e.enddate) as enddate
FROM (
  VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)
) mm (month_nr)
JOIN emp_test e
     ON mm.month_nr = extract(month from e.startdate)
ORDER BY e.employee_id, 
         e.startdate, 
         e.enddate

Это, конечно, предполагает, что тип данных для начальной и конечной даты равен DATE.
И это будет работать, только если все даты в течение одного года.

Я тестировал это только с DB2 9.7, но думаю, что он также должен работать с 9.5.

Я думаю, что есть решение для годовой проблемы:

WITH yrs (year_month) AS
(
  SELECT DATE(year_nr||'-'||month_nr||'-16')
  FROM (
   VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)
  ) mon (month_nr)
  CROSS JOIN (
    VALUES (2007), (2008), (2009), (2010), (2011), (2012), (2013)
  ) yr (year_nr)
) 
SELECT e.employee_id, 
       yrs.year_month as startdate,
       first_value(e.enddate) over (partition by employee_id order by e.enddate) as enddate
FROM emp_test e
  JOIN yrs ON yrs.year_month between e.startdate and e.enddate

Как видите, годы "жестко закодированы" в CTE (общее табличное выражение). Самым простым решением было бы создать таблицу «месяц / год», содержащую все возможные значения - в основном данные, которые генерирует CTE.

0 голосов
/ 14 марта 2012

FWIW набор ограничений атрибутов и кортежей в некоторой степени упростится:

CHECK (EXTRACT(DAY FROM StartDate) = 16),
CHECK (EXTRACT(DAY FROM EndDate) = 16),
CHECK (StartDate < EndDate)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...