I am preparing a SQL statement from values passed through a query string. ( I am using the Play! framework. Basically what I'm running into (not really an issue just something I don't like very much) is that when I want to use ? in the SQL string and set them later with dynamic values.
This is what I have:
String sql = "SELECT * FROM foobar_table WHERE";
if ( foo != 0 )
sql += " AND foo=?";
if ( !bar )
sql += " AND bar=?";
try{
PreparedStatement getStmt = con.prepareStatement(sql);
if ( foo != 0 )
getStmt.setInt(1,foo);
if ( foo != 0 && !bar )
getStmt.setBoolean(2, bar);
else
getStmt.setBoolean(1, bar);
} catch (SQLException e ){
e.printStackTrace();
}
This does work but as you can see not very intuitive. It's OK when there are 2 dynamic values but when you get up to 5 or 6 this would just get ridiculous.
Is there an easier way of doing this to make it more flexible so that I would know how to fill in all the ? in a better fashion?
An example (was too long for comment):
String sql = "SELECT * FROM foobar_table WHERE 1 = 1 ";
ArrayList paramList = new ArrayList();
if ( foo != 0 ) {
sql += " AND foo=?";
paramList.add(foo);
}
if ( !bar ) {
sql += " AND bar=?";
paramList.add(bar);
}
try{
PreparedStatement getStmt = con.prepareStatement(sql);
int index = 1;
for (Object param : paramList) {
getStmt.setObject(index, param);
index++;
}
// execute
} catch (SQLException e ){
e.printStackTrace();
}
Something like this maybe (just rough code but you get the idea):
class Param{
final int type;
final Object value;
Param(int type, Object value){
this.type = type;
this.value = value;
}
}
final List<Param> params = new ArrayList<>();
final StringBuilder sql = new StringBuilder("SELECT * FROM bcu_venue_events WHERE 1=1");
int foo = 0;
boolean bar = true;
if (foo != 0){
sql.append(" AND foo=?");
params.add(new Param(Types.INTEGER, foo));
}
if (!bar){
sql.append(" AND bar=?");
params.add(new Param(Types.BOOLEAN, bar));
}
try(Connection conn = null; PreparedStatement getStmt = conn.prepareStatement(sql.toString())) {
for(int i = 0; i < params.size(); i++){
Param p = params.get(i);
getStmt.setObject(i + 1, p.value, p.type);
}
} catch (SQLException e) {
e.printStackTrace();
}
How about this:
String sql = "SELECT * FROM foobar_table WHERE 1=1";
if ( foo != 0 )
sql += " AND foo=" + foo;
if ( !bar )
sql += " AND bar=" + bar;
try{
PreparedStatement getStmt = con.prepareStatement(sql);
} catch (SQLException e ){
e.printStackTrace();
}
Related
I am preparing a SQL statement from values passed through a query string. ( I am using the Play! framework. Basically what I'm running into (not really an issue just something I don't like very much) is that when I want to use ? in the SQL string and set them later with dynamic values.
This is what I have:
String sql = "SELECT * FROM foobar_table WHERE";
if ( foo != 0 )
sql += " AND foo=?";
if ( !bar )
sql += " AND bar=?";
try{
PreparedStatement getStmt = con.prepareStatement(sql);
if ( foo != 0 )
getStmt.setInt(1,foo);
if ( foo != 0 && !bar )
getStmt.setBoolean(2, bar);
else
getStmt.setBoolean(1, bar);
} catch (SQLException e ){
e.printStackTrace();
}
This does work but as you can see not very intuitive. It's OK when there are 2 dynamic values but when you get up to 5 or 6 this would just get ridiculous.
Is there an easier way of doing this to make it more flexible so that I would know how to fill in all the ? in a better fashion?
An example (was too long for comment):
String sql = "SELECT * FROM foobar_table WHERE 1 = 1 ";
ArrayList paramList = new ArrayList();
if ( foo != 0 ) {
sql += " AND foo=?";
paramList.add(foo);
}
if ( !bar ) {
sql += " AND bar=?";
paramList.add(bar);
}
try{
PreparedStatement getStmt = con.prepareStatement(sql);
int index = 1;
for (Object param : paramList) {
getStmt.setObject(index, param);
index++;
}
// execute
} catch (SQLException e ){
e.printStackTrace();
}
Something like this maybe (just rough code but you get the idea):
class Param{
final int type;
final Object value;
Param(int type, Object value){
this.type = type;
this.value = value;
}
}
final List<Param> params = new ArrayList<>();
final StringBuilder sql = new StringBuilder("SELECT * FROM bcu_venue_events WHERE 1=1");
int foo = 0;
boolean bar = true;
if (foo != 0){
sql.append(" AND foo=?");
params.add(new Param(Types.INTEGER, foo));
}
if (!bar){
sql.append(" AND bar=?");
params.add(new Param(Types.BOOLEAN, bar));
}
try(Connection conn = null; PreparedStatement getStmt = conn.prepareStatement(sql.toString())) {
for(int i = 0; i < params.size(); i++){
Param p = params.get(i);
getStmt.setObject(i + 1, p.value, p.type);
}
} catch (SQLException e) {
e.printStackTrace();
}
How about this:
String sql = "SELECT * FROM foobar_table WHERE 1=1";
if ( foo != 0 )
sql += " AND foo=" + foo;
if ( !bar )
sql += " AND bar=" + bar;
try{
PreparedStatement getStmt = con.prepareStatement(sql);
} catch (SQLException e ){
e.printStackTrace();
}
I'm trying to take two random rowid from my database. Everything works but I have a scenario when there is only one rowid. I want to make a loop on my try/catch until there is second number in my database.
What I'm doing wrong? Thank you
public void Kaslaimejo() {
String sql = "SELECT rowid FROM Zaidejai WHERE Pirmas < 4 ORDER BY random() LIMIT 2";
Integer value1 = null, value2 = null;
Integer judesiukas1 = null, judesiukas2 = null;
int a = 0;
int k = 15; // kiek kartu? Reikia infinity padaryti
for (a = 0; a < 3; a++) {
try {
Connection conn = Serveris.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if (rs.next()) {
value1 = rs.getInt("rowid");
if (rs.next()) {
value2 = rs.getInt("rowid");
PreparedStatement buvo = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo.setInt(1, i);
buvo.setInt(2, value1);
int buvolala = buvo.executeUpdate ();
PreparedStatement buvo2 = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo2.setInt(1, i);
buvo2.setInt(2, value2);
int buvolala2 = buvo2.executeUpdate ();//
i++;
}
System.out.println("Pirmas zaidejas" + value1); // atspausdina 1 random zaideja is duomenu bazes
System.out.println("Antras zaidejas" + value2); // atspausdina 2 random zaideja is duomenu bazes
}
} catch (SQLException e) {
a--;
//System.out.println(e.getMessage());
}
}
}
Right now my program loops two times and then gives me SQLException. How I can loop my program until there is no SQLException?
OK, I've tried to write what I think you're trying to do.
You wait for ever until someone puts at least two entries in the database.
You extract two values, process them, then wait some more.
Some points to watch out:
1. Object comparisons need to be made with .equals() not with ==
2. You might want to provide some way to break out of the infinite loop I've written (while(true)).
3. Careful with null values. They might produce NullPointerException.
4. Try to break up your code into methods. Each large block of code could go into each own method.
public void Kaslaimejo(){
String sql = "SELECT rowid FROM Zaidejai WHERE Pirmas < 4 ORDER BY random() LIMIT 2";
Integer judesiukas1 = null, judesiukas2 = null;
while(true) {
List<Integer> values = new ArrayList<>();
while (values.size() < 2) {
try (Connection conn = Serveris.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if( rs.next() ){
Integer value = rs.getInt("rowid");
values.add(value);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
try( Connection conn = Serveris.connect()) {
PreparedStatement buvo = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo.setInt(1, i);
buvo.setInt(2, values.get(0));
int buvolala = buvo.executeUpdate ();
PreparedStatement buvo2 = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo2.setInt(1, i);
buvo2.setInt(2, values.get(1));
int buvolala2 = buvo2.executeUpdate ();//
i++;
}catch (SQLException e) {
e.printStackTrace();
}
Connection conn = Serveris.connect();
try {
PreparedStatement pstmt = conn.prepareStatement("SELECT Pirmas FROM Zaidejai WHERE rowid = ?");
PreparedStatement pstmt2 = conn.prepareStatement("SELECT Pirmas FROM Zaidejai WHERE rowid = ?");
pstmt.setInt(1, values.get(0));
pstmt2.setInt(1, values.get(1));
ResultSet myrsv = pstmt.executeQuery();
ResultSet myrsv2 = pstmt2.executeQuery();
{
if (myrsv.next()) {
judesiukas1 = myrsv.getInt("Pirmas");
if (myrsv2.next()) {
judesiukas2 = myrsv2.getInt("Pirmas");
}
}
//System.out.println("Pirmo zaidejo veiksmas" + myrsv.getInt("Pirmas"));
//System.out.println("Antro zaidejo veiksmas" + myrsv2.getInt("Pirmas"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (judesiukas1.equals(judesiukas2)) // careful here. NullPointerException may happen.
{
try {
PreparedStatement laim = conn.prepareStatement("UPDATE Zaidejai SET Rezultatas = ? WHERE rowid = ?"); // ble ble update reikia naudoti , o ne insert into. Insert kai sukuriame nauja kazka tik
PreparedStatement laim2 = conn.prepareStatement("UPDATE Zaidejai SET Rezultatas = ? WHERE rowid = ?");
laim.setString(1, "Lygiosios");
laim.setInt(2, values.get(0));
laim2.setString(1, "Lygiosios");
laim2.setInt(2, values.get(1));
int irasyk = laim.executeUpdate (); // kodel executeupdate, o ne executequery????
int irasyk2 = laim2.executeUpdate (); // kodel executeupdate, o ne executequery????
{
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.print("Lygiosios");
} else {
// (1) - Rock
// (2) Scissors
// (3) - Paper
switch (values.get(0)){
case 1:
if (judesiukas2 == 2)
System.out.print("Zaidejas 1 wins!");
else
System.out.print("Zaidejas 2 wins!");
break;
case 2:
if (judesiukas2 == 3)
System.out.print("Zaidejas 1 wins!");
else
System.out.print("Zaidejas 2 wins!");
break;
case 3:
if (judesiukas2 == 1)
System.out.print("Zaidejas 1 wins!");
else
System.out.print("Zaidejas 2 wins!");
break;
}
}
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The logic becomes easier if you add the values to a list
var values = new ArrayList<Integer>();
while (values.Count < 2) {
try (Connection conn = Serveris.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql))
{
while (values.Count < 2 && rs.next()) {
Integer v = rs.getInt("rowid");
values.Add(v);
}
} catch (SQLException e) {
}
}
//TODO: process the values here
The advantage is, that you can retrieve one value at the first database query and the second at a later one or both in the same round and you don't have to keep track of which one of two variables to use.
(Bear with me with the syntax details, I'm not a Java programmer.)
How i can loop my program until there is no SQLException?
Change this (because, it will only allow to loop two times)
for (a = 0; a < 2; a++) {
to
while(true)
Put everything inside while(true), if exception occurred, then it will come out from the while loop. Something similar :
try
{
while(true)
{
...
...
}
...
}
catch(SQLException e)
{
// do somthing
}
I create this code for get column name in sql databases. But now I ant to modify above code for get all table data with column name. Then get all data and convert to jsonarray and pass. How I modify this code for get all table data with column name.
#Override
public JSONArray getarray(String sheetName) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = (Connection) DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "");
con.setAutoCommit(false);
PreparedStatement pstm = null;
Statement stmt = null;
//-----------------------Drop earliye table -------------------------------------------------------------
try {
String sqldrop = "select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='" + sheetName.replaceAll(" ", "_") + "'";
System.out.println(sqldrop);
PreparedStatement mypstmt = con.prepareStatement(sqldrop);
ResultSet resultSet = mypstmt.executeQuery();
JSONArray jsonArray = new JSONArray();
while (resultSet.next()) {
int total_rows = resultSet.getMetaData().getColumnCount();
JSONObject obj = new JSONObject();
for (int i = 0; i < total_rows; i++) {
String columnName = resultSet.getMetaData().getColumnLabel(i + 1).toLowerCase();
Object columnValue = resultSet.getObject(i + 1).toString().replaceAll("_", " ");
// if value in DB is null, then we set it to default value
if (columnValue == null) {
columnValue = "null";
}
/*
Next if block is a hack. In case when in db we have values like price and price1 there's a bug in jdbc -
both this names are getting stored as price in ResulSet. Therefore when we store second column value,
we overwrite original value of price. To avoid that, i simply add 1 to be consistent with DB.
*/
if (obj.has(columnName)) {
columnName += "1";
}
obj.put(columnName, columnValue);
}
jsonArray.put(obj);
}
mypstmt.close();
con.commit();
return jsonArray;
} catch (Exception e) {
System.out.println("There is no exist earlyer databases table!..... :( :( :( **************** " + sheetName.replaceAll(" ", "_"));
}
//----------------------------------------------------------------------------
} catch (ClassNotFoundException e) {
System.out.println(e);
} catch (SQLException ex) {
Logger.getLogger(PassArrayDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("%%%%%%%%%%");
return null;
}
My target is get all data with column name and above data pass html page as a json. So if you have any method for get all data with column name is suitable for me.
// code starts here
// This method retrieves all data from a mysql table...
public void retrieveAllData( String host, String user, String pass, String query) {
JTextArea textArea = new JTextArea();
try(
Connection connection = DriverManager.getConnection( host, user, pass )
Statement statement = connection.createStatement()
ResultSet resultSet = statement.executeQuery(query)) {
ResultSetMetaData metaData = resultSet.getMetaData();
int totalColumns = metaData.getColumnCount();
for( int i = 1; i <= totalColumns; i++ ) {
textArea.append( String.format( "%-8s\t", metaData.getColumnName(i) ) );
}
textArea.append( "\n" );
while( resultSet.next() ) {
for( int i = 1; i <= totalColumns; i++ ) {
Object object = resultSet.getObject(i).toString();
textArea.append( String.format("%-8s\t", object) );
}
textArea.append( "\n" );
}
}
}
See Below. rs.getString("tags") is subquery with more than 1 row. I want to iterate that subquery(rs.getString("tags") ---- Like rs.next().
while (rs.next()) {
emailDto emaildto = new emailDto();
emaildto.setMid(rs.getInt("id"));
emaildto.setSub(rs.getString("sub"));
emaildto.setMessage(rs.getString("message"));
while(rs.getString("tags").next()){
arrtags[i] = rs.getString(1);
}
emaildto.setTags(arrtags);
rs.getString("tags") does not work --- and contain more than 1 rows. How to extract it. Is there any technique?
Try something like this:
Array tagsArray = rs.getArray("tags");
String[] tags = (String[])tagsArray.getArray();
this is not answer. this is complete code
List emails = new ArrayList();
String listQuery = "select mid, sub, message, "
+ " (select emailid from sub_ids where sub_ids.messageid= sub_mail_list.mid ) // this query fetch more than one row.
as refid"
+ " from sub_mail_list";
PreparedStatement ps = null;
ResultSet rs;
try {
ps = DatabaseConnectionUtil.getConnection().prepareStatement(
listQuery);
rs = ps.executeQuery(listQuery);
while (rs.next()) {
emailDto emaildto = new emailDto();
emaildto.setMid(rs.getInt("mid"));
emaildto.setSub(rs.getString("sub"));
emaildto.setMessage(rs.getString("message"));
Array tagsArray = rs.getArray("refid");
List<vtbDto> vtbdtosvr = new ArrayList<vtbDto>();
int[] tags = (int[])tagsArray.getArray();
for (int i = 0; i < tags.length; i++) {
vtbDto vtbdto = new vtbDto();
vtbdto.setRefid(tags[i]);
vtbdtosvr.add(vtbdto);
}
emaildto.setAr(tagsArray);
emails.add(emaildto);
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
DatabaseConnectionUtil.closeAll(ps);
}
return emails;
And this is code to print function
List emailDtos = emaildao.getAllemails();
for (emailDto emailDto2 : emailDtos) {
System.out.println( emailDto2.getMid());
System.out.println( emailDto2.getSub());
System.out.println( emailDto2.getMessage());
List<vtbDto> vtbdtos= emailDto2.getVtbdtolst();
for (vtbDto vtbdto2 : vtbdtos) {
System.out.print(vtbdto2.getRefid() + ", ");
}
}
and the console print "Subquery returns more than 1 row";
I have a JFrame that has 3 JTextfields and 2 JDatechooser, what I am trying to do is if only one JTextfield has something typed in it and I press the search button, then I will be able to retrieve the data to JTable, but the problem is I have to fill out all JTextFileds and JDatechooser in order to retrieve data. My idea is to ignore null JTextfields and JTdatechooser if only one JTextfield has the keyword I want ?? Any suggestions ?? Thanks in advance,
public ArrayList<BillsRecord> getBillRecordByID(int EmpCode, String Fname, String Lname, String sDate, String eDate) throws SQLException {
String sql = "SELECT B.DATE AS DT, B.EMP_ID, E.FNAME, E.LNAME, MONEY_SENT, RENT, PHONE, GAS, ELECTRICITY, INTERNET, OTHER"
+ " FROM EMPLOYEE E INNER JOIN BILLS B ON E.EMP_ID = B.EMP_ID"
+ " WHERE B.EMP_ID = ? "
+ " OR E.FNAME = ? "
+ " OR E.LNAME = ? "
+ " OR DATE BETWEEN ? AND ? "
+ " ORDER BY B.DATE";
DBConnection con = new DBConnection();
Connection connect = con.getConnection();
PreparedStatement ps = null;
ArrayList<BillsRecord> records = new ArrayList<>();
try {
ps = connect.prepareStatement(sql);
ps.setInt(1, EmpCode);
ps.setString(2, Fname);
ps.setString(3, Lname);
ps.setString(4, sDate);
ps.setString(5, eDate);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
BillsRecord billrec = new BillsRecord();
billrec.setDATE(rs.getString("DT"));
billrec.setEMP_ID(rs.getInt("EMP_ID"));
billrec.setFNAME(rs.getString("FNAME"));
billrec.setLNAME(rs.getString("LNAME"));
billrec.setMONEY_SENT(rs.getDouble("MONEY_SENT"));
billrec.setRENT(rs.getDouble("RENT"));
billrec.setPHONE(rs.getDouble("PHONE"));
billrec.setGAS(rs.getDouble("GAS"));
billrec.setELECTRICITY(rs.getDouble("ELECTRICITY"));
billrec.setINTERNET(rs.getDouble("INTERNET"));
billrec.setOTHER(rs.getDouble("OTHER"));
records.add(billrec);
return records;
}
} catch (SQLException e) {
System.out.println(e.toString());
} finally {
if (ps != null) {
ps.close();
}
if (connect != null) {
connect.close();
}
}
return null;
}
private void search() {
try {
JTextField stxt = ((JTextField) startdatetxt.getDateEditor().getUiComponent());
String sDATE = stxt.getText().trim();
JTextField etxt = ((JTextField) enddatetxt.getDateEditor().getUiComponent());
String eDATE = etxt.getText().trim();
int EMP_ID = Integer.parseInt(this.empidtxt.getText().trim());
String FNAME = this.firstnametxt.getText().trim();
String LNAME = this.lastnametxt.getText().trim();
BillRecordDao billrecdao = new BillRecordDao();
ArrayList<BillsRecord> records = billrecdao.getBillRecordByID(EMP_ID, FNAME, LNAME, sDATE, eDATE);
Object[] tableColumnName = new Object[11];
tableColumnName[0] = "Date";
tableColumnName[1] = "H.License";
tableColumnName[2] = "First Name";
tableColumnName[3] = "Last Name";
tableColumnName[4] = "MONEY SENT";
tableColumnName[5] = "RENT";
tableColumnName[6] = "PHONE";
tableColumnName[7] = "GASE";
tableColumnName[8] = "ELECTRICITY";
tableColumnName[9] = "INTERNET";
tableColumnName[10] = "OTHER";
DefaultTableModel tbd = new DefaultTableModel();
tbd.setColumnIdentifiers(tableColumnName);
this.BillsSummaryTable.setModel(tbd);
Object[] RowRec = new Object[11];
for (int i = 0; i < records.size(); i++) {
RowRec[0] = records.get(i).getDATE();
RowRec[1] = records.get(i).getEMP_ID();
RowRec[2] = records.get(i).getFNAME().toUpperCase();
RowRec[3] = records.get(i).getLNAME().toUpperCase();
RowRec[4] = records.get(i).getMONEY_SENT();
RowRec[5] = records.get(i).getRENT();
RowRec[6] = records.get(i).getPHONE();
RowRec[7] = records.get(i).getGAS();
RowRec[8] = records.get(i).getELECTRICITY();
RowRec[9] = records.get(i).getINTERNET();
RowRec[10] = records.get(i).getOTHER();
tbd.addRow(RowRec);
}
} catch (SQLException e) {
System.out.println(e.toString());
}
}
Basically, you need to create a variable/dynamic query based on the available values
Now, you can do this using something like StringBuilder or even storing each query element in a List or array, but you always end up with the "trailing OR" problem (you need to know when you've got to the last element and not append the "OR" to the String or remove the trailing "OR" from the resulting String). While not difficult, it's just a pain.
However, if you're using Java 8, you can use StringJoiner!
StringJoiner sj = new StringJoiner(" OR ");
String sql = "SELECT B.DATE AS DT, B.EMP_ID, E.FNAME, E.LNAME, MONEY_SENT, RENT, PHONE, GAS, ELECTRICITY, INTERNET, OTHER"
+ " FROM EMPLOYEE E INNER JOIN BILLS B ON E.EMP_ID = B.EMP_ID"
+ " WHERE ";
List values = new ArrayList();
// EmpCode MUST be a Integer, so it can be null
if (EmpCode != null) {
sj.add("B.EMP_ID = ?");
values.add(EmpCode);
}
if (FName != null) {
sj.add("E.FNAME = ?");
values.add(FName);
}
if (LName != null) {
sj.add("E.LNAME = ?");
values.add(LName);
}
if (sDate != null && eDate != null) {
sj.add("DATE BETWEEN ? AND ?");
values.add(sDate);
values.add(eDate);
}
sql += sj.toString();
Connection connect = null;
try (PreparedStatement ps = connect.prepareStatement(sql)) {
for (int index = 0; index < values.size(); index++) {
ps.setObject(index + 1, values.get(index));
}
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
//...
}
}
} catch (SQLException exp) {
exp.printStackTrace();
}
You might also like to have a look at The try-with-resources Statement and have a read through Code Conventions for the Java TM Programming Language, it will make it easier for people to read your code and for you to read others