代码之家  ›  专栏  ›  技术社区  ›  otto.poellath

使用Java或Groovy为SQLite编写用户定义SQL函数?

  •  4
  • otto.poellath  · 技术社区  · 14 年前

    使用sqlite,可以使用 C api PHP . 但是使用Java还是Groovy也是可能的?

    3 回复  |  直到 6 年前
        1
  •  10
  •   T.G    9 年前

    由于问题是关于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());
    

    希望有人会发现它有用。

        2
  •  8
  •   otto.poellath    14 年前

    事实证明,编写用户定义的函数实际上非常容易使用 SQLiteJDBC . 下面是一个绝妙的例子:

    @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"
    }
    
        3
  •  0
  •   Rakesh Chaudhari    6 年前

    我认为,这是创建自定义函数的简单方法,

    Class.forName("org.sqlite.JDBC");
    Connection conn = DriverManager.getConnection("jdbc:sqlite:");
    Function.create(conn, "myFunc", new Function() {
               protected void xFunc() {
                   System.out.println("myFunc called!");
               }
           });        
    conn.createStatement().execute("select myFunc();");