表结构验证-自建

提供PostgreSQL建表语句和模拟数据生成代码,包含用户、商品、订单及关联表,并附有数据验证查询。

三个主表的建表语句:

  • 用户表 (users)
  • 商品表 (products)
  • 订单表 (orders)

一个关联表:

  • 订单商品关联表 (order_items) + 所有字段都添加了中文备注,使用PostgreSQL的COMMENT语法

模拟数据

  • 模拟数据生成代码:
  • 生成5000条用户数据,包含中文姓名、地址等
  • 生成2000条商品数据,包含中文商品名称、类别和描述
  • 生成10000条订单数据,每个订单包含1-5个订单项
  • 所有数据之间保持正确的关联关系

能力验证 (百万级别)

sql434 行
-- PostgreSQL建表语句和模拟数据生成

-- 删除已存在的表(如果存在)
DROP TABLE IF EXISTS order_items CASCADE;
DROP TABLE IF EXISTS orders CASCADE;
DROP TABLE IF EXISTS products CASCADE;
DROP TABLE IF EXISTS users CASCADE;

-- 创建用户表
CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL,
    phone VARCHAR(20),
    real_name VARCHAR(50),
    gender VARCHAR(10),
    birth_date DATE,
    address TEXT,
    registration_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_login_time TIMESTAMP,
    status SMALLINT DEFAULT 1
);

-- 为PostgreSQL添加列注释
COMMENT ON COLUMN users.user_id IS '用户ID';
COMMENT ON COLUMN users.username IS '用户名';
COMMENT ON COLUMN users.password IS '密码';
COMMENT ON COLUMN users.email IS '电子邮箱';
COMMENT ON COLUMN users.phone IS '手机号码';
COMMENT ON COLUMN users.real_name IS '真实姓名';
COMMENT ON COLUMN users.gender IS '性别';
COMMENT ON COLUMN users.birth_date IS '出生日期';
COMMENT ON COLUMN users.address IS '地址';
COMMENT ON COLUMN users.registration_time IS '注册时间';
COMMENT ON COLUMN users.last_login_time IS '最后登录时间';
COMMENT ON COLUMN users.status IS '状态:1-正常,0-禁用';

-- 创建商品表
CREATE TABLE products (
    product_id SERIAL PRIMARY KEY,
    product_name VARCHAR(200) NOT NULL,
    category VARCHAR(100),
    price DECIMAL(10, 2) NOT NULL,
    stock INT NOT NULL DEFAULT 0,
    description TEXT,
    image_url VARCHAR(255),
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    status SMALLINT DEFAULT 1
);

-- 为PostgreSQL添加列注释
COMMENT ON COLUMN products.product_id IS '商品ID';
COMMENT ON COLUMN products.product_name IS '商品名称';
COMMENT ON COLUMN products.category IS '商品类别';
COMMENT ON COLUMN products.price IS '商品价格';
COMMENT ON COLUMN products.stock IS '库存数量';
COMMENT ON COLUMN products.description IS '商品描述';
COMMENT ON COLUMN products.image_url IS '商品图片URL';
COMMENT ON COLUMN products.create_time IS '创建时间';
COMMENT ON COLUMN products.update_time IS '更新时间';
COMMENT ON COLUMN products.status IS '状态:1-上架,0-下架';

-- 创建订单表
CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    user_id INT NOT NULL,
    order_number VARCHAR(50) NOT NULL,
    total_amount DECIMAL(10, 2) NOT NULL,
    payment_method VARCHAR(50),
    shipping_address TEXT,
    contact_phone VARCHAR(20),
    contact_name VARCHAR(50),
    order_status SMALLINT DEFAULT 0,
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    payment_time TIMESTAMP,
    shipping_time TIMESTAMP,
    completion_time TIMESTAMP,
    remark TEXT,
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);

-- 为PostgreSQL添加列注释
COMMENT ON COLUMN orders.order_id IS '订单ID';
COMMENT ON COLUMN orders.user_id IS '用户ID';
COMMENT ON COLUMN orders.order_number IS '订单编号';
COMMENT ON COLUMN orders.total_amount IS '订单总金额';
COMMENT ON COLUMN orders.payment_method IS '支付方式';
COMMENT ON COLUMN orders.shipping_address IS '收货地址';
COMMENT ON COLUMN orders.contact_phone IS '联系电话';
COMMENT ON COLUMN orders.contact_name IS '联系人姓名';
COMMENT ON COLUMN orders.order_status IS '订单状态:0-待付款,1-已付款,2-已发货,3-已完成,4-已取消';
COMMENT ON COLUMN orders.create_time IS '创建时间';
COMMENT ON COLUMN orders.payment_time IS '支付时间';
COMMENT ON COLUMN orders.shipping_time IS '发货时间';
COMMENT ON COLUMN orders.completion_time IS '完成时间';
COMMENT ON COLUMN orders.remark IS '订单备注';

-- 创建订单商品关联表
CREATE TABLE order_items (
    item_id SERIAL PRIMARY KEY,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT NOT NULL,
    unit_price DECIMAL(10, 2) NOT NULL,
    subtotal DECIMAL(10, 2) NOT NULL,
    FOREIGN KEY (order_id) REFERENCES orders(order_id),
    FOREIGN KEY (product_id) REFERENCES products(product_id)
);

-- 为PostgreSQL添加列注释
COMMENT ON COLUMN order_items.item_id IS '订单项ID';
COMMENT ON COLUMN order_items.order_id IS '订单ID';
COMMENT ON COLUMN order_items.product_id IS '商品ID';
COMMENT ON COLUMN order_items.quantity IS '购买数量';
COMMENT ON COLUMN order_items.unit_price IS '单价';
COMMENT ON COLUMN order_items.subtotal IS '小计金额';

-- 生成模拟数据
-- 1. 插入用户数据
DO $$
DECLARE
    i INT;
    gender_arr VARCHAR[] := ARRAY['男', '女'];
    provinces VARCHAR[] := ARRAY['北京市', '上海市', '广东省', '江苏省', '浙江省', '四川省', '湖北省', '河南省', '山东省', '福建省'];
    cities VARCHAR[] := ARRAY['北京', '上海', '广州', '深圳', '杭州', '南京', '成都', '武汉', '郑州', '济南', '厦门'];
    districts VARCHAR[] := ARRAY['海淀区', '朝阳区', '浦东新区', '天河区', '福田区', '西湖区', '玄武区', '武侯区', '江汉区', '金水区', '历下区', '思明区'];
    streets VARCHAR[] := ARRAY['中关村大街', '建国路', '世纪大道', '天河路', '深南大道', '西湖大道', '中山路', '人民路', '解放路', '和平路'];
    last_names VARCHAR[] := ARRAY['张', '王', '李', '赵', '刘', '陈', '杨', '黄', '周', '吴', '郑', '孙', '马', '朱', '胡', '林', '郭', '何', '高', '罗'];
    first_names VARCHAR[] := ARRAY['伟', '芳', '娜', '秀英', '敏', '静', '丽', '强', '磊', '洋', '艳', '勇', '军', '杰', '娟', '涛', '明', '超', '秀兰', '霞', '平', '刚', '桂英'];
    username_prefix VARCHAR[] := ARRAY['happy', 'cool', 'super', 'fancy', 'lucky', 'smart', 'bright', 'sunny', 'clever', 'great'];
    username_suffix VARCHAR[] := ARRAY['user', 'star', 'fan', 'love', 'joy', 'hero', 'king', 'queen', 'master', 'expert'];
    email_domains VARCHAR[] := ARRAY['qq.com', '163.com', '126.com', 'gmail.com', 'hotmail.com', 'sina.com', 'sohu.com', 'yahoo.com', 'outlook.com'];
    random_username VARCHAR;
    random_email VARCHAR;
    random_phone VARCHAR;
    random_real_name VARCHAR;
    random_gender VARCHAR;
    random_birth_date DATE;
    random_address TEXT;
    random_last_login TIMESTAMP;
BEGIN
    FOR i IN 1..5000 LOOP
        -- 生成随机用户名
        random_username := username_prefix[1 + floor(random() * array_length(username_prefix, 1))] || 
                          username_suffix[1 + floor(random() * array_length(username_suffix, 1))] || 
                          i::VARCHAR;
        
        -- 生成随机邮箱
        random_email := random_username || '@' || email_domains[1 + floor(random() * array_length(email_domains, 1))];
        
        -- 生成随机手机号
        random_phone := '1' || (ARRAY['3', '5', '7', '8', '9'])[1 + floor(random() * 5)] || 
                       lpad(floor(random() * 100000000)::TEXT, 8, '0');
        
        -- 生成随机姓名
        random_real_name := last_names[1 + floor(random() * array_length(last_names, 1))] || 
                           first_names[1 + floor(random() * array_length(first_names, 1))];
        
        -- 生成随机性别
        random_gender := gender_arr[1 + floor(random() * 2)];
        
        -- 生成随机出生日期(1970-2000年之间)
        random_birth_date := '1970-01-01'::DATE + (random() * 365 * 30)::INTEGER;
        
        -- 生成随机地址
        random_address := provinces[1 + floor(random() * array_length(provinces, 1))] || 
                         cities[1 + floor(random() * array_length(cities, 1))] || 
                         districts[1 + floor(random() * array_length(districts, 1))] || 
                         streets[1 + floor(random() * array_length(streets, 1))] || 
                         floor(random() * 100)::TEXT || '号';
        
        -- 生成随机最后登录时间(过去一年内)
        random_last_login := CURRENT_TIMESTAMP - (random() * 365 * 24 * 60 * 60)::INTEGER * INTERVAL '1 second';
        
        -- 插入用户数据
        INSERT INTO users (username, password, email, phone, real_name, gender, birth_date, address, registration_time, last_login_time, status)
        VALUES (
            random_username,
            md5(random()::TEXT), -- 使用MD5生成随机密码
            random_email,
            random_phone,
            random_real_name,
            random_gender,
            random_birth_date,
            random_address,
            CURRENT_TIMESTAMP - (random() * 365 * 3 * 24 * 60 * 60)::INTEGER * INTERVAL '1 second', -- 注册时间在过去三年内
            random_last_login,
            CASE WHEN random() < 0.95 THEN 1 ELSE 0 END -- 95%的用户状态为正常
        );
    END LOOP;
END $$;

-- 2. 插入商品数据
DO $$
DECLARE
    i INT;
    categories VARCHAR[] := ARRAY['手机数码', '电脑办公', '家用电器', '服装鞋帽', '食品生鲜', '美妆护肤', '家居家装', '母婴玩具', '运动户外', '图书音像', '汽车用品', '珠宝首饰'];
    product_prefixes VARCHAR[] := ARRAY['全新', '时尚', '高端', '经典', '豪华', '精品', '优质', '舒适', '轻便', '实用', '智能', '专业', '高效', '便携', '耐用'];
    product_names VARCHAR[] := ARRAY['手机', '笔记本电脑', '平板电脑', '智能手表', '电视机', '冰箱', '洗衣机', '空调', 'T恤', '牛仔裤', '连衣裙', '运动鞋', '休闲鞋', '高跟鞋', '水果礼盒', '坚果零食', '有机蔬菜', '面膜', '洗面奶', '护肤套装', '沙发', '床垫', '餐桌', '婴儿奶粉', '尿不湿', '儿童玩具', '跑步机', '瑜伽垫', '登山包', '小说', '教材', '音乐CD', '汽车座套', '行车记录仪', '机油', '钻石项链', '黄金手镯', '银饰耳环'];
    product_suffixes VARCHAR[] := ARRAY['旗舰版', '豪华版', '至尊版', '限量版', '经典款', '时尚款', '舒适款', '轻薄款', '专业版', '入门版', '高配版', '标准版', '增强版', '尊享版'];
    descriptions VARCHAR[] := ARRAY['这是一款高品质的产品,性价比极高。', '采用顶级材料制作,品质保证。', '设计精美,功能强大,是您的不二之选。', '简约时尚的设计,满足您的日常需求。', '专为追求品质生活的您打造。', '精工细作,注重每一个细节。', '多功能设计,满足您的多样化需求。', '经典款式,永不过时。', '创新科技,引领潮流。', '舒适体验,尽享品质生活。'];
    image_prefixes VARCHAR[] := ARRAY['https://img.example.com/products/', 'https://images.store.cn/items/', 'https://pics.mall.com/goods/', 'https://photos.shop.net/product/'];
    random_product_name VARCHAR;
    random_category VARCHAR;
    random_price DECIMAL;
    random_stock INT;
    random_description TEXT;
    random_image_url VARCHAR;
    random_create_time TIMESTAMP;
    random_update_time TIMESTAMP;
BEGIN
    FOR i IN 1..5000 LOOP
        -- 生成随机商品名称
        random_product_name := product_prefixes[1 + floor(random() * array_length(product_prefixes, 1))] || ' ' || 
                              product_names[1 + floor(random() * array_length(product_names, 1))] || ' ' || 
                              product_suffixes[1 + floor(random() * array_length(product_suffixes, 1))];
        
        -- 生成随机商品类别
        random_category := categories[1 + floor(random() * array_length(categories, 1))];
        
        -- 生成随机价格(10-9999元)
        random_price := 10 + (random() * 9989);
        
        -- 生成随机库存(0-1000)
        random_stock := floor(random() * 1001);
        
        -- 生成随机描述
        random_description := descriptions[1 + floor(random() * array_length(descriptions, 1))] || ' ' || 
                             descriptions[1 + floor(random() * array_length(descriptions, 1))];
        
        -- 生成随机图片URL
        random_image_url := image_prefixes[1 + floor(random() * array_length(image_prefixes, 1))] || i || '.jpg';
        
        -- 生成随机创建时间(过去两年内)
        random_create_time := CURRENT_TIMESTAMP - (random() * 365 * 2 * 24 * 60 * 60)::INTEGER * INTERVAL '1 second';
        
        -- 生成随机更新时间(在创建时间之后)
        random_update_time := random_create_time + (random() * (CURRENT_TIMESTAMP - random_create_time));
        
        -- 插入商品数据
        INSERT INTO products (product_name, category, price, stock, description, image_url, create_time, update_time, status)
        VALUES (
            random_product_name,
            random_category,
            ROUND(random_price::NUMERIC, 2),
            random_stock,
            random_description,
            random_image_url,
            random_create_time,
            random_update_time,
            CASE WHEN random() < 0.9 THEN 1 ELSE 0 END -- 90%的商品状态为上架
        );
    END LOOP;
END $$;

-- 3. 插入订单和订单项数据
DO $$
DECLARE
    i INT;
    j INT;
    random_user_id INT;
    random_order_number VARCHAR;
    random_payment_method VARCHAR;
    random_order_status SMALLINT;
    random_create_time TIMESTAMP;
    random_payment_time TIMESTAMP;
    random_shipping_time TIMESTAMP;
    random_completion_time TIMESTAMP;
    random_remark TEXT;
    current_order_id INT;
    random_product_id INT;
    random_quantity INT;
    random_unit_price DECIMAL;
    random_subtotal DECIMAL;
    order_total_amount DECIMAL;
    user_info RECORD;
    payment_methods VARCHAR[] := ARRAY['支付宝', '微信支付', '银行卡', '货到付款', '信用卡'];
    remarks VARCHAR[] := ARRAY['请尽快发货', '周末送货', '工作日送货', '电话联系', '放到门卫处', '需要发票', '送货上门', '不要打电话', '加急处理', ''];
    max_user_id INT;
    max_product_id INT;
    items_count INT;
BEGIN
    -- 获取最大用户ID和商品ID
    SELECT MAX(user_id) INTO max_user_id FROM users;
    SELECT MAX(product_id) INTO max_product_id FROM products;
    
    FOR i IN 1..1000000 LOOP
        -- 随机选择一个用户
        random_user_id := 1 + floor(random() * max_user_id);
        
        -- 获取用户信息
        SELECT phone, real_name, address INTO user_info FROM users WHERE user_id = random_user_id;
        
        -- 生成随机订单编号
        random_order_number := 'ORD' || TO_CHAR(CURRENT_DATE, 'YYYYMMDD') || LPAD(i::TEXT, 6, '0');
        
        -- 随机选择支付方式
        random_payment_method := payment_methods[1 + floor(random() * array_length(payment_methods, 1))];
        
        -- 随机选择订单状态(0-4)
        random_order_status := floor(random() * 5);
        
        -- 生成随机创建时间(过去一年内)
        random_create_time := CURRENT_TIMESTAMP - (random() * 365 * 24 * 60 * 60)::INTEGER * INTERVAL '1 second';
        
        -- 根据订单状态生成相应的时间
        IF random_order_status >= 1 THEN
            -- 已付款及以上状态
            random_payment_time := random_create_time + (random() * 24 * 60 * 60)::INTEGER * INTERVAL '1 second';
        ELSE
            random_payment_time := NULL;
        END IF;
        
        IF random_order_status >= 2 THEN
            -- 已发货及以上状态
            random_shipping_time := random_payment_time + (random() * 3 * 24 * 60 * 60)::INTEGER * INTERVAL '1 second';
        ELSE
            random_shipping_time := NULL;
        END IF;
        
        IF random_order_status >= 3 THEN
            -- 已完成状态
            random_completion_time := random_shipping_time + (random() * 7 * 24 * 60 * 60)::INTEGER * INTERVAL '1 second';
        ELSE
            random_completion_time := NULL;
        END IF;
        
        -- 随机选择备注
        random_remark := remarks[1 + floor(random() * array_length(remarks, 1))];
        
        -- 插入订单数据(总金额先设为0,后面计算)
        INSERT INTO orders (user_id, order_number, total_amount, payment_method, shipping_address, contact_phone, contact_name, order_status, create_time, payment_time, shipping_time, completion_time, remark)
        VALUES (
            random_user_id,
            random_order_number,
            0, -- 总金额先设为0
            random_payment_method,
            user_info.address,
            user_info.phone,
            user_info.real_name,
            random_order_status,
            random_create_time,
            random_payment_time,
            random_shipping_time,
            random_completion_time,
            random_remark
        ) RETURNING order_id INTO current_order_id;
        
        -- 为每个订单生成1-5个订单项
        items_count := 1 + floor(random() * 5);
        order_total_amount := 0;
        
        FOR j IN 1..items_count LOOP
            -- 随机选择一个商品
            random_product_id := 1 + floor(random() * max_product_id);
            
            -- 随机选择购买数量(1-10)
            random_quantity := 1 + floor(random() * 10);
            
            -- 获取商品单价
            SELECT price INTO random_unit_price FROM products WHERE product_id = random_product_id;
            
            -- 如果没有找到商品,使用随机价格
            IF random_unit_price IS NULL THEN
                random_unit_price := 10 + (random() * 990);
            END IF;
            
            -- 计算小计金额
            random_subtotal := random_unit_price * random_quantity;
            
            -- 累加总金额
            order_total_amount := order_total_amount + random_subtotal;
            
            -- 插入订单项数据
            INSERT INTO order_items (order_id, product_id, quantity, unit_price, subtotal)
            VALUES (
                current_order_id,
                random_product_id,
                random_quantity,
                ROUND(random_unit_price::NUMERIC, 2),
                ROUND(random_subtotal::NUMERIC, 2)
            );
        END LOOP;
        
        -- 更新订单总金额
        UPDATE orders SET total_amount = ROUND(order_total_amount::NUMERIC, 2) WHERE order_id = current_order_id;
    END LOOP;
END $$;

-- 验证数据
-- 查询用户总数
SELECT COUNT(*) AS user_count FROM users;

-- 查询商品总数
SELECT COUNT(*) AS product_count FROM products;

-- 查询订单总数
SELECT COUNT(*) AS order_count FROM orders;

-- 查询订单项总数
SELECT COUNT(*) AS order_item_count FROM order_items;

-- 查询各订单状态的订单数量
SELECT order_status, COUNT(*) AS count FROM orders GROUP BY order_status ORDER BY order_status;

-- 查询销量前10的商品
SELECT p.product_id, p.product_name, SUM(oi.quantity) AS total_sales
FROM products p
JOIN order_items oi ON p.product_id = oi.product_id
GROUP BY p.product_id, p.product_name
ORDER BY total_sales DESC
LIMIT 10;

-- 查询消费金额前10的用户
SELECT u.user_id, u.username, u.real_name, SUM(o.total_amount) AS total_spent
FROM users u
JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id, u.username, u.real_name
ORDER BY total_spent DESC
LIMIT 10;

-- 查询平均订单金额
SELECT AVG(total_amount) AS avg_order_amount FROM orders;

-- 查询各商品类别的销售情况
SELECT p.category, COUNT(DISTINCT o.order_id) AS order_count, SUM(oi.quantity) AS total_quantity, SUM(oi.subtotal) AS total_sales
FROM products p
JOIN order_items oi ON p.product_id = oi.product_id
JOIN orders o ON oi.order_id = o.order_id
GROUP BY p.category
ORDER BY total_sales DESC;