Sequelize - where 子句中的子查询
Sequelize - subquery in where clause
我在我的 Express 应用程序中使用 Sequelize。我需要生成一个在 WHERE
子句中包含子查询的查询。
SELECT *
FROM MyTable
WHERE id NOT IN (
SELECT fkey
FROM MyOtherTable
WHERE field1 = 1
AND field2 = 2
AND field3 = 3
)
我首先尝试 relations/associations 通过我的模型,但无法正常工作。类似于:
MyTable.find( {
where: {
id: {
$notIn: // <= what goes here? Can I somehow reference my include model?
}
},
include: [ {
model: MyOtherTable,
where: {
field1: 1,
field2: 2,
field3: 3
} ]
} );
然后我尝试使用 Sequelize.where()
,没有成功。
然后我尝试了 Sequelize.literal()
并且它有效但不确定它是否是 "proper" 在 Sequelize 中的 where 子句中进行子查询的方式,因为我我是新手。
MyTable.find( {
where: {
id: {
$notIn: sequelize.literal(
'( SELECT fkey ' +
'FROM MyOtherTable ' +
'WHERE field1 = ' + field1 +
' AND field2 = ' + field2 +
' AND field3 = ' + field3 +
')'
}
}
} );
我也知道我可以使用 Sequelize.query()
,但我真的不知道我是否应该伸手去拿它,或者 literal()
是否合适,因为我觉得我忽略了一些东西.
我真的很想知道如何使用 "proper" 方式在 WHERE
子句中执行子查询。
感谢反馈!
我在我的项目中遇到了类似的问题。
我选择实现它的方式有点不同,原因有两个:
- 如果在某个时间点 Sequelize 决定实施子查询 - 语法就绪。
- 使用 Sequelize 保护来防止 SQL 注入。
这是我的代码片段,希望对您有所帮助。
续集 v5
const tempSQL = sequelize.dialect.QueryGenerator.selectQuery('MyOtherTable',{
attributes: ['fkey'],
where: {
field1: 1,
field2: 2,
field3: 3
}})
.slice(0,-1); // to remove the ';' from the end of the SQL
MyTable.find( {
where: {
id: {
[Sequelize.Op.notIn]: sequelize.literal(`(${tempSQL})`)
}
}
} );
续集 v6
const tempSQL = sequelize.dialect.queryGenerator.selectQuery('MyOtherTable',{
attributes: ['fkey'],
where: {
field1: 1,
field2: 2,
field3: 3
}})
.slice(0,-1); // to remove the ';' from the end of the SQL
MyTable.find( {
where: {
id: {
[Sequelize.Op.notIn]: sequelize.literal(`(${tempSQL})`)
}
}
} );
有些人可能会选择不使用 tempSQL 变量,而只是在 find 结构中构建 SQL(也许使用辅助方法?)
我还认为这可能是 sequelize 的子查询扩展的基础,因为它几乎使用相同的语法。
除了@Shahar Hadas 的回答,因为我在使用他展示的代码时遇到了一些错误。
这是一个更复杂的例子。在这个例子中,我们有一个名为“艺术家”的主要table,与“标签”存在多对多关系。 “标签”与我命名为“TagType”的预定义标签列表相关联。
我们想要获取链接到所有搜索到的标签 (TagType Id) 的所有艺术家。
const tagsSearched = [1, 2];
const subQueryOptions = {
attributes: ['id'], // You have to list at least one attribute
include: [
{
model: models.Tag,
required: true,
attributes: [], // Avoid the only_full_group_by error
through: {
attributes: [], // Avoid the only_full_group_by error
},
include: {
model: models.TagType,
required: true,
attributes: [], // Avoid the only_full_group_by error
where: {
id: {
[Op.in]: tagsSearched, // Array of tags searched
}
},
},
}
],
group: sequelize.col('artist.id'), // Group by the main parent ID of this query
having: sequelize.where(sequelize.fn('count',
sequelize.col('tags.tagType.id')), {
[Op.gte]: tagsSearched.length,
}), // Get only the artists that have at least the "tagsSearched" associated
}
// Parse the subQueryOptions, this operation would serialize the queryOptions
Model._validateIncludedElements.bind(models.Artist)(subQueryOptions);
// First argument has to be a string (table name, by default in plural)
// Second argument is our serialized query options
// Third argument is the model used
const artistsSubQuery = sequelize.dialect.queryGenerator.selectQuery("artists", subQueryOptions, models.Artist)
.slice(0,-1); // to remove the ';' from the end of the SQL query
models.Artist.findAll({
where: {
id: {
[Op.in]: sequelize.literal(`(${artistsSubQuery})`),
}
}
});
如有问题我会更新。
我在我的 Express 应用程序中使用 Sequelize。我需要生成一个在 WHERE
子句中包含子查询的查询。
SELECT *
FROM MyTable
WHERE id NOT IN (
SELECT fkey
FROM MyOtherTable
WHERE field1 = 1
AND field2 = 2
AND field3 = 3
)
我首先尝试 relations/associations 通过我的模型,但无法正常工作。类似于:
MyTable.find( {
where: {
id: {
$notIn: // <= what goes here? Can I somehow reference my include model?
}
},
include: [ {
model: MyOtherTable,
where: {
field1: 1,
field2: 2,
field3: 3
} ]
} );
然后我尝试使用 Sequelize.where()
,没有成功。
然后我尝试了 Sequelize.literal()
并且它有效但不确定它是否是 "proper" 在 Sequelize 中的 where 子句中进行子查询的方式,因为我我是新手。
MyTable.find( {
where: {
id: {
$notIn: sequelize.literal(
'( SELECT fkey ' +
'FROM MyOtherTable ' +
'WHERE field1 = ' + field1 +
' AND field2 = ' + field2 +
' AND field3 = ' + field3 +
')'
}
}
} );
我也知道我可以使用 Sequelize.query()
,但我真的不知道我是否应该伸手去拿它,或者 literal()
是否合适,因为我觉得我忽略了一些东西.
我真的很想知道如何使用 "proper" 方式在 WHERE
子句中执行子查询。
感谢反馈!
我在我的项目中遇到了类似的问题。 我选择实现它的方式有点不同,原因有两个:
- 如果在某个时间点 Sequelize 决定实施子查询 - 语法就绪。
- 使用 Sequelize 保护来防止 SQL 注入。
这是我的代码片段,希望对您有所帮助。
续集 v5
const tempSQL = sequelize.dialect.QueryGenerator.selectQuery('MyOtherTable',{
attributes: ['fkey'],
where: {
field1: 1,
field2: 2,
field3: 3
}})
.slice(0,-1); // to remove the ';' from the end of the SQL
MyTable.find( {
where: {
id: {
[Sequelize.Op.notIn]: sequelize.literal(`(${tempSQL})`)
}
}
} );
续集 v6
const tempSQL = sequelize.dialect.queryGenerator.selectQuery('MyOtherTable',{
attributes: ['fkey'],
where: {
field1: 1,
field2: 2,
field3: 3
}})
.slice(0,-1); // to remove the ';' from the end of the SQL
MyTable.find( {
where: {
id: {
[Sequelize.Op.notIn]: sequelize.literal(`(${tempSQL})`)
}
}
} );
有些人可能会选择不使用 tempSQL 变量,而只是在 find 结构中构建 SQL(也许使用辅助方法?)
我还认为这可能是 sequelize 的子查询扩展的基础,因为它几乎使用相同的语法。
除了@Shahar Hadas 的回答,因为我在使用他展示的代码时遇到了一些错误。
这是一个更复杂的例子。在这个例子中,我们有一个名为“艺术家”的主要table,与“标签”存在多对多关系。 “标签”与我命名为“TagType”的预定义标签列表相关联。 我们想要获取链接到所有搜索到的标签 (TagType Id) 的所有艺术家。
const tagsSearched = [1, 2];
const subQueryOptions = {
attributes: ['id'], // You have to list at least one attribute
include: [
{
model: models.Tag,
required: true,
attributes: [], // Avoid the only_full_group_by error
through: {
attributes: [], // Avoid the only_full_group_by error
},
include: {
model: models.TagType,
required: true,
attributes: [], // Avoid the only_full_group_by error
where: {
id: {
[Op.in]: tagsSearched, // Array of tags searched
}
},
},
}
],
group: sequelize.col('artist.id'), // Group by the main parent ID of this query
having: sequelize.where(sequelize.fn('count',
sequelize.col('tags.tagType.id')), {
[Op.gte]: tagsSearched.length,
}), // Get only the artists that have at least the "tagsSearched" associated
}
// Parse the subQueryOptions, this operation would serialize the queryOptions
Model._validateIncludedElements.bind(models.Artist)(subQueryOptions);
// First argument has to be a string (table name, by default in plural)
// Second argument is our serialized query options
// Third argument is the model used
const artistsSubQuery = sequelize.dialect.queryGenerator.selectQuery("artists", subQueryOptions, models.Artist)
.slice(0,-1); // to remove the ';' from the end of the SQL query
models.Artist.findAll({
where: {
id: {
[Op.in]: sequelize.literal(`(${artistsSubQuery})`),
}
}
});
如有问题我会更新。