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
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.
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)
- What does addBatch do?
- Why is a parameter safer than joining the number into the SQL text?