使用列名向量,生成一个sql语句

时间:2008-11-29 01:29:14

标签: c++ sql idioms

我们需要在工作场所定期解决的问题是如何根据用户提供的表/列名称构建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";

我对这些实现中的任何一个都不是特别着迷。

我很有兴趣听取有关解决此问题的其他方法的想法,着眼于使代码更易于阅读/理解/维护。

有哪些替代技术?

8 个答案:

答案 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;
}