Sunday, January 31, 2016

Better String Aggregation since Oracle 11gR2

In my previous blog "String aggregate in Oracle", I mentioned the restriction of that function is no ordering. Actually since Oracle 11g Release 2, Oracle introduced a new function LISTAGG which provides the same functionality, and also with ordering. You can find details here.

Anyway, I'll show some quick examples in this blog too. To achieve the same result, the query below can be used:
    select employee_id,
           LISTAGG(job_id, '|') WITHIN GROUP (ORDER BY job_id) job_list
    from job_history
    group by employee_id;

And below is the result.
    EMPLOYEE_ID JOB_LIST                     
    ----------- --------------------
            101 AC_ACCOUNT|AC_MGR   
            102 IT_PROG             
            114 ST_CLERK            
            122 ST_CLERK            
            176 SA_MAN|SA_REP       
            200 AC_ACCOUNT|AD_ASST
            201 MK_REP             

And you can see every item in job_list is order.

This new function can be used as analytical function as well.

Saturday, January 30, 2016

Spring Framework: Confusions of RowCallbackHandler

I have had some time not writing my blog. Mainly because my previous employer doesn't allow me to access blogspot during the work hour - also I kind of ran out of topics. I would like to write something that is advanced, not only just tutorials. You can find some many entry-level materials repeating each other, but many times, you'll struggle too long when facing a deeper issue. At least I struggled so many times.

Anyway, I tried to restart blogging. And today's topic is about RowCallbackHandler interface in Spring framework.

You can find many tutorials/samples that suggesting you write program as below:

public class RowCallbackTutorial {
    private DataSource dataSource;
    public void query(String sql) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.query(sql, new RowCallbackHandler(){
            public void processRow(ResultSet rs) throws SQLException {
                System.out.println("Inside RowCallbackHandler");
while ( rs.next() ) { System.out.println("Got value:" + rs.getObject(1)); } } }); } }
This actually is not right. Mentioned in the Java doc of this interface, method processRow "should not call next() on the ResultSet" - I guess they mean "should not call the next() on the first row of the ResultSet", since the ResultSet has already opened and pointing to first row when this method is called.

Here is a test using Spring embedded database support.

First we prepare a sql script to create table and insert a few rows, "db/init.sql". I have:
    CREATE TABLE customer (
        id         INTEGER PRIMARY KEY,
        name       VARCHAR(30)
    );

    insert into customer values(1, 'cust1');
    insert into customer values(2, 'cust2');
Then we test with the data.

    public static void main(String[] args) {
        EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.DERBY)
        .addScript("db/init.sql")
        .build();
        String sql = "select * from customer";
        RowCallbackTutorial sample = new RowCallbackTutorial();
        sample.setDataSource(db);
        sample.query(sql);
    }
We're expecting the program to output:
    Got value:1
    Got value:2
In fact, the previous program will only show second row: Got value:2. Where is the first row?

The ResultSet has already opened, and the cursor is pointing to first row. The first "next()" will move the cursor to next row. So the correct operation should be:
                do {
                    System.out.println("Got value:" + rs.getObject(1));
                }  while ( rs.next() );
And run the program again, we now get the correct result:
    Got value:1
    Got value:2
Now here is the last question. What if the ResultSet is empty? Will "do {...} while ()" encounter any error?

The answer is, no problem. In such case, the RowCallbackHandler will not be invoked at all. Change the query to "select * from customer where 1=2" for a new test, the output "Inside RowCallbackHandler" will not appear.