Node/Express/SQL Server分页开发:获取总条数及当前页数据报错求助
我来帮你搞定这个分页问题!在Node/Express+SQL Server环境下做分页,确实需要同时拿到不受分页影响的总数据行数和当前页数据,但两个查询的写法有不少容易踩的坑,尤其是异步处理和连接池复用这块,很容易导致报错或者请求挂起。
核心思路与正确实现
你提到的“写两个查询”是可行的,但要注意异步流程的控制和连接池的正确使用;另外还有更高效的方式——用SQL Server的窗口函数一次查询搞定,减少数据库请求次数。下面分别给出两种方案的正确代码:
方案1:两个独立查询(先查总条数,再查分页数据)
这种方式逻辑清晰,但需要注意用async/await处理异步,避免回调地狱,同时复用连接池(不要每次请求新建连接池):
const sql = require('mssql'); const config = require('./your-config-path'); // 替换成你的数据库配置文件路径 // 全局初始化连接池,不要每次请求新建 const pool = new sql.ConnectionPool(config); pool.connect().catch(err => console.error('连接池初始化失败:', err)); router.get('/', async (req, res) => { try { // 解析分页参数,默认第一页,每页10条 const { page = 1, pageSize = 10 } = req.query; const offset = (parseInt(page) - 1) * parseInt(pageSize); // 1. 查询总数据条数 const countQueryResult = await pool.request().query('SELECT COUNT(*) AS totalCount FROM YourTableName'); const totalCount = countQueryResult.recordset[0].totalCount; // 2. 查询当前页数据(注意必须加ORDER BY,否则OFFSET结果不确定) const dataQueryResult = await pool.request() .input('offset', sql.Int, offset) .input('pageSize', sql.Int, parseInt(pageSize)) .query(` SELECT * FROM YourTableName ORDER BY id -- 替换成你需要的排序字段 OFFSET @offset ROWS FETCH NEXT @pageSize ROWS ONLY `); const pageData = dataQueryResult.recordset; // 设置分页响应头(可选,方便前端获取分页信息) res.set('X-Total-Count', totalCount); res.set('X-Current-Page', page); res.set('X-Page-Size', pageSize); // 返回最终响应 res.json({ totalCount, currentPage: parseInt(page), pageSize: parseInt(pageSize), data: pageData }); } catch (err) { console.error('分页查询失败:', err); res.status(500).json({ error: '服务器内部错误', details: err.message }); } });
方案2:用窗口函数一次查询(更高效)
用COUNT(*) OVER()窗口函数可以在查询分页数据的同时,直接拿到总条数,只需要一次数据库请求:
router.get('/', async (req, res) => { try { const { page = 1, pageSize = 10 } = req.query; const offset = (parseInt(page) - 1) * parseInt(pageSize); const queryResult = await pool.request() .input('offset', sql.Int, offset) .input('pageSize', sql.Int, parseInt(pageSize)) .query(` SELECT *, COUNT(*) OVER() AS totalCount FROM YourTableName ORDER BY id OFFSET @offset ROWS FETCH NEXT @pageSize ROWS ONLY `); const pageData = queryResult.recordset; // 总条数取第一条数据的totalCount即可(如果没有数据则为0) const totalCount = pageData.length > 0 ? pageData[0].totalCount : 0; // 响应头和返回数据处理 res.set('X-Total-Count', totalCount); res.set('X-Current-Page', page); res.set('X-Page-Size', pageSize); res.json({ totalCount, currentPage: parseInt(page), pageSize: parseInt(pageSize), data: pageData.map(item => { // 移除返回数据中的totalCount字段,只保留业务数据 const { totalCount, ...businessData } = item; return businessData; }) }); } catch (err) { console.error('分页查询失败:', err); res.status(500).json({ error: '服务器内部错误', details: err.message }); } });
你原来代码可能报错的原因
- 异步流程混乱:没有用
async/await或正确的回调嵌套,导致还没拿到查询结果就尝试发送响应,或者请求挂起; - 连接池使用错误:每次请求新建
sql.ConnectionPool,但没等连接成功就执行查询,导致连接失败; - SQL语法问题:
OFFSET/FETCH是SQL Server 2012及以上版本才支持的语法,或者没有加ORDER BY(必须加,否则分页结果无意义); - 参数未校验:前端传的
page和pageSize是字符串,直接拼接进SQL会导致语法错误,建议转成数字后用参数化查询(上面的代码已经做了处理)。
内容的提问来源于stack exchange,提问作者userlkjsflkdsvm




