我们需要在工作场所定期解决的问题是如何根据用户提供的表/列名称构建sql语句。我想解决的问题是列名之间的逗号。
一种技术看起来像这样。
selectSql = "SELECT ";
for (z = 0; z < columns.size(); z++)
{
selectSql += columns[z]._name;
selectSql += ", ";
}
selectSql = selectSql(0, selectSql.len() - 2);
selectSql += "FROM some-table";
另一种技术看起来像这样
selectSql = "SELECT ";
for (z = 0; z < columns.size(); z++)
{
selectSql += columns[z]._name;
if (z < columns.size() - 1)
selectSql += ", ";
}
selectSql += "FROM some-table";
我对这些实现中的任何一个都不是特别着迷。
我很有兴趣听取有关解决此问题的其他方法的想法,着眼于使代码更易于阅读/理解/维护。
有哪些替代技术?
答案 0 :(得分:5)
在您的情况下,可以安全地假设至少有一列,否则进行选择没有意义。在这种情况下,您可以这样做:
selectSql = "SELECT ";
selectSql += columns[0]._name;
for (z = 1; z < columns.size(); z++) {
selectSql += ", ";
selectSql += columns[z]._name;
}
selectSql += " FROM some-table";
答案 1 :(得分:3)
您可以通过编写一个函数对象,并使用像strager一样的方法(尽管他的实现不是C ++)来一次性地解决问题,而不是每次都重复应用一个工作:
struct join {
std::string sep;
join(std::string const& sep): sep(sep) { }
template<typename Column>
std::string operator()(Column const& a, Column const& b) const {
return a._name + sep + b._name;
}
};
由于我不知道您的列类型,我已将其模板化了。现在,无论何时想要构建查询,只需执行
std::string query = std::accumulate(cols.begin(), cols.end(),
std::string("SELECT "), join(", ")) + " FROM some-table;";
答案 2 :(得分:2)
我们不打算删除尾随的逗号 这是因为您可以选择一个常量,SQL仍然有效。
SELECT A FROM T
-- Is the same as
SELECT A,1 FROM T
-- Apart from there is an extra column named 1 where each value is 1
因此使用STL使其紧凑:
#include <sstream>
#include <iterator>
#include <algorithm>
std::stringstream select;
// Build select statement.
select << "SELECT ";
std::copy(col.begin(),col.end(),std::ostream_iterator<std::string>(select," , "));
select << " 1 FROM TABLE PLOP";
答案 3 :(得分:1)
我建立语句的方式通常是:
pad = ""
stmt = "SELECT "
for (i = 0; i < number; i++)
{
stmt += pad + item[i]
pad = ", "
}
这是相对干净的 - 它会重新分配以填充每次迭代,但这是微不足道的。我已经使用过任何数量的微不足道的变化,但它是我所知道的最干净的机制。
当然,也会有其他人的答案来学习......
答案 4 :(得分:1)
它不一定非常复杂。
string sql = "SELECT " + join(cols.begin(), cols.end(), ", ") + " FROM some_table";
,其中
template <typename I>
string join(I begin, I end, const string& sep){
ostringstream out;
for(; begin != end; ++begin){
out << *begin;
if(begin+1 != end) out << sep;
}
return out.str();
}
答案 5 :(得分:1)
不要强调这一点,但请看一下boost :: algorithm :: join()。以下是一个示例,以防您认为他们的文档过于密集而不是单词:
std::string
build_sql(std::vector<std::string> const& colNames,
std::string const& tableName)
{
std::ostringstream sql;
sql << "SELECT "
<< boost::algorithm::join(colNames, std::string(","))
<< " FROM " << tableName;
return sql.str();
}
如有疑问,请查看Boost.org。他们通常可以解决大多数问题,例如已存在的问题。
答案 6 :(得分:0)
我建议建立一个通用的连接函数来做到这一点。您可以使用例如累积算法来连接列。
编辑:请参阅litb's implementation ;它不那么天真。
// Untested
#include <numeric>
template<std::string separator>
struct JoinColumns {
std::string operator()(Column a, Column b) {
return a._name + separator + b._name;
}
// Too lazy to come up with a better name
std::string inArray(T array) {
stl::accumulate(array.begin(), array.end(), std::string(), *this);
}
};
selectSql += stl::accumulate(columns.begin(), columns.end(), std::string(), JoinColumns<", ">());
// or
selectSql += JoinColumns<", ">().inArray(columns);
当然,您可以使用更好的包装器来获得更清晰的语法。
答案 7 :(得分:0)
for (z = 0; z < columns.size(); z++)
{
if( z != 0 )
selectSql += ", ";
selectSql += columns[z]._name;
}