Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi SQL-Praktikum – 5 - Solution (until 29.01.2009) Solution: Exercise 1.a Write a java method establishing a connection to the DB2 database (running at is54.idb.cs.tu-bs.de, port 50000, database SQLKURS). Use your own username and password to log in. The connection object is to be returned by the method. /** * Connect to database. * * @return the connection object * @throws SQLException * when connection failed */ public static Connection getConnection() throws SQLException { // setup URL components String url = "jdbc:db2://is54.idb.cs.tu-bs.de:50000/SQLKURS"; // your username and password here String user = "skurs69"; String password = "2sbD94SJ"; // load driver try { Class.forName("com.ibm.db2.jcc.DB2Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // set custom properties // as defined above // Properties properties = new Properties(); properties.setProperty("user", user); properties.setProperty("password", password); properties .setProperty("retrieveMessagesFromServerOnGetMessage", "true"); // create the connection object Connection connection = DriverManager.getConnection(url, properties); return connection; } Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi Exercise 1.b Write another method which reads and prints some metadata of the database. Following information should be printed (try to format it so that it can be read without getting an headache): Database product name and major and minor version Number of available schemas and a list of all schema names For the schema matching the current user name, a list of all available tables and for each table, a list of columns and their data type. Also, if the table has any indexes, they should be listed with their name and the column they are indexing. public static void printMetaData(Connection connection) throws SQLException { // get the meta data... DatabaseMetaData meta = connection.getMetaData(); // ...and print the information // using the format function // // // // %s is placeholder for strings %10s is placeholder for string of length 10 the values are given as parameters, where first occurrence of %s will be filled with first parameter etc. // \n is newline // version System.out.format("DBMS : %s \nVersion %s.%s\n\n", meta.getDatabaseProductName(), meta.getDatabaseMajorVersion(), meta.getDatabaseMinorVersion()); // schemas System.out.println("Available Schemas\n-----------------"); ResultSet schemas = meta.getSchemas(); // while there is yet another item in the resultSet while (schemas.next()) { // print schema name System.out.format(" %16s\n", schemas.getString(1)); } schemas.close(); // Print all own tables System.out.println("\n\nTABLE INFO \n-----------------"); Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi //get userName String userName=meta.getUserName(); // get all tables with pattern // (catalog, schemaPattern, tableNamePattern, types) // we use only the userName as schemaPattern here ResultSet tables = meta.getTables(null, userName, null, null); // for each table while (tables.next()) { String tableName = tables.getString("TABLE_NAME"); System.out.format("TABLE : %s\n", tableName); // Columns ResultSet columns = meta .getColumns(null, userName, tableName, null); while (columns.next()) { //print name and type of the current column System.out.format("%17s : %10s\n", columns.getString("COLUMN_NAME"), columns.getString("TYPE_NAME")); } // Indexes // meta.getIndexInfo(catalog, schema, table, unique, approximate) ResultSet indexes = meta.getIndexInfo(null, userName, tableName,false, false); while (indexes.next()) { System.out.format(" Index: %s (%s)\n", indexes.getString("INDEX_NAME"), indexes.getString("COLUMN_NAME")); } } tables.close(); } Exercise 1.c Create a new program (which, of course, may use the connect method of a)). After being started, the program should request the entry of a year of the user. Then, the number of movies which were released in that year and the average number of actors and the average number of actresses (read: two averages, one for each gender) of those movies is returned. The program then asks for a new year and repeats until the user wants to quit. public class JdbcTask_C { /** * A prepared statement for counting the movies in a given year * * @param conn Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi * @return * @throws SQLException */ public static PreparedStatement getStatementMovies(Connection conn) throws SQLException { // prepare a string containing the SQL statement // that expects a year String sql = "SELECT count(t.title) FROM IMDB.title t "; sql += "WHERE t.production_year = ?"; // create and return the prepared statement return conn.prepareStatement(sql); } /** * A prepared statement for counting the average number of actors and * actresses of all movies released in a given year * * @param conn * @return * @throws SQLException */ public static PreparedStatement getStatementActors(Connection conn) throws SQLException { // prepare a string containing the SQL statement // that expects a year String sql = "SELECT avg(CAST(numOfActors AS double)),"; sql += "avg(CAST(numOfActresses AS double)) FROM ("; // count actors as 1, others as 0 sql += "SELECT sum(CASE WHEN role_id = 1 THEN 1 ELSE 0 END)numOfActors, "; // count actresses as 1, other as 0 sql += "sum(CASE WHEN role_id = 2 THEN 1 ELSE 0 END) numOfActresses"; sql += "FROM IMDB.title t, IMDB.cast_info c "; sql += "WHERE t.production_year=? AND c.movie_id=t.id "; sql += "AND (c.role_id=1 OR c.role_id=2)"; sql += "GROUP BY c.movie_id)"; // create and return the prepared statement return conn.prepareStatement(sql.toString()); } /** * Runs the stuff * * @param args */ public static void main(String[] args) { try { // prepare connection and statements Connection conn = JdbcTaskA_B.getConnection(); PreparedStatement statementMovies = getStatementMovies(conn); Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi PreparedStatement statementActors = getStatementActors(conn); // get input scanner Scanner in = new Scanner(System.in); while (true) { // get user input System.out.print("Enter a year (0 for exit) : "); int year = in.nextInt(); System.out.println("You entered : " + year); if (year == 0) { break; } // run query //retrieve the number of movies statementMovies.setInt(1, year); ResultSet rs = statementMovies.executeQuery(); //retrieve the number of actors statementActors.setInt(1, year); ResultSet rs_a = statementActors.executeQuery(); // print result rs.next(); // set result set to first entry rs_a.next(); // set result set to first entry System.out.format( "%d movies in year %d with %f actors and %f actresses in mean.\n", rs.getInt(1), year, rs_a.getDouble(1),rs_a.getDouble(2)); } System.out.println("Exit."); } catch (Exception e) { e.printStackTrace(); } } } Create another new program. When being executed, the program should request two numbers of the user (numOfCols: between 1 and 14, numOfRows: between 1 and 50000). After that, the program should create a new table called “numbers” having as many columns as the user entered before (between 1 and 14. Those columns should be named col_1 to col_14.). The first half of columns should be of type integer, the second of type double (e.g.: 7 columns -> col_1 to col_4 are int, col_5 to col_7 are double). Then, the program inserts as many randomly generated rows as the user has entered before (1 to 50000). Each random number should be between 1 and 100 respecting the data type of the current column. Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi After that, the program computes and returns the average value of each column and deletes the table. Write 3 versions of this program: One version using simple insert statements, one using prepared insert statements, and the last one using an updateable ResultSet and its insert method. Run all three versions for 15 columns and 50000 rows and measure the time needed for execution. Also, run the first two versions of the program with transactions enabled (i.e. all insert statements are considered being one huge transaction) and without transactions (just execute each insert immediately). public class JdbcTaskD { private static String tableName = "numbers"; private static Random random = new Random(); /** * Creates a new table with given number of columns. * * @param connection * @param numOfCols * @throws SQLException */ private static void createTable(Connection connection, int numOfCols) throws SQLException { String sql = "CREATE TABLE "+tableName+" ("; for (int i = 0; i < numOfCols; i++) { sql+="col"+i; if (i <= numOfCols / 2) { sql+=" int"; } else { sql+=" double"; } if (i < numOfCols - 1) { sql+=", "; } } sql+=")"; Statement createStatement = connection.createStatement(); createStatement.execute(sql); createStatement.close(); System.out.println("Table created : " + sql ); } /** * Removes table. * * @param connection * @throws SQLException */ Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi private static void dropTable(Connection connection) throws SQLException { Statement createStatement = connection.createStatement(); createStatement.execute("DROP TABLE " + tableName); createStatement.close(); System.out.println("Table dropped"); } private static void fillTablePrepared(Connection conn, int numOfCols, int numOfRows) throws SQLException { // activate / deactivate autoCommit boolean autoCommit = true; conn.setAutoCommit(autoCommit); //get time at start long startMillis = System.currentTimeMillis(); // prepare statement-string String sql = "INSERT INTO "+tableName+" VALUES ("; for (int col = 0; col < numOfCols; col++) { sql+="?"; if (col < numOfCols - 1) { sql+=","; } } sql+=")"; //prepare statement PreparedStatement insertStmt = conn.prepareStatement(sql); // fill rows for (int row = 0; row < numOfRows; row++) { if (row % 100 == 0) { System.out.print('.'); } for (int col = 0; col < numOfCols; col++) { if (col <= numOfCols / 2) { insertStmt.setInt(col + 1, random.nextInt(100)); } else { insertStmt.setDouble(col + 1, random.nextDouble() * 100); } } insertStmt.executeUpdate(); } if(!autoCommit){ //commit transaction conn.commit(); // System.out.format("\nExecution time for Prepared Statements with Transaction %f\n",(System.currentTimeMillis() - startMillis) / 1000.0); } else{ Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi // System.out.format("\nExecution time for Prepared Statements w/o Transaction %f\n",(System.currentTimeMillis() - startMillis) / 1000.0); } } private static void fillTableResultset(Connection conn, int numOfCols, int numOfRows) throws SQLException{ // prepare statement Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); //get time at start long startMillis = System.currentTimeMillis(); ResultSet rs= stmt.executeQuery("SELECT * FROM "+tableName); // fill rows for (int row = 0; row < numOfRows; row++) { if (row % 100 == 0) { System.out.print('.'); } // move to insertRow rs.moveToInsertRow(); //fill the row for (int col = 0; col < numOfCols; col++) { if (col <= numOfCols / 2) { rs.updateInt(col+1, random.nextInt(100)); } else { rs.updateDouble(col+1, random.nextDouble()*100); } } //insert the row rs.insertRow(); } //measure time System.out.format("\nExecution time for Updatable Resultset %f\n", (System.currentTimeMillis() - startMillis) / 1000.0); } private static void fillTableSimple(Connection conn, int numOfCols, int numOfRows) throws SQLException { // activate / deactivate autoCommit boolean autoCommit = false; conn.setAutoCommit(autoCommit); Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi // prepare statement Statement insertStmt = conn.createStatement(); //get time at start long startMillis = System.currentTimeMillis(); // fill rows for (int row = 0; row < numOfRows; row++) { if (row % 100 == 0) { System.out.print('.'); } String sql = "INSERT INTO "+tableName+" VALUES ("; for (int col = 0; col < numOfCols; col++) { if (col <= numOfCols / 2) { sql+=random.nextInt(100); } else { sql+=random.nextDouble() * 100; } if (col < numOfCols - 1) { sql+=","; } } sql+=")"; insertStmt.executeUpdate(sql); } if(!autoCommit){ //commit transaction conn.commit(); // System.out.format("\nExecution time for Simple Statements action %f\n",(System.currentTimeMillis() - startMillis) / } else{ // System.out.format("\nExecution time for Simple Statements action %f\n",(System.currentTimeMillis() - startMillis) / } } public static void main(String[] args) { Scanner in = new Scanner(System.in); System.out.print("\nEnter number of columns (1-15) : "); int numOfCols = in.nextInt(); System.out.print("\nEnter number of rows (1-50000) : "); int numOfRows = in.nextInt(); if (numOfCols < 1 || numOfCols > 15 || numOfRows < 1 || numOfRows > 50000) { Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de with Trans1000.0); w/o Trans1000.0); Technische Universität Braunschweig Institut für Informationssysteme http://www.ifis.cs.tu-bs.de Wolf-Tilo Balke, Christoph Lofi System.out.println("You are a moron and your paramters are invalid."); System.exit(-1); } // run the program Connection connection = null; try { connection = JdbcTaskA_B.getConnection(); try { dropTable(connection); } catch (SQLException e) { } createTable(connection, numOfCols); // call according function fillTablePrepared(connection, numOfCols, numOfRows); fillTableSimple(connection, numOfCols, numOfRows); fillTableResultset(connection, numOfCols, numOfRows); } catch (SQLException e) { e.printStackTrace(); } finally { if (connection != null) try { // dropTable(connection); } catch (Exception e) { e.printStackTrace(); } } } } Exercises for Relational Databases 1 Institut für Informationssysteme – TU Braunschweig - http://www.ifis.cs.tu-bs.de