Modify array elements

2

I need to create a query with the insertion of several lines.

  • Change an array / list:
  •   

    arrayOriginal = [10,20,30,40]
        valueChave = 999

  • The return must be:
  •   

    arrayNew = [(valueChave, 10), (valueChave, 20), (valueChave, 30), (valueChave, 40)]

  • This will add a query to insert multiple rows into a table:
  • INSERT INTO tabela VALUES + '${arrayNovo}';
    

    What I tried but it is not working:

    String[] novosCodigosArray = codigos;
    
    for(int i = 0; i < novosCodigosArray.length; i++)
        novosCodigosArray[i] = "("+chave+","+novosCodigosArray[i]+")";
    return Arrays.toString(novosCodigosArray);
    
    // depois utilizo desta maneira para fazer query
    String meuINSERT= "INSERT INTO dbo.tabela";
    meuINSERT= meuINSERT +" (col_codigo, col_chave)";
    meuINSERT= meuINSERT +" VALUES ";
    meuINSERT= meuINSERT + novosCodigosArray;
    
    return meuINSERT;
    

    Any help will be greatly appreciated.

        
    asked by anonymous 22.06.2016 / 23:21

    3 answers

    2

    First, concatenating String s to create SQL queries in this way is very dangerous as it opens your system to a security problem known as SQL Injection .

    Doing this is bad programming practice, because in the case of concatenating String s, a hacker or malicious user who has control over one of the concatenated values (for example, some form field that he filled out) , by putting a quote ( ' ) and adding SQL fragments in this field, the malicious user will be able to change the structure of your SQL, and may even find a way to put a DROP DATABASE there in the worst case.

    To solve this problem (or possible problem) of SQL injection is that Java has PreparedStatement . Other programming languages also feature this concept.

    Finally, since you seem to want to do multiple batch inserts, it's best to use the batch mechanism. For this, I borrowed the idea from this SOen response . Having said that, then I think this would be your solution:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    public class MeuDAO {
        private static final String URL = ...;
        private static final String LOGIN = ...;
        private static final String SENHA = ...;
    
        public MeuDAO() {
        }
    
        private static final String SQL_INSERT =
                "INSERT INTO tabela (col_codigo, col_chave) VALUES (?, ?)";
    
        public Connection obterConexao() {
            return DriverManager.getConnection(URL, LOGIN, SENHA);
        }
    
        public void fazMeuInsert(int chave, int[] valores) {
            if (valores.length == 0) return;
            try (
                Connection conn = obterConexao;
                PreparedStatement ps = conn.prepareStatement(SQL_INSERT))
            ) {
                ps.setInt(1, chave);
                for (int valor : valores) {
                    ps.setInt(2, valor);
                    ps.addBatch();
                }
                ps.executeBatch();
            } catch (SQLException e) {
                // Tratar o erro adequadamente.
                // Ou então relançar a exceção declarando "throws SQLException".
                // Ou então encapsular em uma outra exceção e lançá-la.
            }
        }
    }
    

    Note that since your SQL is a String monolithic, so it is not possible to do SQL injection. Also note that due to the try-with-resources of Java 7 or higher, we do not have to explicitly close PreparedStatement and Connection . In addition, the above code ensures that your SQL only needs to be interpreted once instead of once for each insert. In addition only one connection will open at the beginning and closed at the end, instead a lot of connections being opened and then closed. Finally, all of them will be fulfilled together. All this ensures a much better performance and network consumption than it would be when you insert them one-by-one.

    If your array is too large (kind, thousands of elements), you might want to divide it into batches so as not to get a very large consuming lots of memory on both the client and the server). Here is the code that automatically divides array into batches of 1000 elements:

    public void fazMeuInsert(int chave, int[] valores) {
        if (valores.length == 0) return;
        try (
            Connection conn = obterConexao;
            PreparedStatement ps = conn.prepareStatement(SQL_INSERT))
        ) {
            int i = 0;
            ps.setInt(1, chave);
            for (int valor : valores) {
                ps.setInt(2, valor);
                ps.addBatch();
                i++;
                if (i % 1000 == 0 || i == valores.size() {
                    ps.executeBatch();
                }
            } catch (SQLException e) {
                // Tratar o erro adequadamente.
                // Ou então relançar a exceção declarando "throws SQLException".
                // Ou então encapsular em uma outra exceção e lançá-la.
            }
        }
    }
    
        
    23.06.2016 / 01:08
    2

    Ignoring the security issue and assuming you have Java 8, you can do the generation of SQL tuples in almost a command:

    Arrays.stream(arrayOriginal)
        .map(v -> String.format("(%d,'%s')", chave, v))
        .collect(Collectors.joining(" "));
    

    The first line converts the array to stream . The second maps each value by formatting the tuple as defined. The third line takes the result and puts it together in a string separating the items with a blank space.

    Obviously you can adjust each step of the process for your needs.

    Complete code:

    int chave = 999;
    String[] arrayOriginal = {"10", "20", "30", "40"};
    String resultado = Arrays.stream(arrayOriginal).map(v -> String.format("(%d,'%s')", chave, v)).collect(Collectors.joining(" "));
    System.out.println(resultado);
    

    Output:

      (999, '10 ') (999, '20') (999, '30 ') (999, '40')

        
    24.06.2016 / 10:01
    1

    Well, considering you know the dangers of SQL injection and make sure that this is not a risk to you, and that you need to necessarily generate a very large String containing all inserts , I would do so:

    class Teste {
        private static final String SQL_INSERT =
            "INSERT INTO tabela (col_codigo, col_chave) VALUES ('X', 'Y');\n";
    
        public static String juntarTodasAsSQLs(String chave, String[] valores) {
            String a = SQL_INSERT.replace("X", chave);
            StringBuilder sb = new StringBuilder(valores.length * (a.length() + 5));
            for (String valor : valores) {
                sb.append(SQL_INSERT.replace("Y", valor));
            }
            return sb.toString();
        }
    
        public static void main(String[] args) {
            String chave = "999";
            String[] arrayOriginal = {"10", "20", "30", "40"};
            String resultado = juntarTodasAsSQLs(chave, arrayOriginal);
            System.out.println(resultado);
        }
    }
    

    Here's the output:

    INSERT INTO tabela (col_codigo, col_chave) VALUES ('X', '10');
    INSERT INTO tabela (col_codigo, col_chave) VALUES ('X', '20');
    INSERT INTO tabela (col_codigo, col_chave) VALUES ('X', '30');
    INSERT INTO tabela (col_codigo, col_chave) VALUES ('X', '40');
    

    See here this example working on ideone.

    But if in your problem, you only need the part that is after VALUES and it must necessarily come in the form of array as a result, so this should help you:

    class Teste2 {
    
        public static String[] juntarTodasAsSQLs(String chave, String[] valores) {
            String[] novoArray = new String[valores.length];
            for (int i = 0; i < valores.length; i++) {
                novoArray[i] = "('" + chave + "', '" + valores[i] + "')";
            }
            return novoArray;
        }
    
        public static void main(String[] args) {
            String chave = "999";
            String[] arrayOriginal = {"10", "20", "30", "40"};
            String[] resultados = juntarTodasAsSQLs(chave, arrayOriginal);
    
            for (String r : resultados) {
                System.out.println(r);
            }
        }
    }
    

    Here's the output:

    ('999', '10')
    ('999', '20')
    ('999', '30')
    ('999', '40')
    

    See here working on ideone.

        
    23.06.2016 / 14:58