Skip to content

Instantly share code, notes, and snippets.

@gjlondon
Last active April 20, 2017 19:37
Show Gist options
  • Save gjlondon/e28cb1f707b6637421137c0c4bf3c282 to your computer and use it in GitHub Desktop.
Save gjlondon/e28cb1f707b6637421137c0c4bf3c282 to your computer and use it in GitHub Desktop.
reproduction of apparent bug with .label() and not_() in SQLAlchemy
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
# coding: utf-8
from sqlalchemy import create_engine
from sqlalchemy.schema import MetaData, Table, Index, Column
from sqlalchemy.sql import and_, or_, not_, select, text
from sqlalchemy.types import Text, Integer, Float, String
engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()
user = Table('user', metadata,
Column('user_id', Integer, primary_key=True),
Column('user_name', String(16), nullable=False),
Column('email_address', String(60)),
Column('password', String(20), nullable=False)
)
user.create(engine)
with engine.connect() as conn:
for name in ('jack', 'james', 'jenny'):
email = '{name}@gmail.com'.format(name=name)
ins = user.insert().values(user_name=name, email_address=email, password="bad_pass")
result = conn.execute(ins)
with engine.connect() as conn:
query = select([user])
found = conn.execute(query).fetchall()
print("Full results: {results}".format(results=found))
query_with_disjunction = query.where(or_(user.c.user_name == "jack", user.c.user_name == "james"))
print("SQL: {}".format(str(query_with_disjunction)))
found = conn.execute(query_with_disjunction).fetchall()
print("\nReturns: {results}.\nThat makes sense.\n".format(results=found))
disjunction = or_(user.c.user_name == "jack", user.c.user_name == "james")
query_with_negated_disjunction = query.where(not_(disjunction))
print("SQL: {}".format(str(query_with_negated_disjunction)))
found = conn.execute(query_with_negated_disjunction).fetchall()
print("\nReturns: {results}\nThat makes sense.\n".format(results=found))
disjunction_with_label = disjunction.label("labelled_disjunction")
query_with_negated_disjunction_with_label = query.where(not_(disjunction_with_label))
print(("Produces the SQL: {}\n\nNotice that the 'not' does "
"NOT put parentheses around the disjunction".format(str(query_with_negated_disjunction_with_label))))
found = conn.execute(query_with_negated_disjunction_with_label).fetchall()
print(("\nReturns: {results}\n\nThat doesn't make sense for 2 reasons: "
"1) we'd expect the same result as the unlabelled disjunction, i.e. just jenny and "
"2) even if it's correct to apply the 'not' only to the first clause, "
"the result should be james and jenny, not jack and jenny.\n".format(results=found)))
literal_query = str(query_with_negated_disjunction_with_label.compile(
compile_kwargs={"literal_binds": True}))
print("If we pre-bind the variables and run directly, we get james and jenny:")
res = conn.execute(literal_query).fetchall()
print(str(res))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment