Sequelize - 加入多列
Sequelize - Join with multiple column
我喜欢将以下查询转换为 sequelize 代码
select * from table_a
inner join table_b
on table_a.column_1 = table_b.column_1
and table_a.column_2 = table_b.column_2
我尝试了很多方法并遵循了很多提供的解决方案,但我无法通过 sequelize 代码实现所需的查询。
我达到的最大值如下:
select * from table_a
inner join table_b
on table_a.column_1 = table_b.column_1
第二个条件我也要
and table_a.column_2 = table_b.column_2
有什么合适的方法可以实现吗?
您需要定义 JOIN
语句的自己的 on
子句
ModelA.findAll({
include: [
{
model: ModelB,
on: {
col1: sequelize.where(sequelize.col("ModelA.col1"), "=", sequelize.col("ModelB.col1")),
col2: sequelize.where(sequelize.col("ModelA.col2"), "=", sequelize.col("ModelB.col2"))
},
attributes: [] // empty array means that no column from ModelB will be returned
}
]
}).then((modelAInstances) => {
// result...
});
关于@TophatGordon 在已接受答案的评论中的疑问:是否需要在模型中设置任何关联。
还经历了github issue raised back in 2012,还处于open状态。
所以我也遇到了同样的情况,并试图为左外连接设置我自己的 ON
条件。
当我直接尝试在 Table1.findAll(...include Table2 with ON condition...)
中使用 on: {...}
时,它没有用。
它抛出一个错误:
EagerLoadingError [SequelizeEagerLoadingError]: Table2 is not associated to Table1!
我的用例是在左外连接中将表 1 中的两个 non-primary-key 列匹配到表 2 中的两个列。我将展示我是如何实现的以及实现了什么:
不要被 table 名称和列名弄糊涂了,因为我不得不更改它们,而不是我使用的原始名称。
所以我必须在 Table1(Task) 中创建一个关联,例如:
Task.associate = (models) => {
Task.hasOne(models.SubTask, {
foreignKey: 'someId', // <--- one of the column of table2 - SubTask: not a primary key here in my case; can be primary key also
sourceKey: 'someId', // <--- one of the column of table1 - Task: not a primary key here in my case; can be a primary key also
scope: {
[Op.and]: sequelize.where(sequelize.col("Task.some_id_2"),
// '=',
Op.eq, // or you can use '=',
sequelize.col("subTask.some_id_2")),
},
as: 'subTask',
// no constraints should be applied if sequelize will be creating tables and unique keys are not defined,
//as it throws error of unique constraint
constraints: false,
});
};
因此查找查询如下所示:
Task.findAll({
where: whereCondition,
// attributes: ['id','name','someId','someId2'],
include: [{
model: SubTask, as: 'subTask', // <-- model name and alias name as defined in association
attributes: [], // if no attributes needed from SubTask - empty array
},
],
});
结果查询:
- 一个匹配条件取自[foreignKey] = [sourceKey]
- 第二个匹配条件由
sequelize.where(...)
得到,用在scope:{...}
select
"Task"."id",
"Task"."name",
"Task"."some_id" as "someId",
"Task"."some_id_2" as "someId2"
from
"task" as "Task"
left outer join "sub_task" as "subTask" on
"Task"."some_id" = "subTask"."some_id"
and "Task"."some_id_2" = "subTask"."some_id_2";
另一种实现与上述相同的方法来解决在包含中使用 Table1 时的问题,即当 Table1 显示为第 2 级 table 或被其他 table 包含时 - 例如 Table0
Task.associate = (models) => {
Task.hasOne(models.SubTask, {
foreignKey: 'someId', // <--- one of the column of table2 - SubTask: not a primary key here in my case; can be primary key also
sourceKey: 'someId', // <--- one of the column of table1 - Task: not a primary key here in my case; can be a primary key also
as: 'subTask',
// <-- removed scope -->
// no constraints should be applied if sequelize will be creating tables and unique keys are not defined,
//as it throws error of unique constraint
constraints: false,
});
};
所以从 Table0 中查找的查询看起来像这样:而且 foreignKey 和 sourceKey 也不会被考虑,因为我们现在将使用自定义 on: {...}
Table0.findAll({
where: whereCondition,
// attributes: ['id','name','someId','someId2'],
include: {
model: Task, as: 'Table1AliasName', // if association has been defined as alias name
include: [{
model: SubTask, as: 'subTask', // <-- model name and alias name as defined in association
attributes: [], // if no attributes needed from SubTask - empty array
on: {
[Op.and]: [
sequelize.where(
sequelize.col('Table1AliasName_OR_ModelName.some_id'),
Op.eq, // '=',
sequelize.col('Table1AliasName_OR_ModelName->subTask.some_id')
),
sequelize.where(
sequelize.col('Table1AliasName_OR_ModelName.some_id_2'),
Op.eq, // '=',
sequelize.col('Table1AliasName_OR_ModelName->subTask.some_id_2')
),
],
},
}],
}
});
如果您的 table 已经创建,请跳过下面的部分...
将约束设置为 false,就好像 sequelize 试图创建第二个 table(SubTask) 它可能会抛出错误 (DatabaseError [SequelizeDatabaseError]: there is no unique constraint matching given keys for referenced table "task")
由于以下查询:
create table if not exists "sub_task" ("some_id" INTEGER, "some_id_2"
INTEGER references "task" ("some_id") on delete cascade on update
cascade, "data" INTEGER);
如果我们设置 constraint: false,它会创建下面的查询,当我们引用 non-primary 列时不会抛出唯一约束错误:
create table if not exists "sub_task" ("some_id" INTEGER, "some_id_2" INTEGER, "data" INTEGER);
我喜欢将以下查询转换为 sequelize 代码
select * from table_a
inner join table_b
on table_a.column_1 = table_b.column_1
and table_a.column_2 = table_b.column_2
我尝试了很多方法并遵循了很多提供的解决方案,但我无法通过 sequelize 代码实现所需的查询。
我达到的最大值如下:
select * from table_a
inner join table_b
on table_a.column_1 = table_b.column_1
第二个条件我也要
and table_a.column_2 = table_b.column_2
有什么合适的方法可以实现吗?
您需要定义 JOIN
语句的自己的 on
子句
ModelA.findAll({
include: [
{
model: ModelB,
on: {
col1: sequelize.where(sequelize.col("ModelA.col1"), "=", sequelize.col("ModelB.col1")),
col2: sequelize.where(sequelize.col("ModelA.col2"), "=", sequelize.col("ModelB.col2"))
},
attributes: [] // empty array means that no column from ModelB will be returned
}
]
}).then((modelAInstances) => {
// result...
});
关于@TophatGordon 在已接受答案的评论中的疑问:是否需要在模型中设置任何关联。
还经历了github issue raised back in 2012,还处于open状态。
所以我也遇到了同样的情况,并试图为左外连接设置我自己的 ON
条件。
当我直接尝试在 Table1.findAll(...include Table2 with ON condition...)
中使用 on: {...}
时,它没有用。
它抛出一个错误:
EagerLoadingError [SequelizeEagerLoadingError]: Table2 is not associated to Table1!
我的用例是在左外连接中将表 1 中的两个 non-primary-key 列匹配到表 2 中的两个列。我将展示我是如何实现的以及实现了什么:
不要被 table 名称和列名弄糊涂了,因为我不得不更改它们,而不是我使用的原始名称。
所以我必须在 Table1(Task) 中创建一个关联,例如:
Task.associate = (models) => {
Task.hasOne(models.SubTask, {
foreignKey: 'someId', // <--- one of the column of table2 - SubTask: not a primary key here in my case; can be primary key also
sourceKey: 'someId', // <--- one of the column of table1 - Task: not a primary key here in my case; can be a primary key also
scope: {
[Op.and]: sequelize.where(sequelize.col("Task.some_id_2"),
// '=',
Op.eq, // or you can use '=',
sequelize.col("subTask.some_id_2")),
},
as: 'subTask',
// no constraints should be applied if sequelize will be creating tables and unique keys are not defined,
//as it throws error of unique constraint
constraints: false,
});
};
因此查找查询如下所示:
Task.findAll({
where: whereCondition,
// attributes: ['id','name','someId','someId2'],
include: [{
model: SubTask, as: 'subTask', // <-- model name and alias name as defined in association
attributes: [], // if no attributes needed from SubTask - empty array
},
],
});
结果查询:
- 一个匹配条件取自[foreignKey] = [sourceKey]
- 第二个匹配条件由
sequelize.where(...)
得到,用在scope:{...}
select "Task"."id", "Task"."name", "Task"."some_id" as "someId", "Task"."some_id_2" as "someId2" from "task" as "Task" left outer join "sub_task" as "subTask" on "Task"."some_id" = "subTask"."some_id" and "Task"."some_id_2" = "subTask"."some_id_2";
另一种实现与上述相同的方法来解决在包含中使用 Table1 时的问题,即当 Table1 显示为第 2 级 table 或被其他 table 包含时 - 例如 Table0
Task.associate = (models) => {
Task.hasOne(models.SubTask, {
foreignKey: 'someId', // <--- one of the column of table2 - SubTask: not a primary key here in my case; can be primary key also
sourceKey: 'someId', // <--- one of the column of table1 - Task: not a primary key here in my case; can be a primary key also
as: 'subTask',
// <-- removed scope -->
// no constraints should be applied if sequelize will be creating tables and unique keys are not defined,
//as it throws error of unique constraint
constraints: false,
});
};
所以从 Table0 中查找的查询看起来像这样:而且 foreignKey 和 sourceKey 也不会被考虑,因为我们现在将使用自定义 on: {...}
Table0.findAll({
where: whereCondition,
// attributes: ['id','name','someId','someId2'],
include: {
model: Task, as: 'Table1AliasName', // if association has been defined as alias name
include: [{
model: SubTask, as: 'subTask', // <-- model name and alias name as defined in association
attributes: [], // if no attributes needed from SubTask - empty array
on: {
[Op.and]: [
sequelize.where(
sequelize.col('Table1AliasName_OR_ModelName.some_id'),
Op.eq, // '=',
sequelize.col('Table1AliasName_OR_ModelName->subTask.some_id')
),
sequelize.where(
sequelize.col('Table1AliasName_OR_ModelName.some_id_2'),
Op.eq, // '=',
sequelize.col('Table1AliasName_OR_ModelName->subTask.some_id_2')
),
],
},
}],
}
});
如果您的 table 已经创建,请跳过下面的部分...
将约束设置为 false,就好像 sequelize 试图创建第二个 table(SubTask) 它可能会抛出错误 (DatabaseError [SequelizeDatabaseError]: there is no unique constraint matching given keys for referenced table "task")
由于以下查询:
create table if not exists "sub_task" ("some_id" INTEGER, "some_id_2" INTEGER references "task" ("some_id") on delete cascade on update cascade, "data" INTEGER);
如果我们设置 constraint: false,它会创建下面的查询,当我们引用 non-primary 列时不会抛出唯一约束错误:
create table if not exists "sub_task" ("some_id" INTEGER, "some_id_2" INTEGER, "data" INTEGER);