2009-06-15 110 views
4

如何使用SQLAlchemy編寫自己的聚合函數?作爲一個簡單的例子,我想用numpy來計算方差。使用SQLite它應該是這樣的:如何使用sqlalchemy編寫自己的聚合函數?

import sqlite3 as sqlite 
import numpy as np 

class self_written_SQLvar(object): 
    def __init__(self): 
    import numpy as np 
    self.values = [] 
    def step(self, value): 
    self.values.append(value) 
    def finalize(self): 
    return np.array(self.values).var() 

cxn = sqlite.connect(':memory:') 
cur = cxn.cursor() 
cxn.create_aggregate("self_written_SQLvar", 1, self_written_SQLvar) 
# Now - how to use it: 
cur.execute("CREATE TABLE 'mytable' ('numbers' INTEGER)") 
cur.execute("INSERT INTO 'mytable' VALUES (1)") 
cur.execute("INSERT INTO 'mytable' VALUES (2)") 
cur.execute("INSERT INTO 'mytable' VALUES (3)") 
cur.execute("INSERT INTO 'mytable' VALUES (4)") 
a = cur.execute("SELECT avg(numbers), self_written_SQLvar(numbers) FROM mytable") 
print a.fetchall() 
>>> [(2.5, 1.25)] 

回答

9

的新聚合函數創建是後端依賴,並且必須用下劃線連接的API直接完成 。 SQLAlchemy沒有提供 工具來創建這些工具。

但創建後,您可以在SQLAlchemy中正常使用它們。

例子:

import sqlalchemy 
from sqlalchemy import Column, Table, create_engine, MetaData, Integer 
from sqlalchemy import func, select 
from sqlalchemy.pool import StaticPool 
from random import randrange 
import numpy 
import sqlite3 

class NumpyVarAggregate(object): 
    def __init__(self): 
    self.values = [] 
    def step(self, value): 
    self.values.append(value) 
    def finalize(self): 
    return numpy.array(self.values).var() 

def sqlite_memory_engine_creator(): 
    con = sqlite3.connect(':memory:') 
    con.create_aggregate("np_var", 1, NumpyVarAggregate) 
    return con 

e = create_engine('sqlite://', echo=True, poolclass=StaticPool, 
        creator=sqlite_memory_engine_creator) 
m = MetaData(bind=e) 
t = Table('mytable', m, 
      Column('id', Integer, primary_key=True), 
      Column('number', Integer) 
     ) 
m.create_all() 

現在的測試:

# insert 30 random-valued rows 
t.insert().execute([{'number': randrange(100)} for x in xrange(30)]) 

for row in select([func.avg(t.c.number), func.np_var(t.c.number)]).execute(): 
    print 'RESULT ROW: ', row 

,打印(與SQLAlchemy的聲明回聲開啓):

2009-06-15 14:55:34,171 INFO sqlalchemy.engine.base.Engine.0x...d20c PRAGMA 
table_info("mytable") 
2009-06-15 14:55:34,174 INFO sqlalchemy.engine.base.Engine.0x...d20c() 
2009-06-15 14:55:34,175 INFO sqlalchemy.engine.base.Engine.0x...d20c 
CREATE TABLE mytable (
    id INTEGER NOT NULL, 
    number INTEGER, 
    PRIMARY KEY (id) 
) 
2009-06-15 14:55:34,175 INFO sqlalchemy.engine.base.Engine.0x...d20c() 
2009-06-15 14:55:34,176 INFO sqlalchemy.engine.base.Engine.0x...d20c COMMIT 
2009-06-15 14:55:34,177 INFO sqlalchemy.engine.base.Engine.0x...d20c INSERT 
INTO mytable (number) VALUES (?) 
2009-06-15 14:55:34,177 INFO sqlalchemy.engine.base.Engine.0x...d20c [[98], 
[94], [7], [1], [79], [77], [51], [28], [85], [26], [34], [68], [15], [43], 
[52], [97], [64], [82], [11], [71], [27], [75], [60], [85], [42], [40], 
[76], [12], [81], [69]] 
2009-06-15 14:55:34,178 INFO sqlalchemy.engine.base.Engine.0x...d20c COMMIT 
2009-06-15 14:55:34,180 INFO sqlalchemy.engine.base.Engine.0x...d20c SELECT 
avg(mytable.number) AS avg_1, np_var(mytable.number) AS np_var_1 FROM mytable 
2009-06-15 14:55:34,180 INFO sqlalchemy.engine.base.Engine.0x...d20c [] 
RESULT ROW: (55.0, 831.0) 

請注意,我沒有使用SQLAlchemy的ORM(只使用SQLAlchemy的SQL表達式部分),但您也可以使用ORM。

+0

非常感謝。這真是一個非常好的回答! – 2009-06-16 15:16:45

-1

首先你必須從SQLAlchemy的

導入FUNC你可以寫

func.avg( '字段名')

或func.avg( '字段名')。標籤(「user_deined 「)

,或者你可以去通了MRE信息

http://www.sqlalchemy.org/docs/05/ormtutorial.html#using-subqueries

+0

這適用於像avg或count這樣的標準集合函數。但問題是如何看待自我實現的集合函數。順便說一下,該教程似乎相當不錯。 Thanx爲鏈接。 – 2009-07-10 09:24:57