BEGIN; -- ============================================================================ -- RAG 公共知识库未归属默认项迁移 -- -- 背景: -- 历史 RAG 知识库存在 tenant_code 为空、area 为空/default/公共、is_public=true 的公共知识库。 -- 如果这类记录是默认知识库,后端会禁止直接取消默认/删除;同时 PUBLIC 组另有默认 -- 时,页面会出现两个“默认”,但它们属于不同默认组。 -- -- 目标: -- 1. 将历史未归属公共 RAG 知识库迁移到 tenant_code='PUBLIC'、area='公共' -- 2. 同步其关联 rag_chat_app 的 tenant_code/area -- 3. 迁移后 PUBLIC 组只保留一个默认知识库/默认应用 -- -- 执行前: -- 先执行 precheck_rag_public_orphan_defaults.sql,确认候选记录符合预期。 -- ============================================================================ ALTER TABLE public.rag_dataset ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64); ALTER TABLE public.rag_chat_app ADD COLUMN IF NOT EXISTS tenant_code VARCHAR(64); CREATE INDEX IF NOT EXISTS idx_rag_dataset_tenant_code ON public.rag_dataset(tenant_code) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_rag_chat_app_tenant_code ON public.rag_chat_app(tenant_code) WHERE deleted_at IS NULL; CREATE TEMP TABLE tmp_rag_public_orphan_dataset_ids ( id BIGINT PRIMARY KEY ) ON COMMIT DROP; INSERT INTO tmp_rag_public_orphan_dataset_ids (id) SELECT d.id FROM public.rag_dataset d WHERE d.deleted_at IS NULL AND (d.tenant_code IS NULL OR BTRIM(d.tenant_code) = '') AND d.is_public IS TRUE AND ( d.area IS NULL OR BTRIM(d.area) = '' OR LOWER(BTRIM(d.area)) = 'default' OR BTRIM(d.area) = '公共' ) ON CONFLICT (id) DO NOTHING; WITH updated_dataset AS ( UPDATE public.rag_dataset d SET tenant_code = 'PUBLIC', area = '公共', is_public = TRUE, updated_at = NOW() FROM tmp_rag_public_orphan_dataset_ids orphan WHERE d.id = orphan.id RETURNING d.id ) UPDATE public.rag_chat_app a SET tenant_code = 'PUBLIC', area = '公共', updated_at = NOW() FROM updated_dataset ud WHERE a.dataset_id = ud.id AND a.deleted_at IS NULL; WITH ranked_public_dataset AS ( SELECT d.id, ROW_NUMBER() OVER ( ORDER BY d.is_default DESC, CASE WHEN orphan.id IS NULL THEN 0 ELSE 1 END, d.created_at DESC, d.id DESC ) AS keep_default_rank FROM public.rag_dataset d LEFT JOIN tmp_rag_public_orphan_dataset_ids orphan ON orphan.id = d.id WHERE d.deleted_at IS NULL AND BTRIM(COALESCE(d.tenant_code, '')) = 'PUBLIC' ), normalized_public_dataset AS ( UPDATE public.rag_dataset d SET is_default = (rpd.keep_default_rank = 1), updated_at = NOW() FROM ranked_public_dataset rpd WHERE d.id = rpd.id RETURNING d.id, d.is_default ) UPDATE public.rag_chat_app a SET is_default = npd.is_default, tenant_code = 'PUBLIC', area = '公共', updated_at = NOW() FROM normalized_public_dataset npd WHERE a.dataset_id = npd.id AND a.deleted_at IS NULL; -- 验收输出:PUBLIC 组当前默认知识库应只剩 1 条。 SELECT COUNT(*) FILTER (WHERE is_default = TRUE) AS public_default_count, COUNT(*) AS public_dataset_count FROM public.rag_dataset WHERE deleted_at IS NULL AND BTRIM(COALESCE(tenant_code, '')) = 'PUBLIC'; SELECT id, name, area, tenant_code, is_public, is_default, CASE WHEN id IN (SELECT id FROM tmp_rag_public_orphan_dataset_ids) THEN 'migrated_orphan' ELSE 'existing_public' END AS source_scope, created_at, updated_at FROM public.rag_dataset WHERE deleted_at IS NULL AND BTRIM(COALESCE(tenant_code, '')) = 'PUBLIC' ORDER BY is_default DESC, created_at DESC, id DESC; COMMIT;