如何通过Knex.js/Express迁移在PostgreSQL中创建多表外键并解决报错
报错核心原因
你的迁移代码在PostgreSQL环境下执行必然抛出字段不存在类错误,根本问题是你只声明了外键约束,但没有在Overview表结构里预先定义这些约束对应的字段本身。直接调用table.foreign('user_id')时,Knex会尝试给当前表不存在的user_id字段添加外键,PostgreSQL会直接抛出类似column "user_id" of relation "Overview" does not exist的异常。
除了这个核心错误,还有几个高频触发迁移失败的坑需要排查:
- 外键字段的数据类型必须和被关联表的参照字段类型完全一致:比如被关联的
users.user_id是uuid类型,Overview表的user_id也必须定义为uuid;如果被关联字段是自增整型,对应的Overview字段也必须是同范围的整型,类型不匹配时PostgreSQL会直接拒绝创建外键 - PostgreSQL的标识符大小写规则:未加引号的表名、字段名会被数据库自动转为小写,如果之前创建业务表时保留了驼峰命名(比如
playerStats)且建表语句加了引号,数据库里实际的表名是区分大小写的"playerStats",此时直接用无引号的表名引用会触发关系不存在的错误 - 迁移执行顺序:Overview表的迁移脚本必须排在所有被关联业务表(users、playerStats、registration等)的迁移之后执行,否则会触发被关联表不存在的异常
可直接运行的修正版迁移代码
exports.up = function (knex) { return knex.schema.createTable('Overview', (table) => { table.uuid('overview_id').primary() // 先定义所有外键关联的字段,类型必须与被关联表的参照字段完全对齐 table.uuid('user_id') table.uuid('player_id') table.uuid('registration_id') table.uuid('planet_id') table.uuid('buildings_id') table.uuid('production_id') table.uuid('research_id') table.uuid('player_fleet_id') table.uuid('player_defense_id') // 再为已定义的字段添加外键约束 table.foreign('user_id').references('user_id').inTable('users').onDelete('cascade') table.foreign('player_id').references('player_id').inTable('playerStats').onDelete('cascade') table.foreign('registration_id').references('registration_id').inTable('registration').onDelete('cascade') table.foreign('planet_id').references('planet_id').inTable('planetList').onDelete('cascade') table.foreign('buildings_id').references('buildings_id').inTable('buildings').onDelete('cascade') table.foreign('production_id').references('production_id').inTable('production').onDelete('cascade') table.foreign('research_id').references('research_id').inTable('research').onDelete('cascade') table.foreign('player_fleet_id').references('player_fleet_id').inTable('playerFleet').onDelete('cascade') table.foreign('player_defense_id').references('player_defense_id').inTable('playerDefense').onDelete('cascade') }) }
提示:如果业务表的参照字段为整型而非uuid,只需将上述字段定义替换为对应的整型类型即可,必须保证两端字段类型完全一致。
内容的提问来源于stack exchange,提问作者JonathanMartin
相关产品推荐
相关产品推荐

