2014-12-24 18 views
7

Tôi đang cố gắng thay thế việc sử dụng SAS bằng python + sqlite3; Tôi đang cố gắng di chuyển dữ liệu của mình từ bộ dữ liệu SAS sang cơ sở dữ liệu SQLite. Tôi có nhiều trường thời gian được biểu diễn đúng trong python như các đối tượng datetime.time. Vì SQLite được "nhập nhẹ", tôi đang tìm lời khuyên về định dạng nào cần sử dụng để lưu trữ thời gian trong cột. (Tôi biết tôi phải viết bộ điều hợp python, vv để đọc và viết các đối tượng đến và đi từ cột.) Đây là những tính năng tôi cần cân nhắc:Cách tốt nhất để lưu trữ datetime.time python trong một cột sqlite3?

  • Khả năng của SQLite đối phó với cột trong truy vấn. (Ví dụ: tôi có thể chọn các hàng xuất hiện giữa hai lần không?)
  • Kích thước của trường. (Bảng của tôi thường là hàng trăm triệu hàng.)
  • Khả năng đọc của con người. (Tôi đang xem xét lưu trữ thời gian dưới dạng số nguyên: micro giây kể từ nửa đêm. Nhưng điều này làm cho dữ liệu khó hơn.)

Có ai giải quyết vấn đề này cho sự hài lòng của họ không?

Trả lời

8

Có một công thức chung để lưu trữ bất kỳ đối tượng Python tuần tự hóa nào trong bảng sqlite.

Đây là những gì các mã nhìn có thể trông như cho datetime.time đối tượng:

import sqlite3 
import datetime as DT 

def adapt_timeobj(timeobj): 
    return ((3600*timeobj.hour + 60*timeobj.minute + timeobj.second)*10**6 
      + timeobj.microsecond) 

def convert_timeobj(val): 
    val = int(val) 
    hour, val = divmod(val, 3600*10**6) 
    minute, val = divmod(val, 60*10**6) 
    second, val = divmod(val, 10**6) 
    microsecond = int(val) 
    return DT.time(hour, minute, second, microsecond) 


# Converts DT.time to TEXT when inserting 
sqlite3.register_adapter(DT.time, adapt_timeobj) 

# Converts TEXT to DT.time when selecting 
sqlite3.register_converter("timeobj", convert_timeobj) 

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES) 
cur = con.cursor() 

# declare timecol to be of type timeobj 
cur.execute("create table test (timecol timeobj)") 

cur.executemany("insert into test (timecol) values (?)", 
       [(DT.time(1,2,3,4),), (DT.time(5,6,7,8),) ]) 

Bạn có thể sử dụng sự bất bình đẳng trong SQL, nhưng lưu ý rằng các giá trị được so sánh được trả lại bởi adapt_timeobj, không các đối tượng datetime.time. May mắn thay, nếu hàm adapt_timeobj trả về các số nguyên có thể đặt hàng theo cùng thứ tự với các đối tượng tương ứng datetime.time (như chúng làm ở trên), thì sự bất bình đẳng trong SQL sẽ hoạt động như mong muốn.

cur.execute("select timecol from test where timecol < ?", 
      [DT.time(4,5,6)]) 
print(cur.fetchall()) 
# [(datetime.time(1, 2, 3, 4),)] 

cur.execute("select timecol from test where timecol < ?", 
      [DT.time(8,0,0)]) 
print(cur.fetchall()) 
# [(datetime.time(1, 2, 3, 4),), (datetime.time(5, 6, 7, 8),)] 

con.commit() 
cur.close() 
con.close() 

Lưu ý: Nếu bạn nhìn vào lịch sử chỉnh sửa, bạn sẽ thấy một sự thay thế đơn giản hơn cho adapt_timeobjconvert_timeobj lưu trữ dữ liệu như một str thay vì như một int. Nó đơn giản hơn, nhưng lưu trữ dữ liệu dưới dạng int nhanh hơn và hiệu quả hơn với bộ nhớ.

+0

Điều đáng nói đến là việc chuyển 'PARSE_DECLTYPES' không bắt buộc trong trường hợp này. – jfs

+0

@JFSebastian: Cũng có thể sử dụng [PARSE_COLNAMES] (https://docs.python.org/2/library/sqlite3.html#sqlite3.PARSE_COLNAMES), nhưng sau đó bạn sẽ cần sử dụng SQL như 'SELECT timecol [ timeobj] ... ' – unutbu

+0

Tôi đã sử dụng micro giây kể từ nửa đêm trong các tình huống khác (không phải python + sqlite). Tôi không thích nó, nhưng nó là hợp lý. Tôi đã không nhận thức được khả năng sử dụng các đối tượng python trong các truy vấn như bạn đã làm trong ví dụ của bạn. Tôi có thể sẽ bắt đầu với đề xuất của bạn. Cảm ơn. – jdmarino

6

Tôi thực sự thích answer bởi @unutbu nhưng đây là cách đơn giản để lưu dấu thời gian.

RFC 3339 là định dạng dấu thời gian rất rõ ràng, dễ dàng cho máy tính phân tích cú pháp và dễ đọc cho con người. Bạn có thể lưu dấu thời gian dưới dạng chuỗi.

Một thuộc tính tốt đẹp của RFC 3339: sắp xếp ASCII đơn giản cũng sắp xếp theo thứ tự thời gian.

Nhưng bạn không thực sự cần thông số vì nó đơn giản như vậy.Dưới đây là một ví dụ:

2014-12-24T23:59:59.9999-08:00 

Đó là phần cuối cùng của một giây trước lễ Giáng sinh ngày theo múi giờ của tôi, đó là 8 giờ sau UTC (do đó phần -08:00). Năm, tháng, ngày, chuỗi T, giờ, phút, giây, múi giờ thứ hai tùy chọn.

Múi giờ cũng có thể là Z cho biết thời gian UTC. Nhưng nó có thể thuận tiện hơn để lưu trữ thời gian trong múi giờ địa phương để bạn có thể đọc chúng dễ dàng hơn.

+0

rfc3339 * yêu cầu * phần ngày. OP chỉ hỏi về 'datetime.time()' - không có ngày tháng. Ngoài ra, '-08' là không chính xác. Nó phải là '-08: 00' – jfs

+0

Vâng, câu hỏi không * cấm * lưu trữ ngày, và tôi nghĩ RFC 3339 có một số lợi thế. Bạn đúng về múi giờ và tôi đã sửa nó; cảm ơn bạn. – steveha

+0

Cảm ơn câu trả lời của bạn. Bộ dữ liệu của tôi sẽ không luôn luôn có ngày, chỉ là thời gian. Tôi đã xem xét giải pháp của bạn nhưng tôi cần phải thêm "ngày tiêu chuẩn" làm trình giữ chỗ (ví dụ: 1/1/1960). Lợi ích của phương pháp này là phân loại (như bạn đã chỉ ra), cộng với tôi sử dụng các hàm xử lý ngày của sqlite. Nhược điểm là tôi đã đại diện cho một ngày khi tôi không thực sự có một. – jdmarino

Các vấn đề liên quan