I
I
Ivan Tishchenko2016-06-08 11:47:12
Python
Ivan Tishchenko, 2016-06-08 11:47:12

How to use union in SQLAlchemy to join two or more tables with an unlimited number of common relationships?

We need to merge two different models that have a common key with a third model.

Description of models
class Income_Fact(db.Model):
    __tablename__ = 'Income_Fact'
    id = db.Column(
        UUID,
        default=text('uuid_generate_v4()'),
        server_default=text('uuid_generate_v4()'),
        primary_key=True
        )
    codes = db.Column(
        UUID,
        db.ForeignKey('Code.id'),
        nullable=True
        )
    date = db.Column(
        db.Date,
        nullable=False
        )
    value = db.Column(
        db.Float,
        nullable=False
        )

class Income_Plan(db.Model):
    __tablename__ = 'Income_Plan'
    id = db.Column(
        UUID,
        default=text('uuid_generate_v4()'),
        server_default=text('uuid_generate_v4()'),
        primary_key=True
        )
    codes = db.Column(
        UUID,
        db.ForeignKey('Code.id'),
        nullable=True
        )
    date = db.Column(
        db.Date,
        nullable=False
        )
    value = db.Column(
        db.Float,
        nullable=False
        )

class Code(db.Model):
    __tablename__ = 'Code'
    id = db.Column(UUID, default=text('uuid_generate_v4()'), server_default=text('uuid_generate_v4()'), primary_key=True)
    parents = db.Column(
        'parent_id',
        UUID,
        db.ForeignKey(id),
        default=None
        )
    code = db.Column(
        db.String,
        nullable=False
        )
    name = db.Column(
        db.String,
        nullable=False
        )
    popup = db.Column(
        db.String,
        nullable=True
        )
    income_plan_values = db.relationship(
        'Income_Plan',
        order_by='Income_Plan.date',
        backref='Code'
        )
    income_fact_values = db.relationship(
        'Income_Fact',
        order_by='Income_Fact.date',
        backref='Code'
        )


If you call the request like this:
q1 = query(Income_Plan.value.label('plan'), literal_column("0").label('fact'), Code.id, Code.name).select_from(Income_Plan).outerjoin(Code))
q2 = query(literal_column("0").label('plan'), Income_Plan.value.label('fact'), Code.id, Code.name).select_from(Income_Fact).outerjoin(Code))
sq = q1.union_all(q2).subquery()
query(func.sum(sq.c.plan), func.sum(sq.c.fact), Income_Code.name, Income_Code.id).select_entity_from(sq).group_by(Income_Code.id, Income_Code.name)

The SQL code is generated like this
SELECT 
  sum(anon_1.plan) AS sum_1, 
  sum(anon_1.fact) AS sum_2, 
  anon_1."Code_name" AS "anon_1_Code_name",
  anon_1."Code_id" AS "anon_1_Code_id"
FROM (
  SELECT 
    anon_2.plan AS plan, anon_2.fact AS fact, 
    anon_2."Code_id" AS "Code_id",
    anon_2."Code_name" AS "Code_name"
  FROM (
        SELECT
          "Income_Plan".value AS plan,
          0 AS fact, "Code".id AS "Income_Code_id",
          "Code".name AS "Code_name"
        FROM  "Income_Plan"
          LEFT OUTER JOIN "Code" ON "Code".id = "Income_Plan".codes
        UNION ALL
        SELECT
          0 AS plan,
          "Income_Fact".value AS fact,
          "Code".id AS "Code_id",
          "Code".name AS "Code_name"
        FROM "Income_Fact"
          LEFT OUTER JOIN "Code" ON "Code".id = "Income_Fact".codes
       ) AS anon_2
     ) AS anon_1 
GROUP BY anon_1."Code_id", anon_1."Code_name"


What needs to be changed in order to get at least approximately the following output:
SELECT *
FROM (
    SELECT SUM(Income_Plan.value) as 'plan', 0 as 'plan', Code.name
        FROM Income_Plan LEFT JOIN Code ON Code.id = Income_Plan.codes
        GROUP BY Code.id;
    UNION ALL;
    SELECT SUM(Income_Facr.value) as 'plan', 0 as 'fact', Code.name
        FROM Income_Plan LEFT JOIN Code ON Code.id = Income_Plan.codes
        GROUP BY Code.id;
)

How to do it with SQLAlchemy?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question