JDBC: PreparedStatement with Parameters

Problem

Each input line except the last has a name and an age. Insert all these people into a table people(name, age) with a PreparedStatement. The last line is min N. Select the names of all people whose age is at least N, with a PreparedStatement that has ? for N. Sort by age, then by name, and print one name per line. If nobody matches, print none.

Constraints

  • 1 <= people <= 100
  • 0 <= age <= 150

Examples

Input

ann 30
bob 25
cy 41
min 30

Output

ann
cy

Solutions

Best approachTime O(n log n)Space O(n)

A PreparedStatement is compiled once and then filled with values. The database treats the values only as data, which is faster for repeated rows and is the main defence against SQL injection. Batching sends many inserts in one trip. JavaScript and TypeScript use the built-in node:sqlite module (Node.js 22.5 or newer), which prints an experimental warning. Python uses the sqlite3 module that comes with Python.

Same code works in Java810172125Basic features only, so nothing changes between versions.

Java needs a JDBC driver at run time. Download sqlite-jdbc from Maven Central (org.xerial:sqlite-jdbc) and run: java -cp .:sqlite-jdbc.jar Main (on Windows use ; instead of :).

/*
 * Problem : Run the commands.
 * Input   : Input lines.
 * Output  : Output lines.
 * Approach: Parameterized query
 * Time    : O(n log n)
 * Space   : O(n)
 * Java    : 8 or newer.
 */
import java.util.Scanner;
import java.sql.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        List<String> out = new ArrayList<String>();
        int minAge = Integer.parseInt(lines[lines.length - 1].split(" ")[1]);
        try (Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:")) {
            try (Statement create = conn.createStatement()) {
                create.execute("CREATE TABLE people (name TEXT, age INTEGER)");
            }
            // Step 1: Prepare the INSERT once. addBatch collects the rows, and executeBatch sends them together.
            try (PreparedStatement insert = conn.prepareStatement("INSERT INTO people (name, age) VALUES (?, ?)")) {
                for (int i = 0; i < lines.length - 1; i++) {
                    String[] part = lines[i].split(" ");
                    insert.setString(1, part[0]);
                    insert.setInt(2, Integer.parseInt(part[1]));
                    insert.addBatch();
                }
                insert.executeBatch();
            }
            // Step 2: The filter value is passed with setInt. The database never reads it as SQL text.
            try (PreparedStatement select = conn.prepareStatement("SELECT name FROM people WHERE age >= ? ORDER BY age, name")) {
                select.setInt(1, minAge);
                try (ResultSet rs = select.executeQuery()) {
                    while (rs.next()) {
                        out.add(rs.getString(1));
                    }
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        // Step 3: An empty result prints none.
        if (out.isEmpty()) {
            out.add("none");
        }
        return out.toArray(new String[0]);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(String.join("\n", solve(lines)));
    }
}
Hints (2)
  1. What does addBatch do?
  2. Why is a parameter safer than joining the number into the SQL text?