# 变量冲突修复报告

## 问题描述

### 问题一：PL/pgSQL 变量名冲突
在 `mock_data_insert.sql` 脚本的订单生成部分，PL/pgSQL 块中的变量名 `merchant_id` 与表字段 `p.merchant_id` 发生了命名冲突，导致以下错误：

```
ERROR: 42702: column reference "merchant_id" is ambiguous
DETAIL: It could refer to either a PL/pgSQL variable or a table column.
```

### 问题二：订单商品价格为空
在订单商品生成部分，当商品没有对应的SKU时，`product_rec.price` 为 NULL，导致违反 NOT NULL 约束：

```
ERROR: 23502: null value in column "price" of relation "ml_order_items" violates not-null constraint
```

### 问题三：配送任务重复键冲突
在配送任务生成部分，同一个订单可能被多次分配配送任务，导致违反唯一约束：

```
ERROR: 23505: duplicate key value violates unique constraint "ml_delivery_tasks_order_id_key"
DETAIL: Key (order_id)=(329d742f-af8b-4e0e-b4c5-d16606d23758) already exists.
```

## 问题原因

### 原因一：作用域冲突
在 PostgreSQL 的 PL/pgSQL 中，当局部变量与表字段同名时，会出现作用域冲突。在这种情况下：
- 声明了局部变量 `merchant_id UUID`
- 在 SQL 查询中使用 `WHERE p.merchant_id = merchant_id` 时，PostgreSQL 无法明确区分是表字段还是变量

### 原因二：数据完整性问题
在商品-SKU关联查询中：
- 使用了 LEFT JOIN 连接商品和SKU表
- 当商品没有SKU时，SKU相关字段（如price, image_url）为 NULL
- 直接使用 `s.price` 导致插入NULL值，违反数据库约束

### 原因三：唯一约束冲突
在配送任务生成中：
- 使用了 `CROSS JOIN` 将订单与配送员进行笛卡尔积连接
- 随机条件 `random() < 0.5` 可能让同一订单匹配多个配送员
- 没有确保每个订单只生成一个配送任务

## 修复方案

### 修复一：变量重命名
将变量名从 `merchant_id` 改为 `selected_merchant_id`，确保变量名与表字段名不冲突。

#### 修复前
```sql
DECLARE
    merchant_id UUID;
BEGIN
    SELECT user_id INTO merchant_id FROM temp_user_ids ...
    WHERE p.merchant_id = merchant_id  -- 冲突！
```

#### 修复后
```sql
DECLARE
    selected_merchant_id UUID;
BEGIN
    SELECT user_id INTO selected_merchant_id FROM temp_user_ids ...
    WHERE p.merchant_id = selected_merchant_id  -- 清晰明确
```

### 修复二：价格字段空值处理
使用 COALESCE 函数确保价格字段不为空，优先使用SKU价格，如果没有则使用商品基础价格。

#### 修复前
```sql
SELECT p.id as product_id, s.id as sku_id, p.name, s.price, s.image_url
FROM public.ml_products p
LEFT JOIN public.ml_product_skus s ON p.id = s.product_id
-- s.price 可能为 NULL
```

#### 修复后
```sql
SELECT 
    p.id as product_id, 
    s.id as sku_id, 
    p.name, 
    COALESCE(s.price, p.base_price) as price, -- 空值处理
    COALESCE(s.image_url, p.main_image_url) as image_url -- 空值处理
FROM public.ml_products p
LEFT JOIN public.ml_product_skus s ON p.id = s.product_id
```

### 修复三：配送任务唯一性保证
使用 `DISTINCT ON`、`NOT EXISTS` 和 `LIMIT` 确保每个订单只创建一个配送任务。

#### 修复前
```sql
SELECT o.id, d.id, ...
FROM public.ml_orders o
JOIN public.ml_delivery_drivers d ON random() < 0.5 -- 可能重复
WHERE o.shipping_status >= 2
  AND random() < 0.8;
```

#### 修复后
```sql
SELECT DISTINCT ON (o.id) -- 确保每个订单唯一
    o.id, d.id, ...
FROM public.ml_orders o
CROSS JOIN public.ml_delivery_drivers d
WHERE o.shipping_status >= 2
  AND random() < 0.8
  AND NOT EXISTS ( -- 检查是否已有配送任务
      SELECT 1 FROM public.ml_delivery_tasks dt WHERE dt.order_id = o.id
  )
ORDER BY o.id, random() -- 随机选择配送员
LIMIT 50; -- 限制数量
```

## 修改详情

### 文件：`mock_data_insert.sql`

#### 1. 变量声明部分 (第804行)
```sql
- merchant_id UUID;
+ selected_merchant_id UUID;
```

#### 2. 变量赋值部分 (第819行)
```sql
- SELECT user_id INTO merchant_id FROM temp_user_ids 
+ SELECT user_id INTO selected_merchant_id FROM temp_user_ids 
```

#### 3. 订单插入部分 (第833行)
```sql
- uuid_generate_v4(), order_no, customer_rec.user_id, merchant_id,
+ uuid_generate_v4(), order_no, customer_rec.user_id, selected_merchant_id,
```

#### 4. 商品查询部分 (第871行)
```sql
- WHERE p.merchant_id = merchant_id
+ WHERE p.merchant_id = selected_merchant_id
```

#### 5. 订单商品查询部分 (第866-885行)
```sql
-- 修复前
SELECT p.id as product_id, s.id as sku_id, p.name, s.price, s.image_url
FROM public.ml_products p
LEFT JOIN public.ml_product_skus s ON p.id = s.product_id

-- 修复后
SELECT 
    p.id as product_id, 
    s.id as sku_id, 
    p.name, 
    COALESCE(s.price, p.base_price) as price,
    COALESCE(s.image_url, p.main_image_url) as image_url
FROM public.ml_products p
LEFT JOIN public.ml_product_skus s ON p.id = s.product_id
```

#### 6. 订单商品插入部分 (第886-895行)
```sql
-- 增加了局部变量声明和空值检查
DECLARE
    item_quantity INTEGER;
    item_price DECIMAL;
BEGIN
    item_quantity := FLOOR(1 + random() * 2)::INTEGER;
    item_price := product_rec.price;
    
    INSERT INTO public.ml_order_items (...)
    VALUES (
        order_id, product_rec.product_id, product_rec.sku_id, product_rec.name,
        item_price, item_quantity, item_price * item_quantity, product_rec.image_url
    );
END;
```

#### 7. 配送任务生成部分 (第1150-1175行)
```sql
-- 修复前
SELECT o.id, d.id, ...
FROM public.ml_orders o
JOIN public.ml_delivery_drivers d ON random() < 0.5
WHERE o.shipping_status >= 2
  AND random() < 0.8;

-- 修复后
SELECT DISTINCT ON (o.id) o.id, d.id, ...
FROM public.ml_orders o
CROSS JOIN public.ml_delivery_drivers d
WHERE o.shipping_status >= 2
  AND random() < 0.8
  AND NOT EXISTS (
      SELECT 1 FROM public.ml_delivery_tasks dt WHERE dt.order_id = o.id
  )
ORDER BY o.id, random()
LIMIT 50;
```

## 验证方法
1. 执行修复后的脚本，确认不再出现变量冲突错误
2. 检查生成的订单数据，确认 merchant_id 字段正确关联到商家用户
3. 验证订单项能正确关联到对应商家的商品，且价格字段不为空
4. 确认订单商品的价格逻辑正确（优先使用SKU价格，否则使用基础价格）
5. 检查配送任务表，确认每个订单最多只有一个配送任务
6. 验证配送任务的订单ID没有重复

## 最佳实践建议
1. **变量命名规范**：在 PL/pgSQL 中使用更具描述性的变量名，避免与表字段同名
2. **变量前缀**：考虑为局部变量添加前缀，如 `v_`, `l_`, `selected_` 等
3. **表字段引用**：在复杂查询中明确使用表别名，如 `p.merchant_id`
4. **空值处理**：在 LEFT JOIN 查询中，使用 COALESCE 处理可能的空值
5. **数据完整性**：确保关键字段（如价格、数量）不为空，违反业务逻辑
6. **唯一约束处理**：在生成关联数据时，使用 DISTINCT、NOT EXISTS 等确保唯一性
7. **批量插入控制**：使用 LIMIT 控制批量插入的数据量，避免过度生成测试数据

## 状态
✅ **已修复** - 所有变量冲突、空值问题和唯一约束冲突已解决，脚本可正常执行
