Могу ли я использовать Oracle SQL для построения фактических дат из информации о расписании? - PullRequest
1 голос
/ 04 августа 2009

Я задал этот вопрос в отношении SQL Server , но каков ответ для среды Oracle (10g)?

Если у меня есть таблица, содержащая информацию о расписании, которая подразумевает конкретные даты, есть ли оператор SQL, который можно записать для преобразования этой информации в фактические строки, используя что-то вроде выражений таблицы MomSQL Commom, возможно?

Рассмотрим таблицу графика платежей со следующими столбцами:

  • StartDate - дата начала расписания (в этот день должен быть произведен первый платеж)
  • Срок - продолжительность в месяцах расписания
  • Частота - количество месяцев между повторениями
  • PaymentAmt - сумма платежа: -)
SchedID  StartDate    Term  Frequency  PaymentAmt
-------------------------------------------------
1        05-Jan-2003  48    12         1000.00 
2        20-Dec-2008  42    6          25.00

Существует ли один оператор SQL, позволяющий перейти от приведенного выше к следующему?

                              Running
SchedID Payment  Due          Expected
        Num      Date         Total
--------------------------------------
1       1        05-Jan-2003  1000.00
1       2        05-Jan-2004  2000.00
1       3        05-Jan-2005  3000.00
1       4        05-Jan-2006  4000.00
2       1        20-Dec-2008  25.00
2       2        20-Jun-2009  50.00
2       3        20-Dec-2009  75.00
2       4        20-Jun-2010  100.00
2       5        20-Dec-2010  125.00
2       6        20-Jun-2011  150.00
2       7        20-Dec-2011  175.00

Ваши мысли ценятся.

Ответы [ 3 ]

1 голос
/ 05 августа 2009

Я не понимаю, почему 5 дней оплаты для schedid = 1 и 7 дней для scheid = 2?

48/12 = 4 и 42/6 = 7. Так что я ожидал 4 дня оплаты для schedid = 1.

В любом случае я использую предложение модели:

create table PaymentScheduleTable 
( schedid   number(10)
, startdate date
, term      number(3)
, frequency number(3)
, paymentamt number(5)
);

insert into PaymentScheduleTable 
values (1,to_date('05-01-2003','dd-mm-yyyy')
, 48
, 12
, 1000);

insert into PaymentScheduleTable 
values (2,to_date('20-12-2008','dd-mm-yyyy')
, 42
, 6
, 25);

commit;

А теперь предложение select с моделью:

select schedid, to_char(duedate,'dd-mm-yyyy') duedate, expected, i paymentnum
from   paymentscheduletable
model  
partition by (schedid)
dimension by (1 i)
measures (
  startdate duedate
, paymentamt expected
, term 
, frequency) 
rules 
( expected[for i from 1 to term[1]/frequency[1] increment 1] 
  = nvl(expected[cv()-1],0) + expected[1]
, duedate[for i from 1 to term[1]/frequency[1] increment 1] 
  = add_months(duedate[1], (cv(i)-1) * frequency[1])
)
order by schedid,i;

Это выводит:

   SCHEDID DUEDATE      EXPECTED PAYMENTNUM
---------- ---------- ---------- ----------
         1 05-01-2003       1000          1
         1 05-01-2004       2000          2
         1 05-01-2005       3000          3
         1 05-01-2006       4000          4
         2 20-12-2008         25          1
         2 20-06-2009         50          2
         2 20-12-2009         75          3
         2 20-06-2010        100          4
         2 20-12-2010        125          5
         2 20-06-2011        150          6
         2 20-12-2011        175          7


11 rows selected.
1 голос
/ 06 августа 2009

Я не собирался отвечать на свой вопрос, но сейчас я работаю с Oracle, и мне пришлось изучать некоторые новые вещи со вкусом Oracle.

В любом случае, оператор CONNECT BY действительно хорош - да, намного лучше, чем подход с использованием иерархических запросов MSSQL, и с помощью этой конструкции я смог создать очень чистый запрос, который выполняет то, что я искал:

SELECT DISTINCT
     t.SchedID
    ,level as PaymentNum
    ,add_months(T.StartDate,level - 1) as DueDate
    ,(level * t.PaymentAmt) as RunningTotal
FROM SchedTest t
CONNECT BY level <= (t.Term / t.Frequency)
ORDER BY t.SchedID, level

Моя единственная оставшаяся проблема заключается в том, что мне пришлось использовать DISTINCT, потому что я не мог понять, как выбрать мои строки из DUAL (приветливая таблица Oracle из одной строки) вместо из моей таблицы данных расписания, которая имеет по крайней мере 2 ряда Если бы я мог сделать выше с FROM DUAL, то мой индикатор DISTINCT не был бы необходим. Есть мысли?

Кроме этого, я думаю, что это довольно мило. Эт ту?

1 голос
/ 04 августа 2009

Oracle фактически имеет синтаксис для иерархических запросов, используя предложение CONNECT BY. Использование SQL Server предложения WITH выглядит как хак в сравнении:

    SELECT t.SchedId,
           CASE LEVEL
             WHEN 1 THEN
               t.StartDate
             ELSE
               ADD_MONTHS(t.StartDate, t.frequency)
             END 'DueDate',
           CASE LEVEL
             WHEN 1 THEN
               t.PaymentAmt
             ELSE
               SUM(t.paymentAmt)
           END 'RunningExpectedTotal'
      FROM PaymentScheduleTable t
     WHERE t.PaymentNum <= t.Term / t.Frequency
CONNECT BY PRIOR t.startdate = t.startdate
  GROUP BY t.schedid, t.startdate, t.frequency, t.paymentamt
  ORDER BY t.SchedId, t.PaymentNum

Я не на 100% в этом - я более уверен в использовании:

    SELECT t.SchedId,
           t.StartDate 'DueDate',
           t.PaymentAmt 'RunningExpectedTotal'
      FROM PaymentScheduleTable t
     WHERE t.PaymentNum <= t.Term / t.Frequency
CONNECT BY PRIOR t.startdate = t.startdate
  ORDER BY t.SchedId, t.PaymentNum

... но он не включает логику, которую нужно обрабатывать, когда вы имеете дело со вторым + входом в цепочке, чтобы добавлять месяцы и суммировать суммы. Суммирование может быть выполнено с помощью GROUP BY CUBE или ROLLUP в зависимости от необходимой детализации.

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