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))
Asked By: PanAmigo

||

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.

Answered By: ljmc
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.