SQLAlchemy核心。
我需要创建以下查询
SELECT <expression>
FROM (VALUES ('v1', 'v2')) AS v(x)
INNER JOIN...
(我正在使用支持此标准SQL语法的PostgreSQL)
但是VALUES数据必须来自bindparam('values')。
我正在使用此答案中的values类 How to make use of bindparam() in a custom Compiled expression?
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql import true
from sqlalchemy.sql.compiler import SQLCompiler
from sqlalchemy.sql.elements import (
BindParameter, literal, literal_column, quoted_name)
from sqlalchemy.sql.functions import func
from sqlalchemy.sql.expression import (
and_, asc, bindparam, case, cast, or_, select)
from sqlalchemy.sql.selectable import CTE, FromClause, Select
from sqlalchemy.sql.sqltypes import (
Boolean, Integer, Interval, Numeric, String, Text, Time)
from sqlalchemy.schema import Column, Table
class Values(FromClause):
"""Support FROM(VALUES ...)"""
named_with_column = True
def __init__(self, columns, *args, **kw):
self._column_args = columns
self.list = args
self._hide_froms.append(self)
self.alias_name = self.name = kw.pop('alias_name', None)
def _populate_column_collection(self) -> None:
for c in self._column_args:
getattr(c, "_make_proxy")(self)
@compiles(Values)
def compile_values(element: Any,
compiler: SQLCompiler,
asfrom: bool =False,
**kw) -> str:
"""SQL Render instruction for Values,"""
columns = element.columns
if len(element.list) == 1 and isinstance(element.list[0], BindParameter):
v = "VALUES {}".format(
compiler.process(element.list[0]))
else:
v = "VALUES {}".format(
", ".join(
"({})".format(
", ".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:
values = ", ".join(c.name for c in element.columns)
v = f"({v}) AS {element.alias_name} ({values})"
else:
v = f"({v})"
return v
这就是我的用法(逻辑比这更复杂,我只显示相关部分)。
v = Values(
[literal_column("cn", Text)],
bindparam("x"),
alias_name="v")
q = (
select(["*"]).
select_from(
v.join(
table,
onclause=v.c.cn == table.c.field))
engine.execute(q, x=("a", "b", "c"))
我得到的输出是
SELECT *
FROM (VALUES (('a'), ('b'), ('c'))) AS v (cn)
JOIN ...
代替
SELECT *
FROM (VALUES ('a'), ('b'), ('c')) AS v (cn)
JOIN ...
该如何解决?