Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring named parameters: how can I parameterize Oracle interval in my query?

I am having an issue trying to parameterize interval parameter in my Oracle query:

select current_timestamp - interval :hours hour from dual

If I replace the interval parameter with constant then it executes just fine.

Tried quoted and unquoted parameter in SQL.

See an illustration using minimal snippet below:

public class Main {
    private static String SQL_CONSTANT_INTERVAL = "select current_timestamp - interval '1' hour from dual";

    private static String SQL_PARAMETERIZED_INTERVAL_QUOTED = "select current_timestamp - interval ':hours' hour from dual";

    private static String SQL_PARAMETERIZED_INTERVAL_UNQUOTED = "select current_timestamp - interval :hours hour from dual";

    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.load(Main.class.getClassLoader().getSystemResourceAsStream("db.properties"));
        DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);

        NamedParameterJdbcTemplate npTemplate = new NamedParameterJdbcTemplate(dataSource);

        Map<String, String> params = Collections.singletonMap("hours", "1");

        String[] queries =
                new String[] { SQL_CONSTANT_INTERVAL, SQL_PARAMETERIZED_INTERVAL_QUOTED, SQL_PARAMETERIZED_INTERVAL_UNQUOTED };

        for (String q : queries) {
            System.out.println("Executing " + q);
            try {
                System.out.println("Result = " + npTemplate.queryForObject(q, params, String.class));
            } catch (RuntimeException e) {
                System.out.println("Error: " + e);
            }
            System.out.println();
        }
    }
}

Output:

Executing select current_timestamp - interval '1' hour from dual
Result = 2013-01-24 18:55:16.373 Europe/Moscow

Executing select current_timestamp - interval ':hours' hour from dual
24-Jan-2013 20:55:16 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
24-Jan-2013 20:55:16 org.springframework.jdbc.support.SQLErrorCodesFactory <init>
INFO: SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
Error: org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [select current_timestamp - interval ':hours' hour from dual]; ORA-01867: the interval is invalid
; nested exception is java.sql.SQLDataException: ORA-01867: the interval is invalid


Executing select current_timestamp - interval :hours hour from dual
Error: org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [select current_timestamp - interval ? hour from dual]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00923: FROM keyword not found where expected
like image 833
vitaly Avatar asked Jan 24 '13 17:01

vitaly


1 Answers

The interval '1' hour is an Oracle literal. As such, you cannot use a bind parameter to replace the '1' in the middle of it.

Instead, you can use this:

NUMTODSINTERVAL( 1, 'HOUR' )

Then you can replace the integer literal in your Java SQL like so:

NUMTODSINTERVAL( ?, 'HOUR' )
like image 86
GriffeyDog Avatar answered Nov 15 '22 19:11

GriffeyDog