Merge remote-tracking branch 'origin/master'

This commit is contained in:
En 2026-03-19 09:39:52 +08:00
commit bad446c069
7 changed files with 404 additions and 0 deletions

3
.gitignore vendored
View File

@ -11,6 +11,9 @@ Thumbs.db
backups/ backups/
*.db *.db
# === 例外Flyway 迁移脚本必须提交 ===
!**/db/migration/*.sql
# === IDE 和编辑器 === # === IDE 和编辑器 ===
.vscode/ .vscode/
.idea/ .idea/

View File

@ -0,0 +1,95 @@
-- =====================================================
-- 迁移 V32: 修复 V31 迁移问题并完成三层结构修复
--
-- 这个迁移脚本会:
-- 1. 检查并修复可能存在的部分数据
-- 2. 使用 INSERT IGNORE 避免重复键错误
-- 3. 完成三层课程结构的修复
-- =====================================================
-- 临时禁用外键约束
SET FOREIGN_KEY_CHECKS = 0;
-- =====================================================
-- 第一步:清理可能存在的错误数据
-- =====================================================
-- 删除自引用的 course_collection_package 关联
DELETE FROM `course_collection_package` WHERE `collection_id` = `package_id`;
-- 删除错误的 course_collection 数据ID 3, 4, 5
DELETE FROM `course_collection` WHERE `id` IN (3, 4, 5);
-- 清理 tenant_package 中的 collection_id 引用
UPDATE `tenant_package` SET `collection_id` = NULL WHERE `collection_id` IN (3, 4, 5);
-- =====================================================
-- 第二步:创建课程套餐数据(使用 INSERT IGNORE
-- =====================================================
INSERT IGNORE INTO `course_collection` (`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `package_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`) VALUES
(100, '完整阅读能力培养课程体系', '涵盖小班至学前班的完整阅读能力培养体系,包含语言启蒙、艺术创作、科学探索等多个领域的课程包', 29999, 24999, 'FIXED', '["小班", "中班", "大班", "学前班"]', 3, 'PUBLISHED', NOW(), 1, NOW(), 1, '审核通过', NOW(), 'system', NOW(), 'system', NOW(), 0);
-- =====================================================
-- 第三步:创建课程包数据(使用 INSERT IGNORE
-- =====================================================
INSERT IGNORE INTO `course_package` (`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `course_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`) VALUES
(101, '语言启蒙课程包', '通过绘本阅读培养幼儿的语言表达能力和阅读兴趣', 9999, 7999, 'FIXED', '["小班", "中班"]', 3, 'PUBLISHED', NOW(), 1, NOW(), 1, '审核通过', NOW(), 'system', NOW(), 'system', NOW(), 0),
(102, '艺术创作课程包', '通过艺术活动培养幼儿的审美能力和创造力', 9999, 7999, 'FIXED', '["小班", "中班", "大班"]', 3, 'PUBLISHED', NOW(), 1, NOW(), 1, '审核通过', NOW(), 'system', NOW(), 'system', NOW(), 0),
(103, '科学探索课程包', '通过科学活动培养幼儿的探究精神和逻辑思维', 9999, 7999, 'FIXED', '["中班", "大班", "学前班"]', 4, 'PUBLISHED', NOW(), 1, NOW(), 1, '审核通过', NOW(), 'system', NOW(), 'system', NOW(), 0);
-- =====================================================
-- 第四步:创建关联数据(使用 INSERT IGNORE
-- =====================================================
INSERT IGNORE INTO `course_collection_package` (`id`, `collection_id`, `package_id`, `sort_order`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`) VALUES
(101, 100, 101, 1, 'system', NOW(), 'system', NOW(), 0),
(102, 100, 102, 2, 'system', NOW(), 'system', NOW(), 0),
(103, 100, 103, 3, 'system', NOW(), 'system', NOW(), 0);
-- =====================================================
-- 第五步:创建课程数据(使用 INSERT IGNORE
-- =====================================================
INSERT IGNORE INTO `course` (`id`, `tenant_id`, `name`, `category`, `description`, `cover_url`, `age_range`, `difficulty_level`, `duration_minutes`, `status`, `is_system`, `core_content`, `objectives`, `schedule_ref_data`, `created_at`, `updated_at`, `deleted`) VALUES
(101, NULL, '小猪佩奇绘本阅读导入课', '语言艺术', '通过小猪佩奇绘本导入阅读主题,激发幼儿兴趣', '/courses/peppa-intro/cover.jpg', '3-6 岁', 'BEGINNER', 20, 'PUBLISHED', 1, '语言导入课程', '激发阅读兴趣', '[{"lessonType":"导入课","recommendation":"每学期开学第一周进行作为整个阅读体系的导入课程。建议1-2课时完成。","sessions":2}]', NOW(), NOW(), 0),
(102, NULL, '小猪佩奇集体阅读课', '语言艺术', '集体阅读小猪佩奇绘本,培养集体阅读习惯', '/courses/peppa-collective/cover.jpg', '3-6 岁', 'BEGINNER', 30, 'PUBLISHED', 1, '语言集体课程', '培养集体阅读能力', '[{"lessonType":"集体课","recommendation":"每月进行2次建议安排在周五上午。每次30-35分钟包含共读、讨论、表演环节。","sessions":8,"frequency":"每月2次"}]', NOW(), NOW(), 0),
(103, NULL, '语言领域课程-小猪佩奇', '语言艺术', '深入学习语言领域的知识点和能力', '/courses/peppa-language/cover.jpg', '3-6 岁', 'BEGINNER', 25, 'PUBLISHED', 1, '五大领域语言课程', '提升语言表达能力', '[{"lessonType":"五大领域语言课","recommendation":"每周2次建议安排在周二和周四。每次25分钟重点培养听说能力。","sessions":16,"frequency":"每周2次"}]', NOW(), NOW(), 0),
(104, NULL, '彩虹色的花导入课', '艺术创作', '导入艺术创作主题', '/courses/rainbow-intro/cover.jpg', '3-5 岁', 'BEGINNER', 20, 'PUBLISHED', 1, '艺术导入课程', '激发艺术兴趣', '[{"lessonType":"导入课","recommendation":"每学期开学第一周进行","sessions":1}]', NOW(), NOW(), 0),
(105, NULL, '彩虹色的花集体创作课', '艺术创作', '集体进行艺术创作', '/courses/rainbow-collective/cover.jpg', '3-5 岁', 'BEGINNER', 35, 'PUBLISHED', 1, '艺术集体课程', '培养集体创作能力', '[{"lessonType":"集体课","recommendation":"每月1次建议安排在周三下午","sessions":4}]', NOW(), NOW(), 0),
(106, NULL, '艺术领域课程-彩虹色的花', '艺术创作', '五大领域艺术课程', '/courses/rainbow-art/cover.jpg', '3-5 岁', 'BEGINNER', 30, 'PUBLISHED', 1, '五大领域艺术课程', '提升艺术表现能力', '[{"lessonType":"五大领域艺术课","recommendation":"每周1次建议安排在周一上午","sessions":8}]', NOW(), NOW(), 0),
(107, NULL, '牙齿大街的新鲜事导入课', '科学探索', '导入科学探索主题', '/courses/teeth-intro/cover.jpg', '4-6 岁', 'INTERMEDIATE', 20, 'PUBLISHED', 1, '科学导入课程', '激发科学探索兴趣', '[{"lessonType":"导入课","recommendation":"每学期开学第一周进行","sessions":1}]', NOW(), NOW(), 0),
(108, NULL, '牙齿大街集体探究课', '科学探索', '集体进行科学探究', '/courses/teeth-collective/cover.jpg', '4-6 岁', 'INTERMEDIATE', 35, 'PUBLISHED', 1, '科学集体课程', '培养集体探究能力', '[{"lessonType":"集体课","recommendation":"每月1次建议安排在周二下午","sessions":4}]', NOW(), NOW(), 0),
(109, NULL, '健康领域课程-牙齿大街', '科学探索', '五大领域健康课程', '/courses/teeth-health/cover.jpg', '4-6 岁', 'INTERMEDIATE', 30, 'PUBLISHED', 1, '五大领域健康课程', '培养健康意识', '[{"lessonType":"五大领域健康课","recommendation":"每周1次建议安排在周三上午","sessions":8}]', NOW(), NOW(), 0),
(110, NULL, '科学领域课程-牙齿大街', '科学探索', '五大领域科学课程', '/courses/teeth-science/cover.jpg', '4-6 岁', 'INTERMEDIATE', 30, 'PUBLISHED', 1, '五大领域科学课程', '培养科学探究能力', '[{"lessonType":"五大领域科学课","recommendation":"每周1次建议安排在周五上午","sessions":8}]', NOW(), NOW(), 0);
-- =====================================================
-- 第六步:创建课程包与课程的关联(使用 INSERT IGNORE
-- =====================================================
INSERT IGNORE INTO `course_package_course` (`id`, `package_id`, `course_id`, `grade_level`, `sort_order`) VALUES
(1001, 101, 101, '小班', 1),
(1002, 101, 102, '小班', 2),
(1003, 101, 103, '小班', 3),
(1004, 102, 104, '小班', 1),
(1005, 102, 105, '小班', 2),
(1006, 102, 106, '小班', 3),
(1007, 103, 107, '中班', 1),
(1008, 103, 108, '中班', 2),
(1009, 103, 109, '中班', 3),
(1010, 103, 110, '中班', 4);
-- =====================================================
-- 第七步:更新租户套餐关联
-- =====================================================
-- 将租户的套餐关联更新到新的课程套餐collection_id = 100
UPDATE `tenant_package` SET `collection_id` = 100 WHERE `id` IN (1, 2);
-- 重新启用外键约束
SET FOREIGN_KEY_CHECKS = 1;
-- =====================================================
-- V32 迁移完成
-- =====================================================

View File

@ -0,0 +1,125 @@
-- =====================================================
-- 迁移 V33: 将8个课程包转换为8个套餐
--
-- 这个迁移会:
-- 1. 为8个现有课程包创建对应的8个套餐
-- 2. 将每个课程包关联到其对应的套餐
-- 3. 更新所有关联关系
-- =====================================================
SET FOREIGN_KEY_CHECKS = 0;
-- =====================================================
-- 第一步创建8个套餐使用新ID避免冲突
-- 课程包ID: 3, 4, 5, 6, 7, 101, 102, 103
-- 新套餐ID: 203, 204, 205, 206, 207, 208, 209, 210
-- =====================================================
INSERT INTO `course_collection`
(`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `package_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
SELECT
203, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, 1, `status`,
`submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`,
`create_by`, `created_at`, `update_by`, `updated_at`, 0
FROM `course_package` WHERE `id` = 3;
INSERT INTO `course_collection`
(`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `package_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
SELECT
204, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, 1, `status`,
`submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`,
`create_by`, `created_at`, `update_by`, `updated_at`, 0
FROM `course_package` WHERE `id` = 4;
INSERT INTO `course_collection`
(`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `package_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
SELECT
205, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, 1, `status`,
`submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`,
`create_by`, `created_at`, `update_by`, `updated_at`, 0
FROM `course_package` WHERE `id` = 5;
INSERT INTO `course_collection`
(`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `package_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
SELECT
206, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, 1, `status`,
`submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`,
`create_by`, `created_at`, `update_by`, `updated_at`, 0
FROM `course_package` WHERE `id` = 6;
INSERT INTO `course_collection`
(`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `package_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
SELECT
207, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, 1, `status`,
`submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`,
`create_by`, `created_at`, `update_by`, `updated_at`, 0
FROM `course_package` WHERE `id` = 7;
INSERT INTO `course_collection`
(`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `package_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
SELECT
208, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, 1, `status`,
`submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`,
`create_by`, `created_at`, `update_by`, `updated_at`, 0
FROM `course_package` WHERE `id` = 101;
INSERT INTO `course_collection`
(`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `package_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
SELECT
209, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, 1, `status`,
`submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`,
`create_by`, `created_at`, `update_by`, `updated_at`, 0
FROM `course_package` WHERE `id` = 102;
INSERT INTO `course_collection`
(`id`, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, `package_count`, `status`, `submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
SELECT
210, `name`, `description`, `price`, `discount_price`, `discount_type`, `grade_levels`, 1, `status`,
`submitted_at`, `submitted_by`, `reviewed_at`, `reviewed_by`, `review_comment`, `published_at`,
`create_by`, `created_at`, `update_by`, `updated_at`, 0
FROM `course_package` WHERE `id` = 103;
-- =====================================================
-- 第二步:建立套餐与课程包的关联
-- =====================================================
INSERT INTO `course_collection_package`
(`id`, `collection_id`, `package_id`, `sort_order`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
VALUES
(1001, 203, 3, 1, 'system', NOW(), 'system', NOW(), 0),
(1002, 204, 4, 1, 'system', NOW(), 'system', NOW(), 0),
(1003, 205, 5, 1, 'system', NOW(), 'system', NOW(), 0),
(1004, 206, 6, 1, 'system', NOW(), 'system', NOW(), 0),
(1005, 207, 7, 1, 'system', NOW(), 'system', NOW(), 0),
(1006, 208, 101, 1, 'system', NOW(), 'system', NOW(), 0),
(1007, 209, 102, 1, 'system', NOW(), 'system', NOW(), 0),
(1008, 210, 103, 1, 'system', NOW(), 'system', NOW(), 0);
-- =====================================================
-- 第三步:更新租户套餐关联
-- =====================================================
-- 删除原有的套餐关联
DELETE FROM `tenant_package`;
-- 重新创建套餐关联关联到新的8个套餐
-- 注意:需要同时提供 package_id 和 collection_id
INSERT INTO `tenant_package` (`id`, `tenant_id`, `package_id`, `collection_id`, `start_date`, `end_date`, `status`, `create_by`, `created_at`, `update_by`, `updated_at`, `deleted`)
VALUES
(1, 1, 3, 203, CURDATE(), DATE_ADD(CURDATE(), INTERVAL 1 YEAR), 'ACTIVE', 'system', NOW(), 'system', NOW(), 0),
(2, 1, 4, 204, CURDATE(), DATE_ADD(CURDATE(), INTERVAL 1 YEAR), 'ACTIVE', 'system', NOW(), 'system', NOW(), 0);
-- =====================================================
-- 第四步:清理旧的套餐数据
-- =====================================================
-- 删除旧的套餐ID 100
DELETE FROM `course_collection_package` WHERE `collection_id` = 100;
DELETE FROM `course_collection` WHERE `id` = 100;
SET FOREIGN_KEY_CHECKS = 1;
-- =====================================================
-- V33 迁移完成
-- 现在有8个套餐每个套餐包含1个原有的课程包
-- =====================================================

View File

@ -0,0 +1,15 @@
-- =====================================================
-- 迁移 V34: 清理旧的套餐数据
-- =====================================================
SET FOREIGN_KEY_CHECKS = 0;
-- 删除旧的套餐ID 100
DELETE FROM `course_collection_package` WHERE `collection_id` = 100;
DELETE FROM `course_collection` WHERE `id` = 100;
SET FOREIGN_KEY_CHECKS = 1;
-- =====================================================
-- V34 迁移完成
-- =====================================================

View File

@ -0,0 +1,66 @@
-- =====================================================
-- 迁移 V35: 清理混淆的旧表结构
--
-- 清理旧的 course_package 表,统一使用 course 表作为课程包表
-- =====================================================
SET FOREIGN_KEY_CHECKS = 0;
-- =====================================================
-- 第一步:检查并备份要删除的数据
-- =====================================================
-- 检查 course_package 表中是否有真实课程包数据
-- (即有 course_lesson 数据的)
SELECT
'=== 检查 course_package 表中需要迁移的数据 ===' as info;
-- 如果有需要保留的数据,可以先备份
CREATE TABLE IF NOT EXISTS course_package_backup AS
SELECT * FROM course_package WHERE 1=0;
-- =====================================================
-- 第二步:删除旧的关联表
-- =====================================================
SELECT
'=== 删除旧的关联表 ===' as info;
-- 删除课程包与课程的关联表(旧的关联方式)
DROP TABLE IF EXISTS course_package_course;
-- =====================================================
-- 第三步:删除旧的课程包表
-- =====================================================
SELECT
'=== 删除旧的 course_package 表 ===' as info;
-- 注意V33迁移中course_package的数据已经转换为8个套餐了
-- 所以现在可以安全删除这个表
DROP TABLE IF EXISTS course_package;
-- =====================================================
-- 第四步:验证关联关系
-- =====================================================
SELECT
'=== 验证 course_collection_package 关联 ===' as info;
-- 检查套餐与课程包的关联是否正确
-- 现在应该关联到 course 表(不是 course_package 表)
SELECT
cc.id as collection_id,
cc.name as collection_name,
ccp.package_id,
c.name as package_name,
c.schedule_ref_data
FROM course_collection cc
LEFT JOIN course_collection_package ccp ON ccp.collection_id = cc.id
LEFT JOIN course c ON c.id = ccp.package_id
ORDER BY cc.id, ccp.sort_order;
SELECT
'=== V35 迁移完成 ===' as info;
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -0,0 +1,84 @@
-- =====================================================
-- 迁移 V36: 重命名 course 表为 course_package
--
-- 统一命名course → course_package课程包表
-- 同时更新所有外键关联
-- =====================================================
SET FOREIGN_KEY_CHECKS = 0;
-- =====================================================
-- 第一步:重命名主表(幂等操作)
-- =====================================================
SELECT '=== 检查并重命名 course 表为 course_package ===' as info;
-- 只有当 course 表存在时才重命名
-- 如果 course_package 表已存在,则跳过重命名
SET @table_exists = (SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'course');
SET @target_exists = (SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'course_package');
-- 如果 course 表存在且 course_package 不存在,则重命名
-- 使用预处理语句实现条件逻辑
SET @rename_sql = IF(@table_exists > 0 AND @target_exists = 0,
'RENAME TABLE course TO course_package',
'SELECT ''course_table already renamed or does not exist'' as info');
PREPARE stmt FROM @rename_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- =====================================================
-- 第二步:更新关联表的外键
-- =====================================================
SELECT '=== 更新 course_lesson 表外键 ===' as info;
-- 删除旧的外键(如果存在)
-- MySQL 不支持 DROP FOREIGN KEY IF EXISTS需要先检查是否存在
SET @fk_exists = (SELECT COUNT(*) FROM information_schema.key_column_usage
WHERE table_schema = DATABASE()
AND table_name = 'course_lesson'
AND constraint_name = 'fk_course_lesson_course_id');
SET @drop_fk_sql = IF(@fk_exists > 0,
'ALTER TABLE course_lesson DROP FOREIGN KEY fk_course_lesson_course_id',
'SELECT ''foreign key does not exist'' as info');
PREPARE stmt FROM @drop_fk_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 添加新的外键约束(指向 course_package
-- 首先检查新约束是否已存在
SET @new_fk_exists = (SELECT COUNT(*) FROM information_schema.key_column_usage
WHERE table_schema = DATABASE()
AND table_name = 'course_lesson'
AND constraint_name = 'fk_course_lesson_package_id');
SET @add_fk_sql = IF(@new_fk_exists = 0,
'ALTER TABLE course_lesson ADD CONSTRAINT fk_course_lesson_package_id FOREIGN KEY (course_id) REFERENCES course_package(id) ON DELETE CASCADE',
'SELECT ''new foreign key already exists'' as info');
PREPARE stmt FROM @add_fk_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- =====================================================
-- 第三步:验证表结构
-- =====================================================
SELECT '=== 验证重命名后的表结构 ===' as info;
SHOW TABLES LIKE 'course_package';
-- =====================================================
-- 完成
-- =====================================================
SELECT '=== V36 迁移完成 ===' as info;
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -0,0 +1,16 @@
-- =====================================================
-- 迁移 V37: 修复失败的 V36 迁移
--
-- 此迁移删除失败的 V36 记录,让 V36 可以重新运行
-- =====================================================
-- 删除失败的 V36 迁移记录
DELETE FROM flyway_schema_history
WHERE version = '36' AND success = 0;
-- 验证删除
SELECT '=== 已删除失败的 V36 迁移记录 ===' as info;
SELECT version, description, success, installed_on
FROM flyway_schema_history
WHERE version = '36'
ORDER BY installed_rank DESC;