如何在Sequelize中使用子查询引用同一张表?
问题根因
你遇到的两个核心问题的原因非常明确:
- 报错
relation "Pricing" does not exist是因为你调用selectQuery时传入了模型名Pricing.name,如果你的模型没有显式指定tableName: 'Pricing',Sequelize默认会把模型名转成小写复数作为实际表名(比如pricings),生成的SQL里表名不匹配就会触发该错误。 - 子查询设置别名不需要正则替换,
FindOptions本身支持tableAlias参数可以直接指定表别名。
可行实现方案
方案1:基于queryGenerator的改造(保留类型提示)
按照以下步骤修改代码即可实现需求:
- 子查询和主查询都通过
tableAlias显式指定别名 - 子查询中ProductId的过滤条件用
literal引用主查询的字段 - 生成子查询SQL时传入模型的
tableName而非模型名name
完整代码示例:
const whereSubquery: FindOptions<Pricing> = { tableAlias: 't2', // 直接指定子查询表别名 attributes: ['id'], where: { // 引用主查询t1的ProductId字段,替换静态值 ProductId: { [Op.eq]: SequelizeTypeScript.literal('"t1"."ProductId"') }, validFrom: new Date(2021, 9, 15), }, order: [['validFrom', 'desc']], limit: 1, }; // 传入模型实际绑定的表名,避免表名不匹配报错 const subQuery: string = this.queryGenerator .selectQuery(Pricing.tableName, whereSubquery) .slice(0, -1); const result = await this.pricingRepository.findAll({ tableAlias: 't1', // 给主查询表设置别名 where: { id: { [Op.in]: SequelizeTypeScript.literal(`(${subQuery})`), }, }, });
方案2:直接使用rawQuery
如果你的查询逻辑不需要动态拼接条件,直接写原生SQL更简洁,也可以实现TS类型支持:
const result = await this.pricingRepository.sequelize.query<Pricing>( `SELECT * FROM "pricings" t1 WHERE id IN ( SELECT id FROM "pricings" t2 WHERE t1."productId" = t2."productId" ORDER BY t2.validfrom DESC LIMIT 1 )`, { type: QueryTypes.SELECT } );
两种方案都可以正常运行,你可以根据自己的场景选择:如果查询需要动态拼接where、order等条件选方案1,逻辑固定选方案2代码更易维护。
内容的提问来源于stack exchange,提问作者mike35x95x1
相关产品推荐
相关产品推荐

