有没有一种方法可以根据其值可能为空的JSON对象动态构建MySQL查询。
例如,从这样的一个对象开始:
{
"a": 1
"b": ""
"c": "foo"
}
创建类似这样的查询(“ b”为空,不应考虑在内):
SELECT * FROM db.table
WHERE a = 1
AND c = "foo"
或
SELECT * FROM db.table
WHERE a = 1
AND b = ????
AND c = "foo"
编辑:可能确实是重复的。但我认为,例如使用变量和IF语句,这是一种更多的SQL方法。
编辑2:我找到了一种方法(使用node.js API,但在其他语言中应该类似):
const jsonObj = {
"a": 1,
"b": "",
"c": "foo"
}
const query = `
SELECT * FROM db.table
WHERE
IF('${jsonObj.a}' != '', a = '${jsonObj.a}', 1=1)
AND
IF('${jsonObj.b}' != '', b = '${jsonObj.b}', 1=1)
AND
IF('${jsonObj.c}' != '', c = '${jsonObj.c}', 1=1)
`
当然,此代码本身并不可用,必须加以修改以记住注入问题。
答案 0 :(得分:1)
重要:此策略对SQL Injection Attacks开放。您必须转义这些值-最好使用准备好的查询。没有数据库客户端的更多知识,就无法指导您如何操作。
添加:我强烈建议您将允许列列入白名单,并且仅允许将白名单中的列键用于查询。下面的示例包含一个白名单来说明这一点。
这里是一个MVP,它将处理任意/动态对象,并根据您的请求构建SQL语句:
const obj = {
"a": 1,
"b": "",
"c": "foo",
"bad": "disallowed"
}
// example of how to use a whitelist
const whitelist = ['a', 'c'];
// set up an empty array to contain the WHERE conditions
let where = [];
// Iterate over each key / value in the object
Object.keys(obj).forEach(function (key) {
// if the key is not whitelisted, do not use
if ( ! whitelist.includes(key) ) {
return;
}
// if the value is an empty string, do not use
if ( '' === obj[key] ) {
return;
}
// if we've made it this far, add the clause to the array of conditions
where.push(`\`${key}\` = "${obj[key]}"`);
});
// convert the where array into a string of AND clauses
where = where.join(' AND ');
// if there IS a WHERE string, prepend with WHERE keyword
if (where) {
where = `WHERE ${where}`;
}
const sql = `SELECT * FROM table ${where}`;
console.log(sql);
// SELECT * FROM table WHERE `a` = "1" AND `c` = "foo"
注意:
"
),这肯定会失败答案 1 :(得分:1)
让我们尝试创建一个可以处理许多复杂查询的函数
function prepareStmtFromObject(params) {
const constraints = [];
const data = [];
Object.keys(params).forEach((item) => {
if (!params[item] || params[item] == "") {
return;
}
if (Array.isArray(params[item])) {
constraints.push(`${item} in (?)`);
data.push(params[item]);
} else if (typeof params[item] === "string" && params[item].indexOf(",") > -1) {
constraints.push(`${item} in (?)`);
data.push(params[item].split(","));
} else if (params[item] instanceof RegExp) {
constraints.push(`${item} REGEXP ?`);
data.push(params[item]);
} else if (params[item] && typeof params[item] === "object") {
Object.keys(params[item]).forEach((value) => {
if (value === "$gte") {
constraints.push(`${item} >= ?`);
data.push(params[item][value]);
} else if (value === "$lte") {
constraints.push(`${item} <= ?`);
data.push(params[item][value]);
} else if (value === "$gt") {
constraints.push(`${item} > ?`);
data.push(params[item][value]);
} else if (value === "$lt") {
constraints.push(`${item} < ?`);
data.push(params[item][value]);
} else if (value === "$like") {
if (Array.isArray(params[item][value])) {
const localConstraints = [];
params[item][value].forEach((likeValues) => {
localConstraints.push(`${item} LIKE ?`);
data.push(`%${likeValues}%`);
});
constraints.push(`(${localConstraints.join(" OR ")})`);
} else if (typeof params[item][value] === "string" && params[item][value].indexOf(",") > -1) {
const localConstraints = [];
params[item][value] = params[item][value].split(",");
params[item][value].forEach((likeValues) => {
localConstraints.push(`${item} LIKE ?`);
data.push(`%${likeValues}%`);
});
constraints.push(`(${localConstraints.join(" OR ")})`);
} else {
constraints.push(`${item} LIKE ?`);
data.push(`%${params[item][value]}%`);
}
}
});
} else {
constraints.push(`${item} = ?`);
data.push(params[item]);
}
});
return { constraints, data };
}
const data = {
userId: 1,
company: ["google", "microsoft"],
username: { $like: "Test" },
name: { $like: [ "Test1", "Test2" ] },
age: { $gt: 10 }
}
const stmt = prepareStmtFromObject(data);
console.log("SELECT * FROM user WHERE ", stmt.constraints.join(" and "));
console.log(stmt.data);
上面的函数返回一个约束和一个查询数组,可用于转义字符。这样,您还可以防止SQL注入。我假设您使用的是mysql软件包