2010-07-07 97 views

回答

7

事實證明,使用SQLiteJDBC編寫用戶定義的函數實際上相當簡單。這裏是一個Groovy例子:

@GrabConfig(systemClassLoader=true) 
@Grab('org.xerial:sqlite-jdbc:3.6.16') 
import org.sqlite.* 
import java.sql.* 

db = groovy.sql.Sql.newInstance("jdbc:sqlite::memory:","org.sqlite.JDBC") 

// a distance function using the spherical law of cosines 
Function.create(db.getConnection(), "distance", new Function() { 
    protected void xFunc() throws SQLException { 
     def lat1 = value_double(0) 
     def lon1 = value_double(1) 
     def lat2 = value_double(2) 
     def lon2 = value_double(3) 

     double theta = lon1 - lon2; 
     double dist = (Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2))) + 
      (Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta))) 
     dist = Math.acos(dist) 
     dist = rad2deg(dist) 
     dist = dist * 60 * 1.1515 
     dist = dist * 1.609344 
     result(dist); 
    } 

    def deg2rad(deg) { 
     deg * Math.PI/180.0 
    } 

    def rad2deg(rad) { 
     rad * 180.0/Math.PI 
    } 
}) 

db.execute("CREATE TABLE city(name, lat, lon)") 
db.execute("INSERT INTO city(name, lat, lon) VALUES('New York City', 40.7143, -74.0060)") 
db.execute("INSERT INTO city(name, lat, lon) VALUES('San Francisco', 37.7749, -122.4194)") 
db.execute("INSERT INTO city(name, lat, lon) VALUES('Paris', 48.8567, 2.3510)") 
db.execute("INSERT INTO city(name, lat, lon) VALUES('Cologne', 50.9407, 6.9599)") 

db.eachRow("SELECT a.name as a, b.name as b, distance(a.lat, a.lon, b.lat, b.lon) as d FROM city a, city b WHERE a.name != b.name ORDER BY d;") { 
    println "Distance from ${it.a} to ${it.b}: ${it.d}km" 
} 
8

由於問題是關於在Java或Groovy的解決方案,有人可以看看這裏的Java解決方案(就像我)

下面你可以看到簡單的功能驗證,如果提供的日期是同一天:

public class IsSameDay extends Function { 

    @Override 
    protected void xFunc() throws SQLException { 
     if (args() != 2) { 
      throw new SQLException("IsSameDay(date1,date2): Invalid argument count. Requires 2, but found " + args()); 
     } 
     try { 
      DateTime t1 = DateTime.parse(value_text(0).replace(" ", "T")); 
      DateTime t2 = DateTime.parse(value_text(1).replace(" ", "T")); 
      if (t1.getYear() == t2.getYear() && t1.getDayOfYear() == t2.getDayOfYear()) { 
       result(1); 
      } else { 
       result(0); 
      } 
     } catch (Exception exception) { 
      throw new SQLDataException("IsSameDay(date1,date2): One of Arguments is invalid: " + exception.getLocalizedMessage()); 
     } 
    } 
} 

,如果有人需要做一個聚合函數,則可能會發現這個例子有用:

public class MyMax extends Function.Aggregate { 

    private long buff = 0; 

    public MyMax() { 
    } 

    @Override 
    protected void xStep() throws SQLException { 
     long current = value_long(0); 
     if (current > buff) { 
      buff = current; 
     } 

    } 

    @Override 
    protected void xFinal() throws SQLException { 
     result(buff); 
    } 
} 

累加器的工作原理是因爲在每個查詢中MyMax實例被克隆,因此在實例化對象時可以提供起始值。

末例子展示瞭如何連接功能:

Function.create(c, IsSameDay.class.getSimpleName(), new IsSameDay()); 
Function.create(c, MyMax.class.getSimpleName(), new MyMax()); 

希望有人會發現它有用。