如何创建可跨不同MySQL表查询的灵活函数?解决语法报错
问题描述
我正在尝试创建一个可以在MySQL中从不同表查询数据的函数。
我的函数代码如下:
async function getOne(table, table_parameter, parameter) { const result = await pool.query( `SELECT * FROM ? WHERE ? = ?`, [table, table_parameter, parameter] ) }
路由代码:
companiesRouter.get('/:id', async (request, response) => { const id = request.params.id const company = await getOne('Company', 'companyID', id) response.send(company) })
运行后出现如下错误:
sql: "SELECT * FROM 'Company' WHERE 'companyID' = '1'",
sqlState: '42000',
sqlMessage: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''Company' WHERE 'companyID' = '1'' at line 1"
请问有没有办法解决这个问题,让该函数正常工作?
解决方案
问题核心是参数化查询的误用:MySQL参数化查询仅会为数据值(比如1)添加引号,而表名、列名属于SQL标识符,不能用参数化方式处理——你的代码把Company(表名)和companyID(列名)当成了普通值,导致它们被自动套上单引号,直接违反SQL语法。
按以下步骤修复:
- 添加白名单校验:为防止SQL注入,必须先验证传入的表名、列名是否属于允许访问的范围,绝对不能直接把未校验的内容拼进SQL。
- 正确拼接标识符:对合法的表名、列名,用MySQL的反引号
`包裹后拼入SQL(避免标识符含特殊字符时出错)。 - 补充结果返回逻辑:原函数没有返回查询结果,需要补上返回语句。
修改后的函数代码示例:
// 定义允许访问的表及对应列的白名单 const allowedTables = { Company: ['companyID', 'name', /* 这里可以添加该表其他允许查询的列 */] }; async function getOne(table, table_parameter, parameter) { // 校验表名是否合法 if (!allowedTables[table]) { throw new Error('禁止访问该表'); } // 校验列名是否合法 if (!allowedTables[table].includes(table_parameter)) { throw new Error('禁止访问该列'); } // 拼接合法标识符,仅对参数值使用参数化查询 const result = await pool.query( `SELECT * FROM \`${table}\` WHERE \`${table_parameter}\` = ?`, [parameter] ); // 返回查询结果(根据你的数据库库返回格式调整,比如取result[0]) return result[0]; }
路由代码无需修改,白名单校验已经规避了SQL注入风险。
额外注意:
- 永远不要跳过白名单校验直接拼接表名/列名,这会导致严重的SQL注入漏洞。
- MySQL中标识符(表名、列名)必须用反引号
`包裹,单引号仅用于字符串值。
内容的提问来源于stack exchange,提问作者Aleksei Yin
相关产品推荐
相关产品推荐

