创建会员开单耗卡项目数视图.sql 8.59 KB
-- ============================================
-- 创建会员开单耗卡项目数视图
-- ============================================
-- 说明:创建视图可以提升查询效率,避免每次都执行复杂的JOIN和聚合操作
-- 视图会预先聚合好数据,查询时直接使用

-- ============================================
-- 方案1:基础聚合视图(推荐)
-- ============================================
-- 优点:查询简单、性能好、可以灵活按时间范围查询
-- 缺点:仍然需要每次查询时过滤时间范围

-- 删除已存在的视图(如果存在)
DROP VIEW IF EXISTS v_member_billing_consume_project;

-- 创建视图:会员开单项目数汇总(不限制时间,包含所有数据)
CREATE VIEW v_member_billing_project AS
SELECT 
    px.F_MemberId as member_id,
    kd.djmd as store_id,
    kd.kdrq as billing_date,
    SUM(CAST(px.F_ProjectNumber AS DECIMAL(18,2))) as billing_project_count
FROM lq_kd_pxmx px
INNER JOIN lq_kd_kdjlb kd ON px.glkdbh = kd.F_Id
WHERE px.F_IsEffective = 1
    AND kd.F_IsEffective = 1
    AND px.F_MemberId IS NOT NULL
    AND px.F_MemberId != ''
GROUP BY px.F_MemberId, kd.djmd, DATE(kd.kdrq);

-- 创建视图:会员耗卡项目数汇总(不限制时间,包含所有数据)
CREATE VIEW v_member_consume_project AS
SELECT 
    xhpx.F_MemberId as member_id,
    xh.md as store_id,
    xh.hksj as consume_date,
    SUM(CAST(xhpx.F_ProjectNumber AS DECIMAL(18,2))) as consume_project_count
FROM lq_xh_pxmx xhpx
INNER JOIN lq_xh_hyhk xh ON xhpx.F_ConsumeInfoId = xh.F_Id
WHERE xhpx.F_IsEffective = 1
    AND xh.F_IsEffective = 1
    AND xhpx.F_MemberId IS NOT NULL
    AND xhpx.F_MemberId != ''
GROUP BY xhpx.F_MemberId, xh.md, DATE(xh.hksj);

-- 创建组合视图:会员开单耗卡项目数(按日汇总)
CREATE VIEW v_member_billing_consume_daily AS
SELECT 
    COALESCE(billing.member_id, consume.member_id) as member_id,
    COALESCE(billing.store_id, consume.store_id) as store_id,
    COALESCE(billing.billing_date, consume.consume_date) as statistics_date,
    COALESCE(billing.billing_project_count, 0) as billing_project_count,
    COALESCE(consume.consume_project_count, 0) as consume_project_count,
    (COALESCE(billing.billing_project_count, 0) - COALESCE(consume.consume_project_count, 0)) as remaining_project_count
FROM v_member_billing_project billing
FULL OUTER JOIN v_member_consume_project consume 
    ON billing.member_id = consume.member_id 
    AND billing.store_id = consume.store_id
    AND DATE(billing.billing_date) = DATE(consume.consume_date);

-- ============================================
-- 方案2:使用UNION ALL的视图(兼容MySQL,推荐)
-- ============================================
-- 优点:兼容MySQL所有版本、查询简单、性能好

DROP VIEW IF EXISTS v_member_billing_consume_project;

CREATE VIEW v_member_billing_consume_project AS
SELECT 
    member_id,
    store_id,
    statistics_date,
    SUM(billing_project_count) as billing_project_count,
    SUM(consume_project_count) as consume_project_count,
    SUM(billing_project_count) - SUM(consume_project_count) as remaining_project_count
FROM (
    -- 开单项目数(按会员、门店、日期分组)
    SELECT 
        px.F_MemberId as member_id,
        kd.djmd as store_id,
        DATE(kd.kdrq) as statistics_date,
        SUM(CAST(px.F_ProjectNumber AS DECIMAL(18,2))) as billing_project_count,
        0 as consume_project_count
    FROM lq_kd_pxmx px
    INNER JOIN lq_kd_kdjlb kd ON px.glkdbh = kd.F_Id
    WHERE px.F_IsEffective = 1
        AND kd.F_IsEffective = 1
        AND px.F_MemberId IS NOT NULL
        AND px.F_MemberId != ''
    GROUP BY px.F_MemberId, kd.djmd, DATE(kd.kdrq)
    
    UNION ALL
    
    -- 耗卡项目数(按会员、门店、日期分组)
    SELECT 
        xhpx.F_MemberId as member_id,
        xh.md as store_id,
        DATE(xh.hksj) as statistics_date,
        0 as billing_project_count,
        SUM(CAST(xhpx.F_ProjectNumber AS DECIMAL(18,2))) as consume_project_count
    FROM lq_xh_pxmx xhpx
    INNER JOIN lq_xh_hyhk xh ON xhpx.F_ConsumeInfoId = xh.F_Id
    WHERE xhpx.F_IsEffective = 1
        AND xh.F_IsEffective = 1
        AND xhpx.F_MemberId IS NOT NULL
        AND xhpx.F_MemberId != ''
    GROUP BY xhpx.F_MemberId, xh.md, DATE(xh.hksj)
) all_data
GROUP BY member_id, store_id, statistics_date;

-- ============================================
-- 方案3:按会员汇总的总视图(不按日期,累计汇总)
-- ============================================
-- 优点:查询最简单、性能最好(适合查询总量)
-- 缺点:无法按时间范围查询

DROP VIEW IF EXISTS v_member_billing_consume_total;

CREATE VIEW v_member_billing_consume_total AS
SELECT 
    member_id,
    SUM(billing_project_count) as total_billing_project_count,
    SUM(consume_project_count) as total_consume_project_count,
    SUM(billing_project_count) - SUM(consume_project_count) as total_remaining_project_count,
    COUNT(DISTINCT store_id) as store_count
FROM (
    -- 开单项目数(按会员、门店汇总)
    SELECT 
        px.F_MemberId as member_id,
        kd.djmd as store_id,
        SUM(CAST(px.F_ProjectNumber AS DECIMAL(18,2))) as billing_project_count,
        0 as consume_project_count
    FROM lq_kd_pxmx px
    INNER JOIN lq_kd_kdjlb kd ON px.glkdbh = kd.F_Id
    WHERE px.F_IsEffective = 1
        AND kd.F_IsEffective = 1
        AND px.F_MemberId IS NOT NULL
        AND px.F_MemberId != ''
    GROUP BY px.F_MemberId, kd.djmd
    
    UNION ALL
    
    -- 耗卡项目数(按会员、门店汇总)
    SELECT 
        xhpx.F_MemberId as member_id,
        xh.md as store_id,
        0 as billing_project_count,
        SUM(CAST(xhpx.F_ProjectNumber AS DECIMAL(18,2))) as consume_project_count
    FROM lq_xh_pxmx xhpx
    INNER JOIN lq_xh_hyhk xh ON xhpx.F_ConsumeInfoId = xh.F_Id
    WHERE xhpx.F_IsEffective = 1
        AND xh.F_IsEffective = 1
        AND xhpx.F_MemberId IS NOT NULL
        AND xhpx.F_MemberId != ''
    GROUP BY xhpx.F_MemberId, xh.md
) all_data
GROUP BY member_id;


-- ============================================
-- 使用视图的查询示例
-- ============================================

-- 示例1:查询所有会员的开单耗卡项目数(按会员汇总,不限制时间)
SELECT 
    member_id,
    SUM(billing_project_count) as billing_project_count,
    SUM(consume_project_count) as consume_project_count,
    SUM(remaining_project_count) as remaining_project_count
FROM v_member_billing_consume_project
GROUP BY member_id
ORDER BY billing_project_count DESC;

-- 示例2:查询指定时间范围内的数据
SELECT 
    member_id,
    SUM(billing_project_count) as billing_project_count,
    SUM(consume_project_count) as consume_project_count,
    SUM(remaining_project_count) as remaining_project_count
FROM v_member_billing_consume_project
WHERE statistics_date >= '2025-10-01'
    AND statistics_date <= '2025-10-30'
GROUP BY member_id
ORDER BY billing_project_count DESC;

-- 示例3:查询指定门店的数据
SELECT 
    member_id,
    SUM(billing_project_count) as billing_project_count,
    SUM(consume_project_count) as consume_project_count,
    SUM(remaining_project_count) as remaining_project_count
FROM v_member_billing_consume_project
WHERE store_id = '1649328471923847169'
    AND statistics_date >= '2025-10-01'
    AND statistics_date <= '2025-10-30'
GROUP BY member_id
ORDER BY billing_project_count DESC;

-- 示例4:使用总视图(最简单的查询,累计所有数据)
SELECT 
    member_id,
    total_billing_project_count,
    total_consume_project_count,
    total_remaining_project_count,
    store_count
FROM v_member_billing_consume_total
ORDER BY total_billing_project_count DESC
LIMIT 100;


-- ============================================
-- 视图性能优化建议
-- ============================================
-- 1. 确保基础表已创建索引(参考优化GetStoreRemainingRights性能索引.sql)
-- 2. 如果数据量很大,可以考虑:
--    a. 创建物化视图(但MySQL不支持,需要定期刷新汇总表)
--    b. 创建汇总表,定期更新(推荐)
-- 3. 定期分析视图性能:
--    EXPLAIN SELECT * FROM v_member_billing_consume_project WHERE statistics_date >= '2025-10-01';

-- ============================================
-- 视图维护
-- ============================================
-- 查看视图定义
-- SHOW CREATE VIEW v_member_billing_consume_project;

-- 查看所有视图
-- SELECT TABLE_NAME 
-- FROM INFORMATION_SCHEMA.VIEWS 
-- WHERE TABLE_SCHEMA = DATABASE();

-- 删除视图
-- DROP VIEW IF EXISTS v_member_billing_consume_project;
-- DROP VIEW IF EXISTS v_member_billing_consume_total;