고객 추이 정합성 역산

This commit is contained in:
Hyojin Ahn 2026-06-24 10:29:18 -04:00
parent e593be0a2d
commit fcbab196cb
1 changed files with 27 additions and 20 deletions

View File

@ -30,29 +30,36 @@ public interface CustomerRepository extends JpaRepository<Customer, Long> {
// 오늘 추가된 고객 : cus_contract_date = 오늘 // 오늘 추가된 고객 : cus_contract_date = 오늘
long countByCusContractDate(LocalDate cusContractDate); long countByCusContractDate(LocalDate cusContractDate);
// 날짜별 활성 고객 + 신규/해지 (선그래프·막대그래프용). // 날짜별 활성 + 일별 신규/해지 "현재 기준 역산(reverse-calc)" 모델.
// - active_count = cus_status='A' 이고 날짜에 계약기간 안에 있던 고객 (날짜로 과거 재구성) // - 기준점: 오늘 활성 = cus_status='A' (신뢰 기준, 카드와 동일)
// - added_count = 날짜에 계약 시작 (cus_contract_date = D) // - 과거 D의 활성 = 오늘 활성 (D 이후 신규 계약) + (D 이후 해지)
// - removed_count = 날짜에 해지 (cus_terminated_date = D) // · D 이후 신규는 D 시점엔 아직 없었으니 빼고
// - generate_series [startDate, endDate] 날짜 생성 날도 0 // · D 이후 해지는 D 시점엔 아직 있었으니 더함
// - added/removed effective date(cus_contract_date / cus_terminated_date) 기준 일별 이벤트
// - active(D) = active(D-1) + added(D) removed(D) 정확히 성립.
// 소급(백데이트) 건도 조회마다 현재 날짜값으로 재계산되어 effective date 위치에 반영됨.
// - return: [0]=날짜(date), [1]=active(bigint), [2]=added(bigint), [3]=removed(bigint) // - return: [0]=날짜(date), [1]=active(bigint), [2]=added(bigint), [3]=removed(bigint)
@Query(value = """ @Query(value = """
SELECT CAST(series.day AS date) AS day, SELECT days.day AS day,
(SELECT COUNT(*) FROM crm.customer c ( (SELECT COUNT(*) FROM crm.customer WHERE cus_status = 'A')
WHERE c.cus_status = 'A' - (SELECT COUNT(*) FROM crm.customer
AND c.cus_contract_date <= CAST(series.day AS date) WHERE cus_contract_date > days.day
AND (c.cus_terminated_date IS NULL OR c.cus_terminated_date > CAST(series.day AS date)) AND cus_contract_date <= CAST(:endDate AS date))
+ (SELECT COUNT(*) FROM crm.customer
WHERE cus_terminated_date > days.day
AND cus_terminated_date <= CAST(:endDate AS date))
) AS active_count, ) AS active_count,
(SELECT COUNT(*) FROM crm.customer a (SELECT COUNT(*) FROM crm.customer
WHERE a.cus_contract_date = CAST(series.day AS date) WHERE cus_contract_date = days.day) AS added_count,
) AS added_count, (SELECT COUNT(*) FROM crm.customer
(SELECT COUNT(*) FROM crm.customer r WHERE cus_terminated_date = days.day) AS removed_count
WHERE r.cus_terminated_date = CAST(series.day AS date) FROM (
) AS removed_count SELECT CAST(series.day AS date) AS day
FROM generate_series(CAST(:startDate AS timestamp), FROM generate_series(CAST(:startDate AS timestamp),
CAST(:endDate AS timestamp), CAST(:endDate AS timestamp),
INTERVAL '1 day') AS series(day) INTERVAL '1 day') AS series(day)
ORDER BY series.day ) days
ORDER BY days.day
""", nativeQuery = true) """, nativeQuery = true)
List<Object[]> findActiveCustomerTrend(@Param("startDate") LocalDate startDate, List<Object[]> findActiveCustomerTrend(@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate); @Param("endDate") LocalDate endDate);