Hary
Hary

Reputation: 5818

Groovy Prepared Statement with Named Parameters

I used the below way to do named parameters with JDBC Prepared Statement. Any suggestion to improve this?

import java.sql.*;

def sqlQuery = "select * from table where col1=:col1 and col2=:col2"
def namedParameters =[
  ['ColumnName':'col1','Value':'test', 'DataType': 'int'],
  ['ColumnName':'col2','Value':'testsdfdf', 'DataType':'string'],
];

PreparedStatement stmt;

namedParameters.eachWithIndex{ k, v -> 
println "Index: " + v
println "Name: " + k.ColumnName
println "Value: " + k.Value

//To replace named parameters with ?
sqlQuery  = sqlQuery .replace(":" + k.ColumnName, "?")
println sqlQuery 

println "DataType: " + k.DataType

switch(k.DataType.toLowerCase())
{
    case('int'):
    stmt.setInt(v+1, k.Value)
    break;

    case('string'):
    stmt.setString(v+1, k.Value)
    break;

    default:
    stmt.setObject(v+1, k.Value)
}

};

println "End"
  1. I am doing a string replace to replace named parameter with ?
  2. And based on the provided map, identifying data type setting it to PreparedStatement accordingly

Upvotes: 5

Views: 7679

Answers (2)

Marmite Bomber
Marmite Bomber

Reputation: 21085

With Groovy SQL you can even use GString as SQL query.

Example

// Define bind variables
def  keyX = 1
def  keyY = 'row1'

Query

groovyCon.eachRow("select x,y from mytab where x  = ${keyX} and y  = ${keyY}")  {println it}

This send following query to DB:

 select x,y from mytab where x = :1  and y = :2

Groovy SQl is very handy and usefull, except for some special cases (e.g. you need to reuse a preparedStatement in a loop) where you must fallback to plain JDBC.

Upvotes: 1

Szymon Stepniak
Szymon Stepniak

Reputation: 42234

You can use groovy.sql.Sql class and its execute(Map params, String query, Closure processResults method. Consider following exemplary script:

sql.groovy:

@Grab(group='com.h2database', module='h2', version='1.4.197')

import groovy.sql.Sql

// (1) Configure JDBC connection (use H2 in-memory DB in this example)
def config = [
        url:'jdbc:h2:mem:test',
        user:'sa',
        password:'',
        driver: 'org.h2.Driver'
]

// (2) Connect to the database
def sql = Sql.newInstance(config.url, config.user, config.password, config.driver)

// (3) Create table for testing
sql.execute '''
     create table test (
         id integer not null,
         name varchar(50)
     )
'''

// (4) Insert some test data
def query = 'insert into test (id, name) values (?,?)'
sql.withBatch(3, query) { stmt ->
    stmt.addBatch(1, 'test 1')
    stmt.addBatch(2, 'test 2')
    stmt.addBatch(3, 'test 3')
}

// (5) Execute SELECT query
sql.execute([id: 1, name: 'test 1'], 'select * from test where id >= :id and name != :name', { _, result ->
    result.each { row ->
        println "id: ${row.ID}, name: ${row.NAME}"
    }
})

The last part shows how you can use prepared statement with named parameters. In this example we want to list all rows where id is greater or equal 1 and where name does not equal test 1.

The first parameter of sql.execute() method is a map that holds your named parameters (each key maps to :key in the SQL query). The second parameter is your SQL query where :key format is used for named parameters. And the third parameter is a closure that defines processing business logic - result holds a list of maps (e.g. [[ID: 2, NAME: test 2], [ID:3 name: test 3]] in this case) and you have to define how to process this result.

Console output

id: 2, name: test 2
id: 3, name: test 3

sql.eachRow() alternative

Alternatively you can use sql.eachRow(String sql, Map params, Closure closure) instead:

sql.eachRow('select * from test where id > :id', [id: 1], { row ->
    println "id: ${row.ID}, name: ${row.NAME}"
})

It will produce the same output.

Upvotes: 6

Related Questions