Hi,
I'm trying to create a query to check whether a small number of given keys
are all present within a selection of a table. Postgres provides array
types/functions for this to check sub/superset properties, which seem to do
what I want. The query I'm trying to create is one of the following form:
SELECT :selection <@ ARRAY(
SELECT id
FROM city
WHERE size_code = :size_code)
Wrapping this in a text clause, adding parameters and executing it works
without a hitch:
raw_select = sa.text("""
SELECT :selection <@ ARRAY(
SELECT id
FROM city
WHERE size_code = :size_code)""")
parameterized = raw_select.params(
selection=[3, 10, 18],
size_code='M')
result = engine.execute(parameterized).scalar()
However, I'd like to avoid having textual SQL in my codebase as it's more
sensitive to changes in names and generally more error-prone. I'm
struggling converting this to a working Core expression, a spurious
FROM-clause keeps being generated:
city_ids = sa.select([City.id]).where(City.size_code == 'M')
check = sa.select([
array([3, 10, 18]).contained_by(sa.func.array(city_ids))])
engine.execute(check).scalar()
This results in a Syntax Error being thrown by Postgres:
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.SyntaxError) subquery in
FROM must have an alias
LINE 4: FROM (SELECT city.id AS id
^
HINT: For example, FROM (SELECT ...) [AS] foo.
[SQL: SELECT ARRAY[%(param_1)s, %(param_2)s, %(param_3)s] <@ array((SELECT
city.id
FROM city
WHERE city.size_code = %(size_code_1)s)) AS anon_1
FROM (SELECT city.id AS id
FROM city
WHERE city.size_code = %(size_code_1)s)]
[parameters: {'param_1': 3, 'param_2': 10, 'param_3': 18, 'size_code_1':
'M'}]
(Background on this error at: http://sqlalche.me/e/f405)
The problem appears to be in the "_froms" list that is non-empty on the
"check" query, but I can't seem to find a way of coercing SQLAlchemy into
not generating that.
I've attached a minimal script to reproduce the problem. The table is
described though will have to be created still; it need not contain any
data, the problem is one of SQL syntax alone.
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
http://www.sqlalchemy.org/
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable
Example. See http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/sqlalchemy/8437d2b0-7189-4842-b029-e56056a9246a%40googlegroups.com.
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import array
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class City(Base):
__tablename__ = 'city'
id = sa.Column(sa.Integer, primary_key=True)
size_code = sa.Column(sa.Text)
def main():
engine = sa.create_engine('postgres://elmer@/smallville', echo=True)
# Text-based selection works as intended
raw_select = sa.text("""
SELECT :selection <@ ARRAY(
SELECT id
FROM city
WHERE size_code = :size_code)""")
parameterized = raw_select.params(
selection=[3, 10, 18],
size_code='M')
result = engine.execute(parameterized).scalar()
print('\nCity codes all match: {}\n'.format(result))
# Expressing this in Core yields unexpected FROM-clause
city_ids = sa.select([City.id]).where(City.size_code == 'M')
check = sa.select([
array([3, 10, 18]).contained_by(sa.func.array(city_ids))])
engine.execute(check).scalar()
if __name__ == '__main__':
main()