我想在SQLalchemy中运行以下postgreSQL查询:
select c.*
from comments c
join (
values
(1,1),
(3,2),
(2,3),
(4,4)
) as x (id, ordering) on c.id = x.id
order by x.ordering
是否可以加入类似列表或元组列表之类的东西并使用它们来提供SQLalchemy中的排序?
答案 0 :(得分:2)
有关如何使SQLAlchemy编译VALUES
子句,请参阅PGValues recipe:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql import column
from sqlalchemy.sql.expression import FromClause
class values(FromClause):
named_with_column = True
def __init__(self, columns, *args, **kw):
self._column_args = columns
self.list = args
self.alias_name = self.name = kw.pop('alias_name', None)
def _populate_column_collection(self):
for c in self._column_args:
c._make_proxy(self)
@compiles(values)
def compile_values(element, compiler, asfrom=False, **kw):
columns = element.columns
v = "VALUES %s" % ", ".join(
"(%s)" % ", ".join(
compiler.render_literal_value(elem, column.type)
for elem, column in zip(tup, columns))
for tup in element.list
)
if asfrom:
if element.alias_name:
v = "(%s) AS %s (%s)" % (v, element.alias_name, (", ".join(c.name for c in element.columns)))
else:
v = "(%s)" % v
return v
>>> x = values([column("id", Integer), column("ordering", Integer)], (1, 1), (3, 2), (2, 3), (4, 4), alias_name="x")
>>> q = session.query(Comment).join(x, Comment.id == x.c.id).order_by(x.c.ordering)
>>> print(q)
SELECT comments.id AS comments_id
FROM comments JOIN (VALUES (1, 1), (3, 2), (2, 3), (4, 4)) AS x (id, ordering) ON comments.id = x.id ORDER BY x.ordering
答案 1 :(得分:1)
from sqlalchemy import *
from yourdbmodule import dbsession
VALUES = ((1, 1), (3, 2), (2, 3), (4, 4))
temp_table = Table(
'temp_table', MetaData(),
Column('id', INT, primary_key=True),
Column('ordering', INT),
prefixes=['TEMPORARY']
)
temp_table.create(bind=dbsession.bind, checkfirst=True)
dbsession.execute(temp_table.insert().values(VALUES))
# Now you can query it
dbsession.query(Comments)\
.join(temp_table, Comments.id == temp_table.c.id)\
.order_by(temp_table.c.ordering)\
.all()
答案 2 :(得分:1)
univerio的解决方案效果很好,但如果从给定值中选择一列,则会抛出错误:
>>> q = session.query(Comment, c.x.id).join(x, Comment.id == x.c.id).order_by(x.c.ordering)
>>> q.all()
ProgrammingError (ProgrammingError) table name "x" specified more than once
这是因为VALUES填充到FROM和JOIN块
>>> print(q)
SELECT comments.id AS comments_id, x.ordering as x_ordering
FROM (VALUES (1, 1), (3, 2), (2, 3), (4, 4)) AS x (id, ordering), comments
JOIN (VALUES (1, 1), (3, 2), (2, 3), (4, 4)) AS x (id, ordering) ON comments.id = x.id ORDER BY x.ordering
解决方案是从FROM语句中隐藏VALUES:
class values(FromClause):
named_with_column = True
def __init__(self, columns, *args, **kw):
self._column_args = columns
self.list = args
self._hide_froms.append(self) # This line fixes the above error
self.alias_name = self.name = kw.pop('alias_name', None)
def _populate_column_collection(self):
for c in self._column_args:
c._make_proxy(self)
现在工作正常:
>>> q = session.query(Comment, c.x.id).join(x, Comment.id == x.c.id).order_by(x.c.ordering)
>>> print(q)
SELECT comments.id AS comments_id, x.ordering as x_ordering
FROM comments JOIN (VALUES (1, 1), (3, 2), (2, 3), (4, 4)) AS x (id, ordering) ON comments.id = x.id ORDER BY x.ordering