0

私の職場で定期的に解決する必要がある問題は、ユーザーが指定したテーブル/列名に基づいて SQL ステートメントを作成する方法です。私が対処しようとしている問題は、列名の間のコンマです。

1つのテクニックは次のようになります。

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

私は、これらの実装のいずれにも特に夢中になっているわけではありません。

コードを読みやすく、理解しやすく、維持しやすくするために、この問題に対処する他の方法のアイデアを聞くことに興味があります。

どのような代替技術が利用可能ですか?

4

8 に答える 8

5

あなたの場合、選択を行う意味がないため、少なくとも1つの列があると想定するのはおそらく安全です。その場合、次のことができます。

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

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

selectSql += " FROM some-table";
于 2008-11-29T02:37:04.387 に答える
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;";
于 2008-11-29T19:09:26.163 に答える
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";
于 2008-11-29T03:09:16.100 に答える
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をご覧ください。彼らは通常、すでにそこにあるこのようなほとんどの問題に対する解決策を持っています。

于 2008-11-29T21:21:35.507 に答える
1

私がステートメントを作成する方法は、通常次のとおりです。

pad = ""
stmt = "SELECT "

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

これは比較的きれいです - 各反復をパディングするために再割り当てしますが、それは些細なことです。私はこれについて、いくつもの些細なバリエーションを使ってきましたが、私が知っている中で最もクリーンなメカニズムです。

もちろん、そこから学ぶべき他の誰かの答えもあります...

于 2008-11-29T01:42:59.300 に答える
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();
}
于 2008-11-29T19:55:54.867 に答える
0

これを行うには、一般的な結合関数を作成することをお勧めします。たとえば、蓄積アルゴリズムを使用して、列を結合できます。

編集: litb の実装を参照してください。それははるかにナイーブではありません。

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

もちろん、より優れたラッパーを使用することで、よりクリーンな構文を得ることができます。

于 2008-11-29T01:44:12.277 に答える
0
for (z = 0; z < columns.size(); z++)
{
    if( z != 0 )
        selectSql += ", "; 
    selectSql += columns[z]._name;
}
于 2008-11-29T02:19:45.593 に答える