add product/order chart

This commit is contained in:
Timi
2026-09-06 17:56:47 +08:00
parent db2fca5715
commit 01d33a1122
32 changed files with 1783 additions and 0 deletions
@@ -0,0 +1,191 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imyeyu.api.modules.gao.mapper.GaoProductChartMapper">
<sql id="productFilter">
AND p.`deleted_at` IS NULL
<if test="storeId != null and storeId != ''">AND p.`store_id` = #{storeId}</if>
<if test="productId != null and productId != ''">AND p.`id` = #{productId}</if>
<if test="categoryId != null and categoryId != ''">AND p.`category_id` = #{categoryId}</if>
<if test="productType != null">AND p.`product_type` = #{productType}</if>
</sql>
<sql id="orderProductFilter">
AND o.`deleted_at` IS NULL
AND i.`deleted_at` IS NULL
AND o.`status` &lt;&gt; 'CANCELLED'
<if test="storeId != null and storeId != ''">AND o.`store_id` = #{storeId}</if>
<if test="productId != null and productId != ''">AND i.`product_id` = #{productId}</if>
<if test="categoryId != null and categoryId != ''">AND p.`category_id` = #{categoryId}</if>
<if test="productType != null">AND p.`product_type` = #{productType}</if>
AND o.`purchased_at` &gt;= #{beginAt}
AND o.`purchased_at` &lt;= #{endAt}
</sql>
<select id="selectSalesDaily" resultType="com.imyeyu.api.modules.gao.vo.GaoProductSalesDailyStatView">
SELECT
CAST(DATE_FORMAT(FROM_UNIXTIME(o.`purchased_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
COUNT(DISTINCT o.`id`) AS `orderCount`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT' THEN i.`quantity` ELSE 0 END), 0) AS `directQuantity`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'PACKAGE_ENTITLEMENT' THEN i.`quantity` ELSE 0 END), 0) AS `packageQuantity`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT' THEN COALESCE(i.`line_amount`, 0) ELSE 0 END), 0) AS `directSaleAmount`
FROM `gao_sales_order_item` i
INNER JOIN `gao_sales_order` o ON o.`id` = i.`sales_order_id`
INNER JOIN `gao_product` p ON p.`id` = i.`product_id` AND p.`store_id` = o.`store_id`
WHERE 1 = 1
<include refid="orderProductFilter"/>
GROUP BY DATE_FORMAT(FROM_UNIXTIME(o.`purchased_at` / 1000), '%Y%m%d')
ORDER BY `dateValue` ASC
</select>
<select id="selectSalesRank" resultType="com.imyeyu.api.modules.gao.vo.GaoProductSalesRankView">
SELECT
i.`product_id` AS `productId`,
MAX(i.`product_name_snapshot`) AS `productName`,
COUNT(DISTINCT o.`id`) AS `orderCount`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT' THEN i.`quantity` ELSE 0 END), 0) AS `directQuantity`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'PACKAGE_ENTITLEMENT' THEN i.`quantity` ELSE 0 END), 0) AS `packageQuantity`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT' THEN COALESCE(i.`line_amount`, 0) ELSE 0 END), 0) AS `directSaleAmount`
FROM `gao_sales_order_item` i
INNER JOIN `gao_sales_order` o ON o.`id` = i.`sales_order_id`
INNER JOIN `gao_product` p ON p.`id` = i.`product_id` AND p.`store_id` = o.`store_id`
WHERE 1 = 1
<include refid="orderProductFilter"/>
GROUP BY i.`product_id`
ORDER BY (SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT' THEN i.`quantity` ELSE 0 END)
+ SUM(CASE WHEN i.`item_type` = 'PACKAGE_ENTITLEMENT' THEN i.`quantity` ELSE 0 END)) DESC,
directSaleAmount DESC,
i.`product_id` ASC
LIMIT #{topN}
</select>
<select id="selectFulfillmentDaily" resultType="com.imyeyu.api.modules.gao.vo.GaoProductFulfillmentDailyStatView">
SELECT
CAST(DATE_FORMAT(FROM_UNIXTIME(f.`delivered_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT'
THEN CASE WHEN f.`source_fulfillment_id` IS NULL THEN fi.`quantity` ELSE -fi.`quantity` END ELSE 0 END), 0) AS `directQuantity`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'PACKAGE_ENTITLEMENT'
THEN CASE WHEN f.`source_fulfillment_id` IS NULL THEN fi.`quantity` ELSE -fi.`quantity` END ELSE 0 END), 0) AS `packageQuantity`,
COALESCE(SUM(CASE WHEN f.`source_fulfillment_id` IS NULL THEN fi.`base_quantity` ELSE -fi.`base_quantity` END), 0) AS `baseQuantity`
FROM `gao_order_fulfillment` f
INNER JOIN `gao_order_fulfillment_item` fi ON fi.`fulfillment_id` = f.`id`
INNER JOIN `gao_sales_order_item` i ON i.`id` = fi.`source_order_item_id`
INNER JOIN `gao_sales_order` o ON o.`id` = f.`sales_order_id` AND o.`deleted_at` IS NULL
INNER JOIN `gao_product` p ON p.`id` = fi.`product_id` AND p.`store_id` = f.`store_id`
WHERE f.`store_id` = #{storeId}
AND f.`status` = 'VERIFIED'
AND f.`delivered_at` &gt;= #{beginAt}
AND f.`delivered_at` &lt;= #{endAt}
<if test="productId != null and productId != ''">AND fi.`product_id` = #{productId}</if>
<if test="categoryId != null and categoryId != ''">AND p.`category_id` = #{categoryId}</if>
<if test="productType != null">AND p.`product_type` = #{productType}</if>
GROUP BY DATE_FORMAT(FROM_UNIXTIME(f.`delivered_at` / 1000), '%Y%m%d')
ORDER BY `dateValue` ASC
</select>
<select id="selectFulfillmentRank" resultType="com.imyeyu.api.modules.gao.vo.GaoProductFulfillmentRankView">
SELECT
i.`product_id` AS `productId`,
MAX(i.`product_name_snapshot`) AS `productName`,
COUNT(DISTINCT o.`id`) AS `orderCount`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT' THEN i.`quantity` ELSE 0 END), 0) AS `directQuantity`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'PACKAGE_ENTITLEMENT' THEN i.`quantity` ELSE 0 END), 0) AS `packageQuantity`,
COALESCE(SUM(i.`reserved_quantity`), 0) AS `reservedQuantity`,
COALESCE(SUM(i.`fulfilled_quantity`), 0) AS `fulfilledQuantity`,
COALESCE(SUM(i.`quantity` - i.`reserved_quantity` - i.`fulfilled_quantity`), 0) AS `availableQuantity`
FROM `gao_sales_order_item` i
INNER JOIN `gao_sales_order` o ON o.`id` = i.`sales_order_id`
INNER JOIN `gao_product` p ON p.`id` = i.`product_id` AND p.`store_id` = o.`store_id`
WHERE 1 = 1
<include refid="orderProductFilter"/>
GROUP BY i.`product_id`
ORDER BY `availableQuantity` DESC, `fulfilledQuantity` DESC, i.`product_id` ASC
LIMIT #{topN}
</select>
<select id="selectStockMovementDaily" resultType="com.imyeyu.api.modules.gao.vo.GaoProductStockMovementDailyStatView">
SELECT
CAST(DATE_FORMAT(FROM_UNIXTIME(r.`occurred_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
COALESCE(SUM(CASE WHEN r.`on_hand_delta` &gt; 0 THEN r.`on_hand_delta` ELSE 0 END), 0) AS `inQuantity`,
COALESCE(SUM(CASE WHEN r.`on_hand_delta` &lt; 0 THEN -r.`on_hand_delta` ELSE 0 END), 0) AS `outQuantity`,
COALESCE(SUM(r.`on_hand_delta`), 0) AS `netOnHandQuantity`,
COALESCE(SUM(CASE WHEN r.`reserved_delta` &gt; 0 THEN r.`reserved_delta` ELSE 0 END), 0) AS `reserveQuantity`,
COALESCE(SUM(CASE WHEN r.`reserved_delta` &lt; 0 THEN -r.`reserved_delta` ELSE 0 END), 0) AS `releaseQuantity`
FROM `gao_product_stock_record` r
INNER JOIN `gao_product` p ON p.`id` = r.`product_id` AND p.`store_id` = r.`store_id`
WHERE r.`store_id` = #{storeId}
AND r.`occurred_at` &gt;= #{beginAt}
AND r.`occurred_at` &lt;= #{endAt}
<if test="productId != null and productId != ''">AND r.`product_id` = #{productId}</if>
<if test="categoryId != null and categoryId != ''">AND p.`category_id` = #{categoryId}</if>
<if test="productType != null">AND p.`product_type` = #{productType}</if>
GROUP BY DATE_FORMAT(FROM_UNIXTIME(r.`occurred_at` / 1000), '%Y%m%d')
ORDER BY `dateValue` ASC
</select>
<select id="selectStockHealth" resultType="com.imyeyu.api.modules.gao.vo.GaoProductStockHealthView">
SELECT
p.`id` AS `productId`,
p.`name` AS `productName`,
p.`category_id` AS `categoryId`,
c.`name` AS `categoryName`,
p.`product_type` AS `productType`,
COALESCE(s.`on_hand_quantity`, 0) AS `onHandQuantity`,
COALESCE(s.`reserved_quantity`, 0) AS `reservedQuantity`,
COALESCE(s.`on_hand_quantity`, 0) - COALESCE(s.`reserved_quantity`, 0) AS `availableQuantity`,
p.`min_stock_quantity` AS `minStockQuantity`,
CASE WHEN p.`min_stock_quantity` IS NOT NULL
AND COALESCE(s.`on_hand_quantity`, 0) - COALESCE(s.`reserved_quantity`, 0) &lt; p.`min_stock_quantity`
THEN 1 ELSE 0 END AS `lowStock`
FROM `gao_product` p
LEFT JOIN `gao_product_category` c ON c.`id` = p.`category_id` AND c.`store_id` = p.`store_id` AND c.`deleted_at` IS NULL
LEFT JOIN `gao_product_stock` s ON s.`product_id` = p.`id` AND s.`store_id` = p.`store_id`
WHERE p.`store_id` = #{storeId}
AND p.`stock_enabled` = 1
<include refid="productFilter"/>
ORDER BY `lowStock` DESC, `availableQuantity` ASC, p.`sort` ASC, p.`name` ASC
LIMIT #{topN}
</select>
<select id="selectType" resultType="com.imyeyu.api.modules.gao.vo.GaoProductTypeStatView">
SELECT
p.`product_type` AS `productType`,
COUNT(1) AS `productCount`
FROM `gao_product` p
WHERE p.`store_id` = #{storeId}
<include refid="productFilter"/>
GROUP BY p.`product_type`
ORDER BY p.`product_type` ASC
</select>
<select id="selectCategory" resultType="com.imyeyu.api.modules.gao.vo.GaoProductCategoryStatView">
SELECT
p.`category_id` AS `categoryId`,
COALESCE(c.`name`, '未分类') AS `categoryName`,
COUNT(1) AS `productCount`
FROM `gao_product` p
LEFT JOIN `gao_product_category` c ON c.`id` = p.`category_id` AND c.`store_id` = p.`store_id` AND c.`deleted_at` IS NULL
WHERE p.`store_id` = #{storeId}
<include refid="productFilter"/>
GROUP BY p.`category_id`, c.`name`
ORDER BY `productCount` DESC, `categoryName` ASC
</select>
<select id="selectUnitSalesRank" resultType="com.imyeyu.api.modules.gao.vo.GaoProductUnitSalesRankView">
SELECT
i.`product_id` AS `productId`,
MAX(i.`product_name_snapshot`) AS `productName`,
i.`product_unit_id` AS `productUnitId`,
MAX(i.`unit_snapshot`) AS `unitName`,
COUNT(DISTINCT o.`id`) AS `orderCount`,
COALESCE(SUM(i.`quantity`), 0) AS `quantity`,
COALESCE(SUM(i.`line_amount`), 0) AS `saleAmount`
FROM `gao_sales_order_item` i
INNER JOIN `gao_sales_order` o ON o.`id` = i.`sales_order_id`
INNER JOIN `gao_product` p ON p.`id` = i.`product_id` AND p.`store_id` = o.`store_id`
WHERE i.`item_type` = 'DIRECT_PRODUCT'
<include refid="orderProductFilter"/>
GROUP BY i.`product_id`, i.`product_unit_id`
ORDER BY `quantity` DESC, `saleAmount` DESC, i.`product_id` ASC, i.`product_unit_id` ASC
LIMIT #{topN}
</select>
</mapper>
@@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imyeyu.api.modules.gao.mapper.GaoSalesOrderChartMapper">
<sql id="orderFilter">
AND o.`deleted_at` IS NULL
AND o.`store_id` = #{storeId}
<if test="customerId != null and customerId != ''">AND o.`customer_id` = #{customerId}</if>
<if test="orderType != null">AND o.`order_type` = #{orderType}</if>
<if test="status != null">AND o.`status` = #{status}</if>
<if test="paymentStatus != null">AND o.`payment_status` = #{paymentStatus}</if>
AND o.`purchased_at` &gt;= #{beginAt}
AND o.`purchased_at` &lt;= #{endAt}
</sql>
<select id="selectDaily" resultType="com.imyeyu.api.modules.gao.vo.GaoSalesOrderDailyStatView">
SELECT
CAST(DATE_FORMAT(FROM_UNIXTIME(o.`purchased_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
COUNT(1) AS `orderCount`,
COALESCE(SUM(o.`sale_amount`), 0) AS `saleAmount`,
COALESCE(SUM(o.`paid_amount`), 0) AS `paidAmount`,
COALESCE(SUM(o.`pending_paid_amount`), 0) AS `pendingPaidAmount`,
COALESCE(SUM(o.`refunded_amount`), 0) AS `refundedAmount`,
COALESCE(SUM(o.`paid_amount` - o.`refunded_amount`), 0) AS `netPaidAmount`
FROM `gao_sales_order` o
WHERE 1 = 1
<include refid="orderFilter"/>
GROUP BY DATE_FORMAT(FROM_UNIXTIME(o.`purchased_at` / 1000), '%Y%m%d')
ORDER BY `dateValue` ASC
</select>
<select id="selectType" resultType="com.imyeyu.api.modules.gao.vo.GaoSalesOrderTypeStatView">
SELECT
o.`order_type` AS `orderType`,
COUNT(1) AS `orderCount`,
COALESCE(SUM(o.`sale_amount`), 0) AS `saleAmount`,
COALESCE(SUM(o.`paid_amount`), 0) AS `paidAmount`,
COALESCE(SUM(o.`refunded_amount`), 0) AS `refundedAmount`,
COALESCE(SUM(o.`paid_amount` - o.`refunded_amount`), 0) AS `netPaidAmount`
FROM `gao_sales_order` o
WHERE 1 = 1
<include refid="orderFilter"/>
GROUP BY o.`order_type`
ORDER BY o.`order_type` ASC
</select>
<select id="selectPayment" resultType="com.imyeyu.api.modules.gao.vo.GaoSalesOrderPaymentStatView">
SELECT
o.`payment_status` AS `paymentStatus`,
COUNT(1) AS `orderCount`,
COALESCE(SUM(o.`sale_amount`), 0) AS `saleAmount`,
COALESCE(SUM(o.`paid_amount`), 0) AS `paidAmount`,
COALESCE(SUM(o.`pending_paid_amount`), 0) AS `pendingPaidAmount`,
COALESCE(SUM(o.`sale_amount` - o.`paid_amount`), 0) AS `unpaidAmount`,
COALESCE(SUM(o.`refunded_amount`), 0) AS `refundedAmount`
FROM `gao_sales_order` o
WHERE 1 = 1
<include refid="orderFilter"/>
GROUP BY o.`payment_status`
ORDER BY o.`payment_status` ASC
</select>
<select id="selectCustomerRank" resultType="com.imyeyu.api.modules.gao.vo.GaoCustomerOrderRankView">
SELECT
o.`customer_id` AS `customerId`,
c.`code` AS `customerCode`,
c.`name` AS `customerName`,
COUNT(1) AS `orderCount`,
COALESCE(SUM(o.`sale_amount`), 0) AS `saleAmount`,
COALESCE(SUM(o.`paid_amount`), 0) AS `paidAmount`,
COALESCE(SUM(o.`refunded_amount`), 0) AS `refundedAmount`,
COALESCE(SUM(o.`paid_amount` - o.`refunded_amount`), 0) AS `netPaidAmount`
FROM `gao_sales_order` o
LEFT JOIN `gao_customer` c ON c.`id` = o.`customer_id` AND c.`deleted_at` IS NULL
WHERE 1 = 1
<include refid="orderFilter"/>
<if test="status == null">AND o.`status` &lt;&gt; 'CANCELLED'</if>
GROUP BY o.`customer_id`, c.`code`, c.`name`
ORDER BY `netPaidAmount` DESC, `orderCount` DESC, o.`customer_id` ASC
LIMIT #{topN}
</select>
<select id="selectCustomerProductRank" resultType="com.imyeyu.api.modules.gao.vo.GaoCustomerOrderProductRankView">
SELECT
i.`product_id` AS `productId`,
MAX(i.`product_name_snapshot`) AS `productName`,
COUNT(DISTINCT o.`id`) AS `orderCount`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT' THEN i.`quantity` ELSE 0 END), 0) AS `directQuantity`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'PACKAGE_ENTITLEMENT' THEN i.`quantity` ELSE 0 END), 0) AS `packageQuantity`,
COALESCE(SUM(i.`reserved_quantity`), 0) AS `reservedQuantity`,
COALESCE(SUM(i.`fulfilled_quantity`), 0) AS `fulfilledQuantity`,
COALESCE(SUM(i.`quantity` - i.`reserved_quantity` - i.`fulfilled_quantity`), 0) AS `availableQuantity`,
COALESCE(SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT' THEN COALESCE(i.`line_amount`, 0) ELSE 0 END), 0) AS `directSaleAmount`
FROM `gao_sales_order_item` i
INNER JOIN `gao_sales_order` o ON o.`id` = i.`sales_order_id`
INNER JOIN `gao_product` p ON p.`id` = i.`product_id` AND p.`store_id` = o.`store_id`
WHERE o.`store_id` = #{storeId}
AND o.`customer_id` = #{customerId}
AND o.`deleted_at` IS NULL
AND i.`deleted_at` IS NULL
AND o.`status` &lt;&gt; 'CANCELLED'
AND o.`purchased_at` &gt;= #{beginAt}
AND o.`purchased_at` &lt;= #{endAt}
GROUP BY i.`product_id`
ORDER BY (SUM(CASE WHEN i.`item_type` = 'DIRECT_PRODUCT' THEN i.`quantity` ELSE 0 END)
+ SUM(CASE WHEN i.`item_type` = 'PACKAGE_ENTITLEMENT' THEN i.`quantity` ELSE 0 END)) DESC,
directSaleAmount DESC,
i.`product_id` ASC
LIMIT #{topN}
</select>
<select id="selectStatus" resultType="com.imyeyu.api.modules.gao.vo.GaoSalesOrderStatusStatView">
SELECT
o.`status` AS `status`,
COUNT(1) AS `orderCount`,
COALESCE(SUM(o.`sale_amount`), 0) AS `saleAmount`,
COALESCE(SUM(o.`paid_amount`), 0) AS `paidAmount`,
COALESCE(SUM(o.`refunded_amount`), 0) AS `refundedAmount`
FROM `gao_sales_order` o
WHERE 1 = 1
<include refid="orderFilter"/>
GROUP BY o.`status`
ORDER BY o.`status` ASC
</select>
<select id="selectReceivable" resultType="com.imyeyu.api.modules.gao.vo.GaoSalesOrderReceivableStatView">
SELECT
COUNT(1) AS `orderCount`,
COALESCE(SUM(o.`sale_amount`), 0) AS `saleAmount`,
COALESCE(SUM(o.`paid_amount`), 0) AS `paidAmount`,
COALESCE(SUM(o.`pending_paid_amount`), 0) AS `pendingPaidAmount`,
COALESCE(SUM(o.`sale_amount` - o.`paid_amount`), 0) AS `unpaidAmount`,
COALESCE(SUM(o.`refunded_amount`), 0) AS `refundedAmount`,
COALESCE(SUM(o.`paid_amount` - o.`refunded_amount`), 0) AS `netPaidAmount`
FROM `gao_sales_order` o
WHERE 1 = 1
<include refid="orderFilter"/>
</select>
<select id="selectConsumptionDaily" resultType="com.imyeyu.api.modules.gao.vo.GaoSalesOrderConsumptionDailyStatView">
WITH `daily_stat` AS (
SELECT
CAST(DATE_FORMAT(FROM_UNIXTIME(r.`effective_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
COUNT(1) AS `recordCount`,
COALESCE(SUM(r.`amount`), 0) AS `amount`
FROM `gao_customer_consumption_record` r
WHERE r.`store_id` = #{storeId}
AND r.`status` = 'ACTIVE'
AND r.`effective_at` &gt;= #{beginAt}
AND r.`effective_at` &lt;= #{endAt}
AND r.`deleted_at` IS NULL
<if test="customerId != null and customerId != ''">AND r.`customer_id` = #{customerId}</if>
<if test="orderType != null">AND r.`order_type` = #{orderType}</if>
GROUP BY DATE_FORMAT(FROM_UNIXTIME(r.`effective_at` / 1000), '%Y%m%d')
)
SELECT
`dateValue`,
`recordCount`,
`amount`,
SUM(`amount`) OVER (ORDER BY `dateValue` ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS `cumulativeAmount`
FROM `daily_stat`
ORDER BY `dateValue` ASC
</select>
<select id="selectCalendar" resultType="com.imyeyu.api.modules.gao.vo.GaoSalesOrderCalendarStatView">
SELECT
CAST(DATE_FORMAT(FROM_UNIXTIME(o.`purchased_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
COUNT(1) AS `orderCount`,
COALESCE(SUM(o.`sale_amount`), 0) AS `saleAmount`,
COALESCE(SUM(o.`paid_amount` - o.`refunded_amount`), 0) AS `netPaidAmount`
FROM `gao_sales_order` o
WHERE 1 = 1
<include refid="orderFilter"/>
GROUP BY DATE_FORMAT(FROM_UNIXTIME(o.`purchased_at` / 1000), '%Y%m%d')
ORDER BY `dateValue` ASC
</select>
<sql id="repeatOrderFilter">
AND o.`deleted_at` IS NULL
AND o.`store_id` = #{storeId}
<if test="customerId != null and customerId != ''">AND o.`customer_id` = #{customerId}</if>
<if test="orderType != null">AND o.`order_type` = #{orderType}</if>
<choose>
<when test="status != null">AND o.`status` = #{status}</when>
<otherwise>AND o.`status` &lt;&gt; 'CANCELLED'</otherwise>
</choose>
AND o.`purchased_at` &lt;= #{endAt}
</sql>
<select id="selectRepeatDaily" resultType="com.imyeyu.api.modules.gao.vo.GaoCustomerRepeatDailyStatView">
WITH `ranked_order` AS (
SELECT
o.`customer_id`,
o.`purchased_at`,
LAG(o.`purchased_at`) OVER (PARTITION BY o.`customer_id` ORDER BY o.`purchased_at`, o.`id`) AS `previous_purchased_at`
FROM `gao_sales_order` o
WHERE 1 = 1
<include refid="repeatOrderFilter"/>
)
SELECT
CAST(DATE_FORMAT(FROM_UNIXTIME(r.`purchased_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
COUNT(DISTINCT r.`customer_id`) AS `customerCount`,
COUNT(DISTINCT CASE WHEN r.`previous_purchased_at` IS NOT NULL THEN r.`customer_id` END) AS `repeatCustomerCount`,
SUM(CASE WHEN r.`previous_purchased_at` IS NOT NULL THEN 1 ELSE 0 END) AS `repeatOrderCount`
FROM `ranked_order` r
WHERE r.`purchased_at` &gt;= #{beginAt}
GROUP BY DATE_FORMAT(FROM_UNIXTIME(r.`purchased_at` / 1000), '%Y%m%d')
ORDER BY `dateValue` ASC
</select>
<select id="selectRepeatInterval" resultType="com.imyeyu.api.modules.gao.vo.GaoCustomerRepeatIntervalStatView">
WITH `ranked_order` AS (
SELECT
o.`customer_id`,
o.`purchased_at`,
LAG(o.`purchased_at`) OVER (PARTITION BY o.`customer_id` ORDER BY o.`purchased_at`, o.`id`) AS `previous_purchased_at`
FROM `gao_sales_order` o
WHERE 1 = 1
<include refid="repeatOrderFilter"/>
)
SELECT
TIMESTAMPDIFF(DAY, FROM_UNIXTIME(r.`previous_purchased_at` / 1000), FROM_UNIXTIME(r.`purchased_at` / 1000)) AS `intervalDays`,
COUNT(DISTINCT r.`customer_id`) AS `customerCount`,
COUNT(1) AS `orderCount`
FROM `ranked_order` r
WHERE r.`previous_purchased_at` IS NOT NULL
AND r.`purchased_at` &gt;= #{beginAt}
GROUP BY TIMESTAMPDIFF(DAY, FROM_UNIXTIME(r.`previous_purchased_at` / 1000), FROM_UNIXTIME(r.`purchased_at` / 1000))
ORDER BY `intervalDays` ASC
</select>
</mapper>