-- Pair-shaped friend_relations (user_small, user_big) → two directed rows. -- Skipped by cmd/migrate when friend_relations.user_id already exists. CREATE TABLE IF NOT EXISTS friend_relations_new ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT '行 id,表内自增', user_id BIGINT NOT NULL COMMENT '关系所属用户', friend_id BIGINT NOT NULL COMMENT '对方 user_id', status TINYINT NOT NULL DEFAULT 1 COMMENT '1=好友 0=非好友(仅用于单向拉黑占位)', remark VARCHAR(64) NOT NULL DEFAULT '' COMMENT '备注,仅自己可见', is_blocked TINYINT NOT NULL DEFAULT 0 COMMENT '是否拉黑对方', is_pinned TINYINT NOT NULL DEFAULT 0 COMMENT '会话消息置顶', source TINYINT NOT NULL DEFAULT 0 COMMENT '添加来源:0=未知 1=二维码 2=邮箱 3=spark_id', created_at DATETIME(3) NOT NULL COMMENT '成为好友或建边时间', updated_at DATETIME(3) NOT NULL COMMENT '最近更新时间', PRIMARY KEY (id), UNIQUE KEY uk_user_friend (user_id, friend_id), KEY idx_user_status (user_id, status) ) COMMENT='单向好友边。A 与 B 互为好友时存两行,各自维护备注、拉黑、置顶'; INSERT IGNORE INTO friend_relations_new (user_id, friend_id, status, remark, is_blocked, is_pinned, source, created_at, updated_at) SELECT r.user_small, r.user_big, 1, IFNULL(n.remark, ''), 0, 0, 0, r.created_at, r.created_at FROM friend_relations r LEFT JOIN friend_remarks n ON n.user_id = r.user_small AND n.friend_id = r.user_big; INSERT IGNORE INTO friend_relations_new (user_id, friend_id, status, remark, is_blocked, is_pinned, source, created_at, updated_at) SELECT r.user_big, r.user_small, 1, IFNULL(n.remark, ''), 0, 0, 0, r.created_at, r.created_at FROM friend_relations r LEFT JOIN friend_remarks n ON n.user_id = r.user_big AND n.friend_id = r.user_small; INSERT INTO friend_relations_new (user_id, friend_id, status, remark, is_blocked, is_pinned, source, created_at, updated_at) SELECT b.user_id, b.blocked_id, 0, '', 1, 0, 0, b.created_at, b.created_at FROM user_blocks b ON DUPLICATE KEY UPDATE is_blocked = 1, updated_at = VALUES(updated_at); DROP TABLE IF EXISTS friend_remarks; DROP TABLE IF EXISTS user_blocks; DROP TABLE IF EXISTS friend_relations; RENAME TABLE friend_relations_new TO friend_relations;