Files
Mycontent/soul-api/scripts/migrate-super-individual-persons-bind.sql
2026-04-02 19:20:19 +08:00

75 lines
3.5 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================================================
-- migrate-super-individual-persons-bind.sql
-- 超级个体(有效 VIP与 @人物 persons 对齐 — 数据侧「补绑」迁移
--
-- 说明:
-- 1) 新建 persons 行依赖存客宝 APIckb_plan_id / ckb_api_key请勿用纯 SQL 硬插完整行。
-- 未绑上的用户:部署 soul-api 后,在管理端「内容管理 → @列表」点刷新,由接口自动 ensurePersonForUser。
-- 2) 本脚本只做安全场景:已有 @人物、user_id 为空,且「未绑定 person 的 VIP」里仅一人昵称与 person.name 一致时,写入 user_id。
-- 3) 执行前请备份库;建议先只跑「第一节 SELECT」看缺口再跑 UPDATE。
-- 4) VIP 口径is_vip = 1 且 vip_expire_date > NOW()(与 activeSuperIndividualUserIDs 主路径一致)。
-- =============================================================================
-- ---------------------------------------------------------------------------
-- 1) 缺口清单:有效 VIP且没有任何 person.user_id 指向该用户
-- ---------------------------------------------------------------------------
SELECT
u.id AS user_id,
TRIM(u.nickname) AS nickname,
u.vip_expire_date,
u.is_vip
FROM users u
WHERE u.is_vip = 1
AND u.vip_expire_date > NOW()
AND NOT EXISTS (
SELECT 1 FROM persons p WHERE p.user_id IS NOT NULL AND TRIM(p.user_id) <> '' AND p.user_id = u.id
)
ORDER BY u.vip_sort ASC, u.vip_activated_at DESC, u.id;
-- ---------------------------------------------------------------------------
-- 2) 冲突检查:多个未绑定的 person 同名(本脚本不会自动处理,需人工合并或走 API
-- ---------------------------------------------------------------------------
SELECT TRIM(p.name) AS name_norm, COUNT(*) AS unbound_count
FROM persons p
WHERE p.user_id IS NULL OR TRIM(p.user_id) = ''
GROUP BY TRIM(p.name)
HAVING COUNT(*) > 1;
-- ---------------------------------------------------------------------------
-- 3) 同名唯一补绑:未绑 person ↔ 有效 VIP昵称一致且该 VIP 尚无 person
-- MySQL 8+ / 5.7 均可用user_id 列为空串时按未绑定处理
-- ---------------------------------------------------------------------------
UPDATE persons p
INNER JOIN users u
ON TRIM(u.nickname) = TRIM(p.name)
AND CHAR_LENGTH(TRIM(COALESCE(u.nickname, ''))) > 0
SET
p.user_id = u.id,
p.updated_at = NOW()
WHERE (p.user_id IS NULL OR TRIM(p.user_id) = '')
AND u.is_vip = 1
AND u.vip_expire_date > NOW()
AND NOT EXISTS (
SELECT 1 FROM persons px WHERE px.user_id = u.id
)
AND (
SELECT COUNT(*)
FROM persons p3
WHERE TRIM(p3.name) = TRIM(p.name)
AND (p3.user_id IS NULL OR TRIM(p3.user_id) = '')
) = 1;
-- ---------------------------------------------------------------------------
-- 4) 可选:将本次补绑且仍为「手工」来源的 VIP 行标为 vip_sync与统一计划展示一致按业务需要取消注释
-- ---------------------------------------------------------------------------
-- UPDATE persons p
-- INNER JOIN users u ON p.user_id = u.id
-- SET p.person_source = 'vip_sync', p.updated_at = NOW()
-- WHERE u.is_vip = 1
-- AND u.vip_expire_date > NOW()
-- AND (p.person_source IS NULL OR p.person_source = '');
-- ---------------------------------------------------------------------------
-- 5) 执行后再跑第一节 SELECT应只剩「无同名 person」的 VIP须由线上 API 创建 person
-- ---------------------------------------------------------------------------