使用SQLite,可以使用C api或PHP轻松添加用户定义的SQL函数.但它是否也可以使用Java或Groovy?
既然问题是关于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); } }
accumulator工作原因是因为在每个查询中都克隆了MyMax instantion,因此在实例化对象时可以提供起始值.
最后一个示例显示如何附加功能:
Function.create(c, IsSameDay.class.getSimpleName(), new IsSameDay()); Function.create(c, MyMax.class.getSimpleName(), new MyMax());
希望有人会发现它有用.
事实证明,使用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" }