2013-01-14 4 views
5

Per un sistema di commenti nidificati, sto memorizzazione di una struttura ad albero in una tabella di PostgreSQL utilizzando la seguente definizione nel modello Comment:Come utilizzare SQLAlchemy per selezionare il valore in una posizione in un ARRAY PostgreSQL?

path = sa.Column(ARRAY(sa.Integer)) 

Questo memorizza tutti gli ID dei commenti nel percorso a quella attuale. Quindi se un commento con id su 15 è figlio di 11 e 13, il suo percorso sarà [11,13,15].

Ora voglio trovare e contare i commenti dei bambini. Quindi, al fine di trovare tutti i figli di commento 11, tra cui si voglio generare SQL che assomiglia:

SELECT id, path FROM comments WHERE path[1] = 11; 

Su mio database restituisce felicemente un bel set di commento 11 e dei suoi figli.

Con l'esempio di cui sopra, se voglio prendere i figli di commento che posso utilizzare il seguente SQL:

SELECT id, path FROM comments WHERE path[1] = 11 AND path[2] = 13; 

Come dovrebbe SQLAlchemy essere utilizzato per generare questo SQL?

ho violato in giro con filter_by() e filter() senza molto successo ... Nessuno di questi lavori:

q = Comment.query.filter(path[1] == 11) 
> NameError: name 'path' is not defined 

q = Comment.query.filter_by(path[1] = 11) 
> SyntaxError: keyword can't be an expression 

preferirei non scrivere SQL personalizzata per questa query, ma se è l'unico modo, quindi, per favore, fornisci alcune indicazioni su come dovrebbe essere meglio costruita.

Modifica 1

Confermando che sto usando SQLAlchemy 0,7 - così le risposte che funzionano (circa) con questa versione sarebbe utile in più.

Mi sono reso conto che per l'implementazione dei commenti sopra, non è necessario trovare i numeri di identificazione nella posizione esatta, trovarli in qualsiasi posizione potrebbero funzionare anche. Quindi, qualsiasi input su come creare SQLAlchemy per generare qualcosa come questo sarebbe bene:

SELECT id, path FROM comments WHERE 11 = ANY (path); 

è possibile?

+3

che stai ricevendo lo SyntaxError 'parola chiave non può essere un'espressione' perché si è utilizzato un unico eguali = al posto di == – slashdottir

+0

@slashdottir grazie - la sua sempre le piccole cose stupide. – Craicerjack

risposta

5

Questo sarà solo il lavoro a partire dal SQLAlchemy 0.8 (beta2 al momento della stesura di questo):

from sqlalchemy.dialects import postgresql 

class Comment(Base): 
    __tablename__ = 'comments' 
    id = Column(Integer, primary_key=True) 
    path = Column(ARRAY(Integer)) 

q = Comment.query.filter(Comment.path[1] == 11) 
# This is just to demonstrate how compiled query would look like. 
print q.statement.compile(dialect=postgresql.dialect()) 

L'output:

SELECT comments.id, comments.path 
FROM comments 
WHERE comments.path[%(path_1)s] = %(param_1)s 

Aggiornamento

Ci è stato recentemente un discussion nella mailing list di SA abo ut come creare query = ANY (e correlate) per gli array di Postgres. Anche se gli esempi sono scritti per 0.8, dovrebbe funzionare anche in 0.7. Ecco un'implementazione funzionante di = ANY per 0.7 (testato):

from sqlalchemy.sql import literal, tuple_ 

# There's already built-in any() function in Python, we don't want to 
# shadow that. 
def any_(value, col): 
    return literal(value).op('= ANY')(tuple_(col)) 

q = Comment.query.filter(any_(11, Comment.path)) 
+0

Ciao Audrius, questo è utile. Sono bloccato su 0.7 per ora ... c'è un modo per generare 'ANY()' in SQL che conosci? Domanda aggiornata. – jamesc

+0

Ho aggiornato la mia risposta per dimostrare come scrivere query '= ANY' in SA. Non sono sicuro di quanto lontano sarebbe possibile spingere questo in 0.7. –

+0

Grazie - ha funzionato bene e mi sono aggiunto alla mailing list SA. – jamesc