목표
arrival_date(문자열'YYYY. MM. DD.')는 그대로 유지- 검색/집계 성능을 위해
arrival_date_dt(DATE) 파생 컬럼을 DB가 자동 생성하도록 추가arrival_date_dt인덱스로 월별/기간 필터링을 빠르게 만들기
arrival_date_dt는 INSERT/UPDATE 시 DB가 자동 계산해서 저장(STORED)됨 arrival_date_dt를 직접 넣거나 수정할 필요/권한 없음SELECT COUNT(*) AS bad_cnt
FROM reservation
WHERE arrival_date IS NOT NULL
AND arrival_date NOT REGEXP '^[0-9]{4}\\. [0-9]{2}\\. [0-9]{2}\\.$';
selectPartnerProducts7MonthsRevenue: () => {
let query = `
WITH RECURSIVE months AS (
SELECT DATE_SUB(DATE_FORMAT(?, '%Y-%m-01'), INTERVAL 1 MONTH) AS month_start, 0 AS n
UNION ALL
SELECT DATE_ADD(month_start, INTERVAL 1 MONTH), n + 1
FROM months
WHERE n < 7
)
SELECT
DATE_FORMAT(m.month_start, '%Y-%m') AS ym,
COALESCE(COUNT(r.reservation_no), 0) AS total_cnt,
COALESCE(SUM(r.final_payment_local), 0) AS revenue_sum
FROM months m
LEFT JOIN reservation r
ON r.arrival_date_dt >= m.month_start
AND r.arrival_date_dt < DATE_ADD(m.month_start, INTERVAL 1 MONTH)
AND NOT (r.status = 3 AND COALESCE(r.refunded_jpy, 0) > 0)
LEFT JOIN product p
ON p.product_id = r.product_id
AND p.owner_user_no = ?
-- ✅ 월이 비어있는 row( r=NULL )는 살리고
-- ✅ r이 있으면 반드시 p(owner 일치)가 있는 것만 남김
WHERE r.reservation_no IS NULL OR p.product_id IS NOT NULL
GROUP BY m.month_start
ORDER BY m.month_start;
`;
return query;
},
////...../////
params = [anchorDate, ownerUserNo];