Mounting run-time updates

8

When mounting SELECTS at runtime we always have the problem of knowing what might be coming or not depending on the choices made by the user.

When assembling the WHERE clause we are faced with the question of adding AND or not before each condition.

If it is the first condition then it will not have the AND , however if it is the second or greater than this we add at the beginning of the condition AND .

To not be held hostage to this condition, having to analyze it at all times I add an innocuous clause and then I can add AND to all the others.

In this way my WHERE fault clause is WHERE 0 = 0 , so I can add AND to all other conditions.

At run time my WHERE clause will look like this: WHERE 0 = 0 AND condicao1 = 'cond1' AND condicao2 = 'cond2' AND condicao3 = 3 or just like this: WHERE 0 = 0 and it will work without problems.

When we mount a UPDATE at runtime we have the same problem, but the question now is the comma or the total lack of parameters.

We start with "UPDATE tabelax SET" and we're adding columns as the program finds those tags.

At first we add "campo1 = 'campo1'" + "," , in the second "campo2 = 'campo2' + "," . Note that we could not add the comma if field2 were the last field filled because otherwise our final command would be wrong. UPDATE tabelax SET campo1 = 'campo1', campo2 = 'campo2', WHERE condicao is wrong. That is, you have to ask if it is the last one or not, or add in all and at the end of the loop check if the last character is a comma and remove it before adding the WHERE clause.

Anyway, the question: does not have a way, like the case of WHERE , is it easier, smarter or clever to solve this?

    
asked by anonymous 27.05.2016 / 19:46

4 answers

3

My technique is to use a variable to represent the separator and always concatenate the next value after the separator; but the separator is initialized empty and only receives the separator text after the first value is added to the query.

In a loop , it looks something like this:

sql = "update tabela set ";
paramPattern = "%s = '%s'";
separador = "";

// campos a atualizar, separados por vírgula:

for(campo : campos) {
    sql += separador + String.format(paramPattern, campo.nome, campo.valor);
    separador = ", ";
}

// cláusula where:

sql += " where ";
separador = "";

for(condicao : condicoes) {
    sql += separador + condicao;
    separador = " and ";
}

The idea also works if you do not have field and condition lists, but instead use if s. It looks something like this:

sql = "update tabela set ";
paramPattern = "%s = '%s'";
separador = "";

// campos a atualizar, separados por vírgula:

if (atualizarCampo1) {
    sql += separador + String.format(paramPattern, campo1.nome, campo1.valor);
    separador = ", ";
}
if (atualizarCampo2) {
    sql += separador + String.format(paramPattern, campo2.nome, campo2.valor);
    separador = ", ";
}
// outros campos...

// cláusula where:

sql += " where ";
separador = "";

if (filtrarPorData) {
    sql += separador + "DATA between :data1 and :data2";
    separador = " AND ";
}
if (filtrarPorStatus) {
    sql += separador + "STATUS = :status";
    separador = " AND ";
}
// outras condições...

If there is a possibility that there is no filter (command without where clause), simply fill in the conditions in another variable, and only concatenate it to sql if it ends other than empty after passing through conditions. For example:

sql = "select * from tabela";
where = "";
separador = "";

if (filtrarPorData) {
    where += separador + "DATA between :data1 and :data2";
    separador = " AND ";
}
if (filtrarPorStatus) {
    where += separador + "STATUS = :status";
    separador = " AND ";
}
// outras condições...

if (!"".equals(where)) {
    sql += " where " + where;
}

I'd rather do that than add something in the query ( where 1 = 1 ) just by code physiology. And I also prefer to add something unnecessary to the string and then remove it (in this case, an extra comma).

And of course this is a pseudo code just to demonstrate the idea of the separator as variable. I hope you always use parameters instead of concatenating values in the query.

    
03.06.2016 / 18:26
3

In C # use the Join() method, it will mount by setting the tab the right way.

In Java use the join() .

I do not know if modern Delphi has something ready, but it's easy to make a Join() :

function Join(const Texts : array of string; const Separator : string) : string;
var
    i : Integer;
begin
    Result := Texts[low(Texts)];
    for i := low(Texts) + 1 to high(Texts) do
        Result := Separator + Result + Texts[i];
end;

Note that it starts by taking the first element of the array before the loop (this is the secret to not leaving a tab left over) and then always places a separator pair and new item. >     

27.05.2016 / 20:13
2

Based on this response I've made an adaptation for you that allows you to mount update at runtime, see how was:

static string buildUpdate(string table, string nomeCampoId, string idCampo, Dictionary<string, object> parameters)
{           
    StringBuilder builder = new StringBuilder("Update " + table + " SET ");

    foreach (KeyValuePair<string, object> param in parameters)            
        builder.Append(param.Key).Append(" = ").Append(param.Value).Append(",");            

    builder.Remove(builder.Length - 1, 1); /*Aqui remove a virgula.*/
    builder.Append(" WHERE ").Append(nomeCampoId).Append(" = ").Append(idCampo);
    return builder.ToString();
}

To use the buildUpdate() method you need to build your dictionary to populate it with fields and values, see how the implementation got:

static void Main(string[] args)
{
    Dictionary<string, object> parameters = new Dictionary<string, object>();
    parameters.Add("campoNome", "'Maria'");
    parameters.Add("campoIdade", 25);
    parameters.Add("campoGenero", "'Feminino'");

    string update = buildUpdate("Pessoa", "idPessoa", "2",parameters);
    Console.WriteLine(update);
}

The buildUpdate() method will generate the following output on the console:

  

Update Person SET fieldName = 'Maria', fieldIty = 25, fieldGenero =   'Female' WHERE idPessoa = 2

You will need to adapt it, but I believe it is already a path.

    
06.06.2016 / 01:02
1

I usually add the conditions with the comma, and at the end remove the last character of the string. In the case of AND works the same way only removing 3 characters.

public String constroiCondicao1(String... condicoes){
    if(condicoes == null)
        return "";
    StringBuilder sb = new StringBuilder();
    sb.append("WHERE ");
    for(String cond : condicoes){
        sb.append(cond + " AND ");
    }
    return sb.toString().substring(0, sb.length()-4);
}

// OU

public String constroiCondicao2(String... condicoes){
    if(condicoes == null)
        return "";
    return "WHERE " + String.join(" AND ", condicoes);
}
    
31.05.2016 / 05:20