Процедура создания ежемесячного бизнес-отчета

#oracle #plsql

#Oracle #plsql

Вопрос:

Я пытаюсь написать процедуру, которая генерирует ежемесячный бизнес-отчет. Мне нужно показать общее количество арендованных бизнес-объектов и CarRentalSites, на которых есть бизнес-аренда за этот месяц. Должны отображаться только месяцы с арендой бизнеса, и порядок месяцев должен быть от самого раннего к последнему, а порядок сайтов CarRentalSites должен быть по атрибуту CarRentalSiteName.

Для этого я написал следующее

 create or replace procedure MonthlyBusinessRentalsReport as
CURSOR d_cursor is
Select Extract(year from Rentals.RentalDate) as oYear, Extract(month from Rentals.RentalDate) as oMonth, Count(*) as t
    from Rentals where Rentals.Status = 'BUSINESS'
Group By Extract(year from Rentals.RentalDate), Extract(month from Rentals.RentalDate) 
    Order By Extract(year from Rentals.RentalDate), Extract(month from Rentals.RentalDate);
    d_res d_cursor%ROWTYPE;

CURSOR d_retail is  
    Select Extract(year from Rentals.RentalDate) as oYear, Extract(month from Rentals.RentalDate) as oMonth, CarRentalSite.CarRentalSiteName, numOfDays
    from Rentals INNER JOIN CarRentalSite on Rentals.CarRentalSiteId=CarRentalSite.CarRentalSiteId where Rentals.Status='BUSINESS'
    Group By Extract(year from Rentals.RentalDate), Extract(month from Rentals.RentalDate), CarRentalSite.CarRentalSiteName, numOfDays
    Order By Extract(year from Rentals.RentalDate), Extract(month from Rentals.RentalDate), CarRentalSite.CarRentalSiteName, numOfDays;
    d_res2 d_retail%ROWTYPE;

BEGIN
    OPEN d_retail;
    Fetch d_retail into d_res2;
    for d_res in d_cursor loop
    dbms_output.put_line('Total Business Rentals in ' || d_res.oYear || '-' || d_res.oMonth || ': ' || d_res.t);
    dbms_output.put_line('In Car Rental Sites:');
    loop
    dbms_output.put_line('- ' || d_res2.CarRentalSiteName || ': ' || d_res2.numOfDays || ' days');
    Fetch d_retail into d_res2;
    exit when d_retail%NOTFOUND or d_res2.oYear != d_res.oYear or d_res2.oMonth != d_res.oMonth;
    end loop;
    end loop;
    Close d_retail;

    END MonthlyBusinessRentalsReport;
    /   

    show errors;

    BEGIN
    MonthlyBusinessRentalsReport;
    End;
    /   
  

Это дает мне результат, но не тот, который ожидался, мне нужна помощь в его исправлении.
Мой результат по сравнению с ожидаемым таков

 ---- Result of Procedure 2:
Total Business Rentals in 2018-1: 2
In Car Rental Sites:
- Hertz: 15 days

Expected:
Total Business Rentals in 2018-1: 2
In Car Rental Sites:
- Hertz: 36 days

---- Result of Procedure 2:
- Hertz: 21 days
Total Business Rentals in 2018-2: 2
In Car Rental Sites:
- Alamo: 10 days

Expected:
Total Business Rentals in 2018-2: 2
In Car Rental Sites:
- Alamo: 10 days
- Hertz: 14 days

---- Result of Procedure 2:
- Hertz: 14 days
Total Business Rentals in 2018-4: 1
In Car Rental Sites:

Expected:
Total Business Rentals in 2018-4: 1
In Car Rental Sites:
- Enterprise: 2 days

---- Result of Procedure 2:
- Enterprise: 2 days
Total Business Rentals in 2018-5: 3
In Car Rental Sites:
- Avis: 2 days
- Budget: 3 days

Expected:
Total Business Rentals in 2018-5: 3
In Car Rental Sites:
- Avis: 2 days
- Budget: 3 days
- Hertz: 25 days

---- Result of Procedure 2:
- Hertz: 25 days
Total Business Rentals in 2018-6: 1
In Car Rental Sites:

Expected:
Total Business Rentals in 2018-6: 1
In Car Rental Sites:
- Alamo: 10 days
  

Это таблица и файлы данных, которые будут использоваться

Файл данных
Файл таблиц

Комментарии:

1. Второй запрос содержит столбец numOfDays . Это должно быть каким-то образом агрегировано? Это выглядит неправильно.

2. Да, я так считаю. Нам нужно добавить количество дней для каждой аренды. например, если есть две аренды, вам нужно добавить значение в таблицу для каждой

Ответ №1:

Мне кажется, проблема в том, что ваше ручное управление циклом выборки означает, что вы теряете данные. Проще и безопаснее позволить Oracle управлять этим:

 create or replace procedure MonthlyBusinessRentalsReport as
BEGIN

    for d_res in 
       (Select Extract(year from Rentals.RentalDate) as oYear
                , Extract(month from Rentals.RentalDate) as oMonth
                , Count(*) as t
        from Rentals 
        where Rentals.Status = 'BUSINESS'
        Group By Extract(year from Rentals.RentalDate), Extract(month from Rentals.RentalDate) 
        Order By Extract(year from Rentals.RentalDate), Extract(month from Rentals.RentalDate)
    )
    loop
        dbms_output.put_line('Total Business Rentals in ' || d_res.oYear || '-' || d_res.oMonth || ': ' || d_res.t);
        dbms_output.put_line('In Car Rental Sites:');
        for d_res2 in (
              Select CarRentalSite.CarRentalSiteName
                     , sum(numOfDays) as numOfDays
              from Rentals
              INNER JOIN CarRentalSite on Rentals.CarRentalSiteId=CarRentalSite.CarRentalSiteId 
              where Rentals.Status='BUSINESS'
              and  Extract(year from Rentals.RentalDate) = d_res.oYear
              and Extract(month from Rentals.RentalDate) = d_res.oMonth
              group by CarRentalSite.CarRentalSiteName
              Order By CarRentalSite.CarRentalSiteName
        )
        loop
            dbms_output.put_line('- ' || d_res2.CarRentalSiteName || ': ' || d_res2.numOfDays || ' days');
        end loop;
    end loop;

END MonthlyBusinessRentalsReport;
/   
  

В вашем коде есть вещи, которые я бы сделал по-другому, но я попытался изменить только те вещи, которые ответственны за получение неправильных результатов.

Комментарии:

1. Привет @APC спасибо за ваш ответ. Я запущу этот код со своей стороны и обновлю вас. Кстати, вам не удалось загрузить файлы так, как я их загрузил? Должен ли я загружать их другим способом?

2. Файлы загружаются на uploadfiles.io они зашифрованы и проверены на вирусы. Можете ли вы загрузить и просмотреть выходные данные вашего кода?