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
^
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 city
WHERE city.size_code = %(size_code_1)s)]
[parameters: {'param_1': 3, 'param_2': 10, 'param_3': 18, 'size_code_1': 'M'}]
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.