Расчет среднего срока исполнения по запросу SQL - PullRequest
1 голос
/ 13 апреля 2020

Я хочу рассчитать среднюю дату исполнения и остаток для каждого клиента. У меня есть две таблицы, первая из них - Таблица списка клиентов, вторая - Платежные транзакции.

Таблица A (lG_060_CLCARD) - Список клиентов

LOGICALREF  DEFINITION_
------------------------
18166       ABC INC

Таблица B (LG_060_04_PAYTRANS) - ОПЛАТА ОПЕРАЦИЙ

CARDREF      PROCDATE     SIGN   TOTAL   DISCDUEDATE
-----------------------------------------------------
18166       2020.03.21     1     1000     2020.03.21
18166       2020.03.21     1     15000    2020.03.21
18166       2020.02.29     0     2500     2020.03.30
18166       2020.02.29     0     6000     2020.03.30
18166       2020.03.16     0     4000     2020.04.15
18166       2020.03.16     0     6500     2020.04.15
18166       2020.03.16     0     2000     2020.05.15

Объяснение второй таблицы: этот клиент (18166) заплатил мне дважды (SIGN означает, что заплатил мне, если равен 1) 21 марта 2020 года, что составляет 1000 + 15000 = 16000. Тот же клиент купил 5 разные вещи в 2 разных дня. Дата их оплаты указана в столбце DISCDUEDATE.

Ручное вычисление средней даты оплаты:

Таблица B (LG_060_04_PAYTRANS) - ОПЛАТА ОПЕРАЦИЙ

CARDREF      PROCDATE     SIGN   TOTAL   DISCDUEDATE   *cumulativeBalance
-------------------------------------------------------------------------
18166       2020.03.21     1     1000     2020.03.21    -1000
18166       2020.03.21     1     15000    2020.03.21    -16000
18166       2020.02.29     0     2500     2020.03.30    -13500
18166       2020.02.29     0     6000     2020.03.30    -7500
18166       2020.03.16     0     4000     2020.04.15    -3500
18166       2020.03.16     0     6500     2020.04.15    3000 --> balance turns into positive
18166       2020.03.16     0     2000     2020.05.15    

Расчет начинается с шестого строка, потому что баланс становится положительным с этой строкой. И мы используем 3000 вместо 6500 для шестой строки.

Таблица расчетов должна выглядеть следующим образом:

CARDREF      PROCDATE     SIGN   TOTAL   DISCDUEDATE   DAY
-----------------------------------------------------------
18166       2020.03.16     0     3000     2020.04.15   2
18166       2020.03.16     0     2000     2020.05.15   32

DAY означает разницу между сегодняшним днем ​​и сроком исполнения DISCDUEDATE. Сегодня 2020.04.13

Итак, средняя дата оплаты (ADD):

2 x 3000  = 6000
32 x 2000 = 64000
          +--------
            68000

ADD = 68000 : (3000+2000) = 13,6 = 13 days

Реальная проблема для меня - это вычислить сумму баланса и дату, которая становится положительной (дата положительного баланса) и сумма). После этого дня все положительные строки (SIGN = 0) должны быть добавлены в расчет.

У меня есть код для этого расчета.

SELECT
    CL.DEFINITION_,
    SUM(CASE WHEN SIGN=1 THEN -1 WHEN SIGN=0 THEN 1 END * TOTAL) AS BALANCE,
    FLOOR(SUM(DUEDATE)/SUM(TOTAL)) AS 'AVG DATE',
    CONVERT(VARCHAR, DATEADD(DAY, FLOOR(SUM(DUEDATE)/SUM(TOTAL)), GETDATE()),104) AS 'AVG DUE DATE'
FROM
    LG_060_CLCARD CL
LEFT JOIN 
    (SELECT
         CARDREF, SIGN, TOTAL,
         (DATEDIFF(DAY, GETDATE(),DISCDUEDATE) * TOTAL) AS DUEDATE
     FROM
         LG_060_04_PAYTRANS
     WHERE
         CANCELLED = 0) PT ON PT.CARDREF = LOGICALREF
WHERE
    LOGICALREF = 18166
GROUP BY
    CL.DEFINITION_, CL.LOGICALREF

Этот код работает хорошо, он правильно вычисляет баланс но он неправильно вычисляет средний день и средний срок оплаты. Потому что я не знаю, как рассчитать положительную дату баланса и сумму?

1 Ответ

0 голосов
/ 13 апреля 2020

Я создал таблицу, похожую на вашу, под названием «payt», и с t sql работает следующее. Я добавил cardref, чтобы убедиться, что код все еще работает, когда есть больше cardref:

/*
create table payt (
      cardref int,
      procdate date,
      sign int,
      total float,
      discduedate date);


    insert into payt values (18166,'2020-03-21',1,1000,'2020-03-21'),
                              (18166,'2020-03-21',1,15000,'2020-03-21'),
                              (18166,'2020-02-29',0,2500,'2020-03-30'),
                              (18166,'2020-02-29',0,6000,'2020-03-30'),
                              (18166,'2020-03-16',0,4000,'2020-04-15'),
                              (18166,'2020-03-16',0,6500,'2020-04-15'),
                              (18166,'2020-03-16',0,2000,'2020-05-15'),
                              (18164,'2020-03-16',1,600,'2020-04-16'),
                              (18164,'2020-03-16',0,2000,'2020-05-10')
    */
    select *,
    case when sign=1 then -total else total end as num,
    row_number() over (partition by cardref order by discduedate) as r1
    into #t1
    from payt

    declare @c as int=(select min(cardref) from payt)
    declare @m as int=(select max(cardref) from payt)


    select *,0 as dd
    into #t2
    from payt
    where cardref<@c

    while @c<=@m
    begin
    declare @r as int=0
    declare @s as int=-1

    while @s<0
    begin
    set @r=@r+1
    set @s=(select sum(num) as num
    from #t1
    where r1<=@r
    and cardref=@c)
    end

    insert into #t2
    select a.cardref,a.procdate,a.sign,
    case when a.r1=@r then @s else a.num end as total,
    a.discduedate,
    datediff(day,getdate(),a.discduedate) as dd
    from #t1 a
    where a.r1>=@r
    and a.cardref=@c

    set @c=(select min(cardref) from payt where cardref>@c)
    end

    select *
    from #t2
...