前言
在node.js web框架中使用sequelize来作为ORM是十分方便的。但是,有的时候我们需要用到子查询语句,使用sequelize无法完成需求。这时候,
如果你的查询语句不是很复杂,可以使用sequelize提供的query()方法直接执行生成的sql语句。
如果你的查询语句很复杂,但是子表查询结果数据不是很多,你可以先把子表查询结果获取到,在后端代码中进行数据处理,完成其它操作。
如果你的查询语句很复杂,并且子表查询结果数据非常多,不可能在代码中完成数据处理,简单的可以执行两次,第一次查询字表数据,获取到查询的sql语句,拼接好子查询语句后再查询一次即可。
由于sequelize只有执行查询后才可以在logging的回调函数中获取到生成的sql语句,这样就会多执行一次无用的数据库查询,下边写一个不执行查询获取sql语句的方法。
实例
- 以nodejs为例
- 根据options获取sql语句
const Utils = require('sequelize/lib/utils');
/**
* @parms model 当前表的模型实例
* @options {object} 查询参数
*/
module.exports = function genSqlString(model, options) {
return (function (options) {
const tableNames = {};
tableNames[this.getTableName(options)] = true;
options = Utils.cloneDeep(options);
options = Object.assign({}, options, {
hooks: true,
rejectOnEmpty: true,
type: 'SELECT',
model: this,
tableNames: Object.keys(tableNames)
});
options.originalAttributes = this._injectDependentVirtualAttributes(options.attributes);
if (options.include) {
options.hasJoin = true;
this._validateIncludedElements(options, tableNames);
if (
options.attributes
&& !options.raw
&& this.primaryKeyAttribute
&& !options.attributes.includes(this.primaryKeyAttribute)
&& (!options.group || !options.hasSingleAssociation || options.hasMultiAssociation)
) {
options.attributes = [this.primaryKeyAttribute].concat(options.attributes);
}
}
if (!options.attributes) {
options.attributes = Object.keys(this.rawAttributes);
options.originalAttributes = this._injectDependentVirtualAttributes(options.attributes);
}
this.options.whereCollection = options.where || null;
Utils.mapFinderOptions(options, this);
options = this._paranoidClause(this, options);
return this.QueryGenerator.selectQuery(this.getTableName(options), options, this);
}).bind(model)(options);
};
- 补充一个执行后获取sql语句的实例
let sql = '';
options.logging = function (str) {
sql = str.substring(20, str.length-1); // 截取其中的sql语句
};
await models.OrderBasic.findAll(options); // options为查询时存入的参数
总结
-
获取sql语句的方法实际上是将源码中生成sql语句的部分提取出来了
-
目前还没有遇到sql解析错误,等遇到了再来更新