2008-11-29 87 views
0

我們需要在工作場所定期解決的問題是如何基於用戶提供的表/列名稱來構建sql語句。我試圖解決的問題是列名之間的逗號。使用列名稱向量來生成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"; 

我並不是通過這些實現的如醉如癡。

我很感興趣的是通過其他方式來解決這個問題,並着眼於使代碼更易於閱讀/理解/維護。

可以使用哪些替代技術?

回答

5

在你的情況下,假設至少有一列可能是安全的,否則在做選擇時沒有意義。在這種情況下,你可以這樣做:

selectSql = "SELECT "; 
selectSql += columns[0]._name; 

for (z = 1; z < columns.size(); z++) { 
    selectSql += ", "; 
    selectSql += columns[z]._name; 
} 

selectSql += " FROM some-table"; 
1

我建立語句的方式通常是:

pad = "" 
stmt = "SELECT " 

for (i = 0; i < number; i++) 
{ 
    stmt += pad + item[i] 
    pad = ", " 
} 

這是比較乾淨的 - 它重新分配給墊每次迭代,但是這是微不足道的。我已經使用了許多微不足道的變化,但它是我所知道的最乾淨的機制。

當然,還會有別人的答案從太學...

+0

我在快速而髒的代碼中使用了類似的方法,除了我使用bool來檢查是否需要打印逗號。 – strager 2008-11-29 01:45:15

+0

我要說的是,你最終會收到尾隨的逗號。然後我看到你在那裏做了什麼。我會說這個代碼有點「棘手」,很難維護。 – 2008-11-29 02:21:58

+0

另外,如果這是一個高性能的循環,您最終會得到多餘的分配給'pad',這將是浪費。 – 2008-11-29 02:22:43

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); 

當然,您可以通過使用更好的包裝獲得更清晰的語法。

+0

看起來相當複雜。 – EvilTeach 2008-11-29 03:34:56

0
for (z = 0; z < columns.size(); z++) 
{ 
    if(z != 0) 
     selectSql += ", "; 
    selectSql += columns[z]._name; 
} 
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

而不是重新申請,每次圍繞一個工作,你可以一勞永逸通過編寫一個函數對象,並使用解決問題建議像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;"; 
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(); 
} 
1

不要痛打了點,但看看的boost ::算法:: 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。他們通常有解決大多數問題的方法,例如已經存在的問題。