2017-06-01 22 views
3
import sqlite3 
import numpy as np 

def convert_int(x): 
    print('convert_int was called with {}'.format(x)) 
    if x == b'None' or x == b'': 
     return -1 # minus 1 as placeholder for integer nan 
    return np.int64(np.float64(x)) # np.float64 needed here as int(b'4.0') throws 

sqlite3.register_converter('int', convert_int) 
sqlite3.register_converter('None', convert_int) # attempt to tigger upon None 
sqlite3.register_converter('NoneType', convert_int) # attempt to tigger upon None 
sqlite3.register_converter('null', convert_int) # attempt to tigger upon None 

values = [(4.0,), (4,), (None,), ('',), (1.0,)] # 

conn = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES) 
conn.execute("create table test(p int)") 
conn.executemany("insert into test(p) values (?)", values) 

print(list(conn.execute("select p from test"))) 

產生以下輸出:sqlite - register_converters不觸發Python的NoneType?

convert_int was called with b'4' 
convert_int was called with b'4' 
convert_int was called with b'1' 
Out[2]: 
[(4,), (4,), (None,), (None,), (1,)] # 

convert_int()僅稱爲3次,非無型條目? 我需要註冊的轉換器是什麼,才能將其他2種類型轉換/解析爲某種替代值? 不幸的是我上面的嘗試不起作用。

回答

1

這是如何the _pysqlite_fetch_one_row() function in Modules/_sqlite/cursor.c處理的值被轉換:

if (converter != Py_None) { 
    nbytes = sqlite3_column_bytes(self->statement->st, i); 
    val_str = (const char*)sqlite3_column_blob(self->statement->st, i); 
    if (!val_str) { 
     Py_INCREF(Py_None); 
     converted = Py_None; 
    } else { 
     item = PyBytes_FromStringAndSize(val_str, nbytes); 
     if (!item) 
      goto error; 
     converted = PyObject_CallFunction(converter, "O", item); 
     Py_DECREF(item); 
     if (!converted) 
      break; 
    } 
} 

sqlite3_column_blob() function返回NULL用於SQL NULL值;在這種情況下,if (!val_str)分支返回一個None值而不調用轉換器。

所以不可能將NULL值轉換爲其他值。

轉換器旨在添加對其他數據類型的支持。如果你想獲得,其實不是在數據庫中的值更改查詢:

SELECT ifnull(p, -1) AS "p [int]" FROM test; 

(無裸表列,這也需要PARSE_COLNAMES

+0

非常感謝!這就結束了我的謎題,將按照建議使用IFNULL。 – kzk2000