Tedious 或 Sequelize 对 `findOne()` 使用了错误的语法
Tedious or Sequelize uses the wrong syntax for `findOne()`
我正在使用带有 Tedious 的 Sequelize 来访问 SQL Server 2008。
当我执行 sequelizeModel.findOne()
时出现异常 -
Unhandled rejection SequelizeDatabaseError: Invalid usage of the option NEXT in the FETCH statement.
我知道 SQL Server 2008 不支持 OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
,这就是抛出异常的原因。
不过我也把繁琐的选项中的tdsVersion
明确设置为7_3_B
。
如此处所述 -
http://pekim.github.io/tedious/api-connection.html
我已经尝试了所有的 tds 版本,生成的查询语法总是包含 FETCH/NEXT
语法。
我错过了什么吗?
语法不应该特定于 tds 版本吗?
我还验证了 tdsVersion
选项正在从 sequelize 成功传递到繁琐的连接库。
生成的查询语法示例 -
SELECT
[id], [FIRST_NAME], [LAST_NAME]
FROM
[USERs] AS [USERS]
ORDER BY
[id]
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY;
这是 Sequelize 中的一个问题——它使用 OFFSET FETCH 语法,仅在 SQL Server 2012 及更新版本中受支持。
我在 GitHub 上将此作为问题提交:https://github.com/sequelize/sequelize/issues/4404
该问题还影响 findById
方法。该方法的解决方法是使用 findAll
和 where
来指定 ID,并且仅使用返回数组中的第一个元素:
Thing.findAll({
where: {id: id}
}).then( function(things) {
if (things.length == 0) {
// handle error
}
doSomething(things[0])
}).catch( function(err) {
// handle error
});
如果你可以更改节点模块中的sequelize 库。请按照以下步骤操作:
转到 Node_modules -> sequelize ->lib -> mssql -> query-generator.js
你会发现这一行:
fragment += ` OFFSET ${this.escape(offset)} ROWS`;
在上面添加一行:
fragment += ` ORDER BY ${this.quoteTable(options.tableAs || model.name)}.${this.quoteIdentifier(model.primaryKeyField)}`;
这应该是这样的:
fragment += ` ORDER BY ${this.quoteTable(options.tableAs || model.name)}.${this.quoteIdentifier(model.primaryKeyField)}`;
fragment += ` OFFSET ${this.escape(offset)} ROWS`;
初始化后立即执行"sequeIize.authenticate"方法解决了我的问题。我不知道这里发生了什么,但是我遇到了同样的错误。
SequelizeDatabaseError: Invalid usage of the option NEXT in the FETCH statement.
at Query.formatError (C:\xampp\htdocs\Benoit\node_modules\sequelize\lib\dialects\mssql\query.js:315:12)
at Request.connection.lib.Request [as userCallback] (C:\xampp\htdocs\Benoit\node_modules\sequelize\lib\dialects\mssql\query.js:107:25)
at Request._this.callback (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\request.js:60:27)
at Connection.endOfMessageMarkerReceived (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\connection.js:1922:20)
at Connection.dispatchEvent (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\connection.js:1004:38)
at Parser.<anonymous> (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\connection.js:805:18)
at emitOne (events.js:116:13)
at Parser.emit (events.js:211:7)
at Parser.<anonymous> (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\token\token-stream-parser.js:54:15)
at emitOne (events.js:116:13)
at Parser.emit (events.js:211:7)
at addChunk (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_readable.js:291:12)
at readableAddChunk (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_readable.js:278:11)
at Parser.Readable.push (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_readable.js:245:10)
at Parser.Transform.push (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_transform.js:148:32)
at Parser.afterTransform (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_transform.js:91:10)
at Parser._transform (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\token\stream-parser.js:69:9)
at Parser.Transform._read (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_transform.js:184:10)
at Parser.Transform._write (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_transform.js:172:83)
at doWrite (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_writable.js:428:64)
at writeOrBuffer (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_writable.js:417:5)
at Parser.Writable.write (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_writable.js:334:11)
我在对一个项目的代码进行了简短的重组后遇到了错误,
我意识到,只是因为我的 sublime 的历史存储了它,所以我只是删除了项目中所有多余的代码,并且 authenticated 方法被注释了。
我不知道初始身份验证方法和查询的语法和句法之间有什么关系,我什至不认为一定有关系,但就是这样
我在使用 sequelize v4.42.0 和 SQL Server 2008 R2 (SP1) 时遇到同样的问题。检查 SequelizeJS 的源代码,我在文件 lib/dialects/mssql/query-generator.js 中发现该版本的第 821 行有 selectFromTableFragment 函数。在 826 行中存在一个 if 语句,该语句通过来自 Sequelize 选项对象的 databaseVersion 选项验证 SQL 服务器的版本号。
// Handle SQL Server 2008 with TOP instead of LIMIT
if (semver.valid(this.sequelize.options.databaseVersion) && semver.lt(this.sequelize.options.databaseVersion, '11.0.0')) {
http://docs.sequelizejs.com 的文档中没有此选项,我搜索过此选项但没有找到。在此选项中,我设置了我的 SQL 服务器版本号('10.50.2500' - 相当于 2008 R2 SP1),这确实有效。现在使用 SELECT TOP ... 而不是 OFFSET AND FETCH NEXT 创建查询。
我希望这能帮助像我一样遇到这个问题的其他人。
我正在使用 select @@version
->
Microsoft SQL Server 2014 - 12.0.2000.8 (X64)
Feb 20 2014 20:04:26
Copyright (c) Microsoft Corporation
Express Edition (64-bit) on Windows NT 6.3 <X64> (Build 17134: ) (Hypervisor)
并得到了同样的错误。 sequelize.authenticate()
没修好。
另请参阅:https://github.com/tediousjs/tedious/issues/872
对我来说,root cause。基本上,您需要一个 ORDER BY 才能使 OFFSET 有意义。上面的@prayag 回答添加了 ORDER BY.
校验码node_modules/sequelize/lib/dialects/mssql/query-generator.js
看到那部分
const dbVersion = this.sequelize.options.databaseVersion;
const isSQLServer2008 = semver.valid(dbVersion) && semver.lt(dbVersion, '11.0.0');
所以我刚刚添加了我的连接配置:
production: {
dialect: 'mssql',
databaseVersion: '10.50.6000',
host: process.env.DB_HOST,
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
dialectOptions: {
options: {
useUTC: false,
dateFirst: 1,
enableArithAbort: true,
encrypt: false,
},
},
},
我正在使用带有 Tedious 的 Sequelize 来访问 SQL Server 2008。
当我执行 sequelizeModel.findOne()
时出现异常 -
Unhandled rejection SequelizeDatabaseError: Invalid usage of the option NEXT in the FETCH statement.
我知道 SQL Server 2008 不支持 OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
,这就是抛出异常的原因。
不过我也把繁琐的选项中的tdsVersion
明确设置为7_3_B
。
如此处所述 -
http://pekim.github.io/tedious/api-connection.html
我已经尝试了所有的 tds 版本,生成的查询语法总是包含 FETCH/NEXT
语法。
我错过了什么吗?
语法不应该特定于 tds 版本吗?
我还验证了 tdsVersion
选项正在从 sequelize 成功传递到繁琐的连接库。
生成的查询语法示例 -
SELECT
[id], [FIRST_NAME], [LAST_NAME]
FROM
[USERs] AS [USERS]
ORDER BY
[id]
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY;
这是 Sequelize 中的一个问题——它使用 OFFSET FETCH 语法,仅在 SQL Server 2012 及更新版本中受支持。
我在 GitHub 上将此作为问题提交:https://github.com/sequelize/sequelize/issues/4404
该问题还影响 findById
方法。该方法的解决方法是使用 findAll
和 where
来指定 ID,并且仅使用返回数组中的第一个元素:
Thing.findAll({
where: {id: id}
}).then( function(things) {
if (things.length == 0) {
// handle error
}
doSomething(things[0])
}).catch( function(err) {
// handle error
});
如果你可以更改节点模块中的sequelize 库。请按照以下步骤操作: 转到 Node_modules -> sequelize ->lib -> mssql -> query-generator.js
你会发现这一行:
fragment += ` OFFSET ${this.escape(offset)} ROWS`;
在上面添加一行:
fragment += ` ORDER BY ${this.quoteTable(options.tableAs || model.name)}.${this.quoteIdentifier(model.primaryKeyField)}`;
这应该是这样的:
fragment += ` ORDER BY ${this.quoteTable(options.tableAs || model.name)}.${this.quoteIdentifier(model.primaryKeyField)}`;
fragment += ` OFFSET ${this.escape(offset)} ROWS`;
初始化后立即执行"sequeIize.authenticate"方法解决了我的问题。我不知道这里发生了什么,但是我遇到了同样的错误。
SequelizeDatabaseError: Invalid usage of the option NEXT in the FETCH statement.
at Query.formatError (C:\xampp\htdocs\Benoit\node_modules\sequelize\lib\dialects\mssql\query.js:315:12)
at Request.connection.lib.Request [as userCallback] (C:\xampp\htdocs\Benoit\node_modules\sequelize\lib\dialects\mssql\query.js:107:25)
at Request._this.callback (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\request.js:60:27)
at Connection.endOfMessageMarkerReceived (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\connection.js:1922:20)
at Connection.dispatchEvent (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\connection.js:1004:38)
at Parser.<anonymous> (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\connection.js:805:18)
at emitOne (events.js:116:13)
at Parser.emit (events.js:211:7)
at Parser.<anonymous> (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\token\token-stream-parser.js:54:15)
at emitOne (events.js:116:13)
at Parser.emit (events.js:211:7)
at addChunk (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_readable.js:291:12)
at readableAddChunk (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_readable.js:278:11)
at Parser.Readable.push (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_readable.js:245:10)
at Parser.Transform.push (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_transform.js:148:32)
at Parser.afterTransform (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_transform.js:91:10)
at Parser._transform (C:\xampp\htdocs\Benoit\node_modules\tedious\lib\token\stream-parser.js:69:9)
at Parser.Transform._read (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_transform.js:184:10)
at Parser.Transform._write (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_transform.js:172:83)
at doWrite (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_writable.js:428:64)
at writeOrBuffer (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_writable.js:417:5)
at Parser.Writable.write (C:\xampp\htdocs\Benoit\node_modules\readable-stream\lib\_stream_writable.js:334:11)
我在对一个项目的代码进行了简短的重组后遇到了错误, 我意识到,只是因为我的 sublime 的历史存储了它,所以我只是删除了项目中所有多余的代码,并且 authenticated 方法被注释了。
我不知道初始身份验证方法和查询的语法和句法之间有什么关系,我什至不认为一定有关系,但就是这样
我在使用 sequelize v4.42.0 和 SQL Server 2008 R2 (SP1) 时遇到同样的问题。检查 SequelizeJS 的源代码,我在文件 lib/dialects/mssql/query-generator.js 中发现该版本的第 821 行有 selectFromTableFragment 函数。在 826 行中存在一个 if 语句,该语句通过来自 Sequelize 选项对象的 databaseVersion 选项验证 SQL 服务器的版本号。
// Handle SQL Server 2008 with TOP instead of LIMIT
if (semver.valid(this.sequelize.options.databaseVersion) && semver.lt(this.sequelize.options.databaseVersion, '11.0.0')) {
http://docs.sequelizejs.com 的文档中没有此选项,我搜索过此选项但没有找到。在此选项中,我设置了我的 SQL 服务器版本号('10.50.2500' - 相当于 2008 R2 SP1),这确实有效。现在使用 SELECT TOP ... 而不是 OFFSET AND FETCH NEXT 创建查询。
我希望这能帮助像我一样遇到这个问题的其他人。
我正在使用 select @@version
->
Microsoft SQL Server 2014 - 12.0.2000.8 (X64)
Feb 20 2014 20:04:26
Copyright (c) Microsoft Corporation
Express Edition (64-bit) on Windows NT 6.3 <X64> (Build 17134: ) (Hypervisor)
并得到了同样的错误。 sequelize.authenticate()
没修好。
另请参阅:https://github.com/tediousjs/tedious/issues/872
对我来说,root cause。基本上,您需要一个 ORDER BY 才能使 OFFSET 有意义。上面的@prayag 回答添加了 ORDER BY.
校验码node_modules/sequelize/lib/dialects/mssql/query-generator.js
看到那部分
const dbVersion = this.sequelize.options.databaseVersion;
const isSQLServer2008 = semver.valid(dbVersion) && semver.lt(dbVersion, '11.0.0');
所以我刚刚添加了我的连接配置:
production: {
dialect: 'mssql',
databaseVersion: '10.50.6000',
host: process.env.DB_HOST,
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
dialectOptions: {
options: {
useUTC: false,
dateFirst: 1,
enableArithAbort: true,
encrypt: false,
},
},
},