Как дублировать записи в соответствии с начальной и конечной датами - PullRequest
0 голосов
/ 17 мая 2018

У меня есть записи в базе данных SQL, которые имеют startDate и endDate, которые мне нужно расширить.

| userName    | startDate  | endDate    | weekDay |  
| :---------: | :--------: | :--------: | :-----: |  
| Test User 1 | 2011-03-30 | 2011-04-05 | 1       |  
| Test User 2 | 2016-10-05 | 2016-10-07 | 5       |  
| Test User 3 | 2018-05-22 | 2018-05-26 | 4       |  

В приведенной выше таблице каждая запись содержит информацию, которая охватывает более одной даты. Мне нужна одна запись на одну дату на пользователя. Пример того, что я ищу:

| userName    | startDate  | weekDay    |
| :---------: | :--------: | :--------: |
| Test User 1 | 2011-03-30 | 1          |
| Test User 1 | 2011-03-31 | 1          |
| Test User 1 | 2011-04-01 | 1          |
| Test User 1 | 2011-04-02 | 1          |
| Test User 1 | 2011-04-03 | 1          |
| Test User 1 | 2011-04-04 | 1          |
| Test User 1 | 2011-04-05 | 1          |
| Test User 2 | 2016-10-05 | 5          |
| Test User 2 | 2016-10-06 | 5          |
| Test User 2 | 2016-10-07 | 5          |
| Test User 3 | 2018-05-22 | 4          |
| Test User 3 | 2018-05-23 | 4          |
| Test User 3 | 2018-05-24 | 4          |
| Test User 3 | 2018-05-25 | 4          |
| Test User 3 | 2018-05-26 | 4          |

Этот ответ приблизил меня на шаг, указав, как генерировать последовательность дат в SQL. Как я могу дублировать табличные записи в соответствии с датами начала и окончания в SQL?

Как примечание, мне нужно, чтобы это решение работало как в MSSQL, так и в PostgreSQL.

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

попробуйте код ниже. Я использовал рекурсивное общее табличное выражение.

;with cte
AS
(
  SELECT userName,startDate,startDate AS endDate,weekDay FROM tab1
    Union all
  SELECT t1.userName,DATEADD(d,1,t1.startdate) AS startDate,
  DATEADD(d,1,t1.startdate) AS startDate,t1.weekDay
  FROM cte t1
 JOIN tab1 t2 on t1.userName=t2.userName
 WHERE t2.endDate>t1.endDate
) 

 Select userName,startDate,weekDay from cte order by userName

SQL Fiddle: http://sqlfiddle.com/#!18/fa22a/3

0 голосов
/ 17 мая 2018

Вы можете использовать рекурсивный CTE как в SQL Server, так и в Postgres, но синтаксис немного отличается.И есть более простой метод в Postgres.Итак, в SQL Server вы можете сделать:

with cte as (
      select username, startdate, weekday, enddate
      from t
      union all
      select username, dateadd(day, 1, startdate) weekday, enddate
      from cte
      where startdate < enddate
     )
select username, startdate, weekday
from cte
order by username, startdate;

Вы можете настроить арифметику даты и добавить ключевое слово recursive для Postgres.

Более простой метод в Postgres - это боковое соединение:

select t.username, g.startdate, t.weekday
from t, lateral
     generate_series(start_date, end_date, interval '1 day') g(startdate);

Если вам нужен один и тот же код для работы с обоими, вам нужно сгенерировать таблицу чисел.Вот один (неприятный) метод:

with digits as (
      select v.n
      from (values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) v(n)
     ),
     n as (
      select d1.n * 100 + d2.n * 10 + d3.n as n
      from digits d1 cross join digits d2 cross join digits d3
     )
select t.username, t.startdate + n.n, t.weekday
from t join
     n 
     on t.startdate + n.n <= t.enddate;

Обратите внимание, что для этого startdate должен быть datetime в SQL Server, но date в Postgres.

...