2013-12-09 14 views
7

Hãy gợi ý có cách nào để viết truy vấn multi-column trong mệnh đề sử dụng SQLAlchemy không?Cách viết nhiều cột trong mệnh đề với sqlalchemy

Dưới đây là ví dụ về truy vấn thực tế:

SELECT url FROM pages WHERE (url_crc, url) IN ((2752937066, 'http://members.aye.net/~gharris/blog/'), (3799762538, 'http://www.coxandforkum.com/')); 

Tôi có một bảng mà có chìa khóa hai cột chính và tôi hy vọng sẽ tránh thêm một chìa khóa hơn chỉ để được sử dụng như một chỉ mục.

PS Tôi đang sử dụng DB mysql.

Cập nhật: Truy vấn này sẽ được sử dụng để xử lý theo lô - vì vậy tôi cần phải đặt vài trăm cặp vào mệnh đề trong. Với phương pháp tiếp cận mệnh đề IN, tôi hy vọng sẽ biết giới hạn cố định về số lượng cặp mà tôi có thể gắn vào một truy vấn. Theo mặc định, Oracle có 1000 giới hạn enum.

Sử dụng kết hợp AND/OR có thể bị giới hạn bởi độ dài của truy vấn trong ký tự. Mà sẽ là biến và ít dự đoán được.

Trả lời

0

tôi đã kết thúc bằng cách sử dụng thử nghiệm() dựa trên giải pháp: tạo ra "(a, b) trong ((: a1,: b1), (: a2 ,: b2), ...) "với các vlog ràng buộc có tên và tạo từ điển với các giá trị ràng buộc của vars.

params = {} 
for counter, r in enumerate(records): 
    a_param = "a%s" % counter 
    params[a_param] = r['a'] 
    b_param = "b%s" % counter 
    params[b_param] = r['b'] 
    pair_text = "(:%s,:%s)" % (a_param, b_param) 
    enum_pairs.append(pair_text) 
multicol_in_enumeration = ','.join(enum_pairs) 
multicol_in_clause = text(
    " (a,b) in (" + multicol_in_enumeration + ")") 
q = session.query(Table.id, Table.a, 
          Table.b).filter(multicol_in_clause).params(params) 

Một tùy chọn khác Tôi đã nghĩ về việc sử dụng upss mysql nhưng điều này sẽ làm cho toàn bộ thậm chí còn ít di động hơn cho động cơ db khác, sau đó sử dụng nhiều cột trong mệnh đề.

Cập nhật SQLAlchemy có cấu trúc sqlalchemy.sql.expression.tuple_(*clauses, **kw) có thể được sử dụng cho cùng một mục đích. (Tôi đã không thử nó chưa)

1

Tôi không nghĩ rằng điều này hiện có thể thực hiện trong sqlalchemy, và không phải tất cả RDMBS đều hỗ trợ điều này.
Bạn luôn có thể chuyển đổi này vào một tình trạng OR(AND...) mặc dù:

filter_rows = [ 
    (2752937066, 'http://members.aye.net/~gharris/blog/'), 
    (3799762538, 'http://www.coxandforkum.com/'), 
    ] 
qry = session.query(Page) 
qry = qry.filter(or_(*(and_(Page.url_crc == crc, Page.url == url) for crc, url in filter_rows))) 
print qry 

nên sản xuất cái gì đó tương tự (ví SQLite):

SELECT pages.id AS pages_id, pages.url_crc AS pages_url_crc, pages.url AS pages_url 
FROM pages 
WHERE pages.url_crc = ? AND pages.url = ? OR pages.url_crc = ? AND pages.url = ? 
-- (2752937066L, 'http://members.aye.net/~gharris/blog/', 3799762538L, 'http://www.coxandforkum.com/') 

Ngoài ra, bạn có thể kết hợp hai cột vào chỉ là một:

filter_rows = [ 
    (2752937066, 'http://members.aye.net/~gharris/blog/'), 
    (3799762538, 'http://www.coxandforkum.com/'), 
    ] 
qry = session.query(Page) 
qry = qry.filter((func.cast(Page.url_crc, String) + '|' + Page.url).in_(["{}|{}".format(*_frow) for _frow in filter_rows])) 
print qry 

sản xuất bên dưới (đối với SQLite), vì vậy bạn có thể sử dụng IN:

SELECT pages.id AS pages_id, pages.url_crc AS pages_url_crc, pages.url AS pages_url 
FROM pages 
WHERE (CAST(pages.url_crc AS VARCHAR) || ? || pages.url) IN (?, ?) 
-- ('|', '2752937066|http://members.aye.net/~gharris/blog/', '3799762538|http://www.coxandforkum.com/') 
+0

Nó là ý tưởng khả thi. Nhưng sẽ không phù hợp với nhu cầu của tôi. Tôi đã mở rộng câu hỏi với nhiều chi tiết hơn. – vvladymyrov

+0

Cập nhật câu trả lời với phiên bản 'IN'. – van

+0

Cảm ơn bạn đã cập nhật. Tôi nghĩ về việc kết hợp hai cột thành một chuỗi - nhưng điều này sẽ chậm - vì không có chỉ mục nào được sử dụng trong trường hợp này. – vvladymyrov

7

Giả sử rằng bạn đã mô hình của bạn được định nghĩa trong Page, đây là một ví dụ sử dụng tuple_:

keys = [ 
    (2752937066, 'http://members.aye.net/~gharris/blog/'), 
    (3799762538, 'http://www.coxandforkum.com/') 
] 

select([ 
    Page.url 
]).select_from(
    Page 
).where(
    tuple_(Page.url_crc, Page.url).in_(keys) 
) 

Hoặc, sử dụng API truy vấn:

session.query(Page.url).filter(tuple_(Page.url_crc, Page.url).in_(keys)) 
Các vấn đề liên quan