Заполните определенное количество строк между 2 даты - PullRequest
0 голосов
/ 07 января 2020

Я ищу способ заполнить определенное количество строк между двумя датами, чтобы я мог выполнить стандартное отклонение. Заполненные данные будут иметь значение по умолчанию 0.

Вот пример моей таблицы:

+------------+---------+-------+
|    Date    | Account | Value |
+------------+---------+-------+
| 01/01/2020 |       1 |   100 |
| 07/01/2020 |       1 |   200 |
+------------+---------+-------+

То, что я хочу, чтобы это было так:

+------------+---------+-------+
|    Date    | Account | Value |
+------------+---------+-------+
| 01/01/2020 |       1 |   100 |
| 02/01/2020 |       1 |     0 |
| 03/01/2020 |       1 |     0 |
| 04/01/2020 |       1 |     0 |
| 05/01/2020 |       1 |     0 |
| 06/01/2020 |       1 |     0 |
| 07/01/2020 |       1 |   200 |
+------------+---------+-------+

Можно ли построить это утверждение?

Ответы [ 4 ]

1 голос
/ 07 января 2020

Вот один простой способ сделать это с помощью рекурсивного cte:

with cte(mydate, maxdate) as (
    select min(mydate) mydate, max(mydate) maxdate from mytable
    union all
    select mydate + 1, maxdate from cte where mydate < maxdate
)
select c.mydate, coalesce(t.value, 0) value
from cte c
left join mytable t on t.mydate = c.mydate
order by c.mydate

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

Демонстрация на DB Fiddle :

MYDATE    | VALUE
:-------- | ----:
01-JAN-20 |   100
02-JAN-20 |     0
03-JAN-20 |     0
04-JAN-20 |     0
05-JAN-20 |     0
06-JAN-20 |     0
07-JAN-20 |   200
1 голос
/ 07 января 2020

Это можно сделать с помощью рекурсивного запроса:

WITH cte (mydate, account, gap_months) AS 
(
  -- Generate dates to fill in gaps, per account
  SELECT 
    MIN(mydate) OVER(PARTITION BY account) AS mydate, -- Get min date, per account
    account,
    ABS(
      MONTHS_BETWEEN(
        MIN(mydate) OVER(PARTITION BY account),
        MAX(mydate) OVER(PARTITION BY account)
      )
    ) AS gap_months -- Get number of months between min / max dates, per account
  FROM mytable

  UNION ALL

  SELECT 
    ADD_MONTHS(mydate, 1) AS mydate, -- Get next month's date
    account, 
    gap_months - 1 -- Decrease counter
  FROM cte
  WHERE gap_months > 0 -- Stop recursion
)
SELECT DISTINCT 
  cte.mydate, 
  cte.account, 
  COALESCE(mt.value, 0) AS value
FROM cte
LEFT JOIN mytable mt ON cte.mydate = mt.mydate 
  AND cte.account = mt.account -- Get existing data
ORDER BY cte.mydate

DB Fiddle

1 голос
/ 07 января 2020

Вы можете использовать иерархический запрос следующим образом:

SQL> with YOUR_TABLE (date_, account, value)
  2  as
  3  (select date'2020-01-01', 1, 100 from dual
  4  union all select date'2020-01-07', 1, 200 from dual)
  5  ,
  6  -- YOUR QUERY STARTS FROM HERE
  7  -- WITH
  8  MIN_MAX_DATES AS (
  9      SELECT
 10          ACCOUNT,
 11          MIN(DATE_) AS MINDATE,
 12          MAX(DATE_) AS MAXDATE
 13      FROM YOUR_TABLE
 14      GROUP BY ACCOUNT
 15  ), ALL_DATES AS (
 16      SELECT
 17          MINDATE + COLUMN_VALUE - 1 DATE_,
 18          ACCOUNT
 19      FROM MIN_MAX_DATES
 20          CROSS JOIN TABLE ( CAST(MULTISET(
 21              SELECT LEVEL
 22              FROM DUAL
 23              CONNECT BY LEVEL <= MAXDATE - MINDATE + 1
 24          ) AS SYS.ODCINUMBERLIST) )
 25  )
 26  SELECT A.DATE_,
 27           A.ACCOUNT,
 28           COALESCE(T.VALUE, 0) AS VALUE FROM ALL_DATES A
 29  LEFT JOIN YOUR_TABLE T ON T.DATE_ = A.DATE_;

DATE_        ACCOUNT      VALUE
--------- ---------- ----------
01-JAN-20          1        100
02-JAN-20          1          0
03-JAN-20          1          0
04-JAN-20          1          0
05-JAN-20          1          0
06-JAN-20          1          0
07-JAN-20          1        200

7 rows selected.

SQL>

Cheers !!

0 голосов
/ 07 января 2020

Вот как вы можете сделать это с помощью процедуры:

create procedure insert_emptry_date
as

cursor c_cur 
is
select (nvl(date_c - lag(date_c) over (order by date_c), 0)) as a 
       , date_c 
from test
order by date_c;;

var_a number := 0;

begin

for rec in c_cur loop
   if rec.a > 0 then
      var_a := rec.a -1;
   end if;
   dbms_output.put_line(var_a);

   if var_a > 0 then
   loop
      insert into test values ((rec.date_c - var_a), 1, 0);
      commit;
      var_a := var_a -1;
      exit when var_a = 0;
   end loop;
   end if;

end loop;

end;
/

Вот DEMO

В этом коде я использую курсор c_cur, чтобы получить разница между двумя датами и датой, с которой я буду вставлять другие даты.

Я использую переменную var_a, чтобы сохранить полученную разницу с курсором, уменьшенным на 1, потому что я не хочу добавлять то же самое свидание. Затем я уменьшаю это значение до тех пор, пока оно не станет 0. (В вашем примере это значение будет: 5, затем 4, 3, 2, 1).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...