باستخدام متجه لأسماء الأعمدة، لإنشاء عبارة SQL

StackOverflow https://stackoverflow.com/questions/327010

  •  11-07-2019
  •  | 
  •  

سؤال

المشكلة التي نحتاج إلى حلها بانتظام في مكان عملي هي كيفية إنشاء عبارات 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";

أنا لست مفتونًا بشكل خاص بأي من هذه التطبيقات.

أنا مهتم بسماع أفكار حول طرق أخرى لمعالجة هذه المشكلة، مع التركيز على تسهيل قراءة/فهم/صيانة الكود.

ما هي التقنيات البديلة المتاحة؟

هل كانت مفيدة؟

المحلول

في قضيتك وربما هو الأسلم أن نفترض أن هناك عمود واحد على الأقل وإلا فلا فائدة في القيام اختر. في هذه الحالة يمكن أن تفعله:

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

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

selectSql += " FROM some-table";

نصائح أخرى

وبدلا من تطبيق العمل حول كل مرة، يمكنك علاج هذه المشكلة مرة واحدة وإلى الأبد من خلال كتابة موضوع وظيفة، واستخدام تلك 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;";

ونحن لا تهتم لإزالة الفاصلة زائدة.
هذا هو لأنه يمكنك تحديد ثابت و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

وذلك باستخدام المحكمة الخاصة بلبنان لجعله المدمجة:

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

والطريق الأول بناء البيانات هي عادة:

pad = ""
stmt = "SELECT "

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

وهذا هو نظيفة نسبيا - أنه يعيد تعيين لوحة كل تكرار، ولكن هذا تافهة. لقد استعملت أي عدد من الاختلافات تافهة حول هذا الموضوع، ولكن هذا هو أنظف آلية أعرف.

وبطبيعة الحال، سوف تكون هناك إجابة لشخص آخر لمعرفة من جدا ...

وليس من الضروري أن تكون معقدة للغاية.

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

وليس لأكرر نفس النقطة ولكن إلقاء نظرة على دفعة :: :: خوارزمية الانضمام (). وإليك مثالا في حال كنت تعتقد أن وثائقها كثيفة جدا للكلمات:

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. وعادة ما يكون حل لمعظم المشاكل مثل هذا واحد بالفعل هناك.

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

أود أن أقترح إنشاء وظيفة ربط عامة للقيام بذلك.يمكنك استخدام على سبيل المثال.تتراكم الخوارزمية لربط الأعمدة.

يحرر: يرى تنفيذ 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);

يمكنك الحصول على بناء جملة أكثر وضوحًا باستخدام أغلفة أفضل بالطبع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top