Вот более прямая часть вопроса. Что-то не так со следующим запросом. Он возвращает каждый ip_address, когда-либо использовавшийся клиентом, вместо того, чтобы фильтровать его за текущий месяц. Когда Deallocation_date имеет значение null или между датами, это единственные IP-адреса, которые необходимо выбрать. Запрос, приведенный ниже, является моей попыткой сделать это с помощью коррелированного подзапроса, используя, если он существует в этих условиях, подсчет и сумму для этих IP-адресов. Однако ниже я показываю, что существует только 29 IP-адресов с datelocation_date = null, которые были освобождены между этими датами, потому что для этого клиента максимальная дата освобождения приходится на август. Я знаю, что он выбирает все IP-адреса, когда-либо назначенные клиенту. Пожалуйста, помогите мне исправить подзапрос, чтобы вернуть правильные данные. Я просто не настолько хорошо разбираюсь в SQL, чтобы понять, в чем моя ошибка. Я знаю, что это как-то связано с тем, как я использую or.

Я также знаю, как было указано, что он будет выбирать только до 00:00:00 в последний день месяца, и пока я согласен с этим, я могу исправить это позже. Мне нужно, чтобы он возвращал правильные данные. Насколько я знаю, для этого клиента в этом месяце не было ни одного освобождения.

Проблемная часть:

И (trunc(d.deallocation_date) между to_date(:run_date) и last_day(:run_date) или f.deallocation_date равно null))

Потому что это должно отфильтровать IP-адреса до 29, независимо от того, что находится в таблице ip_address_usages, но счетчик остается на уровне 57, что означает, что он выбирает их все.

set pagesize 2000
set linesize 300
break on report on customer_name skip 1
compute sum label Total of GigaBytes_Sent GigaBytes_Received IPS_IN_USE on customer_name
compute sum label Grand-Total of GigaBytes_Sent GigaBytes_Received IPS_IN_USE on REPORT
column GigaBytes_Sent format 999,999,999,999.99
column GigaBytes_Received format 999,999,999,999.99

select customer_name,
       substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100) vm_name,
       decode(vcd_managed,'Y',null,'N',vm_display_name) vm_display_name,
       sum(bytes_sent)*1.8/power(10,9) GigaBytes_Sent,
       sum(bytes_received)*1.8/power(10,9) GigaBytes_Received,
       count(unique e.ip_address_id) IPS_IN_USE
  from customers a,
       vm_groups b, 
       vms c, 
       vm_ip_address_histories d, 
       ip_address_usages e
 where a.customer_id = b.customer_id
   and b.vm_group_id=c.vm_group_id
   and c.vm_id=d.vm_id
   and d.ip_address_id=e.ip_address_id
   and trunc(e.datetime) between :run_date and last_day(:run_date)
   and exists (select f.deallocation_date 
                   from vm_ip_address_histories f 
                   where f.vm_id = d.vm_id 
                   and (trunc(d.deallocation_date) between to_date(:run_date) and last_day(:run_date) or f.deallocation_date is null))
   and inactive = 'N'
   and a.customer_id = 30
--   and (bytes_sent > 0 or bytes_received > 0)
 group by customer_name,
       substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100),
       decode(vcd_managed,'Y',null,'N',vm_display_name)
 order by 1,2,3
/

Я пытаюсь суммировать байты, отправленные и полученные из таблицы ip_address_usages, при этом подсчитывая отдельные ip_address_id, принадлежащие клиенту между первым и последним днем ​​​​месяца, дата освобождения которых равна нулю, или значение, которое находится между первым и последний день месяца. Когда я запускаю первый запрос ниже, он возвращает неправильное количество IP-адресов, связанных с клиентом.

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

Вот табличные отношения, я включил только релевантные с описаниями.

    Customers > VM_Groups  
    VM_Groups > VMS 
    VMS > VM_IP_ADDRESS_HISTORIES 
    VM_IP_ADDRESS_HISTORIES > IP_ADDRESSES by ip_address_id, 
    IP_ADDRESSES > IP_ADDRESS_USAGES "this is where bytes sent and received is" relates to IP_ADDRESSES by ip_address_id

Я замаскировал информацию из соображений безопасности, но она вам не нужна, чтобы ответить на вопрос:

Возвращенные значения из первого неверного запроса, количество равно 57, а не 29:

    variable run_date varchar2(30)
    exec :run_date := to_date('1-oct-14')

    set pagesize 2000
    set linesize 300
    break on report on customer_name skip 1
    compute sum label Total of GigaBytes_Sent GigaBytes_Received IPS_IN_USE on customer_name
    compute sum label Grand-Total of GigaBytes_Sent GigaBytes_Received IPS_IN_USE on REPORT
    column GigaBytes_Sent format 999,999,999,999.99
    column GigaBytes_Received format 999,999,999,999.99

    select customer_name,
           substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100) vm_name,
           decode(vcd_managed,'Y',null,'N',vm_display_name) vm_display_name,
           sum(bytes_sent)*1.8/power(10,9) GigaBytes_Sent,
           sum(bytes_received)*1.8/power(10,9) GigaBytes_Received,
           count(unique e.ip_address_id) IPS_IN_USE
      from customers a,
           vm_groups b, 
           vms c, 
           vm_ip_address_histories d, 
           ip_address_usages e
     where a.customer_id = b.customer_id
       and b.vm_group_id=c.vm_group_id
       and c.vm_id=d.vm_id
       and d.ip_address_id=e.ip_address_id
       and trunc(e.datetime) between :run_date and last_day(:run_date)
       and inactive = 'N'
       and a.customer_id = 30
    --   and (bytes_sent > 0 or bytes_received > 0)
     group by customer_name,
           substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100),
           decode(vcd_managed,'Y',null,'N',vm_display_name)
     order by 1,2,3
    /


    CUSTOMER_NAME              VM_NAME                                                  VM_DISPLAY_NAME         GIGABYTES_SENT  GIGABYTES_RECEIVED IPS_IN_USE
    ------------------------------ ---------------------------------------------------------------------------------------------------- ------------------------------ ------------------- ------------------- ----------
    mask/masked        mask/masked                                                                                  198.59                    168.57            29
                       mask/masked                                                                                  43.35                      33.95            19
                       mask/masked                                                                                  164.04                    135.86             9
    ***************************************************************************************************************************************************************************************************     
    Total                                                                                       405.98                    338.38            57

    set pagesize 2000
    set linesize 300
    break on report on customer_name skip 1
    compute sum label Total of GigaBytes_Sent GigaBytes_Received IPS_IN_USE on customer_name
    compute sum label Grand-Total of GigaBytes_Sent GigaBytes_Received IPS_IN_USE on REPORT
    column GigaBytes_Sent format 999,999,999,999.99
    column GigaBytes_Received format 999,999,999,999.99

    select customer_name,
           substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100) vm_name,
           decode(vcd_managed,'Y',null,'N',vm_display_name) vm_display_name,
           sum(bytes_sent)*1.8/power(10,9) GigaBytes_Sent,
           sum(bytes_received)*1.8/power(10,9) GigaBytes_Received,
           count(unique e.ip_address_id) IPS_IN_USE
      from customers a,
           vm_groups b, 
           vms c, 
           vm_ip_address_histories d, 
           ip_address_usages e
     where a.customer_id = b.customer_id
       and b.vm_group_id=c.vm_group_id
       and c.vm_id=d.vm_id
       and d.ip_address_id=e.ip_address_id
       and trunc(e.datetime) between :run_date and last_day(:run_date)
       and (d.deallocation_date is null or d.deallocation_date between to_date(:run_date) and last_day(:run_date))
       and inactive = 'N'
       and a.customer_id =30
    --   and (bytes_sent > 0 or bytes_received > 0)
     group by customer_name,
           substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100),
           decode(vcd_managed,'Y',null,'N',vm_display_name)
     order by 1,2,3
    /

    CUSTOMER_NAME              VM_NAME                                                  VM_DISPLAY_NAME         GIGABYTES_SENT  GIGABYTES_RECEIVED IPS_IN_USE
    ------------------------------ ---------------------------------------------------------------------------------------------------- ------------------------------ ------------------- ------------------- ----------
    mask/masked        mask/masked                                                                                  .00                          .01              8
                       mask/masked                                                                                  43.35                      33.95             18
                       mask/masked                                                                                  .00                          .01              3
    ***************************************************************************************************************************************************************************************************                                                                 
    Total                                                                                       43.35                        33.97          29

    select max(deallocation_date) 
    from vm_ip_address_histories a, 
    vms b, vm_groups c, 
    customers d 
    where a.vm_id = b.vm_id 
    and b.vm_group_id = c.vm_group_id 
    and c.customer_id = d.customer_id 
    and d.customer_id = 30
    /

    MAX(DEALLOCATION_DATE)
    ---------------------------------------------------------------------------
    04-AUG-14 06.04.30.000000 PM


    select distinct e.ip_address, 
    a.customer_name,
    c.vm_id, 
    d.allocation_date, 
    d.deallocation_date
    from customers a, 
    vm_groups b, 
    vms c, 
    vm_ip_address_histories d, 
    ip_addresses e 
    where a.customer_id=30
    and a.customer_id = b.customer_id
    and b.vm_group_id = c.vm_group_id
    and c.vm_id = d.vm_id
    and d.ip_address_id = e.ip_address_id
    and exists (select * from vm_ip_address_histories where d.deallocation_date is null or trunc(d.deallocation_date) >= to_date('1-oct-14') )
    /

      2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17  
    IP_ADDRESS           CUSTOMER_NAME               VM_ID ALLOCATION_DATE                                 DEALLOCATION_DATE
    -------------------------------- ------------------------------ ---------- --------------------------------------------------------------------------- ---------------------------------------------------------------------------
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 03.58.48.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 30-JUL-14 03.18.41.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 04.43.48.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 03.43.48.000000 PM
    XXXXXXXX             XXXXXXXXX                 365 17-JAN-14 03.02.25.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 03.43.48.000000 PM
    XXXXXXXX             XXXXXXXXX                1586 26-FEB-14 10.48.18.000000 AM
    XXXXXXXX             XXXXXXXXX                 365 17-JAN-14 03.02.25.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 28-JUN-14 12.45.22.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 21-JUN-14 01.29.23.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 04.58.48.000000 PM

    IP_ADDRESS           CUSTOMER_NAME               VM_ID ALLOCATION_DATE                                 DEALLOCATION_DATE
    -------------------------------- ------------------------------ ---------- --------------------------------------------------------------------------- ---------------------------------------------------------------------------
    XXXXXXXX             XXXXXXXXX                 365 17-JAN-14 03.02.25.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 03.58.48.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 03.43.48.000000 PM
    XXXXXXXX             XXXXXXXXX                 365 17-JAN-14 03.02.25.000000 PM
    XXXXXXXX             XXXXXXXXX                 365 20-FEB-14 04.47.33.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 04.13.48.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 03.58.48.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 04.43.48.000000 PM
    XXXXXXXX             XXXXXXXXX                1586 17-JUN-14 02.13.47.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 04-AUG-14 06.04.30.000000 PM
    XXXXXXXX             XXXXXXXXX                1586 25-FEB-14 05.03.12.000000 PM

    IP_ADDRESS           CUSTOMER_NAME               VM_ID ALLOCATION_DATE                                 DEALLOCATION_DATE
    -------------------------------- ------------------------------ ---------- ---------------------------select customer_name,
       substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100) vm_name,
       decode(vcd_managed,'Y',null,'N',vm_display_name) vm_display_name,
       sum(bytes_sent)*1.8/power(10,9) GigaBytes_Sent,
       sum(bytes_received)*1.8/power(10,9) GigaBytes_Received,
       count(unique e.ip_address_id) IPS_IN_USE
  from customers a,
       vm_groups b, 
       vms c, 
       vm_ip_address_histories d, 
       ip_address_usages e
 where a.customer_id = b.customer_id
   and b.vm_group_id=c.vm_group_id
   and c.vm_id=d.vm_id
   and d.ip_address_id=e.ip_address_id
   and trunc(e.datetime) between :run_date and last_day(:run_date)
   and exists (select * from vm_ip_address_histories f where deallocation_date is null or trunc(deallocation_date) between :run_date and last_day(:run_date) )
   and inactive = 'N'
   and a.customer_id = 30
--   and (bytes_sent > 0 or bytes_received > 0)
 group by customer_name,
       substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100),
       decode(vcd_managed,'Y',null,'N',vm_display_name)
 order by 1,2,3
------------------------------------------------ ---------------------------------------------------------------------------
    XXXXXXXX             XXXXXXXXX                 365 17-JAN-14 03.02.25.000000 PM
    XXXXXXXX             XXXXXXXXX                 365 17-JAN-14 03.02.25.000000 PM
    XXXXXXXX             XXXXXXXXX                 365 17-JAN-14 03.02.25.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 04.13.48.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 03.43.48.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 28-JUN-14 12.30.23.000000 PM
    XXXXXXXX             XXXXXXXXX               27374 17-JUN-14 04.43.48.000000 PM

    29 rows selected.




    select distinct e.ip_address
    from customers a, 
    vm_groups b, 
    vms c, 
    vm_ip_address_histories d, 
    ip_addresses e 
    where a.customer_id=30
    and a.customer_id = b.customer_id
    and b.vm_group_id = c.vm_group_id
    and c.vm_id = d.vm_id
    and d.ip_address_id = e.ip_address_id
    and (d.deallocation_date is null or d.deallocation_date between to_date('01-10-2014', 'DD-MM-YYYY') and to_date('31-10-2014 23:59:59', 'DD-MM-YYYY HH24:MI:SS'))
    /  

    IP_ADDRESS
    --------------------------------
    MASKED FOR SECURITY

    29 rows selected.



    select count(distinct e.ip_address)
    from customers a, 
    vm_groups b, 
    vms c, 
    vm_ip_address_histories d, 
    ip_addresses e 
    where a.customer_id=30
    and a.customer_id = b.customer_id
    and b.vm_group_id = c.vm_group_id
    and c.vm_id = d.vm_id
    and d.ip_address_id = e.ip_address_id
    and (d.deallocation_date is null or d.deallocation_date between to_date('01-10-2014', 'DD-MM-YYYY') and to_date('31-10-2014 23:59:59', 'DD-MM-YYYY HH24:MI:SS'))
    /

    COUNT(DISTINCTE.IP_ADDRESS)
    ---------------------------
                 29

Поэтому я написал еще один запрос, используя коррелированный подзапрос, чтобы попытаться отфильтровать только IP-адреса, выделенные и освобожденные в пределах диапазона, но он все равно вернул 57, но правильные данные об использовании. Теперь, очевидно, их всего 29, как я вполне адекватно показал выше. Таким образом, это что-то в моем запросе. Пожалуйста, посмотрите и скажите мне, что не так с запросом.

    select customer_name,
           substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100) vm_name,
           decode(vcd_managed,'Y',null,'N',vm_display_name) vm_display_name,
           sum(bytes_sent)*1.8/power(10,9) GigaBytes_Sent,
           sum(bytes_received)*1.8/power(10,9) GigaBytes_Received,
           count(unique e.ip_address_id) IPS_IN_USE
      from customers a,
           vm_groups b, 
           vms c, 
           vm_ip_address_histories d, 
           ip_address_usages e
     where a.customer_id = b.customer_id
       and b.vm_group_id=c.vm_group_id
       and c.vm_id=d.vm_id
       and d.ip_address_id=e.ip_address_id
       and trunc(e.datetime) between :run_date and last_day(:run_date)
       and exists (select * from vm_ip_address_histories f where deallocation_date is null or trunc(deallocation_date) between :run_date and last_day(:run_date) )
       and inactive = 'N'
       and a.customer_id = 30
    --   and (bytes_sent > 0 or bytes_received > 0)
     group by customer_name,
           substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100),
           decode(vcd_managed,'Y',null,'N',vm_display_name)
     order by 1,2,3

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

То же самое здесь

select customer_name,
       substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100) vm_name,
       decode(vcd_managed,'Y',null,'N',vm_display_name) vm_display_name,
       sum(bytes_sent)*1.8/power(10,9) GigaBytes_Sent,
       sum(bytes_received)*1.8/power(10,9) GigaBytes_Received,
       count(unique e.ip_address_id) IPS_IN_USE
  from customers a,
       vm_groups b, 
       vms c, 
       vm_ip_address_histories d, 
       ip_address_usages e
 where a.customer_id = b.customer_id
   and b.vm_group_id=c.vm_group_id
   and c.vm_id=d.vm_id
   and d.ip_address_id=e.ip_address_id
   and trunc(e.datetime) between :run_date and last_day(:run_date)
   and exists (select f.deallocation_date from vm_ip_address_histories f where f.vm_id = d.vm_id and (f.deallocation_date is null or trunc(f.deallocation_date) between :run_date and last_day(:run_date)) )
   and inactive = 'N'
   and a.customer_id = 30
--   and (bytes_sent > 0 or bytes_received > 0)
 group by customer_name,
       substr(decode(vcd_managed,'Y',vm_name,'N',vm_group_name || ' ' || vm_display_name),1,100),
       decode(vcd_managed,'Y',null,'N',vm_display_name)
 order by 1,2,3
0
Grant Zukel 28 Окт 2014 в 01:55
1
Можете ли вы собрать воспроизводимый тестовый пример (т.е. что-то, что мы можем запустить в нашей системе, что создаст нужные вам таблицы, заполнит некоторые фиктивные данные и покажет нам ожидаемые результаты)? В противном случае никому другому будет практически невозможно догадаться, в чем заключается ваша проблема.
 – 
Justin Cave
28 Окт 2014 в 02:01
Если у меня будет время, я сделаю это сегодня вечером. Спасибо, что нашли время посмотреть. Вот почему я включил так много данных в надежде, что кто-то сможет увидеть то, чего не вижу я, или скорректировать мой запрос. в основном он просматривает все IP-адреса, которые когда-либо были в таблице vm_ip_address_histories, и игнорирует дату освобождения, но когда я настроил его для просмотра, он сбрасывает данные об использовании, я ожидаю, что он немного уменьшится, потому что он не будет связывать плохие IP-адреса с клиентом но это так далеко, что я знаю, что это неправильно.\
 – 
Grant Zukel
28 Окт 2014 в 02:05
Теперь я добавляю некоторые данные, которые могут помочь.
 – 
Grant Zukel
28 Окт 2014 в 02:06
Не могли бы вы сейчас взглянуть на верхнюю часть вопроса и просто помочь мне с подзапросом @JustinCave
 – 
Grant Zukel
28 Окт 2014 в 03:05
Я предлагаю вам уточнять имена столбцов с их именами таблиц в каждой точке запроса, включая любые подзапросы.
 – 
WW.
28 Окт 2014 в 08:12

2 ответа

Функция LAST_DAY возвращает дату последнего дня месяца, указанную в качестве входных данных, но она также включает компонент времени указанной вами даты, поэтому ваше предложение

    d.deallocation_date between to_date(:run_date) and last_day(:run_date))

Вероятно должно быть

   truncate(d.deallocation_date) between to_date(:run_date) and last_day(:run_date))

Ваш код устанавливает :run_date в поле varchar без компонента времени, поэтому last_day(:run_date) будет в 00:00:00, и поэтому, если d.deallocation_date имеет время позже, чем тогда, он не будет выбран.

SQL> variable run_date varchar2(30)
SQL> exec :run_date := to_date('1-oct-14')

SQL>  select to_char(to_date(:run_date), 'yyyy-mm-dd hh24:mi:ss') as first_of_month,
2*     to_char(last_day(to_date(:run_date)), 'yyyy-mm-dd hh24:mi:ss') as last_of_month from dual;

FIRST_OF_MONTH      LAST_OF_MONTH
------------------- -------------------
2014-10-01 00:00:00 2014-10-31 00:00:00
0
Mark Stewart 28 Окт 2014 в 02:43
Я вижу это, но с моим запросом что-то не так, на самом деле он не фильтрует даты освобождения, он просто продолжает выбирать все
 – 
Grant Zukel
28 Окт 2014 в 02:58
Не могли бы вы сейчас взглянуть на верхнюю часть вопроса и просто помочь мне с подзапросом @Mark Stewart
 – 
Grant Zukel
28 Окт 2014 в 03:05
А, ладно, извини, @Грант. Я сейчас тоже в тупике!
 – 
Mark Stewart
28 Окт 2014 в 03:18

Что касается этой части:

(trunc(d.deallocation_date) between to_date(:run_date) and last_day(:run_date) 
or f.deallocation_date is null))

Должны ли вы использовать deallocation_date из одной и той же таблицы с обеих сторон or?

0
WW. 28 Окт 2014 в 08:13
Ну, я пытаюсь найти, есть ли у него дата освобождения между датами или она нулевая.
 – 
Grant Zukel
28 Окт 2014 в 17:47