Получите среднее количество дней - PullRequest
0 голосов
/ 13 марта 2019

Я работаю над запросом SQL, который возвращает всех клиентов, которые разместили как минимум 3 заказа, а также возвращает среднее количество дней между 1-м и 3-м заказами.

Я использовал этот пост в качестве ссылки:

Расчет среднего времени между заказами для каждого клиента

и приведенный ниже запрос:

select CUSTID , avg(OrderDate - lag_order)
from 
(select CUSTID , OrderDate , count(1) as total, LAG(OrderDate) over (partition by CUSTID ) as lag_order 
from ORDERS group by CUSTID having total >= 3)
group by CUSTID 

Но это не правильный синтаксис, здеськак узнать среднее количество дней между 1-м и 3-м заказом.

Кроме того, я вижу, что lag - это функция в SQLServer, это работает и для базы данных Oracle?

Ответы [ 4 ]

3 голосов
/ 13 марта 2019
with orders as
(select 001 custid, date '2019-01-01' OrderDate from dual union all
 select 001 custid, date '2019-01-02' OrderDate from dual union all
 select 001 custid, date '2019-01-03' OrderDate from dual union all
 select 001 custid, date '2019-01-04' OrderDate from dual union all
 select 001 custid, date '2019-01-05' OrderDate from dual union all

 select 002 custid, date '2019-01-06' OrderDate from dual union all
 select 002 custid, date '2019-01-05' OrderDate from dual union all
 select 002 custid, date '2019-01-07' OrderDate from dual union all
 select 002 custid, date '2019-01-10' OrderDate from dual union all
 select 002 custid, date '2019-01-20' OrderDate from dual
)
select custid, avg(OrderDate - lg) average
from
   (select o.*, 
    count(*)            over (partition by custid) cnt,
    lag  (OrderDate, 2) over (partition by custid order by OrderDate) lg
    from orders o
   )
where cnt >= 3
group by custid;
1 голос
/ 13 марта 2019

Я бы использовал условную агрегацию.Один из методов:

select custid,
       (max(case when seqnum = 3 then OrderDate end) - 
        max(case when seqnum = 1 then OrderDate end)
       ) / 2 as avg_1_3
from (select o.*,
             row_number() over (partition by custid order by orderdate)  as seqnum,
             count(*) over (partition by custid) cnt
      from orders o
     ) o
where cnt >= 3
group by custid;

Более простой способ выразить это - использовать предложение where для фильтрации до первых трех записей:

select custid, (max(OrderDate) - min(OrderDate)) / 2 as avg_1_3
from (select o.*,
             row_number() over (partition by custid order by orderdate)  as seqnum,
             count(*) over (partition by custid) cnt
      from orders o
     ) o
where seqnum <= 3 and cnt >= 3
group by custid;
1 голос
/ 13 марта 2019

Если вам нужно среднее время для клиента между одним заказом и заказом двух заказов назад.Тогда решение будет следующим:
- сначала сгенерируйте заказанный список для каждого клиента
- Затем объедините каждый заказ с двумя шагами назад.

@ akk0rd87: Я позаимствовал ваши данные.

with orders as
(select 001 custid, date '2019-01-01' OrderDate from dual union all
 select 001 custid, date '2019-01-02' OrderDate from dual union all
 select 001 custid, date '2019-01-03' OrderDate from dual union all
 select 001 custid, date '2019-01-04' OrderDate from dual union all
 select 001 custid, date '2019-01-05' OrderDate from dual union all

 select 002 custid, date '2019-01-06' OrderDate from dual union all
 select 002 custid, date '2019-01-05' OrderDate from dual union all
 select 002 custid, date '2019-01-07' OrderDate from dual union all
 select 002 custid, date '2019-01-10' OrderDate from dual union all
 select 002 custid, date '2019-01-20' OrderDate from dual
),
ordered_orders as (select custid, orderdate, row_number() over (partition by custid order by orderdate) onum 
   from orders o)
select co.custid, avg(trunc(co.orderdate) - trunc(oo.orderdate)) adays
from ordered_orders co, ordered_orders oo 
where oo.onum = co.onum - 2
and oo.custid = co.custid
group by co.custid;
1 голос
/ 13 марта 2019

Вы можете попробовать выполнить следующие действия, используя ROW_NUMBER() для себя JOIN, чтобы найти первую и третью дату для клиента.

;WITH cte 
     AS (SELECT custid, 
                orderdate, 
                Count(*) 
                  OVER ( 
                    partition BY custid) tot, 
                Row_number() 
                  OVER( 
                    partition BY custid 
                    ORDER BY orderdate)  rn 
         FROM   orders) 
SELECT * 
FROM   (SELECT t1.custid, 
               Datediff(day, t1.orderdate, t2.orderdate) Days, 
               t1.rn 
        FROM   cte t1 
               INNER JOIN cte t2 
                       ON t1.custid = t2.custid 
                          AND t1.rn = 1 
                          AND t2.rn = 3 
        WHERE  t1.tot >= 3) t 
WHERE  t.rn = 1 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...