464 lines
14 KiB
SQL
464 lines
14 KiB
SQL
-- ============================================
|
||
-- 数据分析模块测试数据 Seed(Supabase/Postgres)
|
||
-- ============================================
|
||
-- 用途:为 `pages/mall/analytics/*` 页面提供可联调的模拟数据
|
||
-- 参考:`docs/ANALYTICS_DB_DESIGN.md`
|
||
--
|
||
-- 执行顺序:
|
||
-- 1. 先执行基础业务表的 seed(users/merchants/products/orders等)
|
||
-- 2. 再执行本文档(analytics_* 表 + 基础表补充数据)
|
||
--
|
||
-- ⚠️ 重要(RLS):
|
||
-- 本脚本会写入已启用 RLS 的表(orders/user_sessions/page_views/analytics_*)。
|
||
-- 请使用 Supabase Dashboard SQL Editor(等价于 postgres/service_role)执行,
|
||
-- 不要用 anon/authenticated 直接执行,否则会被 RLS 策略拦截。
|
||
-- ============================================
|
||
|
||
-- ============================================
|
||
-- 1. 基础业务表补充数据(如果还没有)
|
||
-- ============================================
|
||
|
||
-- 1.1 确保有测试用户(分析师)
|
||
-- 注意:如果 users 表已通过 02_insert_test_data.sql 插入数据,这里可以跳过或补充
|
||
INSERT INTO users (id, phone, email, nickname, last_login_at, created_at)
|
||
VALUES
|
||
('00000000-0000-0000-0000-000000000001', '13800001001', 'analyst1@test.com', '分析师张三', NOW() - INTERVAL '1 day', NOW() - INTERVAL '30 days'),
|
||
('00000000-0000-0000-0000-000000000002', '13800001002', 'analyst2@test.com', '分析师李四', NOW() - INTERVAL '2 days', NOW() - INTERVAL '20 days')
|
||
ON CONFLICT (id) DO NOTHING;
|
||
|
||
-- 1.2 确保有测试商家
|
||
-- 注意:如果 merchants 表已通过 02_insert_test_data.sql 插入数据,这里可以跳过或补充
|
||
INSERT INTO merchants (id, shop_name, created_at)
|
||
VALUES
|
||
('10000000-0000-0000-0000-000000000001', '测试商家A', NOW() - INTERVAL '60 days'),
|
||
('10000000-0000-0000-0000-000000000002', '测试商家B', NOW() - INTERVAL '50 days')
|
||
ON CONFLICT (id) DO NOTHING;
|
||
|
||
-- 1.3 确保有测试商品
|
||
-- 注意:如果 products 表已通过 02_insert_test_data.sql 插入数据,这里可以跳过或补充
|
||
INSERT INTO products (id, merchant_id, name, price, sales, status, created_at)
|
||
VALUES
|
||
('20000000-0000-0000-0000-000000000001', '10000000-0000-0000-0000-000000000001', '测试商品1', 99.00, 50, 1, NOW() - INTERVAL '40 days'),
|
||
('20000000-0000-0000-0000-000000000002', '10000000-0000-0000-0000-000000000001', '测试商品2', 199.00, 30, 1, NOW() - INTERVAL '35 days'),
|
||
('20000000-0000-0000-0000-000000000003', '10000000-0000-0000-0000-000000000002', '测试商品3', 299.00, 20, 1, NOW() - INTERVAL '30 days')
|
||
ON CONFLICT (id) DO NOTHING;
|
||
|
||
-- 1.4 生成过去30天的测试订单(用于首页实时KPI和趋势)
|
||
DO $$
|
||
DECLARE
|
||
i INTEGER;
|
||
j INTEGER;
|
||
order_date DATE;
|
||
order_id UUID;
|
||
user_id_val UUID := '00000000-0000-0000-0000-000000000001';
|
||
merchant_id_val UUID := '10000000-0000-0000-0000-000000000001';
|
||
product_id_val UUID := '20000000-0000-0000-0000-000000000001';
|
||
BEGIN
|
||
FOR i IN 0..29 LOOP
|
||
order_date := CURRENT_DATE - (29 - i);
|
||
|
||
-- 每天生成 5-15 个订单
|
||
FOR j IN 1..(5 + (i % 11)) LOOP
|
||
order_id := gen_random_uuid();
|
||
|
||
-- 插入订单(状态2=已支付/已完成)
|
||
INSERT INTO orders (
|
||
id, user_id, merchant_id, status, total_amount, payment_method, created_at
|
||
)
|
||
VALUES (
|
||
order_id,
|
||
user_id_val,
|
||
merchant_id_val,
|
||
2, -- 已支付/已完成
|
||
(50 + (j * 10) + (i * 2))::numeric(10,2),
|
||
'alipay',
|
||
order_date + (random() * INTERVAL '1 day')
|
||
)
|
||
ON CONFLICT (id) DO NOTHING;
|
||
|
||
-- 插入订单商品
|
||
INSERT INTO order_items (
|
||
id, order_id, product_id, quantity, price, total_amount, created_at
|
||
)
|
||
VALUES (
|
||
gen_random_uuid(),
|
||
order_id,
|
||
product_id_val,
|
||
1,
|
||
(50 + (j * 10))::numeric(10,2),
|
||
(50 + (j * 10))::numeric(10,2),
|
||
order_date + (random() * INTERVAL '1 day')
|
||
)
|
||
ON CONFLICT (id) DO NOTHING;
|
||
END LOOP;
|
||
END LOOP;
|
||
END $$;
|
||
|
||
-- 1.5 插入 user_sessions(在线用户/访问用户统计)
|
||
INSERT INTO user_sessions (id, user_id, created_at, last_active_at, is_active)
|
||
VALUES
|
||
(gen_random_uuid(), '00000000-0000-0000-0000-000000000001', NOW() - INTERVAL '10 minutes', NOW() - INTERVAL '1 minutes', TRUE),
|
||
(gen_random_uuid(), '00000000-0000-0000-0000-000000000002', NOW() - INTERVAL '8 minutes', NOW() - INTERVAL '2 minutes', TRUE),
|
||
(gen_random_uuid(), '00000000-0000-0000-0000-000000000001', NOW() - INTERVAL '20 minutes', NOW() - INTERVAL '6 minutes', FALSE)
|
||
ON CONFLICT DO NOTHING;
|
||
|
||
-- 1.6 插入 page_views(流量来源统计)
|
||
DO $$
|
||
DECLARE
|
||
i INTEGER;
|
||
v_date DATE;
|
||
v_source TEXT;
|
||
BEGIN
|
||
FOR i IN 0..29 LOOP
|
||
v_date := CURRENT_DATE - (29 - i);
|
||
v_source := CASE
|
||
WHEN (i % 4) = 0 THEN 'direct'
|
||
WHEN (i % 4) = 1 THEN 'search'
|
||
WHEN (i % 4) = 2 THEN 'social'
|
||
ELSE 'ad'
|
||
END;
|
||
INSERT INTO page_views (id, user_id, path, source, created_at)
|
||
VALUES
|
||
(gen_random_uuid(), '00000000-0000-0000-0000-000000000001', '/pages/mall/analytics/index', v_source, v_date + (random() * INTERVAL '1 day'))
|
||
ON CONFLICT DO NOTHING;
|
||
END LOOP;
|
||
END $$;
|
||
|
||
-- ============================================
|
||
-- 2. Analytics 表数据
|
||
-- ============================================
|
||
|
||
-- 2.1 分析师偏好设置
|
||
INSERT INTO analytics_user_preferences (id, user_id, default_period, timezone, currency, kpi_cards, created_at, updated_at)
|
||
VALUES
|
||
(
|
||
gen_random_uuid(),
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'7d',
|
||
'Asia/Shanghai',
|
||
'CNY',
|
||
'["gmv", "orders", "users", "conversion"]'::jsonb,
|
||
NOW() - INTERVAL '10 days',
|
||
NOW()
|
||
),
|
||
(
|
||
gen_random_uuid(),
|
||
'00000000-0000-0000-0000-000000000002',
|
||
'30d',
|
||
'Asia/Shanghai',
|
||
'CNY',
|
||
'["gmv", "orders"]'::jsonb,
|
||
NOW() - INTERVAL '5 days',
|
||
NOW()
|
||
)
|
||
ON CONFLICT (user_id) DO UPDATE SET
|
||
default_period = EXCLUDED.default_period,
|
||
updated_at = NOW();
|
||
|
||
-- 2.2 报表定义(3个示例报表)
|
||
INSERT INTO analytics_reports (
|
||
id, owner_user_id, merchant_id, title, description, type, period,
|
||
date_start, date_end, status, generated_at, created_at, updated_at
|
||
)
|
||
VALUES
|
||
(
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
'00000000-0000-0000-0000-000000000001',
|
||
NULL,
|
||
'销售报表 - 近7天',
|
||
'展示近7天的销售趋势和核心指标',
|
||
'sales',
|
||
'7d',
|
||
CURRENT_DATE - 7,
|
||
CURRENT_DATE,
|
||
'ready',
|
||
NOW() - INTERVAL '1 hour',
|
||
NOW() - INTERVAL '2 days',
|
||
NOW() - INTERVAL '1 hour'
|
||
),
|
||
(
|
||
'a0000000-0000-0000-0000-000000000002',
|
||
'00000000-0000-0000-0000-000000000001',
|
||
NULL,
|
||
'用户分析报表 - 近30天',
|
||
'用户增长、活跃度、留存率分析',
|
||
'users',
|
||
'30d',
|
||
CURRENT_DATE - 30,
|
||
CURRENT_DATE,
|
||
'ready',
|
||
NOW() - INTERVAL '2 hours',
|
||
NOW() - INTERVAL '5 days',
|
||
NOW() - INTERVAL '2 hours'
|
||
),
|
||
(
|
||
'a0000000-0000-0000-0000-000000000003',
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'10000000-0000-0000-0000-000000000001',
|
||
'商家销售报表 - 近90天',
|
||
'商家A的销售表现分析',
|
||
'sales',
|
||
'90d',
|
||
CURRENT_DATE - 90,
|
||
CURRENT_DATE,
|
||
'ready',
|
||
NOW() - INTERVAL '30 minutes',
|
||
NOW() - INTERVAL '10 days',
|
||
NOW() - INTERVAL '30 minutes'
|
||
)
|
||
ON CONFLICT (id) DO NOTHING;
|
||
|
||
-- 2.3 报表核心指标(为第一个报表生成)
|
||
INSERT INTO analytics_report_metrics (
|
||
id, report_id, metric_key, metric_label, metric_value_num, metric_value_text,
|
||
format, change_pct, icon, color, created_at
|
||
)
|
||
VALUES
|
||
(
|
||
gen_random_uuid(),
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
'gmv',
|
||
'GMV',
|
||
125680.50,
|
||
NULL,
|
||
'currency',
|
||
15.6,
|
||
'money',
|
||
'#3b82f6',
|
||
NOW()
|
||
),
|
||
(
|
||
gen_random_uuid(),
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
'orders',
|
||
'订单量',
|
||
856,
|
||
NULL,
|
||
'number',
|
||
12.3,
|
||
'list',
|
||
'#10b981',
|
||
NOW()
|
||
),
|
||
(
|
||
gen_random_uuid(),
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
'conversion_rate',
|
||
'转化率',
|
||
3.45,
|
||
NULL,
|
||
'percent',
|
||
0.8,
|
||
'trend',
|
||
'#f59e0b',
|
||
NOW()
|
||
),
|
||
(
|
||
gen_random_uuid(),
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
'avg_order_amount',
|
||
'客单价',
|
||
146.82,
|
||
NULL,
|
||
'currency',
|
||
-2.1,
|
||
'wallet',
|
||
'#8b5cf6',
|
||
NOW()
|
||
)
|
||
ON CONFLICT DO NOTHING;
|
||
|
||
-- 2.4 报表明细行(趋势数据,为第一个报表生成过去7天的数据)
|
||
DO $$
|
||
DECLARE
|
||
i INTEGER;
|
||
row_date DATE;
|
||
report_id_val UUID := 'a0000000-0000-0000-0000-000000000001';
|
||
BEGIN
|
||
FOR i IN 0..6 LOOP
|
||
row_date := CURRENT_DATE - (6 - i);
|
||
|
||
INSERT INTO analytics_report_rows (
|
||
id, report_id, row_date, gmv, orders, users, conversion, avg_order_amount, extra, created_at
|
||
)
|
||
VALUES (
|
||
gen_random_uuid(),
|
||
report_id_val,
|
||
row_date,
|
||
(15000 + (i * 2000) + (random() * 3000))::numeric(10,2),
|
||
(100 + (i * 15) + floor(random() * 30))::integer,
|
||
(80 + (i * 10) + floor(random() * 20))::integer,
|
||
(3.0 + (i * 0.1) + (random() * 0.5))::numeric(5,2),
|
||
(140 + (i * 2) + (random() * 20))::numeric(10,2),
|
||
'{}'::jsonb,
|
||
NOW()
|
||
)
|
||
ON CONFLICT DO NOTHING;
|
||
END LOOP;
|
||
END $$;
|
||
|
||
-- 2.5 数据洞察(为第一个报表生成3条洞察)
|
||
INSERT INTO analytics_insights (
|
||
id, report_id, owner_user_id, type, impact, title, content, tags, created_at
|
||
)
|
||
VALUES
|
||
(
|
||
gen_random_uuid(),
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'positive',
|
||
'high',
|
||
'GMV持续增长',
|
||
'近7天GMV较上周期增长15.6%,主要得益于新用户增长和促销活动',
|
||
ARRAY['销售', '增长']::text[],
|
||
NOW() - INTERVAL '1 hour'
|
||
),
|
||
(
|
||
gen_random_uuid(),
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'warning',
|
||
'medium',
|
||
'客单价略有下降',
|
||
'客单价较上周期下降2.1%,建议关注高价值商品推广',
|
||
ARRAY['客单价', '预警']::text[],
|
||
NOW() - INTERVAL '1 hour'
|
||
),
|
||
(
|
||
gen_random_uuid(),
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'info',
|
||
'low',
|
||
'转化率稳定',
|
||
'转化率保持在3.45%,与行业平均水平相当',
|
||
ARRAY['转化率']::text[],
|
||
NOW() - INTERVAL '1 hour'
|
||
)
|
||
ON CONFLICT DO NOTHING;
|
||
|
||
-- 2.6 报表收藏
|
||
INSERT INTO analytics_report_favorites (id, user_id, report_id, created_at)
|
||
VALUES
|
||
(
|
||
gen_random_uuid(),
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
NOW() - INTERVAL '1 day'
|
||
),
|
||
(
|
||
gen_random_uuid(),
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'a0000000-0000-0000-0000-000000000002',
|
||
NOW() - INTERVAL '2 days'
|
||
)
|
||
ON CONFLICT (user_id, report_id) DO NOTHING;
|
||
|
||
-- 2.7 导出任务历史
|
||
INSERT INTO analytics_export_jobs (
|
||
id, user_id, report_id, format, status, file_path, error_message, created_at, finished_at
|
||
)
|
||
VALUES
|
||
(
|
||
gen_random_uuid(),
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'a0000000-0000-0000-0000-000000000001',
|
||
'xlsx',
|
||
'done',
|
||
'exports/report_001.xlsx',
|
||
'',
|
||
NOW() - INTERVAL '3 days',
|
||
NOW() - INTERVAL '3 days' + INTERVAL '5 minutes'
|
||
),
|
||
(
|
||
gen_random_uuid(),
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'a0000000-0000-0000-0000-000000000002',
|
||
'pdf',
|
||
'done',
|
||
'exports/report_002.pdf',
|
||
'',
|
||
NOW() - INTERVAL '1 day',
|
||
NOW() - INTERVAL '1 day' + INTERVAL '2 minutes'
|
||
),
|
||
(
|
||
gen_random_uuid(),
|
||
'00000000-0000-0000-0000-000000000001',
|
||
'a0000000-0000-0000-0000-000000000003',
|
||
'csv',
|
||
'running',
|
||
NULL,
|
||
'',
|
||
NOW() - INTERVAL '10 minutes',
|
||
NULL
|
||
)
|
||
ON CONFLICT DO NOTHING;
|
||
|
||
-- ============================================
|
||
-- 3. 补充报表明细行(为其他报表生成数据)
|
||
-- ============================================
|
||
|
||
-- 为第二个报表(用户分析报表)生成过去30天的趋势数据
|
||
DO $$
|
||
DECLARE
|
||
i INTEGER;
|
||
row_date DATE;
|
||
report_id_val UUID := 'a0000000-0000-0000-0000-000000000002';
|
||
BEGIN
|
||
FOR i IN 0..29 LOOP
|
||
row_date := CURRENT_DATE - (29 - i);
|
||
|
||
INSERT INTO analytics_report_rows (
|
||
id, report_id, row_date, gmv, orders, users, conversion, avg_order_amount, extra, created_at
|
||
)
|
||
VALUES (
|
||
gen_random_uuid(),
|
||
report_id_val,
|
||
row_date,
|
||
(18000 + (i * 500) + (random() * 2000))::numeric(10,2),
|
||
(120 + (i * 3) + floor(random() * 20))::integer,
|
||
(90 + (i * 2) + floor(random() * 15))::integer,
|
||
(3.2 + (i * 0.05) + (random() * 0.3))::numeric(5,2),
|
||
(150 + (i * 1) + (random() * 30))::numeric(10,2),
|
||
'{}'::jsonb,
|
||
NOW()
|
||
)
|
||
ON CONFLICT DO NOTHING;
|
||
END LOOP;
|
||
END $$;
|
||
|
||
-- 为第三个报表(商家销售报表)生成过去90天的趋势数据
|
||
DO $$
|
||
DECLARE
|
||
i INTEGER;
|
||
row_date DATE;
|
||
report_id_val UUID := 'a0000000-0000-0000-0000-000000000003';
|
||
BEGIN
|
||
FOR i IN 0..89 LOOP
|
||
row_date := CURRENT_DATE - (89 - i);
|
||
|
||
INSERT INTO analytics_report_rows (
|
||
id, report_id, row_date, gmv, orders, users, conversion, avg_order_amount, extra, created_at
|
||
)
|
||
VALUES (
|
||
gen_random_uuid(),
|
||
report_id_val,
|
||
row_date,
|
||
(20000 + (i * 100) + (random() * 3000))::numeric(10,2),
|
||
(150 + (i * 1) + floor(random() * 30))::integer,
|
||
(100 + (i * 1) + floor(random() * 20))::integer,
|
||
(3.5 + (i * 0.01) + (random() * 0.4))::numeric(5,2),
|
||
(130 + (i * 0.5) + (random() * 40))::numeric(10,2),
|
||
'{}'::jsonb,
|
||
NOW()
|
||
)
|
||
ON CONFLICT DO NOTHING;
|
||
END LOOP;
|
||
END $$;
|
||
|
||
-- ============================================
|
||
-- 完成
|
||
-- ============================================
|
||
|
||
SELECT 'Analytics test data seed completed!' AS message;
|