-- ============================================= -- 优惠券业务基础表(最小集,用于优惠券效果分析) -- 说明: -- - 基于项目规格文档 pages/mall/mall.md 第4节“优惠券系统”抽象而来。 -- - 仅创建 Analytics 所需的最小字段集合,兼容后续完整业务表替换。 -- - 可安全重复执行(IF NOT EXISTS + 列存在性检查)。 -- - 依赖:merchants、orders 表已存在(由 01_create_tables.sql 提供)。 -- ============================================= -- 1) 优惠券模板表(coupon_templates) CREATE TABLE IF NOT EXISTS public.coupon_templates ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name text NOT NULL, description text, coupon_type integer NOT NULL, -- 1..8:满减/折扣/免运费/新人/会员/品类/商家/限时(见 mall.md) discount_type integer NOT NULL, -- 满减 / 折扣 / 免运费 等类型枚举 discount_value numeric(10,2) NOT NULL, -- 金额或折扣值 min_order_amount numeric(10,2) DEFAULT 0, max_discount_amount numeric(10,2), total_quantity integer, per_user_limit integer DEFAULT 1, usage_limit integer DEFAULT 1, merchant_id uuid, category_ids jsonb, product_ids jsonb, user_type_limit integer, start_time timestamptz NOT NULL, end_time timestamptz NOT NULL, status integer DEFAULT 1, created_at timestamptz DEFAULT now() ); DO $$ BEGIN -- 若缺少 merchant_id 外键且 merchants 表存在,则补充外键 IF EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'merchants' ) THEN IF NOT EXISTS ( SELECT 1 FROM pg_constraint c JOIN pg_class t ON t.oid = c.conrelid JOIN pg_namespace n ON n.oid = t.relnamespace WHERE n.nspname = 'public' AND t.relname = 'coupon_templates' AND c.conname = 'coupon_templates_merchant_id_fkey' ) THEN ALTER TABLE public.coupon_templates ADD CONSTRAINT coupon_templates_merchant_id_fkey FOREIGN KEY (merchant_id) REFERENCES public.merchants(id) ON DELETE SET NULL; END IF; END IF; END; $$; COMMENT ON TABLE public.coupon_templates IS '优惠券模板表(业务权威表,来自 mall.md)'; COMMENT ON COLUMN public.coupon_templates.coupon_type IS '券类型:1..8(满减/折扣/免运费/新人/会员/品类/商家/限时)'; -- 2) 用户优惠券表(user_coupons) CREATE TABLE IF NOT EXISTS public.user_coupons ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), user_id uuid, template_id uuid REFERENCES public.coupon_templates(id) ON DELETE CASCADE, coupon_code varchar(50) UNIQUE NOT NULL, status integer DEFAULT 1, -- 1 未使用,2 已使用,3 已过期 等(与 mall.md 对齐) used_at timestamptz, order_id uuid, received_at timestamptz DEFAULT now(), expire_at timestamptz NOT NULL ); DO $$ BEGIN -- 若 users 表存在则补 user_id 外键(保证幂等) IF EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'users' ) THEN IF NOT EXISTS ( SELECT 1 FROM pg_constraint c JOIN pg_class t ON t.oid = c.conrelid JOIN pg_namespace n ON n.oid = t.relnamespace WHERE n.nspname = 'public' AND t.relname = 'user_coupons' AND c.conname = 'user_coupons_user_id_fkey' ) THEN ALTER TABLE public.user_coupons ADD CONSTRAINT user_coupons_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; END IF; END IF; -- 若 orders 表存在则补 order_id 外键 IF EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'orders' ) THEN IF NOT EXISTS ( SELECT 1 FROM pg_constraint c JOIN pg_class t ON t.oid = c.conrelid JOIN pg_namespace n ON n.oid = t.relnamespace WHERE n.nspname = 'public' AND t.relname = 'user_coupons' AND c.conname = 'user_coupons_order_id_fkey' ) THEN ALTER TABLE public.user_coupons ADD CONSTRAINT user_coupons_order_id_fkey FOREIGN KEY (order_id) REFERENCES public.orders(id) ON DELETE SET NULL; END IF; END IF; -- 分析增强字段:发放渠道 obtain_channel IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'user_coupons' AND column_name = 'obtain_channel' ) THEN ALTER TABLE public.user_coupons ADD COLUMN obtain_channel text; END IF; -- 分析增强字段:冗余 merchant_id,便于按商家过滤 IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'user_coupons' AND column_name = 'merchant_id' ) THEN ALTER TABLE public.user_coupons ADD COLUMN merchant_id uuid; END IF; END; $$; COMMENT ON TABLE public.user_coupons IS '用户优惠券表(领取/使用/到期信息)'; COMMENT ON COLUMN public.user_coupons.obtain_channel IS '发放渠道:manual/auto/campaign/invite/cs/points 等'; -- 3) 优惠券使用记录表(coupon_usage_logs) CREATE TABLE IF NOT EXISTS public.coupon_usage_logs ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), user_coupon_id uuid REFERENCES public.user_coupons(id) ON DELETE CASCADE, order_id uuid NOT NULL, discount_amount numeric(10,2) NOT NULL, used_at timestamptz DEFAULT now() ); DO $$ BEGIN -- 若 orders 表存在则补 order_id 外键 IF EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'orders' ) THEN IF NOT EXISTS ( SELECT 1 FROM pg_constraint c JOIN pg_class t ON t.oid = c.conrelid JOIN pg_namespace n ON n.oid = t.relnamespace WHERE n.nspname = 'public' AND t.relname = 'coupon_usage_logs' AND c.conname = 'coupon_usage_logs_order_id_fkey' ) THEN ALTER TABLE public.coupon_usage_logs ADD CONSTRAINT coupon_usage_logs_order_id_fkey FOREIGN KEY (order_id) REFERENCES public.orders(id) ON DELETE CASCADE; END IF; END IF; -- 分析增强字段:冗余 user_id / template_id / merchant_id / order_amount / created_at IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'coupon_usage_logs' AND column_name = 'user_id' ) THEN ALTER TABLE public.coupon_usage_logs ADD COLUMN user_id uuid; END IF; IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'coupon_usage_logs' AND column_name = 'template_id' ) THEN ALTER TABLE public.coupon_usage_logs ADD COLUMN template_id uuid; END IF; IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'coupon_usage_logs' AND column_name = 'merchant_id' ) THEN ALTER TABLE public.coupon_usage_logs ADD COLUMN merchant_id uuid; END IF; IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'coupon_usage_logs' AND column_name = 'order_amount' ) THEN ALTER TABLE public.coupon_usage_logs ADD COLUMN order_amount numeric(10,2); END IF; IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'coupon_usage_logs' AND column_name = 'created_at' ) THEN ALTER TABLE public.coupon_usage_logs ADD COLUMN created_at timestamptz DEFAULT now(); END IF; END; $$; COMMENT ON TABLE public.coupon_usage_logs IS '优惠券使用记录表(单次核销流水,用于 GMV / ROI 分析)'; -- 4) 索引(幂等) CREATE INDEX IF NOT EXISTS idx_coupon_templates_merchant_id ON public.coupon_templates(merchant_id); CREATE INDEX IF NOT EXISTS idx_user_coupons_user_id ON public.user_coupons(user_id); CREATE INDEX IF NOT EXISTS idx_user_coupons_template_id ON public.user_coupons(template_id); CREATE INDEX IF NOT EXISTS idx_user_coupons_status ON public.user_coupons(status); CREATE INDEX IF NOT EXISTS idx_user_coupons_received_at ON public.user_coupons(received_at); CREATE INDEX IF NOT EXISTS idx_user_coupons_expire_at ON public.user_coupons(expire_at); CREATE INDEX IF NOT EXISTS idx_coupon_usage_logs_order_id ON public.coupon_usage_logs(order_id); CREATE INDEX IF NOT EXISTS idx_coupon_usage_logs_used_at ON public.coupon_usage_logs(used_at); -- 完成 SELECT 'coupon tables ensured' AS message;