I'm attempting to create a JDBC query with the following statement
String query = "SELECT COLUMN1,DATECOLUMN2 FROM tableName +
"where datediff(d,DATECOLUMN2,getdate()) <= 1";
st = conn1.createStatement();
rs = st.executeQuery(query); //receiving error here
I am receiving the following error message
java.sql.SQLException: "d" is not a recognized table hints option. If it is intended as a parameter to a table-valued function or to the CHANGETABLE function, ensure that your database compatibility mode is set to 90.
I'm sure the query isn't recognizing the datediff function for some reason I am not sure why since i was previously using HQL in the same application and retrieving the values.
In an attempt to use an alternative function I used
{fn TIMESTAMPADD( SQL_TSI_DAY, 1, CURRENT_TIMESTAMP)}
but it also failed I later on found that this is only used for Derby Database's
Can someone assist me in using the proper sql function to compare a date with the current date using JDBC
String query = "SELECT COLUMN1,DATECOLUMN2 FROM tableName "+
"where datediff(day,DATECOLUMN2,getdate()) <= 1";
You have a comma before from. Based on the error messages you are running this against SQL server.
String query = "SELECT COLUMN1,DATECOLUMN2 FROM tableName "
+" where datediff(d,DATECOLUMN2,getdate()) <= 1";
The comma after the "d" should be a dot:
where datediff(d.DATECOLUMN2,getdate())
--------------- ^ dot here
The posted snippet doesn't have a closing double quote between tableName and +, but I figure that is just a typo. However, in your real code, where precisely is the double quote? Is it directly after tablename, like this
String query = "SELECT COLUMN1,DATECOLUMN2 FROM tableName" +
or after the space that follows tablename, like this
String query = "SELECT COLUMN1,DATECOLUMN2 FROM tableName "+
It is very likely the former, because in that case the resulting query would look exactly the way as to cause the error you are getting. Take a look at this:
SELECT COLUMN1,DATECOLUMN2 FROM tableNamewhere datediff(d,DATECOLUMN2,getdate()) <= 1
You can see that where merges with the table name and datediff becomes an alias. What follows is interpreted as table hints. (You can specify table hints without WITH in older versions of SQL Server/older compatibility levels.) Consequently, SQL Server stumbles over d, as that is indeed an incorrect table hint.
Related
I'm trying to run an insert or update on a table - the string generated from below works fine when copy pasted into HeidiSQL but throws SQLSyntaxErrorExceptions when run from Java:
Statement statement = con.createStatement();
String escapedXML = EscapeString(billboard.getXml());
String sql = String.format(
"DELIMITER $ \r\nBEGIN NOT ATOMIC\r\n" +
"IF EXISTS(SELECT * FROM billboards where Name='%s') THEN UPDATE billboards SET XML='%s' where Name='%s';\r\n" +
"ELSE insert into billboards(Name, XML, CreatorName) values('%s', '%s', '%s');\r\n" +
"END IF;\r\n" +
"END $\r\n" +
"DELIMITER ;", billboard.getName(), escapedXML, billboard.getName(), billboard.getName(), escapedXML, billboard.getCreatorName());
// Insert or update billboard
statement.execute(sql);
I can't figure out why.
I would recommend using the insert ... ok duplicate key syntax here rather than a code block. This is more efficient, and implements the lockout a single statement, which should avoid the problem you meet when running the query from your php code.
insert into billboards(Name, XML, CreatorName)
values(?, ?, ?)
on duplicate key update set XML = values(XML)
For this to work, you need a unique (or primary key) constraint on column Name.
Also, consider using a parameterized query rather than concatenating variables in your query stringW Escaping is inefficient and does not really make your code safer.
You should have tried NamedParameterStatement with your query to facilitate setting of string parameters and avoid their duplication (using refactored query suggested in GMB's earlier answer):
String sql = "INSERT INTO billboards (Name, XML, CreatorName) VALUES (:name, :xml, :creator) "
+ "ON DUPLICATE KEY UPDATE SET XML = :xml";
NamedParameterStatement statement = new NamedParameterStatement(con, sql);
statement.setString("name", billboard.getName());
statement.setString("xml", EscapeString(billboard.getXml()));
statement.setString("creator", billboard.getCreatorName());
// Insert or update billboard
statement.execute(sql);
The reason that you are getting a syntax error is that DELIMITER is a MySQL client command and not an SQL statement. MySQL commands may not be used in with JDBC.
For more information:
Delimiters in MySQL
I'm having issues dealing with the single quote while using it in a prepared statement in JAVA via Oracle JDBC.
Let's say we have a table Restaurant with a column restaurant_name with 1 value : Jack's Deli
I want to use a simple prepared statement query like this:
String result = "Jack\'\'s Deli"
String sqlStatement = "select * from Restaurant where restauraunt_name like ? escape '\\' ";
PreparedStatement pStmt = conn.prepareStatement(sqlStatement);
pstmt.setString(1, result);
The result shows 0 returned values, however when I directly search the query in the database (ORACLE) it works fine and retrieves the result. (Oracle uses two single quotes as an escape for the first)
I am thinking that the value is not being passed properly to the database. Or there is some other formatting issue.
The point of prepared statements is that you don't need any escaping.
.setString(1, "Jack's Deli") will get it done.
I am using JDBC PreparedStatement to query a Teradata database from a web service. My table has a PHONE_NUMBER column, stored as VARCHAR(10). I have always used PreparedStatement setString() to supply the parameter for this column, like below:
String myPhoneNumber = "5551234567";
String sql = "SELECT * FROM MYTABLE " +
"WHERE PHONE_NUMBER = ? ";
PreparedStatement p_stmt = db.getPreparedStatement(sql);
p_stmt.setString(1, myPhoneNumber);
ResultSet rs = db.executeQuery(p_stmt);
It returns correct results, but I noticed the CPU Teradata is using for this query is quite high. According to the EXPLAIN plan, it appears that Teradata is interpreting the myPhoneNumber parameter as a FLOAT, instead of VARCHAR, and so it has to do a data conversion to compare it to the VARCHAR column PHONE_NUMBER. Here is an excerpt of the EXPLAIN plan:
...
MYDATABASE.MYTABLE.PHONE_NUMBER (FLOAT, FORMAT
'-9.99999999999999E-999'))= 5.55123456700000E 009)
So, I came up with the below, which showed a great improvement in CPU usage (99.86% improvement):
String myPhoneNumber = "5551234567";
String sql = "SELECT * FROM MYTABLE " +
"WHERE PHONE_NUMBER = ''||?||'' ";
PreparedStatement p_stmt = db.getPreparedStatement(sql);
p_stmt.setString(1, myPhoneNumber);
ResultSet rs = db.executeQuery(p_stmt);
So my question is why is this necessary? Shouldn't setString tell JDBC to tell Teradata to expect a String/VARCHAR parameter?
Thanks!
Have you tried String myPhoneNumber = "'5551234567'";
Note -- The inclusion of the single quotes to wrap the value.
If you look at the example in the Teradata manuals here, you will see that a Query Band being set the same way as the OP's first example arrives as expected without single quotes wrapping it. It would seem to me this behavior in the first example of the OP is expected.
EDIT
The sample code provided by Teradata for their JDBC driver is using java.sql.PreparedStatment. With this their example program uses setString without any tricks to provide a string value for an INSERT statement. Sample Code If you are not able to replicate that behavior, I would open an incident with the Teradata GSC.
This question already has answers here:
Java PreparedStatement complaining about SQL syntax on execute()
(6 answers)
Closed 6 years ago.
This is a really weird error that only started appearing today. When I use a prepared statement with ? for parameters, I get an error, but when I use it without parameters, it works just fine.
Here is the error-causing code:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM ?");
prep.setString(1, table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This produces the following error:
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''files'' at line 1
Also, changing it to the following works just fine:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM " + table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This doesn't seem to be making a whole lot of sense. Any ideas?
Tried it on another table and got more weired results.
This works and logs the admin in correctly:
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE " + column + " = '" + hashedPassword + "'";
PreparedStatement prepared = connection.prepareStatement(sql);
The following doesn't cause errors, but returns a message saying that the password entered is incorrect (it's correct - I double triple checked).
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE ? = ?";
PreparedStatement prepared = connection.prepareStatement(sql);
prepared.setString(1, column);
prepared.setString(2, hashedPassword);
Got it: use ? for values.
Also, the answer here helped.
Bind parameters cannot be used for identifiers in the SQL statement. Only values can supplied through bind placeholders.
This will work:
SELECT foo FROM bar WHERE id = ?
This will not work, because the table name is an identifier
SELECT foo FROM ? WHERE id = 2
You can't supply a column name, because column names are also identifiers.
A statement like this will run, but it may not do what you think it does.
SELECT ? AS foo FROM bar WHERE ? = 0
If we supply values of 'foo' for both placeholders, the query will actually be equivalent to a query containing two string literals:
SELECT 'foo' AS foo FROM bar WHERE 'foo' = 0
MySQL will run that statement, because it's a valid statement (if the table bar exists and we have privileges on it.) That query will return every row in bar (because the predicate in the WHERE clause evaluates to TRUE, independent of the contents of the table.. And we get returned the constant string foo.
It doesn't matter one whit that the string foo happens to match the name of column in our table.
This restriction has to do with how the SQL optimizer operates. We don't need to delve into all the details of the steps (briefly: parsing tokens, performing syntax check, performing semantics check, determining query plan, and then the actual execution of the query plan.)
So here's the short story: The values for bind parameters are supplied too late in that process. They are not supplied until that final step, the execution of the query plan.
The optimizer needs to know which tables and columns are being referenced at earlier stages... for the semantics check, and for developing a query plan. The tables and columns have to be identified to the optimizer. Bind placeholders are "unknowns" at the time the table names and column names are needed.
(That short story isn't entirely accurate; don't take all of that as gospel. But it does explain the reason that bind parameters can't be used for identifiers, like table names and column names.)
tl;dr
Given the particular statement you're running, the only value that can be passed in as a bind parameter would be the "hashedPassword" value. Everything else in that statement has to be in the SQL string.
For example, something like this would work:
String sqltext = "SELECT * FROM mytable WHERE mycolumn = ?";
PreparedStatement prepared = connection.prepareStatement(sqltext);
prepared.setString(1, hashedPassword);
To make other parts of the SQL statement "dynamic" (like the table name and column name) you'd have to handle that in the Java code (using string concatenation.) The contents of that string would need to end up like the contents of the sqltext string (in my example) when it's passed to the prepareStatement method.
The parameters of PreparedStatement should be applied only in parameters that can be used in conditional clauses. The table name is not the case here.
If you have a select where the table name can be applied in the conditional clause you can do it, otherwise you can not.
The query code and query:
ps = conn.prepareStatement("select instance_id, ? from eam_measurement where resource_id in (select RESOURCE_ID from eam_res_grp_res_map where resource_group_id = ?) and DSN like '?' order by 2");
ps.setString(1,"SUBSTR(DSN,27,16)");
ps.setInt(2,defaultWasGroup);
ps.setString(3,"%Module=jvmRuntimeModule:freeMemory%");
rs = ps.executeQuery();
while (rs.next()) { bla blah blah blah ...
Returns an empty ResultSet.
Through basic debugging I have found its the third bind that is the problem i.e.
DSN like '?'
I have tried all kinds of variations, the most sensible of which seemed to be using:
DSN like concat('%',?,'%')
but that does not work as I am missing the ' on either side of the concatenated string so I try:
DSN like ' concat('%',Module=P_STAG_JDBC01:poolSize,'%') ' order by 2
but I just cannot seem to find a way to get them in that works.
What am I missing?
First, the PreparedStatement placeholders (those ? things) are for column values only, not for table names, column names, SQL functions/clauses, etcetera. Better use String#format() instead. Second, you should not quote the placeholders like '?', it would only malform the final query. The PreparedStatement setters already do the quoting (and escaping) job for you.
Here's the fixed SQL:
private static final String SQL = "select instance_id, %s from eam_measurement"
+ " where resource_id in (select RESOURCE_ID from eam_res_grp_res_map where"
+ " resource_group_id = ?) and DSN like ? order by 2");
Here is how to use it:
String sql = String.format(SQL, "SUBSTR(DSN,27,16)"); // This replaces the %s.
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, defaultWasGroup);
preparedStatement.setString(2, "%Module=jvmRuntimeModule:freeMemory%");
See also:
Sun JDBC tutorial: Using Prepared Statements
Format string syntax
If you want to use LIKE in prepared statement and also want to use % characters in LIKE;
write prepared statement as normally " .... LIKE ? ...." and while assigning parameter value to question mark use
ps.setString(1, "%" + "your string value" + "%");
This will work :)
There are two problems with your statement. You have to understand how bind variables work. The query is not processed by substituing the characters ? with your parameters. Instead, the statement is compiled with placeholders and then, during execution, the actual values of the parameters are given to the DB.
In other words, you parse the following query:
SELECT instance_id, :p1
FROM eam_measurement
WHERE resource_id IN (SELECT RESOURCE_ID
FROM eam_res_grp_res_map
WHERE resource_group_id = :p2)
AND DSN LIKE '?'
ORDER BY 2
I'm pretty sure the last parameter will be ignored because it is in a delimited character string. Even if it is not ignored, it does not make sense to have ' characters around because Oracle won't bind a parameter in a string (I'm surprised it hasn't raised any error, do you catch exceptions ?).
Now if you replace your DNS LIKE '?' with DSN LIKE ? and bind "%Module=jvmRuntimeModule:freeMemory%" this will make sense and should return the correct rows.
You still have the problem with your first parameter, it won't do what you expect, i-e the query that will be executed will be equivalent to the following query:
SELECT instance_id, 'SUBSTR(DSN,27,16)'
FROM ...
which is not at all the same as
SELECT instance_id, SUBSTR(DSN,27,16)
FROM ...
I would suggest parsing (=prepareStatement) the following query if you expect the SUBSTR to be dynamic:
SELECT instance_id, SUBSTR(DSN,?,?)
FROM eam_measurement
WHERE resource_id IN (SELECT RESOURCE_ID
FROM eam_res_grp_res_map
WHERE resource_group_id = ?)
AND DSN LIKE ?
ORDER BY 2
Omit the ' around the ?. Without the ', ? is a placeholder for a parameter. With it, it's an SQL string (i.e. the same as "?" in Java).
Then you must concatenate the string on the Java side; you can't pass SQL functions as parameters to queries; only basic values (like string, integer, etc) because the JDBC driver will convert the parameter to the SQL type the database expects and it cannot execute SQL functions in this step.
You can try:
String beforeAndAfter = "%" + yourVariable + "%";
PreparedStatement ps = con.prepareStatement(
"select columname from tablename where LOWER(columnname) LIKE LOWER('"+var+"%')");
Here var is the variable in which value that is to be searched is stored...
This should work:
"\'" + "?" + "\'"