문제

문의사항을 처리할 때 조언이 필요합니다.이를 프런트엔드 애플리케이션에서 처리할 수 있지만 설계상 이를 백엔드에서 구현해야 합니다.나는 다음을 가지고 있습니다


CREATE TABLE [dbo].[openitems](
    [id] [varchar](8) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [type] [char](5) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [date] [smalldatetime] NULL,
    [amount] [decimal](9, 2) NULL,
    [daysOpen] [smallint] NULL,
    [balance] [decimal](9, 2) NULL
) ON [PRIMARY]




insert into openitems values('A12399','INV','2008-12-05',491.96,123)

insert into openitems values('A12399','INV','2008-12-12',4911.37,116)

insert into openitems values('A12399','INV','2008-12-05',3457.69,109)

위의 표에는 고객에 대한 미결제 송장이 모두 나와 있습니다.가장 오래된 인보이스부터 시작하여 이 인보이스에 결제를 적용해야 합니다(표의 daysOpen 열).따라서 $550.00 결제가 있는 경우 먼저 123 daysOld가 있는 송장에 적용하겠습니다. 즉 $491.96 -$500입니다(다음 송장에 적용하려면 $8.04가 남습니다...).등), 해당 레코드(표의 잔액 열)를 0.00으로 업데이트하고 다음으로 이동하여 나머지를 적용합니다.그러면 $4911.37 - $8.04가 되고 $4903.33이 남게 됩니다.적용할 잔액이 남아 있지 않으므로 루프가 종료됩니다.

이제 잔액 열이 읽어야 합니다.

0
4903.33
3457.69

메모:테이블에 있는 모든 고객(약 10,000명)에 대해 이 작업을 수행해야 합니다.고객은 평균 약 20개의 송장을 미결 상태로 가지고 있습니다.

감사해요

도움이 되었습니까?

해결책

다음을 고려하세요:

지불은 잔액 전체에 적용되거나, 잔액에 부분적으로 적용되거나, 잔액을 초과하여 지불됩니다.

이제 모든 잔액에 대해 현재까지의 송장 누적 잔액을 찾을 수 있다고 가정해 보겠습니다.상상하기보다는 이렇게 해보자.

create view cumulative_balance as
select a.*, 
  (select sum( balance ) 
  from openitems b 
  where b.id = a.id and b.type = a.type and a.daysOpen >= a.daysOpen)
  as cumulative_balance
from openitems a;

이제 우리는 모든 ID와 유형에 대해 결제 금액보다 작거나 같은 첫 번째 누적 잔액을 찾아 이를 서버 변수에 저장할 수 있고 daysOpen과 누적 잔액을 저장할 수 있습니다.

그런 다음 해당 ID와 유형으로 모든 openItem을 업데이트합니다. 여기서 daysOpen <= 우리가 얻은 값이며 모든 잔액을 0으로 설정합니다.

그런 다음 해당 ID와 유형의 첫 번째 0이 아닌 잔액을 찾고 잔액을 잔액(지불 - 우리가 저장한 누적 잔액)으로 설정합니다.초과지불이 있는 경우 이 잔액은 정확하게 마이너스가 됩니다.

올바른 쿼리를 사용하면 하나의 문에서 조회와 첫 번째 업데이트를 수행할 수 있습니다.

두 가지 문제가 있습니다.하나는 동일한 ID, 유형 및 daysOpen을 가진 두 개 이상의 lance를 결정할 수 없으며 먼저 지불해야 한다는 것입니다.추가 고유한 귀하의 테이블에 대한 이드의 판단은 그러한 경우에 대한 결정적인 역할을 할 것입니다.

두 번째는 두 번째 업데이트에 대한 쿼리에 사용하기 위해 누적 잔액을 저장해야 한다는 것입니다.결제로 업데이트되지 않은invoice_amount 열과 업데이트된 결제 열을 사용하여 테이블을 올바르게 디자인했다면 문제가 해결될 것입니다.

더 나은 리팩토링은 두 개의 테이블(송장용 테이블과 결제용 테이블)을 갖는 것입니다.그런 다음 뷰는 누적 잔액을 누적 지불과 비교하여 미지급 잔액 또는 초과 지불 목록을 생성하는 등 모든 작업을 수행할 수 있습니다.

사실 저는 FM이라는 이니셜을 가진 주요 모기지 보증 회사를 위해 바로 그러한 시스템을 설계했습니다.잔액은 금액과 백분율의 여러 공식으로 계산되었으며 여러 지불자(실제로는 보험사, 이는 채무 불이행에 들어간 모기지에 대한 것임)로 송장을 발행해야 했다는 점에서 기존의 것보다 조금 더 복잡했습니다. 채무 불이행 모기지에 따라 다른 규칙에 따라 규정된 순서.

이 모든 작업은 위에서 설명한 작업을 본질적으로 수행하는 짧은(100줄 정도) 저장 프로시저를 사용하여 뷰에서 수행되었습니다.이러한 규칙에 따라 청구서 청구를 정렬하고, 지불을 적용하고(보기에서), 어느 날짜에 어느 보험사에 청구할 추가 지불액을 계산하는 보기를 사용했습니다.그런 다음 저장 프로시저는 현재 날짜에 대한 송장을 생성했습니다(현재 날짜는 다시 뷰를 사용하여 테스트 목적으로 임의의 날짜로 설정할 수 있음).

(아이러니한 점은 C++를 작성하겠다고 약속하자마자 그 일을 맡았다는 것입니다.내가 작성한 유일한 C++는 Oracle 및 Sybase C API를 사용하여 Oracle 시스템에서 Sybase 시스템으로 데이터를 전송했습니다.)

다른 팁

이렇게 하면 됩니다.지역 변수를 선언했지만 이를 저장 프로시저의 매개 변수로 만들 수 있습니다.또한 ID와 날짜가 고유하지 않은 것 같기 때문에 송장을 고유하게 식별하기 위해 테이블에voice_id를 추가했습니다.

DECLARE
    @paid_amount DECIMAL(9, 2)

SET @paid_amount = 500

UPDATE
    OI
SET
    balance =
            CASE
                WHEN @paid_amount - SQ.running_total > balance THEN 0
                ELSE balance - (@paid_amount - SQ.running_total)
            END
FROM
    dbo.OpenItems OI
INNER JOIN (
    SELECT
        I1.id,
        I1.invoice_id,
        I1.date,
        ISNULL(SUM(I2.amount), 0) AS running_total
    FROM
        OpenItems I1
    LEFT OUTER JOIN OpenItems I2 ON
        I2.id = I1.id AND
        I2.type = 'INV' AND
        I2.daysopen > I1.daysopen
    GROUP BY
        I1.id,
        I1.invoice_id,
        I1.date
) AS SQ ON
    SQ.id = OI.id AND
    SQ.invoice_id = OI.invoice_id
WHERE
    @paid_amount > SQ.running_total

일회성 노력이 아니라면...

이는 비즈니스 논리이며 애플리케이션의 비즈니스 계층에 속하는 것처럼 들립니다.

두 개의 커서와 두 개의 중첩 루프를 사용해야 합니다.(조금 느릴 수도 있습니다)

모든 결제 내역을 읽는 사람 - 고객, 금액을 가정합니다.

그런 다음 각 고객에 대해 열린 항목에 대한 또 다른 커서를 만듭니다.

첫 번째 루프는 완료될 때까지 결제를 읽습니다.

해당 루프 내에서 가장 오래된 것부터 정렬된 고객의 열린 항목에 대한 새 커서를 엽니다.

각 미결 항목을 반복하고 설명된 대로 결제를 적용합니다.

그런 다음 다음 지불을 받으십시오.

더 이상 결제가 없을 때까지 반복합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top