在 SQLAPI c++ 中向 IN 子句添加多个参数

Add multiple parameters to IN clause in SQLAPI c++

本文关键字:添加 参数 子句 IN SQLAPI c++ 中向      更新时间:2023-10-16

我正在使用SQLAPI从C++代码连接到SQL-Server数据库。我需要使用 IN 子句执行一个简单的 select 语句,其中子句中的字符串值作为字符串向量接收。我们想使用参数化查询,所以做了这样的事情:

std::string getSQLQuery(std::vector<std::string> ids){
std::stringstream sql;
sql << "SELECT ID, Name, DOB FROM Employees WHERE ID IN (";
unsigned int counter = 0;
for each (auto id in ids)
{
sql << ":" << counter + 1;
if (++counter < ids.size())
{
sql << ",";
}
}
sql << ")";
return sql.str();
}

然后

int param_counter = 0;
for each (auto id in ids) {
command.Param(++param_counter).setAsString() = id.c_str();
}

任何人都可以提出更好的方法吗?

好吧,我不想削弱你的基本问题,我认为这是"这样做的好方法是什么?",但你的C++有一些基本的语法问题。从上面的错误代码推断出您的意图,我发现目标是从任意一组输入 id 中创建一个具有通用 SQL 选择查询的命令合成器。凉。我认为首先创建一个带有插入点的合成模板命令,然后使用它们的参数替换方案没有任何好处。不妨一次全部合成。编译时正确的版本看起来像这样(进行一些调整以使其更可重用) -

std::string getSQLQuery(
const std::string& columns
, const std::string& table
, const std::vector<std::string>& ids
){
// Check for empty strings/arrays here - leads to illegal SQL,
// so error out or except on empty ids, columns, or "table".
std::stringstream sql("SELECT ", std::ios_base::out | std::ios_base::ate);
sql << columns << " FROM " << table << " WHERE ID IN ( ";
// Trailing commas are not allowed in SQL, which makes synthesis a little trickier.
// We checked for empty inputs earlier, so we have at least one ID.
auto iter = ids.begin();
sql << *iter++;  // add the first (and possibly only) ID
for (; iter != ids.end(); ++iter) {  // add the rest (if any) with commas
sql << ", " << *iter;
}
sql << " )";   // <- should this be " );"? Or does SQLAPI++ deal with that?
return sql.str();  // There's a shrink-to-fit method you may want to use here.
}

现在你可以做一些类似的事情——

std::vector<std::string> id_array{ "1", "50", "aardvark" };
SACommand basic_command(connection, getSQLQuery("ID, Name, DOB", "Employees", id_array));
basic_command.Execute();

这完全跳过了第二个替换阶段。SQLAPI++ 参数替换适用于具有更严格的模板的查询,但您正在执行更动态的操作。您可以想象使用列的输入数组进一步扩展它,以避免表列表中的语法错误(就像我们在 id 列表中所做的那样)。此外,由于 id 通常是数字的,因此您可以将 id 数组设为std::vector<std::uint64_t>或任何适合您特定应用程序的内容。事实上,您可以通过制作签名来使用相同的代码体处理这两种情况 -

template<typename T> std::string getSQLQuery(
const std::string& columns
, const std::string& table
, const std::vector<T>& ids
){
... // rest of the implementation is the same
}

我是一个新的贡献者,但是一个长期用户,所以只是关于问题。当你问这样的问题时,"任何人都可以提出一个更好的方法吗?",答案总是"是的"。那里有很多聪明的人,每个高级问题都有无数的解决方案。将来,您想陈述您尝试解决的问题(在这种情况下不难弄清楚),如果您展示了一个尝试过但失败的解决方案,您应该详细说明它是如何失败的。就您提出的代码而言,失败的最明显原因是它在语法上是错误的 - 编译器不会接受它。"for each"来自其他一些语言。在C++中,它类似于"for (auto id : ids)"。但是,如果您只是尝试显示某种伪代码,则表明您并不真正知道现有方法是否有效,因为它尚未尝试过。即使在这种情况下,您也应该说出您不喜欢所提出的解决方案的地方(例如使用 SQLAPI++ 替换方案的不必要的第二步),并具体询问是否有人可以想到一种方法来删除它。我是一个健谈者,我会给出同样的回答,但为了将来参考,尽量避免一个归结为"以下代码已损坏"的问题。有人帮我修好了。只是FWIW。