Convert SQL query with case when to sqlalchemy code
Question:
How can I convert this code to sqlalchemy?
df = pd.read_sql_query(f"SELECT id, year, "
f"CASE WHEN processed IS NULL THEN 'no' else 'yes' END [Processed], "
f"CASE WHEN email IS NULL THEN 'oryginal' else email END [Author], "
f"CASE WHEN txt IS NOT NULL THEN 'txt' "
f"WHEN csv IS NOT NULL THEN 'csv' ELSE 'no file' END [Type] "
f"FROM table1 WHERE pd_id = {id}", db_engine)
I’m using SQLAlchemy for simple like:
logs_id = db.session.query(Logs.id).filter(Logs.Errors != "Critical")
but I can’t find right solution for so many conditions in query.
Model:
class table1(db.Model):
__tablename__ = 'table1'
id = db.Column(db.Integer, primary_key=True)
txt = db.Column(db.String)
csv = db.Column(db.String)
year = db.Column(db.String(4))
pd_id = db.Column(db.Integer)
processed = db.Column(db.SMALLINT)
email = db.Column(db.String(50))
Answers:
You can use the case
expression, also your email
case is equivalent to a COALESCE
so I used func.coalesce
instead.
from sqlalchemy import Column, Integer, String, case, func, select
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class table1(Base):
__tablename__ = "table1"
id = Column(Integer, primary_key=True)
txt = Column(String)
csv = Column(String)
year = Column(String(4))
pd_id = Column(Integer)
processed = Column(Integer) # Simplified Integer for demo
email = Column(String(50))
id_ = 75232296
stmt = select(
table1.id,
table1.year,
case((table1.processed == None, "no"), else_="yes").label("processed"),
func.coalesce(table1.email, "oryginal").label("author"),
case(
(table1.txt != None, "txt"),
(table1.csv != None, "csv"),
else_="no file",
).label("type"),
).filter(table1.pd_id == id_)
print(stmt.compile(compile_kwargs={"literal_binds": True}))
gives
SELECT table1.id
, table1.year
, CASE WHEN (table1.processed IS NULL) THEN 'no' ELSE 'yes' END AS processed
, coalesce(table1.email, 'oryginal') AS author
, CASE WHEN (table1.txt IS NOT NULL) THEN 'txt'
WHEN (table1.csv IS NOT NULL) THEN 'csv'
ELSE 'no file'
END AS type
FROM table1
WHERE table1.pd_id = 75232296
PS. since those changes are trivial and fast in pandas, I would consider simplifying the query from SQL and using pandas to transform.
How can I convert this code to sqlalchemy?
df = pd.read_sql_query(f"SELECT id, year, "
f"CASE WHEN processed IS NULL THEN 'no' else 'yes' END [Processed], "
f"CASE WHEN email IS NULL THEN 'oryginal' else email END [Author], "
f"CASE WHEN txt IS NOT NULL THEN 'txt' "
f"WHEN csv IS NOT NULL THEN 'csv' ELSE 'no file' END [Type] "
f"FROM table1 WHERE pd_id = {id}", db_engine)
I’m using SQLAlchemy for simple like:
logs_id = db.session.query(Logs.id).filter(Logs.Errors != "Critical")
but I can’t find right solution for so many conditions in query.
Model:
class table1(db.Model):
__tablename__ = 'table1'
id = db.Column(db.Integer, primary_key=True)
txt = db.Column(db.String)
csv = db.Column(db.String)
year = db.Column(db.String(4))
pd_id = db.Column(db.Integer)
processed = db.Column(db.SMALLINT)
email = db.Column(db.String(50))
You can use the case
expression, also your email
case is equivalent to a COALESCE
so I used func.coalesce
instead.
from sqlalchemy import Column, Integer, String, case, func, select
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class table1(Base):
__tablename__ = "table1"
id = Column(Integer, primary_key=True)
txt = Column(String)
csv = Column(String)
year = Column(String(4))
pd_id = Column(Integer)
processed = Column(Integer) # Simplified Integer for demo
email = Column(String(50))
id_ = 75232296
stmt = select(
table1.id,
table1.year,
case((table1.processed == None, "no"), else_="yes").label("processed"),
func.coalesce(table1.email, "oryginal").label("author"),
case(
(table1.txt != None, "txt"),
(table1.csv != None, "csv"),
else_="no file",
).label("type"),
).filter(table1.pd_id == id_)
print(stmt.compile(compile_kwargs={"literal_binds": True}))
gives
SELECT table1.id
, table1.year
, CASE WHEN (table1.processed IS NULL) THEN 'no' ELSE 'yes' END AS processed
, coalesce(table1.email, 'oryginal') AS author
, CASE WHEN (table1.txt IS NOT NULL) THEN 'txt'
WHEN (table1.csv IS NOT NULL) THEN 'csv'
ELSE 'no file'
END AS type
FROM table1
WHERE table1.pd_id = 75232296
PS. since those changes are trivial and fast in pandas, I would consider simplifying the query from SQL and using pandas to transform.